diff --git a/examples/query/react/infinite-queries/.eslintrc.json b/examples/query/react/infinite-queries/.eslintrc.json new file mode 100644 index 0000000000..e41a5aee79 --- /dev/null +++ b/examples/query/react/infinite-queries/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": [ + "eslint:recommended", + "react-app", + "plugin:react/jsx-runtime", + "prettier" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { "project": true, "tsconfigRootDir": "./" }, + "plugins": ["@typescript-eslint"], + "root": true, + "ignorePatterns": ["dist"], + "rules": { + "@typescript-eslint/consistent-type-imports": [ + 2, + { "fixStyle": "separate-type-imports" } + ], + "@typescript-eslint/no-restricted-imports": [ + 2, + { + "paths": [ + { + "name": "react-redux", + "importNames": ["useSelector", "useStore", "useDispatch"], + "message": "Please use pre-typed versions from `src/app/hooks.ts` instead." + } + ] + } + ] + }, + "overrides": [ + { "files": ["*.{c,m,}{t,j}s", "*.{t,j}sx"] }, + { "files": ["*{test,spec}.{t,j}s?(x)"], "env": { "jest": true } } + ] +} diff --git a/examples/query/react/infinite-queries/.gitignore b/examples/query/react/infinite-queries/.gitignore new file mode 100644 index 0000000000..a0fe5fd01e --- /dev/null +++ b/examples/query/react/infinite-queries/.gitignore @@ -0,0 +1,36 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +typesversions +.cache +.yarnrc +.yarn/* +!.yarn/patches +!.yarn/releases +!.yarn/plugins +!.yarn/sdks +!.yarn/versions +.pnp.* +*.tgz \ No newline at end of file diff --git a/examples/query/react/infinite-queries/.prettierrc.json b/examples/query/react/infinite-queries/.prettierrc.json new file mode 100644 index 0000000000..18b9c97f02 --- /dev/null +++ b/examples/query/react/infinite-queries/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "semi": false, + "arrowParens": "avoid" +} diff --git a/examples/query/react/infinite-queries/README.md b/examples/query/react/infinite-queries/README.md new file mode 100644 index 0000000000..7247e9edb7 --- /dev/null +++ b/examples/query/react/infinite-queries/README.md @@ -0,0 +1,27 @@ +# vite-template-redux + +Uses [Vite](https://vitejs.dev/), [Vitest](https://vitest.dev/), and [React Testing Library](https://github.com/testing-library/react-testing-library) to create a modern [React](https://react.dev/) app compatible with [Create React App](https://create-react-app.dev/) + +```sh +npx degit reduxjs/redux-templates/packages/vite-template-redux my-app +``` + +## Goals + +- Easy migration from Create React App or Vite +- As beginner friendly as Create React App +- Optimized performance compared to Create React App +- Customizable without ejecting + +## Scripts + +- `dev`/`start` - start dev server and open browser +- `build` - build for production +- `preview` - locally preview production build +- `test` - launch test runner + +## Inspiration + +- [Create React App](https://github.com/facebook/create-react-app/tree/main/packages/cra-template) +- [Vite](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react) +- [Vitest](https://github.com/vitest-dev/vitest/tree/main/examples/react-testing-lib) diff --git a/examples/query/react/infinite-queries/index.html b/examples/query/react/infinite-queries/index.html new file mode 100644 index 0000000000..b5fae3da23 --- /dev/null +++ b/examples/query/react/infinite-queries/index.html @@ -0,0 +1,14 @@ + + + + + + + React Redux App + + + +
+ + + diff --git a/examples/query/react/infinite-queries/package.json b/examples/query/react/infinite-queries/package.json new file mode 100644 index 0000000000..933e07886d --- /dev/null +++ b/examples/query/react/infinite-queries/package.json @@ -0,0 +1,45 @@ +{ + "name": "vite-template-redux", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "start": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "test": "vitest run", + "format": "prettier --write .", + "lint": "eslint .", + "lint:fix": "eslint --fix .", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@reduxjs/toolkit": "https://pkg.csb.dev/reduxjs/redux-toolkit/commit/aa419c22/@reduxjs/toolkit/_pkg.tgz", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-intersection-observer": "^9.13.1", + "react-redux": "^9.1.0", + "react-router": "^7.0.1" + }, + "devDependencies": { + "@testing-library/dom": "^9.3.4", + "@testing-library/jest-dom": "^6.2.0", + "@testing-library/react": "^14.1.2", + "@testing-library/user-event": "^14.5.2", + "@types/react": "^18.2.47", + "@types/react-dom": "^18.2.18", + "@vitejs/plugin-react": "^4.2.1", + "jsdom": "^23.2.0", + "msw": "^2.6.6", + "prettier": "^3.2.1", + "typescript": "^5.3.3", + "vite": "^5.0.0", + "vitest": "^1.2.0" + }, + "msw": { + "workerDirectory": [ + "public" + ] + } +} diff --git a/examples/query/react/infinite-queries/public/mockServiceWorker.js b/examples/query/react/infinite-queries/public/mockServiceWorker.js new file mode 100644 index 0000000000..fead0b3ff9 --- /dev/null +++ b/examples/query/react/infinite-queries/public/mockServiceWorker.js @@ -0,0 +1,295 @@ +/* eslint-disable */ +/* tslint:disable */ + +/** + * Mock Service Worker. + * @see https://github.com/mswjs/msw + * - Please do NOT modify this file. + * - Please do NOT serve this file on production. + */ + +const PACKAGE_VERSION = '2.6.6' +const INTEGRITY_CHECKSUM = 'ca7800994cc8bfb5eb961e037c877074' +const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') +const activeClientIds = new Set() + +self.addEventListener('install', function () { + self.skipWaiting() +}) + +self.addEventListener('activate', function (event) { + event.waitUntil(self.clients.claim()) +}) + +self.addEventListener('message', async function (event) { + const clientId = event.source.id + + if (!clientId || !self.clients) { + return + } + + const client = await self.clients.get(clientId) + + if (!client) { + return + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }) + + switch (event.data) { + case 'KEEPALIVE_REQUEST': { + sendToClient(client, { + type: 'KEEPALIVE_RESPONSE', + }) + break + } + + case 'INTEGRITY_CHECK_REQUEST': { + sendToClient(client, { + type: 'INTEGRITY_CHECK_RESPONSE', + payload: { + packageVersion: PACKAGE_VERSION, + checksum: INTEGRITY_CHECKSUM, + }, + }) + break + } + + case 'MOCK_ACTIVATE': { + activeClientIds.add(clientId) + + sendToClient(client, { + type: 'MOCKING_ENABLED', + payload: { + client: { + id: client.id, + frameType: client.frameType, + }, + }, + }) + break + } + + case 'MOCK_DEACTIVATE': { + activeClientIds.delete(clientId) + break + } + + case 'CLIENT_CLOSED': { + activeClientIds.delete(clientId) + + const remainingClients = allClients.filter((client) => { + return client.id !== clientId + }) + + // Unregister itself when there are no more clients + if (remainingClients.length === 0) { + self.registration.unregister() + } + + break + } + } +}) + +self.addEventListener('fetch', function (event) { + const { request } = event + + // Bypass navigation requests. + if (request.mode === 'navigate') { + return + } + + // Opening the DevTools triggers the "only-if-cached" request + // that cannot be handled by the worker. Bypass such requests. + if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { + return + } + + // Bypass all requests when there are no active clients. + // Prevents the self-unregistered worked from handling requests + // after it's been deleted (still remains active until the next reload). + if (activeClientIds.size === 0) { + return + } + + // Generate unique request ID. + const requestId = crypto.randomUUID() + event.respondWith(handleRequest(event, requestId)) +}) + +async function handleRequest(event, requestId) { + const client = await resolveMainClient(event) + const response = await getResponse(event, client, requestId) + + // Send back the response clone for the "response:*" life-cycle events. + // Ensure MSW is active and ready to handle the message, otherwise + // this message will pend indefinitely. + if (client && activeClientIds.has(client.id)) { + ;(async function () { + const responseClone = response.clone() + + sendToClient( + client, + { + type: 'RESPONSE', + payload: { + requestId, + isMockedResponse: IS_MOCKED_RESPONSE in response, + type: responseClone.type, + status: responseClone.status, + statusText: responseClone.statusText, + body: responseClone.body, + headers: Object.fromEntries(responseClone.headers.entries()), + }, + }, + [responseClone.body], + ) + })() + } + + return response +} + +// Resolve the main client for the given event. +// Client that issues a request doesn't necessarily equal the client +// that registered the worker. It's with the latter the worker should +// communicate with during the response resolving phase. +async function resolveMainClient(event) { + const client = await self.clients.get(event.clientId) + + if (activeClientIds.has(event.clientId)) { + return client + } + + if (client?.frameType === 'top-level') { + return client + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }) + + return allClients + .filter((client) => { + // Get only those clients that are currently visible. + return client.visibilityState === 'visible' + }) + .find((client) => { + // Find the client ID that's recorded in the + // set of clients that have registered the worker. + return activeClientIds.has(client.id) + }) +} + +async function getResponse(event, client, requestId) { + const { request } = event + + // Clone the request because it might've been already used + // (i.e. its body has been read and sent to the client). + const requestClone = request.clone() + + function passthrough() { + // Cast the request headers to a new Headers instance + // so the headers can be manipulated with. + const headers = new Headers(requestClone.headers) + + // Remove the "accept" header value that marked this request as passthrough. + // This prevents request alteration and also keeps it compliant with the + // user-defined CORS policies. + headers.delete('accept', 'msw/passthrough') + + return fetch(requestClone, { headers }) + } + + // Bypass mocking when the client is not active. + if (!client) { + return passthrough() + } + + // Bypass initial page load requests (i.e. static assets). + // The absence of the immediate/parent client in the map of the active clients + // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet + // and is not ready to handle requests. + if (!activeClientIds.has(client.id)) { + return passthrough() + } + + // Notify the client that a request has been intercepted. + const requestBuffer = await request.arrayBuffer() + const clientMessage = await sendToClient( + client, + { + type: 'REQUEST', + payload: { + id: requestId, + url: request.url, + mode: request.mode, + method: request.method, + headers: Object.fromEntries(request.headers.entries()), + cache: request.cache, + credentials: request.credentials, + destination: request.destination, + integrity: request.integrity, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + body: requestBuffer, + keepalive: request.keepalive, + }, + }, + [requestBuffer], + ) + + switch (clientMessage.type) { + case 'MOCK_RESPONSE': { + return respondWithMock(clientMessage.data) + } + + case 'PASSTHROUGH': { + return passthrough() + } + } + + return passthrough() +} + +function sendToClient(client, message, transferrables = []) { + return new Promise((resolve, reject) => { + const channel = new MessageChannel() + + channel.port1.onmessage = (event) => { + if (event.data && event.data.error) { + return reject(event.data.error) + } + + resolve(event.data) + } + + client.postMessage( + message, + [channel.port2].concat(transferrables.filter(Boolean)), + ) + }) +} + +async function respondWithMock(response) { + // Setting response status code to 0 is a no-op. + // However, when responding with a "Response.error()", the produced Response + // instance will have status code set to 0. Since it's not possible to create + // a Response instance with status code 0, handle that use-case separately. + if (response.status === 0) { + return Response.error() + } + + const mockedResponse = new Response(response.body, response) + + Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { + value: true, + enumerable: true, + }) + + return mockedResponse +} diff --git a/examples/query/react/infinite-queries/src/App.css b/examples/query/react/infinite-queries/src/App.css new file mode 100644 index 0000000000..d757820542 --- /dev/null +++ b/examples/query/react/infinite-queries/src/App.css @@ -0,0 +1,39 @@ +.App { + margin: 1rem; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-float infinite 3s ease-in-out; + } +} + +.App-header { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} + +.App-link { + color: rgb(112, 76, 182); +} + +@keyframes App-logo-float { + 0% { + transform: translateY(0); + } + 50% { + transform: translateY(10px); + } + 100% { + transform: translateY(0px); + } +} diff --git a/examples/query/react/infinite-queries/src/App.test.tsx b/examples/query/react/infinite-queries/src/App.test.tsx new file mode 100644 index 0000000000..06b45be816 --- /dev/null +++ b/examples/query/react/infinite-queries/src/App.test.tsx @@ -0,0 +1,105 @@ +import { screen, waitFor } from "@testing-library/react" +import App from "./App" +import { renderWithProviders } from "./utils/test-utils" + +test("App should have correct initial render", () => { + renderWithProviders() + + // The app should be rendered correctly + expect(screen.getByText(/learn/i)).toBeInTheDocument() + + // Initial state: count should be 0, incrementValue should be 2 + expect(screen.getByLabelText("Count")).toHaveTextContent("0") + expect(screen.getByLabelText("Set increment amount")).toHaveValue(2) +}) + +test("Increment value and Decrement value should work as expected", async () => { + const { user } = renderWithProviders() + + // Click on "+" => Count should be 1 + await user.click(screen.getByLabelText("Increment value")) + expect(screen.getByLabelText("Count")).toHaveTextContent("1") + + // Click on "-" => Count should be 0 + await user.click(screen.getByLabelText("Decrement value")) + expect(screen.getByLabelText("Count")).toHaveTextContent("0") +}) + +test("Add Amount should work as expected", async () => { + const { user } = renderWithProviders() + + // "Add Amount" button is clicked => Count should be 2 + await user.click(screen.getByText("Add Amount")) + expect(screen.getByLabelText("Count")).toHaveTextContent("2") + + const incrementValueInput = screen.getByLabelText("Set increment amount") + // incrementValue is 2, click on "Add Amount" => Count should be 4 + await user.clear(incrementValueInput) + await user.type(incrementValueInput, "2") + await user.click(screen.getByText("Add Amount")) + expect(screen.getByLabelText("Count")).toHaveTextContent("4") + + // [Negative number] incrementValue is -1, click on "Add Amount" => Count should be 3 + await user.clear(incrementValueInput) + await user.type(incrementValueInput, "-1") + await user.click(screen.getByText("Add Amount")) + expect(screen.getByLabelText("Count")).toHaveTextContent("3") +}) + +it("Add Async should work as expected", async () => { + const { user } = renderWithProviders() + + // "Add Async" button is clicked => Count should be 2 + await user.click(screen.getByText("Add Async")) + + await waitFor(() => + expect(screen.getByLabelText("Count")).toHaveTextContent("2"), + ) + + const incrementValueInput = screen.getByLabelText("Set increment amount") + // incrementValue is 2, click on "Add Async" => Count should be 4 + await user.clear(incrementValueInput) + await user.type(incrementValueInput, "2") + + await user.click(screen.getByText("Add Async")) + await waitFor(() => + expect(screen.getByLabelText("Count")).toHaveTextContent("4"), + ) + + // [Negative number] incrementValue is -1, click on "Add Async" => Count should be 3 + await user.clear(incrementValueInput) + await user.type(incrementValueInput, "-1") + await user.click(screen.getByText("Add Async")) + await waitFor(() => + expect(screen.getByLabelText("Count")).toHaveTextContent("3"), + ) +}) + +test("Add If Odd should work as expected", async () => { + const { user } = renderWithProviders() + + // "Add If Odd" button is clicked => Count should stay 0 + await user.click(screen.getByText("Add If Odd")) + expect(screen.getByLabelText("Count")).toHaveTextContent("0") + + // Click on "+" => Count should be updated to 1 + await user.click(screen.getByLabelText("Increment value")) + expect(screen.getByLabelText("Count")).toHaveTextContent("1") + + // "Add If Odd" button is clicked => Count should be updated to 3 + await user.click(screen.getByText("Add If Odd")) + expect(screen.getByLabelText("Count")).toHaveTextContent("3") + + const incrementValueInput = screen.getByLabelText("Set increment amount") + // incrementValue is 1, click on "Add If Odd" => Count should be updated to 4 + await user.clear(incrementValueInput) + await user.type(incrementValueInput, "1") + await user.click(screen.getByText("Add If Odd")) + expect(screen.getByLabelText("Count")).toHaveTextContent("4") + + // click on "Add If Odd" => Count should stay 4 + await user.clear(incrementValueInput) + await user.type(incrementValueInput, "-1") + await user.click(screen.getByText("Add If Odd")) + expect(screen.getByLabelText("Count")).toHaveTextContent("4") +}) diff --git a/examples/query/react/infinite-queries/src/App.tsx b/examples/query/react/infinite-queries/src/App.tsx new file mode 100644 index 0000000000..af9d854e4d --- /dev/null +++ b/examples/query/react/infinite-queries/src/App.tsx @@ -0,0 +1,53 @@ +import "./App.css" +import { BrowserRouter, Routes, Route, Link } from "react-router" + +import { PaginationExample } from "./features/pagination/PaginationExample" +import { + InfiniteScrollExample, + InfiniteScrollAbout, +} from "./features/infinite-scroll/InfiniteScrollExample" +import { InfiniteScrollMaxPagesExample } from "./features/max-pages/InfiniteScrollMaxExample" + +const Menu = () => { + return ( +
+

Examples

+
    +
  • + Pagination +
  • +
  • + Infinite Scroll +
  • +
  • + Infinite Scroll + max pages +
  • +
+
+ ) +} + +const App = () => { + return ( + +
+

RTKQ Infinite Query Example Showcase

+ + } /> + } /> + } /> + } + /> + } + /> + +
+
+ ) +} + +export default App diff --git a/examples/query/react/infinite-queries/src/app/createAppSlice.ts b/examples/query/react/infinite-queries/src/app/createAppSlice.ts new file mode 100644 index 0000000000..64afebbb60 --- /dev/null +++ b/examples/query/react/infinite-queries/src/app/createAppSlice.ts @@ -0,0 +1,6 @@ +import { asyncThunkCreator, buildCreateSlice } from "@reduxjs/toolkit" + +// `buildCreateSlice` allows us to create a slice with async thunks. +export const createAppSlice = buildCreateSlice({ + creators: { asyncThunk: asyncThunkCreator }, +}) diff --git a/examples/query/react/infinite-queries/src/app/hooks.ts b/examples/query/react/infinite-queries/src/app/hooks.ts new file mode 100644 index 0000000000..bc8990df57 --- /dev/null +++ b/examples/query/react/infinite-queries/src/app/hooks.ts @@ -0,0 +1,12 @@ +// This file serves as a central hub for re-exporting pre-typed Redux hooks. +// These imports are restricted elsewhere to ensure consistent +// usage of typed hooks throughout the application. +// We disable the ESLint rule here because this is the designated place +// for importing and re-exporting the typed versions of hooks. +/* eslint-disable @typescript-eslint/no-restricted-imports */ +import { useDispatch, useSelector } from "react-redux" +import type { AppDispatch, RootState } from "./store" + +// Use throughout your app instead of plain `useDispatch` and `useSelector` +export const useAppDispatch = useDispatch.withTypes() +export const useAppSelector = useSelector.withTypes() diff --git a/examples/query/react/infinite-queries/src/app/store.ts b/examples/query/react/infinite-queries/src/app/store.ts new file mode 100644 index 0000000000..f71a782819 --- /dev/null +++ b/examples/query/react/infinite-queries/src/app/store.ts @@ -0,0 +1,41 @@ +import type { Action, ThunkAction } from "@reduxjs/toolkit" +import { combineSlices, configureStore } from "@reduxjs/toolkit" +import { setupListeners } from "@reduxjs/toolkit/query" +import { baseApi } from "../features/baseApi" + +// `combineSlices` automatically combines the reducers using +// their `reducerPath`s, therefore we no longer need to call `combineReducers`. +const rootReducer = combineSlices(baseApi) +// Infer the `RootState` type from the root reducer +export type RootState = ReturnType + +// The store setup is wrapped in `makeStore` to allow reuse +// when setting up tests that need the same store config +export const makeStore = (preloadedState?: Partial) => { + const store = configureStore({ + reducer: rootReducer, + // Adding the api middleware enables caching, invalidation, polling, + // and other useful features of `rtk-query`. + middleware: getDefaultMiddleware => { + return getDefaultMiddleware().concat(baseApi.middleware) + }, + preloadedState, + }) + // configure listeners using the provided defaults + // optional, but required for `refetchOnFocus`/`refetchOnReconnect` behaviors + setupListeners(store.dispatch) + return store +} + +export const store = makeStore() + +// Infer the type of `store` +export type AppStore = typeof store +// Infer the `AppDispatch` type from the store itself +export type AppDispatch = AppStore["dispatch"] +export type AppThunk = ThunkAction< + ThunkReturnType, + RootState, + unknown, + Action +> diff --git a/examples/query/react/infinite-queries/src/features/baseApi.ts b/examples/query/react/infinite-queries/src/features/baseApi.ts new file mode 100644 index 0000000000..9f460f1a8c --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/baseApi.ts @@ -0,0 +1,6 @@ +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react" + +export const baseApi = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: "/" }), + endpoints: build => ({}), +}) diff --git a/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx b/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx new file mode 100644 index 0000000000..745394d7a2 --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx @@ -0,0 +1,104 @@ +import React from "react" +import { useInView } from "react-intersection-observer" +import { Link } from "react-router" + +import { apiWithInfiniteScroll } from "./infiniteScrollApi" + +export const InfiniteScrollAbout = () => { + return ( + { + window.history.back() + e.preventDefault() + }} + > + Back + + ) +} + +export const InfiniteScrollExample = () => { + const { + data, + error, + fetchNextPage, + fetchPreviousPage, + hasNextPage, + isFetchingNextPage, + isFetching, + isError, + } = + apiWithInfiniteScroll.endpoints.getProjectsCursor.useInfiniteQuery( + "projects", + ) + + const { ref, inView } = useInView() + + React.useEffect(() => { + if (inView) { + console.log("Fetching next page") + fetchNextPage() + } + }, [fetchNextPage, inView]) + + return ( +
+

Infinite Scroll Example

+ {isFetching ? ( +

Loading...

+ ) : isError ? ( + Error: {error.message} + ) : null} + { + <> +
+ +
+ {data?.pages.map(page => ( + + {page.projects.map(project => ( +

+ {project.name} +

+ ))} +
+ ))} +
+ +
+
{isFetching ? "Background Updating..." : null}
+ + } +
+ Go to another page +
+ ) +} diff --git a/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts new file mode 100644 index 0000000000..ea0b48abbb --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts @@ -0,0 +1,34 @@ +import { baseApi } from "../baseApi" + +type Project = { + id: number + name: string +} + +type ProjectsPageCursor = { + projects: Project[] + nextId: number | null + previousId: number | null +} + +export const apiWithInfiniteScroll = baseApi.injectEndpoints({ + endpoints: build => ({ + getProjectsCursor: build.infiniteQuery({ + query: page => `https://example.com/api/projectsCursor?cursor=${page}`, + infiniteQueryOptions: { + initialPageParam: 0, + getPreviousPageParam: firstPage => firstPage.previousId, + getNextPageParam: ( + lastPage, + allPages, + lastPageParam, + allPageParams, + ) => { + return lastPage.nextId + }, + }, + }), + }), +}) + +// export const { useGetProjectsQuery } = apiWithPagination diff --git a/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx b/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx new file mode 100644 index 0000000000..f91c47e0e3 --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx @@ -0,0 +1,85 @@ +import React from "react" +import { apiWithInfiniteScrollMax } from "./infiniteScrollApi" + +export const InfiniteScrollMaxPagesExample = () => { + const { + data, + error, + fetchNextPage, + fetchPreviousPage, + // hasNextPage, + isFetchingNextPage, + isFetching, + isError, + } = + apiWithInfiniteScrollMax.endpoints.getProjectsCursorMax.useInfiniteQuery( + "projects", + ) + + // TODO This should be built in to RTKQ + const hasNextPage = data?.pages[data.pages.length - 1].nextId !== null + const hasPreviousPage = data?.pages[0].previousId !== null + + return ( +
+

Infinite Query with max pages

+

3 pages max

+ {isFetching ? ( +

Loading...

+ ) : isError ? ( + Error: {error.message} + ) : ( + <> +
+ +
+ {data?.pages.map(page => ( + + {page.projects.map(project => ( +

+ {project.name} +

+ ))} +
+ ))} +
+ +
+
+ {isFetching && !isFetchingNextPage + ? "Background Updating..." + : null} +
+ + )} +
+
+ ) +} diff --git a/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts new file mode 100644 index 0000000000..48e8194e12 --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts @@ -0,0 +1,32 @@ +import { baseApi } from "../baseApi" + +type Project = { + id: number + name: string +} + +type ProjectsPageCursor = { + projects: Project[] + nextId: number | null + previousId: number | null +} + +export const apiWithInfiniteScrollMax = baseApi.injectEndpoints({ + endpoints: build => ({ + getProjectsCursorMax: build.infiniteQuery< + ProjectsPageCursor, + string, + number + >({ + query: page => `https://example.com/api/projectsCursor?cursor=${page}`, + infiniteQueryOptions: { + initialPageParam: 0, + maxPages: 3, + getPreviousPageParam: firstPage => firstPage.previousId ?? undefined, + getNextPageParam: lastPage => lastPage.nextId ?? undefined, + }, + }), + }), +}) + +// export const { useGetProjectsQuery } = apiWithPagination diff --git a/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx b/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx new file mode 100644 index 0000000000..d0c46fd68a --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx @@ -0,0 +1,61 @@ +import React from "react" +import { apiWithPagination } from "./paginationApi" + +// The React Query example actually just uses a normal query +// rather than an infinite query, and Dominik confirmed that +// that "infinite queries" should really only be used if you +// want to display _all_ of the pages. +// > "The drawback is shown right in your example: fetching is no longer declarative - you need to keep page in-sync with fetchNextPage. And if you are on page 3 and go back to two, then forward to 3 again it falls apart as fetchNextPage would fetch page 4 instead of refetching page 3" +// Still, it's worth exploring how we might use infinite queries +// for a basic pagination scenario. + +export const PaginationExample = () => { + const [page, setPage] = React.useState(0) + const { + data, + error, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + isFetching, + isError, + } = apiWithPagination.endpoints.getProjects.useInfiniteQuery("projects") + + const currentPage = data?.pages[page] + + return ( +
+

Pagination Example

+
Current Page: {page + 1}
+ {" "} + +

Results

+ {isFetching ? ( +
Loading...
+ ) : isError ? ( +
Error: {error.message}
+ ) : ( +
+ {currentPage?.projects.map(project => ( +

{project.name}

+ ))} +
+ )} +
+ ) +} diff --git a/examples/query/react/infinite-queries/src/features/pagination/paginationApi.ts b/examples/query/react/infinite-queries/src/features/pagination/paginationApi.ts new file mode 100644 index 0000000000..1dd2a197bd --- /dev/null +++ b/examples/query/react/infinite-queries/src/features/pagination/paginationApi.ts @@ -0,0 +1,28 @@ +import { baseApi } from "../baseApi" + +type Project = { + id: number + name: string +} + +type ProjectsPage = { + projects: Project[] + hasMore: boolean +} + +export const apiWithPagination = baseApi.injectEndpoints({ + endpoints: build => ({ + getProjects: build.infiniteQuery({ + query: page => `https://example.com/api/projects?page=${page}`, + infiniteQueryOptions: { + initialPageParam: 0, + getNextPageParam: (lastPage, pages, lastPageParam, allPageParams) => { + if (!lastPage.hasMore) return undefined + return pages.length + }, + }, + }), + }), +}) + +// export const { useGetProjectsQuery } = apiWithPagination diff --git a/examples/query/react/infinite-queries/src/index.css b/examples/query/react/infinite-queries/src/index.css new file mode 100644 index 0000000000..4a1df4db71 --- /dev/null +++ b/examples/query/react/infinite-queries/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} diff --git a/examples/query/react/infinite-queries/src/main.tsx b/examples/query/react/infinite-queries/src/main.tsx new file mode 100644 index 0000000000..fc1ea22f15 --- /dev/null +++ b/examples/query/react/infinite-queries/src/main.tsx @@ -0,0 +1,36 @@ +import React from "react" +import { createRoot } from "react-dom/client" +import { Provider } from "react-redux" +import App from "./App" +import { store } from "./app/store" +import "./index.css" + +async function enableMocking() { + if (process.env.NODE_ENV !== "development") { + return + } + + const { worker } = await import("./mocks/browser") + + return worker.start() +} + +enableMocking().then(() => { + const container = document.getElementById("root") + + if (container) { + const root = createRoot(container) + + root.render( + + + + + , + ) + } else { + throw new Error( + "Root element with ID 'root' was not found in the document. Ensure there is a corresponding HTML element with the ID 'root' in your HTML file.", + ) + } +}) diff --git a/examples/query/react/infinite-queries/src/mocks/browser.ts b/examples/query/react/infinite-queries/src/mocks/browser.ts new file mode 100644 index 0000000000..b9fe759c8a --- /dev/null +++ b/examples/query/react/infinite-queries/src/mocks/browser.ts @@ -0,0 +1,4 @@ +import { setupWorker } from "msw/browser" +import { handlers } from "./handlers" + +export const worker = setupWorker(...handlers) diff --git a/examples/query/react/infinite-queries/src/mocks/handlers.ts b/examples/query/react/infinite-queries/src/mocks/handlers.ts new file mode 100644 index 0000000000..75edcac3a6 --- /dev/null +++ b/examples/query/react/infinite-queries/src/mocks/handlers.ts @@ -0,0 +1,72 @@ +import { http, HttpResponse } from "msw" + +function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +export const handlers = [ + http.get("https://example.com/api/projects", async ({ request, params }) => { + const url = new URL(request.url) + const pageParam = url.searchParams.get("page") || "0" + const page = parseInt(pageParam, 10) + + const pageSize = 10 + const maxPages = 5 + + await delay(1000) + + const projects = Array(pageSize) + .fill(0) + .map((_, i) => { + const id = page * pageSize + (i + 1) + return { + name: "Project " + id, + id, + } + }) + + return HttpResponse.json({ + projects, + // 0-based pagination, so match total count + hasMore: page < maxPages - 1, + }) + }), + http.get( + "https://example.com/api/projectsCursor", + async ({ request, params }) => { + const url = new URL(request.url) + const cursorParam = url.searchParams.get("cursor") || "0" + const cursor = parseInt(cursorParam, 10) + + const pageSize = 10 + const totalItems = 50 + + await delay(1000) + + const projects = Array(pageSize) + .fill(0) + .map((_, i) => { + const id = cursor + i + return { + name: "Project " + id + ` (server time: ${Date.now()})`, + id, + } + }) + + const hasNext = cursor < totalItems - pageSize + const nextId = hasNext ? projects[projects.length - 1].id + 1 : null + + // Prevent negative cursors + const hasPrevious = cursor > -(totalItems - pageSize) + const maybePrevCursor = projects[0].id - pageSize + const previousId = + hasPrevious && maybePrevCursor >= 0 ? maybePrevCursor : null + + return HttpResponse.json({ + projects, + nextId, + previousId, + }) + }, + ), +] diff --git a/examples/query/react/infinite-queries/src/setupTests.ts b/examples/query/react/infinite-queries/src/setupTests.ts new file mode 100644 index 0000000000..b9e7622996 --- /dev/null +++ b/examples/query/react/infinite-queries/src/setupTests.ts @@ -0,0 +1 @@ +import "@testing-library/jest-dom/vitest" diff --git a/examples/query/react/infinite-queries/src/utils/test-utils.tsx b/examples/query/react/infinite-queries/src/utils/test-utils.tsx new file mode 100644 index 0000000000..90e184a1f3 --- /dev/null +++ b/examples/query/react/infinite-queries/src/utils/test-utils.tsx @@ -0,0 +1,65 @@ +import type { RenderOptions } from "@testing-library/react" +import { render } from "@testing-library/react" +import userEvent from "@testing-library/user-event" +import type { PropsWithChildren, ReactElement } from "react" +import { Provider } from "react-redux" +import type { AppStore, RootState } from "../app/store" +import { makeStore } from "../app/store" + +/** + * This type extends the default options for + * React Testing Library's render function. It allows for + * additional configuration such as specifying an initial Redux state and + * a custom store instance. + */ +interface ExtendedRenderOptions extends Omit { + /** + * Defines a specific portion or the entire initial state for the Redux store. + * This is particularly useful for initializing the state in a + * controlled manner during testing, allowing components to be rendered + * with predetermined state conditions. + */ + preloadedState?: Partial + + /** + * Allows the use of a specific Redux store instance instead of a + * default or global store. This flexibility is beneficial when + * testing components with unique store requirements or when isolating + * tests from a global store state. The custom store should be configured + * to match the structure and middleware of the store used by the application. + * + * @default makeStore(preloadedState) + */ + store?: AppStore +} + +/** + * Renders the given React element with Redux Provider and custom store. + * This function is useful for testing components that are connected to the Redux store. + * + * @param ui - The React component or element to render. + * @param extendedRenderOptions - Optional configuration options for rendering. This includes `preloadedState` for initial Redux state and `store` for a specific Redux store instance. Any additional properties are passed to React Testing Library's render function. + * @returns An object containing the Redux store used in the render, User event API for simulating user interactions in tests, and all of React Testing Library's query functions for testing the component. + */ +export const renderWithProviders = ( + ui: ReactElement, + extendedRenderOptions: ExtendedRenderOptions = {}, +) => { + const { + preloadedState = {}, + // Automatically create a store instance if no store was passed in + store = makeStore(preloadedState), + ...renderOptions + } = extendedRenderOptions + + const Wrapper = ({ children }: PropsWithChildren) => ( + {children} + ) + + // Return an object with the store and all of RTL's query functions + return { + store, + user: userEvent.setup(), + ...render(ui, { wrapper: Wrapper, ...renderOptions }), + } +} diff --git a/examples/query/react/infinite-queries/src/vite-env.d.ts b/examples/query/react/infinite-queries/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/query/react/infinite-queries/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/query/react/infinite-queries/tsconfig.json b/examples/query/react/infinite-queries/tsconfig.json new file mode 100644 index 0000000000..dedb7b81b8 --- /dev/null +++ b/examples/query/react/infinite-queries/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "types": ["vitest/globals"] + }, + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/examples/query/react/infinite-queries/tsconfig.node.json b/examples/query/react/infinite-queries/tsconfig.node.json new file mode 100644 index 0000000000..a535f7d4d2 --- /dev/null +++ b/examples/query/react/infinite-queries/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/query/react/infinite-queries/vite.config.ts b/examples/query/react/infinite-queries/vite.config.ts new file mode 100644 index 0000000000..39a5632b23 --- /dev/null +++ b/examples/query/react/infinite-queries/vite.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from "vitest/config" +import react from "@vitejs/plugin-react" + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + open: true, + }, + test: { + globals: true, + environment: "jsdom", + setupFiles: "src/setupTests", + mockReset: true, + }, +}) diff --git a/yarn.lock b/yarn.lock index 95f6db27c9..9f2c34b77d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,6 +12,13 @@ __metadata: languageName: node linkType: hard +"@adobe/css-tools@npm:^4.4.0": + version: 4.4.1 + resolution: "@adobe/css-tools@npm:4.4.1" + checksum: 10/a0ea05517308593a52728936a833b1075c4cf1a6b68baaea817063f34e75faa1dba1209dd285003c4f8072804227dfa563e7e903f72ae2d39cb520aaee3f4bcc + languageName: node + linkType: hard + "@algolia/autocomplete-core@npm:1.7.1": version: 1.7.1 resolution: "@algolia/autocomplete-core@npm:1.7.1" @@ -291,6 +298,17 @@ __metadata: languageName: node linkType: hard +"@asamuzakjp/dom-selector@npm:^2.0.1": + version: 2.0.2 + resolution: "@asamuzakjp/dom-selector@npm:2.0.2" + dependencies: + bidi-js: "npm:^1.0.3" + css-tree: "npm:^2.3.1" + is-potential-custom-element-name: "npm:^1.0.1" + checksum: 10/04b32a68aa6de5d2b945c7cdf1a6a4e765ae3ac957dea12e86c1e2725a2889226125f04e983962b6d49a508c7a103144648ae45514c5dd56670dfaed6d07b2c3 + languageName: node + linkType: hard + "@babel/code-frame@npm:7.12.11": version: 7.12.11 resolution: "@babel/code-frame@npm:7.12.11" @@ -320,6 +338,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.25.9" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/db2c2122af79d31ca916755331bb4bac96feb2b334cdaca5097a6b467fdd41963b89b14b6836a14f083de7ff887fc78fa1b3c10b14e743d33e12dbfe5ee3d223 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.19.4, @babel/compat-data@npm:^7.24.8": version: 7.24.8 resolution: "@babel/compat-data@npm:7.24.8" @@ -327,6 +356,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.25.9": + version: 7.26.2 + resolution: "@babel/compat-data@npm:7.26.2" + checksum: 10/ed9eed6b62ce803ef4a320b1dac76b0302abbb29c49dddf96f3e3207d9717eb34e299a8651bb1582e9c3346ead74b6d595ffced5b3dae718afa08b18741f8402 + languageName: node + linkType: hard + "@babel/core@npm:7.12.9": version: 7.12.9 resolution: "@babel/core@npm:7.12.9" @@ -374,6 +410,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/core@npm:7.26.0" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.26.0" + "@babel/generator": "npm:^7.26.0" + "@babel/helper-compilation-targets": "npm:^7.25.9" + "@babel/helper-module-transforms": "npm:^7.26.0" + "@babel/helpers": "npm:^7.26.0" + "@babel/parser": "npm:^7.26.0" + "@babel/template": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.26.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/65767bfdb1f02e80d3af4f138066670ef8fdd12293de85ef151758a901c191c797e86d2e99b11c4cdfca33c72385ecaf38bbd7fa692791ec44c77763496b9b93 + languageName: node + linkType: hard + "@babel/eslint-parser@npm:^7.16.3": version: 7.18.2 resolution: "@babel/eslint-parser@npm:7.18.2" @@ -412,6 +471,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0": + version: 7.26.2 + resolution: "@babel/generator@npm:7.26.2" + dependencies: + "@babel/parser": "npm:^7.26.2" + "@babel/types": "npm:^7.26.0" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10/71ace82b5b07a554846a003624bfab93275ccf73cdb9f1a37a4c1094bf9dc94bb677c67e8b8c939dbd6c5f0eda2e8f268aa2b0d9c3b9511072565660e717e045 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" @@ -444,6 +516,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-compilation-targets@npm:7.25.9" + dependencies: + "@babel/compat-data": "npm:^7.25.9" + "@babel/helper-validator-option": "npm:^7.25.9" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10/8053fbfc21e8297ab55c8e7f9f119e4809fa7e505268691e1bedc2cf5e7a5a7de8c60ad13da2515378621b7601c42e101d2d679904da395fa3806a1edef6b92e + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.12.1, @babel/helper-create-class-features-plugin@npm:^7.18.0, @babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0": version: 7.23.10 resolution: "@babel/helper-create-class-features-plugin@npm:7.23.10" @@ -611,6 +696,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-module-imports@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10/e090be5dee94dda6cd769972231b21ddfae988acd76b703a480ac0c96f3334557d70a965bf41245d6ee43891e7571a8b400ccf2b2be5803351375d0f4e5bcf08 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.12.1, @babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -657,6 +752,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helper-module-transforms@npm:7.26.0" + dependencies: + "@babel/helper-module-imports": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/9841d2a62f61ad52b66a72d08264f23052d533afc4ce07aec2a6202adac0bfe43014c312f94feacb3291f4c5aafe681955610041ece2c276271adce3f570f2f5 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.18.6, @babel/helper-optimise-call-expression@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" @@ -687,6 +795,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-plugin-utils@npm:7.25.9" + checksum: 10/e347d87728b1ab10b6976d46403941c8f9008c045ea6d99997a7ffca7b852dc34b6171380f7b17edf94410e0857ff26f3a53d8618f11d73744db86e8ca9b8c64 + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.18.6, @babel/helper-remap-async-to-generator@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-remap-async-to-generator@npm:7.18.9" @@ -796,6 +911,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 10/c28656c52bd48e8c1d9f3e8e68ecafd09d949c57755b0d353739eb4eae7ba4f7e67e92e4036f1cd43378cc1397a2c943ed7bcaf5949b04ab48607def0258b775 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.12.11, @babel/helper-validator-identifier@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-validator-identifier@npm:7.22.20" @@ -817,6 +939,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 10/3f9b649be0c2fd457fa1957b694b4e69532a668866b8a0d81eabfa34ba16dbf3107b39e0e7144c55c3c652bf773ec816af8df4a61273a2bb4eb3145ca9cf478e + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.18.6, @babel/helper-validator-option@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helper-validator-option@npm:7.24.8" @@ -831,6 +960,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-option@npm:7.25.9" + checksum: 10/9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.18.9": version: 7.19.0 resolution: "@babel/helper-wrap-function@npm:7.19.0" @@ -853,6 +989,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helpers@npm:7.26.0" + dependencies: + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.26.0" + checksum: 10/fd4757f65d10b64cfdbf4b3adb7ea6ffff9497c53e0786452f495d1f7794da7e0898261b4db65e1c62bbb9a360d7d78a1085635c23dfc3af2ab6dcba06585f86 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -922,6 +1068,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/parser@npm:7.26.2" + dependencies: + "@babel/types": "npm:^7.26.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10/8baee43752a3678ad9f9e360ec845065eeee806f1fdc8e0f348a8a0e13eef0959dabed4a197c978896c493ea205c804d0a1187cc52e4a1ba017c7935bab4983d + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6" @@ -1815,6 +1972,28 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx-self@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/41c833cd7f91b1432710f91b1325706e57979b2e8da44e83d86312c78bbe96cd9ef778b4e79e4e17ab25fa32c72b909f2be7f28e876779ede28e27506c41f4ae + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/a3e0e5672e344e9d01fb20b504fe29a84918eaa70cec512c4d4b1b035f72803261257343d8e93673365b72c371f35cf34bb0d129720bf178a4c87812c8b9c662 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx@npm:^7.0.0, @babel/plugin-transform-react-jsx@npm:^7.12.11, @babel/plugin-transform-react-jsx@npm:^7.18.6": version: 7.19.0 resolution: "@babel/plugin-transform-react-jsx@npm:7.19.0" @@ -2205,6 +2384,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/template@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10/e861180881507210150c1335ad94aff80fd9e9be6202e1efa752059c93224e2d5310186ddcdd4c0f0b0fc658ce48cb47823f15142b5c00c8456dde54f5de80b2 + languageName: node + linkType: hard + "@babel/traverse@npm:7.12.13": version: 7.12.13 resolution: "@babel/traverse@npm:7.12.13" @@ -2258,6 +2448,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/traverse@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/generator": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/7431614d76d4a053e429208db82f2846a415833f3d9eb2e11ef72eeb3c64dfd71f4a4d983de1a4a047b36165a1f5a64de8ca2a417534cc472005c740ffcb9c6a + languageName: node + linkType: hard + "@babel/types@npm:7.12.13": version: 7.12.13 resolution: "@babel/types@npm:7.12.13" @@ -2291,6 +2496,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/types@npm:7.26.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10/40780741ecec886ed9edae234b5eb4976968cc70d72b4e5a40d55f83ff2cc457de20f9b0f4fe9d858350e43dab0ea496e7ef62e2b2f08df699481a76df02cd6e + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -2307,6 +2522,15 @@ __metadata: languageName: node linkType: hard +"@bundled-es-modules/cookie@npm:^2.0.1": + version: 2.0.1 + resolution: "@bundled-es-modules/cookie@npm:2.0.1" + dependencies: + cookie: "npm:^0.7.2" + checksum: 10/0038a5e82c41bfcd722afedabeb6961a5f15747b3681d7f4b61e35eb1e33130039e10ee9250dc9c9e4d3915ce1aeee717c0fb92225111574f0a030411abc0987 + languageName: node + linkType: hard + "@bundled-es-modules/statuses@npm:^1.0.1": version: 1.0.1 resolution: "@bundled-es-modules/statuses@npm:1.0.1" @@ -2316,6 +2540,16 @@ __metadata: languageName: node linkType: hard +"@bundled-es-modules/tough-cookie@npm:^0.1.6": + version: 0.1.6 + resolution: "@bundled-es-modules/tough-cookie@npm:0.1.6" + dependencies: + "@types/tough-cookie": "npm:^4.0.5" + tough-cookie: "npm:^4.1.4" + checksum: 10/4f24a820f02c08c3ca0ff21272317357152093f76f9c8cc182517f61fa426ae53dadc4d68a3d6da5078e8d73f0ff8c0907a9f994c0be756162ba9c7358533e57 + languageName: node + linkType: hard + "@chakra-ui/accordion@npm:1.0.0": version: 1.0.0 resolution: "@chakra-ui/accordion@npm:1.0.0" @@ -5596,6 +5830,51 @@ __metadata: languageName: node linkType: hard +"@inquirer/confirm@npm:^5.0.0": + version: 5.0.2 + resolution: "@inquirer/confirm@npm:5.0.2" + dependencies: + "@inquirer/core": "npm:^10.1.0" + "@inquirer/type": "npm:^3.0.1" + peerDependencies: + "@types/node": ">=18" + checksum: 10/4e775b80b689adeb0b2852ed79b368ef23a82fe3d5f580a562f4af7cdf002a19e0ec1b3b95acc6d49427a72c0fcb5b6548e0cdcafe2f0d3f3d6a923e04aabd0c + languageName: node + linkType: hard + +"@inquirer/core@npm:^10.1.0": + version: 10.1.0 + resolution: "@inquirer/core@npm:10.1.0" + dependencies: + "@inquirer/figures": "npm:^1.0.8" + "@inquirer/type": "npm:^3.0.1" + ansi-escapes: "npm:^4.3.2" + cli-width: "npm:^4.1.0" + mute-stream: "npm:^2.0.0" + signal-exit: "npm:^4.1.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^6.2.0" + yoctocolors-cjs: "npm:^2.1.2" + checksum: 10/5d097d0484c1b758f788b792d29395199bdc84af3e8cd4d9273e31de2c5202839b6edf299056956044ba7fb097c4cee7b5c0288e094a380c045082b044f9946e + languageName: node + linkType: hard + +"@inquirer/figures@npm:^1.0.8": + version: 1.0.8 + resolution: "@inquirer/figures@npm:1.0.8" + checksum: 10/0e5e4fbb15e799e818c598fcc3558ef076daf78662149711b046723fd6316381e95f7d5573d6ef0062095ad22c6ac98833033f0948df5c722932107a567fd9c3 + languageName: node + linkType: hard + +"@inquirer/type@npm:^3.0.1": + version: 3.0.1 + resolution: "@inquirer/type@npm:3.0.1" + peerDependencies: + "@types/node": ">=18" + checksum: 10/af412f1e7541d43554b02199ae71a2039a1bff5dc51ceefd87de9ece55b199682733b28810fb4b6cb3ed4a159af4cc4a26d4bb29c58dd127e7d9dbda0797d8e7 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -6239,6 +6518,20 @@ __metadata: languageName: node linkType: hard +"@mswjs/interceptors@npm:^0.37.0": + version: 0.37.1 + resolution: "@mswjs/interceptors@npm:0.37.1" + dependencies: + "@open-draft/deferred-promise": "npm:^2.2.0" + "@open-draft/logger": "npm:^0.3.0" + "@open-draft/until": "npm:^2.0.0" + is-node-process: "npm:^1.2.0" + outvariant: "npm:^1.4.3" + strict-event-emitter: "npm:^0.5.1" + checksum: 10/332d8aa50beb4834ccbda6a800ca00b1204adc0eba23e1c1f7bb9f4e564a92707e563f7a2424d4a8607404ec91424e5d8c34a87c250b191ca7b24dff12eba2c5 + languageName: node + linkType: hard + "@mswjs/interceptors@npm:^0.8.0": version: 0.8.1 resolution: "@mswjs/interceptors@npm:0.8.1" @@ -6607,6 +6900,26 @@ __metadata: languageName: unknown linkType: soft +"@reduxjs/toolkit@https://pkg.csb.dev/reduxjs/redux-toolkit/commit/aa419c22/@reduxjs/toolkit/_pkg.tgz": + version: 2.4.0 + resolution: "@reduxjs/toolkit@https://pkg.csb.dev/reduxjs/redux-toolkit/commit/aa419c22/@reduxjs/toolkit/_pkg.tgz" + dependencies: + immer: "npm:^10.0.3" + redux: "npm:^5.0.1" + redux-thunk: "npm:^3.1.0" + reselect: "npm:^5.1.0" + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + checksum: 10/83dd571381b1e16bb75731c7dedc51e90934039d5b73ac6d4115d8e2408bbf8ca679d2030aaa59b0aa67cd85e5747a967b2005604ce670134189c0e74abb98df + languageName: node + linkType: hard + "@reduxjs/toolkit@npm:1.8.1": version: 1.8.1 resolution: "@reduxjs/toolkit@npm:1.8.1" @@ -7532,6 +7845,22 @@ __metadata: languageName: node linkType: hard +"@testing-library/dom@npm:^9.0.0, @testing-library/dom@npm:^9.3.4": + version: 9.3.4 + resolution: "@testing-library/dom@npm:9.3.4" + dependencies: + "@babel/code-frame": "npm:^7.10.4" + "@babel/runtime": "npm:^7.12.5" + "@types/aria-query": "npm:^5.0.1" + aria-query: "npm:5.1.3" + chalk: "npm:^4.1.0" + dom-accessibility-api: "npm:^0.5.9" + lz-string: "npm:^1.5.0" + pretty-format: "npm:^27.0.2" + checksum: 10/510da752ea76f4a10a0a4e3a77917b0302cf03effe576cd3534cab7e796533ee2b0e9fb6fb11b911a1ebd7c70a0bb6f235bf4f816c9b82b95b8fe0cddfd10975 + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:^5.11.5": version: 5.16.4 resolution: "@testing-library/jest-dom@npm:5.16.4" @@ -7549,6 +7878,21 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:^6.2.0": + version: 6.6.3 + resolution: "@testing-library/jest-dom@npm:6.6.3" + dependencies: + "@adobe/css-tools": "npm:^4.4.0" + aria-query: "npm:^5.0.0" + chalk: "npm:^3.0.0" + css.escape: "npm:^1.5.1" + dom-accessibility-api: "npm:^0.6.3" + lodash: "npm:^4.17.21" + redent: "npm:^3.0.0" + checksum: 10/1f3427e45870eab9dcc59d6504b780d4a595062fe1687762ae6e67d06a70bf439b40ab64cf58cbace6293a99e3764d4647fdc8300a633b721764f5ce39dade18 + languageName: node + linkType: hard + "@testing-library/react-render-stream@npm:^1.0.3": version: 1.0.3 resolution: "@testing-library/react-render-stream@npm:1.0.3" @@ -7566,6 +7910,20 @@ __metadata: languageName: node linkType: hard +"@testing-library/react@npm:^14.1.2": + version: 14.3.1 + resolution: "@testing-library/react@npm:14.3.1" + dependencies: + "@babel/runtime": "npm:^7.12.5" + "@testing-library/dom": "npm:^9.0.0" + "@types/react-dom": "npm:^18.0.0" + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + checksum: 10/83359dcdf9eaf067839f34604e1a181cbc14fc09f3a07672403700fcc6a900c4b8054ad1114fc24b4b9f89d84e2a09e1b7c9afce2306b1d4b4c9e30eb1cb12de + languageName: node + linkType: hard + "@testing-library/react@npm:^16.0.1": version: 16.0.1 resolution: "@testing-library/react@npm:16.0.1" @@ -8231,6 +8589,15 @@ __metadata: languageName: node linkType: hard +"@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.18": + version: 18.3.1 + resolution: "@types/react-dom@npm:18.3.1" + dependencies: + "@types/react": "npm:*" + checksum: 10/33f9ba79b26641ddf00a8699c30066b7e3573ab254e97475bf08f82fab83a6d3ce8d4ebad86afeb49bb8df3374390a9ba93125cece33badc4b3e8f7eac3c84d8 + languageName: node + linkType: hard + "@types/react-dom@npm:^18.0.5, @types/react-dom@npm:^18.2.25, @types/react-dom@npm:^18.3.0": version: 18.3.0 resolution: "@types/react-dom@npm:18.3.0" @@ -8282,6 +8649,16 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.2.47": + version: 18.3.12 + resolution: "@types/react@npm:18.3.12" + dependencies: + "@types/prop-types": "npm:*" + csstype: "npm:^3.0.2" + checksum: 10/c9bbdfeacd5347d2240e0d2cb5336bc57dbc1b9ff557b6c4024b49df83419e4955553518169d3736039f1b62608e15b35762a6c03d49bd86e33add4b43b19033 + languageName: node + linkType: hard + "@types/resolve@npm:1.17.1": version: 1.17.1 resolution: "@types/resolve@npm:1.17.1" @@ -8406,6 +8783,13 @@ __metadata: languageName: node linkType: hard +"@types/tough-cookie@npm:^4.0.5": + version: 4.0.5 + resolution: "@types/tough-cookie@npm:4.0.5" + checksum: 10/01fd82efc8202670865928629697b62fe9bf0c0dcbc5b1c115831caeb073a2c0abb871ff393d7df1ae94ea41e256cb87d2a5a91fd03cdb1b0b4384e08d4ee482 + languageName: node + linkType: hard + "@types/trusted-types@npm:^2.0.2": version: 2.0.2 resolution: "@types/trusted-types@npm:2.0.2" @@ -8945,6 +9329,21 @@ __metadata: languageName: node linkType: hard +"@vitejs/plugin-react@npm:^4.2.1": + version: 4.3.4 + resolution: "@vitejs/plugin-react@npm:4.3.4" + dependencies: + "@babel/core": "npm:^7.26.0" + "@babel/plugin-transform-react-jsx-self": "npm:^7.25.9" + "@babel/plugin-transform-react-jsx-source": "npm:^7.25.9" + "@types/babel__core": "npm:^7.20.5" + react-refresh: "npm:^0.14.2" + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + checksum: 10/3b220908ed9b7b96a380a9c53e82fb428ca1f76b798ab59d1c63765bdff24de61b4778dd3655952b7d3d922645aea2d97644503b879aba6e3fcf467605b9913d + languageName: node + linkType: hard + "@vitest/expect@npm:1.6.0": version: 1.6.0 resolution: "@vitest/expect@npm:1.6.0" @@ -9742,7 +10141,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.1": +"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.1, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" dependencies: @@ -9930,6 +10329,15 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:5.1.3": + version: 5.1.3 + resolution: "aria-query@npm:5.1.3" + dependencies: + deep-equal: "npm:^2.0.5" + checksum: 10/e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2 + languageName: node + linkType: hard + "aria-query@npm:5.3.0": version: 5.3.0 resolution: "aria-query@npm:5.3.0" @@ -9956,6 +10364,16 @@ __metadata: languageName: node linkType: hard +"array-buffer-byte-length@npm:^1.0.0": + version: 1.0.1 + resolution: "array-buffer-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.5" + is-array-buffer: "npm:^3.0.4" + checksum: 10/53524e08f40867f6a9f35318fafe467c32e45e9c682ba67b11943e167344d2febc0f6977a17e699b05699e805c3e8f073d876f8bbf1b559ed494ad2cd0fae09e + languageName: node + linkType: hard + "array-flatten@npm:1.1.1": version: 1.1.1 resolution: "array-flatten@npm:1.1.1" @@ -10167,6 +10585,15 @@ __metadata: languageName: node linkType: hard +"available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" + dependencies: + possible-typed-array-names: "npm:^1.0.0" + checksum: 10/6c9da3a66caddd83c875010a1ca8ef11eac02ba15fb592dc9418b2b5e7b77b645fa7729380a92d9835c2f05f2ca1b6251f39b993e0feb3f1517c74fa1af02cab + languageName: node + linkType: hard + "axe-core@npm:^4.3.5": version: 4.4.2 resolution: "axe-core@npm:4.4.2" @@ -10560,6 +10987,15 @@ __metadata: languageName: node linkType: hard +"bidi-js@npm:^1.0.3": + version: 1.0.3 + resolution: "bidi-js@npm:1.0.3" + dependencies: + require-from-string: "npm:^2.0.2" + checksum: 10/c4341c7a98797efe3d186cd99d6f97e9030a4f959794ca200ef2ec0a678483a916335bba6c2c0608a21d04a221288a31c9fd0faa0cd9b3903b93594b42466a6a + languageName: node + linkType: hard + "big.js@npm:^5.2.2": version: 5.2.2 resolution: "big.js@npm:5.2.2" @@ -10765,6 +11201,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.0": + version: 4.24.2 + resolution: "browserslist@npm:4.24.2" + dependencies: + caniuse-lite: "npm:^1.0.30001669" + electron-to-chromium: "npm:^1.5.41" + node-releases: "npm:^2.0.18" + update-browserslist-db: "npm:^1.1.1" + bin: + browserslist: cli.js + checksum: 10/f8a9d78bbabe466c57ffd5c50a9e5582a5df9aa68f43078ca62a9f6d0d6c70ba72eca72d0a574dbf177cf55cdca85a46f7eb474917a47ae5398c66f8b76f7d1c + languageName: node + linkType: hard + "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -10926,6 +11376,19 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.7": + version: 1.0.7 + resolution: "call-bind@npm:1.0.7" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + set-function-length: "npm:^1.2.1" + checksum: 10/cd6fe658e007af80985da5185bff7b55e12ef4c2b6f41829a26ed1eef254b1f1c12e3dfd5b2b068c6ba8b86aba62390842d81752e67dcbaec4f6f76e7113b6b7 + languageName: node + linkType: hard + "call-me-maybe@npm:^1.0.1": version: 1.0.1 resolution: "call-me-maybe@npm:1.0.1" @@ -11036,6 +11499,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001669": + version: 1.0.30001684 + resolution: "caniuse-lite@npm:1.0.30001684" + checksum: 10/35dd0941dd32319c87409441e8400faea32114c4a74938c29262a613160d2890a4f57902e24c770f076dbd0b85c4442aa135f9f641d4a74a9246fe624e6f780a + languageName: node + linkType: hard + "capital-case@npm:^1.0.4": version: 1.0.4 resolution: "capital-case@npm:1.0.4" @@ -11470,6 +11940,13 @@ __metadata: languageName: node linkType: hard +"cli-width@npm:^4.1.0": + version: 4.1.0 + resolution: "cli-width@npm:4.1.0" + checksum: 10/b58876fbf0310a8a35c79b72ecfcf579b354e18ad04e6b20588724ea2b522799a758507a37dfe132fafaf93a9922cafd9514d9e1598e6b2cd46694853aed099f + languageName: node + linkType: hard + "clipboardy@npm:3.0.0": version: 3.0.0 resolution: "clipboardy@npm:3.0.0" @@ -11982,6 +12459,20 @@ __metadata: languageName: node linkType: hard +"cookie@npm:^0.7.2": + version: 0.7.2 + resolution: "cookie@npm:0.7.2" + checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f + languageName: node + linkType: hard + +"cookie@npm:^1.0.1": + version: 1.0.2 + resolution: "cookie@npm:1.0.2" + checksum: 10/f5817cdc84d8977761b12549eba29435e675e65c7fef172bc31737788cd8adc83796bf8abe6d950554e7987325ad2d9ac2971c5bd8ff0c4f81c145f82e4ab1be + languageName: node + linkType: hard + "copy-text-to-clipboard@npm:^3.0.1": version: 3.0.1 resolution: "copy-text-to-clipboard@npm:3.0.1" @@ -12387,6 +12878,16 @@ __metadata: languageName: node linkType: hard +"css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" + dependencies: + mdn-data: "npm:2.0.30" + source-map-js: "npm:^1.0.1" + checksum: 10/e5e39b82eb4767c664fa5c2cd9968c8c7e6b7fd2c0079b52680a28466d851e2826d5e64699c449d933c0e8ca0554beca43c41a9fcb09fb6a46139d462dbdf0df + languageName: node + linkType: hard + "css-what@npm:^3.2.1": version: 3.4.2 resolution: "css-what@npm:3.4.2" @@ -12651,7 +13152,7 @@ __metadata: languageName: node linkType: hard -"cssstyle@npm:^4.1.0": +"cssstyle@npm:^4.0.1, cssstyle@npm:^4.1.0": version: 4.1.0 resolution: "cssstyle@npm:4.1.0" dependencies: @@ -12861,6 +13362,32 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:^2.0.5": + version: 2.2.3 + resolution: "deep-equal@npm:2.2.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.0" + call-bind: "npm:^1.0.5" + es-get-iterator: "npm:^1.1.3" + get-intrinsic: "npm:^1.2.2" + is-arguments: "npm:^1.1.1" + is-array-buffer: "npm:^3.0.2" + is-date-object: "npm:^1.0.5" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.2" + isarray: "npm:^2.0.5" + object-is: "npm:^1.1.5" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.4" + regexp.prototype.flags: "npm:^1.5.1" + side-channel: "npm:^1.0.4" + which-boxed-primitive: "npm:^1.0.2" + which-collection: "npm:^1.0.1" + which-typed-array: "npm:^1.1.13" + checksum: 10/1ce49d0b71d0f14d8ef991a742665eccd488dfc9b3cada069d4d7a86291e591c92d2589c832811dea182b4015736b210acaaebce6184be356c1060d176f5a05f + languageName: node + linkType: hard + "deep-extend@npm:^0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -12932,6 +13459,17 @@ __metadata: languageName: node linkType: hard +"define-data-property@npm:^1.1.4": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.0.1" + checksum: 10/abdcb2505d80a53524ba871273e5da75e77e52af9e15b3aa65d8aad82b8a3a424dad7aee2cc0b71470ac7acf501e08defac362e8b6a73cdb4309f028061df4ae + languageName: node + linkType: hard + "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" @@ -13230,6 +13768,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.6.3": + version: 0.6.3 + resolution: "dom-accessibility-api@npm:0.6.3" + checksum: 10/83d3371f8226487fbad36e160d44f1d9017fb26d46faba6a06fcad15f34633fc827b8c3e99d49f71d5f3253d866e2131826866fd0a3c86626f8eccfc361881ff + languageName: node + linkType: hard + "dom-converter@npm:^0.2.0": version: 0.2.0 resolution: "dom-converter@npm:0.2.0" @@ -13469,6 +14014,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.41": + version: 1.5.67 + resolution: "electron-to-chromium@npm:1.5.67" + checksum: 10/02dc78eeaa5eb6630353e48a30f2f081e283a6e1ef9ba0d4a932ca289795fd98947b6fa85c9d74d8fb335b80ad8f65d893052b047a9ac78093e5b37501c3d34f + languageName: node + linkType: hard + "elegant-spinner@npm:^1.0.1": version: 1.0.1 resolution: "elegant-spinner@npm:1.0.1" @@ -13670,6 +14222,39 @@ __metadata: languageName: node linkType: hard +"es-define-property@npm:^1.0.0": + version: 1.0.0 + resolution: "es-define-property@npm:1.0.0" + dependencies: + get-intrinsic: "npm:^1.2.4" + checksum: 10/f66ece0a887b6dca71848fa71f70461357c0e4e7249696f81bad0a1f347eed7b31262af4a29f5d726dc026426f085483b6b90301855e647aa8e21936f07293c6 + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10/96e65d640156f91b707517e8cdc454dd7d47c32833aa3e85d79f24f9eb7ea85f39b63e36216ef0114996581969b59fe609a94e30316b08f5f4df1d44134cf8d5 + languageName: node + linkType: hard + +"es-get-iterator@npm:^1.1.3": + version: 1.1.3 + resolution: "es-get-iterator@npm:1.1.3" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.1.3" + has-symbols: "npm:^1.0.3" + is-arguments: "npm:^1.1.1" + is-map: "npm:^2.0.2" + is-set: "npm:^2.0.2" + is-string: "npm:^1.0.7" + isarray: "npm:^2.0.5" + stop-iteration-iterator: "npm:^1.0.0" + checksum: 10/bc2194befbe55725f9489098626479deee3c801eda7e83ce0dff2eb266a28dc808edb9b623ff01d31ebc1328f09d661333d86b601036692c2e3c1a6942319433 + languageName: node + linkType: hard + "es-module-lexer@npm:^0.9.0": version: 0.9.3 resolution: "es-module-lexer@npm:0.9.3" @@ -13909,6 +14494,13 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 + languageName: node + linkType: hard + "escape-goat@npm:^2.0.0": version: 2.1.1 resolution: "escape-goat@npm:2.1.1" @@ -15338,7 +15930,7 @@ __metadata: languageName: node linkType: hard -"functions-have-names@npm:^1.2.2": +"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" checksum: 10/0ddfd3ed1066a55984aaecebf5419fbd9344a5c38dd120ffb0739fac4496758dcf371297440528b115e4367fc46e3abc86a2cc0ff44612181b175ae967a11a05 @@ -15403,6 +15995,19 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.2.4": + version: 1.2.4 + resolution: "get-intrinsic@npm:1.2.4" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10/85bbf4b234c3940edf8a41f4ecbd4e25ce78e5e6ad4e24ca2f77037d983b9ef943fd72f00f3ee97a49ec622a506b67db49c36246150377efcda1c9eb03e5f06d + languageName: node + linkType: hard + "get-nonce@npm:^1.0.0": version: 1.0.1 resolution: "get-nonce@npm:1.0.1" @@ -15930,6 +16535,15 @@ __metadata: languageName: node linkType: hard +"has-property-descriptors@npm:^1.0.2": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" + dependencies: + es-define-property: "npm:^1.0.0" + checksum: 10/2d8c9ab8cebb572e3362f7d06139a4592105983d4317e68f7adba320fe6ddfc8874581e0971e899e633fd5f72e262830edce36d5a0bc863dad17ad20572484b2 + languageName: node + linkType: hard + "has-proto@npm:^1.0.1": version: 1.0.1 resolution: "has-proto@npm:1.0.1" @@ -15953,6 +16567,15 @@ __metadata: languageName: node linkType: hard +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10/c74c5f5ceee3c8a5b8bc37719840dc3749f5b0306d818974141dda2471a1a2ca6c8e46b9d6ac222c5345df7a901c9b6f350b1e6d62763fec877e26609a401bfe + languageName: node + linkType: hard + "has-unicode@npm:^2.0.0": version: 2.0.1 resolution: "has-unicode@npm:2.0.1" @@ -16370,7 +16993,7 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^7.0.2": +"http-proxy-agent@npm:^7.0.0, http-proxy-agent@npm:^7.0.2": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" dependencies: @@ -16436,7 +17059,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.5": +"https-proxy-agent@npm:^7.0.2, https-proxy-agent@npm:^7.0.5": version: 7.0.5 resolution: "https-proxy-agent@npm:7.0.5" dependencies: @@ -16857,6 +17480,17 @@ __metadata: languageName: node linkType: hard +"internal-slot@npm:^1.0.4": + version: 1.0.7 + resolution: "internal-slot@npm:1.0.7" + dependencies: + es-errors: "npm:^1.3.0" + hasown: "npm:^2.0.0" + side-channel: "npm:^1.0.4" + checksum: 10/3e66720508831153ecf37d13def9f6856f9f2960989ec8a0a0476c98f887fca9eff0163127466485cb825c900c2d6fc601aa9117b7783b90ffce23a71ea5d053 + languageName: node + linkType: hard + "interpret@npm:^1.0.0": version: 1.4.0 resolution: "interpret@npm:1.4.0" @@ -16928,7 +17562,7 @@ __metadata: languageName: node linkType: hard -"is-arguments@npm:^1.0.4": +"is-arguments@npm:^1.0.4, is-arguments@npm:^1.1.1": version: 1.1.1 resolution: "is-arguments@npm:1.1.1" dependencies: @@ -16938,6 +17572,16 @@ __metadata: languageName: node linkType: hard +"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4": + version: 3.0.4 + resolution: "is-array-buffer@npm:3.0.4" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.1" + checksum: 10/34a26213d981d58b30724ef37a1e0682f4040d580fa9ff58fdfdd3cefcb2287921718c63971c1c404951e7b747c50fdc7caf6e867e951353fa71b369c04c969b + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -17066,6 +17710,15 @@ __metadata: languageName: node linkType: hard +"is-date-object@npm:^1.0.5": + version: 1.0.5 + resolution: "is-date-object@npm:1.0.5" + dependencies: + has-tostringtag: "npm:^1.0.0" + checksum: 10/cc80b3a4b42238fa0d358b9a6230dae40548b349e64a477cb7c5eff9b176ba194c11f8321daaf6dd157e44073e9b7fd01f87db1f14952a88d5657acdcd3a56e2 + languageName: node + linkType: hard + "is-decimal@npm:^1.0.0": version: 1.0.4 resolution: "is-decimal@npm:1.0.4" @@ -17200,6 +17853,13 @@ __metadata: languageName: node linkType: hard +"is-map@npm:^2.0.2, is-map@npm:^2.0.3": + version: 2.0.3 + resolution: "is-map@npm:2.0.3" + checksum: 10/8de7b41715b08bcb0e5edb0fb9384b80d2d5bcd10e142188f33247d19ff078abaf8e9b6f858e2302d8d05376a26a55cd23a3c9f8ab93292b02fcd2cc9e4e92bb + languageName: node + linkType: hard + "is-module@npm:^1.0.0": version: 1.0.0 resolution: "is-module@npm:1.0.0" @@ -17396,6 +18056,13 @@ __metadata: languageName: node linkType: hard +"is-set@npm:^2.0.2, is-set@npm:^2.0.3": + version: 2.0.3 + resolution: "is-set@npm:2.0.3" + checksum: 10/5685df33f0a4a6098a98c72d94d67cad81b2bc72f1fb2091f3d9283c4a1c582123cd709145b02a9745f0ce6b41e3e43f1c944496d1d74d4ea43358be61308669 + languageName: node + linkType: hard + "is-shared-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "is-shared-array-buffer@npm:1.0.2" @@ -17494,6 +18161,13 @@ __metadata: languageName: node linkType: hard +"is-weakmap@npm:^2.0.2": + version: 2.0.2 + resolution: "is-weakmap@npm:2.0.2" + checksum: 10/a7b7e23206c542dcf2fa0abc483142731788771527e90e7e24f658c0833a0d91948a4f7b30d78f7a65255a48512e41a0288b778ba7fc396137515c12e201fd11 + languageName: node + linkType: hard + "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -17503,6 +18177,16 @@ __metadata: languageName: node linkType: hard +"is-weakset@npm:^2.0.3": + version: 2.0.3 + resolution: "is-weakset@npm:2.0.3" + dependencies: + call-bind: "npm:^1.0.7" + get-intrinsic: "npm:^1.2.4" + checksum: 10/40159582ff1b44fc40085f631baf19f56479b05af2faede65b4e6a0b6acab745c13fd070e35b475aafd8a1ee50879ba5a3f1265125b46bebdb446b6be1f62165 + languageName: node + linkType: hard + "is-whitespace-character@npm:^1.0.0": version: 1.0.4 resolution: "is-whitespace-character@npm:1.0.4" @@ -17547,6 +18231,13 @@ __metadata: languageName: node linkType: hard +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: 10/1d8bc7911e13bb9f105b1b3e0b396c787a9e63046af0b8fe0ab1414488ab06b2b099b87a2d8a9e31d21c9a6fad773c7fc8b257c4880f2d957274479d28ca3414 + languageName: node + linkType: hard + "isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" @@ -18567,6 +19258,40 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^23.2.0": + version: 23.2.0 + resolution: "jsdom@npm:23.2.0" + dependencies: + "@asamuzakjp/dom-selector": "npm:^2.0.1" + cssstyle: "npm:^4.0.1" + data-urls: "npm:^5.0.0" + decimal.js: "npm:^10.4.3" + form-data: "npm:^4.0.0" + html-encoding-sniffer: "npm:^4.0.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.2" + is-potential-custom-element-name: "npm:^1.0.1" + parse5: "npm:^7.1.2" + rrweb-cssom: "npm:^0.6.0" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^4.1.3" + w3c-xmlserializer: "npm:^5.0.0" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^3.1.1" + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + ws: "npm:^8.16.0" + xml-name-validator: "npm:^5.0.0" + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + checksum: 10/71ad2e769515a23896881233a30d292e03752a5b01329e668a73cf205f935b55bf0881f345c747c5b4faf6288d5a01d0b0dae7b9f3379fa73d014c5a990ca0a0 + languageName: node + linkType: hard + "jsdom@npm:^25.0.1": version: 25.0.1 resolution: "jsdom@npm:25.0.1" @@ -18610,6 +19335,15 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^3.0.2": + version: 3.0.2 + resolution: "jsesc@npm:3.0.2" + bin: + jsesc: bin/jsesc + checksum: 10/8e5a7de6b70a8bd71f9cb0b5a7ade6a73ae6ab55e697c74cc997cede97417a3a65ed86c36f7dd6125fe49766e8386c845023d9e213916ca92c9dfdd56e2babf3 + languageName: node + linkType: hard + "jsesc@npm:~0.5.0": version: 0.5.0 resolution: "jsesc@npm:0.5.0" @@ -19559,6 +20293,13 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: 10/e4944322bf3e0461a2daa2aee7e14e208960a036289531e4ef009e53d32bd41528350c070c4a33be867980443fe4c0523518d99318423cffa7c825fe7b1154e2 + languageName: node + linkType: hard + "mdn-data@npm:2.0.4": version: 2.0.4 resolution: "mdn-data@npm:2.0.4" @@ -20112,6 +20853,39 @@ __metadata: languageName: node linkType: hard +"msw@npm:^2.6.6": + version: 2.6.6 + resolution: "msw@npm:2.6.6" + dependencies: + "@bundled-es-modules/cookie": "npm:^2.0.1" + "@bundled-es-modules/statuses": "npm:^1.0.1" + "@bundled-es-modules/tough-cookie": "npm:^0.1.6" + "@inquirer/confirm": "npm:^5.0.0" + "@mswjs/interceptors": "npm:^0.37.0" + "@open-draft/deferred-promise": "npm:^2.2.0" + "@open-draft/until": "npm:^2.1.0" + "@types/cookie": "npm:^0.6.0" + "@types/statuses": "npm:^2.0.4" + chalk: "npm:^4.1.2" + graphql: "npm:^16.8.1" + headers-polyfill: "npm:^4.0.2" + is-node-process: "npm:^1.2.0" + outvariant: "npm:^1.4.3" + path-to-regexp: "npm:^6.3.0" + strict-event-emitter: "npm:^0.5.1" + type-fest: "npm:^4.26.1" + yargs: "npm:^17.7.2" + peerDependencies: + typescript: ">= 4.8.x" + peerDependenciesMeta: + typescript: + optional: true + bin: + msw: cli/index.js + checksum: 10/7762ba5f1570789328af27167e03c2b8eb4981faa476ae47d74c125c90ddc1792bc28b9ce1100bbc4e105b55e3e7d65e7cae8d27fa7677b6516e42a63c38b7a3 + languageName: node + linkType: hard + "multicast-dns@npm:^7.2.5": version: 7.2.5 resolution: "multicast-dns@npm:7.2.5" @@ -20131,6 +20905,13 @@ __metadata: languageName: node linkType: hard +"mute-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "mute-stream@npm:2.0.0" + checksum: 10/d2e4fd2f5aa342b89b98134a8d899d8ef9b0a6d69274c4af9df46faa2d97aeb1f2ce83d867880d6de63643c52386579b99139801e24e7526c3b9b0a6d1e18d6c + languageName: node + linkType: hard + "mz@npm:^2.7.0": version: 2.7.0 resolution: "mz@npm:2.7.0" @@ -20392,6 +21173,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.18": + version: 2.0.18 + resolution: "node-releases@npm:2.0.18" + checksum: 10/241e5fa9556f1c12bafb83c6c3e94f8cf3d8f2f8f904906ecef6e10bcaa1d59aa61212d4651bec70052015fc54bd3fdcdbe7fc0f638a17e6685aa586c076ec4e + languageName: node + linkType: hard + "node-releases@npm:^2.0.6": version: 2.0.6 resolution: "node-releases@npm:2.0.6" @@ -20933,6 +21721,13 @@ __metadata: languageName: node linkType: hard +"outvariant@npm:^1.4.3": + version: 1.4.3 + resolution: "outvariant@npm:1.4.3" + checksum: 10/3a7582745850cb344d49641867a4c080858c54f4091afd91b9c0765ba6e471c2bc841348f0fff344845ddd0a4db42fd5d68c6f7ebaf32d4b676a3a9987b2488a + languageName: node + linkType: hard + "p-cancelable@npm:^1.0.0": version: 1.1.0 resolution: "p-cancelable@npm:1.1.0" @@ -21378,6 +22173,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:^6.3.0": + version: 6.3.0 + resolution: "path-to-regexp@npm:6.3.0" + checksum: 10/6822f686f01556d99538b350722ef761541ec0ce95ca40ce4c29e20a5b492fe8361961f57993c71b2418de12e604478dcf7c430de34b2c31a688363a7a944d9c + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -21434,6 +22236,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.0": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -21558,6 +22367,13 @@ __metadata: languageName: node linkType: hard +"possible-typed-array-names@npm:^1.0.0": + version: 1.0.0 + resolution: "possible-typed-array-names@npm:1.0.0" + checksum: 10/8ed3e96dfeea1c5880c1f4c9cb707e5fb26e8be22f14f82ef92df20fd2004e635c62ba47fbe8f2bb63bfd80dac1474be2fb39798da8c2feba2815435d1f749af + languageName: node + linkType: hard + "postcss-attribute-case-insensitive@npm:^5.0.1": version: 5.0.1 resolution: "postcss-attribute-case-insensitive@npm:5.0.1" @@ -22870,6 +23686,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.2.1": + version: 3.4.1 + resolution: "prettier@npm:3.4.1" + bin: + prettier: bin/prettier.cjs + checksum: 10/1ee4d1b1a9b6761cbb847cd81b9d87e51a0f4b2a4d5fe5755627c24828afe057a7ee9b764c3ee777d84abd46218d173d8a204ee9cb3acdd321ff9a6b25f99c1c + languageName: node + linkType: hard + "prettier@npm:^3.2.5": version: 3.2.5 resolution: "prettier@npm:3.2.5" @@ -23432,6 +24257,19 @@ __metadata: languageName: node linkType: hard +"react-intersection-observer@npm:^9.13.1": + version: 9.13.1 + resolution: "react-intersection-observer@npm:9.13.1" + peerDependencies: + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react-dom: + optional: true + checksum: 10/341e99fdd2fddeb031a7f3b513443a5bf894519236c2c39198bf04b212158c98157469dbed8ffdbff60812ae1ea8145af31b8b22edcbaec8185ce4a0d615df2b + languageName: node + linkType: hard + "react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -23523,6 +24361,13 @@ __metadata: languageName: node linkType: hard +"react-refresh@npm:^0.14.2": + version: 0.14.2 + resolution: "react-refresh@npm:0.14.2" + checksum: 10/512abf97271ab8623486061be04b608c39d932e3709f9af1720b41573415fa4993d0009fa5138b6705b60a98f4102f744d4e26c952b14f41a0e455521c6be4cc + languageName: node + linkType: hard + "react-remove-scroll-bar@npm:^2.1.0": version: 2.2.0 resolution: "react-remove-scroll-bar@npm:2.2.0" @@ -23655,6 +24500,24 @@ __metadata: languageName: node linkType: hard +"react-router@npm:^7.0.1": + version: 7.0.1 + resolution: "react-router@npm:7.0.1" + dependencies: + "@types/cookie": "npm:^0.6.0" + cookie: "npm:^1.0.1" + set-cookie-parser: "npm:^2.6.0" + turbo-stream: "npm:2.4.0" + peerDependencies: + react: ">=18" + react-dom: ">=18" + peerDependenciesMeta: + react-dom: + optional: true + checksum: 10/f41ee8b496c70f625112b0ade9e11575d8ef344e672704425db2fe4fb02ace66cb8aeb6fce56745dda85839fb589446fc5604f30e7e7860fb85f2eeb83216df5 + languageName: node + linkType: hard + "react-scripts@npm:5.0.1": version: 5.0.1 resolution: "react-scripts@npm:5.0.1" @@ -23986,6 +24849,18 @@ __metadata: languageName: node linkType: hard +"regexp.prototype.flags@npm:^1.5.1": + version: 1.5.3 + resolution: "regexp.prototype.flags@npm:1.5.3" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-errors: "npm:^1.3.0" + set-function-name: "npm:^2.0.2" + checksum: 10/fe17bc4eebbc72945aaf9dd059eb7784a5ca453a67cc4b5b3e399ab08452c9a05befd92063e2c52e7b24d9238c60031656af32dd57c555d1ba6330dbf8c23b43 + languageName: node + linkType: hard + "regexpp@npm:^3.0.0, regexpp@npm:^3.1.0": version: 3.2.0 resolution: "regexpp@npm:3.2.0" @@ -24762,6 +25637,13 @@ __metadata: languageName: node linkType: hard +"rrweb-cssom@npm:^0.6.0": + version: 0.6.0 + resolution: "rrweb-cssom@npm:0.6.0" + checksum: 10/5411836a4a78d6b68480767b8312de291f32d5710a278343954a778e5b420eaf13c90d9d2a942acf4718ddf497baa75ce653a314b332a380b6eaae1dee72257e + languageName: node + linkType: hard + "rrweb-cssom@npm:^0.7.1": version: 0.7.1 resolution: "rrweb-cssom@npm:0.7.1" @@ -25278,6 +26160,13 @@ __metadata: languageName: node linkType: hard +"set-cookie-parser@npm:^2.6.0": + version: 2.7.1 + resolution: "set-cookie-parser@npm:2.7.1" + checksum: 10/c92b1130032693342bca13ea1b1bc93967ab37deec4387fcd8c2a843c0ef2fd9a9f3df25aea5bb3976cd05a91c2cf4632dd6164d6e1814208fb7d7e14edd42b4 + languageName: node + linkType: hard + "set-function-length@npm:^1.1.1": version: 1.2.0 resolution: "set-function-length@npm:1.2.0" @@ -25291,6 +26180,32 @@ __metadata: languageName: node linkType: hard +"set-function-length@npm:^1.2.1": + version: 1.2.2 + resolution: "set-function-length@npm:1.2.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + checksum: 10/505d62b8e088468917ca4e3f8f39d0e29f9a563b97dbebf92f4bd2c3172ccfb3c5b8e4566d5fcd00784a00433900e7cb8fbc404e2dbd8c3818ba05bb9d4a8a6d + languageName: node + linkType: hard + +"set-function-name@npm:^2.0.2": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.2" + checksum: 10/c7614154a53ebf8c0428a6c40a3b0b47dac30587c1a19703d1b75f003803f73cdfa6a93474a9ba678fa565ef5fbddc2fae79bca03b7d22ab5fd5163dbe571a74 + languageName: node + linkType: hard + "setimmediate@npm:^1.0.5": version: 1.0.5 resolution: "setimmediate@npm:1.0.5" @@ -25886,6 +26801,15 @@ __metadata: languageName: node linkType: hard +"stop-iteration-iterator@npm:^1.0.0": + version: 1.0.0 + resolution: "stop-iteration-iterator@npm:1.0.0" + dependencies: + internal-slot: "npm:^1.0.4" + checksum: 10/2a23a36f4f6bfa63f46ae2d53a3f80fe8276110b95a55345d8ed3d92125413494033bc8697eb774e8f7aeb5725f70e3d69753caa2ecacdac6258c16fa8aa8b0f + languageName: node + linkType: hard + "strict-event-emitter@npm:^0.2.0": version: 0.2.0 resolution: "strict-event-emitter@npm:0.2.0" @@ -26915,6 +27839,18 @@ __metadata: languageName: node linkType: hard +"tough-cookie@npm:^4.1.3, tough-cookie@npm:^4.1.4": + version: 4.1.4 + resolution: "tough-cookie@npm:4.1.4" + dependencies: + psl: "npm:^1.1.33" + punycode: "npm:^2.1.1" + universalify: "npm:^0.2.0" + url-parse: "npm:^1.5.3" + checksum: 10/75663f4e2cd085f16af0b217e4218772adf0617fb3227171102618a54ce0187a164e505d61f773ed7d65988f8ff8a8f935d381f87da981752c1171b076b4afac + languageName: node + linkType: hard + "tough-cookie@npm:^5.0.0": version: 5.0.0 resolution: "tough-cookie@npm:5.0.0" @@ -27257,6 +28193,13 @@ __metadata: languageName: node linkType: hard +"turbo-stream@npm:2.4.0": + version: 2.4.0 + resolution: "turbo-stream@npm:2.4.0" + checksum: 10/7079bbc82b58340f783144cd669cc7e598288523103a8d68bb8a4c6bb28c64eccb71d389b33aab07788d3a9030638b795709e15cb8486f722b1cdac59cb58afc + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -27338,6 +28281,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.26.1": + version: 4.29.0 + resolution: "type-fest@npm:4.29.0" + checksum: 10/e13757fcbad2c7ee2418c4a888eb4de8f44ecabdc67f8a00b6d5c7af5f39c605154382f99f8f134f31c1f81bfbe3bf8d7e72e5129373afdb41b6b9199e74d062 + languageName: node + linkType: hard + "type-fest@npm:^4.9.0": version: 4.15.0 resolution: "type-fest@npm:4.15.0" @@ -27851,6 +28801,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.1": + version: 1.1.1 + resolution: "update-browserslist-db@npm:1.1.1" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.0" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10/7678dd8609750588d01aa7460e8eddf2ff9d16c2a52fb1811190e0d056390f1fdffd94db3cf8fb209cf634ab4fa9407886338711c71cc6ccade5eeb22b093734 + languageName: node + linkType: hard + "update-check@npm:1.5.4": version: 1.5.4 resolution: "update-check@npm:1.5.4" @@ -28231,6 +29195,32 @@ __metadata: languageName: node linkType: hard +"vite-template-redux@workspace:examples/query/react/infinite-queries": + version: 0.0.0-use.local + resolution: "vite-template-redux@workspace:examples/query/react/infinite-queries" + dependencies: + "@reduxjs/toolkit": "https://pkg.csb.dev/reduxjs/redux-toolkit/commit/aa419c22/@reduxjs/toolkit/_pkg.tgz" + "@testing-library/dom": "npm:^9.3.4" + "@testing-library/jest-dom": "npm:^6.2.0" + "@testing-library/react": "npm:^14.1.2" + "@testing-library/user-event": "npm:^14.5.2" + "@types/react": "npm:^18.2.47" + "@types/react-dom": "npm:^18.2.18" + "@vitejs/plugin-react": "npm:^4.2.1" + jsdom: "npm:^23.2.0" + msw: "npm:^2.6.6" + prettier: "npm:^3.2.1" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + react-intersection-observer: "npm:^9.13.1" + react-redux: "npm:^9.1.0" + react-router: "npm:^7.0.1" + typescript: "npm:^5.3.3" + vite: "npm:^5.0.0" + vitest: "npm:^1.2.0" + languageName: unknown + linkType: soft + "vite-tsconfig-paths@npm:^4.3.1": version: 4.3.1 resolution: "vite-tsconfig-paths@npm:4.3.1" @@ -28303,7 +29293,7 @@ __metadata: languageName: node linkType: hard -"vitest@npm:^1.6.0": +"vitest@npm:^1.2.0, vitest@npm:^1.6.0": version: 1.6.0 resolution: "vitest@npm:1.6.0" dependencies: @@ -28919,6 +29909,18 @@ __metadata: languageName: node linkType: hard +"which-collection@npm:^1.0.1": + version: 1.0.2 + resolution: "which-collection@npm:1.0.2" + dependencies: + is-map: "npm:^2.0.3" + is-set: "npm:^2.0.3" + is-weakmap: "npm:^2.0.2" + is-weakset: "npm:^2.0.3" + checksum: 10/674bf659b9bcfe4055f08634b48a8588e879161b9fefed57e9ec4ff5601e4d50a05ccd76cf10f698ef5873784e5df3223336d56c7ce88e13bcf52ebe582fc8d7 + languageName: node + linkType: hard + "which-module@npm:^2.0.0": version: 2.0.0 resolution: "which-module@npm:2.0.0" @@ -28946,6 +29948,19 @@ __metadata: languageName: node linkType: hard +"which-typed-array@npm:^1.1.13": + version: 1.1.16 + resolution: "which-typed-array@npm:1.1.16" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + checksum: 10/7106e94729632cdcedc94080442872392806b3364225156952981777f46b75d2e3b13813b5d935bdb2ac8523f8758fcf3513f7e1ed44a8e10d6c4f1029c3fa7d + languageName: node + linkType: hard + "which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1" @@ -29363,7 +30378,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.18.0": +"ws@npm:^8.16.0, ws@npm:^8.18.0": version: 8.18.0 resolution: "ws@npm:8.18.0" peerDependencies: @@ -29600,6 +30615,13 @@ __metadata: languageName: node linkType: hard +"yoctocolors-cjs@npm:^2.1.2": + version: 2.1.2 + resolution: "yoctocolors-cjs@npm:2.1.2" + checksum: 10/d731e3ba776a0ee19021d909787942933a6c2eafb2bbe85541f0c59aa5c7d475ce86fcb860d5803105e32244c3dd5ba875b87c4c6bf2d6f297da416aa54e556f + languageName: node + linkType: hard + "z-schema@npm:~3.18.3": version: 3.18.4 resolution: "z-schema@npm:3.18.4"