@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,1124 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AsyncThunk,
|
|
3
|
+
AsyncThunkPayloadCreator,
|
|
4
|
+
Draft,
|
|
5
|
+
ThunkAction,
|
|
6
|
+
ThunkDispatch,
|
|
7
|
+
UnknownAction,
|
|
8
|
+
} from '@reduxjs/toolkit'
|
|
9
|
+
import type { Patch } from 'immer'
|
|
10
|
+
import { isDraftable, produceWithPatches } from '../utils/immerImports'
|
|
11
|
+
import type { Api, ApiContext } from '../apiTypes'
|
|
12
|
+
import type {
|
|
13
|
+
BaseQueryError,
|
|
14
|
+
BaseQueryFn,
|
|
15
|
+
QueryReturnValue,
|
|
16
|
+
} from '../baseQueryTypes'
|
|
17
|
+
import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
|
|
18
|
+
import type {
|
|
19
|
+
AssertTagTypes,
|
|
20
|
+
EndpointDefinition,
|
|
21
|
+
EndpointDefinitions,
|
|
22
|
+
InfiniteQueryArgFrom,
|
|
23
|
+
InfiniteQueryCombinedArg,
|
|
24
|
+
InfiniteQueryDefinition,
|
|
25
|
+
MutationDefinition,
|
|
26
|
+
PageParamFrom,
|
|
27
|
+
QueryArgFrom,
|
|
28
|
+
QueryDefinition,
|
|
29
|
+
ResultDescription,
|
|
30
|
+
ResultTypeFrom,
|
|
31
|
+
SchemaFailureConverter,
|
|
32
|
+
SchemaFailureHandler,
|
|
33
|
+
SchemaFailureInfo,
|
|
34
|
+
SchemaType,
|
|
35
|
+
} from '../endpointDefinitions'
|
|
36
|
+
import {
|
|
37
|
+
calculateProvidedBy,
|
|
38
|
+
ENDPOINT_QUERY,
|
|
39
|
+
isInfiniteQueryDefinition,
|
|
40
|
+
isQueryDefinition,
|
|
41
|
+
} from '../endpointDefinitions'
|
|
42
|
+
import { HandledError } from '../HandledError'
|
|
43
|
+
import type { UnwrapPromise } from '../tsHelpers'
|
|
44
|
+
import type {
|
|
45
|
+
RootState,
|
|
46
|
+
QueryKeys,
|
|
47
|
+
QuerySubstateIdentifier,
|
|
48
|
+
InfiniteData,
|
|
49
|
+
InfiniteQueryConfigOptions,
|
|
50
|
+
QueryCacheKey,
|
|
51
|
+
InfiniteQueryDirection,
|
|
52
|
+
InfiniteQueryKeys,
|
|
53
|
+
} from './apiState'
|
|
54
|
+
import { QueryStatus, STATUS_UNINITIALIZED } from './apiState'
|
|
55
|
+
import type {
|
|
56
|
+
InfiniteQueryActionCreatorResult,
|
|
57
|
+
QueryActionCreatorResult,
|
|
58
|
+
StartInfiniteQueryActionCreatorOptions,
|
|
59
|
+
StartQueryActionCreatorOptions,
|
|
60
|
+
} from './buildInitiate'
|
|
61
|
+
import { forceQueryFnSymbol, isUpsertQuery } from './buildInitiate'
|
|
62
|
+
import type { AllSelectors } from './buildSelectors'
|
|
63
|
+
import type { ApiEndpointQuery, PrefetchOptions } from './module'
|
|
64
|
+
import {
|
|
65
|
+
createAsyncThunk,
|
|
66
|
+
isAllOf,
|
|
67
|
+
isFulfilled,
|
|
68
|
+
isPending,
|
|
69
|
+
isRejected,
|
|
70
|
+
isRejectedWithValue,
|
|
71
|
+
SHOULD_AUTOBATCH,
|
|
72
|
+
} from './rtkImports'
|
|
73
|
+
import {
|
|
74
|
+
parseWithSchema,
|
|
75
|
+
NamedSchemaError,
|
|
76
|
+
shouldSkip,
|
|
77
|
+
} from '../standardSchema'
|
|
78
|
+
|
|
79
|
+
export type BuildThunksApiEndpointQuery<
|
|
80
|
+
Definition extends QueryDefinition<any, any, any, any, any>,
|
|
81
|
+
> = Matchers<QueryThunk, Definition>
|
|
82
|
+
|
|
83
|
+
export type BuildThunksApiEndpointInfiniteQuery<
|
|
84
|
+
Definition extends InfiniteQueryDefinition<any, any, any, any, any>,
|
|
85
|
+
> = Matchers<InfiniteQueryThunk<any>, Definition>
|
|
86
|
+
|
|
87
|
+
export type BuildThunksApiEndpointMutation<
|
|
88
|
+
Definition extends MutationDefinition<any, any, any, any, any>,
|
|
89
|
+
> = Matchers<MutationThunk, Definition>
|
|
90
|
+
|
|
91
|
+
type EndpointThunk<
|
|
92
|
+
Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
|
|
93
|
+
Definition extends EndpointDefinition<any, any, any, any>,
|
|
94
|
+
> =
|
|
95
|
+
Definition extends EndpointDefinition<
|
|
96
|
+
infer QueryArg,
|
|
97
|
+
infer BaseQueryFn,
|
|
98
|
+
any,
|
|
99
|
+
infer ResultType
|
|
100
|
+
>
|
|
101
|
+
? Thunk extends AsyncThunk<unknown, infer ATArg, infer ATConfig>
|
|
102
|
+
? AsyncThunk<
|
|
103
|
+
ResultType,
|
|
104
|
+
ATArg & { originalArgs: QueryArg },
|
|
105
|
+
ATConfig & { rejectValue: BaseQueryError<BaseQueryFn> }
|
|
106
|
+
>
|
|
107
|
+
: never
|
|
108
|
+
: Definition extends InfiniteQueryDefinition<
|
|
109
|
+
infer QueryArg,
|
|
110
|
+
infer PageParam,
|
|
111
|
+
infer BaseQueryFn,
|
|
112
|
+
any,
|
|
113
|
+
infer ResultType
|
|
114
|
+
>
|
|
115
|
+
? Thunk extends AsyncThunk<unknown, infer ATArg, infer ATConfig>
|
|
116
|
+
? AsyncThunk<
|
|
117
|
+
InfiniteData<ResultType, PageParam>,
|
|
118
|
+
ATArg & { originalArgs: QueryArg },
|
|
119
|
+
ATConfig & { rejectValue: BaseQueryError<BaseQueryFn> }
|
|
120
|
+
>
|
|
121
|
+
: never
|
|
122
|
+
: never
|
|
123
|
+
|
|
124
|
+
export type PendingAction<
|
|
125
|
+
Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
|
|
126
|
+
Definition extends EndpointDefinition<any, any, any, any>,
|
|
127
|
+
> = ReturnType<EndpointThunk<Thunk, Definition>['pending']>
|
|
128
|
+
|
|
129
|
+
export type FulfilledAction<
|
|
130
|
+
Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
|
|
131
|
+
Definition extends EndpointDefinition<any, any, any, any>,
|
|
132
|
+
> = ReturnType<EndpointThunk<Thunk, Definition>['fulfilled']>
|
|
133
|
+
|
|
134
|
+
export type RejectedAction<
|
|
135
|
+
Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
|
|
136
|
+
Definition extends EndpointDefinition<any, any, any, any>,
|
|
137
|
+
> = ReturnType<EndpointThunk<Thunk, Definition>['rejected']>
|
|
138
|
+
|
|
139
|
+
export type Matcher<M> = (value: any) => value is M
|
|
140
|
+
|
|
141
|
+
export interface Matchers<
|
|
142
|
+
Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
|
|
143
|
+
Definition extends EndpointDefinition<any, any, any, any>,
|
|
144
|
+
> {
|
|
145
|
+
matchPending: Matcher<PendingAction<Thunk, Definition>>
|
|
146
|
+
matchFulfilled: Matcher<FulfilledAction<Thunk, Definition>>
|
|
147
|
+
matchRejected: Matcher<RejectedAction<Thunk, Definition>>
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type QueryThunkArg = QuerySubstateIdentifier &
|
|
151
|
+
StartQueryActionCreatorOptions & {
|
|
152
|
+
type: 'query'
|
|
153
|
+
originalArgs: unknown
|
|
154
|
+
endpointName: string
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type InfiniteQueryThunkArg<
|
|
158
|
+
D extends InfiniteQueryDefinition<any, any, any, any, any>,
|
|
159
|
+
> = QuerySubstateIdentifier &
|
|
160
|
+
StartInfiniteQueryActionCreatorOptions<D> & {
|
|
161
|
+
type: `query`
|
|
162
|
+
originalArgs: unknown
|
|
163
|
+
endpointName: string
|
|
164
|
+
param: unknown
|
|
165
|
+
direction?: InfiniteQueryDirection
|
|
166
|
+
refetchCachedPages?: boolean
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
type MutationThunkArg = {
|
|
170
|
+
type: 'mutation'
|
|
171
|
+
originalArgs: unknown
|
|
172
|
+
endpointName: string
|
|
173
|
+
track?: boolean
|
|
174
|
+
fixedCacheKey?: string
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export type ThunkResult = unknown
|
|
178
|
+
|
|
179
|
+
export type ThunkApiMetaConfig = {
|
|
180
|
+
pendingMeta: { startedTimeStamp: number; [SHOULD_AUTOBATCH]: true }
|
|
181
|
+
fulfilledMeta: {
|
|
182
|
+
fulfilledTimeStamp: number
|
|
183
|
+
baseQueryMeta: unknown
|
|
184
|
+
[SHOULD_AUTOBATCH]: true
|
|
185
|
+
}
|
|
186
|
+
rejectedMeta: { baseQueryMeta: unknown; [SHOULD_AUTOBATCH]: true }
|
|
187
|
+
}
|
|
188
|
+
export type QueryThunk = AsyncThunk<
|
|
189
|
+
ThunkResult,
|
|
190
|
+
QueryThunkArg,
|
|
191
|
+
ThunkApiMetaConfig
|
|
192
|
+
>
|
|
193
|
+
export type InfiniteQueryThunk<
|
|
194
|
+
D extends InfiniteQueryDefinition<any, any, any, any, any>,
|
|
195
|
+
> = AsyncThunk<ThunkResult, InfiniteQueryThunkArg<D>, ThunkApiMetaConfig>
|
|
196
|
+
export type MutationThunk = AsyncThunk<
|
|
197
|
+
ThunkResult,
|
|
198
|
+
MutationThunkArg,
|
|
199
|
+
ThunkApiMetaConfig
|
|
200
|
+
>
|
|
201
|
+
|
|
202
|
+
function defaultTransformResponse(baseQueryReturnValue: unknown) {
|
|
203
|
+
return baseQueryReturnValue
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type MaybeDrafted<T> = T | Draft<T>
|
|
207
|
+
export type Recipe<T> = (data: MaybeDrafted<T>) => void | MaybeDrafted<T>
|
|
208
|
+
export type UpsertRecipe<T> = (
|
|
209
|
+
data: MaybeDrafted<T> | undefined,
|
|
210
|
+
) => void | MaybeDrafted<T>
|
|
211
|
+
|
|
212
|
+
export type PatchQueryDataThunk<
|
|
213
|
+
Definitions extends EndpointDefinitions,
|
|
214
|
+
PartialState,
|
|
215
|
+
> = <EndpointName extends QueryKeys<Definitions>>(
|
|
216
|
+
endpointName: EndpointName,
|
|
217
|
+
arg: QueryArgFrom<Definitions[EndpointName]>,
|
|
218
|
+
patches: readonly Patch[],
|
|
219
|
+
updateProvided?: boolean,
|
|
220
|
+
) => ThunkAction<void, PartialState, any, UnknownAction>
|
|
221
|
+
|
|
222
|
+
export type AllQueryKeys<Definitions extends EndpointDefinitions> =
|
|
223
|
+
| QueryKeys<Definitions>
|
|
224
|
+
| InfiniteQueryKeys<Definitions>
|
|
225
|
+
|
|
226
|
+
export type QueryArgFromAnyQueryDefinition<
|
|
227
|
+
Definitions extends EndpointDefinitions,
|
|
228
|
+
EndpointName extends AllQueryKeys<Definitions>,
|
|
229
|
+
> =
|
|
230
|
+
Definitions[EndpointName] extends InfiniteQueryDefinition<
|
|
231
|
+
any,
|
|
232
|
+
any,
|
|
233
|
+
any,
|
|
234
|
+
any,
|
|
235
|
+
any
|
|
236
|
+
>
|
|
237
|
+
? InfiniteQueryArgFrom<Definitions[EndpointName]>
|
|
238
|
+
: Definitions[EndpointName] extends QueryDefinition<any, any, any, any>
|
|
239
|
+
? QueryArgFrom<Definitions[EndpointName]>
|
|
240
|
+
: never
|
|
241
|
+
|
|
242
|
+
export type DataFromAnyQueryDefinition<
|
|
243
|
+
Definitions extends EndpointDefinitions,
|
|
244
|
+
EndpointName extends AllQueryKeys<Definitions>,
|
|
245
|
+
> =
|
|
246
|
+
Definitions[EndpointName] extends InfiniteQueryDefinition<
|
|
247
|
+
any,
|
|
248
|
+
any,
|
|
249
|
+
any,
|
|
250
|
+
any,
|
|
251
|
+
any
|
|
252
|
+
>
|
|
253
|
+
? InfiniteData<
|
|
254
|
+
ResultTypeFrom<Definitions[EndpointName]>,
|
|
255
|
+
PageParamFrom<Definitions[EndpointName]>
|
|
256
|
+
>
|
|
257
|
+
: Definitions[EndpointName] extends QueryDefinition<any, any, any, any>
|
|
258
|
+
? ResultTypeFrom<Definitions[EndpointName]>
|
|
259
|
+
: unknown
|
|
260
|
+
|
|
261
|
+
export type UpsertThunkResult<
|
|
262
|
+
Definitions extends EndpointDefinitions,
|
|
263
|
+
EndpointName extends AllQueryKeys<Definitions>,
|
|
264
|
+
> =
|
|
265
|
+
Definitions[EndpointName] extends InfiniteQueryDefinition<
|
|
266
|
+
any,
|
|
267
|
+
any,
|
|
268
|
+
any,
|
|
269
|
+
any,
|
|
270
|
+
any
|
|
271
|
+
>
|
|
272
|
+
? InfiniteQueryActionCreatorResult<Definitions[EndpointName]>
|
|
273
|
+
: Definitions[EndpointName] extends QueryDefinition<any, any, any, any>
|
|
274
|
+
? QueryActionCreatorResult<Definitions[EndpointName]>
|
|
275
|
+
: QueryActionCreatorResult<never>
|
|
276
|
+
|
|
277
|
+
export type UpdateQueryDataThunk<
|
|
278
|
+
Definitions extends EndpointDefinitions,
|
|
279
|
+
PartialState,
|
|
280
|
+
> = <EndpointName extends AllQueryKeys<Definitions>>(
|
|
281
|
+
endpointName: EndpointName,
|
|
282
|
+
arg: QueryArgFromAnyQueryDefinition<Definitions, EndpointName>,
|
|
283
|
+
updateRecipe: Recipe<DataFromAnyQueryDefinition<Definitions, EndpointName>>,
|
|
284
|
+
updateProvided?: boolean,
|
|
285
|
+
) => ThunkAction<PatchCollection, PartialState, any, UnknownAction>
|
|
286
|
+
|
|
287
|
+
export type UpsertQueryDataThunk<
|
|
288
|
+
Definitions extends EndpointDefinitions,
|
|
289
|
+
PartialState,
|
|
290
|
+
> = <EndpointName extends AllQueryKeys<Definitions>>(
|
|
291
|
+
endpointName: EndpointName,
|
|
292
|
+
arg: QueryArgFromAnyQueryDefinition<Definitions, EndpointName>,
|
|
293
|
+
value: DataFromAnyQueryDefinition<Definitions, EndpointName>,
|
|
294
|
+
) => ThunkAction<
|
|
295
|
+
UpsertThunkResult<Definitions, EndpointName>,
|
|
296
|
+
PartialState,
|
|
297
|
+
any,
|
|
298
|
+
UnknownAction
|
|
299
|
+
>
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* An object returned from dispatching a `api.util.updateQueryData` call.
|
|
303
|
+
*/
|
|
304
|
+
export type PatchCollection = {
|
|
305
|
+
/**
|
|
306
|
+
* An `immer` Patch describing the cache update.
|
|
307
|
+
*/
|
|
308
|
+
patches: Patch[]
|
|
309
|
+
/**
|
|
310
|
+
* An `immer` Patch to revert the cache update.
|
|
311
|
+
*/
|
|
312
|
+
inversePatches: Patch[]
|
|
313
|
+
/**
|
|
314
|
+
* A function that will undo the cache update.
|
|
315
|
+
*/
|
|
316
|
+
undo: () => void
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
type TransformCallback = (
|
|
320
|
+
baseQueryReturnValue: unknown,
|
|
321
|
+
meta: unknown,
|
|
322
|
+
arg: unknown,
|
|
323
|
+
) => any
|
|
324
|
+
|
|
325
|
+
export const addShouldAutoBatch = <T extends Record<string, any>>(
|
|
326
|
+
arg: T = {} as T,
|
|
327
|
+
): T & { [SHOULD_AUTOBATCH]: true } => {
|
|
328
|
+
return { ...arg, [SHOULD_AUTOBATCH]: true }
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function buildThunks<
|
|
332
|
+
BaseQuery extends BaseQueryFn,
|
|
333
|
+
ReducerPath extends string,
|
|
334
|
+
Definitions extends EndpointDefinitions,
|
|
335
|
+
>({
|
|
336
|
+
reducerPath,
|
|
337
|
+
baseQuery,
|
|
338
|
+
context: { endpointDefinitions },
|
|
339
|
+
serializeQueryArgs,
|
|
340
|
+
api,
|
|
341
|
+
assertTagType,
|
|
342
|
+
selectors,
|
|
343
|
+
onSchemaFailure,
|
|
344
|
+
catchSchemaFailure: globalCatchSchemaFailure,
|
|
345
|
+
skipSchemaValidation: globalSkipSchemaValidation,
|
|
346
|
+
}: {
|
|
347
|
+
baseQuery: BaseQuery
|
|
348
|
+
reducerPath: ReducerPath
|
|
349
|
+
context: ApiContext<Definitions>
|
|
350
|
+
serializeQueryArgs: InternalSerializeQueryArgs
|
|
351
|
+
api: Api<BaseQuery, Definitions, ReducerPath, any>
|
|
352
|
+
assertTagType: AssertTagTypes
|
|
353
|
+
selectors: AllSelectors
|
|
354
|
+
onSchemaFailure: SchemaFailureHandler | undefined
|
|
355
|
+
catchSchemaFailure: SchemaFailureConverter<BaseQuery> | undefined
|
|
356
|
+
skipSchemaValidation: boolean | SchemaType[] | undefined
|
|
357
|
+
}) {
|
|
358
|
+
type State = RootState<any, string, ReducerPath>
|
|
359
|
+
|
|
360
|
+
const patchQueryData: PatchQueryDataThunk<EndpointDefinitions, State> =
|
|
361
|
+
(endpointName, arg, patches, updateProvided) => (dispatch, getState) => {
|
|
362
|
+
const endpointDefinition = endpointDefinitions[endpointName]
|
|
363
|
+
|
|
364
|
+
const queryCacheKey = serializeQueryArgs({
|
|
365
|
+
queryArgs: arg,
|
|
366
|
+
endpointDefinition,
|
|
367
|
+
endpointName,
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
dispatch(
|
|
371
|
+
api.internalActions.queryResultPatched({ queryCacheKey, patches }),
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
if (!updateProvided) {
|
|
375
|
+
return
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const newValue = api.endpoints[endpointName].select(arg)(
|
|
379
|
+
// Work around TS 4.1 mismatch
|
|
380
|
+
getState() as RootState<any, any, any>,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
const providedTags = calculateProvidedBy(
|
|
384
|
+
endpointDefinition.providesTags,
|
|
385
|
+
newValue.data,
|
|
386
|
+
undefined,
|
|
387
|
+
arg,
|
|
388
|
+
{},
|
|
389
|
+
assertTagType,
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
dispatch(
|
|
393
|
+
api.internalActions.updateProvidedBy([{ queryCacheKey, providedTags }]),
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function addToStart<T>(items: Array<T>, item: T, max = 0): Array<T> {
|
|
398
|
+
const newItems = [item, ...items]
|
|
399
|
+
return max && newItems.length > max ? newItems.slice(0, -1) : newItems
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function addToEnd<T>(items: Array<T>, item: T, max = 0): Array<T> {
|
|
403
|
+
const newItems = [...items, item]
|
|
404
|
+
return max && newItems.length > max ? newItems.slice(1) : newItems
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const updateQueryData: UpdateQueryDataThunk<EndpointDefinitions, State> =
|
|
408
|
+
(endpointName, arg, updateRecipe, updateProvided = true) =>
|
|
409
|
+
(dispatch, getState) => {
|
|
410
|
+
const endpointDefinition = api.endpoints[endpointName]
|
|
411
|
+
|
|
412
|
+
const currentState = endpointDefinition.select(arg)(
|
|
413
|
+
// Work around TS 4.1 mismatch
|
|
414
|
+
getState() as RootState<any, any, any>,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
const ret: PatchCollection = {
|
|
418
|
+
patches: [],
|
|
419
|
+
inversePatches: [],
|
|
420
|
+
undo: () =>
|
|
421
|
+
dispatch(
|
|
422
|
+
api.util.patchQueryData(
|
|
423
|
+
endpointName,
|
|
424
|
+
arg,
|
|
425
|
+
ret.inversePatches,
|
|
426
|
+
updateProvided,
|
|
427
|
+
),
|
|
428
|
+
),
|
|
429
|
+
}
|
|
430
|
+
if (currentState.status === STATUS_UNINITIALIZED) {
|
|
431
|
+
return ret
|
|
432
|
+
}
|
|
433
|
+
let newValue
|
|
434
|
+
if ('data' in currentState) {
|
|
435
|
+
if (isDraftable(currentState.data)) {
|
|
436
|
+
const [value, patches, inversePatches] = produceWithPatches(
|
|
437
|
+
currentState.data,
|
|
438
|
+
updateRecipe,
|
|
439
|
+
)
|
|
440
|
+
ret.patches.push(...patches)
|
|
441
|
+
ret.inversePatches.push(...inversePatches)
|
|
442
|
+
newValue = value
|
|
443
|
+
} else {
|
|
444
|
+
newValue = updateRecipe(currentState.data)
|
|
445
|
+
ret.patches.push({ op: 'replace', path: [], value: newValue })
|
|
446
|
+
ret.inversePatches.push({
|
|
447
|
+
op: 'replace',
|
|
448
|
+
path: [],
|
|
449
|
+
value: currentState.data,
|
|
450
|
+
})
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (ret.patches.length === 0) {
|
|
455
|
+
return ret
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
dispatch(
|
|
459
|
+
api.util.patchQueryData(endpointName, arg, ret.patches, updateProvided),
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
return ret
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const upsertQueryData: UpsertQueryDataThunk<Definitions, State> =
|
|
466
|
+
(endpointName, arg, value) => (dispatch) => {
|
|
467
|
+
type EndpointName = typeof endpointName
|
|
468
|
+
const res = dispatch(
|
|
469
|
+
(
|
|
470
|
+
api.endpoints[endpointName] as ApiEndpointQuery<
|
|
471
|
+
QueryDefinition<any, any, any, any, any>,
|
|
472
|
+
Definitions
|
|
473
|
+
>
|
|
474
|
+
).initiate(arg, {
|
|
475
|
+
subscribe: false,
|
|
476
|
+
forceRefetch: true,
|
|
477
|
+
[forceQueryFnSymbol]: () => ({ data: value }),
|
|
478
|
+
}),
|
|
479
|
+
) as UpsertThunkResult<Definitions, EndpointName>
|
|
480
|
+
|
|
481
|
+
return res
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const getTransformCallbackForEndpoint = (
|
|
485
|
+
endpointDefinition: EndpointDefinition<any, any, any, any>,
|
|
486
|
+
transformFieldName: 'transformResponse' | 'transformErrorResponse',
|
|
487
|
+
): TransformCallback => {
|
|
488
|
+
return endpointDefinition.query && endpointDefinition[transformFieldName]
|
|
489
|
+
? (endpointDefinition[transformFieldName]! as TransformCallback)
|
|
490
|
+
: defaultTransformResponse
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// The generic async payload function for all of our thunks
|
|
494
|
+
const executeEndpoint: AsyncThunkPayloadCreator<
|
|
495
|
+
ThunkResult,
|
|
496
|
+
QueryThunkArg | MutationThunkArg | InfiniteQueryThunkArg<any>,
|
|
497
|
+
ThunkApiMetaConfig & { state: RootState<any, string, ReducerPath> }
|
|
498
|
+
> = async (
|
|
499
|
+
arg,
|
|
500
|
+
{
|
|
501
|
+
signal,
|
|
502
|
+
abort,
|
|
503
|
+
rejectWithValue,
|
|
504
|
+
fulfillWithValue,
|
|
505
|
+
dispatch,
|
|
506
|
+
getState,
|
|
507
|
+
extra,
|
|
508
|
+
},
|
|
509
|
+
) => {
|
|
510
|
+
const endpointDefinition = endpointDefinitions[arg.endpointName]
|
|
511
|
+
const { metaSchema, skipSchemaValidation = globalSkipSchemaValidation } =
|
|
512
|
+
endpointDefinition
|
|
513
|
+
|
|
514
|
+
const isQuery = arg.type === ENDPOINT_QUERY
|
|
515
|
+
|
|
516
|
+
try {
|
|
517
|
+
let transformResponse: TransformCallback = defaultTransformResponse
|
|
518
|
+
|
|
519
|
+
const baseQueryApi = {
|
|
520
|
+
signal,
|
|
521
|
+
abort,
|
|
522
|
+
dispatch,
|
|
523
|
+
getState,
|
|
524
|
+
extra,
|
|
525
|
+
endpoint: arg.endpointName,
|
|
526
|
+
type: arg.type,
|
|
527
|
+
forced: isQuery ? isForcedQuery(arg, getState()) : undefined,
|
|
528
|
+
queryCacheKey: isQuery ? arg.queryCacheKey : undefined,
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const forceQueryFn = isQuery ? arg[forceQueryFnSymbol] : undefined
|
|
532
|
+
|
|
533
|
+
let finalQueryReturnValue: QueryReturnValue
|
|
534
|
+
|
|
535
|
+
// Infinite query wrapper, which executes the request and returns
|
|
536
|
+
// the InfiniteData `{pages, pageParams}` structure
|
|
537
|
+
const fetchPage = async (
|
|
538
|
+
data: InfiniteData<unknown, unknown>,
|
|
539
|
+
param: unknown,
|
|
540
|
+
maxPages: number,
|
|
541
|
+
previous?: boolean,
|
|
542
|
+
): Promise<QueryReturnValue> => {
|
|
543
|
+
// This should handle cases where there is no `getPrevPageParam`,
|
|
544
|
+
// or `getPPP` returned nullish
|
|
545
|
+
if (param == null && data.pages.length) {
|
|
546
|
+
return Promise.resolve({ data })
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const finalQueryArg: InfiniteQueryCombinedArg<any, any> = {
|
|
550
|
+
queryArg: arg.originalArgs,
|
|
551
|
+
pageParam: param,
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const pageResponse = await executeRequest(finalQueryArg)
|
|
555
|
+
|
|
556
|
+
const addTo = previous ? addToStart : addToEnd
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
data: {
|
|
560
|
+
pages: addTo(data.pages, pageResponse.data, maxPages),
|
|
561
|
+
pageParams: addTo(data.pageParams, param, maxPages),
|
|
562
|
+
},
|
|
563
|
+
meta: pageResponse.meta,
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Wrapper for executing either `query` or `queryFn`,
|
|
568
|
+
// and handling any errors
|
|
569
|
+
async function executeRequest(
|
|
570
|
+
finalQueryArg: unknown,
|
|
571
|
+
): Promise<QueryReturnValue> {
|
|
572
|
+
let result: QueryReturnValue
|
|
573
|
+
const { extraOptions, argSchema, rawResponseSchema, responseSchema } =
|
|
574
|
+
endpointDefinition
|
|
575
|
+
|
|
576
|
+
if (argSchema && !shouldSkip(skipSchemaValidation, 'arg')) {
|
|
577
|
+
finalQueryArg = await parseWithSchema(
|
|
578
|
+
argSchema,
|
|
579
|
+
finalQueryArg,
|
|
580
|
+
'argSchema',
|
|
581
|
+
{}, // we don't have a meta yet, so we can't pass it
|
|
582
|
+
)
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (forceQueryFn) {
|
|
586
|
+
// upsertQueryData relies on this to pass in the user-provided value
|
|
587
|
+
result = forceQueryFn()
|
|
588
|
+
} else if (endpointDefinition.query) {
|
|
589
|
+
// We should only run `transformResponse` when the endpoint has a `query` method,
|
|
590
|
+
// and we're not doing an `upsertQueryData`.
|
|
591
|
+
transformResponse = getTransformCallbackForEndpoint(
|
|
592
|
+
endpointDefinition,
|
|
593
|
+
'transformResponse',
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
result = await baseQuery(
|
|
597
|
+
endpointDefinition.query(finalQueryArg as any),
|
|
598
|
+
baseQueryApi,
|
|
599
|
+
extraOptions as any,
|
|
600
|
+
)
|
|
601
|
+
} else {
|
|
602
|
+
result = await endpointDefinition.queryFn(
|
|
603
|
+
finalQueryArg as any,
|
|
604
|
+
baseQueryApi,
|
|
605
|
+
extraOptions as any,
|
|
606
|
+
(arg) => baseQuery(arg, baseQueryApi, extraOptions as any),
|
|
607
|
+
)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (
|
|
611
|
+
typeof process !== 'undefined' &&
|
|
612
|
+
process.env.NODE_ENV === 'development'
|
|
613
|
+
) {
|
|
614
|
+
const what = endpointDefinition.query ? '`baseQuery`' : '`queryFn`'
|
|
615
|
+
let err: undefined | string
|
|
616
|
+
if (!result) {
|
|
617
|
+
err = `${what} did not return anything.`
|
|
618
|
+
} else if (typeof result !== 'object') {
|
|
619
|
+
err = `${what} did not return an object.`
|
|
620
|
+
} else if (result.error && result.data) {
|
|
621
|
+
err = `${what} returned an object containing both \`error\` and \`result\`.`
|
|
622
|
+
} else if (result.error === undefined && result.data === undefined) {
|
|
623
|
+
err = `${what} returned an object containing neither a valid \`error\` and \`result\`. At least one of them should not be \`undefined\``
|
|
624
|
+
} else {
|
|
625
|
+
for (const key of Object.keys(result)) {
|
|
626
|
+
if (key !== 'error' && key !== 'data' && key !== 'meta') {
|
|
627
|
+
err = `The object returned by ${what} has the unknown property ${key}.`
|
|
628
|
+
break
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if (err) {
|
|
633
|
+
console.error(
|
|
634
|
+
`Error encountered handling the endpoint ${arg.endpointName}.
|
|
635
|
+
${err}
|
|
636
|
+
It needs to return an object with either the shape \`{ data: <value> }\` or \`{ error: <value> }\` that may contain an optional \`meta\` property.
|
|
637
|
+
Object returned was:`,
|
|
638
|
+
result,
|
|
639
|
+
)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if (result.error) throw new HandledError(result.error, result.meta)
|
|
644
|
+
|
|
645
|
+
let { data } = result
|
|
646
|
+
|
|
647
|
+
if (
|
|
648
|
+
rawResponseSchema &&
|
|
649
|
+
!shouldSkip(skipSchemaValidation, 'rawResponse')
|
|
650
|
+
) {
|
|
651
|
+
data = await parseWithSchema(
|
|
652
|
+
rawResponseSchema,
|
|
653
|
+
result.data,
|
|
654
|
+
'rawResponseSchema',
|
|
655
|
+
result.meta,
|
|
656
|
+
)
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
let transformedResponse = await transformResponse(
|
|
660
|
+
data,
|
|
661
|
+
result.meta,
|
|
662
|
+
finalQueryArg,
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
if (responseSchema && !shouldSkip(skipSchemaValidation, 'response')) {
|
|
666
|
+
transformedResponse = await parseWithSchema(
|
|
667
|
+
responseSchema,
|
|
668
|
+
transformedResponse,
|
|
669
|
+
'responseSchema',
|
|
670
|
+
result.meta,
|
|
671
|
+
)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
return {
|
|
675
|
+
...result,
|
|
676
|
+
data: transformedResponse,
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (isQuery && 'infiniteQueryOptions' in endpointDefinition) {
|
|
681
|
+
// This is an infinite query endpoint
|
|
682
|
+
const { infiniteQueryOptions } = endpointDefinition
|
|
683
|
+
|
|
684
|
+
// Runtime checks should guarantee this is a positive number if provided
|
|
685
|
+
const { maxPages = Infinity } = infiniteQueryOptions
|
|
686
|
+
|
|
687
|
+
// Priority: per-call override > endpoint config > default (true)
|
|
688
|
+
const refetchCachedPages =
|
|
689
|
+
(arg as InfiniteQueryThunkArg<any>).refetchCachedPages ??
|
|
690
|
+
infiniteQueryOptions.refetchCachedPages ??
|
|
691
|
+
true
|
|
692
|
+
|
|
693
|
+
let result: QueryReturnValue
|
|
694
|
+
|
|
695
|
+
// Start by looking up the existing InfiniteData value from state,
|
|
696
|
+
// falling back to an empty value if it doesn't exist yet
|
|
697
|
+
const blankData = { pages: [], pageParams: [] }
|
|
698
|
+
const cachedData = selectors.selectQueryEntry(
|
|
699
|
+
getState(),
|
|
700
|
+
arg.queryCacheKey,
|
|
701
|
+
)?.data as InfiniteData<unknown, unknown> | undefined
|
|
702
|
+
|
|
703
|
+
// When the arg changes or the user forces a refetch,
|
|
704
|
+
// we don't include the `direction` flag. This lets us distinguish
|
|
705
|
+
// between actually refetching with a forced query, vs just fetching
|
|
706
|
+
// the next page.
|
|
707
|
+
const isForcedQueryNeedingRefetch = // arg.forceRefetch
|
|
708
|
+
isForcedQuery(arg, getState()) &&
|
|
709
|
+
!(arg as InfiniteQueryThunkArg<any>).direction
|
|
710
|
+
const existingData = (
|
|
711
|
+
isForcedQueryNeedingRefetch || !cachedData ? blankData : cachedData
|
|
712
|
+
) as InfiniteData<unknown, unknown>
|
|
713
|
+
|
|
714
|
+
// If the thunk specified a direction and we do have at least one page,
|
|
715
|
+
// fetch the next or previous page
|
|
716
|
+
if ('direction' in arg && arg.direction && existingData.pages.length) {
|
|
717
|
+
const previous = arg.direction === 'backward'
|
|
718
|
+
const pageParamFn = previous ? getPreviousPageParam : getNextPageParam
|
|
719
|
+
const param = pageParamFn(
|
|
720
|
+
infiniteQueryOptions,
|
|
721
|
+
existingData,
|
|
722
|
+
arg.originalArgs,
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
result = await fetchPage(existingData, param, maxPages, previous)
|
|
726
|
+
} else {
|
|
727
|
+
// Otherwise, fetch the first page and then any remaining pages
|
|
728
|
+
|
|
729
|
+
const { initialPageParam = infiniteQueryOptions.initialPageParam } =
|
|
730
|
+
arg as InfiniteQueryThunkArg<any>
|
|
731
|
+
|
|
732
|
+
// If we're doing a refetch, we should start from
|
|
733
|
+
// the first page we have cached.
|
|
734
|
+
// Otherwise, we should start from the initialPageParam
|
|
735
|
+
const cachedPageParams = cachedData?.pageParams ?? []
|
|
736
|
+
const firstPageParam = cachedPageParams[0] ?? initialPageParam
|
|
737
|
+
const totalPages = cachedPageParams.length
|
|
738
|
+
|
|
739
|
+
// Fetch first page
|
|
740
|
+
result = await fetchPage(existingData, firstPageParam, maxPages)
|
|
741
|
+
|
|
742
|
+
if (forceQueryFn) {
|
|
743
|
+
// HACK `upsertQueryData` expects the user to pass in the `{pages, pageParams}` structure,
|
|
744
|
+
// but `fetchPage` treats that as `pages[0]`. We have to manually un-nest it.
|
|
745
|
+
result = {
|
|
746
|
+
data: (result.data as InfiniteData<unknown, unknown>).pages[0],
|
|
747
|
+
} as QueryReturnValue
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (refetchCachedPages) {
|
|
751
|
+
// Fetch remaining pages
|
|
752
|
+
for (let i = 1; i < totalPages; i++) {
|
|
753
|
+
const param = getNextPageParam(
|
|
754
|
+
infiniteQueryOptions,
|
|
755
|
+
result.data as InfiniteData<unknown, unknown>,
|
|
756
|
+
arg.originalArgs,
|
|
757
|
+
)
|
|
758
|
+
result = await fetchPage(
|
|
759
|
+
result.data as InfiniteData<unknown, unknown>,
|
|
760
|
+
param,
|
|
761
|
+
maxPages,
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
finalQueryReturnValue = result
|
|
768
|
+
} else {
|
|
769
|
+
// Non-infinite endpoint. Just run the one request.
|
|
770
|
+
finalQueryReturnValue = await executeRequest(arg.originalArgs)
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (
|
|
774
|
+
metaSchema &&
|
|
775
|
+
!shouldSkip(skipSchemaValidation, 'meta') &&
|
|
776
|
+
finalQueryReturnValue.meta
|
|
777
|
+
) {
|
|
778
|
+
finalQueryReturnValue.meta = await parseWithSchema(
|
|
779
|
+
metaSchema,
|
|
780
|
+
finalQueryReturnValue.meta,
|
|
781
|
+
'metaSchema',
|
|
782
|
+
finalQueryReturnValue.meta,
|
|
783
|
+
)
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// console.log('Final result: ', transformedData)
|
|
787
|
+
return fulfillWithValue(
|
|
788
|
+
finalQueryReturnValue.data,
|
|
789
|
+
addShouldAutoBatch({
|
|
790
|
+
fulfilledTimeStamp: Date.now(),
|
|
791
|
+
baseQueryMeta: finalQueryReturnValue.meta,
|
|
792
|
+
}),
|
|
793
|
+
)
|
|
794
|
+
} catch (error) {
|
|
795
|
+
let caughtError = error
|
|
796
|
+
if (caughtError instanceof HandledError) {
|
|
797
|
+
let transformErrorResponse = getTransformCallbackForEndpoint(
|
|
798
|
+
endpointDefinition,
|
|
799
|
+
'transformErrorResponse',
|
|
800
|
+
)
|
|
801
|
+
const { rawErrorResponseSchema, errorResponseSchema } =
|
|
802
|
+
endpointDefinition
|
|
803
|
+
|
|
804
|
+
let { value, meta } = caughtError
|
|
805
|
+
|
|
806
|
+
try {
|
|
807
|
+
if (
|
|
808
|
+
rawErrorResponseSchema &&
|
|
809
|
+
!shouldSkip(skipSchemaValidation, 'rawErrorResponse')
|
|
810
|
+
) {
|
|
811
|
+
value = await parseWithSchema(
|
|
812
|
+
rawErrorResponseSchema,
|
|
813
|
+
value,
|
|
814
|
+
'rawErrorResponseSchema',
|
|
815
|
+
meta,
|
|
816
|
+
)
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if (metaSchema && !shouldSkip(skipSchemaValidation, 'meta')) {
|
|
820
|
+
meta = await parseWithSchema(metaSchema, meta, 'metaSchema', meta)
|
|
821
|
+
}
|
|
822
|
+
let transformedErrorResponse = await transformErrorResponse(
|
|
823
|
+
value,
|
|
824
|
+
meta,
|
|
825
|
+
arg.originalArgs,
|
|
826
|
+
)
|
|
827
|
+
if (
|
|
828
|
+
errorResponseSchema &&
|
|
829
|
+
!shouldSkip(skipSchemaValidation, 'errorResponse')
|
|
830
|
+
) {
|
|
831
|
+
transformedErrorResponse = await parseWithSchema(
|
|
832
|
+
errorResponseSchema,
|
|
833
|
+
transformedErrorResponse,
|
|
834
|
+
'errorResponseSchema',
|
|
835
|
+
meta,
|
|
836
|
+
)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
return rejectWithValue(
|
|
840
|
+
transformedErrorResponse,
|
|
841
|
+
addShouldAutoBatch({ baseQueryMeta: meta }),
|
|
842
|
+
)
|
|
843
|
+
} catch (e) {
|
|
844
|
+
caughtError = e
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
try {
|
|
848
|
+
if (caughtError instanceof NamedSchemaError) {
|
|
849
|
+
const info: SchemaFailureInfo = {
|
|
850
|
+
endpoint: arg.endpointName,
|
|
851
|
+
arg: arg.originalArgs,
|
|
852
|
+
type: arg.type,
|
|
853
|
+
queryCacheKey: isQuery ? arg.queryCacheKey : undefined,
|
|
854
|
+
}
|
|
855
|
+
endpointDefinition.onSchemaFailure?.(caughtError, info)
|
|
856
|
+
onSchemaFailure?.(caughtError, info)
|
|
857
|
+
const { catchSchemaFailure = globalCatchSchemaFailure } =
|
|
858
|
+
endpointDefinition
|
|
859
|
+
if (catchSchemaFailure) {
|
|
860
|
+
return rejectWithValue(
|
|
861
|
+
catchSchemaFailure(caughtError, info),
|
|
862
|
+
addShouldAutoBatch({ baseQueryMeta: caughtError._bqMeta }),
|
|
863
|
+
)
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
} catch (e) {
|
|
867
|
+
caughtError = e
|
|
868
|
+
}
|
|
869
|
+
if (
|
|
870
|
+
typeof process !== 'undefined' &&
|
|
871
|
+
process.env.NODE_ENV !== 'production'
|
|
872
|
+
) {
|
|
873
|
+
console.error(
|
|
874
|
+
`An unhandled error occurred processing a request for the endpoint "${arg.endpointName}".
|
|
875
|
+
In the case of an unhandled error, no tags will be "provided" or "invalidated".`,
|
|
876
|
+
caughtError,
|
|
877
|
+
)
|
|
878
|
+
} else {
|
|
879
|
+
console.error(caughtError)
|
|
880
|
+
}
|
|
881
|
+
throw caughtError
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
function isForcedQuery(
|
|
886
|
+
arg: QueryThunkArg,
|
|
887
|
+
state: RootState<any, string, ReducerPath>,
|
|
888
|
+
) {
|
|
889
|
+
const requestState = selectors.selectQueryEntry(state, arg.queryCacheKey)
|
|
890
|
+
const baseFetchOnMountOrArgChange =
|
|
891
|
+
selectors.selectConfig(state).refetchOnMountOrArgChange
|
|
892
|
+
|
|
893
|
+
const fulfilledVal = requestState?.fulfilledTimeStamp
|
|
894
|
+
const refetchVal =
|
|
895
|
+
arg.forceRefetch ?? (arg.subscribe && baseFetchOnMountOrArgChange)
|
|
896
|
+
|
|
897
|
+
if (refetchVal) {
|
|
898
|
+
// Return if it's true or compare the dates because it must be a number
|
|
899
|
+
return (
|
|
900
|
+
refetchVal === true ||
|
|
901
|
+
(Number(new Date()) - Number(fulfilledVal)) / 1000 >= refetchVal
|
|
902
|
+
)
|
|
903
|
+
}
|
|
904
|
+
return false
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
const createQueryThunk = <
|
|
908
|
+
ThunkArgType extends QueryThunkArg | InfiniteQueryThunkArg<any>,
|
|
909
|
+
>() => {
|
|
910
|
+
const generatedQueryThunk = createAsyncThunk<
|
|
911
|
+
ThunkResult,
|
|
912
|
+
ThunkArgType,
|
|
913
|
+
ThunkApiMetaConfig & { state: RootState<any, string, ReducerPath> }
|
|
914
|
+
>(`${reducerPath}/executeQuery`, executeEndpoint, {
|
|
915
|
+
getPendingMeta({ arg }) {
|
|
916
|
+
const endpointDefinition = endpointDefinitions[arg.endpointName]
|
|
917
|
+
return addShouldAutoBatch({
|
|
918
|
+
startedTimeStamp: Date.now(),
|
|
919
|
+
...(isInfiniteQueryDefinition(endpointDefinition)
|
|
920
|
+
? { direction: (arg as InfiniteQueryThunkArg<any>).direction }
|
|
921
|
+
: {}),
|
|
922
|
+
})
|
|
923
|
+
},
|
|
924
|
+
condition(queryThunkArg, { getState }) {
|
|
925
|
+
const state = getState()
|
|
926
|
+
|
|
927
|
+
const requestState = selectors.selectQueryEntry(
|
|
928
|
+
state,
|
|
929
|
+
queryThunkArg.queryCacheKey,
|
|
930
|
+
)
|
|
931
|
+
const fulfilledVal = requestState?.fulfilledTimeStamp
|
|
932
|
+
const currentArg = queryThunkArg.originalArgs
|
|
933
|
+
const previousArg = requestState?.originalArgs
|
|
934
|
+
const endpointDefinition =
|
|
935
|
+
endpointDefinitions[queryThunkArg.endpointName]
|
|
936
|
+
const direction = (queryThunkArg as InfiniteQueryThunkArg<any>)
|
|
937
|
+
.direction
|
|
938
|
+
|
|
939
|
+
// Order of these checks matters.
|
|
940
|
+
// In order for `upsertQueryData` to successfully run while an existing request is in flight,
|
|
941
|
+
/// we have to check for that first, otherwise `queryThunk` will bail out and not run at all.
|
|
942
|
+
if (isUpsertQuery(queryThunkArg)) {
|
|
943
|
+
return true
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// Don't retry a request that's currently in-flight
|
|
947
|
+
if (requestState?.status === 'pending') {
|
|
948
|
+
return false
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// if this is forced, continue
|
|
952
|
+
if (isForcedQuery(queryThunkArg, state)) {
|
|
953
|
+
return true
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
if (
|
|
957
|
+
isQueryDefinition(endpointDefinition) &&
|
|
958
|
+
endpointDefinition?.forceRefetch?.({
|
|
959
|
+
currentArg,
|
|
960
|
+
previousArg,
|
|
961
|
+
endpointState: requestState,
|
|
962
|
+
state,
|
|
963
|
+
})
|
|
964
|
+
) {
|
|
965
|
+
return true
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Pull from the cache unless we explicitly force refetch or qualify based on time
|
|
969
|
+
if (fulfilledVal && !direction) {
|
|
970
|
+
// Value is cached and we didn't specify to refresh, skip it.
|
|
971
|
+
return false
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
return true
|
|
975
|
+
},
|
|
976
|
+
dispatchConditionRejection: true,
|
|
977
|
+
})
|
|
978
|
+
return generatedQueryThunk
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
const queryThunk = createQueryThunk<QueryThunkArg>()
|
|
982
|
+
const infiniteQueryThunk = createQueryThunk<InfiniteQueryThunkArg<any>>()
|
|
983
|
+
|
|
984
|
+
const mutationThunk = createAsyncThunk<
|
|
985
|
+
ThunkResult,
|
|
986
|
+
MutationThunkArg,
|
|
987
|
+
ThunkApiMetaConfig & { state: RootState<any, string, ReducerPath> }
|
|
988
|
+
>(`${reducerPath}/executeMutation`, executeEndpoint, {
|
|
989
|
+
getPendingMeta() {
|
|
990
|
+
return addShouldAutoBatch({ startedTimeStamp: Date.now() })
|
|
991
|
+
},
|
|
992
|
+
})
|
|
993
|
+
|
|
994
|
+
const hasTheForce = (options: any): options is { force: boolean } =>
|
|
995
|
+
'force' in options
|
|
996
|
+
const hasMaxAge = (
|
|
997
|
+
options: any,
|
|
998
|
+
): options is { ifOlderThan: false | number } => 'ifOlderThan' in options
|
|
999
|
+
|
|
1000
|
+
const prefetch =
|
|
1001
|
+
<EndpointName extends QueryKeys<Definitions>>(
|
|
1002
|
+
endpointName: EndpointName,
|
|
1003
|
+
arg: any,
|
|
1004
|
+
options: PrefetchOptions = {},
|
|
1005
|
+
): ThunkAction<void, any, any, UnknownAction> =>
|
|
1006
|
+
(dispatch: ThunkDispatch<any, any, any>, getState: () => any) => {
|
|
1007
|
+
const force = hasTheForce(options) && options.force
|
|
1008
|
+
const maxAge = hasMaxAge(options) && options.ifOlderThan
|
|
1009
|
+
|
|
1010
|
+
const queryAction = (force: boolean = true) => {
|
|
1011
|
+
const options: StartQueryActionCreatorOptions = {
|
|
1012
|
+
forceRefetch: force,
|
|
1013
|
+
subscribe: false,
|
|
1014
|
+
}
|
|
1015
|
+
return (
|
|
1016
|
+
api.endpoints[endpointName] as ApiEndpointQuery<any, any>
|
|
1017
|
+
).initiate(arg, options)
|
|
1018
|
+
}
|
|
1019
|
+
const latestStateValue = (
|
|
1020
|
+
api.endpoints[endpointName] as ApiEndpointQuery<any, any>
|
|
1021
|
+
).select(arg)(getState())
|
|
1022
|
+
|
|
1023
|
+
if (force) {
|
|
1024
|
+
dispatch(queryAction())
|
|
1025
|
+
} else if (maxAge) {
|
|
1026
|
+
const lastFulfilledTs = latestStateValue?.fulfilledTimeStamp
|
|
1027
|
+
if (!lastFulfilledTs) {
|
|
1028
|
+
dispatch(queryAction())
|
|
1029
|
+
return
|
|
1030
|
+
}
|
|
1031
|
+
const shouldRetrigger =
|
|
1032
|
+
(Number(new Date()) - Number(new Date(lastFulfilledTs))) / 1000 >=
|
|
1033
|
+
maxAge
|
|
1034
|
+
if (shouldRetrigger) {
|
|
1035
|
+
dispatch(queryAction())
|
|
1036
|
+
}
|
|
1037
|
+
} else {
|
|
1038
|
+
// If prefetching with no options, just let it try
|
|
1039
|
+
dispatch(queryAction(false))
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
function matchesEndpoint(endpointName: string) {
|
|
1044
|
+
return (action: any): action is UnknownAction =>
|
|
1045
|
+
action?.meta?.arg?.endpointName === endpointName
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function buildMatchThunkActions<
|
|
1049
|
+
Thunk extends
|
|
1050
|
+
| AsyncThunk<any, QueryThunkArg, ThunkApiMetaConfig>
|
|
1051
|
+
| AsyncThunk<any, MutationThunkArg, ThunkApiMetaConfig>,
|
|
1052
|
+
>(thunk: Thunk, endpointName: string) {
|
|
1053
|
+
return {
|
|
1054
|
+
matchPending: isAllOf(isPending(thunk), matchesEndpoint(endpointName)),
|
|
1055
|
+
matchFulfilled: isAllOf(
|
|
1056
|
+
isFulfilled(thunk),
|
|
1057
|
+
matchesEndpoint(endpointName),
|
|
1058
|
+
),
|
|
1059
|
+
matchRejected: isAllOf(isRejected(thunk), matchesEndpoint(endpointName)),
|
|
1060
|
+
} as Matchers<Thunk, any>
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
return {
|
|
1064
|
+
queryThunk,
|
|
1065
|
+
mutationThunk,
|
|
1066
|
+
infiniteQueryThunk,
|
|
1067
|
+
prefetch,
|
|
1068
|
+
updateQueryData,
|
|
1069
|
+
upsertQueryData,
|
|
1070
|
+
patchQueryData,
|
|
1071
|
+
buildMatchThunkActions,
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
export function getNextPageParam(
|
|
1076
|
+
options: InfiniteQueryConfigOptions<unknown, unknown, unknown>,
|
|
1077
|
+
{ pages, pageParams }: InfiniteData<unknown, unknown>,
|
|
1078
|
+
queryArg: unknown,
|
|
1079
|
+
): unknown | undefined {
|
|
1080
|
+
const lastIndex = pages.length - 1
|
|
1081
|
+
return options.getNextPageParam(
|
|
1082
|
+
pages[lastIndex],
|
|
1083
|
+
pages,
|
|
1084
|
+
pageParams[lastIndex],
|
|
1085
|
+
pageParams,
|
|
1086
|
+
queryArg,
|
|
1087
|
+
)
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
export function getPreviousPageParam(
|
|
1091
|
+
options: InfiniteQueryConfigOptions<unknown, unknown, unknown>,
|
|
1092
|
+
{ pages, pageParams }: InfiniteData<unknown, unknown>,
|
|
1093
|
+
queryArg: unknown,
|
|
1094
|
+
): unknown | undefined {
|
|
1095
|
+
return options.getPreviousPageParam?.(
|
|
1096
|
+
pages[0],
|
|
1097
|
+
pages,
|
|
1098
|
+
pageParams[0],
|
|
1099
|
+
pageParams,
|
|
1100
|
+
queryArg,
|
|
1101
|
+
)
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
export function calculateProvidedByThunk(
|
|
1105
|
+
action: UnwrapPromise<
|
|
1106
|
+
| ReturnType<ReturnType<QueryThunk>>
|
|
1107
|
+
| ReturnType<ReturnType<MutationThunk>>
|
|
1108
|
+
| ReturnType<ReturnType<InfiniteQueryThunk<any>>>
|
|
1109
|
+
>,
|
|
1110
|
+
type: 'providesTags' | 'invalidatesTags',
|
|
1111
|
+
endpointDefinitions: EndpointDefinitions,
|
|
1112
|
+
assertTagType: AssertTagTypes,
|
|
1113
|
+
) {
|
|
1114
|
+
return calculateProvidedBy(
|
|
1115
|
+
endpointDefinitions[action.meta.arg.endpointName][
|
|
1116
|
+
type
|
|
1117
|
+
] as ResultDescription<any, any, any, any, any>,
|
|
1118
|
+
isFulfilled(action) ? action.payload : undefined,
|
|
1119
|
+
isRejectedWithValue(action) ? action.payload : undefined,
|
|
1120
|
+
action.meta.arg.originalArgs,
|
|
1121
|
+
'baseQueryMeta' in action.meta ? action.meta.baseQueryMeta : undefined,
|
|
1122
|
+
assertTagType,
|
|
1123
|
+
)
|
|
1124
|
+
}
|