@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.
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/changes.json +18 -0
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/redux-toolkit.development.cjs +2406 -0
- package/dist/cjs/redux-toolkit.development.cjs.map +1 -0
- package/dist/cjs/redux-toolkit.production.min.cjs +3 -0
- package/dist/cjs/redux-toolkit.production.min.cjs.map +1 -0
- package/dist/index.d.mts +2665 -0
- package/dist/index.d.ts +2665 -0
- package/dist/query/cjs/index.js +6 -0
- package/dist/query/cjs/rtk-query.development.cjs +3092 -0
- package/dist/query/cjs/rtk-query.development.cjs.map +1 -0
- package/dist/query/cjs/rtk-query.production.min.cjs +2 -0
- package/dist/query/cjs/rtk-query.production.min.cjs.map +1 -0
- package/dist/query/index.d.mts +3066 -0
- package/dist/query/index.d.ts +3066 -0
- package/dist/query/react/cjs/index.js +6 -0
- package/dist/query/react/cjs/rtk-query-react.development.cjs +748 -0
- package/dist/query/react/cjs/rtk-query-react.development.cjs.map +1 -0
- package/dist/query/react/cjs/rtk-query-react.production.min.cjs +2 -0
- package/dist/query/react/cjs/rtk-query-react.production.min.cjs.map +1 -0
- package/dist/query/react/index.d.mts +1009 -0
- package/dist/query/react/index.d.ts +1009 -0
- package/dist/query/react/rtk-query-react.browser.mjs +2 -0
- package/dist/query/react/rtk-query-react.browser.mjs.map +1 -0
- package/dist/query/react/rtk-query-react.legacy-esm.js +740 -0
- package/dist/query/react/rtk-query-react.legacy-esm.js.map +1 -0
- package/dist/query/react/rtk-query-react.modern.mjs +705 -0
- package/dist/query/react/rtk-query-react.modern.mjs.map +1 -0
- package/dist/query/rtk-query.browser.mjs +2 -0
- package/dist/query/rtk-query.browser.mjs.map +1 -0
- package/dist/query/rtk-query.legacy-esm.js +3117 -0
- package/dist/query/rtk-query.legacy-esm.js.map +1 -0
- package/dist/query/rtk-query.modern.mjs +3052 -0
- package/dist/query/rtk-query.modern.mjs.map +1 -0
- package/dist/react/cjs/index.js +6 -0
- package/dist/react/cjs/redux-toolkit-react.development.cjs +55 -0
- package/dist/react/cjs/redux-toolkit-react.development.cjs.map +1 -0
- package/dist/react/cjs/redux-toolkit-react.production.min.cjs +2 -0
- package/dist/react/cjs/redux-toolkit-react.production.min.cjs.map +1 -0
- package/dist/react/index.d.mts +22 -0
- package/dist/react/index.d.ts +22 -0
- package/dist/react/redux-toolkit-react.browser.mjs +2 -0
- package/dist/react/redux-toolkit-react.browser.mjs.map +1 -0
- package/dist/react/redux-toolkit-react.legacy-esm.js +47 -0
- package/dist/react/redux-toolkit-react.legacy-esm.js.map +1 -0
- package/dist/react/redux-toolkit-react.modern.mjs +28 -0
- package/dist/react/redux-toolkit-react.modern.mjs.map +1 -0
- package/dist/redux-toolkit.browser.mjs +3 -0
- package/dist/redux-toolkit.browser.mjs.map +1 -0
- package/dist/redux-toolkit.legacy-esm.js +2351 -0
- package/dist/redux-toolkit.legacy-esm.js.map +1 -0
- package/dist/redux-toolkit.modern.mjs +2330 -0
- package/dist/redux-toolkit.modern.mjs.map +1 -0
- package/dist/uncheckedindexed.ts +16 -0
- package/package.json +310 -0
- package/query/package.json +13 -0
- package/query/react/package.json +13 -0
- package/react/package.json +13 -0
- package/skills/build-modern-redux-apps/modern-redux/SKILL.md +304 -0
- package/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md +53 -0
- package/skills/build-modern-redux-apps/redux-dataflow/SKILL.md +264 -0
- package/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md +269 -0
- package/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md +226 -0
- package/skills/manage-server-data/adopt-rtk-query/SKILL.md +385 -0
- package/skills/manage-server-data/adopt-rtk-query/references/endpoint-lifecycle.md +36 -0
- package/skills/model-redux-state/build-slices-and-selectors/SKILL.md +364 -0
- package/skills/model-redux-state/build-slices-and-selectors/references/slice-patterns.md +59 -0
- package/skills/model-redux-state/design-state-ownership/SKILL.md +322 -0
- package/skills/model-redux-state/design-state-ownership/references/state-ownership.md +28 -0
- package/skills/orchestrate-side-effects/handle-side-effects/SKILL.md +271 -0
- package/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md +34 -0
- package/src/actionCreatorInvariantMiddleware.ts +34 -0
- package/src/autoBatchEnhancer.ts +146 -0
- package/src/combineSlices.ts +487 -0
- package/src/configureStore.ts +248 -0
- package/src/createAction.ts +324 -0
- package/src/createAsyncThunk.ts +791 -0
- package/src/createDraftSafeSelector.ts +30 -0
- package/src/createReducer.ts +217 -0
- package/src/createSlice.ts +1079 -0
- package/src/devtoolsExtension.ts +241 -0
- package/src/dynamicMiddleware/index.ts +93 -0
- package/src/dynamicMiddleware/react/index.ts +101 -0
- package/src/dynamicMiddleware/types.ts +82 -0
- package/src/entities/create_adapter.ts +47 -0
- package/src/entities/entity_state.ts +38 -0
- package/src/entities/index.ts +8 -0
- package/src/entities/models.ts +198 -0
- package/src/entities/sorted_state_adapter.ts +266 -0
- package/src/entities/state_adapter.ts +58 -0
- package/src/entities/state_selectors.ts +73 -0
- package/src/entities/unsorted_state_adapter.ts +204 -0
- package/src/entities/utils.ts +68 -0
- package/src/formatProdErrorMessage.ts +13 -0
- package/src/getDefaultEnhancers.ts +31 -0
- package/src/getDefaultMiddleware.ts +113 -0
- package/src/immerImports.ts +7 -0
- package/src/immutableStateInvariantMiddleware.ts +274 -0
- package/src/index.ts +213 -0
- package/src/listenerMiddleware/exceptions.ts +20 -0
- package/src/listenerMiddleware/index.ts +562 -0
- package/src/listenerMiddleware/task.ts +100 -0
- package/src/listenerMiddleware/types.ts +886 -0
- package/src/listenerMiddleware/utils.ts +30 -0
- package/src/mapBuilders.ts +298 -0
- package/src/matchers.ts +365 -0
- package/src/nanoid.ts +20 -0
- package/src/query/HandledError.ts +6 -0
- package/src/query/apiTypes.ts +120 -0
- package/src/query/baseQueryTypes.ts +101 -0
- package/src/query/core/apiState.ts +377 -0
- package/src/query/core/buildInitiate.ts +596 -0
- package/src/query/core/buildMiddleware/batchActions.ts +207 -0
- package/src/query/core/buildMiddleware/cacheCollection.ts +204 -0
- package/src/query/core/buildMiddleware/cacheLifecycle.ts +379 -0
- package/src/query/core/buildMiddleware/devMiddleware.ts +34 -0
- package/src/query/core/buildMiddleware/index.ts +162 -0
- package/src/query/core/buildMiddleware/invalidationByTags.ts +139 -0
- package/src/query/core/buildMiddleware/polling.ts +187 -0
- package/src/query/core/buildMiddleware/queryLifecycle.ts +508 -0
- package/src/query/core/buildMiddleware/types.ts +173 -0
- package/src/query/core/buildMiddleware/windowEventHandling.ts +64 -0
- package/src/query/core/buildSelectors.ts +413 -0
- package/src/query/core/buildSlice.ts +735 -0
- package/src/query/core/buildThunks.ts +1124 -0
- package/src/query/core/index.ts +58 -0
- package/src/query/core/module.ts +727 -0
- package/src/query/core/rtkImports.ts +24 -0
- package/src/query/core/setupListeners.ts +118 -0
- package/src/query/createApi.ts +506 -0
- package/src/query/defaultSerializeQueryArgs.ts +52 -0
- package/src/query/endpointDefinitions.ts +1717 -0
- package/src/query/fakeBaseQuery.ts +21 -0
- package/src/query/fetchBaseQuery.ts +385 -0
- package/src/query/index.ts +105 -0
- package/src/query/react/ApiProvider.tsx +69 -0
- package/src/query/react/buildHooks.ts +2297 -0
- package/src/query/react/constants.ts +2 -0
- package/src/query/react/index.ts +45 -0
- package/src/query/react/module.ts +275 -0
- package/src/query/react/namedHooks.ts +59 -0
- package/src/query/react/reactImports.ts +10 -0
- package/src/query/react/reactReduxImports.ts +1 -0
- package/src/query/react/rtkqImports.ts +8 -0
- package/src/query/react/useSerializedStableValue.ts +17 -0
- package/src/query/react/useShallowStableValue.ts +13 -0
- package/src/query/retry.ts +233 -0
- package/src/query/standardSchema.ts +35 -0
- package/src/query/tsHelpers.ts +48 -0
- package/src/query/utils/capitalize.ts +3 -0
- package/src/query/utils/copyWithStructuralSharing.ts +27 -0
- package/src/query/utils/countObjectKeys.ts +14 -0
- package/src/query/utils/filterMap.ts +27 -0
- package/src/query/utils/getCurrent.ts +6 -0
- package/src/query/utils/getOrInsert.ts +41 -0
- package/src/query/utils/immerImports.ts +9 -0
- package/src/query/utils/index.ts +11 -0
- package/src/query/utils/isAbsoluteUrl.ts +9 -0
- package/src/query/utils/isDocumentVisible.ts +12 -0
- package/src/query/utils/isNotNullish.ts +7 -0
- package/src/query/utils/isOnline.ts +12 -0
- package/src/query/utils/isValidUrl.ts +9 -0
- package/src/query/utils/joinUrls.ts +26 -0
- package/src/query/utils/signals.ts +33 -0
- package/src/react/index.ts +7 -0
- package/src/reduxImports.ts +8 -0
- package/src/reselectImports.ts +1 -0
- package/src/serializableStateInvariantMiddleware.ts +285 -0
- package/src/tsHelpers.ts +214 -0
- package/src/uncheckedindexed.ts +16 -0
- package/src/utils.ts +125 -0
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
import type { PayloadAction } from '@reduxjs/toolkit'
|
|
2
|
+
import {
|
|
3
|
+
combineReducers,
|
|
4
|
+
createAction,
|
|
5
|
+
createSlice,
|
|
6
|
+
isAnyOf,
|
|
7
|
+
isFulfilled,
|
|
8
|
+
isRejectedWithValue,
|
|
9
|
+
createNextState,
|
|
10
|
+
prepareAutoBatched,
|
|
11
|
+
SHOULD_AUTOBATCH,
|
|
12
|
+
nanoid,
|
|
13
|
+
} from './rtkImports'
|
|
14
|
+
import type {
|
|
15
|
+
QuerySubstateIdentifier,
|
|
16
|
+
QuerySubState,
|
|
17
|
+
MutationSubstateIdentifier,
|
|
18
|
+
MutationSubState,
|
|
19
|
+
MutationState,
|
|
20
|
+
QueryState,
|
|
21
|
+
InvalidationState,
|
|
22
|
+
Subscribers,
|
|
23
|
+
QueryCacheKey,
|
|
24
|
+
SubscriptionState,
|
|
25
|
+
ConfigState,
|
|
26
|
+
InfiniteQuerySubState,
|
|
27
|
+
InfiniteQueryDirection,
|
|
28
|
+
} from './apiState'
|
|
29
|
+
import {
|
|
30
|
+
STATUS_FULFILLED,
|
|
31
|
+
STATUS_PENDING,
|
|
32
|
+
QueryStatus,
|
|
33
|
+
STATUS_REJECTED,
|
|
34
|
+
STATUS_UNINITIALIZED,
|
|
35
|
+
} from './apiState'
|
|
36
|
+
import type {
|
|
37
|
+
AllQueryKeys,
|
|
38
|
+
QueryArgFromAnyQueryDefinition,
|
|
39
|
+
DataFromAnyQueryDefinition,
|
|
40
|
+
InfiniteQueryThunk,
|
|
41
|
+
MutationThunk,
|
|
42
|
+
QueryThunk,
|
|
43
|
+
QueryThunkArg,
|
|
44
|
+
} from './buildThunks'
|
|
45
|
+
import { calculateProvidedByThunk } from './buildThunks'
|
|
46
|
+
import {
|
|
47
|
+
ENDPOINT_QUERY,
|
|
48
|
+
isInfiniteQueryDefinition,
|
|
49
|
+
type AssertTagTypes,
|
|
50
|
+
type EndpointDefinitions,
|
|
51
|
+
type FullTagDescription,
|
|
52
|
+
type QueryDefinition,
|
|
53
|
+
} from '../endpointDefinitions'
|
|
54
|
+
import type { Patch } from 'immer'
|
|
55
|
+
import { applyPatches, original, isDraft } from '../utils/immerImports'
|
|
56
|
+
import { onFocus, onFocusLost, onOffline, onOnline } from './setupListeners'
|
|
57
|
+
import {
|
|
58
|
+
isDocumentVisible,
|
|
59
|
+
isOnline,
|
|
60
|
+
copyWithStructuralSharing,
|
|
61
|
+
} from '../utils'
|
|
62
|
+
import type { ApiContext } from '../apiTypes'
|
|
63
|
+
import { isUpsertQuery } from './buildInitiate'
|
|
64
|
+
import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
|
|
65
|
+
import type { UnwrapPromise } from '../tsHelpers'
|
|
66
|
+
import { getCurrent } from '../utils/getCurrent'
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* A typesafe single entry to be upserted into the cache
|
|
70
|
+
*/
|
|
71
|
+
export type NormalizedQueryUpsertEntry<
|
|
72
|
+
Definitions extends EndpointDefinitions,
|
|
73
|
+
EndpointName extends AllQueryKeys<Definitions>,
|
|
74
|
+
> = {
|
|
75
|
+
endpointName: EndpointName
|
|
76
|
+
arg: QueryArgFromAnyQueryDefinition<Definitions, EndpointName>
|
|
77
|
+
value: DataFromAnyQueryDefinition<Definitions, EndpointName>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The internal version that is not typesafe since we can't carry the generics through `createSlice`
|
|
82
|
+
*/
|
|
83
|
+
type NormalizedQueryUpsertEntryPayload = {
|
|
84
|
+
endpointName: string
|
|
85
|
+
arg: unknown
|
|
86
|
+
value: unknown
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type ProcessedQueryUpsertEntry = {
|
|
90
|
+
queryDescription: QueryThunkArg
|
|
91
|
+
value: unknown
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A typesafe representation of a util action creator that accepts cache entry descriptions to upsert
|
|
96
|
+
*/
|
|
97
|
+
export type UpsertEntries<Definitions extends EndpointDefinitions> = (<
|
|
98
|
+
EndpointNames extends Array<AllQueryKeys<Definitions>>,
|
|
99
|
+
>(
|
|
100
|
+
entries: [
|
|
101
|
+
...{
|
|
102
|
+
[I in keyof EndpointNames]: NormalizedQueryUpsertEntry<
|
|
103
|
+
Definitions,
|
|
104
|
+
EndpointNames[I]
|
|
105
|
+
>
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
) => PayloadAction<NormalizedQueryUpsertEntryPayload[]>) & {
|
|
109
|
+
match: (
|
|
110
|
+
action: unknown,
|
|
111
|
+
) => action is PayloadAction<NormalizedQueryUpsertEntryPayload[]>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function updateQuerySubstateIfExists(
|
|
115
|
+
state: QueryState<any>,
|
|
116
|
+
queryCacheKey: QueryCacheKey,
|
|
117
|
+
update: (substate: QuerySubState<any> | InfiniteQuerySubState<any>) => void,
|
|
118
|
+
) {
|
|
119
|
+
const substate = state[queryCacheKey]
|
|
120
|
+
if (substate) {
|
|
121
|
+
update(substate)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function getMutationCacheKey(
|
|
126
|
+
id:
|
|
127
|
+
| MutationSubstateIdentifier
|
|
128
|
+
| { requestId: string; arg: { fixedCacheKey?: string | undefined } },
|
|
129
|
+
): string
|
|
130
|
+
export function getMutationCacheKey(id: {
|
|
131
|
+
fixedCacheKey?: string
|
|
132
|
+
requestId?: string
|
|
133
|
+
}): string | undefined
|
|
134
|
+
|
|
135
|
+
export function getMutationCacheKey(
|
|
136
|
+
id:
|
|
137
|
+
| { fixedCacheKey?: string; requestId?: string }
|
|
138
|
+
| MutationSubstateIdentifier
|
|
139
|
+
| { requestId: string; arg: { fixedCacheKey?: string | undefined } },
|
|
140
|
+
): string | undefined {
|
|
141
|
+
return ('arg' in id ? id.arg.fixedCacheKey : id.fixedCacheKey) ?? id.requestId
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function updateMutationSubstateIfExists(
|
|
145
|
+
state: MutationState<any>,
|
|
146
|
+
id:
|
|
147
|
+
| MutationSubstateIdentifier
|
|
148
|
+
| { requestId: string; arg: { fixedCacheKey?: string | undefined } },
|
|
149
|
+
update: (substate: MutationSubState<any>) => void,
|
|
150
|
+
) {
|
|
151
|
+
const substate = state[getMutationCacheKey(id)]
|
|
152
|
+
if (substate) {
|
|
153
|
+
update(substate)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const initialState = {} as any
|
|
158
|
+
|
|
159
|
+
export function buildSlice({
|
|
160
|
+
reducerPath,
|
|
161
|
+
queryThunk,
|
|
162
|
+
mutationThunk,
|
|
163
|
+
serializeQueryArgs,
|
|
164
|
+
context: {
|
|
165
|
+
endpointDefinitions: definitions,
|
|
166
|
+
apiUid,
|
|
167
|
+
extractRehydrationInfo,
|
|
168
|
+
hasRehydrationInfo,
|
|
169
|
+
},
|
|
170
|
+
assertTagType,
|
|
171
|
+
config,
|
|
172
|
+
}: {
|
|
173
|
+
reducerPath: string
|
|
174
|
+
queryThunk: QueryThunk
|
|
175
|
+
infiniteQueryThunk: InfiniteQueryThunk<any>
|
|
176
|
+
mutationThunk: MutationThunk
|
|
177
|
+
serializeQueryArgs: InternalSerializeQueryArgs
|
|
178
|
+
context: ApiContext<EndpointDefinitions>
|
|
179
|
+
assertTagType: AssertTagTypes
|
|
180
|
+
config: Omit<
|
|
181
|
+
ConfigState<string>,
|
|
182
|
+
'online' | 'focused' | 'middlewareRegistered'
|
|
183
|
+
>
|
|
184
|
+
}) {
|
|
185
|
+
const resetApiState = createAction(`${reducerPath}/resetApiState`)
|
|
186
|
+
|
|
187
|
+
function writePendingCacheEntry(
|
|
188
|
+
draft: QueryState<any>,
|
|
189
|
+
arg: QueryThunkArg,
|
|
190
|
+
upserting: boolean,
|
|
191
|
+
meta: {
|
|
192
|
+
arg: QueryThunkArg
|
|
193
|
+
requestId: string
|
|
194
|
+
// requestStatus: 'pending'
|
|
195
|
+
} & { startedTimeStamp: number },
|
|
196
|
+
) {
|
|
197
|
+
draft[arg.queryCacheKey] ??= {
|
|
198
|
+
status: STATUS_UNINITIALIZED,
|
|
199
|
+
endpointName: arg.endpointName,
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
updateQuerySubstateIfExists(draft, arg.queryCacheKey, (substate) => {
|
|
203
|
+
substate.status = STATUS_PENDING
|
|
204
|
+
|
|
205
|
+
substate.requestId =
|
|
206
|
+
upserting && substate.requestId
|
|
207
|
+
? // for `upsertQuery` **updates**, keep the current `requestId`
|
|
208
|
+
substate.requestId
|
|
209
|
+
: // for normal queries or `upsertQuery` **inserts** always update the `requestId`
|
|
210
|
+
meta.requestId
|
|
211
|
+
if (arg.originalArgs !== undefined) {
|
|
212
|
+
substate.originalArgs = arg.originalArgs
|
|
213
|
+
}
|
|
214
|
+
substate.startedTimeStamp = meta.startedTimeStamp
|
|
215
|
+
|
|
216
|
+
const endpointDefinition = definitions[meta.arg.endpointName]
|
|
217
|
+
|
|
218
|
+
if (isInfiniteQueryDefinition(endpointDefinition) && 'direction' in arg) {
|
|
219
|
+
;(substate as InfiniteQuerySubState<any>).direction =
|
|
220
|
+
arg.direction as InfiniteQueryDirection
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function writeFulfilledCacheEntry(
|
|
226
|
+
draft: QueryState<any>,
|
|
227
|
+
meta: { arg: QueryThunkArg; requestId: string } & {
|
|
228
|
+
fulfilledTimeStamp: number
|
|
229
|
+
baseQueryMeta: unknown
|
|
230
|
+
},
|
|
231
|
+
payload: unknown,
|
|
232
|
+
upserting: boolean,
|
|
233
|
+
) {
|
|
234
|
+
updateQuerySubstateIfExists(draft, meta.arg.queryCacheKey, (substate) => {
|
|
235
|
+
if (substate.requestId !== meta.requestId && !upserting) return
|
|
236
|
+
const { merge } = definitions[meta.arg.endpointName] as QueryDefinition<
|
|
237
|
+
any,
|
|
238
|
+
any,
|
|
239
|
+
any,
|
|
240
|
+
any
|
|
241
|
+
>
|
|
242
|
+
substate.status = STATUS_FULFILLED
|
|
243
|
+
|
|
244
|
+
if (merge) {
|
|
245
|
+
if (substate.data !== undefined) {
|
|
246
|
+
const { fulfilledTimeStamp, arg, baseQueryMeta, requestId } = meta
|
|
247
|
+
// There's existing cache data. Let the user merge it in themselves.
|
|
248
|
+
// We're already inside an Immer-powered reducer, and the user could just mutate `substate.data`
|
|
249
|
+
// themselves inside of `merge()`. But, they might also want to return a new value.
|
|
250
|
+
// Try to let Immer figure that part out, save the result, and assign it to `substate.data`.
|
|
251
|
+
let newData = createNextState(substate.data, (draftSubstateData) => {
|
|
252
|
+
// As usual with Immer, you can mutate _or_ return inside here, but not both
|
|
253
|
+
return merge(draftSubstateData, payload, {
|
|
254
|
+
arg: arg.originalArgs,
|
|
255
|
+
baseQueryMeta,
|
|
256
|
+
fulfilledTimeStamp,
|
|
257
|
+
requestId,
|
|
258
|
+
})
|
|
259
|
+
})
|
|
260
|
+
substate.data = newData
|
|
261
|
+
} else {
|
|
262
|
+
// Presumably a fresh request. Just cache the response data.
|
|
263
|
+
substate.data = payload
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
// Assign or safely update the cache data.
|
|
267
|
+
substate.data =
|
|
268
|
+
(definitions[meta.arg.endpointName].structuralSharing ?? true)
|
|
269
|
+
? copyWithStructuralSharing(
|
|
270
|
+
isDraft(substate.data)
|
|
271
|
+
? original(substate.data)
|
|
272
|
+
: substate.data,
|
|
273
|
+
payload,
|
|
274
|
+
)
|
|
275
|
+
: payload
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
delete substate.error
|
|
279
|
+
substate.fulfilledTimeStamp = meta.fulfilledTimeStamp
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const querySlice = createSlice({
|
|
284
|
+
name: `${reducerPath}/queries`,
|
|
285
|
+
initialState: initialState as QueryState<any>,
|
|
286
|
+
reducers: {
|
|
287
|
+
removeQueryResult: {
|
|
288
|
+
reducer(
|
|
289
|
+
draft,
|
|
290
|
+
{
|
|
291
|
+
payload: { queryCacheKey },
|
|
292
|
+
}: PayloadAction<QuerySubstateIdentifier>,
|
|
293
|
+
) {
|
|
294
|
+
delete draft[queryCacheKey]
|
|
295
|
+
},
|
|
296
|
+
prepare: prepareAutoBatched<QuerySubstateIdentifier>(),
|
|
297
|
+
},
|
|
298
|
+
cacheEntriesUpserted: {
|
|
299
|
+
reducer(
|
|
300
|
+
draft,
|
|
301
|
+
action: PayloadAction<
|
|
302
|
+
ProcessedQueryUpsertEntry[],
|
|
303
|
+
string,
|
|
304
|
+
{ RTK_autoBatch: boolean; requestId: string; timestamp: number }
|
|
305
|
+
>,
|
|
306
|
+
) {
|
|
307
|
+
for (const entry of action.payload) {
|
|
308
|
+
const { queryDescription: arg, value } = entry
|
|
309
|
+
writePendingCacheEntry(draft, arg, true, {
|
|
310
|
+
arg,
|
|
311
|
+
requestId: action.meta.requestId,
|
|
312
|
+
startedTimeStamp: action.meta.timestamp,
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
writeFulfilledCacheEntry(
|
|
316
|
+
draft,
|
|
317
|
+
{
|
|
318
|
+
arg,
|
|
319
|
+
requestId: action.meta.requestId,
|
|
320
|
+
fulfilledTimeStamp: action.meta.timestamp,
|
|
321
|
+
baseQueryMeta: {},
|
|
322
|
+
},
|
|
323
|
+
value,
|
|
324
|
+
// We know we're upserting here
|
|
325
|
+
true,
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
prepare: (payload: NormalizedQueryUpsertEntryPayload[]) => {
|
|
330
|
+
const queryDescriptions: ProcessedQueryUpsertEntry[] = payload.map(
|
|
331
|
+
(entry) => {
|
|
332
|
+
const { endpointName, arg, value } = entry
|
|
333
|
+
const endpointDefinition = definitions[endpointName]
|
|
334
|
+
const queryDescription: QueryThunkArg = {
|
|
335
|
+
type: ENDPOINT_QUERY as 'query',
|
|
336
|
+
endpointName,
|
|
337
|
+
originalArgs: entry.arg,
|
|
338
|
+
queryCacheKey: serializeQueryArgs({
|
|
339
|
+
queryArgs: arg,
|
|
340
|
+
endpointDefinition,
|
|
341
|
+
endpointName,
|
|
342
|
+
}),
|
|
343
|
+
}
|
|
344
|
+
return { queryDescription, value }
|
|
345
|
+
},
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
const result = {
|
|
349
|
+
payload: queryDescriptions,
|
|
350
|
+
meta: {
|
|
351
|
+
[SHOULD_AUTOBATCH]: true,
|
|
352
|
+
requestId: nanoid(),
|
|
353
|
+
timestamp: Date.now(),
|
|
354
|
+
},
|
|
355
|
+
}
|
|
356
|
+
return result
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
queryResultPatched: {
|
|
360
|
+
reducer(
|
|
361
|
+
draft,
|
|
362
|
+
{
|
|
363
|
+
payload: { queryCacheKey, patches },
|
|
364
|
+
}: PayloadAction<
|
|
365
|
+
QuerySubstateIdentifier & { patches: readonly Patch[] }
|
|
366
|
+
>,
|
|
367
|
+
) {
|
|
368
|
+
updateQuerySubstateIfExists(draft, queryCacheKey, (substate) => {
|
|
369
|
+
substate.data = applyPatches(substate.data as any, patches.concat())
|
|
370
|
+
})
|
|
371
|
+
},
|
|
372
|
+
prepare: prepareAutoBatched<
|
|
373
|
+
QuerySubstateIdentifier & { patches: readonly Patch[] }
|
|
374
|
+
>(),
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
extraReducers(builder) {
|
|
378
|
+
builder
|
|
379
|
+
.addCase(queryThunk.pending, (draft, { meta, meta: { arg } }) => {
|
|
380
|
+
const upserting = isUpsertQuery(arg)
|
|
381
|
+
writePendingCacheEntry(draft, arg, upserting, meta)
|
|
382
|
+
})
|
|
383
|
+
.addCase(queryThunk.fulfilled, (draft, { meta, payload }) => {
|
|
384
|
+
const upserting = isUpsertQuery(meta.arg)
|
|
385
|
+
writeFulfilledCacheEntry(draft, meta, payload, upserting)
|
|
386
|
+
})
|
|
387
|
+
.addCase(
|
|
388
|
+
queryThunk.rejected,
|
|
389
|
+
(draft, { meta: { condition, arg, requestId }, error, payload }) => {
|
|
390
|
+
updateQuerySubstateIfExists(
|
|
391
|
+
draft,
|
|
392
|
+
arg.queryCacheKey,
|
|
393
|
+
(substate) => {
|
|
394
|
+
if (condition) {
|
|
395
|
+
// request was aborted due to condition (another query already running)
|
|
396
|
+
} else {
|
|
397
|
+
// request failed
|
|
398
|
+
if (substate.requestId !== requestId) return
|
|
399
|
+
substate.status = STATUS_REJECTED
|
|
400
|
+
substate.error = (payload ?? error) as any
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
)
|
|
404
|
+
},
|
|
405
|
+
)
|
|
406
|
+
.addMatcher(hasRehydrationInfo, (draft, action) => {
|
|
407
|
+
const { queries } = extractRehydrationInfo(action)!
|
|
408
|
+
for (const [key, entry] of Object.entries(queries)) {
|
|
409
|
+
if (
|
|
410
|
+
// do not rehydrate entries that were currently in flight.
|
|
411
|
+
entry?.status === STATUS_FULFILLED ||
|
|
412
|
+
entry?.status === STATUS_REJECTED
|
|
413
|
+
) {
|
|
414
|
+
draft[key] = entry
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
})
|
|
418
|
+
},
|
|
419
|
+
})
|
|
420
|
+
const mutationSlice = createSlice({
|
|
421
|
+
name: `${reducerPath}/mutations`,
|
|
422
|
+
initialState: initialState as MutationState<any>,
|
|
423
|
+
reducers: {
|
|
424
|
+
removeMutationResult: {
|
|
425
|
+
reducer(draft, { payload }: PayloadAction<MutationSubstateIdentifier>) {
|
|
426
|
+
const cacheKey = getMutationCacheKey(payload)
|
|
427
|
+
if (cacheKey in draft) {
|
|
428
|
+
delete draft[cacheKey]
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
prepare: prepareAutoBatched<MutationSubstateIdentifier>(),
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
extraReducers(builder) {
|
|
435
|
+
builder
|
|
436
|
+
.addCase(
|
|
437
|
+
mutationThunk.pending,
|
|
438
|
+
(draft, { meta, meta: { requestId, arg, startedTimeStamp } }) => {
|
|
439
|
+
if (!arg.track) return
|
|
440
|
+
|
|
441
|
+
draft[getMutationCacheKey(meta)] = {
|
|
442
|
+
requestId,
|
|
443
|
+
status: STATUS_PENDING,
|
|
444
|
+
endpointName: arg.endpointName,
|
|
445
|
+
startedTimeStamp,
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
)
|
|
449
|
+
.addCase(mutationThunk.fulfilled, (draft, { payload, meta }) => {
|
|
450
|
+
if (!meta.arg.track) return
|
|
451
|
+
|
|
452
|
+
updateMutationSubstateIfExists(draft, meta, (substate) => {
|
|
453
|
+
if (substate.requestId !== meta.requestId) return
|
|
454
|
+
substate.status = STATUS_FULFILLED
|
|
455
|
+
substate.data = payload
|
|
456
|
+
substate.fulfilledTimeStamp = meta.fulfilledTimeStamp
|
|
457
|
+
})
|
|
458
|
+
})
|
|
459
|
+
.addCase(mutationThunk.rejected, (draft, { payload, error, meta }) => {
|
|
460
|
+
if (!meta.arg.track) return
|
|
461
|
+
|
|
462
|
+
updateMutationSubstateIfExists(draft, meta, (substate) => {
|
|
463
|
+
if (substate.requestId !== meta.requestId) return
|
|
464
|
+
|
|
465
|
+
substate.status = STATUS_REJECTED
|
|
466
|
+
substate.error = (payload ?? error) as any
|
|
467
|
+
})
|
|
468
|
+
})
|
|
469
|
+
.addMatcher(hasRehydrationInfo, (draft, action) => {
|
|
470
|
+
const { mutations } = extractRehydrationInfo(action)!
|
|
471
|
+
for (const [key, entry] of Object.entries(mutations)) {
|
|
472
|
+
if (
|
|
473
|
+
// do not rehydrate entries that were currently in flight.
|
|
474
|
+
(entry?.status === STATUS_FULFILLED ||
|
|
475
|
+
entry?.status === STATUS_REJECTED) &&
|
|
476
|
+
// only rehydrate endpoints that were persisted using a `fixedCacheKey`
|
|
477
|
+
key !== entry?.requestId
|
|
478
|
+
) {
|
|
479
|
+
draft[key] = entry
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
})
|
|
483
|
+
},
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
type CalculateProvidedByAction = UnwrapPromise<
|
|
487
|
+
| ReturnType<ReturnType<QueryThunk>>
|
|
488
|
+
| ReturnType<ReturnType<InfiniteQueryThunk<any>>>
|
|
489
|
+
>
|
|
490
|
+
|
|
491
|
+
const initialInvalidationState: InvalidationState<string> = {
|
|
492
|
+
tags: {},
|
|
493
|
+
keys: {},
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const invalidationSlice = createSlice({
|
|
497
|
+
name: `${reducerPath}/invalidation`,
|
|
498
|
+
initialState: initialInvalidationState,
|
|
499
|
+
reducers: {
|
|
500
|
+
updateProvidedBy: {
|
|
501
|
+
reducer(
|
|
502
|
+
draft,
|
|
503
|
+
action: PayloadAction<
|
|
504
|
+
Array<{
|
|
505
|
+
queryCacheKey: QueryCacheKey
|
|
506
|
+
providedTags: readonly FullTagDescription<string>[]
|
|
507
|
+
}>
|
|
508
|
+
>,
|
|
509
|
+
) {
|
|
510
|
+
for (const { queryCacheKey, providedTags } of action.payload) {
|
|
511
|
+
removeCacheKeyFromTags(draft, queryCacheKey)
|
|
512
|
+
|
|
513
|
+
for (const { type, id } of providedTags) {
|
|
514
|
+
const subscribedQueries = ((draft.tags[type] ??= {})[
|
|
515
|
+
id || '__internal_without_id'
|
|
516
|
+
] ??= [])
|
|
517
|
+
const alreadySubscribed =
|
|
518
|
+
subscribedQueries.includes(queryCacheKey)
|
|
519
|
+
if (!alreadySubscribed) {
|
|
520
|
+
subscribedQueries.push(queryCacheKey)
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Remove readonly from the providedTags array
|
|
525
|
+
draft.keys[queryCacheKey] =
|
|
526
|
+
providedTags as FullTagDescription<string>[]
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
prepare: prepareAutoBatched<
|
|
530
|
+
Array<{
|
|
531
|
+
queryCacheKey: QueryCacheKey
|
|
532
|
+
providedTags: readonly FullTagDescription<string>[]
|
|
533
|
+
}>
|
|
534
|
+
>(),
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
extraReducers(builder) {
|
|
538
|
+
builder
|
|
539
|
+
.addCase(
|
|
540
|
+
querySlice.actions.removeQueryResult,
|
|
541
|
+
(draft, { payload: { queryCacheKey } }) => {
|
|
542
|
+
removeCacheKeyFromTags(draft, queryCacheKey)
|
|
543
|
+
},
|
|
544
|
+
)
|
|
545
|
+
.addMatcher(hasRehydrationInfo, (draft, action) => {
|
|
546
|
+
const { provided } = extractRehydrationInfo(action)!
|
|
547
|
+
for (const [type, incomingTags] of Object.entries(
|
|
548
|
+
provided.tags ?? {},
|
|
549
|
+
)) {
|
|
550
|
+
for (const [id, cacheKeys] of Object.entries(incomingTags)) {
|
|
551
|
+
const subscribedQueries = ((draft.tags[type] ??= {})[
|
|
552
|
+
id || '__internal_without_id'
|
|
553
|
+
] ??= [])
|
|
554
|
+
for (const queryCacheKey of cacheKeys) {
|
|
555
|
+
const alreadySubscribed =
|
|
556
|
+
subscribedQueries.includes(queryCacheKey)
|
|
557
|
+
if (!alreadySubscribed) {
|
|
558
|
+
subscribedQueries.push(queryCacheKey)
|
|
559
|
+
}
|
|
560
|
+
draft.keys[queryCacheKey] = provided.keys[queryCacheKey]
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
})
|
|
565
|
+
.addMatcher(
|
|
566
|
+
isAnyOf(isFulfilled(queryThunk), isRejectedWithValue(queryThunk)),
|
|
567
|
+
(draft, action) => {
|
|
568
|
+
writeProvidedTagsForQueries(draft, [action])
|
|
569
|
+
},
|
|
570
|
+
)
|
|
571
|
+
.addMatcher(
|
|
572
|
+
querySlice.actions.cacheEntriesUpserted.match,
|
|
573
|
+
(draft, action) => {
|
|
574
|
+
const mockActions: CalculateProvidedByAction[] = action.payload.map(
|
|
575
|
+
({ queryDescription, value }) => {
|
|
576
|
+
return {
|
|
577
|
+
type: 'UNKNOWN',
|
|
578
|
+
payload: value,
|
|
579
|
+
meta: {
|
|
580
|
+
requestStatus: 'fulfilled',
|
|
581
|
+
requestId: 'UNKNOWN',
|
|
582
|
+
arg: queryDescription,
|
|
583
|
+
},
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
)
|
|
587
|
+
writeProvidedTagsForQueries(draft, mockActions)
|
|
588
|
+
},
|
|
589
|
+
)
|
|
590
|
+
},
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
function removeCacheKeyFromTags(
|
|
594
|
+
draft: InvalidationState<any>,
|
|
595
|
+
queryCacheKey: QueryCacheKey,
|
|
596
|
+
) {
|
|
597
|
+
const existingTags = getCurrent(draft.keys[queryCacheKey] ?? [])
|
|
598
|
+
|
|
599
|
+
// Delete this cache key from any existing tags that may have provided it
|
|
600
|
+
for (const tag of existingTags) {
|
|
601
|
+
const tagType = tag.type
|
|
602
|
+
const tagId = tag.id ?? '__internal_without_id'
|
|
603
|
+
const tagSubscriptions = draft.tags[tagType]?.[tagId]
|
|
604
|
+
|
|
605
|
+
if (tagSubscriptions) {
|
|
606
|
+
draft.tags[tagType][tagId] = getCurrent(tagSubscriptions).filter(
|
|
607
|
+
(qc) => qc !== queryCacheKey,
|
|
608
|
+
)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
delete draft.keys[queryCacheKey]
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function writeProvidedTagsForQueries(
|
|
616
|
+
draft: InvalidationState<string>,
|
|
617
|
+
actions: CalculateProvidedByAction[],
|
|
618
|
+
) {
|
|
619
|
+
const providedByEntries = actions.map((action) => {
|
|
620
|
+
const providedTags = calculateProvidedByThunk(
|
|
621
|
+
action,
|
|
622
|
+
'providesTags',
|
|
623
|
+
definitions,
|
|
624
|
+
assertTagType,
|
|
625
|
+
)
|
|
626
|
+
const { queryCacheKey } = action.meta.arg
|
|
627
|
+
return { queryCacheKey, providedTags }
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
invalidationSlice.caseReducers.updateProvidedBy(
|
|
631
|
+
draft,
|
|
632
|
+
invalidationSlice.actions.updateProvidedBy(providedByEntries),
|
|
633
|
+
)
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Dummy slice to generate actions
|
|
637
|
+
const subscriptionSlice = createSlice({
|
|
638
|
+
name: `${reducerPath}/subscriptions`,
|
|
639
|
+
initialState: initialState as SubscriptionState,
|
|
640
|
+
reducers: {
|
|
641
|
+
updateSubscriptionOptions(
|
|
642
|
+
d,
|
|
643
|
+
a: PayloadAction<
|
|
644
|
+
{
|
|
645
|
+
endpointName: string
|
|
646
|
+
requestId: string
|
|
647
|
+
options: Subscribers[number]
|
|
648
|
+
} & QuerySubstateIdentifier
|
|
649
|
+
>,
|
|
650
|
+
) {
|
|
651
|
+
// Dummy
|
|
652
|
+
},
|
|
653
|
+
unsubscribeQueryResult(
|
|
654
|
+
d,
|
|
655
|
+
a: PayloadAction<{ requestId: string } & QuerySubstateIdentifier>,
|
|
656
|
+
) {
|
|
657
|
+
// Dummy
|
|
658
|
+
},
|
|
659
|
+
internal_getRTKQSubscriptions() {},
|
|
660
|
+
},
|
|
661
|
+
})
|
|
662
|
+
|
|
663
|
+
const internalSubscriptionsSlice = createSlice({
|
|
664
|
+
name: `${reducerPath}/internalSubscriptions`,
|
|
665
|
+
initialState: initialState as SubscriptionState,
|
|
666
|
+
reducers: {
|
|
667
|
+
subscriptionsUpdated: {
|
|
668
|
+
reducer(state, action: PayloadAction<Patch[]>) {
|
|
669
|
+
return applyPatches(state, action.payload)
|
|
670
|
+
},
|
|
671
|
+
prepare: prepareAutoBatched<Patch[]>(),
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
const configSlice = createSlice({
|
|
677
|
+
name: `${reducerPath}/config`,
|
|
678
|
+
initialState: {
|
|
679
|
+
online: isOnline(),
|
|
680
|
+
focused: isDocumentVisible(),
|
|
681
|
+
middlewareRegistered: false,
|
|
682
|
+
...config,
|
|
683
|
+
} as ConfigState<string>,
|
|
684
|
+
reducers: {
|
|
685
|
+
middlewareRegistered(state, { payload }: PayloadAction<string>) {
|
|
686
|
+
state.middlewareRegistered =
|
|
687
|
+
state.middlewareRegistered === 'conflict' || apiUid !== payload
|
|
688
|
+
? 'conflict'
|
|
689
|
+
: true
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
extraReducers: (builder) => {
|
|
693
|
+
builder
|
|
694
|
+
.addCase(onOnline, (state) => {
|
|
695
|
+
state.online = true
|
|
696
|
+
})
|
|
697
|
+
.addCase(onOffline, (state) => {
|
|
698
|
+
state.online = false
|
|
699
|
+
})
|
|
700
|
+
.addCase(onFocus, (state) => {
|
|
701
|
+
state.focused = true
|
|
702
|
+
})
|
|
703
|
+
.addCase(onFocusLost, (state) => {
|
|
704
|
+
state.focused = false
|
|
705
|
+
})
|
|
706
|
+
// update the state to be a new object to be picked up as a "state change"
|
|
707
|
+
// by redux-persist's `autoMergeLevel2`
|
|
708
|
+
.addMatcher(hasRehydrationInfo, (draft) => ({ ...draft }))
|
|
709
|
+
},
|
|
710
|
+
})
|
|
711
|
+
|
|
712
|
+
const combinedReducer = combineReducers({
|
|
713
|
+
queries: querySlice.reducer,
|
|
714
|
+
mutations: mutationSlice.reducer,
|
|
715
|
+
provided: invalidationSlice.reducer,
|
|
716
|
+
subscriptions: internalSubscriptionsSlice.reducer,
|
|
717
|
+
config: configSlice.reducer,
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
const reducer: typeof combinedReducer = (state, action) =>
|
|
721
|
+
combinedReducer(resetApiState.match(action) ? undefined : state, action)
|
|
722
|
+
|
|
723
|
+
const actions = {
|
|
724
|
+
...configSlice.actions,
|
|
725
|
+
...querySlice.actions,
|
|
726
|
+
...subscriptionSlice.actions,
|
|
727
|
+
...internalSubscriptionsSlice.actions,
|
|
728
|
+
...mutationSlice.actions,
|
|
729
|
+
...invalidationSlice.actions,
|
|
730
|
+
resetApiState,
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
return { reducer, actions }
|
|
734
|
+
}
|
|
735
|
+
export type SliceActions = ReturnType<typeof buildSlice>['actions']
|