@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,173 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Action,
|
|
3
|
+
AsyncThunkAction,
|
|
4
|
+
Dispatch,
|
|
5
|
+
Middleware,
|
|
6
|
+
MiddlewareAPI,
|
|
7
|
+
ThunkAction,
|
|
8
|
+
ThunkDispatch,
|
|
9
|
+
UnknownAction,
|
|
10
|
+
} from '@reduxjs/toolkit'
|
|
11
|
+
import type { Api, ApiContext } from '../../apiTypes'
|
|
12
|
+
import type {
|
|
13
|
+
AssertTagTypes,
|
|
14
|
+
EndpointDefinitions,
|
|
15
|
+
} from '../../endpointDefinitions'
|
|
16
|
+
import type {
|
|
17
|
+
QueryStatus,
|
|
18
|
+
QuerySubState,
|
|
19
|
+
RootState,
|
|
20
|
+
SubscriptionInternalState,
|
|
21
|
+
SubscriptionState,
|
|
22
|
+
} from '../apiState'
|
|
23
|
+
import type {
|
|
24
|
+
InfiniteQueryThunk,
|
|
25
|
+
MutationThunk,
|
|
26
|
+
QueryThunk,
|
|
27
|
+
QueryThunkArg,
|
|
28
|
+
ThunkResult,
|
|
29
|
+
} from '../buildThunks'
|
|
30
|
+
import type {
|
|
31
|
+
InfiniteQueryActionCreatorResult,
|
|
32
|
+
MutationActionCreatorResult,
|
|
33
|
+
QueryActionCreatorResult,
|
|
34
|
+
} from '../buildInitiate'
|
|
35
|
+
import type { AllSelectors } from '../buildSelectors'
|
|
36
|
+
|
|
37
|
+
export type QueryStateMeta<T> = Record<string, undefined | T>
|
|
38
|
+
export type TimeoutId = ReturnType<typeof setTimeout>
|
|
39
|
+
|
|
40
|
+
type QueryPollState = {
|
|
41
|
+
nextPollTimestamp: number
|
|
42
|
+
timeout?: TimeoutId
|
|
43
|
+
pollingInterval: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface InternalMiddlewareState {
|
|
47
|
+
currentSubscriptions: SubscriptionInternalState
|
|
48
|
+
currentPolls: Map<string, QueryPollState>
|
|
49
|
+
runningQueries: Map<
|
|
50
|
+
string,
|
|
51
|
+
| QueryActionCreatorResult<any>
|
|
52
|
+
| InfiniteQueryActionCreatorResult<any>
|
|
53
|
+
| undefined
|
|
54
|
+
>
|
|
55
|
+
runningMutations: Map<string, MutationActionCreatorResult<any> | undefined>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface SubscriptionSelectors {
|
|
59
|
+
getSubscriptions: () => SubscriptionInternalState
|
|
60
|
+
getSubscriptionCount: (queryCacheKey: string) => number
|
|
61
|
+
isRequestSubscribed: (queryCacheKey: string, requestId: string) => boolean
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface BuildMiddlewareInput<
|
|
65
|
+
Definitions extends EndpointDefinitions,
|
|
66
|
+
ReducerPath extends string,
|
|
67
|
+
TagTypes extends string,
|
|
68
|
+
> {
|
|
69
|
+
reducerPath: ReducerPath
|
|
70
|
+
context: ApiContext<Definitions>
|
|
71
|
+
queryThunk: QueryThunk
|
|
72
|
+
mutationThunk: MutationThunk
|
|
73
|
+
infiniteQueryThunk: InfiniteQueryThunk<any>
|
|
74
|
+
api: Api<any, Definitions, ReducerPath, TagTypes>
|
|
75
|
+
assertTagType: AssertTagTypes
|
|
76
|
+
selectors: AllSelectors
|
|
77
|
+
getRunningQueryThunk: (
|
|
78
|
+
endpointName: string,
|
|
79
|
+
queryArgs: any,
|
|
80
|
+
) => (dispatch: Dispatch) => QueryActionCreatorResult<any> | undefined
|
|
81
|
+
getInternalState: (dispatch: Dispatch) => InternalMiddlewareState
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type SubMiddlewareApi = MiddlewareAPI<
|
|
85
|
+
ThunkDispatch<any, any, UnknownAction>,
|
|
86
|
+
RootState<EndpointDefinitions, string, string>
|
|
87
|
+
>
|
|
88
|
+
|
|
89
|
+
export interface BuildSubMiddlewareInput
|
|
90
|
+
extends BuildMiddlewareInput<EndpointDefinitions, string, string> {
|
|
91
|
+
internalState: InternalMiddlewareState
|
|
92
|
+
refetchQuery(
|
|
93
|
+
querySubState: Exclude<
|
|
94
|
+
QuerySubState<any>,
|
|
95
|
+
{ status: QueryStatus.uninitialized }
|
|
96
|
+
>,
|
|
97
|
+
): ThunkAction<QueryActionCreatorResult<any>, any, any, UnknownAction>
|
|
98
|
+
isThisApiSliceAction: (action: Action) => boolean
|
|
99
|
+
selectors: AllSelectors
|
|
100
|
+
mwApi: MiddlewareAPI<
|
|
101
|
+
ThunkDispatch<any, any, UnknownAction>,
|
|
102
|
+
RootState<EndpointDefinitions, string, string>
|
|
103
|
+
>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type SubMiddlewareBuilder = (
|
|
107
|
+
input: BuildSubMiddlewareInput,
|
|
108
|
+
) => Middleware<
|
|
109
|
+
{},
|
|
110
|
+
RootState<EndpointDefinitions, string, string>,
|
|
111
|
+
ThunkDispatch<any, any, UnknownAction>
|
|
112
|
+
>
|
|
113
|
+
|
|
114
|
+
type MwNext = Parameters<ReturnType<Middleware>>[0]
|
|
115
|
+
|
|
116
|
+
export type ApiMiddlewareInternalHandler<Return = void> = (
|
|
117
|
+
action: Action,
|
|
118
|
+
mwApi: SubMiddlewareApi & { next: MwNext },
|
|
119
|
+
prevState: RootState<EndpointDefinitions, string, string>,
|
|
120
|
+
) => Return
|
|
121
|
+
|
|
122
|
+
export type InternalHandlerBuilder<ReturnType = void> = (
|
|
123
|
+
input: BuildSubMiddlewareInput,
|
|
124
|
+
) => ApiMiddlewareInternalHandler<ReturnType>
|
|
125
|
+
|
|
126
|
+
export interface PromiseConstructorWithKnownReason {
|
|
127
|
+
/**
|
|
128
|
+
* Creates a new Promise with a known rejection reason.
|
|
129
|
+
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
|
130
|
+
* a resolve callback used to resolve the promise with a value or the result of another promise,
|
|
131
|
+
* and a reject callback used to reject the promise with a provided reason or error.
|
|
132
|
+
*/
|
|
133
|
+
new <T, R>(
|
|
134
|
+
executor: (
|
|
135
|
+
resolve: (value: T | PromiseLike<T>) => void,
|
|
136
|
+
reject: (reason?: R) => void,
|
|
137
|
+
) => void,
|
|
138
|
+
): PromiseWithKnownReason<T, R>
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type PromiseWithKnownReason<T, R> = Omit<
|
|
142
|
+
Promise<T>,
|
|
143
|
+
'then' | 'catch'
|
|
144
|
+
> & {
|
|
145
|
+
/**
|
|
146
|
+
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
|
147
|
+
* @param onfulfilled The callback to execute when the Promise is resolved.
|
|
148
|
+
* @param onrejected The callback to execute when the Promise is rejected.
|
|
149
|
+
* @returns A Promise for the completion of which ever callback is executed.
|
|
150
|
+
*/
|
|
151
|
+
then<TResult1 = T, TResult2 = never>(
|
|
152
|
+
onfulfilled?:
|
|
153
|
+
| ((value: T) => TResult1 | PromiseLike<TResult1>)
|
|
154
|
+
| undefined
|
|
155
|
+
| null,
|
|
156
|
+
onrejected?:
|
|
157
|
+
| ((reason: R) => TResult2 | PromiseLike<TResult2>)
|
|
158
|
+
| undefined
|
|
159
|
+
| null,
|
|
160
|
+
): Promise<TResult1 | TResult2>
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Attaches a callback for only the rejection of the Promise.
|
|
164
|
+
* @param onrejected The callback to execute when the Promise is rejected.
|
|
165
|
+
* @returns A Promise for the completion of the callback.
|
|
166
|
+
*/
|
|
167
|
+
catch<TResult = never>(
|
|
168
|
+
onrejected?:
|
|
169
|
+
| ((reason: R) => TResult | PromiseLike<TResult>)
|
|
170
|
+
| undefined
|
|
171
|
+
| null,
|
|
172
|
+
): Promise<T | TResult>
|
|
173
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { QueryStatus, STATUS_UNINITIALIZED } from '../apiState'
|
|
2
|
+
import type { QueryCacheKey } from '../apiState'
|
|
3
|
+
import { onFocus, onOnline } from '../setupListeners'
|
|
4
|
+
import type {
|
|
5
|
+
ApiMiddlewareInternalHandler,
|
|
6
|
+
InternalHandlerBuilder,
|
|
7
|
+
SubMiddlewareApi,
|
|
8
|
+
} from './types'
|
|
9
|
+
|
|
10
|
+
export const buildWindowEventHandler: InternalHandlerBuilder = ({
|
|
11
|
+
reducerPath,
|
|
12
|
+
context,
|
|
13
|
+
api,
|
|
14
|
+
refetchQuery,
|
|
15
|
+
internalState,
|
|
16
|
+
}) => {
|
|
17
|
+
const { removeQueryResult } = api.internalActions
|
|
18
|
+
|
|
19
|
+
const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
|
|
20
|
+
if (onFocus.match(action)) {
|
|
21
|
+
refetchValidQueries(mwApi, 'refetchOnFocus')
|
|
22
|
+
}
|
|
23
|
+
if (onOnline.match(action)) {
|
|
24
|
+
refetchValidQueries(mwApi, 'refetchOnReconnect')
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function refetchValidQueries(
|
|
29
|
+
api: SubMiddlewareApi,
|
|
30
|
+
type: 'refetchOnFocus' | 'refetchOnReconnect',
|
|
31
|
+
) {
|
|
32
|
+
const state = api.getState()[reducerPath]
|
|
33
|
+
const queries = state.queries
|
|
34
|
+
const subscriptions = internalState.currentSubscriptions
|
|
35
|
+
|
|
36
|
+
context.batch(() => {
|
|
37
|
+
for (const queryCacheKey of subscriptions.keys()) {
|
|
38
|
+
const querySubState = queries[queryCacheKey]
|
|
39
|
+
const subscriptionSubState = subscriptions.get(queryCacheKey)
|
|
40
|
+
|
|
41
|
+
if (!subscriptionSubState || !querySubState) continue
|
|
42
|
+
|
|
43
|
+
const values = [...subscriptionSubState.values()]
|
|
44
|
+
const shouldRefetch =
|
|
45
|
+
values.some((sub) => sub[type] === true) ||
|
|
46
|
+
(values.every((sub) => sub[type] === undefined) && state.config[type])
|
|
47
|
+
|
|
48
|
+
if (shouldRefetch) {
|
|
49
|
+
if (subscriptionSubState.size === 0) {
|
|
50
|
+
api.dispatch(
|
|
51
|
+
removeQueryResult({
|
|
52
|
+
queryCacheKey: queryCacheKey as QueryCacheKey,
|
|
53
|
+
}),
|
|
54
|
+
)
|
|
55
|
+
} else if (querySubState.status !== STATUS_UNINITIALIZED) {
|
|
56
|
+
api.dispatch(refetchQuery(querySubState))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return handler
|
|
64
|
+
}
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
|
|
2
|
+
import type {
|
|
3
|
+
EndpointDefinition,
|
|
4
|
+
EndpointDefinitions,
|
|
5
|
+
InfiniteQueryArgFrom,
|
|
6
|
+
InfiniteQueryDefinition,
|
|
7
|
+
MutationDefinition,
|
|
8
|
+
QueryArgFrom,
|
|
9
|
+
QueryArgFromAnyQuery,
|
|
10
|
+
QueryDefinition,
|
|
11
|
+
ReducerPathFrom,
|
|
12
|
+
TagDescription,
|
|
13
|
+
TagTypesFrom,
|
|
14
|
+
} from '../endpointDefinitions'
|
|
15
|
+
import { expandTagDescription } from '../endpointDefinitions'
|
|
16
|
+
import { filterMap, isNotNullish } from '../utils'
|
|
17
|
+
import type {
|
|
18
|
+
InfiniteData,
|
|
19
|
+
InfiniteQueryConfigOptions,
|
|
20
|
+
InfiniteQuerySubState,
|
|
21
|
+
MutationSubState,
|
|
22
|
+
QueryCacheKey,
|
|
23
|
+
QueryState,
|
|
24
|
+
QuerySubState,
|
|
25
|
+
RequestStatusFlags,
|
|
26
|
+
RootState as _RootState,
|
|
27
|
+
QueryStatus,
|
|
28
|
+
} from './apiState'
|
|
29
|
+
import { STATUS_UNINITIALIZED, getRequestStatusFlags } from './apiState'
|
|
30
|
+
import { getMutationCacheKey } from './buildSlice'
|
|
31
|
+
import type { createSelector as _createSelector } from './rtkImports'
|
|
32
|
+
import { createNextState } from './rtkImports'
|
|
33
|
+
import {
|
|
34
|
+
type AllQueryKeys,
|
|
35
|
+
getNextPageParam,
|
|
36
|
+
getPreviousPageParam,
|
|
37
|
+
} from './buildThunks'
|
|
38
|
+
|
|
39
|
+
export type SkipToken = typeof skipToken
|
|
40
|
+
/**
|
|
41
|
+
* Can be passed into `useQuery`, `useQueryState` or `useQuerySubscription`
|
|
42
|
+
* instead of the query argument to get the same effect as if setting
|
|
43
|
+
* `skip: true` in the query options.
|
|
44
|
+
*
|
|
45
|
+
* Useful for scenarios where a query should be skipped when `arg` is `undefined`
|
|
46
|
+
* and TypeScript complains about it because `arg` is not allowed to be passed
|
|
47
|
+
* in as `undefined`, such as
|
|
48
|
+
*
|
|
49
|
+
* ```ts
|
|
50
|
+
* // codeblock-meta title="will error if the query argument is not allowed to be undefined" no-transpile
|
|
51
|
+
* useSomeQuery(arg, { skip: !!arg })
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* // codeblock-meta title="using skipToken instead" no-transpile
|
|
56
|
+
* useSomeQuery(arg ?? skipToken)
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* If passed directly into a query or mutation selector, that selector will always
|
|
60
|
+
* return an uninitialized state.
|
|
61
|
+
*/
|
|
62
|
+
export const skipToken = /* @__PURE__ */ Symbol.for('RTKQ/skipToken')
|
|
63
|
+
|
|
64
|
+
export type BuildSelectorsApiEndpointQuery<
|
|
65
|
+
Definition extends QueryDefinition<any, any, any, any, any>,
|
|
66
|
+
Definitions extends EndpointDefinitions,
|
|
67
|
+
> = {
|
|
68
|
+
select: QueryResultSelectorFactory<
|
|
69
|
+
Definition,
|
|
70
|
+
_RootState<
|
|
71
|
+
Definitions,
|
|
72
|
+
TagTypesFrom<Definition>,
|
|
73
|
+
ReducerPathFrom<Definition>
|
|
74
|
+
>
|
|
75
|
+
>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type BuildSelectorsApiEndpointInfiniteQuery<
|
|
79
|
+
Definition extends InfiniteQueryDefinition<any, any, any, any, any>,
|
|
80
|
+
Definitions extends EndpointDefinitions,
|
|
81
|
+
> = {
|
|
82
|
+
select: InfiniteQueryResultSelectorFactory<
|
|
83
|
+
Definition,
|
|
84
|
+
_RootState<
|
|
85
|
+
Definitions,
|
|
86
|
+
TagTypesFrom<Definition>,
|
|
87
|
+
ReducerPathFrom<Definition>
|
|
88
|
+
>
|
|
89
|
+
>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type BuildSelectorsApiEndpointMutation<
|
|
93
|
+
Definition extends MutationDefinition<any, any, any, any, any>,
|
|
94
|
+
Definitions extends EndpointDefinitions,
|
|
95
|
+
> = {
|
|
96
|
+
select: MutationResultSelectorFactory<
|
|
97
|
+
Definition,
|
|
98
|
+
_RootState<
|
|
99
|
+
Definitions,
|
|
100
|
+
TagTypesFrom<Definition>,
|
|
101
|
+
ReducerPathFrom<Definition>
|
|
102
|
+
>
|
|
103
|
+
>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
type QueryResultSelectorFactory<
|
|
107
|
+
Definition extends QueryDefinition<any, any, any, any>,
|
|
108
|
+
RootState,
|
|
109
|
+
> = (
|
|
110
|
+
queryArg: QueryArgFrom<Definition> | SkipToken,
|
|
111
|
+
) => (state: RootState) => QueryResultSelectorResult<Definition>
|
|
112
|
+
|
|
113
|
+
export type QueryResultSelectorResult<
|
|
114
|
+
Definition extends QueryDefinition<any, any, any, any>,
|
|
115
|
+
> = QuerySubState<Definition> & RequestStatusFlags
|
|
116
|
+
|
|
117
|
+
type InfiniteQueryResultSelectorFactory<
|
|
118
|
+
Definition extends InfiniteQueryDefinition<any, any, any, any, any>,
|
|
119
|
+
RootState,
|
|
120
|
+
> = (
|
|
121
|
+
queryArg: InfiniteQueryArgFrom<Definition> | SkipToken,
|
|
122
|
+
) => (state: RootState) => InfiniteQueryResultSelectorResult<Definition>
|
|
123
|
+
|
|
124
|
+
export type InfiniteQueryResultFlags = {
|
|
125
|
+
hasNextPage: boolean
|
|
126
|
+
hasPreviousPage: boolean
|
|
127
|
+
isFetchingNextPage: boolean
|
|
128
|
+
isFetchingPreviousPage: boolean
|
|
129
|
+
isFetchNextPageError: boolean
|
|
130
|
+
isFetchPreviousPageError: boolean
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export type InfiniteQueryResultSelectorResult<
|
|
134
|
+
Definition extends InfiniteQueryDefinition<any, any, any, any, any>,
|
|
135
|
+
> = InfiniteQuerySubState<Definition> &
|
|
136
|
+
RequestStatusFlags &
|
|
137
|
+
InfiniteQueryResultFlags
|
|
138
|
+
|
|
139
|
+
type MutationResultSelectorFactory<
|
|
140
|
+
Definition extends MutationDefinition<any, any, any, any>,
|
|
141
|
+
RootState,
|
|
142
|
+
> = (
|
|
143
|
+
requestId:
|
|
144
|
+
| string
|
|
145
|
+
| { requestId: string | undefined; fixedCacheKey: string | undefined }
|
|
146
|
+
| SkipToken,
|
|
147
|
+
) => (state: RootState) => MutationResultSelectorResult<Definition>
|
|
148
|
+
|
|
149
|
+
export type MutationResultSelectorResult<
|
|
150
|
+
Definition extends MutationDefinition<any, any, any, any>,
|
|
151
|
+
> = MutationSubState<Definition> & RequestStatusFlags
|
|
152
|
+
|
|
153
|
+
const initialSubState: QuerySubState<any> = {
|
|
154
|
+
status: STATUS_UNINITIALIZED,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// abuse immer to freeze default states
|
|
158
|
+
const defaultQuerySubState = /* @__PURE__ */ createNextState(
|
|
159
|
+
initialSubState,
|
|
160
|
+
() => {},
|
|
161
|
+
)
|
|
162
|
+
const defaultMutationSubState = /* @__PURE__ */ createNextState(
|
|
163
|
+
initialSubState as MutationSubState<any>,
|
|
164
|
+
() => {},
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
export type AllSelectors = ReturnType<typeof buildSelectors>
|
|
168
|
+
|
|
169
|
+
export function buildSelectors<
|
|
170
|
+
Definitions extends EndpointDefinitions,
|
|
171
|
+
ReducerPath extends string,
|
|
172
|
+
>({
|
|
173
|
+
serializeQueryArgs,
|
|
174
|
+
reducerPath,
|
|
175
|
+
createSelector,
|
|
176
|
+
}: {
|
|
177
|
+
serializeQueryArgs: InternalSerializeQueryArgs
|
|
178
|
+
reducerPath: ReducerPath
|
|
179
|
+
createSelector: typeof _createSelector
|
|
180
|
+
}) {
|
|
181
|
+
type RootState = _RootState<Definitions, string, string>
|
|
182
|
+
|
|
183
|
+
const selectSkippedQuery = (state: RootState) => defaultQuerySubState
|
|
184
|
+
const selectSkippedMutation = (state: RootState) => defaultMutationSubState
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
buildQuerySelector,
|
|
188
|
+
buildInfiniteQuerySelector,
|
|
189
|
+
buildMutationSelector,
|
|
190
|
+
selectInvalidatedBy,
|
|
191
|
+
selectCachedArgsForQuery,
|
|
192
|
+
selectApiState,
|
|
193
|
+
selectQueries,
|
|
194
|
+
selectMutations,
|
|
195
|
+
selectQueryEntry,
|
|
196
|
+
selectConfig,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function withRequestFlags<T extends { status: QueryStatus }>(
|
|
200
|
+
substate: T,
|
|
201
|
+
): T & RequestStatusFlags {
|
|
202
|
+
return { ...substate, ...getRequestStatusFlags(substate.status) }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function selectApiState(rootState: RootState) {
|
|
206
|
+
const state = rootState[reducerPath]
|
|
207
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
208
|
+
if (!state) {
|
|
209
|
+
if ((selectApiState as any).triggered) return state
|
|
210
|
+
;(selectApiState as any).triggered = true
|
|
211
|
+
console.error(
|
|
212
|
+
`Error: No data found at \`state.${reducerPath}\`. Did you forget to add the reducer to the store?`,
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return state
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function selectQueries(rootState: RootState) {
|
|
220
|
+
return selectApiState(rootState)?.queries
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function selectQueryEntry(rootState: RootState, cacheKey: QueryCacheKey) {
|
|
224
|
+
return selectQueries(rootState)?.[cacheKey]
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function selectMutations(rootState: RootState) {
|
|
228
|
+
return selectApiState(rootState)?.mutations
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function selectConfig(rootState: RootState) {
|
|
232
|
+
return selectApiState(rootState)?.config
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function buildAnyQuerySelector(
|
|
236
|
+
endpointName: string,
|
|
237
|
+
endpointDefinition: EndpointDefinition<any, any, any, any>,
|
|
238
|
+
combiner: <T extends { status: QueryStatus }>(
|
|
239
|
+
substate: T,
|
|
240
|
+
) => T & RequestStatusFlags,
|
|
241
|
+
) {
|
|
242
|
+
return (queryArgs: any) => {
|
|
243
|
+
// Avoid calling serializeQueryArgs if the arg is skipToken
|
|
244
|
+
if (queryArgs === skipToken) {
|
|
245
|
+
return createSelector(selectSkippedQuery, combiner)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const serializedArgs = serializeQueryArgs({
|
|
249
|
+
queryArgs,
|
|
250
|
+
endpointDefinition,
|
|
251
|
+
endpointName,
|
|
252
|
+
})
|
|
253
|
+
const selectQuerySubstate = (state: RootState) =>
|
|
254
|
+
selectQueryEntry(state, serializedArgs) ?? defaultQuerySubState
|
|
255
|
+
|
|
256
|
+
return createSelector(selectQuerySubstate, combiner)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function buildQuerySelector(
|
|
261
|
+
endpointName: string,
|
|
262
|
+
endpointDefinition: QueryDefinition<any, any, any, any>,
|
|
263
|
+
) {
|
|
264
|
+
return buildAnyQuerySelector(
|
|
265
|
+
endpointName,
|
|
266
|
+
endpointDefinition,
|
|
267
|
+
withRequestFlags,
|
|
268
|
+
) as QueryResultSelectorFactory<any, RootState>
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function buildInfiniteQuerySelector(
|
|
272
|
+
endpointName: string,
|
|
273
|
+
endpointDefinition: InfiniteQueryDefinition<any, any, any, any, any>,
|
|
274
|
+
) {
|
|
275
|
+
const { infiniteQueryOptions } = endpointDefinition
|
|
276
|
+
|
|
277
|
+
function withInfiniteQueryResultFlags<T extends { status: QueryStatus }>(
|
|
278
|
+
substate: T,
|
|
279
|
+
): T & RequestStatusFlags & InfiniteQueryResultFlags {
|
|
280
|
+
const stateWithRequestFlags = {
|
|
281
|
+
...(substate as InfiniteQuerySubState<any>),
|
|
282
|
+
...getRequestStatusFlags(substate.status),
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const { isLoading, isError, direction } = stateWithRequestFlags
|
|
286
|
+
const isForward = direction === 'forward'
|
|
287
|
+
const isBackward = direction === 'backward'
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
...stateWithRequestFlags,
|
|
291
|
+
hasNextPage: getHasNextPage(
|
|
292
|
+
infiniteQueryOptions,
|
|
293
|
+
stateWithRequestFlags.data,
|
|
294
|
+
stateWithRequestFlags.originalArgs,
|
|
295
|
+
),
|
|
296
|
+
hasPreviousPage: getHasPreviousPage(
|
|
297
|
+
infiniteQueryOptions,
|
|
298
|
+
stateWithRequestFlags.data,
|
|
299
|
+
stateWithRequestFlags.originalArgs,
|
|
300
|
+
),
|
|
301
|
+
isFetchingNextPage: isLoading && isForward,
|
|
302
|
+
isFetchingPreviousPage: isLoading && isBackward,
|
|
303
|
+
isFetchNextPageError: isError && isForward,
|
|
304
|
+
isFetchPreviousPageError: isError && isBackward,
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return buildAnyQuerySelector(
|
|
309
|
+
endpointName,
|
|
310
|
+
endpointDefinition,
|
|
311
|
+
withInfiniteQueryResultFlags,
|
|
312
|
+
) as unknown as InfiniteQueryResultSelectorFactory<any, RootState>
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function buildMutationSelector() {
|
|
316
|
+
return ((id) => {
|
|
317
|
+
let mutationId: string | typeof skipToken
|
|
318
|
+
if (typeof id === 'object') {
|
|
319
|
+
mutationId = getMutationCacheKey(id) ?? skipToken
|
|
320
|
+
} else {
|
|
321
|
+
mutationId = id
|
|
322
|
+
}
|
|
323
|
+
const selectMutationSubstate = (state: RootState) =>
|
|
324
|
+
selectApiState(state)?.mutations?.[mutationId as string] ??
|
|
325
|
+
defaultMutationSubState
|
|
326
|
+
const finalSelectMutationSubstate =
|
|
327
|
+
mutationId === skipToken
|
|
328
|
+
? selectSkippedMutation
|
|
329
|
+
: selectMutationSubstate
|
|
330
|
+
|
|
331
|
+
return createSelector(finalSelectMutationSubstate, withRequestFlags)
|
|
332
|
+
}) as MutationResultSelectorFactory<any, RootState>
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function selectInvalidatedBy(
|
|
336
|
+
state: RootState,
|
|
337
|
+
tags: ReadonlyArray<TagDescription<string> | null | undefined>,
|
|
338
|
+
): Array<{
|
|
339
|
+
endpointName: string
|
|
340
|
+
originalArgs: any
|
|
341
|
+
queryCacheKey: QueryCacheKey
|
|
342
|
+
}> {
|
|
343
|
+
const apiState = state[reducerPath]
|
|
344
|
+
const toInvalidate = new Set<QueryCacheKey>()
|
|
345
|
+
const finalTags = filterMap(tags, isNotNullish, expandTagDescription)
|
|
346
|
+
for (const tag of finalTags) {
|
|
347
|
+
const provided = apiState.provided.tags[tag.type]
|
|
348
|
+
if (!provided) {
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
let invalidateSubscriptions =
|
|
353
|
+
(tag.id !== undefined
|
|
354
|
+
? // id given: invalidate all queries that provide this type & id
|
|
355
|
+
provided[tag.id]
|
|
356
|
+
: // no id: invalidate all queries that provide this type
|
|
357
|
+
Object.values(provided).flat()) ?? []
|
|
358
|
+
|
|
359
|
+
for (const invalidate of invalidateSubscriptions) {
|
|
360
|
+
toInvalidate.add(invalidate)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return Array.from(toInvalidate.values()).flatMap((queryCacheKey) => {
|
|
365
|
+
const querySubState = apiState.queries[queryCacheKey]
|
|
366
|
+
return querySubState
|
|
367
|
+
? {
|
|
368
|
+
queryCacheKey,
|
|
369
|
+
endpointName: querySubState.endpointName!,
|
|
370
|
+
originalArgs: querySubState.originalArgs,
|
|
371
|
+
}
|
|
372
|
+
: []
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function selectCachedArgsForQuery<
|
|
377
|
+
QueryName extends AllQueryKeys<Definitions>,
|
|
378
|
+
>(
|
|
379
|
+
state: RootState,
|
|
380
|
+
queryName: QueryName,
|
|
381
|
+
): Array<QueryArgFromAnyQuery<Definitions[QueryName]>> {
|
|
382
|
+
return filterMap(
|
|
383
|
+
Object.values(selectQueries(state) as QueryState<any>),
|
|
384
|
+
(
|
|
385
|
+
entry,
|
|
386
|
+
): entry is Exclude<
|
|
387
|
+
QuerySubState<Definitions[QueryName]>,
|
|
388
|
+
{ status: QueryStatus.uninitialized }
|
|
389
|
+
> =>
|
|
390
|
+
entry?.endpointName === queryName &&
|
|
391
|
+
entry.status !== STATUS_UNINITIALIZED,
|
|
392
|
+
(entry) => entry.originalArgs,
|
|
393
|
+
)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function getHasNextPage(
|
|
397
|
+
options: InfiniteQueryConfigOptions<any, any, any>,
|
|
398
|
+
data?: InfiniteData<unknown, unknown>,
|
|
399
|
+
queryArg?: unknown,
|
|
400
|
+
): boolean {
|
|
401
|
+
if (!data) return false
|
|
402
|
+
return getNextPageParam(options, data, queryArg) != null
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function getHasPreviousPage(
|
|
406
|
+
options: InfiniteQueryConfigOptions<any, any, any>,
|
|
407
|
+
data?: InfiniteData<unknown, unknown>,
|
|
408
|
+
queryArg?: unknown,
|
|
409
|
+
): boolean {
|
|
410
|
+
if (!data || !options.getPreviousPageParam) return false
|
|
411
|
+
return getPreviousPageParam(options, data, queryArg) != null
|
|
412
|
+
}
|
|
413
|
+
}
|