Add settings page for managing forecasting API key and URL via UI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cae411eae7
commit
1c411e402e
19809 changed files with 1962608 additions and 97 deletions
21
frontend/node_modules/@reduxjs/toolkit/LICENSE
generated
vendored
Normal file
21
frontend/node_modules/@reduxjs/toolkit/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Mark Erikson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
112
frontend/node_modules/@reduxjs/toolkit/README.md
generated
vendored
Normal file
112
frontend/node_modules/@reduxjs/toolkit/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# Redux Toolkit
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/@reduxjs/toolkit)
|
||||
[](https://www.npmjs.com/package/@reduxjs/toolkit)
|
||||
|
||||
**The official, opinionated, batteries-included toolset for efficient Redux development**
|
||||
|
||||
## Installation
|
||||
|
||||
### Create a React Redux App
|
||||
|
||||
The recommended way to start new apps with React and Redux Toolkit is by using [our official Redux Toolkit + TS template for Vite](https://github.com/reduxjs/redux-templates), or by creating a new Next.js project using [Next's `with-redux` template](https://github.com/vercel/next.js/tree/canary/examples/with-redux).
|
||||
|
||||
Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.
|
||||
|
||||
```bash
|
||||
# Vite with our Redux+TS template
|
||||
# (using the `degit` tool to clone and extract the template)
|
||||
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
|
||||
|
||||
# Next.js using the `with-redux` template
|
||||
npx create-next-app --example with-redux my-app
|
||||
```
|
||||
|
||||
We do not currently have official React Native templates, but recommend these templates for standard React Native and for Expo:
|
||||
|
||||
- https://github.com/rahsheen/react-native-template-redux-typescript
|
||||
- https://github.com/rahsheen/expo-template-redux-typescript
|
||||
|
||||
### An Existing App
|
||||
|
||||
Redux Toolkit is available as a package on NPM for use with a module bundler or in a Node application:
|
||||
|
||||
```bash
|
||||
# NPM
|
||||
npm install @reduxjs/toolkit
|
||||
|
||||
# Yarn
|
||||
yarn add @reduxjs/toolkit
|
||||
```
|
||||
|
||||
If you use an AI agent, run `npx @tanstack/intent@latest install` to install agent skills.
|
||||
|
||||
The package includes a precompiled ESM build that can be used as a [`<script type="module">` tag](https://unpkg.com/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs) directly in the browser.
|
||||
|
||||
## Documentation
|
||||
|
||||
The Redux Toolkit docs are available at **https://redux-toolkit.js.org**, including API references and usage guides for all of the APIs included in Redux Toolkit.
|
||||
|
||||
The Redux core docs at https://redux.js.org includes the full Redux tutorials, as well usage guides on general Redux patterns.
|
||||
|
||||
## Purpose
|
||||
|
||||
The **Redux Toolkit** package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux:
|
||||
|
||||
- "Configuring a Redux store is too complicated"
|
||||
- "I have to add a lot of packages to get Redux to do anything useful"
|
||||
- "Redux requires too much boilerplate code"
|
||||
|
||||
We can't solve every use case, but in the spirit of [`create-react-app`](https://github.com/facebook/create-react-app), we can try to provide some tools that abstract over the setup process and handle the most common use cases, as well as include some useful utilities that will let the user simplify their application code.
|
||||
|
||||
Because of that, this package is deliberately limited in scope. It does _not_ address concepts like "reusable encapsulated Redux modules", folder or file structures, managing entity relationships in the store, and so on.
|
||||
|
||||
Redux Toolkit also includes a powerful data fetching and caching capability that we've dubbed "RTK Query". It's included in the package as a separate set of entry points. It's optional, but can eliminate the need to hand-write data fetching logic yourself.
|
||||
|
||||
## What's Included
|
||||
|
||||
Redux Toolkit includes these APIs:
|
||||
|
||||
- `configureStore()`: wraps `createStore` to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, add whatever Redux middleware you supply, includes `redux-thunk` by default, and enables use of the Redux DevTools Extension.
|
||||
- `createReducer()`: lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the [`immer` library](https://github.com/mweststrate/immer) to let you write simpler immutable updates with normal mutative code, like `state.todos[3].completed = true`.
|
||||
- `createAction()`: generates an action creator function for the given action type string. The function itself has `toString()` defined, so that it can be used in place of the type constant.
|
||||
- `createSlice()`: combines `createReducer()` + `createAction()`. Accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
|
||||
- `combineSlices()`: combines multiple slices into a single reducer, and allows "lazy loading" of slices after initialisation.
|
||||
- `createListenerMiddleware()`: lets you define "listener" entries that contain an "effect" callback with additional logic, and a way to specify when that callback should run based on dispatched actions or state changes. A lightweight alternative to Redux async middleware like sagas and observables.
|
||||
- `createAsyncThunk()`: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches `pending/resolved/rejected` action types based on that promise
|
||||
- `createEntityAdapter()`: generates a set of reusable reducers and selectors to manage normalized data in the store
|
||||
- The `createSelector()` utility from the [Reselect](https://github.com/reduxjs/reselect) library, re-exported for ease of use.
|
||||
|
||||
For details, see [the Redux Toolkit API Reference section in the docs](https://redux-toolkit.js.org/api/configureStore).
|
||||
|
||||
## RTK Query
|
||||
|
||||
**RTK Query** is provided as an optional addon within the `@reduxjs/toolkit` package. It is purpose-built to solve the use case of data fetching and caching, supplying a compact, but powerful toolset to define an API interface layer for your app. It is intended to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
|
||||
|
||||
RTK Query is built on top of the Redux Toolkit core for its implementation, using [Redux](https://redux.js.org/) internally for its architecture. Although knowledge of Redux and RTK are not required to use RTK Query, you should explore all of the additional global store management capabilities they provide, as well as installing the [Redux DevTools browser extension](https://github.com/reduxjs/redux-devtools), which works flawlessly with RTK Query to traverse and replay a timeline of your request & cache behavior.
|
||||
|
||||
RTK Query is included within the installation of the core Redux Toolkit package. It is available via either of the two entry points below:
|
||||
|
||||
```ts no-transpile
|
||||
import { createApi } from '@reduxjs/toolkit/query'
|
||||
|
||||
/* React-specific entry point that automatically generates
|
||||
hooks corresponding to the defined endpoints */
|
||||
import { createApi } from '@reduxjs/toolkit/query/react'
|
||||
```
|
||||
|
||||
### What's included
|
||||
|
||||
RTK Query includes these APIs:
|
||||
|
||||
- `createApi()`: The core of RTK Query's functionality. It allows you to define a set of endpoints describe how to retrieve data from a series of endpoints, including configuration of how to fetch and transform that data. In most cases, you should use this once per app, with "one API slice per base URL" as a rule of thumb.
|
||||
- `fetchBaseQuery()`: A small wrapper around fetch that aims to simplify requests. Intended as the recommended baseQuery to be used in createApi for the majority of users.
|
||||
- `<ApiProvider />`: Can be used as a Provider if you do not already have a Redux store.
|
||||
- `setupListeners()`: A utility used to enable refetchOnMount and refetchOnReconnect behaviors.
|
||||
|
||||
See the [**RTK Query Overview**](https://redux-toolkit.js.org/rtk-query/overview) page for more details on what RTK Query is, what problems it solves, and how to use it.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please refer to our [contributing guide](/CONTRIBUTING.md) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Redux Toolkit.
|
||||
6
frontend/node_modules/@reduxjs/toolkit/dist/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/cjs/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./redux-toolkit.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./redux-toolkit.development.cjs')
|
||||
}
|
||||
2406
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs
generated
vendored
Normal file
2406
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs
generated
vendored
Normal file
3
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2665
frontend/node_modules/@reduxjs/toolkit/dist/index.d.mts
generated
vendored
Normal file
2665
frontend/node_modules/@reduxjs/toolkit/dist/index.d.mts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
2665
frontend/node_modules/@reduxjs/toolkit/dist/index.d.ts
generated
vendored
Normal file
2665
frontend/node_modules/@reduxjs/toolkit/dist/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./rtk-query.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./rtk-query.development.cjs')
|
||||
}
|
||||
3092
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs
generated
vendored
Normal file
3092
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3066
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.mts
generated
vendored
Normal file
3066
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.mts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
3066
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.ts
generated
vendored
Normal file
3066
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./rtk-query-react.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./rtk-query-react.development.cjs')
|
||||
}
|
||||
748
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs
generated
vendored
Normal file
748
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs
generated
vendored
Normal file
|
|
@ -0,0 +1,748 @@
|
|||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/query/react/index.ts
|
||||
var react_exports = {};
|
||||
__export(react_exports, {
|
||||
ApiProvider: () => ApiProvider,
|
||||
UNINITIALIZED_VALUE: () => UNINITIALIZED_VALUE,
|
||||
createApi: () => createApi,
|
||||
reactHooksModule: () => reactHooksModule,
|
||||
reactHooksModuleName: () => reactHooksModuleName
|
||||
});
|
||||
module.exports = __toCommonJS(react_exports);
|
||||
|
||||
// src/query/react/rtkqImports.ts
|
||||
var import_query = require("@reduxjs/toolkit/query");
|
||||
|
||||
// src/query/react/module.ts
|
||||
var import_toolkit2 = require("@reduxjs/toolkit");
|
||||
var import_react_redux2 = require("react-redux");
|
||||
var import_reselect = require("reselect");
|
||||
|
||||
// src/query/utils/capitalize.ts
|
||||
function capitalize(str) {
|
||||
return str.replace(str[0], str[0].toUpperCase());
|
||||
}
|
||||
|
||||
// src/query/utils/countObjectKeys.ts
|
||||
function countObjectKeys(obj) {
|
||||
let count = 0;
|
||||
for (const _key in obj) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// src/query/endpointDefinitions.ts
|
||||
var ENDPOINT_QUERY = "query" /* query */;
|
||||
var ENDPOINT_MUTATION = "mutation" /* mutation */;
|
||||
var ENDPOINT_INFINITEQUERY = "infinitequery" /* infinitequery */;
|
||||
function isQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_QUERY;
|
||||
}
|
||||
function isMutationDefinition(e) {
|
||||
return e.type === ENDPOINT_MUTATION;
|
||||
}
|
||||
function isInfiniteQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_INFINITEQUERY;
|
||||
}
|
||||
|
||||
// src/query/tsHelpers.ts
|
||||
function safeAssign(target, ...args) {
|
||||
return Object.assign(target, ...args);
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var import_toolkit = require("@reduxjs/toolkit");
|
||||
|
||||
// src/query/react/constants.ts
|
||||
var UNINITIALIZED_VALUE = /* @__PURE__ */ Symbol();
|
||||
|
||||
// src/query/react/reactImports.ts
|
||||
var import_react = require("react");
|
||||
|
||||
// src/query/react/reactReduxImports.ts
|
||||
var import_react_redux = require("react-redux");
|
||||
|
||||
// src/query/react/useSerializedStableValue.ts
|
||||
function useStableQueryArgs(queryArgs) {
|
||||
const cache = (0, import_react.useRef)(queryArgs);
|
||||
const copy = (0, import_react.useMemo)(() => (0, import_query.copyWithStructuralSharing)(cache.current, queryArgs), [queryArgs]);
|
||||
(0, import_react.useEffect)(() => {
|
||||
if (cache.current !== copy) {
|
||||
cache.current = copy;
|
||||
}
|
||||
}, [copy]);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// src/query/react/useShallowStableValue.ts
|
||||
function useShallowStableValue(value) {
|
||||
const cache = (0, import_react.useRef)(value);
|
||||
(0, import_react.useEffect)(() => {
|
||||
if (!(0, import_react_redux.shallowEqual)(cache.current, value)) {
|
||||
cache.current = value;
|
||||
}
|
||||
}, [value]);
|
||||
return (0, import_react_redux.shallowEqual)(cache.current, value) ? cache.current : value;
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
||||
var isDOM = /* @__PURE__ */ canUseDOM();
|
||||
var isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
||||
var isReactNative = /* @__PURE__ */ isRunningInReactNative();
|
||||
var getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? import_react.useLayoutEffect : import_react.useEffect;
|
||||
var useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect();
|
||||
var noPendingQueryStateSelector = (selected) => {
|
||||
if (selected.isUninitialized) {
|
||||
return {
|
||||
...selected,
|
||||
isUninitialized: false,
|
||||
isFetching: true,
|
||||
isLoading: selected.data !== void 0 ? false : true,
|
||||
// This is the one place where we still have to use `QueryStatus` as an enum,
|
||||
// since it's the only reference in the React package and not in the core.
|
||||
status: import_query.QueryStatus.pending
|
||||
};
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
function pick(obj, ...keys) {
|
||||
const ret = {};
|
||||
keys.forEach((key) => {
|
||||
ret[key] = obj[key];
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
var COMMON_HOOK_DEBUG_FIELDS = ["data", "status", "isLoading", "isSuccess", "isError", "error"];
|
||||
function buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks: {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
useStore
|
||||
},
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
}) {
|
||||
const usePossiblyImmediateEffect = unstable__sideEffectsInRender ? (cb) => cb() : import_react.useEffect;
|
||||
const unsubscribePromiseRef = (ref) => ref.current?.unsubscribe?.();
|
||||
const endpointDefinitions = context.endpointDefinitions;
|
||||
return {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
};
|
||||
function queryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== import_query.skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !lastResult?.isError || currentState.isUninitialized);
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function infiniteQueryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== import_query.skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !lastResult?.isError || currentState.isUninitialized);
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function usePrefetch(endpointName, defaultOptions) {
|
||||
const dispatch = useDispatch();
|
||||
const stableDefaultOptions = useShallowStableValue(defaultOptions);
|
||||
return (0, import_react.useCallback)((arg, options) => dispatch(api.util.prefetch(endpointName, arg, {
|
||||
...stableDefaultOptions,
|
||||
...options
|
||||
})), [endpointName, dispatch, stableDefaultOptions]);
|
||||
}
|
||||
function useQuerySubscriptionCommonImpl(endpointName, arg, {
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
refetchOnMountOrArgChange,
|
||||
skip = false,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false,
|
||||
...rest
|
||||
} = {}) {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const subscriptionSelectorsRef = (0, import_react.useRef)(void 0);
|
||||
if (!subscriptionSelectorsRef.current) {
|
||||
const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions());
|
||||
if (true) {
|
||||
if (typeof returnedValue !== "object" || typeof returnedValue?.type === "string") {
|
||||
throw new Error(false ? _formatProdErrorMessage(37) : `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
|
||||
You must add the middleware for RTK-Query to function correctly!`);
|
||||
}
|
||||
}
|
||||
subscriptionSelectorsRef.current = returnedValue;
|
||||
}
|
||||
const stableArg = useStableQueryArgs(skip ? import_query.skipToken : arg);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
const initialPageParam = rest.initialPageParam;
|
||||
const stableInitialPageParam = useShallowStableValue(initialPageParam);
|
||||
const refetchCachedPages = rest.refetchCachedPages;
|
||||
const stableRefetchCachedPages = useShallowStableValue(refetchCachedPages);
|
||||
const promiseRef = (0, import_react.useRef)(void 0);
|
||||
let {
|
||||
queryCacheKey,
|
||||
requestId
|
||||
} = promiseRef.current || {};
|
||||
let currentRenderHasSubscription = false;
|
||||
if (queryCacheKey && requestId) {
|
||||
currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed(queryCacheKey, requestId);
|
||||
}
|
||||
const subscriptionRemoved = !currentRenderHasSubscription && promiseRef.current !== void 0;
|
||||
usePossiblyImmediateEffect(() => {
|
||||
if (subscriptionRemoved) {
|
||||
promiseRef.current = void 0;
|
||||
}
|
||||
}, [subscriptionRemoved]);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastPromise = promiseRef.current;
|
||||
if (typeof process !== "undefined" && false) {
|
||||
console.log(subscriptionRemoved);
|
||||
}
|
||||
if (stableArg === import_query.skipToken) {
|
||||
lastPromise?.unsubscribe();
|
||||
promiseRef.current = void 0;
|
||||
return;
|
||||
}
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (!lastPromise || lastPromise.arg !== stableArg) {
|
||||
lastPromise?.unsubscribe();
|
||||
const promise = dispatch(initiate(stableArg, {
|
||||
subscriptionOptions: stableSubscriptionOptions,
|
||||
forceRefetch: refetchOnMountOrArgChange,
|
||||
...isInfiniteQueryDefinition(endpointDefinitions[endpointName]) ? {
|
||||
initialPageParam: stableInitialPageParam,
|
||||
refetchCachedPages: stableRefetchCachedPages
|
||||
} : {}
|
||||
}));
|
||||
promiseRef.current = promise;
|
||||
} else if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
lastPromise.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [dispatch, initiate, refetchOnMountOrArgChange, stableArg, stableSubscriptionOptions, subscriptionRemoved, stableInitialPageParam, stableRefetchCachedPages, endpointName]);
|
||||
return [promiseRef, dispatch, initiate, stableSubscriptionOptions];
|
||||
}
|
||||
function buildUseQueryState(endpointName, preSelector) {
|
||||
const useQueryState = (arg, {
|
||||
skip = false,
|
||||
selectFromResult
|
||||
} = {}) => {
|
||||
const {
|
||||
select
|
||||
} = api.endpoints[endpointName];
|
||||
const stableArg = useStableQueryArgs(skip ? import_query.skipToken : arg);
|
||||
const lastValue = (0, import_react.useRef)(void 0);
|
||||
const selectDefaultResult = (0, import_react.useMemo)(() => (
|
||||
// Normally ts-ignores are bad and should be avoided, but we're
|
||||
// already casting this selector to be `Selector<any>` anyway,
|
||||
// so the inconsistencies don't matter here
|
||||
// @ts-ignore
|
||||
createSelector([
|
||||
// @ts-ignore
|
||||
select(stableArg),
|
||||
(_, lastResult) => lastResult,
|
||||
(_) => stableArg
|
||||
], preSelector, {
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: import_react_redux.shallowEqual
|
||||
}
|
||||
})
|
||||
), [select, stableArg]);
|
||||
const querySelector = (0, import_react.useMemo)(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult, {
|
||||
devModeChecks: {
|
||||
identityFunctionCheck: "never"
|
||||
}
|
||||
}) : selectDefaultResult, [selectDefaultResult, selectFromResult]);
|
||||
const currentState = useSelector((state) => querySelector(state, lastValue.current), import_react_redux.shallowEqual);
|
||||
const store = useStore();
|
||||
const newLastValue = selectDefaultResult(store.getState(), lastValue.current);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
lastValue.current = newLastValue;
|
||||
}, [newLastValue]);
|
||||
return currentState;
|
||||
};
|
||||
return useQueryState;
|
||||
}
|
||||
function usePromiseRefUnsubscribeOnUnmount(promiseRef) {
|
||||
(0, import_react.useEffect)(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = void 0;
|
||||
};
|
||||
}, [promiseRef]);
|
||||
}
|
||||
function refetchOrErrorIfUnmounted(promiseRef) {
|
||||
if (!promiseRef.current) throw new Error(false ? _formatProdErrorMessage2(38) : "Cannot refetch a query that has not been started yet.");
|
||||
return promiseRef.current.refetch();
|
||||
}
|
||||
function buildQueryHooks(endpointName) {
|
||||
const useQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
return (0, import_react.useMemo)(() => ({
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch: () => refetchOrErrorIfUnmounted(promiseRef)
|
||||
}), [promiseRef]);
|
||||
};
|
||||
const useLazyQuerySubscription = ({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = {}) => {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const [arg, setArg] = (0, import_react.useState)(UNINITIALIZED_VALUE);
|
||||
const promiseRef = (0, import_react.useRef)(void 0);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
promiseRef.current?.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [stableSubscriptionOptions]);
|
||||
const subscriptionOptionsRef = (0, import_react.useRef)(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const trigger = (0, import_react.useCallback)(function(arg2, preferCacheValue = false) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
forceRefetch: !preferCacheValue
|
||||
}));
|
||||
setArg(arg2);
|
||||
});
|
||||
return promise;
|
||||
}, [dispatch, initiate]);
|
||||
const reset = (0, import_react.useCallback)(() => {
|
||||
if (promiseRef.current?.queryCacheKey) {
|
||||
dispatch(api.internalActions.removeQueryResult({
|
||||
queryCacheKey: promiseRef.current?.queryCacheKey
|
||||
}));
|
||||
}
|
||||
}, [dispatch]);
|
||||
(0, import_react.useEffect)(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
};
|
||||
}, []);
|
||||
(0, import_react.useEffect)(() => {
|
||||
if (arg !== UNINITIALIZED_VALUE && !promiseRef.current) {
|
||||
trigger(arg, true);
|
||||
}
|
||||
}, [arg, trigger]);
|
||||
return (0, import_react.useMemo)(() => [trigger, arg, {
|
||||
reset
|
||||
}], [trigger, arg, reset]);
|
||||
};
|
||||
const useQueryState = buildUseQueryState(endpointName, queryStatePreSelector);
|
||||
return {
|
||||
useQueryState,
|
||||
useQuerySubscription,
|
||||
useLazyQuerySubscription,
|
||||
useLazyQuery(options) {
|
||||
const [trigger, arg, {
|
||||
reset
|
||||
}] = useLazyQuerySubscription(options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
...options,
|
||||
skip: arg === UNINITIALIZED_VALUE
|
||||
});
|
||||
const info = (0, import_react.useMemo)(() => ({
|
||||
lastArg: arg
|
||||
}), [arg]);
|
||||
return (0, import_react.useMemo)(() => [trigger, {
|
||||
...queryStateResults,
|
||||
reset
|
||||
}, info], [trigger, queryStateResults, reset, info]);
|
||||
},
|
||||
useQuery(arg, options) {
|
||||
const querySubscriptionResults = useQuerySubscription(arg, options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
selectFromResult: arg === import_query.skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS);
|
||||
(0, import_react.useDebugValue)(debugValue);
|
||||
return (0, import_react.useMemo)(() => ({
|
||||
...queryStateResults,
|
||||
...querySubscriptionResults
|
||||
}), [queryStateResults, querySubscriptionResults]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildInfiniteQueryHooks(endpointName) {
|
||||
const useInfiniteQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef, dispatch, initiate, stableSubscriptionOptions] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
const subscriptionOptionsRef = (0, import_react.useRef)(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const hookRefetchCachedPages = options.refetchCachedPages;
|
||||
const stableHookRefetchCachedPages = useShallowStableValue(hookRefetchCachedPages);
|
||||
const trigger = (0, import_react.useCallback)(function(arg2, direction) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
direction
|
||||
}));
|
||||
});
|
||||
return promise;
|
||||
}, [promiseRef, dispatch, initiate]);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
const stableArg = useStableQueryArgs(options.skip ? import_query.skipToken : arg);
|
||||
const refetch = (0, import_react.useCallback)((options2) => {
|
||||
if (!promiseRef.current) throw new Error(false ? _formatProdErrorMessage3(38) : "Cannot refetch a query that has not been started yet.");
|
||||
const mergedOptions = {
|
||||
refetchCachedPages: options2?.refetchCachedPages ?? stableHookRefetchCachedPages
|
||||
};
|
||||
return promiseRef.current.refetch(mergedOptions);
|
||||
}, [promiseRef, stableHookRefetchCachedPages]);
|
||||
return (0, import_react.useMemo)(() => {
|
||||
const fetchNextPage = () => {
|
||||
return trigger(stableArg, "forward");
|
||||
};
|
||||
const fetchPreviousPage = () => {
|
||||
return trigger(stableArg, "backward");
|
||||
};
|
||||
return {
|
||||
trigger,
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
};
|
||||
}, [refetch, trigger, stableArg]);
|
||||
};
|
||||
const useInfiniteQueryState = buildUseQueryState(endpointName, infiniteQueryStatePreSelector);
|
||||
return {
|
||||
useInfiniteQueryState,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQuery(arg, options) {
|
||||
const {
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
} = useInfiniteQuerySubscription(arg, options);
|
||||
const queryStateResults = useInfiniteQueryState(arg, {
|
||||
selectFromResult: arg === import_query.skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS, "hasNextPage", "hasPreviousPage");
|
||||
(0, import_react.useDebugValue)(debugValue);
|
||||
return (0, import_react.useMemo)(() => ({
|
||||
...queryStateResults,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
refetch
|
||||
}), [queryStateResults, fetchNextPage, fetchPreviousPage, refetch]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildMutationHook(name) {
|
||||
return ({
|
||||
selectFromResult,
|
||||
fixedCacheKey
|
||||
} = {}) => {
|
||||
const {
|
||||
select,
|
||||
initiate
|
||||
} = api.endpoints[name];
|
||||
const dispatch = useDispatch();
|
||||
const [promise, setPromise] = (0, import_react.useState)();
|
||||
(0, import_react.useEffect)(() => () => {
|
||||
if (!promise?.arg.fixedCacheKey) {
|
||||
promise?.reset();
|
||||
}
|
||||
}, [promise]);
|
||||
const triggerMutation = (0, import_react.useCallback)(function(arg) {
|
||||
const promise2 = dispatch(initiate(arg, {
|
||||
fixedCacheKey
|
||||
}));
|
||||
setPromise(promise2);
|
||||
return promise2;
|
||||
}, [dispatch, initiate, fixedCacheKey]);
|
||||
const {
|
||||
requestId
|
||||
} = promise || {};
|
||||
const selectDefaultResult = (0, import_react.useMemo)(() => select({
|
||||
fixedCacheKey,
|
||||
requestId: promise?.requestId
|
||||
}), [fixedCacheKey, promise, select]);
|
||||
const mutationSelector = (0, import_react.useMemo)(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, [selectFromResult, selectDefaultResult]);
|
||||
const currentState = useSelector(mutationSelector, import_react_redux.shallowEqual);
|
||||
const originalArgs = fixedCacheKey == null ? promise?.arg.originalArgs : void 0;
|
||||
const reset = (0, import_react.useCallback)(() => {
|
||||
batch(() => {
|
||||
if (promise) {
|
||||
setPromise(void 0);
|
||||
}
|
||||
if (fixedCacheKey) {
|
||||
dispatch(api.internalActions.removeMutationResult({
|
||||
requestId,
|
||||
fixedCacheKey
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [dispatch, fixedCacheKey, promise, requestId]);
|
||||
const debugValue = pick(currentState, ...COMMON_HOOK_DEBUG_FIELDS, "endpointName");
|
||||
(0, import_react.useDebugValue)(debugValue);
|
||||
const finalState = (0, import_react.useMemo)(() => ({
|
||||
...currentState,
|
||||
originalArgs,
|
||||
reset
|
||||
}), [currentState, originalArgs, reset]);
|
||||
return (0, import_react.useMemo)(() => [triggerMutation, finalState], [triggerMutation, finalState]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// src/query/react/module.ts
|
||||
var reactHooksModuleName = /* @__PURE__ */ Symbol();
|
||||
var reactHooksModule = ({
|
||||
batch = import_react_redux2.batch,
|
||||
hooks = {
|
||||
useDispatch: import_react_redux2.useDispatch,
|
||||
useSelector: import_react_redux2.useSelector,
|
||||
useStore: import_react_redux2.useStore
|
||||
},
|
||||
createSelector = import_reselect.createSelector,
|
||||
unstable__sideEffectsInRender = false,
|
||||
...rest
|
||||
} = {}) => {
|
||||
if (true) {
|
||||
const hookNames = ["useDispatch", "useSelector", "useStore"];
|
||||
let warned = false;
|
||||
for (const hookName of hookNames) {
|
||||
if (countObjectKeys(rest) > 0) {
|
||||
if (rest[hookName]) {
|
||||
if (!warned) {
|
||||
console.warn("As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
hooks[hookName] = rest[hookName];
|
||||
}
|
||||
if (typeof hooks[hookName] !== "function") {
|
||||
throw new Error(false ? _formatProdErrorMessage4(36) : `When using custom hooks for context, all ${hookNames.length} hooks need to be provided: ${hookNames.join(", ")}.
|
||||
Hook ${hookName} was either not provided or not a function.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: reactHooksModuleName,
|
||||
init(api, {
|
||||
serializeQueryArgs
|
||||
}, context) {
|
||||
const anyApi = api;
|
||||
const {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
} = buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks,
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
});
|
||||
safeAssign(anyApi, {
|
||||
usePrefetch
|
||||
});
|
||||
safeAssign(context, {
|
||||
batch
|
||||
});
|
||||
return {
|
||||
injectEndpoint(endpointName, definition) {
|
||||
if (isQueryDefinition(definition)) {
|
||||
const {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
} = buildQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Query`] = useQuery;
|
||||
api[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
|
||||
}
|
||||
if (isMutationDefinition(definition)) {
|
||||
const useMutation = buildMutationHook(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useMutation
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Mutation`] = useMutation;
|
||||
} else if (isInfiniteQueryDefinition(definition)) {
|
||||
const {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
} = buildInfiniteQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
});
|
||||
api[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/query/react/index.ts
|
||||
__reExport(react_exports, require("@reduxjs/toolkit/query"), module.exports);
|
||||
|
||||
// src/query/react/ApiProvider.tsx
|
||||
var import_toolkit3 = require("@reduxjs/toolkit");
|
||||
var React = __toESM(require("react"));
|
||||
function ApiProvider(props) {
|
||||
const context = props.context || import_react_redux.ReactReduxContext;
|
||||
const existingContext = (0, import_react.useContext)(context);
|
||||
if (existingContext) {
|
||||
throw new Error(false ? _formatProdErrorMessage5(35) : "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.");
|
||||
}
|
||||
const [store] = React.useState(() => (0, import_toolkit3.configureStore)({
|
||||
reducer: {
|
||||
[props.api.reducerPath]: props.api.reducer
|
||||
},
|
||||
middleware: (gDM) => gDM().concat(props.api.middleware)
|
||||
}));
|
||||
(0, import_react.useEffect)(() => props.setupListeners === false ? void 0 : (0, import_query.setupListeners)(store.dispatch, props.setupListeners), [props.setupListeners, store.dispatch]);
|
||||
return /* @__PURE__ */ React.createElement(import_react_redux.Provider, { store, context }, props.children);
|
||||
}
|
||||
|
||||
// src/query/react/index.ts
|
||||
var createApi = /* @__PURE__ */ (0, import_query.buildCreateApi)((0, import_query.coreModule)(), reactHooksModule());
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
ApiProvider,
|
||||
UNINITIALIZED_VALUE,
|
||||
createApi,
|
||||
reactHooksModule,
|
||||
reactHooksModuleName,
|
||||
...require("@reduxjs/toolkit/query")
|
||||
});
|
||||
//# sourceMappingURL=rtk-query-react.development.cjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1009
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.mts
generated
vendored
Normal file
1009
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.mts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1009
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.ts
generated
vendored
Normal file
1009
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
740
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js
generated
vendored
Normal file
740
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js
generated
vendored
Normal file
|
|
@ -0,0 +1,740 @@
|
|||
var __defProp = Object.defineProperty;
|
||||
var __defProps = Object.defineProperties;
|
||||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
||||
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
var __spreadValues = (a, b) => {
|
||||
for (var prop in b || (b = {}))
|
||||
if (__hasOwnProp.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
if (__getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(b)) {
|
||||
if (__propIsEnum.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
||||
var __objRest = (source, exclude) => {
|
||||
var target = {};
|
||||
for (var prop in source)
|
||||
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
||||
target[prop] = source[prop];
|
||||
if (source != null && __getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(source)) {
|
||||
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
||||
target[prop] = source[prop];
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
// src/query/react/rtkqImports.ts
|
||||
import { buildCreateApi, coreModule, copyWithStructuralSharing, setupListeners, QueryStatus, skipToken } from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/module.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage4 } from "@reduxjs/toolkit";
|
||||
import { batch as rrBatch, useDispatch as rrUseDispatch, useSelector as rrUseSelector, useStore as rrUseStore } from "react-redux";
|
||||
import { createSelector as _createSelector } from "reselect";
|
||||
|
||||
// src/query/utils/capitalize.ts
|
||||
function capitalize(str) {
|
||||
return str.replace(str[0], str[0].toUpperCase());
|
||||
}
|
||||
|
||||
// src/query/utils/countObjectKeys.ts
|
||||
function countObjectKeys(obj) {
|
||||
let count = 0;
|
||||
for (const _key in obj) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// src/query/endpointDefinitions.ts
|
||||
var ENDPOINT_QUERY = "query" /* query */;
|
||||
var ENDPOINT_MUTATION = "mutation" /* mutation */;
|
||||
var ENDPOINT_INFINITEQUERY = "infinitequery" /* infinitequery */;
|
||||
function isQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_QUERY;
|
||||
}
|
||||
function isMutationDefinition(e) {
|
||||
return e.type === ENDPOINT_MUTATION;
|
||||
}
|
||||
function isInfiniteQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_INFINITEQUERY;
|
||||
}
|
||||
|
||||
// src/query/tsHelpers.ts
|
||||
function safeAssign(target, ...args) {
|
||||
return Object.assign(target, ...args);
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage, formatProdErrorMessage as _formatProdErrorMessage2, formatProdErrorMessage as _formatProdErrorMessage3 } from "@reduxjs/toolkit";
|
||||
|
||||
// src/query/react/constants.ts
|
||||
var UNINITIALIZED_VALUE = /* @__PURE__ */ Symbol();
|
||||
|
||||
// src/query/react/reactImports.ts
|
||||
import { useEffect, useRef, useMemo, useContext, useCallback, useDebugValue, useLayoutEffect, useState } from "react";
|
||||
|
||||
// src/query/react/reactReduxImports.ts
|
||||
import { shallowEqual, Provider, ReactReduxContext } from "react-redux";
|
||||
|
||||
// src/query/react/useSerializedStableValue.ts
|
||||
function useStableQueryArgs(queryArgs) {
|
||||
const cache = useRef(queryArgs);
|
||||
const copy = useMemo(() => copyWithStructuralSharing(cache.current, queryArgs), [queryArgs]);
|
||||
useEffect(() => {
|
||||
if (cache.current !== copy) {
|
||||
cache.current = copy;
|
||||
}
|
||||
}, [copy]);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// src/query/react/useShallowStableValue.ts
|
||||
function useShallowStableValue(value) {
|
||||
const cache = useRef(value);
|
||||
useEffect(() => {
|
||||
if (!shallowEqual(cache.current, value)) {
|
||||
cache.current = value;
|
||||
}
|
||||
}, [value]);
|
||||
return shallowEqual(cache.current, value) ? cache.current : value;
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
||||
var isDOM = /* @__PURE__ */ canUseDOM();
|
||||
var isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
||||
var isReactNative = /* @__PURE__ */ isRunningInReactNative();
|
||||
var getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? useLayoutEffect : useEffect;
|
||||
var useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect();
|
||||
var noPendingQueryStateSelector = (selected) => {
|
||||
if (selected.isUninitialized) {
|
||||
return __spreadProps(__spreadValues({}, selected), {
|
||||
isUninitialized: false,
|
||||
isFetching: true,
|
||||
isLoading: selected.data !== void 0 ? false : true,
|
||||
// This is the one place where we still have to use `QueryStatus` as an enum,
|
||||
// since it's the only reference in the React package and not in the core.
|
||||
status: QueryStatus.pending
|
||||
});
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
function pick(obj, ...keys) {
|
||||
const ret = {};
|
||||
keys.forEach((key) => {
|
||||
ret[key] = obj[key];
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
var COMMON_HOOK_DEBUG_FIELDS = ["data", "status", "isLoading", "isSuccess", "isError", "error"];
|
||||
function buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks: {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
useStore
|
||||
},
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
}) {
|
||||
const usePossiblyImmediateEffect = unstable__sideEffectsInRender ? (cb) => cb() : useEffect;
|
||||
const unsubscribePromiseRef = (ref) => {
|
||||
var _a, _b;
|
||||
return (_b = (_a = ref.current) == null ? void 0 : _a.unsubscribe) == null ? void 0 : _b.call(_a);
|
||||
};
|
||||
const endpointDefinitions = context.endpointDefinitions;
|
||||
return {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
};
|
||||
function queryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if ((lastResult == null ? void 0 : lastResult.endpointName) && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult == null ? void 0 : lastResult.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !(lastResult == null ? void 0 : lastResult.isError) || currentState.isUninitialized);
|
||||
return __spreadProps(__spreadValues({}, currentState), {
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
});
|
||||
}
|
||||
function infiniteQueryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if ((lastResult == null ? void 0 : lastResult.endpointName) && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult == null ? void 0 : lastResult.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !(lastResult == null ? void 0 : lastResult.isError) || currentState.isUninitialized);
|
||||
return __spreadProps(__spreadValues({}, currentState), {
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
});
|
||||
}
|
||||
function usePrefetch(endpointName, defaultOptions) {
|
||||
const dispatch = useDispatch();
|
||||
const stableDefaultOptions = useShallowStableValue(defaultOptions);
|
||||
return useCallback((arg, options) => dispatch(api.util.prefetch(endpointName, arg, __spreadValues(__spreadValues({}, stableDefaultOptions), options))), [endpointName, dispatch, stableDefaultOptions]);
|
||||
}
|
||||
function useQuerySubscriptionCommonImpl(endpointName, arg, _a = {}) {
|
||||
var _b = _a, {
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
refetchOnMountOrArgChange,
|
||||
skip = false,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = _b, rest = __objRest(_b, [
|
||||
"refetchOnReconnect",
|
||||
"refetchOnFocus",
|
||||
"refetchOnMountOrArgChange",
|
||||
"skip",
|
||||
"pollingInterval",
|
||||
"skipPollingIfUnfocused"
|
||||
]);
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const subscriptionSelectorsRef = useRef(void 0);
|
||||
if (!subscriptionSelectorsRef.current) {
|
||||
const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions());
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (typeof returnedValue !== "object" || typeof (returnedValue == null ? void 0 : returnedValue.type) === "string") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage(37) : `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
|
||||
You must add the middleware for RTK-Query to function correctly!`);
|
||||
}
|
||||
}
|
||||
subscriptionSelectorsRef.current = returnedValue;
|
||||
}
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
const initialPageParam = rest.initialPageParam;
|
||||
const stableInitialPageParam = useShallowStableValue(initialPageParam);
|
||||
const refetchCachedPages = rest.refetchCachedPages;
|
||||
const stableRefetchCachedPages = useShallowStableValue(refetchCachedPages);
|
||||
const promiseRef = useRef(void 0);
|
||||
let {
|
||||
queryCacheKey,
|
||||
requestId
|
||||
} = promiseRef.current || {};
|
||||
let currentRenderHasSubscription = false;
|
||||
if (queryCacheKey && requestId) {
|
||||
currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed(queryCacheKey, requestId);
|
||||
}
|
||||
const subscriptionRemoved = !currentRenderHasSubscription && promiseRef.current !== void 0;
|
||||
usePossiblyImmediateEffect(() => {
|
||||
if (subscriptionRemoved) {
|
||||
promiseRef.current = void 0;
|
||||
}
|
||||
}, [subscriptionRemoved]);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
var _a2;
|
||||
const lastPromise = promiseRef.current;
|
||||
if (typeof process !== "undefined" && process.env.NODE_ENV === "removeMeOnCompilation") {
|
||||
console.log(subscriptionRemoved);
|
||||
}
|
||||
if (stableArg === skipToken) {
|
||||
lastPromise == null ? void 0 : lastPromise.unsubscribe();
|
||||
promiseRef.current = void 0;
|
||||
return;
|
||||
}
|
||||
const lastSubscriptionOptions = (_a2 = promiseRef.current) == null ? void 0 : _a2.subscriptionOptions;
|
||||
if (!lastPromise || lastPromise.arg !== stableArg) {
|
||||
lastPromise == null ? void 0 : lastPromise.unsubscribe();
|
||||
const promise = dispatch(initiate(stableArg, __spreadValues({
|
||||
subscriptionOptions: stableSubscriptionOptions,
|
||||
forceRefetch: refetchOnMountOrArgChange
|
||||
}, isInfiniteQueryDefinition(endpointDefinitions[endpointName]) ? {
|
||||
initialPageParam: stableInitialPageParam,
|
||||
refetchCachedPages: stableRefetchCachedPages
|
||||
} : {})));
|
||||
promiseRef.current = promise;
|
||||
} else if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
lastPromise.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [dispatch, initiate, refetchOnMountOrArgChange, stableArg, stableSubscriptionOptions, subscriptionRemoved, stableInitialPageParam, stableRefetchCachedPages, endpointName]);
|
||||
return [promiseRef, dispatch, initiate, stableSubscriptionOptions];
|
||||
}
|
||||
function buildUseQueryState(endpointName, preSelector) {
|
||||
const useQueryState = (arg, {
|
||||
skip = false,
|
||||
selectFromResult
|
||||
} = {}) => {
|
||||
const {
|
||||
select
|
||||
} = api.endpoints[endpointName];
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const lastValue = useRef(void 0);
|
||||
const selectDefaultResult = useMemo(() => (
|
||||
// Normally ts-ignores are bad and should be avoided, but we're
|
||||
// already casting this selector to be `Selector<any>` anyway,
|
||||
// so the inconsistencies don't matter here
|
||||
// @ts-ignore
|
||||
createSelector([
|
||||
// @ts-ignore
|
||||
select(stableArg),
|
||||
(_, lastResult) => lastResult,
|
||||
(_) => stableArg
|
||||
], preSelector, {
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallowEqual
|
||||
}
|
||||
})
|
||||
), [select, stableArg]);
|
||||
const querySelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult, {
|
||||
devModeChecks: {
|
||||
identityFunctionCheck: "never"
|
||||
}
|
||||
}) : selectDefaultResult, [selectDefaultResult, selectFromResult]);
|
||||
const currentState = useSelector((state) => querySelector(state, lastValue.current), shallowEqual);
|
||||
const store = useStore();
|
||||
const newLastValue = selectDefaultResult(store.getState(), lastValue.current);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
lastValue.current = newLastValue;
|
||||
}, [newLastValue]);
|
||||
return currentState;
|
||||
};
|
||||
return useQueryState;
|
||||
}
|
||||
function usePromiseRefUnsubscribeOnUnmount(promiseRef) {
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = void 0;
|
||||
};
|
||||
}, [promiseRef]);
|
||||
}
|
||||
function refetchOrErrorIfUnmounted(promiseRef) {
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage2(38) : "Cannot refetch a query that has not been started yet.");
|
||||
return promiseRef.current.refetch();
|
||||
}
|
||||
function buildQueryHooks(endpointName) {
|
||||
const useQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
return useMemo(() => ({
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch: () => refetchOrErrorIfUnmounted(promiseRef)
|
||||
}), [promiseRef]);
|
||||
};
|
||||
const useLazyQuerySubscription = ({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = {}) => {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const [arg, setArg] = useState(UNINITIALIZED_VALUE);
|
||||
const promiseRef = useRef(void 0);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
usePossiblyImmediateEffect(() => {
|
||||
var _a, _b;
|
||||
const lastSubscriptionOptions = (_a = promiseRef.current) == null ? void 0 : _a.subscriptionOptions;
|
||||
if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
(_b = promiseRef.current) == null ? void 0 : _b.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [stableSubscriptionOptions]);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const trigger = useCallback(function(arg2, preferCacheValue = false) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
forceRefetch: !preferCacheValue
|
||||
}));
|
||||
setArg(arg2);
|
||||
});
|
||||
return promise;
|
||||
}, [dispatch, initiate]);
|
||||
const reset = useCallback(() => {
|
||||
var _a, _b;
|
||||
if ((_a = promiseRef.current) == null ? void 0 : _a.queryCacheKey) {
|
||||
dispatch(api.internalActions.removeQueryResult({
|
||||
queryCacheKey: (_b = promiseRef.current) == null ? void 0 : _b.queryCacheKey
|
||||
}));
|
||||
}
|
||||
}, [dispatch]);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (arg !== UNINITIALIZED_VALUE && !promiseRef.current) {
|
||||
trigger(arg, true);
|
||||
}
|
||||
}, [arg, trigger]);
|
||||
return useMemo(() => [trigger, arg, {
|
||||
reset
|
||||
}], [trigger, arg, reset]);
|
||||
};
|
||||
const useQueryState = buildUseQueryState(endpointName, queryStatePreSelector);
|
||||
return {
|
||||
useQueryState,
|
||||
useQuerySubscription,
|
||||
useLazyQuerySubscription,
|
||||
useLazyQuery(options) {
|
||||
const [trigger, arg, {
|
||||
reset
|
||||
}] = useLazyQuerySubscription(options);
|
||||
const queryStateResults = useQueryState(arg, __spreadProps(__spreadValues({}, options), {
|
||||
skip: arg === UNINITIALIZED_VALUE
|
||||
}));
|
||||
const info = useMemo(() => ({
|
||||
lastArg: arg
|
||||
}), [arg]);
|
||||
return useMemo(() => [trigger, __spreadProps(__spreadValues({}, queryStateResults), {
|
||||
reset
|
||||
}), info], [trigger, queryStateResults, reset, info]);
|
||||
},
|
||||
useQuery(arg, options) {
|
||||
const querySubscriptionResults = useQuerySubscription(arg, options);
|
||||
const queryStateResults = useQueryState(arg, __spreadValues({
|
||||
selectFromResult: arg === skipToken || (options == null ? void 0 : options.skip) ? void 0 : noPendingQueryStateSelector
|
||||
}, options));
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS);
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => __spreadValues(__spreadValues({}, queryStateResults), querySubscriptionResults), [queryStateResults, querySubscriptionResults]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildInfiniteQueryHooks(endpointName) {
|
||||
const useInfiniteQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef, dispatch, initiate, stableSubscriptionOptions] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const hookRefetchCachedPages = options.refetchCachedPages;
|
||||
const stableHookRefetchCachedPages = useShallowStableValue(hookRefetchCachedPages);
|
||||
const trigger = useCallback(function(arg2, direction) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
direction
|
||||
}));
|
||||
});
|
||||
return promise;
|
||||
}, [promiseRef, dispatch, initiate]);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
const stableArg = useStableQueryArgs(options.skip ? skipToken : arg);
|
||||
const refetch = useCallback((options2) => {
|
||||
var _a;
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage3(38) : "Cannot refetch a query that has not been started yet.");
|
||||
const mergedOptions = {
|
||||
refetchCachedPages: (_a = options2 == null ? void 0 : options2.refetchCachedPages) != null ? _a : stableHookRefetchCachedPages
|
||||
};
|
||||
return promiseRef.current.refetch(mergedOptions);
|
||||
}, [promiseRef, stableHookRefetchCachedPages]);
|
||||
return useMemo(() => {
|
||||
const fetchNextPage = () => {
|
||||
return trigger(stableArg, "forward");
|
||||
};
|
||||
const fetchPreviousPage = () => {
|
||||
return trigger(stableArg, "backward");
|
||||
};
|
||||
return {
|
||||
trigger,
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
};
|
||||
}, [refetch, trigger, stableArg]);
|
||||
};
|
||||
const useInfiniteQueryState = buildUseQueryState(endpointName, infiniteQueryStatePreSelector);
|
||||
return {
|
||||
useInfiniteQueryState,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQuery(arg, options) {
|
||||
const {
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
} = useInfiniteQuerySubscription(arg, options);
|
||||
const queryStateResults = useInfiniteQueryState(arg, __spreadValues({
|
||||
selectFromResult: arg === skipToken || (options == null ? void 0 : options.skip) ? void 0 : noPendingQueryStateSelector
|
||||
}, options));
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS, "hasNextPage", "hasPreviousPage");
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => __spreadProps(__spreadValues({}, queryStateResults), {
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
refetch
|
||||
}), [queryStateResults, fetchNextPage, fetchPreviousPage, refetch]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildMutationHook(name) {
|
||||
return ({
|
||||
selectFromResult,
|
||||
fixedCacheKey
|
||||
} = {}) => {
|
||||
const {
|
||||
select,
|
||||
initiate
|
||||
} = api.endpoints[name];
|
||||
const dispatch = useDispatch();
|
||||
const [promise, setPromise] = useState();
|
||||
useEffect(() => () => {
|
||||
if (!(promise == null ? void 0 : promise.arg.fixedCacheKey)) {
|
||||
promise == null ? void 0 : promise.reset();
|
||||
}
|
||||
}, [promise]);
|
||||
const triggerMutation = useCallback(function(arg) {
|
||||
const promise2 = dispatch(initiate(arg, {
|
||||
fixedCacheKey
|
||||
}));
|
||||
setPromise(promise2);
|
||||
return promise2;
|
||||
}, [dispatch, initiate, fixedCacheKey]);
|
||||
const {
|
||||
requestId
|
||||
} = promise || {};
|
||||
const selectDefaultResult = useMemo(() => select({
|
||||
fixedCacheKey,
|
||||
requestId: promise == null ? void 0 : promise.requestId
|
||||
}), [fixedCacheKey, promise, select]);
|
||||
const mutationSelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, [selectFromResult, selectDefaultResult]);
|
||||
const currentState = useSelector(mutationSelector, shallowEqual);
|
||||
const originalArgs = fixedCacheKey == null ? promise == null ? void 0 : promise.arg.originalArgs : void 0;
|
||||
const reset = useCallback(() => {
|
||||
batch(() => {
|
||||
if (promise) {
|
||||
setPromise(void 0);
|
||||
}
|
||||
if (fixedCacheKey) {
|
||||
dispatch(api.internalActions.removeMutationResult({
|
||||
requestId,
|
||||
fixedCacheKey
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [dispatch, fixedCacheKey, promise, requestId]);
|
||||
const debugValue = pick(currentState, ...COMMON_HOOK_DEBUG_FIELDS, "endpointName");
|
||||
useDebugValue(debugValue);
|
||||
const finalState = useMemo(() => __spreadProps(__spreadValues({}, currentState), {
|
||||
originalArgs,
|
||||
reset
|
||||
}), [currentState, originalArgs, reset]);
|
||||
return useMemo(() => [triggerMutation, finalState], [triggerMutation, finalState]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// src/query/react/module.ts
|
||||
var reactHooksModuleName = /* @__PURE__ */ Symbol();
|
||||
var reactHooksModule = (_a = {}) => {
|
||||
var _b = _a, {
|
||||
batch = rrBatch,
|
||||
hooks = {
|
||||
useDispatch: rrUseDispatch,
|
||||
useSelector: rrUseSelector,
|
||||
useStore: rrUseStore
|
||||
},
|
||||
createSelector = _createSelector,
|
||||
unstable__sideEffectsInRender = false
|
||||
} = _b, rest = __objRest(_b, [
|
||||
"batch",
|
||||
"hooks",
|
||||
"createSelector",
|
||||
"unstable__sideEffectsInRender"
|
||||
]);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const hookNames = ["useDispatch", "useSelector", "useStore"];
|
||||
let warned = false;
|
||||
for (const hookName of hookNames) {
|
||||
if (countObjectKeys(rest) > 0) {
|
||||
if (rest[hookName]) {
|
||||
if (!warned) {
|
||||
console.warn("As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
hooks[hookName] = rest[hookName];
|
||||
}
|
||||
if (typeof hooks[hookName] !== "function") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage4(36) : `When using custom hooks for context, all ${hookNames.length} hooks need to be provided: ${hookNames.join(", ")}.
|
||||
Hook ${hookName} was either not provided or not a function.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: reactHooksModuleName,
|
||||
init(api, {
|
||||
serializeQueryArgs
|
||||
}, context) {
|
||||
const anyApi = api;
|
||||
const {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
} = buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks,
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
});
|
||||
safeAssign(anyApi, {
|
||||
usePrefetch
|
||||
});
|
||||
safeAssign(context, {
|
||||
batch
|
||||
});
|
||||
return {
|
||||
injectEndpoint(endpointName, definition) {
|
||||
if (isQueryDefinition(definition)) {
|
||||
const {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
} = buildQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Query`] = useQuery;
|
||||
api[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
|
||||
}
|
||||
if (isMutationDefinition(definition)) {
|
||||
const useMutation = buildMutationHook(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useMutation
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Mutation`] = useMutation;
|
||||
} else if (isInfiniteQueryDefinition(definition)) {
|
||||
const {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
} = buildInfiniteQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
});
|
||||
api[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/query/react/index.ts
|
||||
export * from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/ApiProvider.tsx
|
||||
import { configureStore, formatProdErrorMessage as _formatProdErrorMessage5 } from "@reduxjs/toolkit";
|
||||
import * as React from "react";
|
||||
function ApiProvider(props) {
|
||||
const context = props.context || ReactReduxContext;
|
||||
const existingContext = useContext(context);
|
||||
if (existingContext) {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage5(35) : "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.");
|
||||
}
|
||||
const [store] = React.useState(() => configureStore({
|
||||
reducer: {
|
||||
[props.api.reducerPath]: props.api.reducer
|
||||
},
|
||||
middleware: (gDM) => gDM().concat(props.api.middleware)
|
||||
}));
|
||||
useEffect(() => props.setupListeners === false ? void 0 : setupListeners(store.dispatch, props.setupListeners), [props.setupListeners, store.dispatch]);
|
||||
return /* @__PURE__ */ React.createElement(Provider, { store, context }, props.children);
|
||||
}
|
||||
|
||||
// src/query/react/index.ts
|
||||
var createApi = /* @__PURE__ */ buildCreateApi(coreModule(), reactHooksModule());
|
||||
export {
|
||||
ApiProvider,
|
||||
UNINITIALIZED_VALUE,
|
||||
createApi,
|
||||
reactHooksModule,
|
||||
reactHooksModuleName
|
||||
};
|
||||
//# sourceMappingURL=rtk-query-react.legacy-esm.js.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
705
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs
generated
vendored
Normal file
705
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs
generated
vendored
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
// src/query/react/rtkqImports.ts
|
||||
import { buildCreateApi, coreModule, copyWithStructuralSharing, setupListeners, QueryStatus, skipToken } from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/module.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage4 } from "@reduxjs/toolkit";
|
||||
import { batch as rrBatch, useDispatch as rrUseDispatch, useSelector as rrUseSelector, useStore as rrUseStore } from "react-redux";
|
||||
import { createSelector as _createSelector } from "reselect";
|
||||
|
||||
// src/query/utils/capitalize.ts
|
||||
function capitalize(str) {
|
||||
return str.replace(str[0], str[0].toUpperCase());
|
||||
}
|
||||
|
||||
// src/query/utils/countObjectKeys.ts
|
||||
function countObjectKeys(obj) {
|
||||
let count = 0;
|
||||
for (const _key in obj) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// src/query/endpointDefinitions.ts
|
||||
var ENDPOINT_QUERY = "query" /* query */;
|
||||
var ENDPOINT_MUTATION = "mutation" /* mutation */;
|
||||
var ENDPOINT_INFINITEQUERY = "infinitequery" /* infinitequery */;
|
||||
function isQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_QUERY;
|
||||
}
|
||||
function isMutationDefinition(e) {
|
||||
return e.type === ENDPOINT_MUTATION;
|
||||
}
|
||||
function isInfiniteQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_INFINITEQUERY;
|
||||
}
|
||||
|
||||
// src/query/tsHelpers.ts
|
||||
function safeAssign(target, ...args) {
|
||||
return Object.assign(target, ...args);
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage, formatProdErrorMessage as _formatProdErrorMessage2, formatProdErrorMessage as _formatProdErrorMessage3 } from "@reduxjs/toolkit";
|
||||
|
||||
// src/query/react/constants.ts
|
||||
var UNINITIALIZED_VALUE = /* @__PURE__ */ Symbol();
|
||||
|
||||
// src/query/react/reactImports.ts
|
||||
import { useEffect, useRef, useMemo, useContext, useCallback, useDebugValue, useLayoutEffect, useState } from "react";
|
||||
|
||||
// src/query/react/reactReduxImports.ts
|
||||
import { shallowEqual, Provider, ReactReduxContext } from "react-redux";
|
||||
|
||||
// src/query/react/useSerializedStableValue.ts
|
||||
function useStableQueryArgs(queryArgs) {
|
||||
const cache = useRef(queryArgs);
|
||||
const copy = useMemo(() => copyWithStructuralSharing(cache.current, queryArgs), [queryArgs]);
|
||||
useEffect(() => {
|
||||
if (cache.current !== copy) {
|
||||
cache.current = copy;
|
||||
}
|
||||
}, [copy]);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// src/query/react/useShallowStableValue.ts
|
||||
function useShallowStableValue(value) {
|
||||
const cache = useRef(value);
|
||||
useEffect(() => {
|
||||
if (!shallowEqual(cache.current, value)) {
|
||||
cache.current = value;
|
||||
}
|
||||
}, [value]);
|
||||
return shallowEqual(cache.current, value) ? cache.current : value;
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
||||
var isDOM = /* @__PURE__ */ canUseDOM();
|
||||
var isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
||||
var isReactNative = /* @__PURE__ */ isRunningInReactNative();
|
||||
var getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? useLayoutEffect : useEffect;
|
||||
var useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect();
|
||||
var noPendingQueryStateSelector = (selected) => {
|
||||
if (selected.isUninitialized) {
|
||||
return {
|
||||
...selected,
|
||||
isUninitialized: false,
|
||||
isFetching: true,
|
||||
isLoading: selected.data !== void 0 ? false : true,
|
||||
// This is the one place where we still have to use `QueryStatus` as an enum,
|
||||
// since it's the only reference in the React package and not in the core.
|
||||
status: QueryStatus.pending
|
||||
};
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
function pick(obj, ...keys) {
|
||||
const ret = {};
|
||||
keys.forEach((key) => {
|
||||
ret[key] = obj[key];
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
var COMMON_HOOK_DEBUG_FIELDS = ["data", "status", "isLoading", "isSuccess", "isError", "error"];
|
||||
function buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks: {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
useStore
|
||||
},
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
}) {
|
||||
const usePossiblyImmediateEffect = unstable__sideEffectsInRender ? (cb) => cb() : useEffect;
|
||||
const unsubscribePromiseRef = (ref) => ref.current?.unsubscribe?.();
|
||||
const endpointDefinitions = context.endpointDefinitions;
|
||||
return {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
};
|
||||
function queryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !lastResult?.isError || currentState.isUninitialized);
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function infiniteQueryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !lastResult?.isError || currentState.isUninitialized);
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function usePrefetch(endpointName, defaultOptions) {
|
||||
const dispatch = useDispatch();
|
||||
const stableDefaultOptions = useShallowStableValue(defaultOptions);
|
||||
return useCallback((arg, options) => dispatch(api.util.prefetch(endpointName, arg, {
|
||||
...stableDefaultOptions,
|
||||
...options
|
||||
})), [endpointName, dispatch, stableDefaultOptions]);
|
||||
}
|
||||
function useQuerySubscriptionCommonImpl(endpointName, arg, {
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
refetchOnMountOrArgChange,
|
||||
skip = false,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false,
|
||||
...rest
|
||||
} = {}) {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const subscriptionSelectorsRef = useRef(void 0);
|
||||
if (!subscriptionSelectorsRef.current) {
|
||||
const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions());
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (typeof returnedValue !== "object" || typeof returnedValue?.type === "string") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage(37) : `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
|
||||
You must add the middleware for RTK-Query to function correctly!`);
|
||||
}
|
||||
}
|
||||
subscriptionSelectorsRef.current = returnedValue;
|
||||
}
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
const initialPageParam = rest.initialPageParam;
|
||||
const stableInitialPageParam = useShallowStableValue(initialPageParam);
|
||||
const refetchCachedPages = rest.refetchCachedPages;
|
||||
const stableRefetchCachedPages = useShallowStableValue(refetchCachedPages);
|
||||
const promiseRef = useRef(void 0);
|
||||
let {
|
||||
queryCacheKey,
|
||||
requestId
|
||||
} = promiseRef.current || {};
|
||||
let currentRenderHasSubscription = false;
|
||||
if (queryCacheKey && requestId) {
|
||||
currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed(queryCacheKey, requestId);
|
||||
}
|
||||
const subscriptionRemoved = !currentRenderHasSubscription && promiseRef.current !== void 0;
|
||||
usePossiblyImmediateEffect(() => {
|
||||
if (subscriptionRemoved) {
|
||||
promiseRef.current = void 0;
|
||||
}
|
||||
}, [subscriptionRemoved]);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastPromise = promiseRef.current;
|
||||
if (typeof process !== "undefined" && process.env.NODE_ENV === "removeMeOnCompilation") {
|
||||
console.log(subscriptionRemoved);
|
||||
}
|
||||
if (stableArg === skipToken) {
|
||||
lastPromise?.unsubscribe();
|
||||
promiseRef.current = void 0;
|
||||
return;
|
||||
}
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (!lastPromise || lastPromise.arg !== stableArg) {
|
||||
lastPromise?.unsubscribe();
|
||||
const promise = dispatch(initiate(stableArg, {
|
||||
subscriptionOptions: stableSubscriptionOptions,
|
||||
forceRefetch: refetchOnMountOrArgChange,
|
||||
...isInfiniteQueryDefinition(endpointDefinitions[endpointName]) ? {
|
||||
initialPageParam: stableInitialPageParam,
|
||||
refetchCachedPages: stableRefetchCachedPages
|
||||
} : {}
|
||||
}));
|
||||
promiseRef.current = promise;
|
||||
} else if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
lastPromise.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [dispatch, initiate, refetchOnMountOrArgChange, stableArg, stableSubscriptionOptions, subscriptionRemoved, stableInitialPageParam, stableRefetchCachedPages, endpointName]);
|
||||
return [promiseRef, dispatch, initiate, stableSubscriptionOptions];
|
||||
}
|
||||
function buildUseQueryState(endpointName, preSelector) {
|
||||
const useQueryState = (arg, {
|
||||
skip = false,
|
||||
selectFromResult
|
||||
} = {}) => {
|
||||
const {
|
||||
select
|
||||
} = api.endpoints[endpointName];
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const lastValue = useRef(void 0);
|
||||
const selectDefaultResult = useMemo(() => (
|
||||
// Normally ts-ignores are bad and should be avoided, but we're
|
||||
// already casting this selector to be `Selector<any>` anyway,
|
||||
// so the inconsistencies don't matter here
|
||||
// @ts-ignore
|
||||
createSelector([
|
||||
// @ts-ignore
|
||||
select(stableArg),
|
||||
(_, lastResult) => lastResult,
|
||||
(_) => stableArg
|
||||
], preSelector, {
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallowEqual
|
||||
}
|
||||
})
|
||||
), [select, stableArg]);
|
||||
const querySelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult, {
|
||||
devModeChecks: {
|
||||
identityFunctionCheck: "never"
|
||||
}
|
||||
}) : selectDefaultResult, [selectDefaultResult, selectFromResult]);
|
||||
const currentState = useSelector((state) => querySelector(state, lastValue.current), shallowEqual);
|
||||
const store = useStore();
|
||||
const newLastValue = selectDefaultResult(store.getState(), lastValue.current);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
lastValue.current = newLastValue;
|
||||
}, [newLastValue]);
|
||||
return currentState;
|
||||
};
|
||||
return useQueryState;
|
||||
}
|
||||
function usePromiseRefUnsubscribeOnUnmount(promiseRef) {
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = void 0;
|
||||
};
|
||||
}, [promiseRef]);
|
||||
}
|
||||
function refetchOrErrorIfUnmounted(promiseRef) {
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage2(38) : "Cannot refetch a query that has not been started yet.");
|
||||
return promiseRef.current.refetch();
|
||||
}
|
||||
function buildQueryHooks(endpointName) {
|
||||
const useQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
return useMemo(() => ({
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch: () => refetchOrErrorIfUnmounted(promiseRef)
|
||||
}), [promiseRef]);
|
||||
};
|
||||
const useLazyQuerySubscription = ({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = {}) => {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const [arg, setArg] = useState(UNINITIALIZED_VALUE);
|
||||
const promiseRef = useRef(void 0);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
promiseRef.current?.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [stableSubscriptionOptions]);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const trigger = useCallback(function(arg2, preferCacheValue = false) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
forceRefetch: !preferCacheValue
|
||||
}));
|
||||
setArg(arg2);
|
||||
});
|
||||
return promise;
|
||||
}, [dispatch, initiate]);
|
||||
const reset = useCallback(() => {
|
||||
if (promiseRef.current?.queryCacheKey) {
|
||||
dispatch(api.internalActions.removeQueryResult({
|
||||
queryCacheKey: promiseRef.current?.queryCacheKey
|
||||
}));
|
||||
}
|
||||
}, [dispatch]);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (arg !== UNINITIALIZED_VALUE && !promiseRef.current) {
|
||||
trigger(arg, true);
|
||||
}
|
||||
}, [arg, trigger]);
|
||||
return useMemo(() => [trigger, arg, {
|
||||
reset
|
||||
}], [trigger, arg, reset]);
|
||||
};
|
||||
const useQueryState = buildUseQueryState(endpointName, queryStatePreSelector);
|
||||
return {
|
||||
useQueryState,
|
||||
useQuerySubscription,
|
||||
useLazyQuerySubscription,
|
||||
useLazyQuery(options) {
|
||||
const [trigger, arg, {
|
||||
reset
|
||||
}] = useLazyQuerySubscription(options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
...options,
|
||||
skip: arg === UNINITIALIZED_VALUE
|
||||
});
|
||||
const info = useMemo(() => ({
|
||||
lastArg: arg
|
||||
}), [arg]);
|
||||
return useMemo(() => [trigger, {
|
||||
...queryStateResults,
|
||||
reset
|
||||
}, info], [trigger, queryStateResults, reset, info]);
|
||||
},
|
||||
useQuery(arg, options) {
|
||||
const querySubscriptionResults = useQuerySubscription(arg, options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
selectFromResult: arg === skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS);
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => ({
|
||||
...queryStateResults,
|
||||
...querySubscriptionResults
|
||||
}), [queryStateResults, querySubscriptionResults]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildInfiniteQueryHooks(endpointName) {
|
||||
const useInfiniteQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef, dispatch, initiate, stableSubscriptionOptions] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const hookRefetchCachedPages = options.refetchCachedPages;
|
||||
const stableHookRefetchCachedPages = useShallowStableValue(hookRefetchCachedPages);
|
||||
const trigger = useCallback(function(arg2, direction) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
direction
|
||||
}));
|
||||
});
|
||||
return promise;
|
||||
}, [promiseRef, dispatch, initiate]);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
const stableArg = useStableQueryArgs(options.skip ? skipToken : arg);
|
||||
const refetch = useCallback((options2) => {
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage3(38) : "Cannot refetch a query that has not been started yet.");
|
||||
const mergedOptions = {
|
||||
refetchCachedPages: options2?.refetchCachedPages ?? stableHookRefetchCachedPages
|
||||
};
|
||||
return promiseRef.current.refetch(mergedOptions);
|
||||
}, [promiseRef, stableHookRefetchCachedPages]);
|
||||
return useMemo(() => {
|
||||
const fetchNextPage = () => {
|
||||
return trigger(stableArg, "forward");
|
||||
};
|
||||
const fetchPreviousPage = () => {
|
||||
return trigger(stableArg, "backward");
|
||||
};
|
||||
return {
|
||||
trigger,
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
};
|
||||
}, [refetch, trigger, stableArg]);
|
||||
};
|
||||
const useInfiniteQueryState = buildUseQueryState(endpointName, infiniteQueryStatePreSelector);
|
||||
return {
|
||||
useInfiniteQueryState,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQuery(arg, options) {
|
||||
const {
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
} = useInfiniteQuerySubscription(arg, options);
|
||||
const queryStateResults = useInfiniteQueryState(arg, {
|
||||
selectFromResult: arg === skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS, "hasNextPage", "hasPreviousPage");
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => ({
|
||||
...queryStateResults,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
refetch
|
||||
}), [queryStateResults, fetchNextPage, fetchPreviousPage, refetch]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildMutationHook(name) {
|
||||
return ({
|
||||
selectFromResult,
|
||||
fixedCacheKey
|
||||
} = {}) => {
|
||||
const {
|
||||
select,
|
||||
initiate
|
||||
} = api.endpoints[name];
|
||||
const dispatch = useDispatch();
|
||||
const [promise, setPromise] = useState();
|
||||
useEffect(() => () => {
|
||||
if (!promise?.arg.fixedCacheKey) {
|
||||
promise?.reset();
|
||||
}
|
||||
}, [promise]);
|
||||
const triggerMutation = useCallback(function(arg) {
|
||||
const promise2 = dispatch(initiate(arg, {
|
||||
fixedCacheKey
|
||||
}));
|
||||
setPromise(promise2);
|
||||
return promise2;
|
||||
}, [dispatch, initiate, fixedCacheKey]);
|
||||
const {
|
||||
requestId
|
||||
} = promise || {};
|
||||
const selectDefaultResult = useMemo(() => select({
|
||||
fixedCacheKey,
|
||||
requestId: promise?.requestId
|
||||
}), [fixedCacheKey, promise, select]);
|
||||
const mutationSelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, [selectFromResult, selectDefaultResult]);
|
||||
const currentState = useSelector(mutationSelector, shallowEqual);
|
||||
const originalArgs = fixedCacheKey == null ? promise?.arg.originalArgs : void 0;
|
||||
const reset = useCallback(() => {
|
||||
batch(() => {
|
||||
if (promise) {
|
||||
setPromise(void 0);
|
||||
}
|
||||
if (fixedCacheKey) {
|
||||
dispatch(api.internalActions.removeMutationResult({
|
||||
requestId,
|
||||
fixedCacheKey
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [dispatch, fixedCacheKey, promise, requestId]);
|
||||
const debugValue = pick(currentState, ...COMMON_HOOK_DEBUG_FIELDS, "endpointName");
|
||||
useDebugValue(debugValue);
|
||||
const finalState = useMemo(() => ({
|
||||
...currentState,
|
||||
originalArgs,
|
||||
reset
|
||||
}), [currentState, originalArgs, reset]);
|
||||
return useMemo(() => [triggerMutation, finalState], [triggerMutation, finalState]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// src/query/react/module.ts
|
||||
var reactHooksModuleName = /* @__PURE__ */ Symbol();
|
||||
var reactHooksModule = ({
|
||||
batch = rrBatch,
|
||||
hooks = {
|
||||
useDispatch: rrUseDispatch,
|
||||
useSelector: rrUseSelector,
|
||||
useStore: rrUseStore
|
||||
},
|
||||
createSelector = _createSelector,
|
||||
unstable__sideEffectsInRender = false,
|
||||
...rest
|
||||
} = {}) => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const hookNames = ["useDispatch", "useSelector", "useStore"];
|
||||
let warned = false;
|
||||
for (const hookName of hookNames) {
|
||||
if (countObjectKeys(rest) > 0) {
|
||||
if (rest[hookName]) {
|
||||
if (!warned) {
|
||||
console.warn("As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
hooks[hookName] = rest[hookName];
|
||||
}
|
||||
if (typeof hooks[hookName] !== "function") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage4(36) : `When using custom hooks for context, all ${hookNames.length} hooks need to be provided: ${hookNames.join(", ")}.
|
||||
Hook ${hookName} was either not provided or not a function.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: reactHooksModuleName,
|
||||
init(api, {
|
||||
serializeQueryArgs
|
||||
}, context) {
|
||||
const anyApi = api;
|
||||
const {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
} = buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks,
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
});
|
||||
safeAssign(anyApi, {
|
||||
usePrefetch
|
||||
});
|
||||
safeAssign(context, {
|
||||
batch
|
||||
});
|
||||
return {
|
||||
injectEndpoint(endpointName, definition) {
|
||||
if (isQueryDefinition(definition)) {
|
||||
const {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
} = buildQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Query`] = useQuery;
|
||||
api[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
|
||||
}
|
||||
if (isMutationDefinition(definition)) {
|
||||
const useMutation = buildMutationHook(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useMutation
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Mutation`] = useMutation;
|
||||
} else if (isInfiniteQueryDefinition(definition)) {
|
||||
const {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
} = buildInfiniteQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
});
|
||||
api[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/query/react/index.ts
|
||||
export * from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/ApiProvider.tsx
|
||||
import { configureStore, formatProdErrorMessage as _formatProdErrorMessage5 } from "@reduxjs/toolkit";
|
||||
import * as React from "react";
|
||||
function ApiProvider(props) {
|
||||
const context = props.context || ReactReduxContext;
|
||||
const existingContext = useContext(context);
|
||||
if (existingContext) {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage5(35) : "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.");
|
||||
}
|
||||
const [store] = React.useState(() => configureStore({
|
||||
reducer: {
|
||||
[props.api.reducerPath]: props.api.reducer
|
||||
},
|
||||
middleware: (gDM) => gDM().concat(props.api.middleware)
|
||||
}));
|
||||
useEffect(() => props.setupListeners === false ? void 0 : setupListeners(store.dispatch, props.setupListeners), [props.setupListeners, store.dispatch]);
|
||||
return /* @__PURE__ */ React.createElement(Provider, { store, context }, props.children);
|
||||
}
|
||||
|
||||
// src/query/react/index.ts
|
||||
var createApi = /* @__PURE__ */ buildCreateApi(coreModule(), reactHooksModule());
|
||||
export {
|
||||
ApiProvider,
|
||||
UNINITIALIZED_VALUE,
|
||||
createApi,
|
||||
reactHooksModule,
|
||||
reactHooksModuleName
|
||||
};
|
||||
//# sourceMappingURL=rtk-query-react.modern.mjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3117
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js
generated
vendored
Normal file
3117
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3052
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs
generated
vendored
Normal file
3052
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
6
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./redux-toolkit-react.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./redux-toolkit-react.development.cjs')
|
||||
}
|
||||
55
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs
generated
vendored
Normal file
55
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/react/index.ts
|
||||
var react_exports = {};
|
||||
__export(react_exports, {
|
||||
createDynamicMiddleware: () => createDynamicMiddleware
|
||||
});
|
||||
module.exports = __toCommonJS(react_exports);
|
||||
__reExport(react_exports, require("@reduxjs/toolkit"), module.exports);
|
||||
|
||||
// src/dynamicMiddleware/react/index.ts
|
||||
var import_toolkit = require("@reduxjs/toolkit");
|
||||
var import_react_redux = require("react-redux");
|
||||
var createDynamicMiddleware = () => {
|
||||
const instance = (0, import_toolkit.createDynamicMiddleware)();
|
||||
const createDispatchWithMiddlewareHookFactory = (context = import_react_redux.ReactReduxContext) => {
|
||||
const useDispatch = context === import_react_redux.ReactReduxContext ? import_react_redux.useDispatch : (0, import_react_redux.createDispatchHook)(context);
|
||||
function createDispatchWithMiddlewareHook2(...middlewares) {
|
||||
instance.addMiddleware(...middlewares);
|
||||
return useDispatch;
|
||||
}
|
||||
createDispatchWithMiddlewareHook2.withTypes = () => createDispatchWithMiddlewareHook2;
|
||||
return createDispatchWithMiddlewareHook2;
|
||||
};
|
||||
const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();
|
||||
return {
|
||||
...instance,
|
||||
createDispatchWithMiddlewareHookFactory,
|
||||
createDispatchWithMiddlewareHook
|
||||
};
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
createDynamicMiddleware,
|
||||
...require("@reduxjs/toolkit")
|
||||
});
|
||||
//# sourceMappingURL=redux-toolkit-react.development.cjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["../../../src/react/index.ts","../../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,0BAAc,6BAHd;;;ACCA,qBAA+C;AAG/C,yBAAyF;AAYlF,IAAM,0BAA0B,MAAgJ;AACrL,QAAM,eAAW,eAAAA,yBAAyB;AAC1C,QAAM,0CAA0C,CAEhD,UAA2F,yCAAsB;AAC/G,UAAM,cAAc,YAAY,uCAAoB,mBAAAC,kBAAqB,uCAAmB,OAAO;AACnG,aAASC,qCAAgG,aAA0B;AACjI,eAAS,cAAc,GAAG,WAAW;AACrC,aAAO;AAAA,IACT;AACA,IAAAA,kCAAiC,YAAY,MAAMA;AACnD,WAAOA;AAAA,EACT;AACA,QAAM,mCAAmC,wCAAwC;AACjF,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AACF;","names":["cDM","useDefaultDispatch","createDispatchWithMiddlewareHook"]}
|
||||
2
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";var s=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var x=(t,e)=>{for(var a in e)s(t,a,{get:e[a],enumerable:!0})},d=(t,e,a,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of y(e))!M.call(t,i)&&i!==a&&s(t,i,{get:()=>e[i],enumerable:!(n=w(e,i))||n.enumerable});return t},r=(t,e,a)=>(d(t,e,"default"),a&&d(a,e,"default"));var m=t=>d(s({},"__esModule",{value:!0}),t);var o={};x(o,{createDynamicMiddleware:()=>D});module.exports=m(o);r(o,require("@reduxjs/toolkit"),module.exports);var h=require("@reduxjs/toolkit"),c=require("react-redux"),D=()=>{let t=(0,h.createDynamicMiddleware)(),e=(n=c.ReactReduxContext)=>{let i=n===c.ReactReduxContext?c.useDispatch:(0,c.createDispatchHook)(n);function p(...l){return t.addMiddleware(...l),i}return p.withTypes=()=>p,p},a=e();return{...t,createDispatchWithMiddlewareHookFactory:e,createDispatchWithMiddlewareHook:a}};0&&(module.exports={createDynamicMiddleware,...require("@reduxjs/toolkit")});
|
||||
//# sourceMappingURL=redux-toolkit-react.production.min.cjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["../../../src/react/index.ts","../../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":"2dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6BAAAE,IAAA,eAAAC,EAAAH,GAGAI,EAAAJ,EAAc,4BAHd,gBCCA,IAAAK,EAA+C,4BAG/CC,EAAyF,uBAY5EC,EAA0B,IAAgJ,CACrL,IAAMC,KAAW,EAAAC,yBAAyB,EACpCC,EAA0C,CAEhDC,EAA2F,sBAAsB,CAC/G,IAAMC,EAAcD,IAAY,oBAAoB,EAAAE,eAAqB,sBAAmBF,CAAO,EACnG,SAASG,KAAgGC,EAA0B,CACjI,OAAAP,EAAS,cAAc,GAAGO,CAAW,EAC9BH,CACT,CACA,OAAAE,EAAiC,UAAY,IAAMA,EAC5CA,CACT,EACMA,EAAmCJ,EAAwC,EACjF,MAAO,CACL,GAAGF,EACH,wCAAAE,EACA,iCAAAI,CACF,CACF","names":["react_exports","__export","createDynamicMiddleware","__toCommonJS","__reExport","import_toolkit","import_react_redux","createDynamicMiddleware","instance","cDM","createDispatchWithMiddlewareHookFactory","context","useDispatch","useDefaultDispatch","createDispatchWithMiddlewareHook","middlewares"]}
|
||||
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.mts
generated
vendored
Normal file
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.mts
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { TSHelpersExtractDispatchExtensions, MiddlewareApiConfig, GetState, GetDispatch, DynamicMiddlewareInstance } from '@reduxjs/toolkit';
|
||||
export * from '@reduxjs/toolkit';
|
||||
import { Context } from 'react';
|
||||
import { ReactReduxContextValue } from 'react-redux';
|
||||
import { Dispatch, UnknownAction, Middleware, Action } from 'redux';
|
||||
|
||||
type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;
|
||||
type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {
|
||||
<Middlewares extends [
|
||||
Middleware<any, State, DispatchType>,
|
||||
...Middleware<any, State, DispatchType>[]
|
||||
]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;
|
||||
withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;
|
||||
};
|
||||
type ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;
|
||||
type ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {
|
||||
createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
};
|
||||
declare const createDynamicMiddleware: <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>() => ReactDynamicMiddlewareInstance<State, DispatchType>;
|
||||
|
||||
export { type CreateDispatchWithMiddlewareHook, createDynamicMiddleware };
|
||||
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.ts
generated
vendored
Normal file
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { TSHelpersExtractDispatchExtensions, MiddlewareApiConfig, GetState, GetDispatch, DynamicMiddlewareInstance } from '@reduxjs/toolkit';
|
||||
export * from '@reduxjs/toolkit';
|
||||
import { Context } from 'react';
|
||||
import { ReactReduxContextValue } from 'react-redux';
|
||||
import { Dispatch, UnknownAction, Middleware, Action } from 'redux';
|
||||
|
||||
type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;
|
||||
type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {
|
||||
<Middlewares extends [
|
||||
Middleware<any, State, DispatchType>,
|
||||
...Middleware<any, State, DispatchType>[]
|
||||
]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;
|
||||
withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;
|
||||
};
|
||||
type ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;
|
||||
type ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {
|
||||
createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
};
|
||||
declare const createDynamicMiddleware: <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>() => ReactDynamicMiddlewareInstance<State, DispatchType>;
|
||||
|
||||
export { type CreateDispatchWithMiddlewareHook, createDynamicMiddleware };
|
||||
2
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.browser.mjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.browser.mjs
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export*from"@reduxjs/toolkit";import{createDynamicMiddleware as p}from"@reduxjs/toolkit";import{createDispatchHook as d,ReactReduxContext as c,useDispatch as s}from"react-redux";var h=()=>{let t=p(),a=(i=c)=>{let o=i===c?s:d(i);function e(...r){return t.addMiddleware(...r),o}return e.withTypes=()=>e,e},n=a();return{...t,createDispatchWithMiddlewareHookFactory:a,createDispatchWithMiddlewareHook:n}};export{h as createDynamicMiddleware};
|
||||
//# sourceMappingURL=redux-toolkit-react.browser.mjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.browser.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.browser.mjs.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["../../src/react/index.ts","../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":"AAGA,WAAc,mBCFd,OAAS,2BAA2BA,MAAW,mBAG/C,OAAS,sBAAAC,EAAoB,qBAAAC,EAAmB,eAAeC,MAA0B,cAYlF,IAAMC,EAA0B,IAAgJ,CACrL,IAAMC,EAAWL,EAAyB,EACpCM,EAA0C,CAEhDC,EAA2FL,IAAsB,CAC/G,IAAMM,EAAcD,IAAYL,EAAoBC,EAAqBF,EAAmBM,CAAO,EACnG,SAASE,KAAgGC,EAA0B,CACjI,OAAAL,EAAS,cAAc,GAAGK,CAAW,EAC9BF,CACT,CACA,OAAAC,EAAiC,UAAY,IAAMA,EAC5CA,CACT,EACMA,EAAmCH,EAAwC,EACjF,MAAO,CACL,GAAGD,EACH,wCAAAC,EACA,iCAAAG,CACF,CACF","names":["cDM","createDispatchHook","ReactReduxContext","useDefaultDispatch","createDynamicMiddleware","instance","createDispatchWithMiddlewareHookFactory","context","useDispatch","createDispatchWithMiddlewareHook","middlewares"]}
|
||||
47
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.legacy-esm.js
generated
vendored
Normal file
47
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.legacy-esm.js
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
var __defProp = Object.defineProperty;
|
||||
var __defProps = Object.defineProperties;
|
||||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
||||
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
var __spreadValues = (a, b) => {
|
||||
for (var prop in b || (b = {}))
|
||||
if (__hasOwnProp.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
if (__getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(b)) {
|
||||
if (__propIsEnum.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
||||
|
||||
// src/react/index.ts
|
||||
export * from "@reduxjs/toolkit";
|
||||
|
||||
// src/dynamicMiddleware/react/index.ts
|
||||
import { createDynamicMiddleware as cDM } from "@reduxjs/toolkit";
|
||||
import { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from "react-redux";
|
||||
var createDynamicMiddleware = () => {
|
||||
const instance = cDM();
|
||||
const createDispatchWithMiddlewareHookFactory = (context = ReactReduxContext) => {
|
||||
const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);
|
||||
function createDispatchWithMiddlewareHook2(...middlewares) {
|
||||
instance.addMiddleware(...middlewares);
|
||||
return useDispatch;
|
||||
}
|
||||
createDispatchWithMiddlewareHook2.withTypes = () => createDispatchWithMiddlewareHook2;
|
||||
return createDispatchWithMiddlewareHook2;
|
||||
};
|
||||
const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();
|
||||
return __spreadProps(__spreadValues({}, instance), {
|
||||
createDispatchWithMiddlewareHookFactory,
|
||||
createDispatchWithMiddlewareHook
|
||||
});
|
||||
};
|
||||
export {
|
||||
createDynamicMiddleware
|
||||
};
|
||||
//# sourceMappingURL=redux-toolkit-react.legacy-esm.js.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.legacy-esm.js.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["../../src/react/index.ts","../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAGA,cAAc;;;ACFd,SAAS,2BAA2B,WAAW;AAG/C,SAAS,oBAAoB,mBAAmB,eAAe,0BAA0B;AAYlF,IAAM,0BAA0B,MAAgJ;AACrL,QAAM,WAAW,IAAyB;AAC1C,QAAM,0CAA0C,CAEhD,UAA2F,sBAAsB;AAC/G,UAAM,cAAc,YAAY,oBAAoB,qBAAqB,mBAAmB,OAAO;AACnG,aAASA,qCAAgG,aAA0B;AACjI,eAAS,cAAc,GAAG,WAAW;AACrC,aAAO;AAAA,IACT;AACA,IAAAA,kCAAiC,YAAY,MAAMA;AACnD,WAAOA;AAAA,EACT;AACA,QAAM,mCAAmC,wCAAwC;AACjF,SAAO,iCACF,WADE;AAAA,IAEL;AAAA,IACA;AAAA,EACF;AACF;","names":["createDispatchWithMiddlewareHook"]}
|
||||
28
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.modern.mjs
generated
vendored
Normal file
28
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.modern.mjs
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// src/react/index.ts
|
||||
export * from "@reduxjs/toolkit";
|
||||
|
||||
// src/dynamicMiddleware/react/index.ts
|
||||
import { createDynamicMiddleware as cDM } from "@reduxjs/toolkit";
|
||||
import { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from "react-redux";
|
||||
var createDynamicMiddleware = () => {
|
||||
const instance = cDM();
|
||||
const createDispatchWithMiddlewareHookFactory = (context = ReactReduxContext) => {
|
||||
const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);
|
||||
function createDispatchWithMiddlewareHook2(...middlewares) {
|
||||
instance.addMiddleware(...middlewares);
|
||||
return useDispatch;
|
||||
}
|
||||
createDispatchWithMiddlewareHook2.withTypes = () => createDispatchWithMiddlewareHook2;
|
||||
return createDispatchWithMiddlewareHook2;
|
||||
};
|
||||
const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();
|
||||
return {
|
||||
...instance,
|
||||
createDispatchWithMiddlewareHookFactory,
|
||||
createDispatchWithMiddlewareHook
|
||||
};
|
||||
};
|
||||
export {
|
||||
createDynamicMiddleware
|
||||
};
|
||||
//# sourceMappingURL=redux-toolkit-react.modern.mjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.modern.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/redux-toolkit-react.modern.mjs.map
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["../../src/react/index.ts","../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":";AAGA,cAAc;;;ACFd,SAAS,2BAA2B,WAAW;AAG/C,SAAS,oBAAoB,mBAAmB,eAAe,0BAA0B;AAYlF,IAAM,0BAA0B,MAAgJ;AACrL,QAAM,WAAW,IAAyB;AAC1C,QAAM,0CAA0C,CAEhD,UAA2F,sBAAsB;AAC/G,UAAM,cAAc,YAAY,oBAAoB,qBAAqB,mBAAmB,OAAO;AACnG,aAASA,qCAAgG,aAA0B;AACjI,eAAS,cAAc,GAAG,WAAW;AACrC,aAAO;AAAA,IACT;AACA,IAAAA,kCAAiC,YAAY,MAAMA;AACnD,WAAOA;AAAA,EACT;AACA,QAAM,mCAAmC,wCAAwC;AACjF,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AACF;","names":["createDispatchWithMiddlewareHook"]}
|
||||
3
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs
generated
vendored
Normal file
3
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2351
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.legacy-esm.js
generated
vendored
Normal file
2351
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.legacy-esm.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.legacy-esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2330
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.modern.mjs
generated
vendored
Normal file
2330
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.modern.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.modern.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/redux-toolkit.modern.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
16
frontend/node_modules/@reduxjs/toolkit/dist/uncheckedindexed.ts
generated
vendored
Normal file
16
frontend/node_modules/@reduxjs/toolkit/dist/uncheckedindexed.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// inlined from https://github.com/EskiMojo14/uncheckedindexed
|
||||
// relies on remaining as a TS file, not .d.ts
|
||||
type IfMaybeUndefined<T, True, False> = [undefined] extends [T] ? True : False
|
||||
|
||||
const testAccess = ({} as Record<string, 0>)['a']
|
||||
|
||||
export type IfUncheckedIndexedAccess<True, False> = IfMaybeUndefined<
|
||||
typeof testAccess,
|
||||
True,
|
||||
False
|
||||
>
|
||||
|
||||
export type UncheckedIndexedAccess<T> = IfUncheckedIndexedAccess<
|
||||
T | undefined,
|
||||
T
|
||||
>
|
||||
285
frontend/node_modules/@reduxjs/toolkit/package.json
generated
vendored
Normal file
285
frontend/node_modules/@reduxjs/toolkit/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
{
|
||||
"name": "@reduxjs/toolkit",
|
||||
"version": "2.12.0",
|
||||
"description": "The official, opinionated, batteries-included toolset for efficient Redux development",
|
||||
"author": "Mark Erikson <mark@isquaredsoftware.com>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/reduxjs/redux-toolkit.git"
|
||||
},
|
||||
"keywords": [
|
||||
"redux",
|
||||
"react",
|
||||
"starter",
|
||||
"toolkit",
|
||||
"reducer",
|
||||
"slice",
|
||||
"immer",
|
||||
"immutable",
|
||||
"redux-toolkit",
|
||||
"tanstack-intent"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"module": "dist/redux-toolkit.legacy-esm.js",
|
||||
"main": "dist/cjs/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"react-native": "dist/redux-toolkit.legacy-esm.js",
|
||||
"unpkg": "dist/redux-toolkit.browser.mjs",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"module-sync": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/redux-toolkit.modern.mjs"
|
||||
},
|
||||
"module": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/redux-toolkit.modern.mjs"
|
||||
},
|
||||
"react-native": {
|
||||
"import": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/redux-toolkit.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"import": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/redux-toolkit.browser.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"default": "./dist/redux-toolkit.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"./react": {
|
||||
"module-sync": {
|
||||
"types": "./dist/react/index.d.mts",
|
||||
"default": "./dist/react/redux-toolkit-react.modern.mjs"
|
||||
},
|
||||
"module": {
|
||||
"types": "./dist/react/index.d.mts",
|
||||
"default": "./dist/react/redux-toolkit-react.modern.mjs"
|
||||
},
|
||||
"react-native": {
|
||||
"import": {
|
||||
"types": "./dist/react/index.d.mts",
|
||||
"default": "./dist/react/redux-toolkit-react.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/react/index.d.ts",
|
||||
"default": "./dist/react/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"import": {
|
||||
"types": "./dist/react/index.d.mts",
|
||||
"default": "./dist/react/redux-toolkit-react.browser.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/react/index.d.ts",
|
||||
"default": "./dist/react/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/react/index.d.mts",
|
||||
"default": "./dist/react/redux-toolkit-react.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/react/index.d.ts",
|
||||
"default": "./dist/react/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"./query": {
|
||||
"module-sync": {
|
||||
"types": "./dist/query/index.d.mts",
|
||||
"default": "./dist/query/rtk-query.modern.mjs"
|
||||
},
|
||||
"module": {
|
||||
"types": "./dist/query/index.d.mts",
|
||||
"default": "./dist/query/rtk-query.modern.mjs"
|
||||
},
|
||||
"react-native": {
|
||||
"import": {
|
||||
"types": "./dist/query/index.d.mts",
|
||||
"default": "./dist/query/rtk-query.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/query/index.d.ts",
|
||||
"default": "./dist/query/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"import": {
|
||||
"types": "./dist/query/index.d.mts",
|
||||
"default": "./dist/query/rtk-query.browser.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/query/index.d.ts",
|
||||
"default": "./dist/query/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/query/index.d.mts",
|
||||
"default": "./dist/query/rtk-query.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/query/index.d.ts",
|
||||
"default": "./dist/query/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"./query/react": {
|
||||
"module-sync": {
|
||||
"types": "./dist/query/react/index.d.mts",
|
||||
"default": "./dist/query/react/rtk-query-react.modern.mjs"
|
||||
},
|
||||
"module": {
|
||||
"types": "./dist/query/react/index.d.mts",
|
||||
"default": "./dist/query/react/rtk-query-react.modern.mjs"
|
||||
},
|
||||
"react-native": {
|
||||
"import": {
|
||||
"types": "./dist/query/react/index.d.mts",
|
||||
"default": "./dist/query/react/rtk-query-react.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/query/react/index.d.ts",
|
||||
"default": "./dist/query/react/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"import": {
|
||||
"types": "./dist/query/react/index.d.mts",
|
||||
"default": "./dist/query/react/rtk-query-react.browser.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/query/react/index.d.ts",
|
||||
"default": "./dist/query/react/cjs/index.js"
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/query/react/index.d.mts",
|
||||
"default": "./dist/query/react/rtk-query-react.modern.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/query/react/index.d.ts",
|
||||
"default": "./dist/query/react/cjs/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.18.2",
|
||||
"@babel/core": "^7.24.8",
|
||||
"@babel/helper-module-imports": "^7.24.7",
|
||||
"@microsoft/api-extractor": "^7.13.2",
|
||||
"@phryneas/ts-version": "^1.0.2",
|
||||
"@size-limit/file": "^11.0.1",
|
||||
"@size-limit/webpack": "^11.0.1",
|
||||
"@tanstack/intent": "^0.0.19",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/react": "^16.0.1",
|
||||
"@testing-library/react-render-stream": "^1.0.3",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/babel__helper-module-imports": "^7.18.3",
|
||||
"@types/node": "^25.5.0",
|
||||
"@types/query-string": "^6.3.0",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6",
|
||||
"@typescript-eslint/parser": "^6",
|
||||
"axios": "^0.19.2",
|
||||
"esbuild": "^0.25.1",
|
||||
"esbuild-extra": "^0.4.0",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-flowtype": "^5.7.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"msw": "^2.1.4",
|
||||
"node-fetch": "^3.3.2",
|
||||
"prettier": "^3.2.5",
|
||||
"query-string": "^7.0.1",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"rimraf": "^6.1.3",
|
||||
"size-limit": "^11.0.1",
|
||||
"tsup": "^8.4.0",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.9.3",
|
||||
"valibot": "^1.0.0",
|
||||
"vite-tsconfig-paths": "^4.3.1",
|
||||
"vitest": "^4"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"run-build": "tsup --config=$INIT_CWD/tsup.config.mts",
|
||||
"build": "yarn clean && yarn run-build && tsx scripts/fixUniqueSymbolExports.mts",
|
||||
"build-only": "yarn clean && yarn run-build",
|
||||
"format": "prettier --write \"(src|examples)/**/*.{ts,tsx}\" \"**/*.md\"",
|
||||
"format:check": "prettier --list-different \"(src|examples)/**/*.{ts,tsx}\" \"docs/*/**.md\"",
|
||||
"lint": "eslint src examples",
|
||||
"test": "vitest --typecheck --run ",
|
||||
"test:watch": "vitest --watch",
|
||||
"type-tests": "yarn tsc -p tsconfig.test.json --noEmit",
|
||||
"prepack": "yarn build",
|
||||
"size": "size-limit"
|
||||
},
|
||||
"files": [
|
||||
"dist/",
|
||||
"src/",
|
||||
"!src/**/tests/**",
|
||||
"!src/**/*.{test,spec}(-d)?.(c|m)[tj]sx?",
|
||||
"query",
|
||||
"react",
|
||||
"skills",
|
||||
"!skills/_artifacts"
|
||||
],
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@standard-schema/utils": "^0.3.0",
|
||||
"immer": "^11.0.0",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
|
||||
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"bugs": {
|
||||
"url": "https://github.com/reduxjs/redux-toolkit/issues"
|
||||
},
|
||||
"homepage": "https://redux-toolkit.js.org"
|
||||
}
|
||||
13
frontend/node_modules/@reduxjs/toolkit/query/package.json
generated
vendored
Normal file
13
frontend/node_modules/@reduxjs/toolkit/query/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@reduxjs/toolkit-query",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"module": "../dist/query/rtk-query.legacy-esm.js",
|
||||
"main": "../dist/query/cjs/index.js",
|
||||
"types": "./../dist/query/index.d.ts",
|
||||
"react-native": "./../dist/query/rtk-query.legacy-esm.js",
|
||||
"author": "Mark Erikson <mark@isquaredsoftware.com>",
|
||||
"license": "MIT",
|
||||
"sideEffects": false
|
||||
}
|
||||
13
frontend/node_modules/@reduxjs/toolkit/query/react/package.json
generated
vendored
Normal file
13
frontend/node_modules/@reduxjs/toolkit/query/react/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@reduxjs/toolkit-query-react",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"module": "../../dist/query/react/rtk-query-react.legacy-esm.js",
|
||||
"main": "../../dist/query/react/cjs/index.js",
|
||||
"types": "./../../dist/query/react/index.d.ts",
|
||||
"react-native": "./../../dist/query/react/rtk-query-react.legacy-esm.js",
|
||||
"author": "Mark Erikson <mark@isquaredsoftware.com>",
|
||||
"license": "MIT",
|
||||
"sideEffects": false
|
||||
}
|
||||
13
frontend/node_modules/@reduxjs/toolkit/react/package.json
generated
vendored
Normal file
13
frontend/node_modules/@reduxjs/toolkit/react/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@reduxjs/toolkit-react",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"module": "../dist/react/redux-toolkit-react.legacy-esm.js",
|
||||
"main": "./../dist/react/redux-toolkit-react.modern.mjs",
|
||||
"types": "./../dist/react/index.d.ts",
|
||||
"react-native": "./../dist/react/redux-toolkit-react.modern.mjs",
|
||||
"author": "Mark Erikson <mark@isquaredsoftware.com>",
|
||||
"license": "MIT",
|
||||
"sideEffects": false
|
||||
}
|
||||
304
frontend/node_modules/@reduxjs/toolkit/skills/build-modern-redux-apps/modern-redux/SKILL.md
generated
vendored
Normal file
304
frontend/node_modules/@reduxjs/toolkit/skills/build-modern-redux-apps/modern-redux/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
---
|
||||
name: build-modern-redux-apps/modern-redux
|
||||
description: >
|
||||
Use this when setting up a new Redux Toolkit app or modernizing an existing
|
||||
React + Redux codebase. Covers configureStore, Provider wiring, typed hooks,
|
||||
hooks-first React-Redux usage, feature folders, and the correct store lifetime
|
||||
for SPA and SSR-heavy React environments.
|
||||
type: lifecycle
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
requires:
|
||||
- build-modern-redux-apps/redux-dataflow
|
||||
sources:
|
||||
- "reduxjs/redux-toolkit:docs/tutorials/quick-start.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/tutorials/typescript.md"
|
||||
- "reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/usage/nextjs.mdx"
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
---
|
||||
|
||||
# Modern Redux
|
||||
|
||||
## Setup
|
||||
|
||||
```tsx
|
||||
// file: src/features/counter/counterSlice.ts
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
export const counterSlice = createSlice({
|
||||
name: 'counter',
|
||||
initialState: { value: 0 },
|
||||
reducers: {
|
||||
increment(state) {
|
||||
state.value += 1
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const { increment } = counterSlice.actions
|
||||
|
||||
// file: src/app/store.ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { counterSlice } from '../features/counter/counterSlice'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
counter: counterSlice.reducer,
|
||||
},
|
||||
})
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>
|
||||
export type AppDispatch = typeof store.dispatch
|
||||
|
||||
// file: src/app/hooks.ts
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import type { AppDispatch, RootState } from './store'
|
||||
|
||||
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
|
||||
export const useAppSelector = useSelector.withTypes<RootState>()
|
||||
|
||||
// file: src/features/counter/Counter.tsx
|
||||
import { increment } from './counterSlice'
|
||||
import { useAppDispatch, useAppSelector } from '../../app/hooks'
|
||||
|
||||
export function Counter() {
|
||||
const value = useAppSelector((state) => state.counter.value)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return <button onClick={() => dispatch(increment())}>{value}</button>
|
||||
}
|
||||
|
||||
// file: src/main.tsx
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { Provider } from 'react-redux'
|
||||
import { store } from './app/store'
|
||||
import { Counter } from './features/counter/Counter'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<Provider store={store}>
|
||||
<Counter />
|
||||
</Provider>,
|
||||
)
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Keep React components on hooks, not wrappers
|
||||
|
||||
```tsx
|
||||
import { postAdded, selectPosts } from './postsSlice'
|
||||
import { useAppDispatch, useAppSelector } from '../../app/hooks'
|
||||
|
||||
export function PostsList() {
|
||||
const posts = useAppSelector(selectPosts)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() =>
|
||||
dispatch(postAdded({ id: 'p2', title: 'Write docs' }))
|
||||
}
|
||||
>
|
||||
{posts.length}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Hooks are the default React-Redux integration for new code.
|
||||
|
||||
### Create the store inside the provider for SSR-heavy React apps
|
||||
|
||||
```tsx
|
||||
// file: src/lib/store.ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { counterSlice } from '../features/counter/counterSlice'
|
||||
|
||||
export const makeStore = () =>
|
||||
configureStore({
|
||||
reducer: {
|
||||
counter: counterSlice.reducer,
|
||||
},
|
||||
})
|
||||
|
||||
export type AppStore = ReturnType<typeof makeStore>
|
||||
export type RootState = ReturnType<AppStore['getState']>
|
||||
export type AppDispatch = AppStore['dispatch']
|
||||
|
||||
// file: src/app/StoreProvider.tsx
|
||||
'use client'
|
||||
|
||||
import { useState, type ReactNode } from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import { makeStore } from '../lib/store'
|
||||
|
||||
export function StoreProvider({ children }: { children: ReactNode }) {
|
||||
const [store] = useState(makeStore)
|
||||
|
||||
return <Provider store={store}>{children}</Provider>
|
||||
}
|
||||
```
|
||||
|
||||
In SSR-heavy React frameworks, create a store per request and keep that instance stable across renders.
|
||||
|
||||
### Keep app wiring in `app/` and feature logic in feature folders
|
||||
|
||||
```text
|
||||
src/
|
||||
app/
|
||||
store.ts
|
||||
hooks.ts
|
||||
features/
|
||||
posts/
|
||||
postsSlice.ts
|
||||
PostsList.tsx
|
||||
users/
|
||||
usersSlice.ts
|
||||
UsersList.tsx
|
||||
```
|
||||
|
||||
This keeps store wiring centralized and feature logic colocated.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### HIGH Importing the store in React components
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { store } from '../../app/store'
|
||||
|
||||
export function PostsList() {
|
||||
const posts = store.getState().posts
|
||||
return <div>{posts.length}</div>
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
import { useAppSelector } from '../../app/hooks'
|
||||
|
||||
export function PostsList() {
|
||||
const posts = useAppSelector((state) => state.posts)
|
||||
return <div>{posts.length}</div>
|
||||
}
|
||||
```
|
||||
|
||||
React components should read through context and hooks; direct store imports are a separate escape hatch for non-React integrations, not the default UI pattern.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### HIGH Defaulting to `connect()` in new React code
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
const increment = () => ({ type: 'counter/increment' as const })
|
||||
const mapState = (state: { counter: { value: number } }) => ({
|
||||
value: state.counter.value,
|
||||
})
|
||||
const mapDispatch = { increment }
|
||||
|
||||
function Counter({ value, increment }: ReturnType<typeof mapState> & typeof mapDispatch) {
|
||||
return <button onClick={() => increment()}>{value}</button>
|
||||
}
|
||||
|
||||
export default connect(mapState, mapDispatch)(Counter)
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
import { increment } from './counterSlice'
|
||||
import { useAppDispatch, useAppSelector } from '../../app/hooks'
|
||||
|
||||
export function Counter() {
|
||||
const value = useAppSelector((state) => state.counter.value)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return <button onClick={() => dispatch(increment())}>{value}</button>
|
||||
}
|
||||
```
|
||||
|
||||
Hooks are the modern default, simpler to type, and the maintainers explicitly want agents to steer new code away from `connect`.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx
|
||||
|
||||
### HIGH Recreating the store during render in SSR-heavy apps
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { makeStore } from '../lib/store'
|
||||
|
||||
export function StoreProvider({ children }: { children: import('react').ReactNode }) {
|
||||
const store = makeStore()
|
||||
return <Provider store={store}>{children}</Provider>
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import { makeStore } from '../lib/store'
|
||||
|
||||
export function StoreProvider({ children }: { children: import('react').ReactNode }) {
|
||||
const [store] = useState(makeStore)
|
||||
return <Provider store={store}>{children}</Provider>
|
||||
}
|
||||
```
|
||||
|
||||
A new store on every render loses client state, while a module singleton can leak across requests on the server.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/nextjs.mdx
|
||||
|
||||
### HIGH Keeping `createStore` boilerplate as the default
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { applyMiddleware, combineReducers, createStore } from 'redux'
|
||||
import thunk from 'redux-thunk'
|
||||
|
||||
const counterReducer = (state = { value: 0 }) => state
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
counter: counterReducer,
|
||||
})
|
||||
|
||||
export const store = createStore(rootReducer, applyMiddleware(thunk))
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
|
||||
const counterReducer = (state = { value: 0 }) => state
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
counter: counterReducer,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Manual store setup works, but it throws away RTK's default middleware, dev checks, and the current recommended baseline.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx
|
||||
|
||||
## References
|
||||
|
||||
- [Store lifetime and framework boundaries](references/store-lifetime.md)
|
||||
53
frontend/node_modules/@reduxjs/toolkit/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md
generated
vendored
Normal file
53
frontend/node_modules/@reduxjs/toolkit/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Store Lifetime
|
||||
|
||||
## Decision table
|
||||
|
||||
| Environment | Default store shape | Why |
|
||||
| --- | --- | --- |
|
||||
| Client-only SPA | One module-level singleton store | There is one browser session and no cross-request leakage risk. |
|
||||
| SSR-heavy React app | `makeStore()` plus provider-local state | Each request needs its own store instance, but that instance must stay stable across client renders. |
|
||||
| Non-React integration code | Direct store access can be acceptable | This is outside the React context boundary and should stay out of UI components. |
|
||||
|
||||
## SPA pattern
|
||||
|
||||
```ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { postsSlice } from '../features/posts/postsSlice'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
posts: postsSlice.reducer,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Use this for classic browser SPAs.
|
||||
|
||||
## SSR-heavy React pattern
|
||||
|
||||
```tsx
|
||||
// file: src/lib/store.ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { postsSlice } from '../features/posts/postsSlice'
|
||||
|
||||
export const makeStore = () =>
|
||||
configureStore({
|
||||
reducer: {
|
||||
posts: postsSlice.reducer,
|
||||
},
|
||||
})
|
||||
|
||||
// file: src/app/StoreProvider.tsx
|
||||
'use client'
|
||||
|
||||
import { useState, type ReactNode } from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import { makeStore } from '../lib/store'
|
||||
|
||||
export function StoreProvider({ children }: { children: ReactNode }) {
|
||||
const [store] = useState(makeStore)
|
||||
return <Provider store={store}>{children}</Provider>
|
||||
}
|
||||
```
|
||||
|
||||
Create the store per request, then keep it stable inside the provider component.
|
||||
264
frontend/node_modules/@reduxjs/toolkit/skills/build-modern-redux-apps/redux-dataflow/SKILL.md
generated
vendored
Normal file
264
frontend/node_modules/@reduxjs/toolkit/skills/build-modern-redux-apps/redux-dataflow/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
---
|
||||
name: build-modern-redux-apps/redux-dataflow
|
||||
description: >
|
||||
Use this when you need the Redux event -> reducer -> selector -> render loop,
|
||||
event-style actions, reducer-owned state transitions, derived data, or a
|
||||
debugging model for Redux Toolkit apps.
|
||||
type: core
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
sources:
|
||||
- "reduxjs/redux:docs/tutorials/fundamentals/part-2-concepts-data-flow.md"
|
||||
- "reduxjs/redux:docs/tutorials/essentials/part-3-data-flow.md"
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
---
|
||||
|
||||
# Redux Dataflow
|
||||
|
||||
## Setup
|
||||
|
||||
```ts
|
||||
import { configureStore, createSelector, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: {
|
||||
items: [] as { id: string; title: string; published: boolean }[],
|
||||
filter: 'all' as 'all' | 'published',
|
||||
},
|
||||
reducers: {
|
||||
postAdded(state, action: { payload: { id: string; title: string } }) {
|
||||
state.items.push({ ...action.payload, published: false })
|
||||
},
|
||||
postPublished(state, action: { payload: { id: string } }) {
|
||||
const post = state.items.find((item) => item.id === action.payload.id)
|
||||
if (post) {
|
||||
post.published = true
|
||||
}
|
||||
},
|
||||
filterChanged(state, action: { payload: 'all' | 'published' }) {
|
||||
state.filter = action.payload
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
posts: postsSlice.reducer,
|
||||
},
|
||||
})
|
||||
|
||||
type RootState = ReturnType<typeof store.getState>
|
||||
|
||||
const selectPostsState = (state: RootState) => state.posts
|
||||
const selectVisiblePosts = createSelector([selectPostsState], (postsState) =>
|
||||
postsState.filter === 'all'
|
||||
? postsState.items
|
||||
: postsState.items.filter((post) => post.published),
|
||||
)
|
||||
|
||||
store.dispatch(postsSlice.actions.postAdded({ id: 'p1', title: 'Draft' }))
|
||||
store.dispatch(postsSlice.actions.postPublished({ id: 'p1' }))
|
||||
|
||||
const visiblePosts = selectVisiblePosts(store.getState())
|
||||
console.log(visiblePosts)
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Dispatch events, not setters
|
||||
|
||||
```ts
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: [] as { id: string; title: string }[],
|
||||
reducers: {
|
||||
postAdded(state, action: { payload: { id: string; title: string } }) {
|
||||
state.push(action.payload)
|
||||
},
|
||||
postRemoved(state, action: { payload: { id: string } }) {
|
||||
return state.filter((post) => post.id !== action.payload.id)
|
||||
},
|
||||
postUpdated(
|
||||
state,
|
||||
action: { payload: { id: string; changes: Partial<{ title: string }> } },
|
||||
) {
|
||||
const post = state.find((item) => item.id === action.payload.id)
|
||||
if (post && action.payload.changes.title) {
|
||||
post.title = action.payload.changes.title
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
postsSlice.actions.postAdded({ id: 'p1', title: 'Draft' })
|
||||
```
|
||||
|
||||
Event-style actions explain what happened in the UI instead of hiding the transition behind a generic setter.
|
||||
|
||||
### Let reducers combine old store data with new outside data
|
||||
|
||||
```ts
|
||||
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const postsAdapter = createEntityAdapter<{ id: string; title: string }>()
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: postsAdapter.getInitialState(),
|
||||
reducers: {
|
||||
postsReceived(state, action: { payload: { id: string; title: string }[] }) {
|
||||
postsAdapter.upsertMany(state, action.payload)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const incomingPosts = [
|
||||
{ id: 'p1', title: 'Draft' },
|
||||
{ id: 'p2', title: 'Published' },
|
||||
]
|
||||
|
||||
postsSlice.actions.postsReceived(incomingPosts)
|
||||
```
|
||||
|
||||
If a transition mixes current store state with new external data, dispatch the new external data and let the reducer own the merge.
|
||||
|
||||
### Derive values with selectors instead of storing duplicates
|
||||
|
||||
```ts
|
||||
import { createSelector } from '@reduxjs/toolkit'
|
||||
|
||||
const selectPosts = (state: RootState) => state.posts.items
|
||||
const selectFilter = (state: RootState) => state.posts.filter
|
||||
|
||||
export const selectVisiblePosts = createSelector(
|
||||
[selectPosts, selectFilter],
|
||||
(posts, filter) =>
|
||||
filter === 'all'
|
||||
? posts
|
||||
: posts.filter((post) => post.published),
|
||||
)
|
||||
```
|
||||
|
||||
Selectors keep a single source of truth in state while still exposing the shapes the UI needs.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### CRITICAL Mutating selected state outside reducers
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const post = selectPostById(store.getState(), 'p1')
|
||||
|
||||
if (post) {
|
||||
post.title = 'Changed in place'
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
store.dispatch(postUpdated({ id: 'p1', changes: { title: 'Changed in place' } }))
|
||||
```
|
||||
|
||||
Objects read from the store are still store state; mutating them outside reducers breaks immutability and stale-render assumptions.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### HIGH Using setter-style actions instead of event-style actions
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const nextPosts = [...selectPosts(store.getState()), { id: 'p2', title: 'Write docs' }]
|
||||
store.dispatch(setPosts(nextPosts))
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
store.dispatch(postAdded({ id: 'p2', title: 'Write docs' }))
|
||||
```
|
||||
|
||||
Actions should describe events, not ask reducers to blindly replace state with a precomputed value.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### HIGH Combining store state before dispatch
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const currentPosts = selectPosts(store.getState())
|
||||
const mergedPosts = [
|
||||
...currentPosts.filter(
|
||||
(currentPost) =>
|
||||
!incomingPosts.some((incomingPost) => incomingPost.id === currentPost.id),
|
||||
),
|
||||
...incomingPosts,
|
||||
]
|
||||
|
||||
store.dispatch(postsReplaced(mergedPosts))
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
store.dispatch(postsReceived(incomingPosts))
|
||||
```
|
||||
|
||||
If the next state depends on current store state, the reducer should own that combination logic; only authoritative external snapshots should replace state wholesale.
|
||||
|
||||
Source: maintainer interview
|
||||
|
||||
### HIGH Ignoring current state in async reducers
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
builder.addCase(fetchPosts.fulfilled, (state, action) => {
|
||||
state.status = 'succeeded'
|
||||
state.items = action.payload
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
builder.addCase(fetchPosts.fulfilled, (state, action) => {
|
||||
if (state.status === 'pending') {
|
||||
state.status = 'succeeded'
|
||||
state.items = action.payload
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Reducers that treat every lifecycle action as valid can move the slice into impossible states or let stale requests win.
|
||||
|
||||
Source: reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md
|
||||
|
||||
### MEDIUM Storing derived values in state
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const initialState = {
|
||||
items: [] as Post[],
|
||||
visiblePosts: [] as Post[],
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
const selectVisiblePosts = createSelector(
|
||||
[selectPosts, selectFilter],
|
||||
(posts, filter) =>
|
||||
filter === 'all' ? posts : posts.filter((post) => post.published),
|
||||
)
|
||||
```
|
||||
|
||||
Derived values drift out of sync quickly; keep the raw state and derive the view shape.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
269
frontend/node_modules/@reduxjs/toolkit/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md
generated
vendored
Normal file
269
frontend/node_modules/@reduxjs/toolkit/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
---
|
||||
name: evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps
|
||||
description: >
|
||||
Use this when debugging duplicate requests, stale cache behavior, broad
|
||||
subscriptions, selector churn, serializability warnings, or other Redux
|
||||
Toolkit and RTK Query bugs. Covers a practical event -> reducer -> selector ->
|
||||
render debugging loop plus RTK Query cache interpretation.
|
||||
type: lifecycle
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
requires:
|
||||
- build-modern-redux-apps/redux-dataflow
|
||||
sources:
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
- "reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md"
|
||||
- "reduxjs/redux:docs/tutorials/essentials/part-8-rtk-query-advanced.md"
|
||||
- "reduxjs/redux-toolkit:docs/usage/usage-guide.md"
|
||||
---
|
||||
|
||||
# Debug Redux Toolkit Apps
|
||||
|
||||
## Setup
|
||||
|
||||
```ts
|
||||
import { configureStore, createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
export const fetchPosts = createAsyncThunk(
|
||||
'posts/fetchPosts',
|
||||
async () => {
|
||||
const response = await fetch('/api/posts')
|
||||
return (await response.json()) as Post[]
|
||||
},
|
||||
{
|
||||
condition(_arg, { getState }) {
|
||||
const state = getState() as RootState
|
||||
return state.posts.status === 'idle'
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: {
|
||||
items: [] as Post[],
|
||||
status: 'idle' as 'idle' | 'pending' | 'succeeded' | 'failed',
|
||||
},
|
||||
reducers: {},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(fetchPosts.pending, (state) => {
|
||||
state.status = 'pending'
|
||||
})
|
||||
.addCase(fetchPosts.fulfilled, (state, action) => {
|
||||
state.status = 'succeeded'
|
||||
state.items = action.payload
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
posts: postsSlice.reducer,
|
||||
},
|
||||
})
|
||||
|
||||
type RootState = ReturnType<typeof store.getState>
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Debug in order: action -> reducer -> selector -> render
|
||||
|
||||
```ts
|
||||
const selectPosts = (state: RootState) => state.posts.items
|
||||
const selectPostsStatus = (state: RootState) => state.posts.status
|
||||
|
||||
store.dispatch(fetchPosts())
|
||||
|
||||
console.log(selectPostsStatus(store.getState()))
|
||||
console.log(selectPosts(store.getState()))
|
||||
```
|
||||
|
||||
If a component looks wrong, first verify the action fired, then the reducer state, then the selector result, then the render boundary.
|
||||
|
||||
### Narrow subscriptions at the usage site
|
||||
|
||||
```tsx
|
||||
import { useAppSelector } from '../../app/hooks'
|
||||
|
||||
export function PostsList() {
|
||||
const posts = useAppSelector((state) => state.posts.items)
|
||||
const status = useAppSelector((state) => state.posts.status)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{status}</div>
|
||||
<div>{posts.length}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
React-Redux behaves best when components select only the values they render and do it as close to usage as possible.
|
||||
|
||||
### Interpret RTK Query invalidation correctly
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
tagTypes: ['Post'],
|
||||
endpoints: (build) => ({
|
||||
getPosts: build.query<Post[], void>({
|
||||
query: () => 'posts',
|
||||
providesTags: ['Post'],
|
||||
}),
|
||||
updatePost: build.mutation<Post, Pick<Post, 'id' | 'title'>>({
|
||||
query: ({ id, title }) => ({
|
||||
url: `posts/${id}`,
|
||||
method: 'PATCH',
|
||||
body: { title },
|
||||
}),
|
||||
invalidatesTags: ['Post'],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
If invalidation did not visibly refetch, check whether anything was still subscribed to that cache entry.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### HIGH Dispatching fetch thunks from effects without a thunk-level guard
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { useEffect } from 'react'
|
||||
import { useAppDispatch, useAppSelector } from '../../app/hooks'
|
||||
|
||||
function PostsPage() {
|
||||
const dispatch = useAppDispatch()
|
||||
const postStatus = useAppSelector((state) => state.posts.status)
|
||||
|
||||
useEffect(() => {
|
||||
if (postStatus === 'idle') {
|
||||
dispatch(fetchPosts())
|
||||
}
|
||||
}, [dispatch, postStatus])
|
||||
|
||||
return null
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
export const fetchPosts = createAsyncThunk(
|
||||
'posts/fetchPosts',
|
||||
async () => {
|
||||
const response = await fetch('/api/posts')
|
||||
return (await response.json()) as Post[]
|
||||
},
|
||||
{
|
||||
condition(_arg, { getState }) {
|
||||
const state = getState() as RootState
|
||||
return state.posts.status === 'idle'
|
||||
},
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
React StrictMode can run effects twice in development, so the guard belongs in the thunk as well as the component.
|
||||
|
||||
Source: reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md
|
||||
|
||||
### HIGH Ignoring serializable-state warnings
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const initialState = {
|
||||
lastSeen: new Date(),
|
||||
pendingIds: new Set<string>(),
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
const initialState = {
|
||||
lastSeenIso: new Date().toISOString(),
|
||||
pendingIds: [] as string[],
|
||||
}
|
||||
```
|
||||
|
||||
Non-serializable values break DevTools, replay, persistence, and equality assumptions in subtle ways.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### HIGH Selecting broad state in parents and threading props
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { useAppSelector } from '../../app/hooks'
|
||||
|
||||
function PostsPage() {
|
||||
const postsState = useAppSelector((state) => state.posts)
|
||||
return <PostsList items={postsState.items} status={postsState.status} />
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
import { useAppSelector } from '../../app/hooks'
|
||||
|
||||
function PostsList() {
|
||||
const items = useAppSelector((state) => state.posts.items)
|
||||
const status = useAppSelector((state) => state.posts.status)
|
||||
return (
|
||||
<div>
|
||||
<div>{status}</div>
|
||||
<div>{items.length}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Selecting whole slices high in the tree widens the subscription surface and pushes rerenders through props.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### MEDIUM Returning unstable objects from query selection logic
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { api } from '../../services/api'
|
||||
|
||||
const result = api.useGetPostsQuery(undefined, {
|
||||
selectFromResult: ({ data = [] }) => ({
|
||||
posts: [...data],
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
import { api } from '../../services/api'
|
||||
|
||||
const result = api.useGetPostsQuery(undefined, {
|
||||
selectFromResult: ({ data = [] }) => ({
|
||||
posts: data,
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
New object and array references defeat memoization and make components rerender even when the underlying cached data did not change.
|
||||
|
||||
Source: reduxjs/redux:docs/tutorials/essentials/part-8-rtk-query-advanced.md
|
||||
226
frontend/node_modules/@reduxjs/toolkit/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md
generated
vendored
Normal file
226
frontend/node_modules/@reduxjs/toolkit/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
---
|
||||
name: evolve-and-diagnose-redux-apps/migrate-to-modern-redux
|
||||
description: >
|
||||
Use this when moving a legacy Redux codebase to current RTK patterns. Covers
|
||||
replacing createStore with configureStore, migrating touched reducers to
|
||||
createSlice, codemod-assisted RTK 2 updates, and replacing server-data stacks
|
||||
with RTK Query instead of writing new legacy Redux code.
|
||||
type: lifecycle
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
requires:
|
||||
- build-modern-redux-apps/modern-redux
|
||||
sources:
|
||||
- "reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md"
|
||||
- "reduxjs/redux-toolkit:packages/rtk-codemods/README.md"
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
---
|
||||
|
||||
# Migrate To Modern Redux
|
||||
|
||||
## Setup
|
||||
|
||||
```ts
|
||||
// before
|
||||
import { applyMiddleware, combineReducers, createStore } from 'redux'
|
||||
import thunk from 'redux-thunk'
|
||||
|
||||
const postsReducer = (state = [] as { id: string; title: string }[]) => state
|
||||
const usersReducer = (state = [] as { id: string; name: string }[]) => state
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
posts: postsReducer,
|
||||
users: usersReducer,
|
||||
})
|
||||
|
||||
export const legacyStore = createStore(rootReducer, applyMiddleware(thunk))
|
||||
|
||||
// after
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
|
||||
const postsReducer = (state = [] as { id: string; title: string }[]) => state
|
||||
const usersReducer = (state = [] as { id: string; name: string }[]) => state
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
posts: postsReducer,
|
||||
users: usersReducer,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Replace the store setup first
|
||||
|
||||
```ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
|
||||
const postsReducer = (state = [] as { id: string; title: string }[]) => state
|
||||
const usersReducer = (state = [] as { id: string; name: string }[]) => state
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
posts: postsReducer,
|
||||
users: usersReducer,
|
||||
},
|
||||
})
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>
|
||||
export type AppDispatch = typeof store.dispatch
|
||||
```
|
||||
|
||||
This is the one migration step that can happen immediately while old reducers continue to work.
|
||||
|
||||
### Migrate reducers as you touch them
|
||||
|
||||
```ts
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
type TodosState = {
|
||||
items: { id: string; text: string; completed: boolean }[]
|
||||
}
|
||||
|
||||
const initialState: TodosState = {
|
||||
items: [],
|
||||
}
|
||||
|
||||
export const todosSlice = createSlice({
|
||||
name: 'todos',
|
||||
initialState,
|
||||
reducers: {
|
||||
todoAdded(state, action: { payload: { id: string; text: string } }) {
|
||||
state.items.push({ ...action.payload, completed: false })
|
||||
},
|
||||
todoToggled(state, action: { payload: { id: string } }) {
|
||||
const todo = state.items.find((item) => item.id === action.payload.id)
|
||||
if (todo) {
|
||||
todo.completed = !todo.completed
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Once a reducer needs editing, migrate that reducer instead of adding more legacy code to it.
|
||||
|
||||
### Use codemods for mechanical updates
|
||||
|
||||
```bash
|
||||
npx @reduxjs/rtk-codemods createSliceBuilder src/features/posts/postsSlice.ts
|
||||
npx @reduxjs/rtk-codemods createReducerBuilder src/features/posts/postsReducer.ts
|
||||
```
|
||||
|
||||
Use codemods for repetitive RTK API migrations, then review the result and finish the semantic cleanup by hand.
|
||||
|
||||
### Replace legacy server-data stacks with RTK Query
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type Todo = { id: string; text: string }
|
||||
|
||||
export const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
endpoints: (build) => ({
|
||||
getTodos: build.query<Todo[], void>({
|
||||
query: () => 'todos',
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
When the old code is just request status plus fetched data, migrate toward RTK Query instead of carrying the thunk stack forward forever.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### HIGH Attempting a big-bang rewrite
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
// Replace every reducer, every connected component, and every async flow
|
||||
// in one branch before shipping anything.
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
// 1) Switch createStore to configureStore
|
||||
// 2) Migrate one touched reducer to createSlice
|
||||
// 3) Convert touched connected components to hooks
|
||||
// 4) Repeat without introducing new legacy Redux code
|
||||
```
|
||||
|
||||
Modern Redux migration is incremental, but once the store is modernized new work should stop adding legacy patterns.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx
|
||||
|
||||
### CRITICAL Carrying removed RTK 2 config forms forward
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
configureStore({
|
||||
reducer,
|
||||
middleware: [logger],
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
configureStore({
|
||||
reducer,
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(logger),
|
||||
})
|
||||
```
|
||||
|
||||
RTK 2 removed array middleware configuration and other older builder forms that agents trained on RTK 1.x still emit.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md
|
||||
|
||||
### HIGH Preserving hand-written fetch state by default
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
|
||||
type Todo = { id: string; text: string }
|
||||
|
||||
const initialState = {
|
||||
items: [] as Todo[],
|
||||
status: 'idle' as 'idle' | 'pending' | 'failed',
|
||||
}
|
||||
|
||||
export const fetchTodos = createAsyncThunk('todos/fetch', async () => {
|
||||
const response = await fetch('/api/todos')
|
||||
return (await response.json()) as Todo[]
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type Todo = { id: string; text: string }
|
||||
|
||||
const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
endpoints: (build) => ({
|
||||
getTodos: build.query<Todo[], void>({
|
||||
query: () => 'todos',
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
If the feature is really server cache, keep the migration moving toward RTK Query instead of rebuilding the old loading-flag architecture in new APIs.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx
|
||||
385
frontend/node_modules/@reduxjs/toolkit/skills/manage-server-data/adopt-rtk-query/SKILL.md
generated
vendored
Normal file
385
frontend/node_modules/@reduxjs/toolkit/skills/manage-server-data/adopt-rtk-query/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
---
|
||||
name: manage-server-data/adopt-rtk-query
|
||||
description: >
|
||||
Use this when adding RTK Query as the default server-data and document-cache
|
||||
layer. Covers createApi, store integration, hooks, invalidation behavior,
|
||||
optimistic updates, and deciding when RTK Query is the right cache model.
|
||||
type: lifecycle
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
requires:
|
||||
- build-modern-redux-apps/modern-redux
|
||||
sources:
|
||||
- "reduxjs/redux-toolkit:docs/rtk-query/api/createApi.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/rtk-query/usage/automated-refetching.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/rtk-query/usage/manual-cache-updates.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/rtk-query/usage/persistence-and-rehydration.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/tutorials/rtk-query.mdx"
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
---
|
||||
|
||||
# Adopt RTK Query
|
||||
|
||||
## Setup
|
||||
|
||||
```tsx
|
||||
// file: src/services/api.ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
export const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
tagTypes: ['Post'],
|
||||
endpoints: (build) => ({
|
||||
getPosts: build.query<Post[], void>({
|
||||
query: () => 'posts',
|
||||
providesTags: (result) =>
|
||||
result
|
||||
? [...result.map(({ id }) => ({ type: 'Post' as const, id })), 'Post']
|
||||
: ['Post'],
|
||||
}),
|
||||
addPost: build.mutation<Post, Pick<Post, 'title'>>({
|
||||
query: (body) => ({
|
||||
url: 'posts',
|
||||
method: 'POST',
|
||||
body,
|
||||
}),
|
||||
invalidatesTags: ['Post'],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetPostsQuery, useAddPostMutation } = api
|
||||
|
||||
// file: src/app/store.ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { api } from '../services/api'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
[api.reducerPath]: api.reducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(api.middleware),
|
||||
})
|
||||
|
||||
// file: src/App.tsx
|
||||
import { Provider } from 'react-redux'
|
||||
import { store } from './app/store'
|
||||
import { useAddPostMutation, useGetPostsQuery } from './services/api'
|
||||
|
||||
function Posts() {
|
||||
const { data: posts = [] } = useGetPostsQuery()
|
||||
const [addPost] = useAddPostMutation()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => addPost({ title: 'Write docs' })}>Add</button>
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li key={post.id}>{post.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Posts />
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Keep one API slice per base URL and extend it
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
export const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
endpoints: () => ({}),
|
||||
})
|
||||
|
||||
export const postsApi = api.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
getPosts: build.query<{ id: string; title: string }[], void>({
|
||||
query: () => 'posts',
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
Split files with `injectEndpoints`, not by making multiple `createApi` roots for the same backend.
|
||||
|
||||
### Use tags for cache invalidation
|
||||
|
||||
```ts
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
export const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
tagTypes: ['Post'],
|
||||
endpoints: (build) => ({
|
||||
getPosts: build.query<Post[], void>({
|
||||
query: () => 'posts',
|
||||
providesTags: (result) =>
|
||||
result
|
||||
? [...result.map(({ id }) => ({ type: 'Post' as const, id })), 'Post']
|
||||
: ['Post'],
|
||||
}),
|
||||
updatePost: build.mutation<Post, Pick<Post, 'id' | 'title'>>({
|
||||
query: ({ id, title }) => ({
|
||||
url: `posts/${id}`,
|
||||
method: 'PATCH',
|
||||
body: { title },
|
||||
}),
|
||||
invalidatesTags: (_result, _error, { id }) => [{ type: 'Post', id }],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
Treat tags as the normal invalidation path before reaching for manual cache patching.
|
||||
|
||||
### Do optimistic updates in endpoint lifecycles
|
||||
|
||||
```ts
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
export const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
tagTypes: ['Post'],
|
||||
endpoints: (build) => ({
|
||||
getPosts: build.query<Post[], void>({
|
||||
query: () => 'posts',
|
||||
providesTags: ['Post'],
|
||||
}),
|
||||
updatePostTitle: build.mutation<Post, Pick<Post, 'id' | 'title'>>({
|
||||
query: ({ id, title }) => ({
|
||||
url: `posts/${id}`,
|
||||
method: 'PATCH',
|
||||
body: { title },
|
||||
}),
|
||||
async onQueryStarted({ id, title }, { dispatch, queryFulfilled }) {
|
||||
const patch = dispatch(
|
||||
api.util.updateQueryData('getPosts', undefined, (draft) => {
|
||||
const post = draft.find((item) => item.id === id)
|
||||
if (post) {
|
||||
post.title = title
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
try {
|
||||
await queryFulfilled
|
||||
} catch {
|
||||
patch.undo()
|
||||
}
|
||||
},
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
Keep optimistic and pessimistic cache updates inside endpoint lifecycle handlers so they stay coupled to the request.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### CRITICAL Creating multiple API slices for one backend
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type User = { id: string; name: string }
|
||||
|
||||
const baseQuery = fetchBaseQuery({ baseUrl: '/api/' })
|
||||
|
||||
const postsApi = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery,
|
||||
endpoints: () => ({}),
|
||||
})
|
||||
|
||||
const usersApi = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery,
|
||||
endpoints: () => ({}),
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type User = { id: string; name: string }
|
||||
|
||||
const baseQuery = fetchBaseQuery({ baseUrl: '/api/' })
|
||||
|
||||
const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery,
|
||||
endpoints: () => ({}),
|
||||
})
|
||||
|
||||
const usersApi = api.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
getUsers: build.query<User[], void>({ query: () => 'users' }),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
One API slice per base URL preserves invalidation behavior and avoids duplicated middleware work.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/rtk-query/api/createApi.mdx
|
||||
|
||||
### HIGH Forgetting `api.reducer` or `api.middleware`
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {},
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
[api.reducerPath]: api.reducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(api.middleware),
|
||||
})
|
||||
```
|
||||
|
||||
RTK Query hooks need both the reducer and middleware to manage cache state and request lifecycles.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/tutorials/rtk-query.mdx
|
||||
|
||||
### MEDIUM Persisting browser API cache by default
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const storage = window.localStorage
|
||||
|
||||
const persistConfig = {
|
||||
key: 'root',
|
||||
storage,
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
|
||||
endpoints: () => ({}),
|
||||
})
|
||||
```
|
||||
|
||||
Persisting RTK Query cache in browsers often keeps stale data around longer than users expect; treat persistence as a special case, not the default.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/rtk-query/usage/persistence-and-rehydration.mdx
|
||||
|
||||
### HIGH Patching cache from components
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { useEffect } from 'react'
|
||||
import { useAppDispatch } from '../../app/hooks'
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(api.util.updateQueryData('getPosts', undefined, (draft) => {
|
||||
draft.push({ id: 'p3', title: 'Patched from component' })
|
||||
}))
|
||||
}, [dispatch])
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
updatePostTitle: build.mutation<Post, Pick<Post, 'id' | 'title'>>({
|
||||
query: ({ id, title }) => ({
|
||||
url: `posts/${id}`,
|
||||
method: 'PATCH',
|
||||
body: { title },
|
||||
}),
|
||||
async onQueryStarted({ id, title }, { dispatch, queryFulfilled }) {
|
||||
const patch = dispatch(
|
||||
api.util.updateQueryData('getPosts', undefined, (draft) => {
|
||||
const post = draft.find((item) => item.id === id)
|
||||
if (post) {
|
||||
post.title = title
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
try {
|
||||
await queryFulfilled
|
||||
} catch {
|
||||
patch.undo()
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Component-level cache patches drift away from the mutation lifecycle that should own them.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/rtk-query/usage/manual-cache-updates.mdx
|
||||
|
||||
### HIGH Expecting invalidation to refetch unsubscribed queries
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { api } from './api'
|
||||
import { store } from './store'
|
||||
|
||||
const subscription = store.dispatch(api.endpoints.getPosts.initiate())
|
||||
subscription.unsubscribe()
|
||||
store.dispatch(api.util.invalidateTags(['Post']))
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { api } from './api'
|
||||
import { store } from './store'
|
||||
|
||||
store.dispatch(api.endpoints.getPosts.initiate())
|
||||
store.dispatch(api.util.invalidateTags(['Post']))
|
||||
```
|
||||
|
||||
Invalidation only refetches actively subscribed queries; if no component is using that cache entry, RTK Query drops it and fetches again next time it is needed.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/rtk-query/usage/automated-refetching.mdx
|
||||
|
||||
## References
|
||||
|
||||
- [Endpoint lifecycle details and cache tradeoffs](references/endpoint-lifecycle.md)
|
||||
36
frontend/node_modules/@reduxjs/toolkit/skills/manage-server-data/adopt-rtk-query/references/endpoint-lifecycle.md
generated
vendored
Normal file
36
frontend/node_modules/@reduxjs/toolkit/skills/manage-server-data/adopt-rtk-query/references/endpoint-lifecycle.md
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Endpoint Lifecycle
|
||||
|
||||
## Invalidation rule
|
||||
|
||||
When a mutation invalidates tags:
|
||||
|
||||
- active subscribers refetch
|
||||
- inactive cache entries are removed
|
||||
- removed entries fetch again only when something subscribes later
|
||||
|
||||
That behavior is deliberate; invalidation is not a background "refresh everything" switch.
|
||||
|
||||
## Document cache tradeoff
|
||||
|
||||
RTK Query is a document cache, not a normalized entity graph cache.
|
||||
|
||||
Use RTK Query by default when:
|
||||
|
||||
- the data comes from request/response APIs
|
||||
- document caching is acceptable
|
||||
- tag invalidation and endpoint lifecycles solve the problem
|
||||
|
||||
Reach for a different tool when:
|
||||
|
||||
- the real requirement is a normalized graph cache
|
||||
- the stack already has a domain-specific normalized client that fits better
|
||||
|
||||
If normalized caching is mandatory and no better library is already in the stack, a slice plus thunk flow may be the fallback.
|
||||
|
||||
## Useful endpoint options
|
||||
|
||||
- `providesTags`: tell RTK Query what cache entries this query represents
|
||||
- `invalidatesTags`: tell RTK Query what a mutation dirties
|
||||
- `onQueryStarted`: optimistic and pessimistic updates tied to a request
|
||||
- `onCacheEntryAdded`: long-lived subscriptions such as streaming data
|
||||
- `keepUnusedDataFor`: how long inactive cache entries stay around
|
||||
364
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/build-slices-and-selectors/SKILL.md
generated
vendored
Normal file
364
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/build-slices-and-selectors/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
---
|
||||
name: model-redux-state/build-slices-and-selectors
|
||||
description: >
|
||||
Use this when authoring or refactoring slices with createSlice, selectors,
|
||||
create.asyncThunk, entity adapters, or lazy reducer injection. Covers
|
||||
Immer-backed mutation syntax, slice selectors, getSelectors, injectInto,
|
||||
withLazyLoadedSlices, and current RTK 2 slice patterns.
|
||||
type: core
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
requires:
|
||||
- model-redux-state/design-state-ownership
|
||||
sources:
|
||||
- "reduxjs/redux-toolkit:docs/api/createSlice.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/api/combineSlices.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/api/createEntityAdapter.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/usage/immer-reducers.md"
|
||||
- "reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md"
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
---
|
||||
|
||||
# Build Slices And Selectors
|
||||
|
||||
## Setup
|
||||
|
||||
```ts
|
||||
// file: src/app/createAppSlice.ts
|
||||
import { asyncThunkCreator, buildCreateSlice } from '@reduxjs/toolkit'
|
||||
|
||||
export const createAppSlice = buildCreateSlice({
|
||||
creators: { asyncThunk: asyncThunkCreator },
|
||||
})
|
||||
|
||||
// file: src/features/posts/postsSlice.ts
|
||||
import { createSelector } from '@reduxjs/toolkit'
|
||||
import { createAppSlice } from '../../app/createAppSlice'
|
||||
|
||||
type PostsState = {
|
||||
items: { id: string; title: string; published: boolean }[]
|
||||
status: 'idle' | 'pending' | 'succeeded' | 'failed'
|
||||
}
|
||||
|
||||
const initialState: PostsState = {
|
||||
items: [],
|
||||
status: 'idle',
|
||||
}
|
||||
|
||||
export const postsSlice = createAppSlice({
|
||||
name: 'posts',
|
||||
initialState,
|
||||
reducers: (create) => ({
|
||||
postAdded: create.reducer<{ id: string; title: string }>((state, action) => {
|
||||
state.items.push({ ...action.payload, published: false })
|
||||
}),
|
||||
fetchPosts: create.asyncThunk(
|
||||
async () => {
|
||||
const response = await fetch('/api/posts')
|
||||
return (await response.json()) as { id: string; title: string; published: boolean }[]
|
||||
},
|
||||
{
|
||||
pending: (state) => {
|
||||
state.status = 'pending'
|
||||
},
|
||||
fulfilled: (state, action) => {
|
||||
state.status = 'succeeded'
|
||||
state.items = action.payload
|
||||
},
|
||||
rejected: (state) => {
|
||||
state.status = 'failed'
|
||||
},
|
||||
},
|
||||
),
|
||||
}),
|
||||
selectors: {
|
||||
selectPosts: (state) => state.items,
|
||||
selectPublishedPosts: createSelector(
|
||||
[(state: PostsState) => state.items],
|
||||
(items) => items.filter((post) => post.published),
|
||||
),
|
||||
},
|
||||
})
|
||||
|
||||
export const { postAdded, fetchPosts } = postsSlice.actions
|
||||
export const { selectPosts, selectPublishedPosts } = postsSlice.selectors
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Use mutating logic inside slice reducers
|
||||
|
||||
```ts
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const todosSlice = createSlice({
|
||||
name: 'todos',
|
||||
initialState: [] as { id: string; text: string; done: boolean }[],
|
||||
reducers: {
|
||||
todoAdded(state, action: { payload: { id: string; text: string } }) {
|
||||
state.push({ ...action.payload, done: false })
|
||||
},
|
||||
todoToggled(state, action: { payload: { id: string } }) {
|
||||
const todo = state.find((item) => item.id === action.payload.id)
|
||||
if (todo) {
|
||||
todo.done = !todo.done
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Immer is the default inside `createSlice`; write the reducer logic directly instead of copying arrays and objects by hand.
|
||||
|
||||
### Define selectors in the slice when they belong to the slice
|
||||
|
||||
```ts
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const counterSlice = createSlice({
|
||||
name: 'counter',
|
||||
initialState: { value: 0 },
|
||||
reducers: {
|
||||
increment(state) {
|
||||
state.value += 1
|
||||
},
|
||||
},
|
||||
selectors: {
|
||||
selectValue: (state) => state.value,
|
||||
selectIsPositive: (state) => state.value > 0,
|
||||
},
|
||||
})
|
||||
|
||||
const { selectValue, selectIsPositive } = counterSlice.selectors
|
||||
```
|
||||
|
||||
Slice selectors keep state-location knowledge next to the slice.
|
||||
|
||||
### Use `create.asyncThunk` when the async lifecycle belongs to the slice
|
||||
|
||||
```ts
|
||||
import { asyncThunkCreator, buildCreateSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const createAppSlice = buildCreateSlice({
|
||||
creators: { asyncThunk: asyncThunkCreator },
|
||||
})
|
||||
|
||||
const usersSlice = createAppSlice({
|
||||
name: 'users',
|
||||
initialState: { items: [] as { id: string; name: string }[], status: 'idle' as 'idle' | 'pending' | 'failed' },
|
||||
reducers: (create) => ({
|
||||
fetchUsers: create.asyncThunk(
|
||||
async () => {
|
||||
const response = await fetch('/api/users')
|
||||
return (await response.json()) as { id: string; name: string }[]
|
||||
},
|
||||
{
|
||||
pending: (state) => {
|
||||
state.status = 'pending'
|
||||
},
|
||||
fulfilled: (state, action) => {
|
||||
state.status = 'idle'
|
||||
state.items = action.payload
|
||||
},
|
||||
rejected: (state) => {
|
||||
state.status = 'failed'
|
||||
},
|
||||
},
|
||||
),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
Use this when the async lifecycle handlers naturally live with the slice; otherwise regular `createAsyncThunk` is still fine.
|
||||
|
||||
### Use entity adapters and lazy injection for scalable slices
|
||||
|
||||
```ts
|
||||
import {
|
||||
combineSlices,
|
||||
createEntityAdapter,
|
||||
createSlice,
|
||||
} from '@reduxjs/toolkit'
|
||||
|
||||
type Book = { bookId: string; title: string }
|
||||
|
||||
const booksAdapter = createEntityAdapter<Book>({
|
||||
selectId: (book) => book.bookId,
|
||||
})
|
||||
|
||||
const booksSlice = createSlice({
|
||||
name: 'books',
|
||||
initialState: booksAdapter.getInitialState(),
|
||||
reducers: {
|
||||
booksReceived: booksAdapter.setAll,
|
||||
},
|
||||
})
|
||||
|
||||
export interface LazyLoadedSlices {}
|
||||
|
||||
export const rootReducer =
|
||||
combineSlices().withLazyLoadedSlices<LazyLoadedSlices>()
|
||||
|
||||
declare module './rootReducer' {
|
||||
export interface LazyLoadedSlices {}
|
||||
}
|
||||
|
||||
const injectedBooksSlice = booksSlice.injectInto(rootReducer)
|
||||
|
||||
const selectors = booksAdapter.getSelectors(
|
||||
(state: ReturnType<typeof rootReducer.selector.original>) =>
|
||||
injectedBooksSlice.selectSlice(state),
|
||||
)
|
||||
```
|
||||
|
||||
Entity adapters standardize normalized collections, and `injectInto` lets a slice stay aware of its injected location.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### CRITICAL Using mutating logic outside slice reducers
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
type Todo = { id: string; text: string }
|
||||
|
||||
export function addTodo(todos: Todo[], todo: Todo) {
|
||||
todos.push(todo)
|
||||
return todos
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
type Todo = { id: string; text: string }
|
||||
|
||||
const todosSlice = createSlice({
|
||||
name: 'todos',
|
||||
initialState: [] as Todo[],
|
||||
reducers: {
|
||||
todoAdded(state, action: { payload: Todo }) {
|
||||
state.push(action.payload)
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Mutation syntax is only safe inside Immer-backed reducer contexts such as `createSlice` and `createReducer`.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/immer-reducers.md
|
||||
|
||||
### HIGH Writing hand-written switch reducers as the default
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
export default function todosReducer(state = initialState, action: { type: string; payload?: Todo }) {
|
||||
switch (action.type) {
|
||||
case 'todos/todoAdded':
|
||||
return state.concat(action.payload as Todo)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
const todosSlice = createSlice({
|
||||
name: 'todos',
|
||||
initialState,
|
||||
reducers: {
|
||||
todoAdded(state, action: { payload: Todo }) {
|
||||
state.push(action.payload)
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Hand-written reducers are an escape hatch for proven bottlenecks, not the normal thing an agent should generate in RTK code.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx
|
||||
|
||||
### HIGH Writing RTK 1.x object syntax for `extraReducers`
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const initialState = { items: [] as { id: string; title: string }[] }
|
||||
|
||||
const fetchPosts = createAsyncThunk('posts/fetch', async () => {
|
||||
const response = await fetch('/api/posts')
|
||||
return (await response.json()) as { id: string; title: string }[]
|
||||
})
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState,
|
||||
reducers: {},
|
||||
extraReducers: {
|
||||
[fetchPosts.fulfilled.type]: (state, action) => {
|
||||
state.items = action.payload
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const initialState = { items: [] as { id: string; title: string }[] }
|
||||
|
||||
const fetchPosts = createAsyncThunk('posts/fetch', async () => {
|
||||
const response = await fetch('/api/posts')
|
||||
return (await response.json()) as { id: string; title: string }[]
|
||||
})
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState,
|
||||
reducers: {},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(fetchPosts.fulfilled, (state, action) => {
|
||||
state.items = action.payload
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
RTK 2 removed the object form; agents trained on RTK 1.x still generate it.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md
|
||||
|
||||
### HIGH Assuming `entity.id` exists for every collection
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
type Book = { bookId: string; title: string }
|
||||
|
||||
const booksAdapter = createEntityAdapter<Book>()
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
type Book = { bookId: string; title: string }
|
||||
|
||||
const booksAdapter = createEntityAdapter<Book>({
|
||||
selectId: (book) => book.bookId,
|
||||
})
|
||||
```
|
||||
|
||||
Adapters default to `entity.id`; collections keyed by another field must provide `selectId`.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/api/createEntityAdapter.mdx
|
||||
|
||||
## References
|
||||
|
||||
- [Slice selectors, async creators, and lazy injection details](references/slice-patterns.md)
|
||||
59
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/build-slices-and-selectors/references/slice-patterns.md
generated
vendored
Normal file
59
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/build-slices-and-selectors/references/slice-patterns.md
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Slice Patterns
|
||||
|
||||
## `getSelectors` for alternate mounting points
|
||||
|
||||
```ts
|
||||
const counterSlice = createSlice({
|
||||
name: 'counter',
|
||||
initialState: { value: 0 },
|
||||
reducers: {},
|
||||
selectors: {
|
||||
selectValue: (state) => state.value,
|
||||
},
|
||||
})
|
||||
|
||||
export const { selectValue } = counterSlice.getSelectors(
|
||||
(state: { customCounter: { value: number } }) => state.customCounter,
|
||||
)
|
||||
```
|
||||
|
||||
Use `getSelectors` when the slice is not mounted at its default `reducerPath`.
|
||||
|
||||
## `withLazyLoadedSlices` and `injectInto`
|
||||
|
||||
```ts
|
||||
import { combineSlices, createSlice, type WithSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const staticSlice = createSlice({
|
||||
name: 'static',
|
||||
initialState: { ready: true },
|
||||
reducers: {},
|
||||
})
|
||||
|
||||
export interface LazyLoadedSlices {}
|
||||
|
||||
export const rootReducer =
|
||||
combineSlices(staticSlice).withLazyLoadedSlices<LazyLoadedSlices>()
|
||||
|
||||
const lazySlice = createSlice({
|
||||
name: 'lazy',
|
||||
initialState: { value: 0 },
|
||||
reducers: {
|
||||
increment(state) {
|
||||
state.value += 1
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
declare module '../rootReducer' {
|
||||
export interface LazyLoadedSlices extends WithSlice<typeof lazySlice> {}
|
||||
}
|
||||
|
||||
export const injectedLazySlice = lazySlice.injectInto(rootReducer)
|
||||
```
|
||||
|
||||
This keeps RootState types aware of reducers that will be injected later.
|
||||
|
||||
## Selector caveat
|
||||
|
||||
If a selector depends on caller-specific arguments and must be memoized per caller, prefer a selector factory outside `createSlice.selectors`. `createSlice.selectors` gives you one selector instance, not a selector factory.
|
||||
322
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/design-state-ownership/SKILL.md
generated
vendored
Normal file
322
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/design-state-ownership/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
---
|
||||
name: model-redux-state/design-state-ownership
|
||||
description: >
|
||||
Use this when deciding whether data belongs in Redux, component state, router
|
||||
state, or another external source. Covers state ownership, authority
|
||||
boundaries, slice sizing, and when to move or split data as the app evolves.
|
||||
type: core
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
sources:
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
- "reduxjs/redux:docs/tutorials/essentials/part-2-app-structure.md"
|
||||
- "reduxjs/redux:docs/tutorials/essentials/part-4-using-data.md"
|
||||
---
|
||||
|
||||
# Design State Ownership
|
||||
|
||||
## Setup
|
||||
|
||||
```tsx
|
||||
import { useState } from 'react'
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
import { useAppDispatch } from '../../app/hooks'
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: [] as { id: string; title: string; content: string }[],
|
||||
reducers: {
|
||||
postAdded(
|
||||
state,
|
||||
action: { payload: { id: string; title: string; content: string } },
|
||||
) {
|
||||
state.push(action.payload)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const { postAdded } = postsSlice.actions
|
||||
|
||||
export function AddPostForm() {
|
||||
const [title, setTitle] = useState('')
|
||||
const [content, setContent] = useState('')
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
dispatch(postAdded({ id: 'p1', title, content }))
|
||||
}}
|
||||
>
|
||||
<input value={title} onChange={(event) => setTitle(event.target.value)} />
|
||||
<textarea
|
||||
value={content}
|
||||
onChange={(event) => setContent(event.target.value)}
|
||||
/>
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Keep editable form state local until the user commits it
|
||||
|
||||
```tsx
|
||||
import { useState } from 'react'
|
||||
import { useAppDispatch } from '../../app/hooks'
|
||||
import { profileSaved } from './profileSlice'
|
||||
|
||||
export function ProfileForm() {
|
||||
const [displayName, setDisplayName] = useState('Lenz')
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
dispatch(profileSaved({ displayName }))
|
||||
}}
|
||||
>
|
||||
<input
|
||||
value={displayName}
|
||||
onChange={(event) => setDisplayName(event.target.value)}
|
||||
/>
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Prefer Redux for shared, durable app state, not every keystroke.
|
||||
|
||||
### Keep URL state with the router and combine it at the edge
|
||||
|
||||
```tsx
|
||||
import { createSelector } from '@reduxjs/toolkit'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { useAppSelector } from '../../app/hooks'
|
||||
|
||||
type RootState = {
|
||||
posts: {
|
||||
items: { id: string; title: string; published: boolean }[]
|
||||
}
|
||||
}
|
||||
|
||||
const selectPosts = (state: RootState) => state.posts.items
|
||||
|
||||
const selectVisiblePosts = createSelector(
|
||||
[selectPosts, (_state: RootState, filter: string) => filter],
|
||||
(posts, filter) =>
|
||||
filter === 'published'
|
||||
? posts.filter((post) => post.published)
|
||||
: posts,
|
||||
)
|
||||
|
||||
export function PostsList() {
|
||||
const [searchParams] = useSearchParams()
|
||||
const filter = searchParams.get('filter') ?? 'all'
|
||||
const posts = useAppSelector((state) => selectVisiblePosts(state, filter))
|
||||
|
||||
return <div>{posts.length}</div>
|
||||
}
|
||||
```
|
||||
|
||||
If the router already owns a piece of state, pass it into selectors or combine it in the component instead of syncing it into Redux.
|
||||
|
||||
### Re-size slices when access patterns change
|
||||
|
||||
```ts
|
||||
import { combineReducers, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const authSlice = createSlice({
|
||||
name: 'auth',
|
||||
initialState: { userId: null as string | null },
|
||||
reducers: {},
|
||||
})
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: { items: [] as { id: string; title: string }[] },
|
||||
reducers: {},
|
||||
})
|
||||
|
||||
export const rootReducer = combineReducers({
|
||||
auth: authSlice.reducer,
|
||||
posts: postsSlice.reducer,
|
||||
})
|
||||
```
|
||||
|
||||
Revisit slice size over time; unrelated data should split apart, and data constantly stitched together in every component may belong closer together.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### MEDIUM Putting form editing state in Redux
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { useAppSelector } from '../../app/hooks'
|
||||
|
||||
const selectDraftTitle = (state: { draft: { title: string } }) => state.draft.title
|
||||
|
||||
const title = useAppSelector(selectDraftTitle)
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
const [title, setTitle] = useState('')
|
||||
|
||||
<input value={title} onChange={(event) => setTitle(event.target.value)} />
|
||||
```
|
||||
|
||||
Per-keystroke dispatching adds global complexity for data that usually lives in one component tree.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### HIGH Synchronizing router or URL state into Redux
|
||||
|
||||
Wrong:
|
||||
|
||||
```tsx
|
||||
import { useEffect } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { useAppDispatch } from '../../app/hooks'
|
||||
|
||||
function PostsPage() {
|
||||
const [searchParams] = useSearchParams()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(filterChanged(searchParams.get('filter') ?? 'all'))
|
||||
}, [dispatch, searchParams])
|
||||
|
||||
return null
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```tsx
|
||||
const filter = searchParams.get('filter') ?? 'all'
|
||||
const posts = useAppSelector((state) => selectVisiblePosts(state, filter))
|
||||
```
|
||||
|
||||
URL state already has an authoritative owner; duplicating it into Redux creates two sources of truth.
|
||||
|
||||
Source: maintainer interview
|
||||
|
||||
### HIGH Naming state after components
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { combineReducers } from '@reduxjs/toolkit'
|
||||
|
||||
const loginReducer = (state = { open: false }) => state
|
||||
const postsReducer = (state = [] as { id: string; title: string }[]) => state
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
loginScreen: loginReducer,
|
||||
postsList: postsReducer,
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { combineReducers } from '@reduxjs/toolkit'
|
||||
|
||||
const authReducer = (state = { userId: null as string | null }) => state
|
||||
const postsReducer = (state = [] as { id: string; title: string }[]) => state
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer,
|
||||
posts: postsReducer,
|
||||
})
|
||||
```
|
||||
|
||||
Store keys should describe data or domain concepts, not the current component tree.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### MEDIUM Letting slice boundaries fossilize
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
type Post = { id: string; title: string }
|
||||
type AppNotification = { id: string; message: string }
|
||||
|
||||
const appSlice = createSlice({
|
||||
name: 'app',
|
||||
initialState: {
|
||||
auth: { userId: null as string | null },
|
||||
posts: [] as Post[],
|
||||
notifications: [] as AppNotification[],
|
||||
},
|
||||
reducers: {},
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
const authSlice = createSlice({
|
||||
name: 'auth',
|
||||
initialState: { userId: null as string | null },
|
||||
reducers: {},
|
||||
})
|
||||
|
||||
const postsSlice = createSlice({
|
||||
name: 'posts',
|
||||
initialState: [] as Post[],
|
||||
reducers: {},
|
||||
})
|
||||
```
|
||||
|
||||
When unrelated data is welded together, every change point gets noisier; split or merge slices as actual access patterns demand.
|
||||
|
||||
Source: maintainer interview
|
||||
|
||||
### HIGH Blindly spreading payloads into state
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const state = { id: '1', name: 'Lenz' }
|
||||
const action = { payload: { id: '2', name: 'Mark', ignored: true } }
|
||||
|
||||
userLoggedIn(state, action) {
|
||||
return { ...state, ...action.payload }
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
const state = { id: '1', name: 'Lenz' }
|
||||
const action = { payload: { id: '2', name: 'Mark', ignored: true } }
|
||||
|
||||
userLoggedIn(state, action) {
|
||||
state.id = action.payload.id
|
||||
state.name = action.payload.name
|
||||
}
|
||||
```
|
||||
|
||||
Reducers should own the slice shape instead of treating payloads as trusted state patches.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
## References
|
||||
|
||||
- [State ownership heuristics](references/state-ownership.md)
|
||||
28
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/design-state-ownership/references/state-ownership.md
generated
vendored
Normal file
28
frontend/node_modules/@reduxjs/toolkit/skills/model-redux-state/design-state-ownership/references/state-ownership.md
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# State Ownership Heuristics
|
||||
|
||||
## Choose the owner, then the tool
|
||||
|
||||
| Kind of state | Default owner | Typical tool |
|
||||
| --- | --- | --- |
|
||||
| Editable form fields | Component | `useState` |
|
||||
| Shared mutable app data | Redux | Slice state |
|
||||
| Server cache | RTK Query | `createApi` |
|
||||
| URL, pathname, search params | Router | Router APIs plus selector inputs |
|
||||
| Browser-only authority like `localStorage` | External source | Read at boundaries, then dispatch events |
|
||||
|
||||
## Good reasons to move data into Redux
|
||||
|
||||
- Multiple distant parts of the UI need the same mutable data.
|
||||
- You need time-travel debugging or a stable action history.
|
||||
- The reducer should own transitions because they mix old store state with new inputs.
|
||||
|
||||
## Reasons to keep data out of Redux
|
||||
|
||||
- Another system already owns it, such as the router.
|
||||
- It only matters during editing inside one component tree.
|
||||
- It is server cache and RTK Query fits the use case better.
|
||||
|
||||
## Re-evaluate slice size
|
||||
|
||||
- If data is constantly stitched together outside reducers, it may belong closer together.
|
||||
- If unrelated updates keep touching the same slice, split the slice by domain ownership.
|
||||
271
frontend/node_modules/@reduxjs/toolkit/skills/orchestrate-side-effects/handle-side-effects/SKILL.md
generated
vendored
Normal file
271
frontend/node_modules/@reduxjs/toolkit/skills/orchestrate-side-effects/handle-side-effects/SKILL.md
generated
vendored
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
---
|
||||
name: orchestrate-side-effects/handle-side-effects
|
||||
description: >
|
||||
Use this when choosing between RTK Query, createAsyncThunk, handwritten
|
||||
thunks, and createListenerMiddleware. Covers imperative versus reactive
|
||||
workflows, listener middleware setup, and keeping side effects out of
|
||||
reducers and UI components.
|
||||
type: core
|
||||
library: "@reduxjs/toolkit"
|
||||
library_version: "2.11.2"
|
||||
requires:
|
||||
- build-modern-redux-apps/redux-dataflow
|
||||
sources:
|
||||
- "reduxjs/redux-toolkit:docs/api/createAsyncThunk.mdx"
|
||||
- "reduxjs/redux-toolkit:docs/api/createListenerMiddleware.mdx"
|
||||
- "reduxjs/redux:docs/style-guide/style-guide.md"
|
||||
- "reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md"
|
||||
---
|
||||
|
||||
# Handle Side Effects
|
||||
|
||||
## Setup
|
||||
|
||||
```ts
|
||||
import {
|
||||
configureStore,
|
||||
createListenerMiddleware,
|
||||
createSlice,
|
||||
} from '@reduxjs/toolkit'
|
||||
|
||||
const docsSlice = createSlice({
|
||||
name: 'docs',
|
||||
initialState: { status: 'idle' as 'idle' | 'saved' },
|
||||
reducers: {
|
||||
saveStarted(state) {
|
||||
state.status = 'idle'
|
||||
},
|
||||
saveFinished(state) {
|
||||
state.status = 'saved'
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const listenerMiddleware = createListenerMiddleware()
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
docs: docsSlice.reducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().prepend(listenerMiddleware.middleware),
|
||||
})
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>
|
||||
export type AppDispatch = typeof store.dispatch
|
||||
|
||||
export const startAppListening =
|
||||
listenerMiddleware.startListening.withTypes<RootState, AppDispatch>()
|
||||
```
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Use RTK Query for server cache by default
|
||||
|
||||
```ts
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
type Post = { id: string; title: string }
|
||||
|
||||
export const api = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
|
||||
tagTypes: ['Post'],
|
||||
endpoints: (build) => ({
|
||||
getPosts: build.query<Post[], void>({
|
||||
query: () => 'posts',
|
||||
providesTags: ['Post'],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
If the problem is server data that should be cached and re-used, start with RTK Query instead of a thunk.
|
||||
|
||||
### Use `createAsyncThunk` for imperative workflows
|
||||
|
||||
```ts
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
type Draft = { title: string }
|
||||
|
||||
export const draftSaved = createAsyncThunk(
|
||||
'drafts/save',
|
||||
async (draft: Draft) => {
|
||||
const response = await fetch('/api/drafts', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(draft),
|
||||
})
|
||||
|
||||
return (await response.json()) as { id: string; title: string }
|
||||
},
|
||||
)
|
||||
|
||||
const draftsSlice = createSlice({
|
||||
name: 'drafts',
|
||||
initialState: { status: 'idle' as 'idle' | 'pending' | 'failed' },
|
||||
reducers: {},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(draftSaved.pending, (state) => {
|
||||
state.status = 'pending'
|
||||
})
|
||||
.addCase(draftSaved.fulfilled, (state) => {
|
||||
state.status = 'idle'
|
||||
})
|
||||
.addCase(draftSaved.rejected, (state) => {
|
||||
state.status = 'failed'
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Use a thunk when you need one imperative async workflow with `dispatch` and `getState`.
|
||||
|
||||
### Use listener middleware for reactive workflows
|
||||
|
||||
```ts
|
||||
import { createListenerMiddleware, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const docsSlice = createSlice({
|
||||
name: 'docs',
|
||||
initialState: { status: 'idle' as 'idle' | 'saved' },
|
||||
reducers: {
|
||||
saveFinished(state) {
|
||||
state.status = 'saved'
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const notificationsSlice = createSlice({
|
||||
name: 'notifications',
|
||||
initialState: [] as string[],
|
||||
reducers: {
|
||||
notificationQueued(state, action: { payload: string }) {
|
||||
state.push(action.payload)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const listenerMiddleware = createListenerMiddleware()
|
||||
|
||||
listenerMiddleware.startListening({
|
||||
actionCreator: docsSlice.actions.saveFinished,
|
||||
effect: async (_action, listenerApi) => {
|
||||
listenerApi.dispatch(
|
||||
notificationsSlice.actions.notificationQueued('Document saved'),
|
||||
)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Listeners fit workflows that react to future actions or state changes over time instead of driving one imperative request from a single callsite.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### CRITICAL Running side effects inside reducers
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
const todosSlice = createSlice({
|
||||
name: 'todos',
|
||||
initialState: [] as { id: string }[],
|
||||
reducers: {
|
||||
todoSaved(state, action: { payload: { id: string } }) {
|
||||
fetch('/api/todos', { method: 'POST' })
|
||||
state.push(action.payload)
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
|
||||
const todoSaved = createAsyncThunk('todos/save', async (todo: { id: string }) => {
|
||||
await fetch('/api/todos', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(todo),
|
||||
})
|
||||
return todo
|
||||
})
|
||||
```
|
||||
|
||||
Reducers must stay pure even when Immer is available.
|
||||
|
||||
Source: reduxjs/redux:docs/style-guide/style-guide.md
|
||||
|
||||
### HIGH Using thunks to watch future state changes
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
export const waitForSave = () => async (
|
||||
_dispatch: unknown,
|
||||
getState: () => { docs: { status: string } },
|
||||
) => {
|
||||
while (getState().docs.status !== 'saved') {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
startAppListening({
|
||||
predicate: (_action, currentState) => currentState.docs.status === 'saved',
|
||||
effect: async () => {
|
||||
console.log('Document saved')
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Polling inside thunks fights the architecture; listener middleware is the reactive tool.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/api/createListenerMiddleware.mdx
|
||||
|
||||
### HIGH Appending listener middleware after the default checks
|
||||
|
||||
Wrong:
|
||||
|
||||
```ts
|
||||
import { configureStore, createListenerMiddleware } from '@reduxjs/toolkit'
|
||||
|
||||
const reducer = (state = { ready: true }) => state
|
||||
const listenerMiddleware = createListenerMiddleware()
|
||||
|
||||
const store = configureStore({
|
||||
reducer,
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(listenerMiddleware.middleware),
|
||||
})
|
||||
```
|
||||
|
||||
Correct:
|
||||
|
||||
```ts
|
||||
import { configureStore, createListenerMiddleware } from '@reduxjs/toolkit'
|
||||
|
||||
const reducer = (state = { ready: true }) => state
|
||||
const listenerMiddleware = createListenerMiddleware()
|
||||
|
||||
const store = configureStore({
|
||||
reducer,
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().prepend(listenerMiddleware.middleware),
|
||||
})
|
||||
```
|
||||
|
||||
Listener add and remove actions may carry functions, so the listener middleware needs to run before serializability checks.
|
||||
|
||||
Source: reduxjs/redux-toolkit:docs/api/createListenerMiddleware.mdx
|
||||
|
||||
## References
|
||||
|
||||
- [Listener helpers and decision heuristics](references/listener-workflows.md)
|
||||
34
frontend/node_modules/@reduxjs/toolkit/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md
generated
vendored
Normal file
34
frontend/node_modules/@reduxjs/toolkit/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Listener Workflows
|
||||
|
||||
## Decision table
|
||||
|
||||
| Need | Reach for |
|
||||
| --- | --- |
|
||||
| Cached server data | RTK Query |
|
||||
| One imperative async workflow with `dispatch` / `getState` | `createAsyncThunk` or a thunk |
|
||||
| React to later actions or state transitions | `createListenerMiddleware` |
|
||||
|
||||
A good app often mixes imperative and reactive workflows. The split is by job, not by ideology.
|
||||
|
||||
## Useful listener helpers
|
||||
|
||||
- `predicate`: react to any action when a state condition becomes true
|
||||
- `condition`: wait until a condition becomes true before continuing
|
||||
- `take`: wait for the next matching action
|
||||
- `cancelActiveListeners`: cancel older instances of the same workflow
|
||||
- `fork`: start a child task
|
||||
|
||||
## Example: cancel stale work
|
||||
|
||||
```ts
|
||||
startAppListening({
|
||||
actionCreator: searchRequested,
|
||||
effect: async (action, listenerApi) => {
|
||||
listenerApi.cancelActiveListeners()
|
||||
await listenerApi.delay(250)
|
||||
listenerApi.dispatch(searchStarted(action.payload))
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
This is the kind of long-lived reactive behavior that does not fit a thunk well.
|
||||
34
frontend/node_modules/@reduxjs/toolkit/src/actionCreatorInvariantMiddleware.ts
generated
vendored
Normal file
34
frontend/node_modules/@reduxjs/toolkit/src/actionCreatorInvariantMiddleware.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import type { Middleware } from 'redux'
|
||||
import { isActionCreator as isRTKAction } from './createAction'
|
||||
|
||||
export interface ActionCreatorInvariantMiddlewareOptions {
|
||||
/**
|
||||
* The function to identify whether a value is an action creator.
|
||||
* The default checks for a function with a static type property and match method.
|
||||
*/
|
||||
isActionCreator?: (action: unknown) => action is Function & { type?: unknown }
|
||||
}
|
||||
|
||||
export function getMessage(type?: unknown) {
|
||||
const splitType = type ? `${type}`.split('/') : []
|
||||
const actionName = splitType[splitType.length - 1] || 'actionCreator'
|
||||
return `Detected an action creator with type "${
|
||||
type || 'unknown'
|
||||
}" being dispatched.
|
||||
Make sure you're calling the action creator before dispatching, i.e. \`dispatch(${actionName}())\` instead of \`dispatch(${actionName})\`. This is necessary even if the action has no payload.`
|
||||
}
|
||||
|
||||
export function createActionCreatorInvariantMiddleware(
|
||||
options: ActionCreatorInvariantMiddlewareOptions = {},
|
||||
): Middleware {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return () => (next) => (action) => next(action)
|
||||
}
|
||||
const { isActionCreator = isRTKAction } = options
|
||||
return () => (next) => (action) => {
|
||||
if (isActionCreator(action)) {
|
||||
console.warn(getMessage(action.type))
|
||||
}
|
||||
return next(action)
|
||||
}
|
||||
}
|
||||
146
frontend/node_modules/@reduxjs/toolkit/src/autoBatchEnhancer.ts
generated
vendored
Normal file
146
frontend/node_modules/@reduxjs/toolkit/src/autoBatchEnhancer.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
import type { StoreEnhancer } from 'redux'
|
||||
|
||||
export const SHOULD_AUTOBATCH = 'RTK_autoBatch'
|
||||
|
||||
export const prepareAutoBatched =
|
||||
<T>() =>
|
||||
(payload: T): { payload: T; meta: unknown } => ({
|
||||
payload,
|
||||
meta: { [SHOULD_AUTOBATCH]: true },
|
||||
})
|
||||
|
||||
const createQueueWithTimer = (timeout: number) => {
|
||||
return (notify: () => void) => {
|
||||
setTimeout(notify, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
const createRafWithFallbackTimer = (
|
||||
raf: typeof requestAnimationFrame,
|
||||
timeout: number,
|
||||
) => {
|
||||
return (notify: () => void) => {
|
||||
let called = false
|
||||
const callback = () => {
|
||||
if (called) return
|
||||
called = true
|
||||
cancelAnimationFrame(rafId)
|
||||
clearTimeout(timerId)
|
||||
notify()
|
||||
}
|
||||
const rafId = raf(callback)
|
||||
const timerId = setTimeout(callback, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
export type AutoBatchOptions =
|
||||
| { type: 'tick' }
|
||||
| { type: 'timer'; timeout: number }
|
||||
| { type: 'raf' }
|
||||
| { type: 'callback'; queueNotification: (notify: () => void) => void }
|
||||
|
||||
/**
|
||||
* A Redux store enhancer that watches for "low-priority" actions, and delays
|
||||
* notifying subscribers until either the queued callback executes or the
|
||||
* next "standard-priority" action is dispatched.
|
||||
*
|
||||
* This allows dispatching multiple "low-priority" actions in a row with only
|
||||
* a single subscriber notification to the UI after the sequence of actions
|
||||
* is finished, thus improving UI re-render performance.
|
||||
*
|
||||
* Watches for actions with the `action.meta[SHOULD_AUTOBATCH]` attribute.
|
||||
* This can be added to `action.meta` manually, or by using the
|
||||
* `prepareAutoBatched` helper.
|
||||
*
|
||||
* By default, it will queue a notification for the end of the event loop tick.
|
||||
* However, you can pass several other options to configure the behavior:
|
||||
* - `{type: 'tick'}`: queues using `queueMicrotask`
|
||||
* - `{type: 'timer', timeout: number}`: queues using `setTimeout`
|
||||
* - `{type: 'raf'}`: queues using `requestAnimationFrame` (default)
|
||||
* - `{type: 'callback', queueNotification: (notify: () => void) => void}`: lets you provide your own callback
|
||||
*
|
||||
*
|
||||
*/
|
||||
export const autoBatchEnhancer =
|
||||
(options: AutoBatchOptions = { type: 'raf' }): StoreEnhancer =>
|
||||
(next) =>
|
||||
(...args) => {
|
||||
const store = next(...args)
|
||||
|
||||
let notifying = true
|
||||
let shouldNotifyAtEndOfTick = false
|
||||
let notificationQueued = false
|
||||
|
||||
const listeners = new Set<() => void>()
|
||||
|
||||
const queueCallback =
|
||||
options.type === 'tick'
|
||||
? queueMicrotask
|
||||
: options.type === 'raf'
|
||||
? // requestAnimationFrame won't exist in SSR environments. Fall back to a vague approximation just to keep from erroring.
|
||||
typeof window !== 'undefined' && window.requestAnimationFrame
|
||||
? createRafWithFallbackTimer(window.requestAnimationFrame, 100)
|
||||
: createQueueWithTimer(10)
|
||||
: options.type === 'callback'
|
||||
? options.queueNotification
|
||||
: createQueueWithTimer(options.timeout)
|
||||
|
||||
const notifyListeners = () => {
|
||||
// We're running at the end of the event loop tick.
|
||||
// Run the real listener callbacks to actually update the UI.
|
||||
notificationQueued = false
|
||||
if (shouldNotifyAtEndOfTick) {
|
||||
shouldNotifyAtEndOfTick = false
|
||||
listeners.forEach((l) => l())
|
||||
}
|
||||
}
|
||||
|
||||
return Object.assign({}, store, {
|
||||
// Override the base `store.subscribe` method to keep original listeners
|
||||
// from running if we're delaying notifications
|
||||
subscribe(listener: () => void) {
|
||||
// Each wrapped listener will only call the real listener if
|
||||
// the `notifying` flag is currently active when it's called.
|
||||
// This lets the base store work as normal, while the actual UI
|
||||
// update becomes controlled by this enhancer.
|
||||
const wrappedListener: typeof listener = () => notifying && listener()
|
||||
const unsubscribe = store.subscribe(wrappedListener)
|
||||
listeners.add(listener)
|
||||
return () => {
|
||||
unsubscribe()
|
||||
listeners.delete(listener)
|
||||
}
|
||||
},
|
||||
// Override the base `store.dispatch` method so that we can check actions
|
||||
// for the `shouldAutoBatch` flag and determine if batching is active
|
||||
dispatch(action: any) {
|
||||
try {
|
||||
// If the action does _not_ have the `shouldAutoBatch` flag,
|
||||
// we resume/continue normal notify-after-each-dispatch behavior
|
||||
notifying = !action?.meta?.[SHOULD_AUTOBATCH]
|
||||
// If a `notifyListeners` microtask was queued, you can't cancel it.
|
||||
// Instead, we set a flag so that it's a no-op when it does run
|
||||
shouldNotifyAtEndOfTick = !notifying
|
||||
if (shouldNotifyAtEndOfTick) {
|
||||
// We've seen at least 1 action with `SHOULD_AUTOBATCH`. Try to queue
|
||||
// a microtask to notify listeners at the end of the event loop tick.
|
||||
// Make sure we only enqueue this _once_ per tick.
|
||||
if (!notificationQueued) {
|
||||
notificationQueued = true
|
||||
queueCallback(notifyListeners)
|
||||
}
|
||||
}
|
||||
// Go ahead and process the action as usual, including reducers.
|
||||
// If normal notification behavior is enabled, the store will notify
|
||||
// all of its own listeners, and the wrapper callbacks above will
|
||||
// see `notifying` is true and pass on to the real listener callbacks.
|
||||
// If we're "batching" behavior, then the wrapped callbacks will
|
||||
// bail out, causing the base store notification behavior to be no-ops.
|
||||
return store.dispatch(action)
|
||||
} finally {
|
||||
// Assume we're back to normal behavior after each action
|
||||
notifying = true
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
487
frontend/node_modules/@reduxjs/toolkit/src/combineSlices.ts
generated
vendored
Normal file
487
frontend/node_modules/@reduxjs/toolkit/src/combineSlices.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
import type {
|
||||
PreloadedStateShapeFromReducersMapObject,
|
||||
Reducer,
|
||||
StateFromReducersMapObject,
|
||||
UnknownAction,
|
||||
} from 'redux'
|
||||
import { combineReducers } from 'redux'
|
||||
import { nanoid } from './nanoid'
|
||||
import type {
|
||||
Id,
|
||||
NonUndefined,
|
||||
Tail,
|
||||
UnionToIntersection,
|
||||
WithOptionalProp,
|
||||
} from './tsHelpers'
|
||||
import { getOrInsertComputed } from './utils'
|
||||
|
||||
type SliceLike<ReducerPath extends string, State, PreloadedState = State> = {
|
||||
reducerPath: ReducerPath
|
||||
reducer: Reducer<State, any, PreloadedState>
|
||||
}
|
||||
|
||||
type AnySliceLike = SliceLike<string, any>
|
||||
|
||||
type SliceLikeReducerPath<A extends AnySliceLike> =
|
||||
A extends SliceLike<infer ReducerPath, any> ? ReducerPath : never
|
||||
|
||||
type SliceLikeState<A extends AnySliceLike> =
|
||||
A extends SliceLike<any, infer State, any> ? State : never
|
||||
|
||||
type SliceLikePreloadedState<A extends AnySliceLike> =
|
||||
A extends SliceLike<any, any, infer PreloadedState> ? PreloadedState : never
|
||||
|
||||
export type WithSlice<A extends AnySliceLike> = {
|
||||
[Path in SliceLikeReducerPath<A>]: SliceLikeState<A>
|
||||
}
|
||||
|
||||
export type WithSlicePreloadedState<A extends AnySliceLike> = {
|
||||
[Path in SliceLikeReducerPath<A>]: SliceLikePreloadedState<A>
|
||||
}
|
||||
|
||||
type ReducerMap = Record<string, Reducer>
|
||||
|
||||
type ExistingSliceLike<DeclaredState, PreloadedState> = {
|
||||
[ReducerPath in keyof DeclaredState]: SliceLike<
|
||||
ReducerPath & string,
|
||||
NonUndefined<DeclaredState[ReducerPath]>,
|
||||
NonUndefined<PreloadedState[ReducerPath & keyof PreloadedState]>
|
||||
>
|
||||
}[keyof DeclaredState]
|
||||
|
||||
export type InjectConfig = {
|
||||
/**
|
||||
* Allow replacing reducer with a different reference. Normally, an error will be thrown if a different reducer instance to the one already injected is used.
|
||||
*/
|
||||
overrideExisting?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* A reducer that allows for slices/reducers to be injected after initialisation.
|
||||
*/
|
||||
export interface CombinedSliceReducer<
|
||||
InitialState,
|
||||
DeclaredState extends InitialState = InitialState,
|
||||
PreloadedState extends Partial<
|
||||
Record<keyof PreloadedState, any>
|
||||
> = Partial<DeclaredState>,
|
||||
> extends Reducer<DeclaredState, UnknownAction, PreloadedState> {
|
||||
/**
|
||||
* Provide a type for slices that will be injected lazily.
|
||||
*
|
||||
* One way to do this would be with interface merging:
|
||||
* ```ts
|
||||
*
|
||||
* export interface LazyLoadedSlices {}
|
||||
*
|
||||
* export const rootReducer = combineSlices(stringSlice).withLazyLoadedSlices<LazyLoadedSlices>();
|
||||
*
|
||||
* // elsewhere
|
||||
*
|
||||
* declare module './reducer' {
|
||||
* export interface LazyLoadedSlices extends WithSlice<typeof booleanSlice> {}
|
||||
* }
|
||||
*
|
||||
* const withBoolean = rootReducer.inject(booleanSlice);
|
||||
*
|
||||
* // elsewhere again
|
||||
*
|
||||
* declare module './reducer' {
|
||||
* export interface LazyLoadedSlices {
|
||||
* customName: CustomState
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* const withCustom = rootReducer.inject({ reducerPath: "customName", reducer: customSlice.reducer })
|
||||
* ```
|
||||
*/
|
||||
withLazyLoadedSlices<Lazy = {}, LazyPreloaded = Lazy>(): CombinedSliceReducer<
|
||||
InitialState,
|
||||
Id<DeclaredState & Partial<Lazy>>,
|
||||
Id<PreloadedState & Partial<LazyPreloaded>>
|
||||
>
|
||||
|
||||
/**
|
||||
* Inject a slice.
|
||||
*
|
||||
* Accepts an individual slice, RTKQ API instance, or a "slice-like" { reducerPath, reducer } object.
|
||||
*
|
||||
* ```ts
|
||||
* rootReducer.inject(booleanSlice)
|
||||
* rootReducer.inject(baseApi)
|
||||
* rootReducer.inject({ reducerPath: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
inject<Sl extends Id<ExistingSliceLike<DeclaredState, PreloadedState>>>(
|
||||
slice: Sl,
|
||||
config?: InjectConfig,
|
||||
): CombinedSliceReducer<
|
||||
InitialState,
|
||||
Id<DeclaredState & WithSlice<Sl>>,
|
||||
Id<PreloadedState & Partial<WithSlicePreloadedState<Sl>>>
|
||||
>
|
||||
|
||||
/**
|
||||
* Inject a slice.
|
||||
*
|
||||
* Accepts an individual slice, RTKQ API instance, or a "slice-like" { reducerPath, reducer } object.
|
||||
*
|
||||
* ```ts
|
||||
* rootReducer.inject(booleanSlice)
|
||||
* rootReducer.inject(baseApi)
|
||||
* rootReducer.inject({ reducerPath: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
inject<ReducerPath extends string, State, PreloadedState = State>(
|
||||
slice: SliceLike<
|
||||
ReducerPath,
|
||||
State & (ReducerPath extends keyof DeclaredState ? never : State),
|
||||
PreloadedState &
|
||||
(ReducerPath extends keyof PreloadedState ? never : PreloadedState)
|
||||
>,
|
||||
config?: InjectConfig,
|
||||
): CombinedSliceReducer<
|
||||
InitialState,
|
||||
Id<DeclaredState & WithSlice<SliceLike<ReducerPath, State>>>,
|
||||
Id<
|
||||
PreloadedState &
|
||||
WithSlicePreloadedState<SliceLike<ReducerPath, State, PreloadedState>>
|
||||
>
|
||||
>
|
||||
|
||||
/**
|
||||
* Create a selector that guarantees that the slices injected will have a defined value when selector is run.
|
||||
*
|
||||
* ```ts
|
||||
* const selectBooleanWithoutInjection = (state: RootState) => state.boolean;
|
||||
* // ^? boolean | undefined
|
||||
*
|
||||
* const selectBoolean = rootReducer.inject(booleanSlice).selector((state) => {
|
||||
* // if action hasn't been dispatched since slice was injected, this would usually be undefined
|
||||
* // however selector() uses a Proxy around the first parameter to ensure that it evaluates to the initial state instead, if undefined
|
||||
* return state.boolean;
|
||||
* // ^? boolean
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* If the reducer is nested inside the root state, a selectState callback can be passed to retrieve the reducer's state.
|
||||
*
|
||||
* ```ts
|
||||
*
|
||||
* export interface LazyLoadedSlices {};
|
||||
*
|
||||
* export const innerReducer = combineSlices(stringSlice).withLazyLoadedSlices<LazyLoadedSlices>();
|
||||
*
|
||||
* export const rootReducer = combineSlices({ inner: innerReducer });
|
||||
*
|
||||
* export type RootState = ReturnType<typeof rootReducer>;
|
||||
*
|
||||
* // elsewhere
|
||||
*
|
||||
* declare module "./reducer.ts" {
|
||||
* export interface LazyLoadedSlices extends WithSlice<typeof booleanSlice> {}
|
||||
* }
|
||||
*
|
||||
* const withBool = innerReducer.inject(booleanSlice);
|
||||
*
|
||||
* const selectBoolean = withBool.selector(
|
||||
* (state) => state.boolean,
|
||||
* (rootState: RootState) => state.inner
|
||||
* );
|
||||
* // now expects to be passed RootState instead of innerReducer state
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* Value passed to selectorFn will be a Proxy - use selector.original(proxy) to get original state value (useful for debugging)
|
||||
*
|
||||
* ```ts
|
||||
* const injectedReducer = rootReducer.inject(booleanSlice);
|
||||
* const selectBoolean = injectedReducer.selector((state) => {
|
||||
* console.log(injectedReducer.selector.original(state).boolean) // possibly undefined
|
||||
* return state.boolean
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
selector: {
|
||||
/**
|
||||
* Create a selector that guarantees that the slices injected will have a defined value when selector is run.
|
||||
*
|
||||
* ```ts
|
||||
* const selectBooleanWithoutInjection = (state: RootState) => state.boolean;
|
||||
* // ^? boolean | undefined
|
||||
*
|
||||
* const selectBoolean = rootReducer.inject(booleanSlice).selector((state) => {
|
||||
* // if action hasn't been dispatched since slice was injected, this would usually be undefined
|
||||
* // however selector() uses a Proxy around the first parameter to ensure that it evaluates to the initial state instead, if undefined
|
||||
* return state.boolean;
|
||||
* // ^? boolean
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* Value passed to selectorFn will be a Proxy - use selector.original(proxy) to get original state value (useful for debugging)
|
||||
*
|
||||
* ```ts
|
||||
* const injectedReducer = rootReducer.inject(booleanSlice);
|
||||
* const selectBoolean = injectedReducer.selector((state) => {
|
||||
* console.log(injectedReducer.selector.original(state).boolean) // undefined
|
||||
* return state.boolean
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
<Selector extends (state: DeclaredState, ...args: any[]) => unknown>(
|
||||
selectorFn: Selector,
|
||||
): (
|
||||
state: WithOptionalProp<
|
||||
Parameters<Selector>[0],
|
||||
Exclude<keyof DeclaredState, keyof InitialState>
|
||||
>,
|
||||
...args: Tail<Parameters<Selector>>
|
||||
) => ReturnType<Selector>
|
||||
|
||||
/**
|
||||
* Create a selector that guarantees that the slices injected will have a defined value when selector is run.
|
||||
*
|
||||
* ```ts
|
||||
* const selectBooleanWithoutInjection = (state: RootState) => state.boolean;
|
||||
* // ^? boolean | undefined
|
||||
*
|
||||
* const selectBoolean = rootReducer.inject(booleanSlice).selector((state) => {
|
||||
* // if action hasn't been dispatched since slice was injected, this would usually be undefined
|
||||
* // however selector() uses a Proxy around the first parameter to ensure that it evaluates to the initial state instead, if undefined
|
||||
* return state.boolean;
|
||||
* // ^? boolean
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* If the reducer is nested inside the root state, a selectState callback can be passed to retrieve the reducer's state.
|
||||
*
|
||||
* ```ts
|
||||
*
|
||||
* interface LazyLoadedSlices {};
|
||||
*
|
||||
* const innerReducer = combineSlices(stringSlice).withLazyLoadedSlices<LazyLoadedSlices>();
|
||||
*
|
||||
* const rootReducer = combineSlices({ inner: innerReducer });
|
||||
*
|
||||
* type RootState = ReturnType<typeof rootReducer>;
|
||||
*
|
||||
* // elsewhere
|
||||
*
|
||||
* declare module "./reducer.ts" {
|
||||
* interface LazyLoadedSlices extends WithSlice<typeof booleanSlice> {}
|
||||
* }
|
||||
*
|
||||
* const withBool = innerReducer.inject(booleanSlice);
|
||||
*
|
||||
* const selectBoolean = withBool.selector(
|
||||
* (state) => state.boolean,
|
||||
* (rootState: RootState) => state.inner
|
||||
* );
|
||||
* // now expects to be passed RootState instead of innerReducer state
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* Value passed to selectorFn will be a Proxy - use selector.original(proxy) to get original state value (useful for debugging)
|
||||
*
|
||||
* ```ts
|
||||
* const injectedReducer = rootReducer.inject(booleanSlice);
|
||||
* const selectBoolean = injectedReducer.selector((state) => {
|
||||
* console.log(injectedReducer.selector.original(state).boolean) // possibly undefined
|
||||
* return state.boolean
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
<
|
||||
Selector extends (state: DeclaredState, ...args: any[]) => unknown,
|
||||
RootState,
|
||||
>(
|
||||
selectorFn: Selector,
|
||||
selectState: (
|
||||
rootState: RootState,
|
||||
...args: Tail<Parameters<Selector>>
|
||||
) => WithOptionalProp<
|
||||
Parameters<Selector>[0],
|
||||
Exclude<keyof DeclaredState, keyof InitialState>
|
||||
>,
|
||||
): (
|
||||
state: RootState,
|
||||
...args: Tail<Parameters<Selector>>
|
||||
) => ReturnType<Selector>
|
||||
/**
|
||||
* Returns the unproxied state. Useful for debugging.
|
||||
* @param state state Proxy, that ensures injected reducers have value
|
||||
* @returns original, unproxied state
|
||||
* @throws if value passed is not a state Proxy
|
||||
*/
|
||||
original: (state: DeclaredState) => InitialState & Partial<DeclaredState>
|
||||
}
|
||||
}
|
||||
|
||||
type InitialState<Slices extends Array<AnySliceLike | ReducerMap>> =
|
||||
UnionToIntersection<
|
||||
Slices[number] extends infer Slice
|
||||
? Slice extends AnySliceLike
|
||||
? WithSlice<Slice>
|
||||
: StateFromReducersMapObject<Slice>
|
||||
: never
|
||||
>
|
||||
|
||||
type InitialPreloadedState<Slices extends Array<AnySliceLike | ReducerMap>> =
|
||||
UnionToIntersection<
|
||||
Slices[number] extends infer Slice
|
||||
? Slice extends AnySliceLike
|
||||
? WithSlicePreloadedState<Slice>
|
||||
: PreloadedStateShapeFromReducersMapObject<Slice>
|
||||
: never
|
||||
>
|
||||
|
||||
const isSliceLike = (
|
||||
maybeSliceLike: AnySliceLike | ReducerMap,
|
||||
): maybeSliceLike is AnySliceLike =>
|
||||
'reducerPath' in maybeSliceLike &&
|
||||
typeof maybeSliceLike.reducerPath === 'string'
|
||||
|
||||
const getReducers = (slices: Array<AnySliceLike | ReducerMap>) =>
|
||||
slices.flatMap<[string, Reducer]>((sliceOrMap) =>
|
||||
isSliceLike(sliceOrMap)
|
||||
? [[sliceOrMap.reducerPath, sliceOrMap.reducer]]
|
||||
: Object.entries(sliceOrMap),
|
||||
)
|
||||
|
||||
const ORIGINAL_STATE = Symbol.for('rtk-state-proxy-original')
|
||||
|
||||
const isStateProxy = (value: any) => !!value && !!value[ORIGINAL_STATE]
|
||||
|
||||
const stateProxyMap = new WeakMap<object, object>()
|
||||
|
||||
const createStateProxy = <State extends object>(
|
||||
state: State,
|
||||
reducerMap: Partial<Record<PropertyKey, Reducer>>,
|
||||
initialStateCache: Record<PropertyKey, unknown>,
|
||||
) =>
|
||||
getOrInsertComputed(
|
||||
stateProxyMap,
|
||||
state,
|
||||
() =>
|
||||
new Proxy(state, {
|
||||
get: (target, prop, receiver) => {
|
||||
if (prop === ORIGINAL_STATE) return target
|
||||
const result = Reflect.get(target, prop, receiver)
|
||||
if (typeof result === 'undefined') {
|
||||
const cached = initialStateCache[prop]
|
||||
if (typeof cached !== 'undefined') return cached
|
||||
const reducer = reducerMap[prop]
|
||||
if (reducer) {
|
||||
// ensure action type is random, to prevent reducer treating it differently
|
||||
const reducerResult = reducer(undefined, { type: nanoid() })
|
||||
if (typeof reducerResult === 'undefined') {
|
||||
throw new Error(
|
||||
`The slice reducer for key "${prop.toString()}" returned undefined when called for selector(). ` +
|
||||
`If the state passed to the reducer is undefined, you must ` +
|
||||
`explicitly return the initial state. The initial state may ` +
|
||||
`not be undefined. If you don't want to set a value for this reducer, ` +
|
||||
`you can use null instead of undefined.`,
|
||||
)
|
||||
}
|
||||
initialStateCache[prop] = reducerResult
|
||||
return reducerResult
|
||||
}
|
||||
}
|
||||
return result
|
||||
},
|
||||
}),
|
||||
) as State
|
||||
|
||||
const original = (state: any) => {
|
||||
if (!isStateProxy(state)) {
|
||||
throw new Error('original must be used on state Proxy')
|
||||
}
|
||||
return state[ORIGINAL_STATE]
|
||||
}
|
||||
|
||||
const emptyObject = {}
|
||||
const noopReducer: Reducer<Record<string, any>> = (state = emptyObject) => state
|
||||
|
||||
export function combineSlices<Slices extends Array<AnySliceLike | ReducerMap>>(
|
||||
...slices: Slices
|
||||
): CombinedSliceReducer<
|
||||
Id<InitialState<Slices>>,
|
||||
Id<InitialState<Slices>>,
|
||||
Partial<Id<InitialPreloadedState<Slices>>>
|
||||
> {
|
||||
const reducerMap = Object.fromEntries(getReducers(slices))
|
||||
|
||||
const getReducer = () =>
|
||||
Object.keys(reducerMap).length ? combineReducers(reducerMap) : noopReducer
|
||||
|
||||
let reducer = getReducer()
|
||||
|
||||
function combinedReducer(
|
||||
state: Record<string, unknown>,
|
||||
action: UnknownAction,
|
||||
) {
|
||||
return reducer(state, action)
|
||||
}
|
||||
|
||||
combinedReducer.withLazyLoadedSlices = () => combinedReducer
|
||||
|
||||
const initialStateCache: Record<PropertyKey, unknown> = {}
|
||||
|
||||
const inject = (
|
||||
slice: AnySliceLike,
|
||||
config: InjectConfig = {},
|
||||
): typeof combinedReducer => {
|
||||
const { reducerPath, reducer: reducerToInject } = slice
|
||||
|
||||
const currentReducer = reducerMap[reducerPath]
|
||||
if (
|
||||
!config.overrideExisting &&
|
||||
currentReducer &&
|
||||
currentReducer !== reducerToInject
|
||||
) {
|
||||
if (
|
||||
typeof process !== 'undefined' &&
|
||||
process.env.NODE_ENV === 'development'
|
||||
) {
|
||||
console.error(
|
||||
`called \`inject\` to override already-existing reducer ${reducerPath} without specifying \`overrideExisting: true\``,
|
||||
)
|
||||
}
|
||||
|
||||
return combinedReducer
|
||||
}
|
||||
|
||||
if (config.overrideExisting && currentReducer !== reducerToInject) {
|
||||
delete initialStateCache[reducerPath]
|
||||
}
|
||||
|
||||
reducerMap[reducerPath] = reducerToInject
|
||||
|
||||
reducer = getReducer()
|
||||
|
||||
return combinedReducer
|
||||
}
|
||||
|
||||
const selector = Object.assign(
|
||||
function makeSelector<State extends object, RootState, Args extends any[]>(
|
||||
selectorFn: (state: State, ...args: Args) => any,
|
||||
selectState?: (rootState: RootState, ...args: Args) => State,
|
||||
) {
|
||||
return function selector(state: State, ...args: Args) {
|
||||
return selectorFn(
|
||||
createStateProxy(
|
||||
selectState ? selectState(state as any, ...args) : state,
|
||||
reducerMap,
|
||||
initialStateCache,
|
||||
),
|
||||
...args,
|
||||
)
|
||||
}
|
||||
},
|
||||
{ original },
|
||||
)
|
||||
|
||||
return Object.assign(combinedReducer, { inject, selector }) as any
|
||||
}
|
||||
248
frontend/node_modules/@reduxjs/toolkit/src/configureStore.ts
generated
vendored
Normal file
248
frontend/node_modules/@reduxjs/toolkit/src/configureStore.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
import type {
|
||||
Reducer,
|
||||
ReducersMapObject,
|
||||
Middleware,
|
||||
Action,
|
||||
StoreEnhancer,
|
||||
Store,
|
||||
UnknownAction,
|
||||
} from 'redux'
|
||||
import {
|
||||
applyMiddleware,
|
||||
createStore,
|
||||
compose,
|
||||
combineReducers,
|
||||
isPlainObject,
|
||||
} from './reduxImports'
|
||||
import type { DevToolsEnhancerOptions as DevToolsOptions } from './devtoolsExtension'
|
||||
import { composeWithDevTools } from './devtoolsExtension'
|
||||
|
||||
import type {
|
||||
ThunkMiddlewareFor,
|
||||
GetDefaultMiddleware,
|
||||
} from './getDefaultMiddleware'
|
||||
import { buildGetDefaultMiddleware } from './getDefaultMiddleware'
|
||||
import type {
|
||||
ExtractDispatchExtensions,
|
||||
ExtractStoreExtensions,
|
||||
ExtractStateExtensions,
|
||||
UnknownIfNonSpecific,
|
||||
} from './tsHelpers'
|
||||
import type { Tuple } from './utils'
|
||||
import type { GetDefaultEnhancers } from './getDefaultEnhancers'
|
||||
import { buildGetDefaultEnhancers } from './getDefaultEnhancers'
|
||||
|
||||
/**
|
||||
* Options for `configureStore()`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ConfigureStoreOptions<
|
||||
S = any,
|
||||
A extends Action = UnknownAction,
|
||||
M extends Tuple<Middlewares<S>> = Tuple<Middlewares<S>>,
|
||||
E extends Tuple<Enhancers> = Tuple<Enhancers>,
|
||||
P = S,
|
||||
> {
|
||||
/**
|
||||
* A single reducer function that will be used as the root reducer, or an
|
||||
* object of slice reducers that will be passed to `combineReducers()`.
|
||||
*/
|
||||
reducer: Reducer<S, A, P> | ReducersMapObject<S, A, P>
|
||||
|
||||
/**
|
||||
* An array of Redux middleware to install, or a callback receiving `getDefaultMiddleware` and returning a Tuple of middleware.
|
||||
* If not supplied, defaults to the set of middleware returned by `getDefaultMiddleware()`.
|
||||
*
|
||||
* @example `middleware: (gDM) => gDM().concat(logger, apiMiddleware, yourCustomMiddleware)`
|
||||
* @see https://redux-toolkit.js.org/api/getDefaultMiddleware#intended-usage
|
||||
*/
|
||||
middleware?: (getDefaultMiddleware: GetDefaultMiddleware<S>) => M
|
||||
|
||||
/**
|
||||
* Whether to enable Redux DevTools integration. Defaults to `true`.
|
||||
*
|
||||
* Additional configuration can be done by passing Redux DevTools options
|
||||
*/
|
||||
devTools?: boolean | DevToolsOptions
|
||||
|
||||
/**
|
||||
* Whether to check for duplicate middleware instances. Defaults to `true`.
|
||||
*/
|
||||
duplicateMiddlewareCheck?: boolean
|
||||
|
||||
/**
|
||||
* The initial state, same as Redux's createStore.
|
||||
* You may optionally specify it to hydrate the state
|
||||
* from the server in universal apps, or to restore a previously serialized
|
||||
* user session. If you use `combineReducers()` to produce the root reducer
|
||||
* function (either directly or indirectly by passing an object as `reducer`),
|
||||
* this must be an object with the same shape as the reducer map keys.
|
||||
*/
|
||||
// we infer here, and instead complain if the reducer doesn't match
|
||||
preloadedState?: P
|
||||
|
||||
/**
|
||||
* The store enhancers to apply. See Redux's `createStore()`.
|
||||
* All enhancers will be included before the DevTools Extension enhancer.
|
||||
* If you need to customize the order of enhancers, supply a callback
|
||||
* function that will receive a `getDefaultEnhancers` function that returns a Tuple,
|
||||
* and should return a Tuple of enhancers (such as `getDefaultEnhancers().concat(offline)`).
|
||||
* If you only need to add middleware, you can use the `middleware` parameter instead.
|
||||
*/
|
||||
enhancers?: (getDefaultEnhancers: GetDefaultEnhancers<M>) => E
|
||||
}
|
||||
|
||||
export type Middlewares<S> = ReadonlyArray<Middleware<{}, S>>
|
||||
|
||||
type Enhancers = ReadonlyArray<StoreEnhancer>
|
||||
|
||||
/**
|
||||
* A Redux store returned by `configureStore()`. Supports dispatching
|
||||
* side-effectful _thunks_ in addition to plain actions.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type EnhancedStore<
|
||||
S = any,
|
||||
A extends Action = UnknownAction,
|
||||
E extends Enhancers = Enhancers,
|
||||
> = ExtractStoreExtensions<E> &
|
||||
Store<S, A, UnknownIfNonSpecific<ExtractStateExtensions<E>>>
|
||||
|
||||
/**
|
||||
* A friendly abstraction over the standard Redux `createStore()` function.
|
||||
*
|
||||
* @param options The store configuration.
|
||||
* @returns A configured Redux store.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function configureStore<
|
||||
S = any,
|
||||
A extends Action = UnknownAction,
|
||||
M extends Tuple<Middlewares<S>> = Tuple<[ThunkMiddlewareFor<S>]>,
|
||||
E extends Tuple<Enhancers> = Tuple<
|
||||
[StoreEnhancer<{ dispatch: ExtractDispatchExtensions<M> }>, StoreEnhancer]
|
||||
>,
|
||||
P = S,
|
||||
>(options: ConfigureStoreOptions<S, A, M, E, P>): EnhancedStore<S, A, E> {
|
||||
const getDefaultMiddleware = buildGetDefaultMiddleware<S>()
|
||||
|
||||
const {
|
||||
reducer = undefined,
|
||||
middleware,
|
||||
devTools = true,
|
||||
duplicateMiddlewareCheck = true,
|
||||
preloadedState = undefined,
|
||||
enhancers = undefined,
|
||||
} = options || {}
|
||||
|
||||
let rootReducer: Reducer<S, A, P>
|
||||
|
||||
if (typeof reducer === 'function') {
|
||||
rootReducer = reducer
|
||||
} else if (isPlainObject(reducer)) {
|
||||
rootReducer = combineReducers(reducer) as unknown as Reducer<S, A, P>
|
||||
} else {
|
||||
throw new Error(
|
||||
'`reducer` is a required argument, and must be a function or an object of functions that can be passed to combineReducers',
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
middleware &&
|
||||
typeof middleware !== 'function'
|
||||
) {
|
||||
throw new Error('`middleware` field must be a callback')
|
||||
}
|
||||
|
||||
let finalMiddleware: Tuple<Middlewares<S>>
|
||||
if (typeof middleware === 'function') {
|
||||
finalMiddleware = middleware(getDefaultMiddleware)
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
!Array.isArray(finalMiddleware)
|
||||
) {
|
||||
throw new Error(
|
||||
'when using a middleware builder function, an array of middleware must be returned',
|
||||
)
|
||||
}
|
||||
} else {
|
||||
finalMiddleware = getDefaultMiddleware()
|
||||
}
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
finalMiddleware.some((item: any) => typeof item !== 'function')
|
||||
) {
|
||||
throw new Error(
|
||||
'each middleware provided to configureStore must be a function',
|
||||
)
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && duplicateMiddlewareCheck) {
|
||||
let middlewareReferences = new Set<Middleware<any, S>>()
|
||||
finalMiddleware.forEach((middleware) => {
|
||||
if (middlewareReferences.has(middleware)) {
|
||||
throw new Error(
|
||||
'Duplicate middleware references found when creating the store. Ensure that each middleware is only included once.',
|
||||
)
|
||||
}
|
||||
middlewareReferences.add(middleware)
|
||||
})
|
||||
}
|
||||
|
||||
let finalCompose = compose
|
||||
|
||||
if (devTools) {
|
||||
finalCompose = composeWithDevTools({
|
||||
// Enable capture of stack traces for dispatched Redux actions
|
||||
trace: process.env.NODE_ENV !== 'production',
|
||||
...(typeof devTools === 'object' && devTools),
|
||||
})
|
||||
}
|
||||
|
||||
const middlewareEnhancer = applyMiddleware(...finalMiddleware)
|
||||
|
||||
const getDefaultEnhancers = buildGetDefaultEnhancers<M>(middlewareEnhancer)
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
enhancers &&
|
||||
typeof enhancers !== 'function'
|
||||
) {
|
||||
throw new Error('`enhancers` field must be a callback')
|
||||
}
|
||||
|
||||
let storeEnhancers =
|
||||
typeof enhancers === 'function'
|
||||
? enhancers(getDefaultEnhancers)
|
||||
: getDefaultEnhancers()
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && !Array.isArray(storeEnhancers)) {
|
||||
throw new Error('`enhancers` callback must return an array')
|
||||
}
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
storeEnhancers.some((item: any) => typeof item !== 'function')
|
||||
) {
|
||||
throw new Error(
|
||||
'each enhancer provided to configureStore must be a function',
|
||||
)
|
||||
}
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
finalMiddleware.length &&
|
||||
!storeEnhancers.includes(middlewareEnhancer)
|
||||
) {
|
||||
console.error(
|
||||
'middlewares were provided, but middleware enhancer was not included in final enhancers - make sure to call `getDefaultEnhancers`',
|
||||
)
|
||||
}
|
||||
|
||||
const composedEnhancer: StoreEnhancer<any> = finalCompose(...storeEnhancers)
|
||||
|
||||
return createStore(rootReducer, preloadedState as P, composedEnhancer)
|
||||
}
|
||||
324
frontend/node_modules/@reduxjs/toolkit/src/createAction.ts
generated
vendored
Normal file
324
frontend/node_modules/@reduxjs/toolkit/src/createAction.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
import { isAction } from './reduxImports'
|
||||
import type {
|
||||
IsUnknownOrNonInferrable,
|
||||
IfMaybeUndefined,
|
||||
IfVoid,
|
||||
IsAny,
|
||||
} from './tsHelpers'
|
||||
import { hasMatchFunction } from './tsHelpers'
|
||||
|
||||
/**
|
||||
* An action with a string type and an associated payload. This is the
|
||||
* type of action returned by `createAction()` action creators.
|
||||
*
|
||||
* @template P The type of the action's payload.
|
||||
* @template T the type used for the action type.
|
||||
* @template M The type of the action's meta (optional)
|
||||
* @template E The type of the action's error (optional)
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PayloadAction<
|
||||
P = void,
|
||||
T extends string = string,
|
||||
M = never,
|
||||
E = never,
|
||||
> = {
|
||||
payload: P
|
||||
type: T
|
||||
} & ([M] extends [never]
|
||||
? {}
|
||||
: {
|
||||
meta: M
|
||||
}) &
|
||||
([E] extends [never]
|
||||
? {}
|
||||
: {
|
||||
error: E
|
||||
})
|
||||
|
||||
/**
|
||||
* A "prepare" method to be used as the second parameter of `createAction`.
|
||||
* Takes any number of arguments and returns a Flux Standard Action without
|
||||
* type (will be added later) that *must* contain a payload (might be undefined).
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PrepareAction<P> =
|
||||
| ((...args: any[]) => { payload: P })
|
||||
| ((...args: any[]) => { payload: P; meta: any })
|
||||
| ((...args: any[]) => { payload: P; error: any })
|
||||
| ((...args: any[]) => { payload: P; meta: any; error: any })
|
||||
|
||||
/**
|
||||
* Internal version of `ActionCreatorWithPreparedPayload`. Not to be used externally.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export type _ActionCreatorWithPreparedPayload<
|
||||
PA extends PrepareAction<any> | void,
|
||||
T extends string = string,
|
||||
> =
|
||||
PA extends PrepareAction<infer P>
|
||||
? ActionCreatorWithPreparedPayload<
|
||||
Parameters<PA>,
|
||||
P,
|
||||
T,
|
||||
ReturnType<PA> extends {
|
||||
error: infer E
|
||||
}
|
||||
? E
|
||||
: never,
|
||||
ReturnType<PA> extends {
|
||||
meta: infer M
|
||||
}
|
||||
? M
|
||||
: never
|
||||
>
|
||||
: void
|
||||
|
||||
/**
|
||||
* Basic type for all action creators.
|
||||
*
|
||||
* @inheritdoc {redux#ActionCreator}
|
||||
*/
|
||||
export type BaseActionCreator<P, T extends string, M = never, E = never> = {
|
||||
type: T
|
||||
match: (action: unknown) => action is PayloadAction<P, T, M, E>
|
||||
}
|
||||
|
||||
/**
|
||||
* An action creator that takes multiple arguments that are passed
|
||||
* to a `PrepareAction` method to create the final Action.
|
||||
* @typeParam Args arguments for the action creator function
|
||||
* @typeParam P `payload` type
|
||||
* @typeParam T `type` name
|
||||
* @typeParam E optional `error` type
|
||||
* @typeParam M optional `meta` type
|
||||
*
|
||||
* @inheritdoc {redux#ActionCreator}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ActionCreatorWithPreparedPayload<
|
||||
Args extends unknown[],
|
||||
P,
|
||||
T extends string = string,
|
||||
E = never,
|
||||
M = never,
|
||||
> extends BaseActionCreator<P, T, M, E> {
|
||||
/**
|
||||
* Calling this {@link redux#ActionCreator} with `Args` will return
|
||||
* an Action with a payload of type `P` and (depending on the `PrepareAction`
|
||||
* method used) a `meta`- and `error` property of types `M` and `E` respectively.
|
||||
*/
|
||||
(...args: Args): PayloadAction<P, T, M, E>
|
||||
}
|
||||
|
||||
/**
|
||||
* An action creator of type `T` that takes an optional payload of type `P`.
|
||||
*
|
||||
* @inheritdoc {redux#ActionCreator}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ActionCreatorWithOptionalPayload<P, T extends string = string>
|
||||
extends BaseActionCreator<P, T> {
|
||||
/**
|
||||
* Calling this {@link redux#ActionCreator} with an argument will
|
||||
* return a {@link PayloadAction} of type `T` with a payload of `P`.
|
||||
* Calling it without an argument will return a PayloadAction with a payload of `undefined`.
|
||||
*/
|
||||
(payload?: P): PayloadAction<P, T>
|
||||
}
|
||||
|
||||
/**
|
||||
* An action creator of type `T` that takes no payload.
|
||||
*
|
||||
* @inheritdoc {redux#ActionCreator}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ActionCreatorWithoutPayload<T extends string = string>
|
||||
extends BaseActionCreator<undefined, T> {
|
||||
/**
|
||||
* Calling this {@link redux#ActionCreator} will
|
||||
* return a {@link PayloadAction} of type `T` with a payload of `undefined`
|
||||
*/
|
||||
(noArgument: void): PayloadAction<undefined, T>
|
||||
}
|
||||
|
||||
/**
|
||||
* An action creator of type `T` that requires a payload of type P.
|
||||
*
|
||||
* @inheritdoc {redux#ActionCreator}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ActionCreatorWithPayload<P, T extends string = string>
|
||||
extends BaseActionCreator<P, T> {
|
||||
/**
|
||||
* Calling this {@link redux#ActionCreator} with an argument will
|
||||
* return a {@link PayloadAction} of type `T` with a payload of `P`
|
||||
*/
|
||||
(payload: P): PayloadAction<P, T>
|
||||
}
|
||||
|
||||
/**
|
||||
* An action creator of type `T` whose `payload` type could not be inferred. Accepts everything as `payload`.
|
||||
*
|
||||
* @inheritdoc {redux#ActionCreator}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ActionCreatorWithNonInferrablePayload<
|
||||
T extends string = string,
|
||||
> extends BaseActionCreator<unknown, T> {
|
||||
/**
|
||||
* Calling this {@link redux#ActionCreator} with an argument will
|
||||
* return a {@link PayloadAction} of type `T` with a payload
|
||||
* of exactly the type of the argument.
|
||||
*/
|
||||
<PT extends unknown>(payload: PT): PayloadAction<PT, T>
|
||||
}
|
||||
|
||||
/**
|
||||
* An action creator that produces actions with a `payload` attribute.
|
||||
*
|
||||
* @typeParam P the `payload` type
|
||||
* @typeParam T the `type` of the resulting action
|
||||
* @typeParam PA if the resulting action is preprocessed by a `prepare` method, the signature of said method.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PayloadActionCreator<
|
||||
P = void,
|
||||
T extends string = string,
|
||||
PA extends PrepareAction<P> | void = void,
|
||||
> = IfPrepareActionMethodProvided<
|
||||
PA,
|
||||
_ActionCreatorWithPreparedPayload<PA, T>,
|
||||
// else
|
||||
IsAny<
|
||||
P,
|
||||
ActionCreatorWithPayload<any, T>,
|
||||
IsUnknownOrNonInferrable<
|
||||
P,
|
||||
ActionCreatorWithNonInferrablePayload<T>,
|
||||
// else
|
||||
IfVoid<
|
||||
P,
|
||||
ActionCreatorWithoutPayload<T>,
|
||||
// else
|
||||
IfMaybeUndefined<
|
||||
P,
|
||||
ActionCreatorWithOptionalPayload<P, T>,
|
||||
// else
|
||||
ActionCreatorWithPayload<P, T>
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
|
||||
/**
|
||||
* A utility function to create an action creator for the given action type
|
||||
* string. The action creator accepts a single argument, which will be included
|
||||
* in the action object as a field called payload. The action creator function
|
||||
* will also have its toString() overridden so that it returns the action type.
|
||||
*
|
||||
* @param type The action type to use for created actions.
|
||||
* @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
|
||||
* If this is given, the resulting action creator will pass its arguments to this method to calculate payload & meta.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createAction<P = void, T extends string = string>(
|
||||
type: T,
|
||||
): PayloadActionCreator<P, T>
|
||||
|
||||
/**
|
||||
* A utility function to create an action creator for the given action type
|
||||
* string. The action creator accepts a single argument, which will be included
|
||||
* in the action object as a field called payload. The action creator function
|
||||
* will also have its toString() overridden so that it returns the action type.
|
||||
*
|
||||
* @param type The action type to use for created actions.
|
||||
* @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
|
||||
* If this is given, the resulting action creator will pass its arguments to this method to calculate payload & meta.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createAction<
|
||||
PA extends PrepareAction<any>,
|
||||
T extends string = string,
|
||||
>(
|
||||
type: T,
|
||||
prepareAction: PA,
|
||||
): PayloadActionCreator<ReturnType<PA>['payload'], T, PA>
|
||||
|
||||
export function createAction(type: string, prepareAction?: Function): any {
|
||||
function actionCreator(...args: any[]) {
|
||||
if (prepareAction) {
|
||||
let prepared = prepareAction(...args)
|
||||
if (!prepared) {
|
||||
throw new Error('prepareAction did not return an object')
|
||||
}
|
||||
|
||||
return {
|
||||
type,
|
||||
payload: prepared.payload,
|
||||
...('meta' in prepared && { meta: prepared.meta }),
|
||||
...('error' in prepared && { error: prepared.error }),
|
||||
}
|
||||
}
|
||||
return { type, payload: args[0] }
|
||||
}
|
||||
|
||||
actionCreator.toString = () => `${type}`
|
||||
|
||||
actionCreator.type = type
|
||||
|
||||
actionCreator.match = (action: unknown): action is PayloadAction =>
|
||||
isAction(action) && action.type === type
|
||||
|
||||
return actionCreator
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if value is an RTK-like action creator, with a static type property and match method.
|
||||
*/
|
||||
export function isActionCreator(
|
||||
action: unknown,
|
||||
): action is BaseActionCreator<unknown, string> & Function {
|
||||
return (
|
||||
typeof action === 'function' &&
|
||||
'type' in action &&
|
||||
// hasMatchFunction only wants Matchers but I don't see the point in rewriting it
|
||||
hasMatchFunction(action as any)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if value is an action with a string type and valid Flux Standard Action keys.
|
||||
*/
|
||||
export function isFSA(action: unknown): action is {
|
||||
type: string
|
||||
payload?: unknown
|
||||
error?: unknown
|
||||
meta?: unknown
|
||||
} {
|
||||
return isAction(action) && Object.keys(action).every(isValidKey)
|
||||
}
|
||||
|
||||
function isValidKey(key: string) {
|
||||
return ['type', 'payload', 'error', 'meta'].indexOf(key) > -1
|
||||
}
|
||||
|
||||
// helper types for more readable typings
|
||||
|
||||
type IfPrepareActionMethodProvided<
|
||||
PA extends PrepareAction<any> | void,
|
||||
True,
|
||||
False,
|
||||
> = PA extends (...args: any[]) => any ? True : False
|
||||
791
frontend/node_modules/@reduxjs/toolkit/src/createAsyncThunk.ts
generated
vendored
Normal file
791
frontend/node_modules/@reduxjs/toolkit/src/createAsyncThunk.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,791 @@
|
|||
import type { Dispatch, UnknownAction } from 'redux'
|
||||
import type { ThunkDispatch } from 'redux-thunk'
|
||||
import type { ActionCreatorWithPreparedPayload } from './createAction'
|
||||
import { createAction } from './createAction'
|
||||
import { isAnyOf } from './matchers'
|
||||
import { nanoid } from './nanoid'
|
||||
import type {
|
||||
FallbackIfUnknown,
|
||||
Id,
|
||||
IsAny,
|
||||
IsUnknown,
|
||||
SafePromise,
|
||||
} from './tsHelpers'
|
||||
|
||||
export type BaseThunkAPI<
|
||||
S,
|
||||
E,
|
||||
D extends Dispatch = Dispatch,
|
||||
RejectedValue = unknown,
|
||||
RejectedMeta = unknown,
|
||||
FulfilledMeta = unknown,
|
||||
> = {
|
||||
dispatch: D
|
||||
getState: () => S
|
||||
extra: E
|
||||
requestId: string
|
||||
signal: AbortSignal
|
||||
abort: (reason?: string) => void
|
||||
rejectWithValue: IsUnknown<
|
||||
RejectedMeta,
|
||||
(value: RejectedValue) => RejectWithValue<RejectedValue, RejectedMeta>,
|
||||
(
|
||||
value: RejectedValue,
|
||||
meta: RejectedMeta,
|
||||
) => RejectWithValue<RejectedValue, RejectedMeta>
|
||||
>
|
||||
fulfillWithValue: IsUnknown<
|
||||
FulfilledMeta,
|
||||
<FulfilledValue>(value: FulfilledValue) => FulfilledValue,
|
||||
<FulfilledValue>(
|
||||
value: FulfilledValue,
|
||||
meta: FulfilledMeta,
|
||||
) => FulfillWithMeta<FulfilledValue, FulfilledMeta>
|
||||
>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SerializedError {
|
||||
name?: string
|
||||
message?: string
|
||||
stack?: string
|
||||
code?: string
|
||||
}
|
||||
|
||||
const commonProperties: Array<keyof SerializedError> = [
|
||||
'name',
|
||||
'message',
|
||||
'stack',
|
||||
'code',
|
||||
]
|
||||
|
||||
class RejectWithValue<Payload, RejectedMeta> {
|
||||
/*
|
||||
type-only property to distinguish between RejectWithValue and FulfillWithMeta
|
||||
does not exist at runtime
|
||||
*/
|
||||
private readonly _type!: 'RejectWithValue'
|
||||
constructor(
|
||||
public readonly payload: Payload,
|
||||
public readonly meta: RejectedMeta,
|
||||
) {}
|
||||
}
|
||||
|
||||
class FulfillWithMeta<Payload, FulfilledMeta> {
|
||||
/*
|
||||
type-only property to distinguish between RejectWithValue and FulfillWithMeta
|
||||
does not exist at runtime
|
||||
*/
|
||||
private readonly _type!: 'FulfillWithMeta'
|
||||
constructor(
|
||||
public readonly payload: Payload,
|
||||
public readonly meta: FulfilledMeta,
|
||||
) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes an error into a plain object.
|
||||
* Reworked from https://github.com/sindresorhus/serialize-error
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const miniSerializeError = (value: any): SerializedError => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
const simpleError: SerializedError = {}
|
||||
for (const property of commonProperties) {
|
||||
if (typeof value[property] === 'string') {
|
||||
simpleError[property] = value[property]
|
||||
}
|
||||
}
|
||||
|
||||
return simpleError
|
||||
}
|
||||
|
||||
return { message: String(value) }
|
||||
}
|
||||
|
||||
export type AsyncThunkConfig = {
|
||||
state?: unknown
|
||||
dispatch?: ThunkDispatch<unknown, unknown, UnknownAction>
|
||||
extra?: unknown
|
||||
rejectValue?: unknown
|
||||
serializedErrorType?: unknown
|
||||
pendingMeta?: unknown
|
||||
fulfilledMeta?: unknown
|
||||
rejectedMeta?: unknown
|
||||
}
|
||||
|
||||
export type GetState<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
state: infer State
|
||||
}
|
||||
? State
|
||||
: unknown
|
||||
|
||||
type GetExtra<ThunkApiConfig> = ThunkApiConfig extends { extra: infer Extra }
|
||||
? Extra
|
||||
: unknown
|
||||
type GetDispatch<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
dispatch: infer Dispatch
|
||||
}
|
||||
? FallbackIfUnknown<
|
||||
Dispatch,
|
||||
ThunkDispatch<
|
||||
GetState<ThunkApiConfig>,
|
||||
GetExtra<ThunkApiConfig>,
|
||||
UnknownAction
|
||||
>
|
||||
>
|
||||
: ThunkDispatch<
|
||||
GetState<ThunkApiConfig>,
|
||||
GetExtra<ThunkApiConfig>,
|
||||
UnknownAction
|
||||
>
|
||||
|
||||
export type GetThunkAPI<ThunkApiConfig> = BaseThunkAPI<
|
||||
GetState<ThunkApiConfig>,
|
||||
GetExtra<ThunkApiConfig>,
|
||||
GetDispatch<ThunkApiConfig>,
|
||||
GetRejectValue<ThunkApiConfig>,
|
||||
GetRejectedMeta<ThunkApiConfig>,
|
||||
GetFulfilledMeta<ThunkApiConfig>
|
||||
>
|
||||
|
||||
type GetRejectValue<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
rejectValue: infer RejectValue
|
||||
}
|
||||
? RejectValue
|
||||
: unknown
|
||||
|
||||
type GetPendingMeta<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
pendingMeta: infer PendingMeta
|
||||
}
|
||||
? PendingMeta
|
||||
: unknown
|
||||
|
||||
type GetFulfilledMeta<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
fulfilledMeta: infer FulfilledMeta
|
||||
}
|
||||
? FulfilledMeta
|
||||
: unknown
|
||||
|
||||
type GetRejectedMeta<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
rejectedMeta: infer RejectedMeta
|
||||
}
|
||||
? RejectedMeta
|
||||
: unknown
|
||||
|
||||
type GetSerializedErrorType<ThunkApiConfig> = ThunkApiConfig extends {
|
||||
serializedErrorType: infer GetSerializedErrorType
|
||||
}
|
||||
? GetSerializedErrorType
|
||||
: SerializedError
|
||||
|
||||
type MaybePromise<T> = T | Promise<T> | (T extends any ? Promise<T> : never)
|
||||
|
||||
/**
|
||||
* A type describing the return value of the `payloadCreator` argument to `createAsyncThunk`.
|
||||
* Might be useful for wrapping `createAsyncThunk` in custom abstractions.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AsyncThunkPayloadCreatorReturnValue<
|
||||
Returned,
|
||||
ThunkApiConfig extends AsyncThunkConfig,
|
||||
> = MaybePromise<
|
||||
| IsUnknown<
|
||||
GetFulfilledMeta<ThunkApiConfig>,
|
||||
Returned,
|
||||
FulfillWithMeta<Returned, GetFulfilledMeta<ThunkApiConfig>>
|
||||
>
|
||||
| RejectWithValue<
|
||||
GetRejectValue<ThunkApiConfig>,
|
||||
GetRejectedMeta<ThunkApiConfig>
|
||||
>
|
||||
>
|
||||
/**
|
||||
* A type describing the `payloadCreator` argument to `createAsyncThunk`.
|
||||
* Might be useful for wrapping `createAsyncThunk` in custom abstractions.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AsyncThunkPayloadCreator<
|
||||
Returned,
|
||||
ThunkArg = void,
|
||||
ThunkApiConfig extends AsyncThunkConfig = {},
|
||||
> = (
|
||||
arg: ThunkArg,
|
||||
thunkAPI: GetThunkAPI<ThunkApiConfig>,
|
||||
) => AsyncThunkPayloadCreatorReturnValue<Returned, ThunkApiConfig>
|
||||
|
||||
/**
|
||||
* A ThunkAction created by `createAsyncThunk`.
|
||||
* Dispatching it returns a Promise for either a
|
||||
* fulfilled or rejected action.
|
||||
* Also, the returned value contains an `abort()` method
|
||||
* that allows the asyncAction to be cancelled from the outside.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AsyncThunkAction<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig extends AsyncThunkConfig,
|
||||
> = (
|
||||
dispatch: NonNullable<GetDispatch<ThunkApiConfig>>,
|
||||
getState: () => GetState<ThunkApiConfig>,
|
||||
extra: GetExtra<ThunkApiConfig>,
|
||||
) => SafePromise<
|
||||
| ReturnType<AsyncThunkFulfilledActionCreator<Returned, ThunkArg>>
|
||||
| ReturnType<AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>>
|
||||
> & {
|
||||
abort: (reason?: string) => void
|
||||
requestId: string
|
||||
arg: ThunkArg
|
||||
unwrap: () => Promise<Returned>
|
||||
}
|
||||
|
||||
/**
|
||||
* Config provided when calling the async thunk action creator.
|
||||
*/
|
||||
export interface AsyncThunkDispatchConfig {
|
||||
/**
|
||||
* An external `AbortSignal` that will be tracked by the internal `AbortSignal`.
|
||||
*/
|
||||
signal?: AbortSignal
|
||||
}
|
||||
|
||||
type AsyncThunkActionCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig extends AsyncThunkConfig,
|
||||
> = IsAny<
|
||||
ThunkArg,
|
||||
// any handling
|
||||
(
|
||||
arg: ThunkArg,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>,
|
||||
// unknown handling
|
||||
unknown extends ThunkArg
|
||||
? (
|
||||
arg: ThunkArg,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> // argument not specified or specified as void or undefined
|
||||
: [ThunkArg] extends [void] | [undefined]
|
||||
? (
|
||||
arg?: undefined,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> // argument contains void
|
||||
: [void] extends [ThunkArg] // make optional
|
||||
? (
|
||||
arg?: ThunkArg,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> // argument contains undefined
|
||||
: [undefined] extends [ThunkArg]
|
||||
? WithStrictNullChecks<
|
||||
// with strict nullChecks: make optional
|
||||
(
|
||||
arg?: ThunkArg,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>,
|
||||
// without strict null checks this will match everything, so don't make it optional
|
||||
(
|
||||
arg: ThunkArg,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
||||
> // default case: normal argument
|
||||
: (
|
||||
arg: ThunkArg,
|
||||
config?: AsyncThunkDispatchConfig,
|
||||
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
||||
>
|
||||
|
||||
/**
|
||||
* Options object for `createAsyncThunk`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AsyncThunkOptions<
|
||||
ThunkArg = void,
|
||||
ThunkApiConfig extends AsyncThunkConfig = {},
|
||||
> = {
|
||||
/**
|
||||
* A method to control whether the asyncThunk should be executed. Has access to the
|
||||
* `arg`, `api.getState()` and `api.extra` arguments.
|
||||
*
|
||||
* @returns `false` if it should be skipped
|
||||
*/
|
||||
condition?(
|
||||
arg: ThunkArg,
|
||||
api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
|
||||
): MaybePromise<boolean | undefined>
|
||||
/**
|
||||
* If `condition` returns `false`, the asyncThunk will be skipped.
|
||||
* This option allows you to control whether a `rejected` action with `meta.condition == false`
|
||||
* will be dispatched or not.
|
||||
*
|
||||
* @default `false`
|
||||
*/
|
||||
dispatchConditionRejection?: boolean
|
||||
|
||||
serializeError?: (x: unknown) => GetSerializedErrorType<ThunkApiConfig>
|
||||
|
||||
/**
|
||||
* A function to use when generating the `requestId` for the request sequence.
|
||||
*
|
||||
* @default `nanoid`
|
||||
*/
|
||||
idGenerator?: (arg: ThunkArg) => string
|
||||
} & IsUnknown<
|
||||
GetPendingMeta<ThunkApiConfig>,
|
||||
{
|
||||
/**
|
||||
* A method to generate additional properties to be added to `meta` of the pending action.
|
||||
*
|
||||
* Using this optional overload will not modify the types correctly, this overload is only in place to support JavaScript users.
|
||||
* Please use the `ThunkApiConfig` parameter `pendingMeta` to get access to a correctly typed overload
|
||||
*/
|
||||
getPendingMeta?(
|
||||
base: {
|
||||
arg: ThunkArg
|
||||
requestId: string
|
||||
},
|
||||
api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
|
||||
): GetPendingMeta<ThunkApiConfig>
|
||||
},
|
||||
{
|
||||
/**
|
||||
* A method to generate additional properties to be added to `meta` of the pending action.
|
||||
*/
|
||||
getPendingMeta(
|
||||
base: {
|
||||
arg: ThunkArg
|
||||
requestId: string
|
||||
},
|
||||
api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
|
||||
): GetPendingMeta<ThunkApiConfig>
|
||||
}
|
||||
>
|
||||
|
||||
export type AsyncThunkPendingActionCreator<
|
||||
ThunkArg,
|
||||
ThunkApiConfig = {},
|
||||
> = ActionCreatorWithPreparedPayload<
|
||||
[string, ThunkArg, GetPendingMeta<ThunkApiConfig>?],
|
||||
undefined,
|
||||
string,
|
||||
never,
|
||||
{
|
||||
arg: ThunkArg
|
||||
requestId: string
|
||||
requestStatus: 'pending'
|
||||
} & GetPendingMeta<ThunkApiConfig>
|
||||
>
|
||||
|
||||
export type AsyncThunkRejectedActionCreator<
|
||||
ThunkArg,
|
||||
ThunkApiConfig = {},
|
||||
> = ActionCreatorWithPreparedPayload<
|
||||
[
|
||||
Error | null,
|
||||
string,
|
||||
ThunkArg,
|
||||
GetRejectValue<ThunkApiConfig>?,
|
||||
GetRejectedMeta<ThunkApiConfig>?,
|
||||
],
|
||||
GetRejectValue<ThunkApiConfig> | undefined,
|
||||
string,
|
||||
GetSerializedErrorType<ThunkApiConfig>,
|
||||
{
|
||||
arg: ThunkArg
|
||||
requestId: string
|
||||
requestStatus: 'rejected'
|
||||
aborted: boolean
|
||||
condition: boolean
|
||||
} & (
|
||||
| ({ rejectedWithValue: false } & {
|
||||
[K in keyof GetRejectedMeta<ThunkApiConfig>]?: undefined
|
||||
})
|
||||
| ({ rejectedWithValue: true } & GetRejectedMeta<ThunkApiConfig>)
|
||||
)
|
||||
>
|
||||
|
||||
export type AsyncThunkFulfilledActionCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig = {},
|
||||
> = ActionCreatorWithPreparedPayload<
|
||||
[Returned, string, ThunkArg, GetFulfilledMeta<ThunkApiConfig>?],
|
||||
Returned,
|
||||
string,
|
||||
never,
|
||||
{
|
||||
arg: ThunkArg
|
||||
requestId: string
|
||||
requestStatus: 'fulfilled'
|
||||
} & GetFulfilledMeta<ThunkApiConfig>
|
||||
>
|
||||
|
||||
/**
|
||||
* A type describing the return value of `createAsyncThunk`.
|
||||
* Might be useful for wrapping `createAsyncThunk` in custom abstractions.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AsyncThunk<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig extends AsyncThunkConfig,
|
||||
> = AsyncThunkActionCreator<Returned, ThunkArg, ThunkApiConfig> & {
|
||||
pending: AsyncThunkPendingActionCreator<ThunkArg, ThunkApiConfig>
|
||||
rejected: AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>
|
||||
fulfilled: AsyncThunkFulfilledActionCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig
|
||||
>
|
||||
// matchSettled?
|
||||
settled: (
|
||||
action: any,
|
||||
) => action is ReturnType<
|
||||
| AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>
|
||||
| AsyncThunkFulfilledActionCreator<Returned, ThunkArg, ThunkApiConfig>
|
||||
>
|
||||
typePrefix: string
|
||||
}
|
||||
|
||||
export type OverrideThunkApiConfigs<OldConfig, NewConfig> = Id<
|
||||
NewConfig & Omit<OldConfig, keyof NewConfig>
|
||||
>
|
||||
|
||||
export type CreateAsyncThunkFunction<
|
||||
CurriedThunkApiConfig extends AsyncThunkConfig,
|
||||
> = {
|
||||
/**
|
||||
*
|
||||
* @param typePrefix
|
||||
* @param payloadCreator
|
||||
* @param options
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
// separate signature without `AsyncThunkConfig` for better inference
|
||||
<Returned, ThunkArg = void>(
|
||||
typePrefix: string,
|
||||
payloadCreator: AsyncThunkPayloadCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
CurriedThunkApiConfig
|
||||
>,
|
||||
options?: AsyncThunkOptions<ThunkArg, CurriedThunkApiConfig>,
|
||||
): AsyncThunk<Returned, ThunkArg, CurriedThunkApiConfig>
|
||||
|
||||
/**
|
||||
*
|
||||
* @param typePrefix
|
||||
* @param payloadCreator
|
||||
* @param options
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
<Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig>(
|
||||
typePrefix: string,
|
||||
payloadCreator: AsyncThunkPayloadCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
||||
>,
|
||||
options?: AsyncThunkOptions<
|
||||
ThunkArg,
|
||||
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
||||
>,
|
||||
): AsyncThunk<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
||||
>
|
||||
}
|
||||
|
||||
type CreateAsyncThunk<CurriedThunkApiConfig extends AsyncThunkConfig> =
|
||||
CreateAsyncThunkFunction<CurriedThunkApiConfig> & {
|
||||
withTypes<ThunkApiConfig extends AsyncThunkConfig>(): CreateAsyncThunk<
|
||||
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
||||
>
|
||||
}
|
||||
|
||||
const externalAbortMessage = 'External signal was aborted'
|
||||
|
||||
export const createAsyncThunk = /* @__PURE__ */ (() => {
|
||||
function createAsyncThunk<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig extends AsyncThunkConfig,
|
||||
>(
|
||||
typePrefix: string,
|
||||
payloadCreator: AsyncThunkPayloadCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig
|
||||
>,
|
||||
options?: AsyncThunkOptions<ThunkArg, ThunkApiConfig>,
|
||||
): AsyncThunk<Returned, ThunkArg, ThunkApiConfig> {
|
||||
type RejectedValue = GetRejectValue<ThunkApiConfig>
|
||||
type PendingMeta = GetPendingMeta<ThunkApiConfig>
|
||||
type FulfilledMeta = GetFulfilledMeta<ThunkApiConfig>
|
||||
type RejectedMeta = GetRejectedMeta<ThunkApiConfig>
|
||||
|
||||
const fulfilled: AsyncThunkFulfilledActionCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig
|
||||
> = createAction(
|
||||
typePrefix + '/fulfilled',
|
||||
(
|
||||
payload: Returned,
|
||||
requestId: string,
|
||||
arg: ThunkArg,
|
||||
meta?: FulfilledMeta,
|
||||
) => ({
|
||||
payload,
|
||||
meta: {
|
||||
...((meta as any) || {}),
|
||||
arg,
|
||||
requestId,
|
||||
requestStatus: 'fulfilled' as const,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const pending: AsyncThunkPendingActionCreator<ThunkArg, ThunkApiConfig> =
|
||||
createAction(
|
||||
typePrefix + '/pending',
|
||||
(requestId: string, arg: ThunkArg, meta?: PendingMeta) => ({
|
||||
payload: undefined,
|
||||
meta: {
|
||||
...((meta as any) || {}),
|
||||
arg,
|
||||
requestId,
|
||||
requestStatus: 'pending' as const,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const rejected: AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig> =
|
||||
createAction(
|
||||
typePrefix + '/rejected',
|
||||
(
|
||||
error: Error | null,
|
||||
requestId: string,
|
||||
arg: ThunkArg,
|
||||
payload?: RejectedValue,
|
||||
meta?: RejectedMeta,
|
||||
) => ({
|
||||
payload,
|
||||
error: ((options && options.serializeError) || miniSerializeError)(
|
||||
error || 'Rejected',
|
||||
) as GetSerializedErrorType<ThunkApiConfig>,
|
||||
meta: {
|
||||
...((meta as any) || {}),
|
||||
arg,
|
||||
requestId,
|
||||
rejectedWithValue: !!payload,
|
||||
requestStatus: 'rejected' as const,
|
||||
aborted: error?.name === 'AbortError',
|
||||
condition: error?.name === 'ConditionError',
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
function actionCreator(
|
||||
arg: ThunkArg,
|
||||
{ signal }: AsyncThunkDispatchConfig = {},
|
||||
): AsyncThunkAction<Returned, ThunkArg, Required<ThunkApiConfig>> {
|
||||
return (dispatch, getState, extra) => {
|
||||
const requestId = options?.idGenerator
|
||||
? options.idGenerator(arg)
|
||||
: nanoid()
|
||||
|
||||
const abortController = new AbortController()
|
||||
let abortHandler: (() => void) | undefined
|
||||
let abortReason: string | undefined
|
||||
|
||||
function abort(reason?: string) {
|
||||
abortReason = reason
|
||||
abortController.abort()
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
if (signal.aborted) {
|
||||
abort(externalAbortMessage)
|
||||
} else {
|
||||
signal.addEventListener(
|
||||
'abort',
|
||||
() => abort(externalAbortMessage),
|
||||
{ once: true },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const promise = (async function () {
|
||||
let finalAction: ReturnType<typeof fulfilled | typeof rejected>
|
||||
try {
|
||||
let conditionResult = options?.condition?.(arg, { getState, extra })
|
||||
if (isThenable(conditionResult)) {
|
||||
conditionResult = await conditionResult
|
||||
}
|
||||
|
||||
if (conditionResult === false || abortController.signal.aborted) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw {
|
||||
name: 'ConditionError',
|
||||
message: 'Aborted due to condition callback returning false.',
|
||||
}
|
||||
}
|
||||
|
||||
const abortedPromise = new Promise<never>((_, reject) => {
|
||||
abortHandler = () => {
|
||||
reject({
|
||||
name: 'AbortError',
|
||||
message: abortReason || 'Aborted',
|
||||
})
|
||||
}
|
||||
abortController.signal.addEventListener('abort', abortHandler, {
|
||||
once: true,
|
||||
})
|
||||
})
|
||||
dispatch(
|
||||
pending(
|
||||
requestId,
|
||||
arg,
|
||||
options?.getPendingMeta?.(
|
||||
{ requestId, arg },
|
||||
{ getState, extra },
|
||||
),
|
||||
) as any,
|
||||
)
|
||||
finalAction = await Promise.race([
|
||||
abortedPromise,
|
||||
Promise.resolve(
|
||||
payloadCreator(arg, {
|
||||
dispatch,
|
||||
getState,
|
||||
extra,
|
||||
requestId,
|
||||
signal: abortController.signal,
|
||||
abort,
|
||||
rejectWithValue: ((
|
||||
value: RejectedValue,
|
||||
meta?: RejectedMeta,
|
||||
) => {
|
||||
return new RejectWithValue(value, meta)
|
||||
}) as any,
|
||||
fulfillWithValue: ((value: unknown, meta?: FulfilledMeta) => {
|
||||
return new FulfillWithMeta(value, meta)
|
||||
}) as any,
|
||||
}),
|
||||
).then((result) => {
|
||||
if (result instanceof RejectWithValue) {
|
||||
throw result
|
||||
}
|
||||
if (result instanceof FulfillWithMeta) {
|
||||
return fulfilled(result.payload, requestId, arg, result.meta)
|
||||
}
|
||||
return fulfilled(result as any, requestId, arg)
|
||||
}),
|
||||
])
|
||||
} catch (err) {
|
||||
finalAction =
|
||||
err instanceof RejectWithValue
|
||||
? rejected(null, requestId, arg, err.payload, err.meta)
|
||||
: rejected(err as any, requestId, arg)
|
||||
} finally {
|
||||
if (abortHandler) {
|
||||
abortController.signal.removeEventListener('abort', abortHandler)
|
||||
}
|
||||
}
|
||||
// We dispatch the result action _after_ the catch, to avoid having any errors
|
||||
// here get swallowed by the try/catch block,
|
||||
// per https://twitter.com/dan_abramov/status/770914221638942720
|
||||
// and https://github.com/reduxjs/redux-toolkit/blob/e85eb17b39a2118d859f7b7746e0f3fee523e089/docs/tutorials/advanced-tutorial.md#async-error-handling-logic-in-thunks
|
||||
|
||||
const skipDispatch =
|
||||
options &&
|
||||
!options.dispatchConditionRejection &&
|
||||
rejected.match(finalAction) &&
|
||||
(finalAction as any).meta.condition
|
||||
|
||||
if (!skipDispatch) {
|
||||
dispatch(finalAction as any)
|
||||
}
|
||||
return finalAction
|
||||
})()
|
||||
return Object.assign(promise as SafePromise<any>, {
|
||||
abort,
|
||||
requestId,
|
||||
arg,
|
||||
unwrap() {
|
||||
return promise.then<any>(unwrapResult)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
actionCreator as AsyncThunkActionCreator<
|
||||
Returned,
|
||||
ThunkArg,
|
||||
ThunkApiConfig
|
||||
>,
|
||||
{
|
||||
pending,
|
||||
rejected,
|
||||
fulfilled,
|
||||
settled: isAnyOf(rejected, fulfilled),
|
||||
typePrefix,
|
||||
},
|
||||
)
|
||||
}
|
||||
createAsyncThunk.withTypes = () => createAsyncThunk
|
||||
|
||||
return createAsyncThunk as CreateAsyncThunk<AsyncThunkConfig>
|
||||
})()
|
||||
|
||||
interface UnwrappableAction {
|
||||
payload: any
|
||||
meta?: any
|
||||
error?: any
|
||||
}
|
||||
|
||||
type UnwrappedActionPayload<T extends UnwrappableAction> = Exclude<
|
||||
T,
|
||||
{ error: any }
|
||||
>['payload']
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function unwrapResult<R extends UnwrappableAction>(
|
||||
action: R,
|
||||
): UnwrappedActionPayload<R> {
|
||||
if (action.meta && action.meta.rejectedWithValue) {
|
||||
throw action.payload
|
||||
}
|
||||
if (action.error) {
|
||||
throw action.error
|
||||
}
|
||||
return action.payload
|
||||
}
|
||||
|
||||
type WithStrictNullChecks<True, False> = undefined extends boolean
|
||||
? False
|
||||
: True
|
||||
|
||||
function isThenable(value: any): value is PromiseLike<any> {
|
||||
return (
|
||||
value !== null &&
|
||||
typeof value === 'object' &&
|
||||
typeof value.then === 'function'
|
||||
)
|
||||
}
|
||||
30
frontend/node_modules/@reduxjs/toolkit/src/createDraftSafeSelector.ts
generated
vendored
Normal file
30
frontend/node_modules/@reduxjs/toolkit/src/createDraftSafeSelector.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { current, isDraft } from './immerImports'
|
||||
import { createSelectorCreator, weakMapMemoize } from './reselectImports'
|
||||
|
||||
export const createDraftSafeSelectorCreator: typeof createSelectorCreator = (
|
||||
...args: unknown[]
|
||||
) => {
|
||||
const createSelector = (createSelectorCreator as any)(...args)
|
||||
const createDraftSafeSelector = Object.assign(
|
||||
(...args: unknown[]) => {
|
||||
const selector = createSelector(...args)
|
||||
const wrappedSelector = (value: unknown, ...rest: unknown[]) =>
|
||||
selector(isDraft(value) ? current(value) : value, ...rest)
|
||||
Object.assign(wrappedSelector, selector)
|
||||
return wrappedSelector as any
|
||||
},
|
||||
{ withTypes: () => createDraftSafeSelector },
|
||||
)
|
||||
return createDraftSafeSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* "Draft-Safe" version of `reselect`'s `createSelector`:
|
||||
* If an `immer`-drafted object is passed into the resulting selector's first argument,
|
||||
* the selector will act on the current draft value, instead of returning a cached value
|
||||
* that might be possibly outdated if the draft has been modified since.
|
||||
* @public
|
||||
*/
|
||||
export const createDraftSafeSelector =
|
||||
/* @__PURE__ */
|
||||
createDraftSafeSelectorCreator(weakMapMemoize)
|
||||
217
frontend/node_modules/@reduxjs/toolkit/src/createReducer.ts
generated
vendored
Normal file
217
frontend/node_modules/@reduxjs/toolkit/src/createReducer.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
import type { Draft } from 'immer'
|
||||
import type { Action, Reducer, UnknownAction } from 'redux'
|
||||
import { createNextState, isDraft, isDraftable } from './immerImports'
|
||||
import type { ActionReducerMapBuilder } from './mapBuilders'
|
||||
import { executeReducerBuilderCallback } from './mapBuilders'
|
||||
import type { TypeGuard } from './tsHelpers'
|
||||
import { freezeDraftable } from './utils'
|
||||
|
||||
/**
|
||||
* Defines a mapping from action types to corresponding action object shapes.
|
||||
*
|
||||
* @deprecated This should not be used manually - it is only used for internal
|
||||
* inference purposes and should not have any further value.
|
||||
* It might be removed in the future.
|
||||
* @public
|
||||
*/
|
||||
export type Actions<T extends keyof any = string> = Record<T, Action>
|
||||
|
||||
export type ActionMatcherDescription<S, A extends Action> = {
|
||||
matcher: TypeGuard<A>
|
||||
reducer: CaseReducer<S, NoInfer<A>>
|
||||
}
|
||||
|
||||
export type ReadonlyActionMatcherDescriptionCollection<S> = ReadonlyArray<
|
||||
ActionMatcherDescription<S, any>
|
||||
>
|
||||
|
||||
export type ActionMatcherDescriptionCollection<S> = Array<
|
||||
ActionMatcherDescription<S, any>
|
||||
>
|
||||
|
||||
/**
|
||||
* A *case reducer* is a reducer function for a specific action type. Case
|
||||
* reducers can be composed to full reducers using `createReducer()`.
|
||||
*
|
||||
* Unlike a normal Redux reducer, a case reducer is never called with an
|
||||
* `undefined` state to determine the initial state. Instead, the initial
|
||||
* state is explicitly specified as an argument to `createReducer()`.
|
||||
*
|
||||
* In addition, a case reducer can choose to mutate the passed-in `state`
|
||||
* value directly instead of returning a new state. This does not actually
|
||||
* cause the store state to be mutated directly; instead, thanks to
|
||||
* [immer](https://github.com/mweststrate/immer), the mutations are
|
||||
* translated to copy operations that result in a new state.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CaseReducer<S = any, A extends Action = UnknownAction> = (
|
||||
state: Draft<S>,
|
||||
action: A,
|
||||
) => NoInfer<S> | void | Draft<NoInfer<S>>
|
||||
|
||||
/**
|
||||
* A mapping from action types to case reducers for `createReducer()`.
|
||||
*
|
||||
* @deprecated This should not be used manually - it is only used
|
||||
* for internal inference purposes and using it manually
|
||||
* would lead to type erasure.
|
||||
* It might be removed in the future.
|
||||
* @public
|
||||
*/
|
||||
export type CaseReducers<S, AS extends Actions> = {
|
||||
[T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void
|
||||
}
|
||||
|
||||
export type NotFunction<T> = T extends Function ? never : T
|
||||
|
||||
function isStateFunction<S>(x: unknown): x is () => S {
|
||||
return typeof x === 'function'
|
||||
}
|
||||
|
||||
export type ReducerWithInitialState<S extends NotFunction<any>> = Reducer<S> & {
|
||||
getInitialState: () => S
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility function that allows defining a reducer as a mapping from action
|
||||
* type to *case reducer* functions that handle these action types. The
|
||||
* reducer's initial state is passed as the first argument.
|
||||
*
|
||||
* @remarks
|
||||
* The body of every case reducer is implicitly wrapped with a call to
|
||||
* `produce()` from the [immer](https://github.com/mweststrate/immer) library.
|
||||
* This means that rather than returning a new state object, you can also
|
||||
* mutate the passed-in state object directly; these mutations will then be
|
||||
* automatically and efficiently translated into copies, giving you both
|
||||
* convenience and immutability.
|
||||
*
|
||||
* @overloadSummary
|
||||
* This function accepts a callback that receives a `builder` object as its argument.
|
||||
* That builder provides `addCase`, `addMatcher` and `addDefaultCase` functions that may be
|
||||
* called to define what actions this reducer will handle.
|
||||
*
|
||||
* @param initialState - `State | (() => State)`: The initial state that should be used when the reducer is called the first time. This may also be a "lazy initializer" function, which should return an initial state value when called. This will be used whenever the reducer is called with `undefined` as its state value, and is primarily useful for cases like reading initial state from `localStorage`.
|
||||
* @param builderCallback - `(builder: Builder) => void` A callback that receives a *builder* object to define
|
||||
* case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.
|
||||
* @example
|
||||
* ```ts
|
||||
* import type { PayloadAction, UnknownAction } from '@reduxjs/toolkit';
|
||||
* import { createAction, createReducer } from '@reduxjs/toolkit';
|
||||
*
|
||||
* const increment = createAction<number>('increment');
|
||||
* const decrement = createAction<number>('decrement');
|
||||
*
|
||||
* function isActionWithNumberPayload(
|
||||
* action: UnknownAction,
|
||||
* ): action is PayloadAction<number> {
|
||||
* return typeof action.payload === 'number';
|
||||
* }
|
||||
*
|
||||
* const reducer = createReducer(
|
||||
* {
|
||||
* counter: 0,
|
||||
* sumOfNumberPayloads: 0,
|
||||
* unhandledActions: 0,
|
||||
* },
|
||||
* (builder) => {
|
||||
* builder
|
||||
* .addCase(increment, (state, action) => {
|
||||
* // action is inferred correctly here
|
||||
* state.counter += action.payload;
|
||||
* })
|
||||
* // You can chain calls, or have separate `builder.addCase()` lines each time
|
||||
* .addCase(decrement, (state, action) => {
|
||||
* state.counter -= action.payload;
|
||||
* })
|
||||
* // You can apply a "matcher function" to incoming actions
|
||||
* .addMatcher(isActionWithNumberPayload, (state, action) => {})
|
||||
* // and provide a default case if no other handlers matched
|
||||
* .addDefaultCase((state, action) => {});
|
||||
* },
|
||||
* );
|
||||
* ```
|
||||
* @public
|
||||
*/
|
||||
export function createReducer<S extends NotFunction<any>>(
|
||||
initialState: S | (() => S),
|
||||
mapOrBuilderCallback: (builder: ActionReducerMapBuilder<S>) => void,
|
||||
): ReducerWithInitialState<S> {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (typeof mapOrBuilderCallback === 'object') {
|
||||
throw new Error(
|
||||
"The object notation for `createReducer` has been removed. Please use the 'builder callback' notation instead: https://redux-toolkit.js.org/api/createReducer",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let [actionsMap, finalActionMatchers, finalDefaultCaseReducer] =
|
||||
executeReducerBuilderCallback(mapOrBuilderCallback)
|
||||
|
||||
// Ensure the initial state gets frozen either way (if draftable)
|
||||
let getInitialState: () => S
|
||||
if (isStateFunction(initialState)) {
|
||||
getInitialState = () => freezeDraftable(initialState())
|
||||
} else {
|
||||
const frozenInitialState = freezeDraftable(initialState)
|
||||
getInitialState = () => frozenInitialState
|
||||
}
|
||||
|
||||
function reducer(state = getInitialState(), action: any): S {
|
||||
let caseReducers = [
|
||||
actionsMap[action.type],
|
||||
...finalActionMatchers
|
||||
.filter(({ matcher }) => matcher(action))
|
||||
.map(({ reducer }) => reducer),
|
||||
]
|
||||
if (caseReducers.filter((cr) => !!cr).length === 0) {
|
||||
caseReducers = [finalDefaultCaseReducer]
|
||||
}
|
||||
|
||||
return caseReducers.reduce((previousState, caseReducer): S => {
|
||||
if (caseReducer) {
|
||||
if (isDraft(previousState)) {
|
||||
// If it's already a draft, we must already be inside a `createNextState` call,
|
||||
// likely because this is being wrapped in `createReducer`, `createSlice`, or nested
|
||||
// inside an existing draft. It's safe to just pass the draft to the mutator.
|
||||
const draft = previousState as Draft<S> // We can assume this is already a draft
|
||||
const result = caseReducer(draft, action)
|
||||
|
||||
if (result === undefined) {
|
||||
return previousState
|
||||
}
|
||||
|
||||
return result as S
|
||||
} else if (!isDraftable(previousState)) {
|
||||
// If state is not draftable (ex: a primitive, such as 0), we want to directly
|
||||
// return the caseReducer func and not wrap it with produce.
|
||||
const result = caseReducer(previousState as any, action)
|
||||
|
||||
if (result === undefined) {
|
||||
if (previousState === null) {
|
||||
return previousState
|
||||
}
|
||||
throw Error(
|
||||
'A case reducer on a non-draftable value must not return undefined',
|
||||
)
|
||||
}
|
||||
|
||||
return result as S
|
||||
} else {
|
||||
// @ts-ignore createNextState() produces an Immutable<Draft<S>> rather
|
||||
// than an Immutable<S>, and TypeScript cannot find out how to reconcile
|
||||
// these two types.
|
||||
return createNextState(previousState, (draft: Draft<S>) => {
|
||||
return caseReducer(draft, action)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return previousState
|
||||
}, state)
|
||||
}
|
||||
|
||||
reducer.getInitialState = getInitialState
|
||||
|
||||
return reducer as ReducerWithInitialState<S>
|
||||
}
|
||||
1079
frontend/node_modules/@reduxjs/toolkit/src/createSlice.ts
generated
vendored
Normal file
1079
frontend/node_modules/@reduxjs/toolkit/src/createSlice.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
241
frontend/node_modules/@reduxjs/toolkit/src/devtoolsExtension.ts
generated
vendored
Normal file
241
frontend/node_modules/@reduxjs/toolkit/src/devtoolsExtension.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
import type { Action, ActionCreator, StoreEnhancer } from 'redux'
|
||||
import { compose } from './reduxImports'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface DevToolsEnhancerOptions {
|
||||
/**
|
||||
* the instance name to be showed on the monitor page. Default value is `document.title`.
|
||||
* If not specified and there's no document title, it will consist of `tabId` and `instanceId`.
|
||||
*/
|
||||
name?: string
|
||||
/**
|
||||
* action creators functions to be available in the Dispatcher.
|
||||
*/
|
||||
actionCreators?: ActionCreator<any>[] | { [key: string]: ActionCreator<any> }
|
||||
/**
|
||||
* if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once.
|
||||
* It is the joint between performance and speed. When set to `0`, all actions will be sent instantly.
|
||||
* Set it to a higher value when experiencing perf issues (also `maxAge` to a lower value).
|
||||
*
|
||||
* @default 500 ms.
|
||||
*/
|
||||
latency?: number
|
||||
/**
|
||||
* (> 1) - maximum allowed actions to be stored in the history tree. The oldest actions are removed once maxAge is reached. It's critical for performance.
|
||||
*
|
||||
* @default 50
|
||||
*/
|
||||
maxAge?: number
|
||||
/**
|
||||
* Customizes how actions and state are serialized and deserialized. Can be a boolean or object. If given a boolean, the behavior is the same as if you
|
||||
* were to pass an object and specify `options` as a boolean. Giving an object allows fine-grained customization using the `replacer` and `reviver`
|
||||
* functions.
|
||||
*/
|
||||
serialize?:
|
||||
| boolean
|
||||
| {
|
||||
/**
|
||||
* - `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode).
|
||||
* - `false` - will handle also circular references.
|
||||
* - `true` - will handle also date, regex, undefined, error objects, symbols, maps, sets and functions.
|
||||
* - object, which contains `date`, `regex`, `undefined`, `error`, `symbol`, `map`, `set` and `function` keys.
|
||||
* For each of them you can indicate if to include (by setting as `true`).
|
||||
* For `function` key you can also specify a custom function which handles serialization.
|
||||
* See [`jsan`](https://github.com/kolodny/jsan) for more details.
|
||||
*/
|
||||
options?:
|
||||
| undefined
|
||||
| boolean
|
||||
| {
|
||||
date?: true
|
||||
regex?: true
|
||||
undefined?: true
|
||||
error?: true
|
||||
symbol?: true
|
||||
map?: true
|
||||
set?: true
|
||||
function?: true | ((fn: (...args: any[]) => any) => string)
|
||||
}
|
||||
/**
|
||||
* [JSON replacer function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter) used for both actions and states stringify.
|
||||
* In addition, you can specify a data type by adding a [`__serializedType__`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/helpers/index.js#L4)
|
||||
* key. So you can deserialize it back while importing or persisting data.
|
||||
* Moreover, it will also [show a nice preview showing the provided custom type](https://cloud.githubusercontent.com/assets/7957859/21814330/a17d556a-d761-11e6-85ef-159dd12f36c5.png):
|
||||
*/
|
||||
replacer?: (key: string, value: unknown) => any
|
||||
/**
|
||||
* [JSON `reviver` function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter)
|
||||
* used for parsing the imported actions and states. See [`remotedev-serialize`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/immutable/serialize.js#L8-L41)
|
||||
* as an example on how to serialize special data types and get them back.
|
||||
*/
|
||||
reviver?: (key: string, value: unknown) => any
|
||||
/**
|
||||
* Automatically serialize/deserialize immutablejs via [remotedev-serialize](https://github.com/zalmoxisus/remotedev-serialize).
|
||||
* Just pass the Immutable library. It will support all ImmutableJS structures. You can even export them into a file and get them back.
|
||||
* The only exception is `Record` class, for which you should pass this in addition the references to your classes in `refs`.
|
||||
*/
|
||||
immutable?: any
|
||||
/**
|
||||
* ImmutableJS `Record` classes used to make possible restore its instances back when importing, persisting...
|
||||
*/
|
||||
refs?: any
|
||||
}
|
||||
/**
|
||||
* function which takes `action` object and id number as arguments, and should return `action` object back.
|
||||
*/
|
||||
actionSanitizer?: <A extends Action>(action: A, id: number) => A
|
||||
/**
|
||||
* function which takes `state` object and index as arguments, and should return `state` object back.
|
||||
*/
|
||||
stateSanitizer?: <S>(state: S, index: number) => S
|
||||
/**
|
||||
* *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).
|
||||
* If `actionsAllowlist` specified, `actionsDenylist` is ignored.
|
||||
*/
|
||||
actionsDenylist?: string | string[]
|
||||
/**
|
||||
* *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).
|
||||
* If `actionsAllowlist` specified, `actionsDenylist` is ignored.
|
||||
*/
|
||||
actionsAllowlist?: string | string[]
|
||||
/**
|
||||
* called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor.
|
||||
* Use it as a more advanced version of `actionsDenylist`/`actionsAllowlist` parameters.
|
||||
*/
|
||||
predicate?: <S, A extends Action>(state: S, action: A) => boolean
|
||||
/**
|
||||
* if specified as `false`, it will not record the changes till clicking on `Start recording` button.
|
||||
* Available only for Redux enhancer, for others use `autoPause`.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
shouldRecordChanges?: boolean
|
||||
/**
|
||||
* if specified, whenever clicking on `Pause recording` button and there are actions in the history log, will add this action type.
|
||||
* If not specified, will commit when paused. Available only for Redux enhancer.
|
||||
*
|
||||
* @default "@@PAUSED""
|
||||
*/
|
||||
pauseActionType?: string
|
||||
/**
|
||||
* auto pauses when the extension’s window is not opened, and so has zero impact on your app when not in use.
|
||||
* Not available for Redux enhancer (as it already does it but storing the data to be sent).
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
autoPause?: boolean
|
||||
/**
|
||||
* if specified as `true`, it will not allow any non-monitor actions to be dispatched till clicking on `Unlock changes` button.
|
||||
* Available only for Redux enhancer.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
shouldStartLocked?: boolean
|
||||
/**
|
||||
* if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Available only for Redux enhancer.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
shouldHotReload?: boolean
|
||||
/**
|
||||
* if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
shouldCatchErrors?: boolean
|
||||
/**
|
||||
* If you want to restrict the extension, specify the features you allow.
|
||||
* If not specified, all of the features are enabled. When set as an object, only those included as `true` will be allowed.
|
||||
* Note that except `true`/`false`, `import` and `export` can be set as `custom` (which is by default for Redux enhancer), meaning that the importing/exporting occurs on the client side.
|
||||
* Otherwise, you'll get/set the data right from the monitor part.
|
||||
*/
|
||||
features?: {
|
||||
/**
|
||||
* start/pause recording of dispatched actions
|
||||
*/
|
||||
pause?: boolean
|
||||
/**
|
||||
* lock/unlock dispatching actions and side effects
|
||||
*/
|
||||
lock?: boolean
|
||||
/**
|
||||
* persist states on page reloading
|
||||
*/
|
||||
persist?: boolean
|
||||
/**
|
||||
* export history of actions in a file
|
||||
*/
|
||||
export?: boolean | 'custom'
|
||||
/**
|
||||
* import history of actions from a file
|
||||
*/
|
||||
import?: boolean | 'custom'
|
||||
/**
|
||||
* jump back and forth (time traveling)
|
||||
*/
|
||||
jump?: boolean
|
||||
/**
|
||||
* skip (cancel) actions
|
||||
*/
|
||||
skip?: boolean
|
||||
/**
|
||||
* drag and drop actions in the history list
|
||||
*/
|
||||
reorder?: boolean
|
||||
/**
|
||||
* dispatch custom actions or action creators
|
||||
*/
|
||||
dispatch?: boolean
|
||||
/**
|
||||
* generate tests for the selected actions
|
||||
*/
|
||||
test?: boolean
|
||||
}
|
||||
/**
|
||||
* Set to true or a stacktrace-returning function to record call stack traces for dispatched actions.
|
||||
* Defaults to false.
|
||||
*/
|
||||
trace?: boolean | (<A extends Action>(action: A) => string)
|
||||
/**
|
||||
* The maximum number of stack trace entries to record per action. Defaults to 10.
|
||||
*/
|
||||
traceLimit?: number
|
||||
}
|
||||
|
||||
type Compose = typeof compose
|
||||
|
||||
interface ComposeWithDevTools {
|
||||
(options: DevToolsEnhancerOptions): Compose
|
||||
<StoreExt extends {}>(
|
||||
...funcs: StoreEnhancer<StoreExt>[]
|
||||
): StoreEnhancer<StoreExt>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const composeWithDevTools: ComposeWithDevTools =
|
||||
typeof window !== 'undefined' &&
|
||||
(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||
? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||
: function () {
|
||||
if (arguments.length === 0) return undefined
|
||||
if (typeof arguments[0] === 'object') return compose
|
||||
return compose.apply(null, arguments as any as Function[])
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const devToolsEnhancer: {
|
||||
(options: DevToolsEnhancerOptions): StoreEnhancer<any>
|
||||
} =
|
||||
typeof window !== 'undefined' && (window as any).__REDUX_DEVTOOLS_EXTENSION__
|
||||
? (window as any).__REDUX_DEVTOOLS_EXTENSION__
|
||||
: function () {
|
||||
return function (noop) {
|
||||
return noop
|
||||
}
|
||||
}
|
||||
93
frontend/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/index.ts
generated
vendored
Normal file
93
frontend/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import type { Dispatch, Middleware, UnknownAction } from 'redux'
|
||||
import { compose } from '../reduxImports'
|
||||
import { createAction } from '../createAction'
|
||||
import { isAllOf } from '../matchers'
|
||||
import { nanoid } from '../nanoid'
|
||||
import { getOrInsertComputed } from '../utils'
|
||||
import type {
|
||||
AddMiddleware,
|
||||
DynamicMiddleware,
|
||||
DynamicMiddlewareInstance,
|
||||
MiddlewareEntry,
|
||||
WithMiddleware,
|
||||
} from './types'
|
||||
export type {
|
||||
DynamicMiddlewareInstance,
|
||||
GetDispatchType as GetDispatch,
|
||||
MiddlewareApiConfig,
|
||||
} from './types'
|
||||
|
||||
const createMiddlewareEntry = <
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
>(
|
||||
middleware: Middleware<any, State, DispatchType>,
|
||||
): MiddlewareEntry<State, DispatchType> => ({
|
||||
middleware,
|
||||
applied: new Map(),
|
||||
})
|
||||
|
||||
const matchInstance =
|
||||
(instanceId: string) =>
|
||||
(action: any): action is { meta: { instanceId: string } } =>
|
||||
action?.meta?.instanceId === instanceId
|
||||
|
||||
export const createDynamicMiddleware = <
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
>(): DynamicMiddlewareInstance<State, DispatchType> => {
|
||||
const instanceId = nanoid()
|
||||
const middlewareMap = new Map<
|
||||
Middleware<any, State, DispatchType>,
|
||||
MiddlewareEntry<State, DispatchType>
|
||||
>()
|
||||
|
||||
const withMiddleware = Object.assign(
|
||||
createAction(
|
||||
'dynamicMiddleware/add',
|
||||
(...middlewares: Middleware<any, State, DispatchType>[]) => ({
|
||||
payload: middlewares,
|
||||
meta: {
|
||||
instanceId,
|
||||
},
|
||||
}),
|
||||
),
|
||||
{ withTypes: () => withMiddleware },
|
||||
) as WithMiddleware<State, DispatchType>
|
||||
|
||||
const addMiddleware = Object.assign(
|
||||
function addMiddleware(
|
||||
...middlewares: Middleware<any, State, DispatchType>[]
|
||||
) {
|
||||
middlewares.forEach((middleware) => {
|
||||
getOrInsertComputed(middlewareMap, middleware, createMiddlewareEntry)
|
||||
})
|
||||
},
|
||||
{ withTypes: () => addMiddleware },
|
||||
) as AddMiddleware<State, DispatchType>
|
||||
|
||||
const getFinalMiddleware: Middleware<{}, State, DispatchType> = (api) => {
|
||||
const appliedMiddleware = Array.from(middlewareMap.values()).map((entry) =>
|
||||
getOrInsertComputed(entry.applied, api, entry.middleware),
|
||||
)
|
||||
return compose(...appliedMiddleware)
|
||||
}
|
||||
|
||||
const isWithMiddleware = isAllOf(withMiddleware, matchInstance(instanceId))
|
||||
|
||||
const middleware: DynamicMiddleware<State, DispatchType> =
|
||||
(api) => (next) => (action) => {
|
||||
if (isWithMiddleware(action)) {
|
||||
addMiddleware(...action.payload)
|
||||
return api.dispatch
|
||||
}
|
||||
return getFinalMiddleware(api)(next)(action)
|
||||
}
|
||||
|
||||
return {
|
||||
middleware,
|
||||
addMiddleware,
|
||||
withMiddleware,
|
||||
instanceId,
|
||||
}
|
||||
}
|
||||
101
frontend/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts
generated
vendored
Normal file
101
frontend/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import type {
|
||||
DynamicMiddlewareInstance,
|
||||
GetDispatch,
|
||||
GetState,
|
||||
MiddlewareApiConfig,
|
||||
TSHelpersExtractDispatchExtensions,
|
||||
} from '@reduxjs/toolkit'
|
||||
import { createDynamicMiddleware as cDM } from '@reduxjs/toolkit'
|
||||
import type { Context } from 'react'
|
||||
import type { ReactReduxContextValue } from 'react-redux'
|
||||
import {
|
||||
createDispatchHook,
|
||||
ReactReduxContext,
|
||||
useDispatch as useDefaultDispatch,
|
||||
} from 'react-redux'
|
||||
import type { Action, Dispatch, Middleware, UnknownAction } from 'redux'
|
||||
|
||||
export type UseDispatchWithMiddlewareHook<
|
||||
Middlewares extends Middleware<any, State, DispatchType>[] = [],
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType
|
||||
|
||||
export type CreateDispatchWithMiddlewareHook<
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = {
|
||||
<
|
||||
Middlewares extends [
|
||||
Middleware<any, State, DispatchType>,
|
||||
...Middleware<any, State, DispatchType>[],
|
||||
],
|
||||
>(
|
||||
...middlewares: Middlewares
|
||||
): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>
|
||||
withTypes<
|
||||
MiddlewareConfig extends MiddlewareApiConfig,
|
||||
>(): CreateDispatchWithMiddlewareHook<
|
||||
GetState<MiddlewareConfig>,
|
||||
GetDispatch<MiddlewareConfig>
|
||||
>
|
||||
}
|
||||
|
||||
type ActionFromDispatch<DispatchType extends Dispatch<Action>> =
|
||||
DispatchType extends Dispatch<infer Action> ? Action : never
|
||||
|
||||
type ReactDynamicMiddlewareInstance<
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = DynamicMiddlewareInstance<State, DispatchType> & {
|
||||
createDispatchWithMiddlewareHookFactory: (
|
||||
context?: Context<ReactReduxContextValue<
|
||||
State,
|
||||
ActionFromDispatch<DispatchType>
|
||||
> | null>,
|
||||
) => CreateDispatchWithMiddlewareHook<State, DispatchType>
|
||||
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<
|
||||
State,
|
||||
DispatchType
|
||||
>
|
||||
}
|
||||
|
||||
export const createDynamicMiddleware = <
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {
|
||||
const instance = cDM<State, DispatchType>()
|
||||
const createDispatchWithMiddlewareHookFactory = (
|
||||
// @ts-ignore
|
||||
context: Context<ReactReduxContextValue<
|
||||
State,
|
||||
ActionFromDispatch<DispatchType>
|
||||
> | null> = ReactReduxContext,
|
||||
) => {
|
||||
const useDispatch =
|
||||
context === ReactReduxContext
|
||||
? useDefaultDispatch
|
||||
: createDispatchHook(context)
|
||||
function createDispatchWithMiddlewareHook<
|
||||
Middlewares extends Middleware<any, State, DispatchType>[],
|
||||
>(...middlewares: Middlewares) {
|
||||
instance.addMiddleware(...middlewares)
|
||||
return useDispatch
|
||||
}
|
||||
createDispatchWithMiddlewareHook.withTypes = () =>
|
||||
createDispatchWithMiddlewareHook
|
||||
return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<
|
||||
State,
|
||||
DispatchType
|
||||
>
|
||||
}
|
||||
|
||||
const createDispatchWithMiddlewareHook =
|
||||
createDispatchWithMiddlewareHookFactory()
|
||||
|
||||
return {
|
||||
...instance,
|
||||
createDispatchWithMiddlewareHookFactory,
|
||||
createDispatchWithMiddlewareHook,
|
||||
}
|
||||
}
|
||||
82
frontend/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/types.ts
generated
vendored
Normal file
82
frontend/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/types.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import type { Dispatch, Middleware, MiddlewareAPI, UnknownAction } from 'redux'
|
||||
import type { BaseActionCreator, PayloadAction } from '../createAction'
|
||||
import type { GetState } from '../createAsyncThunk'
|
||||
import type { ExtractDispatchExtensions, FallbackIfUnknown } from '../tsHelpers'
|
||||
|
||||
export type GetMiddlewareApi<MiddlewareApiConfig> = MiddlewareAPI<
|
||||
GetDispatchType<MiddlewareApiConfig>,
|
||||
GetState<MiddlewareApiConfig>
|
||||
>
|
||||
|
||||
export type MiddlewareApiConfig = {
|
||||
state?: unknown
|
||||
dispatch?: Dispatch
|
||||
}
|
||||
|
||||
// TODO: consolidate with cAT helpers?
|
||||
export type GetDispatchType<MiddlewareApiConfig> = MiddlewareApiConfig extends {
|
||||
dispatch: infer DispatchType
|
||||
}
|
||||
? FallbackIfUnknown<DispatchType, Dispatch>
|
||||
: Dispatch
|
||||
|
||||
export type AddMiddleware<
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = {
|
||||
(...middlewares: Middleware<any, State, DispatchType>[]): void
|
||||
withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): AddMiddleware<
|
||||
GetState<MiddlewareConfig>,
|
||||
GetDispatchType<MiddlewareConfig>
|
||||
>
|
||||
}
|
||||
|
||||
export type WithMiddleware<
|
||||
State = any,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = BaseActionCreator<
|
||||
Middleware<any, State, DispatchType>[],
|
||||
'dynamicMiddleware/add',
|
||||
{ instanceId: string }
|
||||
> & {
|
||||
<Middlewares extends Middleware<any, State, DispatchType>[]>(
|
||||
...middlewares: Middlewares
|
||||
): PayloadAction<Middlewares, 'dynamicMiddleware/add', { instanceId: string }>
|
||||
withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): WithMiddleware<
|
||||
GetState<MiddlewareConfig>,
|
||||
GetDispatchType<MiddlewareConfig>
|
||||
>
|
||||
}
|
||||
|
||||
export interface DynamicDispatch {
|
||||
// return a version of dispatch that knows about middleware
|
||||
<Middlewares extends Middleware<any>[]>(
|
||||
action: PayloadAction<Middlewares, 'dynamicMiddleware/add'>,
|
||||
): ExtractDispatchExtensions<Middlewares> & this
|
||||
}
|
||||
|
||||
export type MiddlewareEntry<
|
||||
State = unknown,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = {
|
||||
middleware: Middleware<any, State, DispatchType>
|
||||
applied: Map<
|
||||
MiddlewareAPI<DispatchType, State>,
|
||||
ReturnType<Middleware<any, State, DispatchType>>
|
||||
>
|
||||
}
|
||||
|
||||
export type DynamicMiddleware<
|
||||
State = unknown,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = Middleware<DynamicDispatch, State, DispatchType>
|
||||
|
||||
export type DynamicMiddlewareInstance<
|
||||
State = unknown,
|
||||
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
|
||||
> = {
|
||||
middleware: DynamicMiddleware<State, DispatchType>
|
||||
addMiddleware: AddMiddleware<State, DispatchType>
|
||||
withMiddleware: WithMiddleware<State, DispatchType>
|
||||
instanceId: string
|
||||
}
|
||||
47
frontend/node_modules/@reduxjs/toolkit/src/entities/create_adapter.ts
generated
vendored
Normal file
47
frontend/node_modules/@reduxjs/toolkit/src/entities/create_adapter.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import type { EntityAdapter, EntityId, EntityAdapterOptions } from './models'
|
||||
import { createInitialStateFactory } from './entity_state'
|
||||
import { createSelectorsFactory } from './state_selectors'
|
||||
import { createSortedStateAdapter } from './sorted_state_adapter'
|
||||
import { createUnsortedStateAdapter } from './unsorted_state_adapter'
|
||||
import type { WithRequiredProp } from '../tsHelpers'
|
||||
|
||||
export function createEntityAdapter<T, Id extends EntityId>(
|
||||
options: WithRequiredProp<EntityAdapterOptions<T, Id>, 'selectId'>,
|
||||
): EntityAdapter<T, Id>
|
||||
|
||||
export function createEntityAdapter<T extends { id: EntityId }>(
|
||||
options?: Omit<EntityAdapterOptions<T, T['id']>, 'selectId'>,
|
||||
): EntityAdapter<T, T['id']>
|
||||
|
||||
/**
|
||||
*
|
||||
* @param options
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createEntityAdapter<T>(
|
||||
options: EntityAdapterOptions<T, EntityId> = {},
|
||||
): EntityAdapter<T, EntityId> {
|
||||
const {
|
||||
selectId,
|
||||
sortComparer,
|
||||
}: Required<EntityAdapterOptions<T, EntityId>> = {
|
||||
sortComparer: false,
|
||||
selectId: (instance: any) => instance.id,
|
||||
...options,
|
||||
}
|
||||
|
||||
const stateAdapter = sortComparer
|
||||
? createSortedStateAdapter(selectId, sortComparer)
|
||||
: createUnsortedStateAdapter(selectId)
|
||||
const stateFactory = createInitialStateFactory(stateAdapter)
|
||||
const selectorsFactory = createSelectorsFactory<T, EntityId>()
|
||||
|
||||
return {
|
||||
selectId,
|
||||
sortComparer,
|
||||
...stateFactory,
|
||||
...selectorsFactory,
|
||||
...stateAdapter,
|
||||
}
|
||||
}
|
||||
38
frontend/node_modules/@reduxjs/toolkit/src/entities/entity_state.ts
generated
vendored
Normal file
38
frontend/node_modules/@reduxjs/toolkit/src/entities/entity_state.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import type {
|
||||
EntityId,
|
||||
EntityState,
|
||||
EntityStateAdapter,
|
||||
EntityStateFactory,
|
||||
} from './models'
|
||||
|
||||
export function getInitialEntityState<T, Id extends EntityId>(): EntityState<
|
||||
T,
|
||||
Id
|
||||
> {
|
||||
return {
|
||||
ids: [],
|
||||
entities: {} as Record<Id, T>,
|
||||
}
|
||||
}
|
||||
|
||||
export function createInitialStateFactory<T, Id extends EntityId>(
|
||||
stateAdapter: EntityStateAdapter<T, Id>,
|
||||
): EntityStateFactory<T, Id> {
|
||||
function getInitialState(
|
||||
state?: undefined,
|
||||
entities?: readonly T[] | Record<Id, T>,
|
||||
): EntityState<T, Id>
|
||||
function getInitialState<S extends object>(
|
||||
additionalState: S,
|
||||
entities?: readonly T[] | Record<Id, T>,
|
||||
): EntityState<T, Id> & S
|
||||
function getInitialState(
|
||||
additionalState: any = {},
|
||||
entities?: readonly T[] | Record<Id, T>,
|
||||
): any {
|
||||
const state = Object.assign(getInitialEntityState(), additionalState)
|
||||
return entities ? stateAdapter.setAll(state, entities) : state
|
||||
}
|
||||
|
||||
return { getInitialState }
|
||||
}
|
||||
8
frontend/node_modules/@reduxjs/toolkit/src/entities/index.ts
generated
vendored
Normal file
8
frontend/node_modules/@reduxjs/toolkit/src/entities/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export { createEntityAdapter } from './create_adapter'
|
||||
export type {
|
||||
EntityState,
|
||||
EntityAdapter,
|
||||
Update,
|
||||
IdSelector,
|
||||
Comparer,
|
||||
} from './models'
|
||||
198
frontend/node_modules/@reduxjs/toolkit/src/entities/models.ts
generated
vendored
Normal file
198
frontend/node_modules/@reduxjs/toolkit/src/entities/models.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
import type { Draft } from 'immer'
|
||||
import type { PayloadAction } from '../createAction'
|
||||
import type { CastAny, Id } from '../tsHelpers'
|
||||
import type { UncheckedIndexedAccess } from '../uncheckedindexed.js'
|
||||
import type { GetSelectorsOptions } from './state_selectors'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type EntityId = number | string
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Comparer<T> = (a: T, b: T) => number
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type IdSelector<T, Id extends EntityId> = (model: T) => Id
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Update<T, Id extends EntityId> = { id: Id; changes: Partial<T> }
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntityState<T, Id extends EntityId> {
|
||||
ids: Id[]
|
||||
entities: Record<Id, T>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntityAdapterOptions<T, Id extends EntityId> {
|
||||
selectId?: IdSelector<T, Id>
|
||||
sortComparer?: false | Comparer<T>
|
||||
}
|
||||
|
||||
export type PreventAny<S, T, Id extends EntityId> = CastAny<
|
||||
S,
|
||||
EntityState<T, Id>
|
||||
>
|
||||
|
||||
export type DraftableEntityState<T, Id extends EntityId> =
|
||||
| EntityState<T, Id>
|
||||
| Draft<EntityState<T, Id>>
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntityStateAdapter<T, Id extends EntityId> {
|
||||
addOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entity: T,
|
||||
): S
|
||||
addOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
action: PayloadAction<T>,
|
||||
): S
|
||||
|
||||
addMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: readonly T[] | Record<Id, T>,
|
||||
): S
|
||||
addMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: PayloadAction<readonly T[] | Record<Id, T>>,
|
||||
): S
|
||||
|
||||
setOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entity: T,
|
||||
): S
|
||||
setOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
action: PayloadAction<T>,
|
||||
): S
|
||||
setMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: readonly T[] | Record<Id, T>,
|
||||
): S
|
||||
setMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: PayloadAction<readonly T[] | Record<Id, T>>,
|
||||
): S
|
||||
setAll<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: readonly T[] | Record<Id, T>,
|
||||
): S
|
||||
setAll<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: PayloadAction<readonly T[] | Record<Id, T>>,
|
||||
): S
|
||||
|
||||
removeOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
key: Id,
|
||||
): S
|
||||
removeOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
key: PayloadAction<Id>,
|
||||
): S
|
||||
|
||||
removeMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
keys: readonly Id[],
|
||||
): S
|
||||
removeMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
keys: PayloadAction<readonly Id[]>,
|
||||
): S
|
||||
|
||||
removeAll<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
): S
|
||||
|
||||
updateOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
update: Update<T, Id>,
|
||||
): S
|
||||
updateOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
update: PayloadAction<Update<T, Id>>,
|
||||
): S
|
||||
|
||||
updateMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
updates: ReadonlyArray<Update<T, Id>>,
|
||||
): S
|
||||
updateMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
updates: PayloadAction<ReadonlyArray<Update<T, Id>>>,
|
||||
): S
|
||||
|
||||
upsertOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entity: T,
|
||||
): S
|
||||
upsertOne<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entity: PayloadAction<T>,
|
||||
): S
|
||||
|
||||
upsertMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: readonly T[] | Record<Id, T>,
|
||||
): S
|
||||
upsertMany<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
entities: PayloadAction<readonly T[] | Record<Id, T>>,
|
||||
): S
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntitySelectors<T, V, IdType extends EntityId> {
|
||||
selectIds: (state: V) => IdType[]
|
||||
selectEntities: (state: V) => Record<IdType, T>
|
||||
selectAll: (state: V) => T[]
|
||||
selectTotal: (state: V) => number
|
||||
selectById: (state: V, id: IdType) => Id<UncheckedIndexedAccess<T>>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntityStateFactory<T, Id extends EntityId> {
|
||||
getInitialState(
|
||||
state?: undefined,
|
||||
entities?: Record<Id, T> | readonly T[],
|
||||
): EntityState<T, Id>
|
||||
getInitialState<S extends object>(
|
||||
state: S,
|
||||
entities?: Record<Id, T> | readonly T[],
|
||||
): EntityState<T, Id> & S
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntityAdapter<T, Id extends EntityId>
|
||||
extends EntityStateAdapter<T, Id>,
|
||||
EntityStateFactory<T, Id>,
|
||||
Required<EntityAdapterOptions<T, Id>> {
|
||||
getSelectors(
|
||||
selectState?: undefined,
|
||||
options?: GetSelectorsOptions,
|
||||
): EntitySelectors<T, EntityState<T, Id>, Id>
|
||||
getSelectors<V>(
|
||||
selectState: (state: V) => EntityState<T, Id>,
|
||||
options?: GetSelectorsOptions,
|
||||
): EntitySelectors<T, V, Id>
|
||||
}
|
||||
266
frontend/node_modules/@reduxjs/toolkit/src/entities/sorted_state_adapter.ts
generated
vendored
Normal file
266
frontend/node_modules/@reduxjs/toolkit/src/entities/sorted_state_adapter.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
import type {
|
||||
IdSelector,
|
||||
Comparer,
|
||||
EntityStateAdapter,
|
||||
Update,
|
||||
EntityId,
|
||||
DraftableEntityState,
|
||||
} from './models'
|
||||
import { createStateOperator } from './state_adapter'
|
||||
import { createUnsortedStateAdapter } from './unsorted_state_adapter'
|
||||
import {
|
||||
selectIdValue,
|
||||
ensureEntitiesArray,
|
||||
splitAddedUpdatedEntities,
|
||||
getCurrent,
|
||||
} from './utils'
|
||||
|
||||
// Borrowed from Replay
|
||||
export function findInsertIndex<T>(
|
||||
sortedItems: T[],
|
||||
item: T,
|
||||
comparisonFunction: Comparer<T>,
|
||||
): number {
|
||||
let lowIndex = 0
|
||||
let highIndex = sortedItems.length
|
||||
while (lowIndex < highIndex) {
|
||||
let middleIndex = (lowIndex + highIndex) >>> 1
|
||||
const currentItem = sortedItems[middleIndex]
|
||||
const res = comparisonFunction(item, currentItem)
|
||||
if (res >= 0) {
|
||||
lowIndex = middleIndex + 1
|
||||
} else {
|
||||
highIndex = middleIndex
|
||||
}
|
||||
}
|
||||
|
||||
return lowIndex
|
||||
}
|
||||
|
||||
export function insert<T>(
|
||||
sortedItems: T[],
|
||||
item: T,
|
||||
comparisonFunction: Comparer<T>,
|
||||
): T[] {
|
||||
const insertAtIndex = findInsertIndex(sortedItems, item, comparisonFunction)
|
||||
|
||||
sortedItems.splice(insertAtIndex, 0, item)
|
||||
|
||||
return sortedItems
|
||||
}
|
||||
|
||||
export function createSortedStateAdapter<T, Id extends EntityId>(
|
||||
selectId: IdSelector<T, Id>,
|
||||
comparer: Comparer<T>,
|
||||
): EntityStateAdapter<T, Id> {
|
||||
type R = DraftableEntityState<T, Id>
|
||||
|
||||
const { removeOne, removeMany, removeAll } =
|
||||
createUnsortedStateAdapter(selectId)
|
||||
|
||||
function addOneMutably(entity: T, state: R): void {
|
||||
return addManyMutably([entity], state)
|
||||
}
|
||||
|
||||
function addManyMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
existingIds?: Id[],
|
||||
): void {
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
|
||||
const existingKeys = new Set<Id>(existingIds ?? getCurrent(state.ids))
|
||||
const addedKeys = new Set<Id>();
|
||||
const models = newEntities.filter(
|
||||
(model) => {
|
||||
const modelId = selectIdValue(model, selectId);
|
||||
const notAdded = !addedKeys.has(modelId);
|
||||
if (notAdded) addedKeys.add(modelId);
|
||||
return !existingKeys.has(modelId) && notAdded;
|
||||
}
|
||||
)
|
||||
|
||||
if (models.length !== 0) {
|
||||
mergeFunction(state, models)
|
||||
}
|
||||
}
|
||||
|
||||
function setOneMutably(entity: T, state: R): void {
|
||||
return setManyMutably([entity], state)
|
||||
}
|
||||
|
||||
function setManyMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
let deduplicatedEntities = {} as Record<Id, T>;
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
if (newEntities.length !== 0) {
|
||||
for (const item of newEntities) {
|
||||
const entityId = selectId(item);
|
||||
// For multiple items with the same ID, we should keep the last one.
|
||||
deduplicatedEntities[entityId] = item;
|
||||
delete (state.entities as Record<Id, T>)[entityId]
|
||||
}
|
||||
newEntities = ensureEntitiesArray(deduplicatedEntities);
|
||||
mergeFunction(state, newEntities)
|
||||
}
|
||||
}
|
||||
|
||||
function setAllMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
state.entities = {} as Record<Id, T>
|
||||
state.ids = []
|
||||
|
||||
addManyMutably(newEntities, state, [])
|
||||
}
|
||||
|
||||
function updateOneMutably(update: Update<T, Id>, state: R): void {
|
||||
return updateManyMutably([update], state)
|
||||
}
|
||||
|
||||
function updateManyMutably(
|
||||
updates: ReadonlyArray<Update<T, Id>>,
|
||||
state: R,
|
||||
): void {
|
||||
let appliedUpdates = false
|
||||
let replacedIds = false
|
||||
|
||||
for (let update of updates) {
|
||||
const entity: T | undefined = (state.entities as Record<Id, T>)[update.id]
|
||||
if (!entity) {
|
||||
continue
|
||||
}
|
||||
|
||||
appliedUpdates = true
|
||||
|
||||
Object.assign(entity, update.changes)
|
||||
const newId = selectId(entity)
|
||||
|
||||
if (update.id !== newId) {
|
||||
// We do support the case where updates can change an item's ID.
|
||||
// This makes things trickier - go ahead and swap the IDs in state now.
|
||||
replacedIds = true
|
||||
delete (state.entities as Record<Id, T>)[update.id]
|
||||
const oldIndex = (state.ids as Id[]).indexOf(update.id)
|
||||
state.ids[oldIndex] = newId
|
||||
;(state.entities as Record<Id, T>)[newId] = entity
|
||||
}
|
||||
}
|
||||
|
||||
if (appliedUpdates) {
|
||||
mergeFunction(state, [], appliedUpdates, replacedIds)
|
||||
}
|
||||
}
|
||||
|
||||
function upsertOneMutably(entity: T, state: R): void {
|
||||
return upsertManyMutably([entity], state)
|
||||
}
|
||||
|
||||
function upsertManyMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
const [added, updated, existingIdsArray] = splitAddedUpdatedEntities<T, Id>(
|
||||
newEntities,
|
||||
selectId,
|
||||
state,
|
||||
)
|
||||
|
||||
if (added.length) {
|
||||
addManyMutably(added, state, existingIdsArray)
|
||||
}
|
||||
if (updated.length) {
|
||||
updateManyMutably(updated, state)
|
||||
}
|
||||
}
|
||||
|
||||
function areArraysEqual(a: readonly unknown[], b: readonly unknown[]) {
|
||||
if (a.length !== b.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] === b[i]) {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type MergeFunction = (
|
||||
state: R,
|
||||
addedItems: readonly T[],
|
||||
appliedUpdates?: boolean,
|
||||
replacedIds?: boolean,
|
||||
) => void
|
||||
|
||||
const mergeFunction: MergeFunction = (
|
||||
state,
|
||||
addedItems,
|
||||
appliedUpdates,
|
||||
replacedIds,
|
||||
) => {
|
||||
const currentEntities = getCurrent(state.entities)
|
||||
const currentIds = getCurrent(state.ids)
|
||||
|
||||
const stateEntities = state.entities as Record<Id, T>
|
||||
|
||||
let ids: Iterable<Id> = currentIds
|
||||
if (replacedIds) {
|
||||
ids = new Set(currentIds)
|
||||
}
|
||||
|
||||
let sortedEntities: T[] = []
|
||||
for (const id of ids) {
|
||||
const entity = currentEntities[id]
|
||||
if (entity) {
|
||||
sortedEntities.push(entity)
|
||||
}
|
||||
}
|
||||
const wasPreviouslyEmpty = sortedEntities.length === 0
|
||||
|
||||
// Insert/overwrite all new/updated
|
||||
for (const item of addedItems) {
|
||||
stateEntities[selectId(item)] = item
|
||||
|
||||
if (!wasPreviouslyEmpty) {
|
||||
// Binary search insertion generally requires fewer comparisons
|
||||
insert(sortedEntities, item, comparer)
|
||||
}
|
||||
}
|
||||
|
||||
if (wasPreviouslyEmpty) {
|
||||
// All we have is the incoming values, sort them
|
||||
sortedEntities = addedItems.slice().sort(comparer)
|
||||
} else if (appliedUpdates) {
|
||||
// We should have a _mostly_-sorted array already
|
||||
sortedEntities.sort(comparer)
|
||||
}
|
||||
|
||||
const newSortedIds = sortedEntities.map(selectId)
|
||||
|
||||
if (!areArraysEqual(currentIds, newSortedIds)) {
|
||||
state.ids = newSortedIds
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
removeOne,
|
||||
removeMany,
|
||||
removeAll,
|
||||
addOne: createStateOperator(addOneMutably),
|
||||
updateOne: createStateOperator(updateOneMutably),
|
||||
upsertOne: createStateOperator(upsertOneMutably),
|
||||
setOne: createStateOperator(setOneMutably),
|
||||
setMany: createStateOperator(setManyMutably),
|
||||
setAll: createStateOperator(setAllMutably),
|
||||
addMany: createStateOperator(addManyMutably),
|
||||
updateMany: createStateOperator(updateManyMutably),
|
||||
upsertMany: createStateOperator(upsertManyMutably),
|
||||
}
|
||||
}
|
||||
58
frontend/node_modules/@reduxjs/toolkit/src/entities/state_adapter.ts
generated
vendored
Normal file
58
frontend/node_modules/@reduxjs/toolkit/src/entities/state_adapter.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { createNextState, isDraft } from '../immerImports'
|
||||
import type { Draft } from 'immer'
|
||||
import type { EntityId, DraftableEntityState, PreventAny } from './models'
|
||||
import type { PayloadAction } from '../createAction'
|
||||
import { isFSA } from '../createAction'
|
||||
|
||||
export const isDraftTyped = isDraft as <T>(
|
||||
value: T | Draft<T>,
|
||||
) => value is Draft<T>
|
||||
|
||||
export function createSingleArgumentStateOperator<T, Id extends EntityId>(
|
||||
mutator: (state: DraftableEntityState<T, Id>) => void,
|
||||
) {
|
||||
const operator = createStateOperator(
|
||||
(_: undefined, state: DraftableEntityState<T, Id>) => mutator(state),
|
||||
)
|
||||
|
||||
return function operation<S extends DraftableEntityState<T, Id>>(
|
||||
state: PreventAny<S, T, Id>,
|
||||
): S {
|
||||
return operator(state as S, undefined)
|
||||
}
|
||||
}
|
||||
|
||||
export function createStateOperator<T, Id extends EntityId, R>(
|
||||
mutator: (arg: R, state: DraftableEntityState<T, Id>) => void,
|
||||
) {
|
||||
return function operation<S extends DraftableEntityState<T, Id>>(
|
||||
state: S,
|
||||
arg: R | PayloadAction<R>,
|
||||
): S {
|
||||
function isPayloadActionArgument(
|
||||
arg: R | PayloadAction<R>,
|
||||
): arg is PayloadAction<R> {
|
||||
return isFSA(arg)
|
||||
}
|
||||
|
||||
const runMutator = (draft: DraftableEntityState<T, Id>) => {
|
||||
if (isPayloadActionArgument(arg)) {
|
||||
mutator(arg.payload, draft)
|
||||
} else {
|
||||
mutator(arg, draft)
|
||||
}
|
||||
}
|
||||
|
||||
if (isDraftTyped<DraftableEntityState<T, Id>>(state)) {
|
||||
// we must already be inside a `createNextState` call, likely because
|
||||
// this is being wrapped in `createReducer` or `createSlice`.
|
||||
// It's safe to just pass the draft to the mutator.
|
||||
runMutator(state)
|
||||
|
||||
// since it's a draft, we'll just return it
|
||||
return state
|
||||
}
|
||||
|
||||
return createNextState(state, runMutator)
|
||||
}
|
||||
}
|
||||
73
frontend/node_modules/@reduxjs/toolkit/src/entities/state_selectors.ts
generated
vendored
Normal file
73
frontend/node_modules/@reduxjs/toolkit/src/entities/state_selectors.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import type { CreateSelectorFunction, Selector } from 'reselect'
|
||||
import { createDraftSafeSelector } from '../createDraftSafeSelector'
|
||||
import type { EntityId, EntitySelectors, EntityState } from './models'
|
||||
|
||||
type AnyCreateSelectorFunction = CreateSelectorFunction<any, any, any>
|
||||
|
||||
export type GetSelectorsOptions = {
|
||||
createSelector?: AnyCreateSelectorFunction
|
||||
}
|
||||
|
||||
export function createSelectorsFactory<T, Id extends EntityId>() {
|
||||
function getSelectors(
|
||||
selectState?: undefined,
|
||||
options?: GetSelectorsOptions,
|
||||
): EntitySelectors<T, EntityState<T, Id>, Id>
|
||||
function getSelectors<V>(
|
||||
selectState: (state: V) => EntityState<T, Id>,
|
||||
options?: GetSelectorsOptions,
|
||||
): EntitySelectors<T, V, Id>
|
||||
function getSelectors<V>(
|
||||
selectState?: (state: V) => EntityState<T, Id>,
|
||||
options: GetSelectorsOptions = {},
|
||||
): EntitySelectors<T, any, Id> {
|
||||
const {
|
||||
createSelector = createDraftSafeSelector as AnyCreateSelectorFunction,
|
||||
} = options
|
||||
|
||||
const selectIds = (state: EntityState<T, Id>) => state.ids
|
||||
|
||||
const selectEntities = (state: EntityState<T, Id>) => state.entities
|
||||
|
||||
const selectAll = createSelector(
|
||||
selectIds,
|
||||
selectEntities,
|
||||
(ids, entities): T[] => ids.map((id) => entities[id]!),
|
||||
)
|
||||
|
||||
const selectId = (_: unknown, id: Id) => id
|
||||
|
||||
const selectById = (entities: Record<Id, T>, id: Id) => entities[id]
|
||||
|
||||
const selectTotal = createSelector(selectIds, (ids) => ids.length)
|
||||
|
||||
if (!selectState) {
|
||||
return {
|
||||
selectIds,
|
||||
selectEntities,
|
||||
selectAll,
|
||||
selectTotal,
|
||||
selectById: createSelector(selectEntities, selectId, selectById),
|
||||
}
|
||||
}
|
||||
|
||||
const selectGlobalizedEntities = createSelector(
|
||||
selectState as Selector<V, EntityState<T, Id>>,
|
||||
selectEntities,
|
||||
)
|
||||
|
||||
return {
|
||||
selectIds: createSelector(selectState, selectIds),
|
||||
selectEntities: selectGlobalizedEntities,
|
||||
selectAll: createSelector(selectState, selectAll),
|
||||
selectTotal: createSelector(selectState, selectTotal),
|
||||
selectById: createSelector(
|
||||
selectGlobalizedEntities,
|
||||
selectId,
|
||||
selectById,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
return { getSelectors }
|
||||
}
|
||||
204
frontend/node_modules/@reduxjs/toolkit/src/entities/unsorted_state_adapter.ts
generated
vendored
Normal file
204
frontend/node_modules/@reduxjs/toolkit/src/entities/unsorted_state_adapter.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import type { Draft } from 'immer'
|
||||
import type {
|
||||
EntityStateAdapter,
|
||||
IdSelector,
|
||||
Update,
|
||||
EntityId,
|
||||
DraftableEntityState,
|
||||
} from './models'
|
||||
import {
|
||||
createStateOperator,
|
||||
createSingleArgumentStateOperator,
|
||||
} from './state_adapter'
|
||||
import {
|
||||
selectIdValue,
|
||||
ensureEntitiesArray,
|
||||
splitAddedUpdatedEntities,
|
||||
} from './utils'
|
||||
|
||||
export function createUnsortedStateAdapter<T, Id extends EntityId>(
|
||||
selectId: IdSelector<T, Id>,
|
||||
): EntityStateAdapter<T, Id> {
|
||||
type R = DraftableEntityState<T, Id>
|
||||
|
||||
function addOneMutably(entity: T, state: R): void {
|
||||
const key = selectIdValue(entity, selectId)
|
||||
|
||||
if (key in state.entities) {
|
||||
return
|
||||
}
|
||||
|
||||
state.ids.push(key as Id & Draft<Id>)
|
||||
;(state.entities as Record<Id, T>)[key] = entity
|
||||
}
|
||||
|
||||
function addManyMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
|
||||
for (const entity of newEntities) {
|
||||
addOneMutably(entity, state)
|
||||
}
|
||||
}
|
||||
|
||||
function setOneMutably(entity: T, state: R): void {
|
||||
const key = selectIdValue(entity, selectId)
|
||||
if (!(key in state.entities)) {
|
||||
state.ids.push(key as Id & Draft<Id>)
|
||||
}
|
||||
;(state.entities as Record<Id, T>)[key] = entity
|
||||
}
|
||||
|
||||
function setManyMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
for (const entity of newEntities) {
|
||||
setOneMutably(entity, state)
|
||||
}
|
||||
}
|
||||
|
||||
function setAllMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
|
||||
state.ids = []
|
||||
state.entities = {} as Record<Id, T>
|
||||
|
||||
addManyMutably(newEntities, state)
|
||||
}
|
||||
|
||||
function removeOneMutably(key: Id, state: R): void {
|
||||
return removeManyMutably([key], state)
|
||||
}
|
||||
|
||||
function removeManyMutably(keys: readonly Id[], state: R): void {
|
||||
let didMutate = false
|
||||
|
||||
keys.forEach((key) => {
|
||||
if (key in state.entities) {
|
||||
delete (state.entities as Record<Id, T>)[key]
|
||||
didMutate = true
|
||||
}
|
||||
})
|
||||
|
||||
if (didMutate) {
|
||||
state.ids = (state.ids as Id[]).filter((id) => id in state.entities) as
|
||||
| Id[]
|
||||
| Draft<Id[]>
|
||||
}
|
||||
}
|
||||
|
||||
function removeAllMutably(state: R): void {
|
||||
Object.assign(state, {
|
||||
ids: [],
|
||||
entities: {},
|
||||
})
|
||||
}
|
||||
|
||||
function takeNewKey(
|
||||
keys: { [id: string]: Id },
|
||||
update: Update<T, Id>,
|
||||
state: R,
|
||||
): boolean {
|
||||
const original: T | undefined = (state.entities as Record<Id, T>)[update.id]
|
||||
if (original === undefined) {
|
||||
return false
|
||||
}
|
||||
const updated: T = Object.assign({}, original, update.changes)
|
||||
const newKey = selectIdValue(updated, selectId)
|
||||
const hasNewKey = newKey !== update.id
|
||||
|
||||
if (hasNewKey) {
|
||||
keys[update.id] = newKey
|
||||
delete (state.entities as Record<Id, T>)[update.id]
|
||||
}
|
||||
|
||||
;(state.entities as Record<Id, T>)[newKey] = updated
|
||||
|
||||
return hasNewKey
|
||||
}
|
||||
|
||||
function updateOneMutably(update: Update<T, Id>, state: R): void {
|
||||
return updateManyMutably([update], state)
|
||||
}
|
||||
|
||||
function updateManyMutably(
|
||||
updates: ReadonlyArray<Update<T, Id>>,
|
||||
state: R,
|
||||
): void {
|
||||
const newKeys: { [id: string]: Id } = {}
|
||||
|
||||
const updatesPerEntity: { [id: string]: Update<T, Id> } = {}
|
||||
|
||||
updates.forEach((update) => {
|
||||
// Only apply updates to entities that currently exist
|
||||
if (update.id in state.entities) {
|
||||
// If there are multiple updates to one entity, merge them together
|
||||
updatesPerEntity[update.id] = {
|
||||
id: update.id,
|
||||
// Spreads ignore falsy values, so this works even if there isn't
|
||||
// an existing update already at this key
|
||||
changes: {
|
||||
...updatesPerEntity[update.id]?.changes,
|
||||
...update.changes,
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
updates = Object.values(updatesPerEntity)
|
||||
|
||||
const didMutateEntities = updates.length > 0
|
||||
|
||||
if (didMutateEntities) {
|
||||
const didMutateIds =
|
||||
updates.filter((update) => takeNewKey(newKeys, update, state)).length >
|
||||
0
|
||||
|
||||
if (didMutateIds) {
|
||||
state.ids = Object.values(state.entities).map((e) =>
|
||||
selectIdValue(e as T, selectId),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function upsertOneMutably(entity: T, state: R): void {
|
||||
return upsertManyMutably([entity], state)
|
||||
}
|
||||
|
||||
function upsertManyMutably(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
state: R,
|
||||
): void {
|
||||
const [added, updated] = splitAddedUpdatedEntities<T, Id>(
|
||||
newEntities,
|
||||
selectId,
|
||||
state,
|
||||
)
|
||||
|
||||
addManyMutably(added, state)
|
||||
updateManyMutably(updated, state)
|
||||
}
|
||||
|
||||
return {
|
||||
removeAll: createSingleArgumentStateOperator(removeAllMutably),
|
||||
addOne: createStateOperator(addOneMutably),
|
||||
addMany: createStateOperator(addManyMutably),
|
||||
setOne: createStateOperator(setOneMutably),
|
||||
setMany: createStateOperator(setManyMutably),
|
||||
setAll: createStateOperator(setAllMutably),
|
||||
updateOne: createStateOperator(updateOneMutably),
|
||||
updateMany: createStateOperator(updateManyMutably),
|
||||
upsertOne: createStateOperator(upsertOneMutably),
|
||||
upsertMany: createStateOperator(upsertManyMutably),
|
||||
removeOne: createStateOperator(removeOneMutably),
|
||||
removeMany: createStateOperator(removeManyMutably),
|
||||
}
|
||||
}
|
||||
68
frontend/node_modules/@reduxjs/toolkit/src/entities/utils.ts
generated
vendored
Normal file
68
frontend/node_modules/@reduxjs/toolkit/src/entities/utils.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import type { Draft } from 'immer'
|
||||
import { current, isDraft } from '../immerImports'
|
||||
import type {
|
||||
DraftableEntityState,
|
||||
EntityId,
|
||||
IdSelector,
|
||||
Update,
|
||||
} from './models'
|
||||
|
||||
export function selectIdValue<T, Id extends EntityId>(
|
||||
entity: T,
|
||||
selectId: IdSelector<T, Id>,
|
||||
) {
|
||||
const key = selectId(entity)
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && key === undefined) {
|
||||
console.warn(
|
||||
'The entity passed to the `selectId` implementation returned undefined.',
|
||||
'You should probably provide your own `selectId` implementation.',
|
||||
'The entity that was passed:',
|
||||
entity,
|
||||
'The `selectId` implementation:',
|
||||
selectId.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
export function ensureEntitiesArray<T, Id extends EntityId>(
|
||||
entities: readonly T[] | Record<Id, T>,
|
||||
): readonly T[] {
|
||||
if (!Array.isArray(entities)) {
|
||||
entities = Object.values(entities)
|
||||
}
|
||||
|
||||
return entities
|
||||
}
|
||||
|
||||
export function getCurrent<T>(value: T | Draft<T>): T {
|
||||
return (isDraft(value) ? current(value) : value) as T
|
||||
}
|
||||
|
||||
export function splitAddedUpdatedEntities<T, Id extends EntityId>(
|
||||
newEntities: readonly T[] | Record<Id, T>,
|
||||
selectId: IdSelector<T, Id>,
|
||||
state: DraftableEntityState<T, Id>,
|
||||
): [T[], Update<T, Id>[], Id[]] {
|
||||
newEntities = ensureEntitiesArray(newEntities)
|
||||
|
||||
const existingIdsArray = getCurrent(state.ids)
|
||||
const existingIds = new Set<Id>(existingIdsArray)
|
||||
|
||||
const added: T[] = []
|
||||
const addedIds = new Set<Id>([])
|
||||
const updated: Update<T, Id>[] = []
|
||||
|
||||
for (const entity of newEntities) {
|
||||
const id = selectIdValue(entity, selectId)
|
||||
if (existingIds.has(id) || addedIds.has(id)) {
|
||||
updated.push({ id, changes: entity })
|
||||
} else {
|
||||
addedIds.add(id)
|
||||
added.push(entity)
|
||||
}
|
||||
}
|
||||
return [added, updated, existingIdsArray]
|
||||
}
|
||||
13
frontend/node_modules/@reduxjs/toolkit/src/formatProdErrorMessage.ts
generated
vendored
Normal file
13
frontend/node_modules/@reduxjs/toolkit/src/formatProdErrorMessage.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
export function formatProdErrorMessage(code: number) {
|
||||
return (
|
||||
`Minified Redux Toolkit error #${code}; visit https://redux-toolkit.js.org/Errors?code=${code} for the full message or ` +
|
||||
'use the non-minified dev environment for full errors. '
|
||||
)
|
||||
}
|
||||
31
frontend/node_modules/@reduxjs/toolkit/src/getDefaultEnhancers.ts
generated
vendored
Normal file
31
frontend/node_modules/@reduxjs/toolkit/src/getDefaultEnhancers.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import type { StoreEnhancer } from 'redux'
|
||||
import type { AutoBatchOptions } from './autoBatchEnhancer'
|
||||
import { autoBatchEnhancer } from './autoBatchEnhancer'
|
||||
import { Tuple } from './utils'
|
||||
import type { Middlewares } from './configureStore'
|
||||
import type { ExtractDispatchExtensions } from './tsHelpers'
|
||||
|
||||
type GetDefaultEnhancersOptions = {
|
||||
autoBatch?: boolean | AutoBatchOptions
|
||||
}
|
||||
|
||||
export type GetDefaultEnhancers<M extends Middlewares<any>> = (
|
||||
options?: GetDefaultEnhancersOptions,
|
||||
) => Tuple<[StoreEnhancer<{ dispatch: ExtractDispatchExtensions<M> }>]>
|
||||
|
||||
export const buildGetDefaultEnhancers = <M extends Middlewares<any>>(
|
||||
middlewareEnhancer: StoreEnhancer<{ dispatch: ExtractDispatchExtensions<M> }>,
|
||||
): GetDefaultEnhancers<M> =>
|
||||
function getDefaultEnhancers(options) {
|
||||
const { autoBatch = true } = options ?? {}
|
||||
|
||||
let enhancerArray = new Tuple<StoreEnhancer[]>(middlewareEnhancer)
|
||||
if (autoBatch) {
|
||||
enhancerArray.push(
|
||||
autoBatchEnhancer(
|
||||
typeof autoBatch === 'object' ? autoBatch : undefined,
|
||||
),
|
||||
)
|
||||
}
|
||||
return enhancerArray as any
|
||||
}
|
||||
113
frontend/node_modules/@reduxjs/toolkit/src/getDefaultMiddleware.ts
generated
vendored
Normal file
113
frontend/node_modules/@reduxjs/toolkit/src/getDefaultMiddleware.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import type { Middleware, UnknownAction } from 'redux'
|
||||
import type { ThunkMiddleware } from 'redux-thunk'
|
||||
import { thunk as thunkMiddleware, withExtraArgument } from 'redux-thunk'
|
||||
import type { ActionCreatorInvariantMiddlewareOptions } from './actionCreatorInvariantMiddleware'
|
||||
import { createActionCreatorInvariantMiddleware } from './actionCreatorInvariantMiddleware'
|
||||
import type { ImmutableStateInvariantMiddlewareOptions } from './immutableStateInvariantMiddleware'
|
||||
/* PROD_START_REMOVE_UMD */
|
||||
import { createImmutableStateInvariantMiddleware } from './immutableStateInvariantMiddleware'
|
||||
/* PROD_STOP_REMOVE_UMD */
|
||||
|
||||
import type { SerializableStateInvariantMiddlewareOptions } from './serializableStateInvariantMiddleware'
|
||||
import { createSerializableStateInvariantMiddleware } from './serializableStateInvariantMiddleware'
|
||||
import type { ExcludeFromTuple } from './tsHelpers'
|
||||
import { Tuple } from './utils'
|
||||
|
||||
function isBoolean(x: any): x is boolean {
|
||||
return typeof x === 'boolean'
|
||||
}
|
||||
|
||||
interface ThunkOptions<E = any> {
|
||||
extraArgument: E
|
||||
}
|
||||
|
||||
interface GetDefaultMiddlewareOptions {
|
||||
thunk?: boolean | ThunkOptions
|
||||
immutableCheck?: boolean | ImmutableStateInvariantMiddlewareOptions
|
||||
serializableCheck?: boolean | SerializableStateInvariantMiddlewareOptions
|
||||
actionCreatorCheck?: boolean | ActionCreatorInvariantMiddlewareOptions
|
||||
}
|
||||
|
||||
export type ThunkMiddlewareFor<
|
||||
S,
|
||||
O extends GetDefaultMiddlewareOptions = {},
|
||||
> = O extends {
|
||||
thunk: false
|
||||
}
|
||||
? never
|
||||
: O extends { thunk: { extraArgument: infer E } }
|
||||
? ThunkMiddleware<S, UnknownAction, E>
|
||||
: ThunkMiddleware<S, UnknownAction>
|
||||
|
||||
export type GetDefaultMiddleware<S = any> = <
|
||||
O extends GetDefaultMiddlewareOptions = {
|
||||
thunk: true
|
||||
immutableCheck: true
|
||||
serializableCheck: true
|
||||
actionCreatorCheck: true
|
||||
},
|
||||
>(
|
||||
options?: O,
|
||||
) => Tuple<ExcludeFromTuple<[ThunkMiddlewareFor<S, O>], never>>
|
||||
|
||||
export const buildGetDefaultMiddleware = <S = any>(): GetDefaultMiddleware<S> =>
|
||||
function getDefaultMiddleware(options) {
|
||||
const {
|
||||
thunk = true,
|
||||
immutableCheck = true,
|
||||
serializableCheck = true,
|
||||
actionCreatorCheck = true,
|
||||
} = options ?? {}
|
||||
|
||||
let middlewareArray = new Tuple<Middleware[]>()
|
||||
|
||||
if (thunk) {
|
||||
if (isBoolean(thunk)) {
|
||||
middlewareArray.push(thunkMiddleware)
|
||||
} else {
|
||||
middlewareArray.push(withExtraArgument(thunk.extraArgument))
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (immutableCheck) {
|
||||
/* PROD_START_REMOVE_UMD */
|
||||
let immutableOptions: ImmutableStateInvariantMiddlewareOptions = {}
|
||||
|
||||
if (!isBoolean(immutableCheck)) {
|
||||
immutableOptions = immutableCheck
|
||||
}
|
||||
|
||||
middlewareArray.unshift(
|
||||
createImmutableStateInvariantMiddleware(immutableOptions),
|
||||
)
|
||||
/* PROD_STOP_REMOVE_UMD */
|
||||
}
|
||||
|
||||
if (serializableCheck) {
|
||||
let serializableOptions: SerializableStateInvariantMiddlewareOptions =
|
||||
{}
|
||||
|
||||
if (!isBoolean(serializableCheck)) {
|
||||
serializableOptions = serializableCheck
|
||||
}
|
||||
|
||||
middlewareArray.push(
|
||||
createSerializableStateInvariantMiddleware(serializableOptions),
|
||||
)
|
||||
}
|
||||
if (actionCreatorCheck) {
|
||||
let actionCreatorOptions: ActionCreatorInvariantMiddlewareOptions = {}
|
||||
|
||||
if (!isBoolean(actionCreatorCheck)) {
|
||||
actionCreatorOptions = actionCreatorCheck
|
||||
}
|
||||
|
||||
middlewareArray.unshift(
|
||||
createActionCreatorInvariantMiddleware(actionCreatorOptions),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return middlewareArray as any
|
||||
}
|
||||
7
frontend/node_modules/@reduxjs/toolkit/src/immerImports.ts
generated
vendored
Normal file
7
frontend/node_modules/@reduxjs/toolkit/src/immerImports.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export {
|
||||
current,
|
||||
isDraft,
|
||||
produce as createNextState,
|
||||
isDraftable,
|
||||
setUseStrictIteration,
|
||||
} from 'immer'
|
||||
274
frontend/node_modules/@reduxjs/toolkit/src/immutableStateInvariantMiddleware.ts
generated
vendored
Normal file
274
frontend/node_modules/@reduxjs/toolkit/src/immutableStateInvariantMiddleware.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
import type { Middleware } from 'redux'
|
||||
import type { IgnoredPaths } from './serializableStateInvariantMiddleware'
|
||||
import { getTimeMeasureUtils } from './utils'
|
||||
|
||||
type EntryProcessor = (key: string, value: any) => any
|
||||
|
||||
/**
|
||||
* The default `isImmutable` function.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function isImmutableDefault(value: unknown): boolean {
|
||||
return typeof value !== 'object' || value == null || Object.isFrozen(value)
|
||||
}
|
||||
|
||||
export function trackForMutations(
|
||||
isImmutable: IsImmutableFunc,
|
||||
ignoredPaths: IgnoredPaths | undefined,
|
||||
obj: any,
|
||||
) {
|
||||
const trackedProperties = trackProperties(isImmutable, ignoredPaths, obj)
|
||||
return {
|
||||
detectMutations() {
|
||||
return detectMutations(isImmutable, ignoredPaths, trackedProperties, obj)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
interface TrackedProperty {
|
||||
value: any
|
||||
children: Record<string, any>
|
||||
}
|
||||
|
||||
function trackProperties(
|
||||
isImmutable: IsImmutableFunc,
|
||||
ignoredPaths: IgnoredPaths = [],
|
||||
obj: Record<string, any>,
|
||||
path: string = '',
|
||||
checkedObjects: Set<Record<string, any>> = new Set(),
|
||||
) {
|
||||
const tracked: Partial<TrackedProperty> = { value: obj }
|
||||
|
||||
if (!isImmutable(obj) && !checkedObjects.has(obj)) {
|
||||
checkedObjects.add(obj)
|
||||
tracked.children = {}
|
||||
|
||||
const hasIgnoredPaths = ignoredPaths.length > 0
|
||||
|
||||
for (const key in obj) {
|
||||
const nestedPath = path ? path + '.' + key : key
|
||||
|
||||
if (hasIgnoredPaths) {
|
||||
const hasMatches = ignoredPaths.some((ignored) => {
|
||||
if (ignored instanceof RegExp) {
|
||||
return ignored.test(nestedPath)
|
||||
}
|
||||
return nestedPath === ignored
|
||||
})
|
||||
if (hasMatches) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
tracked.children[key] = trackProperties(
|
||||
isImmutable,
|
||||
ignoredPaths,
|
||||
obj[key],
|
||||
nestedPath,
|
||||
)
|
||||
}
|
||||
}
|
||||
return tracked as TrackedProperty
|
||||
}
|
||||
|
||||
function detectMutations(
|
||||
isImmutable: IsImmutableFunc,
|
||||
ignoredPaths: IgnoredPaths = [],
|
||||
trackedProperty: TrackedProperty,
|
||||
obj: any,
|
||||
sameParentRef: boolean = false,
|
||||
path: string = '',
|
||||
): { wasMutated: boolean; path?: string } {
|
||||
const prevObj = trackedProperty ? trackedProperty.value : undefined
|
||||
|
||||
const sameRef = prevObj === obj
|
||||
|
||||
if (sameParentRef && !sameRef && !Number.isNaN(obj)) {
|
||||
return { wasMutated: true, path }
|
||||
}
|
||||
|
||||
if (isImmutable(prevObj) || isImmutable(obj)) {
|
||||
return { wasMutated: false }
|
||||
}
|
||||
|
||||
// Gather all keys from prev (tracked) and after objs
|
||||
const keysToDetect: Record<string, boolean> = {}
|
||||
for (let key in trackedProperty.children) {
|
||||
keysToDetect[key] = true
|
||||
}
|
||||
for (let key in obj) {
|
||||
keysToDetect[key] = true
|
||||
}
|
||||
|
||||
const hasIgnoredPaths = ignoredPaths.length > 0
|
||||
|
||||
for (let key in keysToDetect) {
|
||||
const nestedPath = path ? path + '.' + key : key
|
||||
|
||||
if (hasIgnoredPaths) {
|
||||
const hasMatches = ignoredPaths.some((ignored) => {
|
||||
if (ignored instanceof RegExp) {
|
||||
return ignored.test(nestedPath)
|
||||
}
|
||||
return nestedPath === ignored
|
||||
})
|
||||
if (hasMatches) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
const result = detectMutations(
|
||||
isImmutable,
|
||||
ignoredPaths,
|
||||
trackedProperty.children[key],
|
||||
obj[key],
|
||||
sameRef,
|
||||
nestedPath,
|
||||
)
|
||||
|
||||
if (result.wasMutated) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return { wasMutated: false }
|
||||
}
|
||||
|
||||
type IsImmutableFunc = (value: any) => boolean
|
||||
|
||||
/**
|
||||
* Options for `createImmutableStateInvariantMiddleware()`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ImmutableStateInvariantMiddlewareOptions {
|
||||
/**
|
||||
Callback function to check if a value is considered to be immutable.
|
||||
This function is applied recursively to every value contained in the state.
|
||||
The default implementation will return true for primitive types
|
||||
(like numbers, strings, booleans, null and undefined).
|
||||
*/
|
||||
isImmutable?: IsImmutableFunc
|
||||
/**
|
||||
An array of dot-separated path strings that match named nodes from
|
||||
the root state to ignore when checking for immutability.
|
||||
Defaults to undefined
|
||||
*/
|
||||
ignoredPaths?: IgnoredPaths
|
||||
/** Print a warning if checks take longer than N ms. Default: 32ms */
|
||||
warnAfter?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a middleware that checks whether any state was mutated in between
|
||||
* dispatches or during a dispatch. If any mutations are detected, an error is
|
||||
* thrown.
|
||||
*
|
||||
* @param options Middleware options.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createImmutableStateInvariantMiddleware(
|
||||
options: ImmutableStateInvariantMiddlewareOptions = {},
|
||||
): Middleware {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return () => (next) => (action) => next(action)
|
||||
} else {
|
||||
function stringify(
|
||||
obj: any,
|
||||
serializer?: EntryProcessor,
|
||||
indent?: string | number,
|
||||
decycler?: EntryProcessor,
|
||||
): string {
|
||||
return JSON.stringify(obj, getSerialize(serializer, decycler), indent)
|
||||
}
|
||||
|
||||
function getSerialize(
|
||||
serializer?: EntryProcessor,
|
||||
decycler?: EntryProcessor,
|
||||
): EntryProcessor {
|
||||
let stack: any[] = [],
|
||||
keys: any[] = []
|
||||
|
||||
if (!decycler)
|
||||
decycler = function (_: string, value: any) {
|
||||
if (stack[0] === value) return '[Circular ~]'
|
||||
return (
|
||||
'[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']'
|
||||
)
|
||||
}
|
||||
|
||||
return function (this: any, key: string, value: any) {
|
||||
if (stack.length > 0) {
|
||||
var thisPos = stack.indexOf(this)
|
||||
~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
|
||||
~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
|
||||
if (~stack.indexOf(value)) value = decycler!.call(this, key, value)
|
||||
} else stack.push(value)
|
||||
|
||||
return serializer == null ? value : serializer.call(this, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
let {
|
||||
isImmutable = isImmutableDefault,
|
||||
ignoredPaths,
|
||||
warnAfter = 32,
|
||||
} = options
|
||||
|
||||
const track = trackForMutations.bind(null, isImmutable, ignoredPaths)
|
||||
|
||||
return ({ getState }) => {
|
||||
let state = getState()
|
||||
let tracker = track(state)
|
||||
|
||||
let result
|
||||
return (next) => (action) => {
|
||||
const measureUtils = getTimeMeasureUtils(
|
||||
warnAfter,
|
||||
'ImmutableStateInvariantMiddleware',
|
||||
)
|
||||
|
||||
measureUtils.measureTime(() => {
|
||||
state = getState()
|
||||
|
||||
result = tracker.detectMutations()
|
||||
// Track before potentially not meeting the invariant
|
||||
tracker = track(state)
|
||||
|
||||
if (result.wasMutated) {
|
||||
throw new Error(
|
||||
`A state mutation was detected between dispatches, in the path '${
|
||||
result.path || ''
|
||||
}'. This may cause incorrect behavior. (https://redux.js.org/style-guide/style-guide#do-not-mutate-state)`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const dispatchedAction = next(action)
|
||||
|
||||
measureUtils.measureTime(() => {
|
||||
state = getState()
|
||||
|
||||
result = tracker.detectMutations()
|
||||
// Track before potentially not meeting the invariant
|
||||
tracker = track(state)
|
||||
|
||||
if (result.wasMutated) {
|
||||
throw new Error(
|
||||
`A state mutation was detected inside a dispatch, in the path: ${
|
||||
result.path || ''
|
||||
}. Take a look at the reducer(s) handling the action ${stringify(
|
||||
action,
|
||||
)}. (https://redux.js.org/style-guide/style-guide#do-not-mutate-state)`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
measureUtils.warnIfExceeded()
|
||||
|
||||
return dispatchedAction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
213
frontend/node_modules/@reduxjs/toolkit/src/index.ts
generated
vendored
Normal file
213
frontend/node_modules/@reduxjs/toolkit/src/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
// This must remain here so that the `mangleErrors.cjs` build script
|
||||
// does not have to import this into each source file it rewrites.
|
||||
import { formatProdErrorMessage } from './formatProdErrorMessage'
|
||||
|
||||
export * from 'redux'
|
||||
export { freeze, original } from 'immer'
|
||||
export { createNextState, current, isDraft } from './immerImports'
|
||||
export type { Draft, WritableDraft } from 'immer'
|
||||
export { createSelector, lruMemoize } from 'reselect'
|
||||
export { createSelectorCreator, weakMapMemoize } from './reselectImports'
|
||||
export type { Selector, OutputSelector } from 'reselect'
|
||||
export {
|
||||
createDraftSafeSelector,
|
||||
createDraftSafeSelectorCreator,
|
||||
} from './createDraftSafeSelector'
|
||||
export type { ThunkAction, ThunkDispatch, ThunkMiddleware } from 'redux-thunk'
|
||||
|
||||
export {
|
||||
// js
|
||||
configureStore,
|
||||
} from './configureStore'
|
||||
export type {
|
||||
// types
|
||||
ConfigureStoreOptions,
|
||||
EnhancedStore,
|
||||
} from './configureStore'
|
||||
export type { DevToolsEnhancerOptions } from './devtoolsExtension'
|
||||
export {
|
||||
// js
|
||||
createAction,
|
||||
isActionCreator,
|
||||
isFSA as isFluxStandardAction,
|
||||
} from './createAction'
|
||||
export type {
|
||||
// types
|
||||
PayloadAction,
|
||||
PayloadActionCreator,
|
||||
ActionCreatorWithNonInferrablePayload,
|
||||
ActionCreatorWithOptionalPayload,
|
||||
ActionCreatorWithPayload,
|
||||
ActionCreatorWithoutPayload,
|
||||
ActionCreatorWithPreparedPayload,
|
||||
PrepareAction,
|
||||
} from './createAction'
|
||||
export {
|
||||
// js
|
||||
createReducer,
|
||||
} from './createReducer'
|
||||
export type {
|
||||
// types
|
||||
Actions,
|
||||
CaseReducer,
|
||||
CaseReducers,
|
||||
} from './createReducer'
|
||||
export {
|
||||
// js
|
||||
createSlice,
|
||||
buildCreateSlice,
|
||||
asyncThunkCreator,
|
||||
ReducerType,
|
||||
} from './createSlice'
|
||||
|
||||
export type {
|
||||
// types
|
||||
CreateSliceOptions,
|
||||
Slice,
|
||||
CaseReducerActions,
|
||||
SliceCaseReducers,
|
||||
ValidateSliceCaseReducers,
|
||||
CaseReducerWithPrepare,
|
||||
ReducerCreators,
|
||||
SliceSelectors,
|
||||
} from './createSlice'
|
||||
export type { ActionCreatorInvariantMiddlewareOptions } from './actionCreatorInvariantMiddleware'
|
||||
export { createActionCreatorInvariantMiddleware } from './actionCreatorInvariantMiddleware'
|
||||
export {
|
||||
// js
|
||||
createImmutableStateInvariantMiddleware,
|
||||
isImmutableDefault,
|
||||
} from './immutableStateInvariantMiddleware'
|
||||
export type {
|
||||
// types
|
||||
ImmutableStateInvariantMiddlewareOptions,
|
||||
} from './immutableStateInvariantMiddleware'
|
||||
export {
|
||||
// js
|
||||
createSerializableStateInvariantMiddleware,
|
||||
findNonSerializableValue,
|
||||
isPlain,
|
||||
} from './serializableStateInvariantMiddleware'
|
||||
export type {
|
||||
// types
|
||||
SerializableStateInvariantMiddlewareOptions,
|
||||
} from './serializableStateInvariantMiddleware'
|
||||
export type {
|
||||
// types
|
||||
ActionReducerMapBuilder,
|
||||
AsyncThunkReducers,
|
||||
} from './mapBuilders'
|
||||
export { Tuple } from './utils'
|
||||
|
||||
export { createEntityAdapter } from './entities/create_adapter'
|
||||
export type {
|
||||
EntityState,
|
||||
EntityAdapter,
|
||||
EntitySelectors,
|
||||
EntityStateAdapter,
|
||||
EntityId,
|
||||
Update,
|
||||
IdSelector,
|
||||
Comparer,
|
||||
} from './entities/models'
|
||||
|
||||
export {
|
||||
createAsyncThunk,
|
||||
unwrapResult,
|
||||
miniSerializeError,
|
||||
} from './createAsyncThunk'
|
||||
export type {
|
||||
AsyncThunk,
|
||||
AsyncThunkConfig,
|
||||
AsyncThunkDispatchConfig,
|
||||
AsyncThunkOptions,
|
||||
AsyncThunkAction,
|
||||
AsyncThunkPayloadCreatorReturnValue,
|
||||
AsyncThunkPayloadCreator,
|
||||
GetState,
|
||||
GetThunkAPI,
|
||||
SerializedError,
|
||||
CreateAsyncThunkFunction,
|
||||
} from './createAsyncThunk'
|
||||
|
||||
export {
|
||||
// js
|
||||
isAllOf,
|
||||
isAnyOf,
|
||||
isPending,
|
||||
isRejected,
|
||||
isFulfilled,
|
||||
isAsyncThunkAction,
|
||||
isRejectedWithValue,
|
||||
} from './matchers'
|
||||
export type {
|
||||
// types
|
||||
ActionMatchingAllOf,
|
||||
ActionMatchingAnyOf,
|
||||
} from './matchers'
|
||||
|
||||
export { nanoid } from './nanoid'
|
||||
|
||||
export type {
|
||||
ListenerEffect,
|
||||
ListenerMiddleware,
|
||||
ListenerEffectAPI,
|
||||
ListenerMiddlewareInstance,
|
||||
CreateListenerMiddlewareOptions,
|
||||
ListenerErrorHandler,
|
||||
TypedStartListening,
|
||||
TypedAddListener,
|
||||
TypedStopListening,
|
||||
TypedRemoveListener,
|
||||
UnsubscribeListener,
|
||||
UnsubscribeListenerOptions,
|
||||
ForkedTaskExecutor,
|
||||
ForkedTask,
|
||||
ForkedTaskAPI,
|
||||
AsyncTaskExecutor,
|
||||
SyncTaskExecutor,
|
||||
TaskCancelled,
|
||||
TaskRejected,
|
||||
TaskResolved,
|
||||
TaskResult,
|
||||
} from './listenerMiddleware/index'
|
||||
export type { AnyListenerPredicate } from './listenerMiddleware/types'
|
||||
|
||||
export {
|
||||
createListenerMiddleware,
|
||||
addListener,
|
||||
removeListener,
|
||||
clearAllListeners,
|
||||
TaskAbortError,
|
||||
} from './listenerMiddleware/index'
|
||||
|
||||
export type {
|
||||
AddMiddleware,
|
||||
DynamicDispatch,
|
||||
DynamicMiddlewareInstance,
|
||||
GetDispatchType as GetDispatch,
|
||||
MiddlewareApiConfig,
|
||||
} from './dynamicMiddleware/types'
|
||||
export { createDynamicMiddleware } from './dynamicMiddleware/index'
|
||||
|
||||
export {
|
||||
SHOULD_AUTOBATCH,
|
||||
prepareAutoBatched,
|
||||
autoBatchEnhancer,
|
||||
} from './autoBatchEnhancer'
|
||||
export type { AutoBatchOptions } from './autoBatchEnhancer'
|
||||
|
||||
export { combineSlices } from './combineSlices'
|
||||
|
||||
export type {
|
||||
CombinedSliceReducer,
|
||||
WithSlice,
|
||||
WithSlicePreloadedState,
|
||||
} from './combineSlices'
|
||||
|
||||
export type {
|
||||
ExtractDispatchExtensions as TSHelpersExtractDispatchExtensions,
|
||||
SafePromise,
|
||||
} from './tsHelpers'
|
||||
|
||||
export { formatProdErrorMessage } from './formatProdErrorMessage'
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue