@depup/reduxjs__toolkit 2.12.0-depup.28

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 (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/changes.json +18 -0
  4. package/dist/cjs/index.js +6 -0
  5. package/dist/cjs/redux-toolkit.development.cjs +2406 -0
  6. package/dist/cjs/redux-toolkit.development.cjs.map +1 -0
  7. package/dist/cjs/redux-toolkit.production.min.cjs +3 -0
  8. package/dist/cjs/redux-toolkit.production.min.cjs.map +1 -0
  9. package/dist/index.d.mts +2665 -0
  10. package/dist/index.d.ts +2665 -0
  11. package/dist/query/cjs/index.js +6 -0
  12. package/dist/query/cjs/rtk-query.development.cjs +3092 -0
  13. package/dist/query/cjs/rtk-query.development.cjs.map +1 -0
  14. package/dist/query/cjs/rtk-query.production.min.cjs +2 -0
  15. package/dist/query/cjs/rtk-query.production.min.cjs.map +1 -0
  16. package/dist/query/index.d.mts +3066 -0
  17. package/dist/query/index.d.ts +3066 -0
  18. package/dist/query/react/cjs/index.js +6 -0
  19. package/dist/query/react/cjs/rtk-query-react.development.cjs +748 -0
  20. package/dist/query/react/cjs/rtk-query-react.development.cjs.map +1 -0
  21. package/dist/query/react/cjs/rtk-query-react.production.min.cjs +2 -0
  22. package/dist/query/react/cjs/rtk-query-react.production.min.cjs.map +1 -0
  23. package/dist/query/react/index.d.mts +1009 -0
  24. package/dist/query/react/index.d.ts +1009 -0
  25. package/dist/query/react/rtk-query-react.browser.mjs +2 -0
  26. package/dist/query/react/rtk-query-react.browser.mjs.map +1 -0
  27. package/dist/query/react/rtk-query-react.legacy-esm.js +740 -0
  28. package/dist/query/react/rtk-query-react.legacy-esm.js.map +1 -0
  29. package/dist/query/react/rtk-query-react.modern.mjs +705 -0
  30. package/dist/query/react/rtk-query-react.modern.mjs.map +1 -0
  31. package/dist/query/rtk-query.browser.mjs +2 -0
  32. package/dist/query/rtk-query.browser.mjs.map +1 -0
  33. package/dist/query/rtk-query.legacy-esm.js +3117 -0
  34. package/dist/query/rtk-query.legacy-esm.js.map +1 -0
  35. package/dist/query/rtk-query.modern.mjs +3052 -0
  36. package/dist/query/rtk-query.modern.mjs.map +1 -0
  37. package/dist/react/cjs/index.js +6 -0
  38. package/dist/react/cjs/redux-toolkit-react.development.cjs +55 -0
  39. package/dist/react/cjs/redux-toolkit-react.development.cjs.map +1 -0
  40. package/dist/react/cjs/redux-toolkit-react.production.min.cjs +2 -0
  41. package/dist/react/cjs/redux-toolkit-react.production.min.cjs.map +1 -0
  42. package/dist/react/index.d.mts +22 -0
  43. package/dist/react/index.d.ts +22 -0
  44. package/dist/react/redux-toolkit-react.browser.mjs +2 -0
  45. package/dist/react/redux-toolkit-react.browser.mjs.map +1 -0
  46. package/dist/react/redux-toolkit-react.legacy-esm.js +47 -0
  47. package/dist/react/redux-toolkit-react.legacy-esm.js.map +1 -0
  48. package/dist/react/redux-toolkit-react.modern.mjs +28 -0
  49. package/dist/react/redux-toolkit-react.modern.mjs.map +1 -0
  50. package/dist/redux-toolkit.browser.mjs +3 -0
  51. package/dist/redux-toolkit.browser.mjs.map +1 -0
  52. package/dist/redux-toolkit.legacy-esm.js +2351 -0
  53. package/dist/redux-toolkit.legacy-esm.js.map +1 -0
  54. package/dist/redux-toolkit.modern.mjs +2330 -0
  55. package/dist/redux-toolkit.modern.mjs.map +1 -0
  56. package/dist/uncheckedindexed.ts +16 -0
  57. package/package.json +310 -0
  58. package/query/package.json +13 -0
  59. package/query/react/package.json +13 -0
  60. package/react/package.json +13 -0
  61. package/skills/build-modern-redux-apps/modern-redux/SKILL.md +304 -0
  62. package/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md +53 -0
  63. package/skills/build-modern-redux-apps/redux-dataflow/SKILL.md +264 -0
  64. package/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md +269 -0
  65. package/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md +226 -0
  66. package/skills/manage-server-data/adopt-rtk-query/SKILL.md +385 -0
  67. package/skills/manage-server-data/adopt-rtk-query/references/endpoint-lifecycle.md +36 -0
  68. package/skills/model-redux-state/build-slices-and-selectors/SKILL.md +364 -0
  69. package/skills/model-redux-state/build-slices-and-selectors/references/slice-patterns.md +59 -0
  70. package/skills/model-redux-state/design-state-ownership/SKILL.md +322 -0
  71. package/skills/model-redux-state/design-state-ownership/references/state-ownership.md +28 -0
  72. package/skills/orchestrate-side-effects/handle-side-effects/SKILL.md +271 -0
  73. package/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md +34 -0
  74. package/src/actionCreatorInvariantMiddleware.ts +34 -0
  75. package/src/autoBatchEnhancer.ts +146 -0
  76. package/src/combineSlices.ts +487 -0
  77. package/src/configureStore.ts +248 -0
  78. package/src/createAction.ts +324 -0
  79. package/src/createAsyncThunk.ts +791 -0
  80. package/src/createDraftSafeSelector.ts +30 -0
  81. package/src/createReducer.ts +217 -0
  82. package/src/createSlice.ts +1079 -0
  83. package/src/devtoolsExtension.ts +241 -0
  84. package/src/dynamicMiddleware/index.ts +93 -0
  85. package/src/dynamicMiddleware/react/index.ts +101 -0
  86. package/src/dynamicMiddleware/types.ts +82 -0
  87. package/src/entities/create_adapter.ts +47 -0
  88. package/src/entities/entity_state.ts +38 -0
  89. package/src/entities/index.ts +8 -0
  90. package/src/entities/models.ts +198 -0
  91. package/src/entities/sorted_state_adapter.ts +266 -0
  92. package/src/entities/state_adapter.ts +58 -0
  93. package/src/entities/state_selectors.ts +73 -0
  94. package/src/entities/unsorted_state_adapter.ts +204 -0
  95. package/src/entities/utils.ts +68 -0
  96. package/src/formatProdErrorMessage.ts +13 -0
  97. package/src/getDefaultEnhancers.ts +31 -0
  98. package/src/getDefaultMiddleware.ts +113 -0
  99. package/src/immerImports.ts +7 -0
  100. package/src/immutableStateInvariantMiddleware.ts +274 -0
  101. package/src/index.ts +213 -0
  102. package/src/listenerMiddleware/exceptions.ts +20 -0
  103. package/src/listenerMiddleware/index.ts +562 -0
  104. package/src/listenerMiddleware/task.ts +100 -0
  105. package/src/listenerMiddleware/types.ts +886 -0
  106. package/src/listenerMiddleware/utils.ts +30 -0
  107. package/src/mapBuilders.ts +298 -0
  108. package/src/matchers.ts +365 -0
  109. package/src/nanoid.ts +20 -0
  110. package/src/query/HandledError.ts +6 -0
  111. package/src/query/apiTypes.ts +120 -0
  112. package/src/query/baseQueryTypes.ts +101 -0
  113. package/src/query/core/apiState.ts +377 -0
  114. package/src/query/core/buildInitiate.ts +596 -0
  115. package/src/query/core/buildMiddleware/batchActions.ts +207 -0
  116. package/src/query/core/buildMiddleware/cacheCollection.ts +204 -0
  117. package/src/query/core/buildMiddleware/cacheLifecycle.ts +379 -0
  118. package/src/query/core/buildMiddleware/devMiddleware.ts +34 -0
  119. package/src/query/core/buildMiddleware/index.ts +162 -0
  120. package/src/query/core/buildMiddleware/invalidationByTags.ts +139 -0
  121. package/src/query/core/buildMiddleware/polling.ts +187 -0
  122. package/src/query/core/buildMiddleware/queryLifecycle.ts +508 -0
  123. package/src/query/core/buildMiddleware/types.ts +173 -0
  124. package/src/query/core/buildMiddleware/windowEventHandling.ts +64 -0
  125. package/src/query/core/buildSelectors.ts +413 -0
  126. package/src/query/core/buildSlice.ts +735 -0
  127. package/src/query/core/buildThunks.ts +1124 -0
  128. package/src/query/core/index.ts +58 -0
  129. package/src/query/core/module.ts +727 -0
  130. package/src/query/core/rtkImports.ts +24 -0
  131. package/src/query/core/setupListeners.ts +118 -0
  132. package/src/query/createApi.ts +506 -0
  133. package/src/query/defaultSerializeQueryArgs.ts +52 -0
  134. package/src/query/endpointDefinitions.ts +1717 -0
  135. package/src/query/fakeBaseQuery.ts +21 -0
  136. package/src/query/fetchBaseQuery.ts +385 -0
  137. package/src/query/index.ts +105 -0
  138. package/src/query/react/ApiProvider.tsx +69 -0
  139. package/src/query/react/buildHooks.ts +2297 -0
  140. package/src/query/react/constants.ts +2 -0
  141. package/src/query/react/index.ts +45 -0
  142. package/src/query/react/module.ts +275 -0
  143. package/src/query/react/namedHooks.ts +59 -0
  144. package/src/query/react/reactImports.ts +10 -0
  145. package/src/query/react/reactReduxImports.ts +1 -0
  146. package/src/query/react/rtkqImports.ts +8 -0
  147. package/src/query/react/useSerializedStableValue.ts +17 -0
  148. package/src/query/react/useShallowStableValue.ts +13 -0
  149. package/src/query/retry.ts +233 -0
  150. package/src/query/standardSchema.ts +35 -0
  151. package/src/query/tsHelpers.ts +48 -0
  152. package/src/query/utils/capitalize.ts +3 -0
  153. package/src/query/utils/copyWithStructuralSharing.ts +27 -0
  154. package/src/query/utils/countObjectKeys.ts +14 -0
  155. package/src/query/utils/filterMap.ts +27 -0
  156. package/src/query/utils/getCurrent.ts +6 -0
  157. package/src/query/utils/getOrInsert.ts +41 -0
  158. package/src/query/utils/immerImports.ts +9 -0
  159. package/src/query/utils/index.ts +11 -0
  160. package/src/query/utils/isAbsoluteUrl.ts +9 -0
  161. package/src/query/utils/isDocumentVisible.ts +12 -0
  162. package/src/query/utils/isNotNullish.ts +7 -0
  163. package/src/query/utils/isOnline.ts +12 -0
  164. package/src/query/utils/isValidUrl.ts +9 -0
  165. package/src/query/utils/joinUrls.ts +26 -0
  166. package/src/query/utils/signals.ts +33 -0
  167. package/src/react/index.ts +7 -0
  168. package/src/reduxImports.ts +8 -0
  169. package/src/reselectImports.ts +1 -0
  170. package/src/serializableStateInvariantMiddleware.ts +285 -0
  171. package/src/tsHelpers.ts +214 -0
  172. package/src/uncheckedindexed.ts +16 -0
  173. package/src/utils.ts +125 -0
@@ -0,0 +1,207 @@
1
+ import type { InternalHandlerBuilder, SubscriptionSelectors } from './types'
2
+ import type { SubscriptionInternalState, SubscriptionState } from '../apiState'
3
+ import { produceWithPatches } from '../../utils/immerImports'
4
+ import type { Action } from '@reduxjs/toolkit'
5
+ import { getOrInsertComputed, createNewMap } from '../../utils/getOrInsert'
6
+
7
+ export const buildBatchedActionsHandler: InternalHandlerBuilder<
8
+ [actionShouldContinue: boolean, returnValue: SubscriptionSelectors | boolean]
9
+ > = ({ api, queryThunk, internalState, mwApi }) => {
10
+ const subscriptionsPrefix = `${api.reducerPath}/subscriptions`
11
+
12
+ let previousSubscriptions: SubscriptionState =
13
+ null as unknown as SubscriptionState
14
+
15
+ let updateSyncTimer: ReturnType<typeof window.setTimeout> | null = null
16
+
17
+ const { updateSubscriptionOptions, unsubscribeQueryResult } =
18
+ api.internalActions
19
+
20
+ // Actually intentionally mutate the subscriptions state used in the middleware
21
+ // This is done to speed up perf when loading many components
22
+ const actuallyMutateSubscriptions = (
23
+ currentSubscriptions: SubscriptionInternalState,
24
+ action: Action,
25
+ ) => {
26
+ if (updateSubscriptionOptions.match(action)) {
27
+ const { queryCacheKey, requestId, options } = action.payload
28
+
29
+ const sub = currentSubscriptions.get(queryCacheKey)
30
+ if (sub?.has(requestId)) {
31
+ sub.set(requestId, options)
32
+ }
33
+ return true
34
+ }
35
+ if (unsubscribeQueryResult.match(action)) {
36
+ const { queryCacheKey, requestId } = action.payload
37
+ const sub = currentSubscriptions.get(queryCacheKey)
38
+ if (sub) {
39
+ sub.delete(requestId)
40
+ }
41
+ return true
42
+ }
43
+ if (api.internalActions.removeQueryResult.match(action)) {
44
+ currentSubscriptions.delete(action.payload.queryCacheKey)
45
+ return true
46
+ }
47
+ if (queryThunk.pending.match(action)) {
48
+ const {
49
+ meta: { arg, requestId },
50
+ } = action
51
+ const substate = getOrInsertComputed(
52
+ currentSubscriptions,
53
+ arg.queryCacheKey,
54
+ createNewMap,
55
+ )
56
+ if (arg.subscribe) {
57
+ substate.set(
58
+ requestId,
59
+ arg.subscriptionOptions ?? substate.get(requestId) ?? {},
60
+ )
61
+ }
62
+ return true
63
+ }
64
+ let mutated = false
65
+
66
+ if (queryThunk.rejected.match(action)) {
67
+ const {
68
+ meta: { condition, arg, requestId },
69
+ } = action
70
+ if (condition && arg.subscribe) {
71
+ const substate = getOrInsertComputed(
72
+ currentSubscriptions,
73
+ arg.queryCacheKey,
74
+ createNewMap,
75
+ )
76
+ substate.set(
77
+ requestId,
78
+ arg.subscriptionOptions ?? substate.get(requestId) ?? {},
79
+ )
80
+
81
+ mutated = true
82
+ }
83
+ }
84
+
85
+ return mutated
86
+ }
87
+
88
+ const getSubscriptions = () => internalState.currentSubscriptions
89
+ const getSubscriptionCount = (queryCacheKey: string) => {
90
+ const subscriptions = getSubscriptions()
91
+ const subscriptionsForQueryArg = subscriptions.get(queryCacheKey)
92
+ return subscriptionsForQueryArg?.size ?? 0
93
+ }
94
+ const isRequestSubscribed = (queryCacheKey: string, requestId: string) => {
95
+ const subscriptions = getSubscriptions()
96
+ return !!subscriptions?.get(queryCacheKey)?.get(requestId)
97
+ }
98
+
99
+ const subscriptionSelectors: SubscriptionSelectors = {
100
+ getSubscriptions,
101
+ getSubscriptionCount,
102
+ isRequestSubscribed,
103
+ }
104
+
105
+ function serializeSubscriptions(
106
+ currentSubscriptions: SubscriptionInternalState,
107
+ ): SubscriptionState {
108
+ // We now use nested Maps for subscriptions, instead of
109
+ // plain Records. Stringify this accordingly so we can
110
+ // convert it to the shape we need for the store.
111
+ return JSON.parse(
112
+ JSON.stringify(
113
+ Object.fromEntries(
114
+ [...currentSubscriptions].map(([k, v]) => [k, Object.fromEntries(v)]),
115
+ ),
116
+ ),
117
+ )
118
+ }
119
+
120
+ return (
121
+ action,
122
+ mwApi,
123
+ ): [
124
+ actionShouldContinue: boolean,
125
+ result: SubscriptionSelectors | boolean,
126
+ ] => {
127
+ if (!previousSubscriptions) {
128
+ // Initialize it the first time this handler runs
129
+ previousSubscriptions = serializeSubscriptions(
130
+ internalState.currentSubscriptions,
131
+ )
132
+ }
133
+
134
+ if (api.util.resetApiState.match(action)) {
135
+ previousSubscriptions = {}
136
+ internalState.currentSubscriptions.clear()
137
+ updateSyncTimer = null
138
+ return [true, false]
139
+ }
140
+
141
+ // Intercept requests by hooks to see if they're subscribed
142
+ // We return the internal state reference so that hooks
143
+ // can do their own checks to see if they're still active.
144
+ // It's stupid and hacky, but it does cut down on some dispatch calls.
145
+ if (api.internalActions.internal_getRTKQSubscriptions.match(action)) {
146
+ return [false, subscriptionSelectors]
147
+ }
148
+
149
+ // Update subscription data based on this action
150
+ const didMutate = actuallyMutateSubscriptions(
151
+ internalState.currentSubscriptions,
152
+ action,
153
+ )
154
+
155
+ let actionShouldContinue = true
156
+
157
+ // HACK Sneak the test-only polling state back out
158
+ if (
159
+ process.env.NODE_ENV === 'test' &&
160
+ typeof action.type === 'string' &&
161
+ action.type === `${api.reducerPath}/getPolling`
162
+ ) {
163
+ return [false, internalState.currentPolls] as any
164
+ }
165
+
166
+ if (didMutate) {
167
+ if (!updateSyncTimer) {
168
+ // We only use the subscription state for the Redux DevTools at this point,
169
+ // as the real data is kept here in the middleware.
170
+ // Given that, we can throttle synchronizing this state significantly to
171
+ // save on overall perf.
172
+ // In 1.9, it was updated in a microtask, but now we do it at most every 500ms.
173
+ updateSyncTimer = setTimeout(() => {
174
+ // Deep clone the current subscription data
175
+ const newSubscriptions: SubscriptionState = serializeSubscriptions(
176
+ internalState.currentSubscriptions,
177
+ )
178
+ // Figure out a smaller diff between original and current
179
+ const [, patches] = produceWithPatches(
180
+ previousSubscriptions,
181
+ () => newSubscriptions,
182
+ )
183
+
184
+ // Sync the store state for visibility
185
+ mwApi.next(api.internalActions.subscriptionsUpdated(patches))
186
+ // Save the cloned state for later reference
187
+ previousSubscriptions = newSubscriptions
188
+ updateSyncTimer = null
189
+ }, 500)
190
+ }
191
+
192
+ const isSubscriptionSliceAction =
193
+ typeof action.type == 'string' &&
194
+ !!action.type.startsWith(subscriptionsPrefix)
195
+
196
+ const isAdditionalSubscriptionAction =
197
+ queryThunk.rejected.match(action) &&
198
+ action.meta.condition &&
199
+ !!action.meta.arg.subscribe
200
+
201
+ actionShouldContinue =
202
+ !isSubscriptionSliceAction && !isAdditionalSubscriptionAction
203
+ }
204
+
205
+ return [actionShouldContinue, false]
206
+ }
207
+ }
@@ -0,0 +1,204 @@
1
+ import { getEndpointDefinition } from '@internal/query/apiTypes'
2
+ import type { QueryDefinition } from '../../endpointDefinitions'
3
+ import type { ConfigState, QueryCacheKey, QuerySubState } from '../apiState'
4
+ import { isAnyOf } from '../rtkImports'
5
+ import type {
6
+ ApiMiddlewareInternalHandler,
7
+ InternalHandlerBuilder,
8
+ QueryStateMeta,
9
+ SubMiddlewareApi,
10
+ TimeoutId,
11
+ } from './types'
12
+
13
+ export type ReferenceCacheCollection = never
14
+
15
+ /**
16
+ * @example
17
+ * ```ts
18
+ * // codeblock-meta title="keepUnusedDataFor example"
19
+ * import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
20
+ * interface Post {
21
+ * id: number
22
+ * name: string
23
+ * }
24
+ * type PostsResponse = Post[]
25
+ *
26
+ * const api = createApi({
27
+ * baseQuery: fetchBaseQuery({ baseUrl: '/' }),
28
+ * endpoints: (build) => ({
29
+ * getPosts: build.query<PostsResponse, void>({
30
+ * query: () => 'posts',
31
+ * // highlight-start
32
+ * keepUnusedDataFor: 5
33
+ * // highlight-end
34
+ * })
35
+ * })
36
+ * })
37
+ * ```
38
+ */
39
+ export type CacheCollectionQueryExtraOptions = {
40
+ /**
41
+ * Overrides the api-wide definition of `keepUnusedDataFor` for this endpoint only. _(This value is in seconds.)_
42
+ *
43
+ * This is how long RTK Query will keep your data cached for **after** the last component unsubscribes. For example, if you query an endpoint, then unmount the component, then mount another component that makes the same request within the given time frame, the most recent value will be served from the cache.
44
+ */
45
+ keepUnusedDataFor?: number
46
+ }
47
+
48
+ // Per https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value , browsers store
49
+ // `setTimeout()` timer values in a 32-bit int. If we pass a value in that's larger than that,
50
+ // it wraps and ends up executing immediately.
51
+ // Our `keepUnusedDataFor` values are in seconds, so adjust the numbers here accordingly.
52
+ export const THIRTY_TWO_BIT_MAX_INT = 2_147_483_647
53
+ export const THIRTY_TWO_BIT_MAX_TIMER_SECONDS = 2_147_483_647 / 1_000 - 1
54
+
55
+ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
56
+ reducerPath,
57
+ api,
58
+ queryThunk,
59
+ context,
60
+ internalState,
61
+ selectors: { selectQueryEntry, selectConfig },
62
+ getRunningQueryThunk,
63
+ mwApi,
64
+ }) => {
65
+ const { removeQueryResult, unsubscribeQueryResult, cacheEntriesUpserted } =
66
+ api.internalActions
67
+
68
+ const canTriggerUnsubscribe = isAnyOf(
69
+ unsubscribeQueryResult.match,
70
+ queryThunk.fulfilled,
71
+ queryThunk.rejected,
72
+ cacheEntriesUpserted.match,
73
+ )
74
+
75
+ function anySubscriptionsRemainingForKey(queryCacheKey: string) {
76
+ const subscriptions = internalState.currentSubscriptions.get(queryCacheKey)
77
+ if (!subscriptions) {
78
+ return false
79
+ }
80
+
81
+ const hasSubscriptions = subscriptions.size > 0
82
+ return hasSubscriptions
83
+ }
84
+
85
+ const currentRemovalTimeouts: QueryStateMeta<TimeoutId> = {}
86
+
87
+ function abortAllPromises<T extends { abort?: () => void }>(
88
+ promiseMap: Map<string, T | undefined>,
89
+ ): void {
90
+ for (const promise of promiseMap.values()) {
91
+ promise?.abort?.()
92
+ }
93
+ }
94
+
95
+ const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
96
+ const state = mwApi.getState()
97
+ const config = selectConfig(state)
98
+
99
+ if (canTriggerUnsubscribe(action)) {
100
+ let queryCacheKeys: QueryCacheKey[]
101
+
102
+ if (cacheEntriesUpserted.match(action)) {
103
+ queryCacheKeys = action.payload.map(
104
+ (entry) => entry.queryDescription.queryCacheKey,
105
+ )
106
+ } else {
107
+ const { queryCacheKey } = unsubscribeQueryResult.match(action)
108
+ ? action.payload
109
+ : action.meta.arg
110
+ queryCacheKeys = [queryCacheKey]
111
+ }
112
+
113
+ handleUnsubscribeMany(queryCacheKeys, mwApi, config)
114
+ }
115
+
116
+ if (api.util.resetApiState.match(action)) {
117
+ for (const [key, timeout] of Object.entries(currentRemovalTimeouts)) {
118
+ if (timeout) clearTimeout(timeout)
119
+ delete currentRemovalTimeouts[key]
120
+ }
121
+
122
+ abortAllPromises(internalState.runningQueries)
123
+ abortAllPromises(internalState.runningMutations)
124
+ }
125
+
126
+ if (context.hasRehydrationInfo(action)) {
127
+ const { queries } = context.extractRehydrationInfo(action)!
128
+ // Gotcha:
129
+ // If rehydrating before the endpoint has been injected,the global `keepUnusedDataFor`
130
+ // will be used instead of the endpoint-specific one.
131
+ handleUnsubscribeMany(
132
+ Object.keys(queries) as QueryCacheKey[],
133
+ mwApi,
134
+ config,
135
+ )
136
+ }
137
+ }
138
+
139
+ function handleUnsubscribeMany(
140
+ cacheKeys: QueryCacheKey[],
141
+ api: SubMiddlewareApi,
142
+ config: ConfigState<string>,
143
+ ) {
144
+ const state = api.getState()
145
+ for (const queryCacheKey of cacheKeys) {
146
+ const entry = selectQueryEntry(state, queryCacheKey)
147
+ if (entry?.endpointName) {
148
+ handleUnsubscribe(queryCacheKey, entry.endpointName, api, config)
149
+ }
150
+ }
151
+ }
152
+
153
+ function handleUnsubscribe(
154
+ queryCacheKey: QueryCacheKey,
155
+ endpointName: string,
156
+ api: SubMiddlewareApi,
157
+ config: ConfigState<string>,
158
+ ) {
159
+ const endpointDefinition = getEndpointDefinition(
160
+ context,
161
+ endpointName,
162
+ ) as QueryDefinition<any, any, any, any>
163
+ const keepUnusedDataFor =
164
+ endpointDefinition?.keepUnusedDataFor ?? config.keepUnusedDataFor
165
+
166
+ if (keepUnusedDataFor === Infinity) {
167
+ // Hey, user said keep this forever!
168
+ return
169
+ }
170
+ // Prevent `setTimeout` timers from overflowing a 32-bit internal int, by
171
+ // clamping the max value to be at most 1000ms less than the 32-bit max.
172
+ // Look, a 24.8-day keepalive ought to be enough for anybody, right? :)
173
+ // Also avoid negative values too.
174
+ const finalKeepUnusedDataFor = Math.max(
175
+ 0,
176
+ Math.min(keepUnusedDataFor, THIRTY_TWO_BIT_MAX_TIMER_SECONDS),
177
+ )
178
+
179
+ if (!anySubscriptionsRemainingForKey(queryCacheKey)) {
180
+ const currentTimeout = currentRemovalTimeouts[queryCacheKey]
181
+ if (currentTimeout) {
182
+ clearTimeout(currentTimeout)
183
+ }
184
+
185
+ currentRemovalTimeouts[queryCacheKey] = setTimeout(() => {
186
+ if (!anySubscriptionsRemainingForKey(queryCacheKey)) {
187
+ // Try to abort any running query for this cache key
188
+ const entry = selectQueryEntry(api.getState(), queryCacheKey)
189
+
190
+ if (entry?.endpointName) {
191
+ const runningQuery = api.dispatch(
192
+ getRunningQueryThunk(entry.endpointName, entry.originalArgs),
193
+ )
194
+ runningQuery?.abort()
195
+ }
196
+ api.dispatch(removeQueryResult({ queryCacheKey }))
197
+ }
198
+ delete currentRemovalTimeouts![queryCacheKey]
199
+ }, finalKeepUnusedDataFor * 1000)
200
+ }
201
+ }
202
+
203
+ return handler
204
+ }