fix: modernize Redux extensions to RTK, re-enable type-check in CI#60
Conversation
- Migrate react-redux-thunk to @reduxjs/toolkit (configureStore) - Remove CombinedState import (removed in Redux 5.x) - Remove saga imports (copy-paste bug from saga extension) - Remove manual DevTools setup (RTK handles it) - Add proper RootState/AppDispatch types - Migrate react-redux-saga to @reduxjs/toolkit + saga middleware - Same CombinedState and DevTools fixes - Keep saga middleware via RTK middleware config - Remove orphaned react-ionic directory (only had .npmrc, not in templates.json) - Update Recoil.js description to note Meta no longer maintains it - Update templates.json descriptions for Redux extensions - Re-enable type-check in CI (remove || true workaround)
📝 WalkthroughWalkthroughThis PR migrates two Redux extension templates ( Changes
Possibly related PRs
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@extensions/react-redux-saga/`[src]/store.ts.template:
- Around line 30-32: The DEV-only logger isn't being registered because
middlewares.concat(createLogger() as any) returns a new array that is discarded;
update the DEV block to actually add the logger to the middleware array (e.g.,
reassign middlewares = middlewares.concat(createLogger()) or use
middlewares.push(createLogger())) so the logger middleware created by
createLogger() is included, and remove the unnecessary "as any" cast so the
logger uses the proper Middleware type; apply this change around the existing
middlewares variable and the createLogger() call in store.ts.template.
In `@extensions/react-redux-thunk/`[src]/store.ts.template:
- Around line 22-28: The DEV branch discards the result of
middlewares.concat(...) so redux-logger never gets added; update the logic in
the function that builds middlewares so the logger is actually appended (e.g.,
assign the concat result back to middlewares or use push with createLogger() as
any) when import.meta.env.DEV is true, and if necessary adjust types by removing
an overly strict explicit annotation or importing ConfigureStoreOptions from
`@reduxjs/toolkit` so the middleware array type accepts the logger (references:
middlewares, createLogger(), import.meta.env.DEV, concat).
- Line 16: The middleware callback is typed incorrectly: using ReturnType<typeof
configureStore>['middleware'] breaks RTK inference for getDefaultMiddleware and
serializable/dispatch types; change the signature for the middleware factory to
accept CurriedGetDefaultMiddleware<RootState> (or simply use an untyped inline
parameter middleware: (getDefaultMiddleware) => { ... } inside configureStore to
let TS infer) and remove the unnecessary "as any" cast on createLogger(); update
references in this file to use CurriedGetDefaultMiddleware<RootState> (or the
inline middleware callback) and keep configureStore and createLogger usage
unchanged otherwise.
In `@extensions/react-redux-thunk/README.md`:
- Around line 33-35: The README example references useEffect but the top import
block only imports react-redux and Redux Toolkit symbols; update the imports to
include useEffect from React (e.g., add an import for useEffect from 'react'
alongside the existing imports) so the example that uses useEffect compiles;
locate the import block containing useSelector/useDispatch and add the useEffect
symbol to the imports.
- Around line 43-60: Add the missing slice registration so the example works:
export the slice reducer from userSlice (e.g., userSlice.reducer) and include it
when building the root reducer (via combineReducers) and store (e.g.,
configureStore/createStore) so RootState has a user field; then update the
example to import the store/provider or RootState type accordingly so
useSelector((state: RootState) => state.user) resolves at runtime.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1f811627-b7e7-4d94-85f7-899c281ee053
📒 Files selected for processing (14)
.github/workflows/test-combinations.ymlextensions/react-ionic/.npmrcextensions/react-redux-saga/[src]/reducers/index.tsextensions/react-redux-saga/[src]/store.ts.templateextensions/react-redux-saga/[src]/types/global.d.tsextensions/react-redux-saga/[src]/types/store.tsextensions/react-redux-saga/package.jsonextensions/react-redux-thunk/README.mdextensions/react-redux-thunk/[src]/reducers/index.tsextensions/react-redux-thunk/[src]/store.ts.templateextensions/react-redux-thunk/[src]/types/global.d.tsextensions/react-redux-thunk/[src]/types/store.tsextensions/react-redux-thunk/package.jsontemplates.json
💤 Files with no reviewable changes (3)
- extensions/react-ionic/.npmrc
- extensions/react-redux-saga/[src]/types/global.d.ts
- extensions/react-redux-thunk/[src]/types/global.d.ts
| if (import.meta.env.DEV) { | ||
| middlewares.concat(createLogger() as any); | ||
| } |
There was a problem hiding this comment.
Bug: redux-logger is never attached in DEV — same .concat issue as the thunk template.
middlewares.concat(createLogger() as any) returns a new array and discards it, so the logger middleware is built but never registered with the store. Only the saga middleware (attached via the reassigned .concat on line 28) actually runs.
🔧 Proposed fix
- const middlewares = getDefaultMiddleware({
+ let middlewares = getDefaultMiddleware({
thunk: false,
serializableCheck: {
ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
},
}).concat(sagaMiddleware);
if (import.meta.env.DEV) {
- middlewares.concat(createLogger() as any);
+ middlewares = middlewares.concat(createLogger());
}
return middlewares;Also consider dropping as any — redux-logger provides compatible Middleware types, and keeping any here undermines the type-check you're re-enabling in CI.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@extensions/react-redux-saga/`[src]/store.ts.template around lines 30 - 32,
The DEV-only logger isn't being registered because
middlewares.concat(createLogger() as any) returns a new array that is discarded;
update the DEV block to actually add the logger to the middleware array (e.g.,
reassign middlewares = middlewares.concat(createLogger()) or use
middlewares.push(createLogger())) so the logger middleware created by
createLogger() is included, and remove the unnecessary "as any" cast so the
logger uses the proper Middleware type; apply this change around the existing
middlewares variable and the createLogger() call in store.ts.template.
|
|
||
| // Push middleware that you need for both development and production | ||
| packages.push(sagaMiddleware); | ||
| const middleware = (getDefaultMiddleware: ReturnType<typeof configureStore>['middleware']) => { |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In @reduxjs/toolkit2.5, what is the correct TypeScript type for thegetDefaultMiddlewarecallback parameter passed toconfigureStore's middleware option?
💡 Result:
The correct TypeScript type for the getDefaultMiddleware callback parameter passed to configureStore's middleware option in @reduxjs/toolkit 2.5 is GetDefaultMiddleware, where S is the store state type.
Citations:
- 1: https://github.com/reduxjs/redux-toolkit/blob/master/packages/toolkit/src/configureStore.ts
- 2: https://github.com/reduxjs/redux-toolkit/blob/39e7c8fb/packages/toolkit/src/configureStore.ts
- 3: https://github.com/reduxjs/redux-toolkit/blob/39e7c8fb/packages/toolkit/src/getDefaultMiddleware.ts
🏁 Script executed:
# First, locate the file in question
fd -p "store.ts.template" extensions/Repository: Create-Node-App/cna-templates
Length of output: 177
🏁 Script executed:
# Check the actual content of the file
if [ -f "extensions/react-redux-thunk/src/store.ts.template" ]; then
cat -n "extensions/react-redux-thunk/src/store.ts.template"
fiRepository: Create-Node-App/cna-templates
Length of output: 55
🏁 Script executed:
# Search for any Redux Toolkit type definitions or imports in the codebase to understand what types are available
rg "GetDefaultMiddleware|CurriedGetDefaultMiddleware|ConfigureStoreOptions" -A 2 -B 2Repository: Create-Node-App/cna-templates
Length of output: 55
🏁 Script executed:
# Check if there's a node_modules or package.json to understand which version of RTK is used
if [ -f "package.json" ]; then
cat package.json | grep -A 5 "@reduxjs/toolkit"
fiRepository: Create-Node-App/cna-templates
Length of output: 55
🏁 Script executed:
# Also check for any type definitions or tsconfig to understand the TS setup
find . -maxdepth 2 -name "tsconfig.json" -o -name "tsconfig*.json"Repository: Create-Node-App/cna-templates
Length of output: 55
🏁 Script executed:
# Read the actual file content with line numbers
cat -n extensions/react-redux-thunk/src/store.ts.templateRepository: Create-Node-App/cna-templates
Length of output: 155
🏁 Script executed:
# Find package.json files
find . -name "package.json" -type fRepository: Create-Node-App/cna-templates
Length of output: 1903
🏁 Script executed:
# Check for redux-logger type definitions and configuration
rg "redux-logger|createLogger" -A 3 -B 1Repository: Create-Node-App/cna-templates
Length of output: 4042
🏁 Script executed:
# Search for type imports or definitions related to middleware configuration
rg "middleware|GetDefaultMiddleware|CurriedGetDefaultMiddleware" extensions/react-redux-thunk/ -A 2Repository: Create-Node-App/cna-templates
Length of output: 1407
🏁 Script executed:
# Search for Redux Toolkit type definitions to verify the correct types
web_searchRepository: Create-Node-App/cna-templates
Length of output: 123
🌐 Web query:
Redux Toolkit ConfigureStoreOptions middleware type definition CurriedGetDefaultMiddleware
💡 Result:
The CurriedGetDefaultMiddleware type is used in Redux Toolkit's ConfigureStoreOptions interface to define the middleware callback parameter. It represents a curried function (getDefaultMiddleware: CurriedGetDefaultMiddleware) => M where CurriedGetDefaultMiddleware is the type of the getDefaultMiddleware function passed to the middleware callback. This function has the signature that returns a Tuple<Middlewares> (a type-safe array of Middleware<{}, S>[]), which can be chained with .concat or .prepend methods. It is built internally using buildGetDefaultMiddleware from ./getDefaultMiddleware. Key type definitions from source: - export type Middlewares = ReadonlyArray<Middleware<{}, S>> - middleware?: (getDefaultMiddleware: GetDefaultMiddleware) => M (older naming, aliased/equivalent to CurriedGetDefaultMiddleware) - Full interface: ConfigureStoreOptions<S = any, A extends Action = UnknownAction, M extends Tuple<Middlewares> = Tuple<Middlewares>, E extends Tuple = Tuple, P = S> Usage example: middleware: (getDefaultMiddleware: CurriedGetDefaultMiddleware) => getDefaultMiddleware.concat(customMiddleware) This ensures TypeScript inference for the store's dispatch type based on the middleware tuple returned.
Citations:
- 1: https://github.com/reduxjs/redux-toolkit/blob/master/packages/toolkit/src/configureStore.ts
- 2: https://redux-toolkit.js.org/api/getDefaultMiddleware
- 3: https://github.com/reduxjs/redux-toolkit/blob/39e7c8fb/packages/toolkit/src/configureStore.ts
- 4: https://redux-toolkit.js.org/usage/usage-with-typescript
- 5: https://redux-toolkit.js.org/api/configureStore
- 6: https://github.com/reduxjs/redux-toolkit/blob/master/docs/api/configureStore.mdx
🏁 Script executed:
# Check the actual Redux Toolkit types available for import
rg "ConfigureStoreOptions|CurriedGetDefaultMiddleware|GetDefaultMiddleware" -t ts -t tsxRepository: Create-Node-App/cna-templates
Length of output: 100
🏁 Script executed:
# Look at the complete store.ts.template file to understand context
cat -n "extensions/react-redux-thunk/[src]/store.ts.template"Repository: Create-Node-App/cna-templates
Length of output: 1458
Incorrect type annotation for getDefaultMiddleware — breaks type inference for the middleware callback.
ReturnType<typeof configureStore>['middleware'] does not resolve to the callback signature RTK expects. The EnhancedStore type does not expose a public middleware property with that shape, causing type loss for serializableCheck and downstream dispatch typing.
Use CurriedGetDefaultMiddleware<RootState> directly, or inline the callback: configureStore({ middleware: (getDefaultMiddleware) => { ... } }) to let TypeScript infer the type.
Also remove the unnecessary as any cast on createLogger() — redux-logger (3.0.6) with @types/redux-logger (3.0.13) ships proper types.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@extensions/react-redux-thunk/`[src]/store.ts.template at line 16, The
middleware callback is typed incorrectly: using ReturnType<typeof
configureStore>['middleware'] breaks RTK inference for getDefaultMiddleware and
serializable/dispatch types; change the signature for the middleware factory to
accept CurriedGetDefaultMiddleware<RootState> (or simply use an untyped inline
parameter middleware: (getDefaultMiddleware) => { ... } inside configureStore to
let TS infer) and remove the unnecessary "as any" cast on createLogger(); update
references in this file to use CurriedGetDefaultMiddleware<RootState> (or the
inline middleware callback) and keep configureStore and createLogger usage
unchanged otherwise.
|
|
||
| if (import.meta.env.DEV) { | ||
| // Push the middleware that are specific for development | ||
| packages.push(createLogger()); | ||
| if (window.__REDUX_DEVTOOLS_EXTENSION__) { | ||
| enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__()); | ||
| if (import.meta.env.DEV) { | ||
| middlewares.concat(createLogger() as any); | ||
| } | ||
| } | ||
|
|
||
| const middleware = applyMiddleware(...packages); | ||
|
|
||
| export const store = createStore( | ||
| persistReducer<StoreType>(persistConfig, reducers()), | ||
| compose(middleware, ...enhancers), | ||
| ); | ||
| return middlewares; | ||
| }; |
There was a problem hiding this comment.
Bug: redux-logger is never attached in DEV — .concat result is discarded.
Array#concat (and RTK's MiddlewareArray#concat) returns a new array; it doesn't mutate in place. So in DEV the logger middleware is created but thrown away, and the returned middlewares is identical to the base one. This is a regression from the previous saga-based wiring.
🔧 Proposed fix
-const middleware = (getDefaultMiddleware: ReturnType<typeof configureStore>['middleware']) => {
- const middlewares = getDefaultMiddleware({
- serializableCheck: {
- ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
- },
- });
-
- if (import.meta.env.DEV) {
- middlewares.concat(createLogger() as any);
- }
-
- return middlewares;
-};
+const middleware: ConfigureStoreOptions['middleware'] = (getDefaultMiddleware) => {
+ const base = getDefaultMiddleware({
+ serializableCheck: {
+ ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
+ },
+ });
+
+ return import.meta.env.DEV ? base.concat(createLogger()) : base;
+};(Adjust the import to include ConfigureStoreOptions from @reduxjs/toolkit, or drop the explicit annotation and inline the callback so TS infers types from configureStore.)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@extensions/react-redux-thunk/`[src]/store.ts.template around lines 22 - 28,
The DEV branch discards the result of middlewares.concat(...) so redux-logger
never gets added; update the logic in the function that builds middlewares so
the logger is actually appended (e.g., assign the concat result back to
middlewares or use push with createLogger() as any) when import.meta.env.DEV is
true, and if necessary adjust types by removing an overly strict explicit
annotation or importing ConfigureStoreOptions from `@reduxjs/toolkit` so the
middleware array type accepts the logger (references: middlewares,
createLogger(), import.meta.env.DEV, concat).
| import { useSelector, useDispatch } from 'react-redux'; | ||
|
|
||
| // Thunk action creator | ||
| const fetchUser = (userId) => async (dispatch) => { | ||
| dispatch({ type: 'FETCH_USER_START' }); | ||
| try { | ||
| const user = await api.getUser(userId); | ||
| dispatch({ type: 'FETCH_USER_SUCCESS', payload: user }); | ||
| } catch (error) { | ||
| dispatch({ type: 'FETCH_USER_ERROR', payload: error.message }); | ||
| } | ||
| }; | ||
|
|
||
| function UserProfile({ userId }) { | ||
| const user = useSelector(state => state.user); | ||
| const dispatch = useDispatch(); | ||
| import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; | ||
| import type { RootState, AppDispatch } from './store'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name README.md -path "*/react-redux-thunk/*" | head -5Repository: Create-Node-App/cna-templates
Length of output: 113
🏁 Script executed:
wc -l extensions/react-redux-thunk/README.mdRepository: Create-Node-App/cna-templates
Length of output: 114
🏁 Script executed:
cat -n extensions/react-redux-thunk/README.md | sed -n '30,70p'Repository: Create-Node-App/cna-templates
Length of output: 1442
Import useEffect in the README example.
Line 63 uses useEffect, but the import statements at lines 33–35 only include Redux hooks, so a copy-paste example fails to compile.
📝 Proposed README fix
+import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import type { RootState, AppDispatch } from './store';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { useSelector, useDispatch } from 'react-redux'; | |
| // Thunk action creator | |
| const fetchUser = (userId) => async (dispatch) => { | |
| dispatch({ type: 'FETCH_USER_START' }); | |
| try { | |
| const user = await api.getUser(userId); | |
| dispatch({ type: 'FETCH_USER_SUCCESS', payload: user }); | |
| } catch (error) { | |
| dispatch({ type: 'FETCH_USER_ERROR', payload: error.message }); | |
| } | |
| }; | |
| function UserProfile({ userId }) { | |
| const user = useSelector(state => state.user); | |
| const dispatch = useDispatch(); | |
| import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; | |
| import type { RootState, AppDispatch } from './store'; | |
| import { useEffect } from 'react'; | |
| import { useSelector, useDispatch } from 'react-redux'; | |
| import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; | |
| import type { RootState, AppDispatch } from './store'; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@extensions/react-redux-thunk/README.md` around lines 33 - 35, The README
example references useEffect but the top import block only imports react-redux
and Redux Toolkit symbols; update the imports to include useEffect from React
(e.g., add an import for useEffect from 'react' alongside the existing imports)
so the example that uses useEffect compiles; locate the import block containing
useSelector/useDispatch and add the useEffect symbol to the imports.
| // Create a slice | ||
| const userSlice = createSlice({ | ||
| name: 'user', | ||
| initialState: { data: null, loading: false }, | ||
| reducers: {}, | ||
| extraReducers: (builder) => { | ||
| builder | ||
| .addCase(fetchUser.pending, (state) => { state.loading = true; }) | ||
| .addCase(fetchUser.fulfilled, (state, action) => { | ||
| state.loading = false; | ||
| state.data = action.payload; | ||
| }); | ||
| }, | ||
| }); | ||
|
|
||
| // Use in components | ||
| function UserProfile({ userId }: { userId: string }) { | ||
| const user = useSelector((state: RootState) => state.user); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "README.md" -path "*/react-redux-thunk/*" | head -20Repository: Create-Node-App/cna-templates
Length of output: 113
🏁 Script executed:
cat -n ./extensions/react-redux-thunk/README.md | sed -n '40,70p'Repository: Create-Node-App/cna-templates
Length of output: 1023
🏁 Script executed:
cat -n ./extensions/react-redux-thunk/README.md | head -50Repository: Create-Node-App/cna-templates
Length of output: 2129
🏁 Script executed:
cat -n ./extensions/react-redux-thunk/README.md | sed -n '60,100p'Repository: Create-Node-App/cna-templates
Length of output: 630
🏁 Script executed:
cat -n ./extensions/react-redux-thunk/README.mdRepository: Create-Node-App/cna-templates
Length of output: 2969
Add slice registration step to complete the example.
The example creates userSlice and immediately uses state.user in the component, but doesn't show how to register the reducer. Without adding the slice to the root reducer via combineReducers, the selector would fail at runtime. Include the registration step so the example is complete and functional.
Suggested addition after the slice definition
const userSlice = createSlice({
name: 'user',
initialState: { data: null, loading: false },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => { state.loading = true; })
.addCase(fetchUser.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
});
},
});
+
+// Register in your root reducer:
+// const rootReducer = combineReducers({
+// user: userSlice.reducer,
+// });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Create a slice | |
| const userSlice = createSlice({ | |
| name: 'user', | |
| initialState: { data: null, loading: false }, | |
| reducers: {}, | |
| extraReducers: (builder) => { | |
| builder | |
| .addCase(fetchUser.pending, (state) => { state.loading = true; }) | |
| .addCase(fetchUser.fulfilled, (state, action) => { | |
| state.loading = false; | |
| state.data = action.payload; | |
| }); | |
| }, | |
| }); | |
| // Use in components | |
| function UserProfile({ userId }: { userId: string }) { | |
| const user = useSelector((state: RootState) => state.user); | |
| // Create a slice | |
| const userSlice = createSlice({ | |
| name: 'user', | |
| initialState: { data: null, loading: false }, | |
| reducers: {}, | |
| extraReducers: (builder) => { | |
| builder | |
| .addCase(fetchUser.pending, (state) => { state.loading = true; }) | |
| .addCase(fetchUser.fulfilled, (state, action) => { | |
| state.loading = false; | |
| state.data = action.payload; | |
| }); | |
| }, | |
| }); | |
| // Register in your root reducer: | |
| // const rootReducer = combineReducers({ | |
| // user: userSlice.reducer, | |
| // }); | |
| // Use in components | |
| function UserProfile({ userId }: { userId: string }) { | |
| const user = useSelector((state: RootState) => state.user); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@extensions/react-redux-thunk/README.md` around lines 43 - 60, Add the missing
slice registration so the example works: export the slice reducer from userSlice
(e.g., userSlice.reducer) and include it when building the root reducer (via
combineReducers) and store (e.g., configureStore/createStore) so RootState has a
user field; then update the example to import the store/provider or RootState
type accordingly so useSelector((state: RootState) => state.user) resolves at
runtime.
Remove react-easy-state (@risingstack/react-easy-state, abandoned since 2022) and react-global-state (react-hooks-global-state, abandoned since 2022) extensions entirely. Mark Teaful as deprecated in templates.json — only ~126 weekly npm downloads and pre-1.0 stability. Recoil was already marked deprecated in PR #60. Hookstate (74k downloads/week) and Million (31k downloads/week) are kept as healthy extensions.
Summary
Modernize
react-redux-thunkto use@reduxjs/toolkit(configureStore) instead of legacycreateStore+applyMiddlewareCombinedStateimport error (type removed in Redux 5.x) — root cause ofreact-vite-boilerplateCI failuresRootState/AppDispatchTypeScript typeswindow.__REDUX_DEVTOOLS_EXTENSION__)Modernize
react-redux-sagato use@reduxjs/toolkit+ saga middlewareCombinedStateand DevTools fixesmiddlewareoptionCleanup
react-ionic/directory (only contained.npmrc, not listed intemplates.json)templates.jsondescriptions for both Redux extensionsRe-enable
type-checkin CI — removes|| trueworkaround that was masking real TypeScript errorsTesting
CI will run the random template+extension combinations. The
react-vite-boilerplate+react-redux-thunkcombo that was previously failing should now pass.Summary by CodeRabbit
Bug Fixes
New Features
Updates
configureStoreand async handling patterns.