@depup/reduxjs__toolkit 2.12.0-depup.29 → 2.13.0-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +2 -2
  2. package/changes.json +1 -1
  3. package/dist/cjs/redux-toolkit.development.cjs +1755 -2247
  4. package/dist/cjs/redux-toolkit.development.cjs.map +1 -1
  5. package/dist/cjs/redux-toolkit.production.min.cjs +1 -2
  6. package/dist/cjs/redux-toolkit.production.min.cjs.map +1 -1
  7. package/dist/index.d.mts +1496 -1525
  8. package/dist/index.d.ts +1496 -1525
  9. package/dist/query/cjs/rtk-query.development.cjs +2059 -2990
  10. package/dist/query/cjs/rtk-query.development.cjs.map +1 -1
  11. package/dist/query/cjs/rtk-query.production.min.cjs +1 -1
  12. package/dist/query/cjs/rtk-query.production.min.cjs.map +1 -1
  13. package/dist/query/index.d.mts +2300 -2308
  14. package/dist/query/index.d.ts +2300 -2308
  15. package/dist/query/react/cjs/rtk-query-react.development.cjs +609 -714
  16. package/dist/query/react/cjs/rtk-query-react.development.cjs.map +1 -1
  17. package/dist/query/react/cjs/rtk-query-react.production.min.cjs +1 -1
  18. package/dist/query/react/cjs/rtk-query-react.production.min.cjs.map +1 -1
  19. package/dist/query/react/index.d.mts +516 -523
  20. package/dist/query/react/index.d.ts +516 -523
  21. package/dist/query/react/rtk-query-react.browser.mjs +1 -1
  22. package/dist/query/react/rtk-query-react.browser.mjs.map +1 -1
  23. package/dist/query/react/rtk-query-react.legacy-esm.js +672 -714
  24. package/dist/query/react/rtk-query-react.legacy-esm.js.map +1 -1
  25. package/dist/query/react/rtk-query-react.modern.mjs +586 -679
  26. package/dist/query/react/rtk-query-react.modern.mjs.map +1 -1
  27. package/dist/query/rtk-query.browser.mjs +1 -1
  28. package/dist/query/rtk-query.browser.mjs.map +1 -1
  29. package/dist/query/rtk-query.legacy-esm.js +2175 -3014
  30. package/dist/query/rtk-query.legacy-esm.js.map +1 -1
  31. package/dist/query/rtk-query.modern.mjs +2052 -2949
  32. package/dist/query/rtk-query.modern.mjs.map +1 -1
  33. package/dist/react/cjs/redux-toolkit-react.development.cjs +30 -51
  34. package/dist/react/cjs/redux-toolkit-react.development.cjs.map +1 -1
  35. package/dist/react/cjs/redux-toolkit-react.production.min.cjs +1 -1
  36. package/dist/react/cjs/redux-toolkit-react.production.min.cjs.map +1 -1
  37. package/dist/react/index.d.mts +12 -15
  38. package/dist/react/index.d.ts +12 -15
  39. package/dist/react/redux-toolkit-react.browser.mjs +1 -1
  40. package/dist/react/redux-toolkit-react.browser.mjs.map +1 -1
  41. package/dist/react/redux-toolkit-react.legacy-esm.js +83 -44
  42. package/dist/react/redux-toolkit-react.legacy-esm.js.map +1 -1
  43. package/dist/react/redux-toolkit-react.modern.mjs +23 -25
  44. package/dist/react/redux-toolkit-react.modern.mjs.map +1 -1
  45. package/dist/redux-toolkit.browser.mjs +1 -2
  46. package/dist/redux-toolkit.browser.mjs.map +1 -1
  47. package/dist/redux-toolkit.legacy-esm.js +1748 -2201
  48. package/dist/redux-toolkit.legacy-esm.js.map +1 -1
  49. package/dist/redux-toolkit.modern.mjs +1670 -2171
  50. package/dist/redux-toolkit.modern.mjs.map +1 -1
  51. package/package.json +13 -29
  52. package/skills/build-modern-redux-apps/modern-redux/SKILL.md +23 -14
  53. package/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md +6 -6
  54. package/skills/build-modern-redux-apps/redux-dataflow/SKILL.md +13 -10
  55. package/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md +6 -6
  56. package/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md +7 -8
  57. package/skills/manage-server-data/adopt-rtk-query/SKILL.md +13 -11
  58. package/skills/model-redux-state/build-slices-and-selectors/SKILL.md +26 -14
  59. package/skills/model-redux-state/design-state-ownership/SKILL.md +11 -12
  60. package/skills/model-redux-state/design-state-ownership/references/state-ownership.md +6 -6
  61. package/skills/orchestrate-side-effects/handle-side-effects/SKILL.md +27 -23
  62. package/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md +4 -4
  63. package/src/autoBatchEnhancer.ts +5 -3
  64. package/src/combineSlices.ts +5 -5
  65. package/src/createAction.ts +11 -6
  66. package/src/createAsyncThunk.ts +14 -2
  67. package/src/createReducer.ts +1 -1
  68. package/src/createSlice.ts +9 -4
  69. package/src/dynamicMiddleware/index.ts +21 -5
  70. package/src/entities/models.ts +2 -1
  71. package/src/entities/sorted_state_adapter.ts +35 -24
  72. package/src/entities/unsorted_state_adapter.ts +1 -1
  73. package/src/immutableStateInvariantMiddleware.ts +34 -5
  74. package/src/listenerMiddleware/types.ts +10 -10
  75. package/src/mapBuilders.ts +2 -5
  76. package/src/matchers.ts +7 -1
  77. package/src/query/core/apiState.ts +1 -1
  78. package/src/query/core/buildInitiate.ts +19 -15
  79. package/src/query/core/buildMiddleware/cacheLifecycle.ts +3 -1
  80. package/src/query/core/buildMiddleware/index.ts +1 -1
  81. package/src/query/core/buildMiddleware/invalidationByTags.ts +4 -1
  82. package/src/query/core/buildMiddleware/polling.ts +12 -3
  83. package/src/query/core/buildMiddleware/types.ts +5 -2
  84. package/src/query/core/buildSlice.ts +2 -2
  85. package/src/query/core/buildThunks.ts +19 -0
  86. package/src/query/core/module.ts +9 -3
  87. package/src/query/createApi.ts +4 -1
  88. package/src/query/endpointDefinitions.ts +15 -9
  89. package/src/query/fetchBaseQuery.ts +1 -1
  90. package/src/query/react/buildHooks.ts +54 -51
  91. package/src/query/react/namedHooks.ts +28 -24
  92. package/src/query/utils/isAbsoluteUrl.ts +8 -3
  93. package/src/serializableStateInvariantMiddleware.ts +1 -1
@@ -62,9 +62,8 @@ export type InjectConfig = {
62
62
  export interface CombinedSliceReducer<
63
63
  InitialState,
64
64
  DeclaredState extends InitialState = InitialState,
65
- PreloadedState extends Partial<
66
- Record<keyof PreloadedState, any>
67
- > = Partial<DeclaredState>,
65
+ PreloadedState extends Partial<Record<keyof PreloadedState, any>> =
66
+ Partial<DeclaredState>,
68
67
  > extends Reducer<DeclaredState, UnknownAction, PreloadedState> {
69
68
  /**
70
69
  * Provide a type for slices that will be injected lazily.
@@ -354,9 +353,8 @@ const ORIGINAL_STATE = Symbol.for('rtk-state-proxy-original')
354
353
 
355
354
  const isStateProxy = (value: any) => !!value && !!value[ORIGINAL_STATE]
356
355
 
357
- const stateProxyMap = new WeakMap<object, object>()
358
-
359
356
  const createStateProxy = <State extends object>(
357
+ stateProxyMap: WeakMap<object, object>,
360
358
  state: State,
361
359
  reducerMap: Partial<Record<PropertyKey, Reducer>>,
362
360
  initialStateCache: Record<PropertyKey, unknown>,
@@ -411,6 +409,7 @@ export function combineSlices<Slices extends Array<AnySliceLike | ReducerMap>>(
411
409
  Id<InitialState<Slices>>,
412
410
  Partial<Id<InitialPreloadedState<Slices>>>
413
411
  > {
412
+ const stateProxyMap = new WeakMap<object, object>()
414
413
  const reducerMap = Object.fromEntries(getReducers(slices))
415
414
 
416
415
  const getReducer = () =>
@@ -472,6 +471,7 @@ export function combineSlices<Slices extends Array<AnySliceLike | ReducerMap>>(
472
471
  return function selector(state: State, ...args: Args) {
473
472
  return selectorFn(
474
473
  createStateProxy(
474
+ stateProxyMap,
475
475
  selectState ? selectState(state as any, ...args) : state,
476
476
  reducerMap,
477
477
  initialStateCache,
@@ -122,8 +122,10 @@ export interface ActionCreatorWithPreparedPayload<
122
122
  *
123
123
  * @public
124
124
  */
125
- export interface ActionCreatorWithOptionalPayload<P, T extends string = string>
126
- extends BaseActionCreator<P, T> {
125
+ export interface ActionCreatorWithOptionalPayload<
126
+ P,
127
+ T extends string = string,
128
+ > extends BaseActionCreator<P, T> {
127
129
  /**
128
130
  * Calling this {@link redux#ActionCreator} with an argument will
129
131
  * return a {@link PayloadAction} of type `T` with a payload of `P`.
@@ -139,8 +141,9 @@ export interface ActionCreatorWithOptionalPayload<P, T extends string = string>
139
141
  *
140
142
  * @public
141
143
  */
142
- export interface ActionCreatorWithoutPayload<T extends string = string>
143
- extends BaseActionCreator<undefined, T> {
144
+ export interface ActionCreatorWithoutPayload<
145
+ T extends string = string,
146
+ > extends BaseActionCreator<undefined, T> {
144
147
  /**
145
148
  * Calling this {@link redux#ActionCreator} will
146
149
  * return a {@link PayloadAction} of type `T` with a payload of `undefined`
@@ -155,8 +158,10 @@ export interface ActionCreatorWithoutPayload<T extends string = string>
155
158
  *
156
159
  * @public
157
160
  */
158
- export interface ActionCreatorWithPayload<P, T extends string = string>
159
- extends BaseActionCreator<P, T> {
161
+ export interface ActionCreatorWithPayload<
162
+ P,
163
+ T extends string = string,
164
+ > extends BaseActionCreator<P, T> {
160
165
  /**
161
166
  * Calling this {@link redux#ActionCreator} with an argument will
162
167
  * return a {@link PayloadAction} of type `T` with a payload of `P`
@@ -590,7 +590,7 @@ export const createAsyncThunk = /* @__PURE__ */ (() => {
590
590
  ...((meta as any) || {}),
591
591
  arg,
592
592
  requestId,
593
- rejectedWithValue: !!payload,
593
+ rejectedWithValue: payload !== undefined,
594
594
  requestStatus: 'rejected' as const,
595
595
  aborted: error?.name === 'AbortError',
596
596
  condition: error?.name === 'ConditionError',
@@ -636,13 +636,25 @@ export const createAsyncThunk = /* @__PURE__ */ (() => {
636
636
  conditionResult = await conditionResult
637
637
  }
638
638
 
639
- if (conditionResult === false || abortController.signal.aborted) {
639
+ if (conditionResult === false) {
640
640
  // eslint-disable-next-line no-throw-literal
641
641
  throw {
642
642
  name: 'ConditionError',
643
643
  message: 'Aborted due to condition callback returning false.',
644
644
  }
645
645
  }
646
+ if (abortController.signal.aborted) {
647
+ // The request was aborted (e.g. via an already-aborted external
648
+ // signal, or `abort()` called during an async `condition`) before
649
+ // the `pending` action was dispatched. Treat this as an abort
650
+ // rather than a condition rejection, so the reason is preserved
651
+ // and the `rejected` action is not silently swallowed.
652
+ // eslint-disable-next-line no-throw-literal
653
+ throw {
654
+ name: 'AbortError',
655
+ message: abortReason || 'Aborted',
656
+ }
657
+ }
646
658
 
647
659
  const abortedPromise = new Promise<never>((_, reject) => {
648
660
  abortHandler = () => {
@@ -191,7 +191,7 @@ export function createReducer<S extends NotFunction<any>>(
191
191
  if (previousState === null) {
192
192
  return previousState
193
193
  }
194
- throw Error(
194
+ throw new Error(
195
195
  'A case reducer on a non-draftable value must not return undefined',
196
196
  )
197
197
  }
@@ -298,7 +298,9 @@ export type CaseReducerWithPrepare<State, Action extends PayloadAction> = {
298
298
  export interface CaseReducerWithPrepareDefinition<
299
299
  State,
300
300
  Action extends PayloadAction,
301
- > extends CaseReducerWithPrepare<State, Action>,
301
+ >
302
+ extends
303
+ CaseReducerWithPrepare<State, Action>,
302
304
  ReducerDefinition<ReducerType.reducerWithPrepare> {}
303
305
 
304
306
  type AsyncThunkSliceReducerConfig<
@@ -331,8 +333,8 @@ type PreventCircular<ThunkApiConfig> = {
331
333
 
332
334
  interface AsyncThunkCreator<
333
335
  State,
334
- CurriedThunkApiConfig extends
335
- PreventCircular<AsyncThunkConfig> = PreventCircular<AsyncThunkConfig>,
336
+ CurriedThunkApiConfig extends PreventCircular<AsyncThunkConfig> =
337
+ PreventCircular<AsyncThunkConfig>,
336
338
  > {
337
339
  <Returned, ThunkArg = void>(
338
340
  payloadCreator: AsyncThunkPayloadCreator<
@@ -807,7 +809,10 @@ export function buildCreateSlice({ creators }: BuildCreateSliceConfig = {}) {
807
809
  caseReducers: context.sliceCaseReducersByName as any,
808
810
  getInitialState,
809
811
  ...makeSelectorProps(reducerPath),
810
- injectInto(injectable, { reducerPath: pathOpt, ...config } = {}) {
812
+ injectInto(
813
+ injectable,
814
+ { reducerPath: pathOpt, ...config }: InjectIntoConfig<string> = {},
815
+ ) {
811
816
  const newReducerPath = pathOpt ?? reducerPath
812
817
  injectable.inject({ reducerPath: newReducerPath, reducer }, config)
813
818
  return {
@@ -41,6 +41,7 @@ export const createDynamicMiddleware = <
41
41
  Middleware<any, State, DispatchType>,
42
42
  MiddlewareEntry<State, DispatchType>
43
43
  >()
44
+ let middlewareVersion = 0
44
45
 
45
46
  const withMiddleware = Object.assign(
46
47
  createAction(
@@ -59,9 +60,13 @@ export const createDynamicMiddleware = <
59
60
  function addMiddleware(
60
61
  ...middlewares: Middleware<any, State, DispatchType>[]
61
62
  ) {
63
+ const previousSize = middlewareMap.size
62
64
  middlewares.forEach((middleware) => {
63
65
  getOrInsertComputed(middlewareMap, middleware, createMiddlewareEntry)
64
66
  })
67
+ if (middlewareMap.size !== previousSize) {
68
+ middlewareVersion++
69
+ }
65
70
  },
66
71
  { withTypes: () => addMiddleware },
67
72
  ) as AddMiddleware<State, DispatchType>
@@ -76,12 +81,23 @@ export const createDynamicMiddleware = <
76
81
  const isWithMiddleware = isAllOf(withMiddleware, matchInstance(instanceId))
77
82
 
78
83
  const middleware: DynamicMiddleware<State, DispatchType> =
79
- (api) => (next) => (action) => {
80
- if (isWithMiddleware(action)) {
81
- addMiddleware(...action.payload)
82
- return api.dispatch
84
+ (api) => (next) => {
85
+ let appliedVersion = -1
86
+ let dispatch = next
87
+
88
+ return (action) => {
89
+ if (isWithMiddleware(action)) {
90
+ addMiddleware(...action.payload)
91
+ return api.dispatch
92
+ }
93
+
94
+ if (appliedVersion !== middlewareVersion) {
95
+ dispatch = getFinalMiddleware(api)(next)
96
+ appliedVersion = middlewareVersion
97
+ }
98
+
99
+ return dispatch(action)
83
100
  }
84
- return getFinalMiddleware(api)(next)(action)
85
101
  }
86
102
 
87
103
  return {
@@ -184,7 +184,8 @@ export interface EntityStateFactory<T, Id extends EntityId> {
184
184
  * @public
185
185
  */
186
186
  export interface EntityAdapter<T, Id extends EntityId>
187
- extends EntityStateAdapter<T, Id>,
187
+ extends
188
+ EntityStateAdapter<T, Id>,
188
189
  EntityStateFactory<T, Id>,
189
190
  Required<EntityAdapterOptions<T, Id>> {
190
191
  getSelectors(
@@ -70,15 +70,13 @@ export function createSortedStateAdapter<T, Id extends EntityId>(
70
70
  newEntities = ensureEntitiesArray(newEntities)
71
71
 
72
72
  const existingKeys = new Set<Id>(existingIds ?? getCurrent(state.ids))
73
- const addedKeys = new Set<Id>();
74
- const models = newEntities.filter(
75
- (model) => {
76
- const modelId = selectIdValue(model, selectId);
77
- const notAdded = !addedKeys.has(modelId);
78
- if (notAdded) addedKeys.add(modelId);
79
- return !existingKeys.has(modelId) && notAdded;
80
- }
81
- )
73
+ const addedKeys = new Set<Id>()
74
+ const models = newEntities.filter((model) => {
75
+ const modelId = selectIdValue(model, selectId)
76
+ const notAdded = !addedKeys.has(modelId)
77
+ if (notAdded) addedKeys.add(modelId)
78
+ return !existingKeys.has(modelId) && notAdded
79
+ })
82
80
 
83
81
  if (models.length !== 0) {
84
82
  mergeFunction(state, models)
@@ -93,16 +91,16 @@ export function createSortedStateAdapter<T, Id extends EntityId>(
93
91
  newEntities: readonly T[] | Record<Id, T>,
94
92
  state: R,
95
93
  ): void {
96
- let deduplicatedEntities = {} as Record<Id, T>;
94
+ let deduplicatedEntities = {} as Record<Id, T>
97
95
  newEntities = ensureEntitiesArray(newEntities)
98
96
  if (newEntities.length !== 0) {
99
97
  for (const item of newEntities) {
100
- const entityId = selectId(item);
98
+ const entityId = selectId(item)
101
99
  // For multiple items with the same ID, we should keep the last one.
102
- deduplicatedEntities[entityId] = item;
100
+ deduplicatedEntities[entityId] = item
103
101
  delete (state.entities as Record<Id, T>)[entityId]
104
102
  }
105
- newEntities = ensureEntitiesArray(deduplicatedEntities);
103
+ newEntities = ensureEntitiesArray(deduplicatedEntities)
106
104
  mergeFunction(state, newEntities)
107
105
  }
108
106
  }
@@ -115,7 +113,7 @@ export function createSortedStateAdapter<T, Id extends EntityId>(
115
113
  state.entities = {} as Record<Id, T>
116
114
  state.ids = []
117
115
 
118
- addManyMutably(newEntities, state, [])
116
+ setManyMutably(newEntities, state)
119
117
  }
120
118
 
121
119
  function updateOneMutably(update: Update<T, Id>, state: R): void {
@@ -129,7 +127,27 @@ export function createSortedStateAdapter<T, Id extends EntityId>(
129
127
  let appliedUpdates = false
130
128
  let replacedIds = false
131
129
 
132
- for (let update of updates) {
130
+ // Pre-merge all updates that target the same entity ID so that later
131
+ // changes always win for every field—including `id`. Without this step,
132
+ // the first rename moves the entity to a new key; a subsequent update that
133
+ // still targets the original key finds nothing and is silently dropped,
134
+ // producing results inconsistent with the unsorted adapter.
135
+ const updatesPerEntity: { [id: string]: Update<T, Id> } = {}
136
+ for (const update of updates) {
137
+ // Only collect updates for entities that currently exist (same guard
138
+ // used by the unsorted adapter).
139
+ if (update.id in (state.entities as Record<Id, T>)) {
140
+ updatesPerEntity[update.id] = {
141
+ id: update.id,
142
+ changes: {
143
+ ...updatesPerEntity[update.id]?.changes,
144
+ ...update.changes,
145
+ },
146
+ }
147
+ }
148
+ }
149
+
150
+ for (const update of Object.values(updatesPerEntity) as Update<T, Id>[]) {
133
151
  const entity: T | undefined = (state.entities as Record<Id, T>)[update.id]
134
152
  if (!entity) {
135
153
  continue
@@ -192,19 +210,12 @@ export function createSortedStateAdapter<T, Id extends EntityId>(
192
210
  return true
193
211
  }
194
212
 
195
- type MergeFunction = (
213
+ function mergeFunction(
196
214
  state: R,
197
215
  addedItems: readonly T[],
198
216
  appliedUpdates?: boolean,
199
217
  replacedIds?: boolean,
200
- ) => void
201
-
202
- const mergeFunction: MergeFunction = (
203
- state,
204
- addedItems,
205
- appliedUpdates,
206
- replacedIds,
207
- ) => {
218
+ ): void {
208
219
  const currentEntities = getCurrent(state.entities)
209
220
  const currentIds = getCurrent(state.ids)
210
221
 
@@ -70,7 +70,7 @@ export function createUnsortedStateAdapter<T, Id extends EntityId>(
70
70
  state.ids = []
71
71
  state.entities = {} as Record<Id, T>
72
72
 
73
- addManyMutably(newEntities, state)
73
+ setManyMutably(newEntities, state)
74
74
  }
75
75
 
76
76
  function removeOneMutably(key: Id, state: R): void {
@@ -36,13 +36,20 @@ function trackProperties(
36
36
  ignoredPaths: IgnoredPaths = [],
37
37
  obj: Record<string, any>,
38
38
  path: string = '',
39
- checkedObjects: Set<Record<string, any>> = new Set(),
39
+ inProgress: Map<Record<string, any>, TrackedProperty> = new Map(),
40
40
  ) {
41
41
  const tracked: Partial<TrackedProperty> = { value: obj }
42
42
 
43
- if (!isImmutable(obj) && !checkedObjects.has(obj)) {
44
- checkedObjects.add(obj)
43
+ if (!isImmutable(obj)) {
44
+ // An object already being tracked further up the stack contains itself
45
+ const alreadyInProgress = inProgress.get(obj)
46
+ if (alreadyInProgress) {
47
+ return alreadyInProgress
48
+ }
49
+
45
50
  tracked.children = {}
51
+ // Registered before walking children, so a circular reference finds it
52
+ inProgress.set(obj, tracked as TrackedProperty)
46
53
 
47
54
  const hasIgnoredPaths = ignoredPaths.length > 0
48
55
 
@@ -66,8 +73,11 @@ function trackProperties(
66
73
  ignoredPaths,
67
74
  obj[key],
68
75
  nestedPath,
76
+ inProgress,
69
77
  )
70
78
  }
79
+
80
+ inProgress.delete(obj)
71
81
  }
72
82
  return tracked as TrackedProperty
73
83
  }
@@ -79,6 +89,7 @@ function detectMutations(
79
89
  obj: any,
80
90
  sameParentRef: boolean = false,
81
91
  path: string = '',
92
+ seen: Map<TrackedProperty, Set<unknown>> = new Map(),
82
93
  ): { wasMutated: boolean; path?: string } {
83
94
  const prevObj = trackedProperty ? trackedProperty.value : undefined
84
95
 
@@ -92,6 +103,18 @@ function detectMutations(
92
103
  return { wasMutated: false }
93
104
  }
94
105
 
106
+ // Compare each (tracked node, value) pair once, so cycles terminate
107
+ let seenValues = seen.get(trackedProperty)
108
+
109
+ if (!seenValues) {
110
+ seenValues = new Set()
111
+ seen.set(trackedProperty, seenValues)
112
+ } else if (seenValues.has(obj)) {
113
+ return { wasMutated: false }
114
+ }
115
+
116
+ seenValues.add(obj)
117
+
95
118
  // Gather all keys from prev (tracked) and after objs
96
119
  const keysToDetect: Record<string, boolean> = {}
97
120
  for (let key in trackedProperty.children) {
@@ -125,6 +148,7 @@ function detectMutations(
125
148
  obj[key],
126
149
  sameRef,
127
150
  nestedPath,
151
+ seen,
128
152
  )
129
153
 
130
154
  if (result.wasMutated) {
@@ -201,8 +225,13 @@ export function createImmutableStateInvariantMiddleware(
201
225
  return function (this: any, key: string, value: any) {
202
226
  if (stack.length > 0) {
203
227
  var thisPos = stack.indexOf(this)
204
- ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
205
- ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
228
+ if (~thisPos) {
229
+ stack.splice(thisPos + 1)
230
+ keys.splice(thisPos, Infinity, key)
231
+ } else {
232
+ stack.push(this)
233
+ keys.push(key)
234
+ }
206
235
  if (~stack.indexOf(value)) value = decycler!.call(this, key, value)
207
236
  } else stack.push(value)
208
237
 
@@ -36,7 +36,6 @@ export type ListenerPredicate<ActionType extends Action, State> = (
36
36
 
37
37
  /** @public */
38
38
  export interface ConditionFunction<State> {
39
- (predicate: AnyListenerPredicate<State>, timeout?: number): Promise<boolean>
40
39
  (predicate: AnyListenerPredicate<State>, timeout?: number): Promise<boolean>
41
40
  (predicate: () => boolean, timeout?: number): Promise<boolean>
42
41
  }
@@ -157,7 +156,7 @@ export interface ListenerEffectAPI<
157
156
  *
158
157
  * setTimeout(getOriginalState, 0); // async: throws Error
159
158
  *
160
- * await Promise().resolve();
159
+ * await Promise.resolve();
161
160
  *
162
161
  * getOriginalState(); // async: throws Error
163
162
  * },
@@ -324,11 +323,8 @@ export type ListenerMiddleware<
324
323
  /** @public */
325
324
  export interface ListenerMiddlewareInstance<
326
325
  StateType = unknown,
327
- DispatchType extends ThunkDispatch<
328
- StateType,
329
- unknown,
330
- Action
331
- > = ThunkDispatch<StateType, unknown, UnknownAction>,
326
+ DispatchType extends ThunkDispatch<StateType, unknown, Action> =
327
+ ThunkDispatch<StateType, unknown, UnknownAction>,
332
328
  ExtraArgument = unknown,
333
329
  > {
334
330
  middleware: ListenerMiddleware<StateType, DispatchType, ExtraArgument>
@@ -833,7 +829,7 @@ export type TypedCreateListenerEntry<
833
829
  UnknownAction
834
830
  >,
835
831
  OverrideExtraArgument = unknown,
836
- >() => TypedStopListening<
832
+ >() => TypedCreateListenerEntry<
837
833
  OverrideStateType,
838
834
  OverrideDispatchType,
839
835
  OverrideExtraArgument
@@ -870,14 +866,18 @@ export type FallbackAddListenerOptions = {
870
866
  type?: string
871
867
  matcher?: MatchFunction<any>
872
868
  predicate?: ListenerPredicate<any, any>
873
- } & { effect: ListenerEffect<any, any, any> }
869
+ effect: ListenerEffect<any, any, any>
870
+ }
874
871
 
875
872
  /**
876
873
  * Utility Types
877
874
  */
878
875
 
879
876
  /** @public */
880
- export type GuardedType<T> = T extends (x: any, ...args: any[]) => x is infer T
877
+ export type GuardedType<T> = T extends ((
878
+ x: any,
879
+ ...args: any[]
880
+ ) => x is infer T)
881
881
  ? T
882
882
  : never
883
883
 
@@ -200,7 +200,7 @@ export function executeReducerBuilderCallback<S>(
200
200
  const actionsMap: CaseReducers<S, any> = {}
201
201
  const actionMatchers: ActionMatcherDescriptionCollection<S> = []
202
202
  let defaultCaseReducer: CaseReducer<S, Action> | undefined
203
- const builder = {
203
+ const builder: ActionReducerMapBuilder<S> = {
204
204
  addCase(
205
205
  typeOrActionCreator: string | TypedActionCreator<any>,
206
206
  reducer: CaseReducer<S>,
@@ -269,10 +269,7 @@ export function executeReducerBuilderCallback<S>(
269
269
  })
270
270
  return builder
271
271
  },
272
- addMatcher<A>(
273
- matcher: TypeGuard<A>,
274
- reducer: CaseReducer<S, A extends Action ? A : A & Action>,
275
- ) {
272
+ addMatcher(matcher: TypeGuard<any>, reducer: CaseReducer<S, any>) {
276
273
  if (process.env.NODE_ENV !== 'production') {
277
274
  if (defaultCaseReducer) {
278
275
  throw new Error(
package/src/matchers.ts CHANGED
@@ -361,5 +361,11 @@ export function isAsyncThunkAction<
361
361
  return isAsyncThunkAction()(asyncThunks[0])
362
362
  }
363
363
 
364
- return isAnyOf(...asyncThunks.flatMap(asyncThunk => [asyncThunk.pending, asyncThunk.rejected, asyncThunk.fulfilled]))
364
+ return isAnyOf(
365
+ ...asyncThunks.flatMap((asyncThunk) => [
366
+ asyncThunk.pending,
367
+ asyncThunk.rejected,
368
+ asyncThunk.fulfilled,
369
+ ]),
370
+ )
365
371
  }
@@ -354,7 +354,7 @@ export type SubscriptionState = {
354
354
  [queryCacheKey: string]: Subscribers | undefined
355
355
  }
356
356
 
357
- export type ConfigState<ReducerPath> = RefetchConfigOptions & {
357
+ export type ConfigState<ReducerPath> = {
358
358
  reducerPath: ReducerPath
359
359
  online: boolean
360
360
  focused: boolean
@@ -13,7 +13,6 @@ import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
13
13
  import {
14
14
  ENDPOINT_QUERY,
15
15
  isQueryDefinition,
16
- type EndpointDefinition,
17
16
  type EndpointDefinitions,
18
17
  type InfiniteQueryArgFrom,
19
18
  type InfiniteQueryDefinition,
@@ -96,7 +95,7 @@ export type StartInfiniteQueryActionCreatorOptions<
96
95
  >
97
96
  >
98
97
 
99
- type AnyQueryActionCreator<D extends EndpointDefinition<any, any, any, any>> = (
98
+ type AnyQueryActionCreator = (
100
99
  arg: any,
101
100
  options?: StartQueryActionCreatorOptions,
102
101
  ) => ThunkAction<AnyActionCreatorResult, any, any, UnknownAction>
@@ -154,20 +153,22 @@ export type InfiniteQueryActionCreatorResult<
154
153
  ): InfiniteQueryActionCreatorResult<D>
155
154
  }
156
155
 
156
+ type StartMutationActionCreatorOptions = {
157
+ /**
158
+ * If this mutation should be tracked in the store.
159
+ * If you just want to manually trigger this mutation using `dispatch` and don't care about the
160
+ * result, state & potential errors being held in store, you can set this to false.
161
+ * (defaults to `true`)
162
+ */
163
+ track?: boolean
164
+ fixedCacheKey?: string
165
+ }
166
+
157
167
  type StartMutationActionCreator<
158
168
  D extends MutationDefinition<any, any, any, any>,
159
169
  > = (
160
170
  arg: QueryArgFrom<D>,
161
- options?: {
162
- /**
163
- * If this mutation should be tracked in the store.
164
- * If you just want to manually trigger this mutation using `dispatch` and don't care about the
165
- * result, state & potential errors being held in store, you can set this to false.
166
- * (defaults to `true`)
167
- */
168
- track?: boolean
169
- fixedCacheKey?: string
170
- },
171
+ options?: StartMutationActionCreatorOptions,
171
172
  ) => ThunkAction<MutationActionCreatorResult<D>, any, any, UnknownAction>
172
173
 
173
174
  export type MutationActionCreatorResult<
@@ -381,7 +382,7 @@ You must add the middleware for RTK-Query to function correctly!`,
381
382
  | QueryDefinition<any, any, any, any>
382
383
  | InfiniteQueryDefinition<any, any, any, any, any>,
383
384
  ) {
384
- const queryAction: AnyQueryActionCreator<any> =
385
+ const queryAction: AnyQueryActionCreator =
385
386
  (
386
387
  arg,
387
388
  {
@@ -390,7 +391,7 @@ You must add the middleware for RTK-Query to function correctly!`,
390
391
  subscriptionOptions,
391
392
  [forceQueryFnSymbol]: forceQueryFn,
392
393
  ...rest
393
- } = {},
394
+ }: StartQueryActionCreatorOptions = {},
394
395
  ) =>
395
396
  (dispatch, getState) => {
396
397
  const queryCacheKey = serializeQueryArgs({
@@ -546,7 +547,10 @@ You must add the middleware for RTK-Query to function correctly!`,
546
547
  function buildInitiateMutation(
547
548
  endpointName: string,
548
549
  ): StartMutationActionCreator<any> {
549
- return (arg, { track = true, fixedCacheKey } = {}) =>
550
+ return (
551
+ arg,
552
+ { track = true, fixedCacheKey }: StartMutationActionCreatorOptions = {},
553
+ ) =>
550
554
  (dispatch, getState) => {
551
555
  const thunk = mutationThunk({
552
556
  type: 'mutation',
@@ -129,7 +129,9 @@ export interface QueryCacheLifecycleApi<
129
129
  BaseQuery extends BaseQueryFn,
130
130
  ResultType,
131
131
  ReducerPath extends string = string,
132
- > extends QueryBaseLifecycleApi<QueryArg, BaseQuery, ResultType, ReducerPath>,
132
+ >
133
+ extends
134
+ QueryBaseLifecycleApi<QueryArg, BaseQuery, ResultType, ReducerPath>,
133
135
  CacheLifecyclePromises<ResultType, BaseQueryMeta<BaseQuery>> {}
134
136
 
135
137
  export type MutationCacheLifecycleApi<
@@ -118,7 +118,7 @@ export function buildMiddleware<
118
118
  res = internalProbeResult
119
119
  }
120
120
 
121
- if (!!mwApi.getState()[reducerPath]) {
121
+ if (mwApi.getState()[reducerPath]) {
122
122
  // Only run these checks if the middleware is registered okay
123
123
 
124
124
  // This looks for actions that aren't specific to the API slice
@@ -53,7 +53,10 @@ export const buildInvalidationByTagsHandler: InternalHandlerBuilder = ({
53
53
  pendingRequestCount++
54
54
  }
55
55
 
56
- if (isQueryEnd(action)) {
56
+ if (
57
+ isQueryEnd(action) &&
58
+ !(queryThunk.rejected.match(action) && action.meta.condition)
59
+ ) {
57
60
  pendingRequestCount = Math.max(0, pendingRequestCount - 1)
58
61
  }
59
62
 
@@ -102,8 +102,17 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
102
102
  nextPollTimestamp,
103
103
  pollingInterval: lowestPollingInterval,
104
104
  timeout: setTimeout(() => {
105
- if (state.config.focused || !skipPollingIfUnfocused) {
106
- api.dispatch(refetchQuery(querySubState))
105
+ const currentState = api.getState()[reducerPath]
106
+ const currentQuerySubState = currentState.queries[queryCacheKey]
107
+ if (
108
+ !currentQuerySubState ||
109
+ currentQuerySubState.status === STATUS_UNINITIALIZED
110
+ ) {
111
+ cleanupPollForKey(queryCacheKey)
112
+ return
113
+ }
114
+ if (currentState.config.focused || !skipPollingIfUnfocused) {
115
+ api.dispatch(refetchQuery(currentQuerySubState))
107
116
  }
108
117
  startNextPoll({ queryCacheKey }, api)
109
118
  }, lowestPollingInterval),
@@ -167,7 +176,7 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
167
176
  let lowestPollingInterval = Number.POSITIVE_INFINITY
168
177
 
169
178
  for (const entry of subscribers.values()) {
170
- if (!!entry.pollingInterval) {
179
+ if (entry.pollingInterval) {
171
180
  lowestPollingInterval = Math.min(
172
181
  entry.pollingInterval!,
173
182
  lowestPollingInterval,