diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b8da699897..7d95a4f9dd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -99,6 +99,60 @@ jobs: TEST_DIST: true run: yarn test + - name: Run type tests with `moduleResolution Bundler` + run: rm -rf dist && yarn tsc -p . --moduleResolution Bundler --module ESNext --noEmit false --declaration --emitDeclarationOnly --outDir dist --target ESNext && rm -rf dist + + test-type-portability: + name: Test Type Portability with TypeScript ${{ matrix.ts }} and Node.js ${{ matrix.node }} + needs: [build] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node: ['20.x'] + ts: ['5.0', '5.1', '5.2', '5.3', '5.4', '5.5', 'next'] + example: + [ + { name: 'bundler', moduleResolution: 'Bundler' }, + { name: 'nodenext-cjs', moduleResolution: 'NodeNext' }, + { name: 'nodenext-esm', moduleResolution: 'NodeNext' }, + ] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Use node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'yarn' + + - name: Install deps + run: yarn install + + - uses: actions/download-artifact@v4 + with: + name: package + path: packages/toolkit + + - name: Install build artifact + run: yarn workspace @examples-type-portability/${{ matrix.example.name }} add $(pwd)/package.tgz + + - name: Install TypeScript ${{ matrix.ts }} + run: yarn workspace @examples-type-portability/${{ matrix.example.name }} add -D typescript@${{ matrix.ts }} + + - name: Test type portability with `moduleResolution ${{ matrix.example.moduleResolution }}` + run: yarn workspace @examples-type-portability/${{ matrix.example.name }} run test + + - name: Test type portability with `moduleResolution Node10` + run: yarn workspace @examples-type-portability/${{ matrix.example.name }} run test --module CommonJS --moduleResolution Node10 --preserveSymLinks --verbatimModuleSyntax false + + - name: Test type portability with `moduleResolution Node10` and `type module` in `package.json` + if: matrix.example.name == 'nodenext-esm' || matrix.example.name == 'bundler' + run: | + npm --workspace=@examples-type-portability/${{ matrix.example.name }} pkg set type=module + yarn workspace @examples-type-portability/${{ matrix.example.name }} run test --module ESNext --moduleResolution Node10 --preserveSymLinks --verbatimModuleSyntax false + test-types: name: Test Types with TypeScript ${{ matrix.ts }} diff --git a/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch b/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch index 74ee5988a2..7f41eabd06 100644 --- a/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch +++ b/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch @@ -1,3 +1,30 @@ +diff --git a/package.json b/package.json +index b924e066ecfdb30917b9c1056b360834da357698..15e155bd84f9d16537ffe36f9a87debcb0ec3591 100644 +--- a/package.json ++++ b/package.json +@@ -8,12 +8,15 @@ + "type": "module", + "main": "dist/index.js", + "typings": "index.d.ts", ++ "types": "index.d.ts", + "exports": { + ".": { ++ "types": "./index.d.ts", + "require": "./dist/index.js", + "default": "./src/index.js" + }, + "./pure": { ++ "types": "./pure.d.ts", + "require": "./dist/pure.js", + "default": "./src/pure.js" + } +diff --git a/pure.d.ts b/pure.d.ts +index b13bb4eb87d0b316bb51bd6094b2353c6fc8527d..ee01cc9bd3233f5e67b050d48e22202b495a4a0a 100644 +--- a/pure.d.ts ++++ b/pure.d.ts +@@ -1 +1 @@ +-export * from './'; ++export * from './index.js'; diff --git a/src/index.js b/src/index.js index 90ff7fa3d7d4fa62dbbf638958ae4e28abd089a8..28434687b5163b7472e86bdb11bed69e0868e660 100644 --- a/src/index.js @@ -5,7 +32,7 @@ index 90ff7fa3d7d4fa62dbbf638958ae4e28abd089a8..28434687b5163b7472e86bdb11bed69e @@ -1,4 +1,4 @@ -import { mockConsole, createConsole } from './pure'; +import { mockConsole, createConsole } from './pure.js'; - + // Keep an instance of the original console and export it const originalConsole = global.console; diff --git a/src/pure.js b/src/pure.js @@ -15,7 +42,7 @@ index b00ea2abbaea833e336676aa46e7ced2d59d6d88..42b83ed83fa16cf2234571500fe09868 @@ -228,10 +228,11 @@ export function restore() { global.console = global.originalConsole; } - + +/* if (typeof expect === 'function' && typeof expect.extend === 'function') { expect.extend({ @@ -24,13 +51,13 @@ index b00ea2abbaea833e336676aa46e7ced2d59d6d88..42b83ed83fa16cf2234571500fe09868 + // Workaround for custom inline snapshot matchers const error = new Error(); const stacks = error.stack.split('\n'); - + @@ -245,7 +246,6 @@ if (typeof expect === 'function' && typeof expect.extend === 'function') { error.stack = stacks.join('\n'); - + const context = Object.assign(this, { error }); - /* -------------------------------------------------------------- */ - + const testingConsoleInstance = (received && received.testingConsole) || received; @@ -270,3 +270,4 @@ if (typeof expect === 'function' && typeof expect.extend === 'function') { diff --git a/examples/type-portability/bundler/package.json b/examples/type-portability/bundler/package.json new file mode 100644 index 0000000000..895920e39a --- /dev/null +++ b/examples/type-portability/bundler/package.json @@ -0,0 +1,42 @@ +{ + "name": "@examples-type-portability/bundler", + "private": true, + "version": "1.0.0", + "description": "testing type portability for moduleResolution Bundler", + "keywords": [], + "main": "src/index.tsx", + "dependencies": { + "@reduxjs/toolkit": "workspace:^", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-redux": "^9.1.2", + "react-router-dom": "^6.25.1", + "react-scripts": "5.0.1" + }, + "devDependencies": { + "@types/node": "^20.14.11", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "typescript": "^5.5.4" + }, + "eslintConfig": { + "extends": [ + "react-app" + ], + "rules": { + "react/react-in-jsx-scope": "off" + } + }, + "scripts": { + "clean": "rm -rf dist", + "start": "react-scripts start", + "build": "react-scripts build", + "test": "yarn clean && tsc -p tsconfig.json" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/examples/type-portability/bundler/src/App.tsx b/examples/type-portability/bundler/src/App.tsx new file mode 100644 index 0000000000..b769e4ff4f --- /dev/null +++ b/examples/type-portability/bundler/src/App.tsx @@ -0,0 +1,36 @@ +import { Link, Route, Routes } from 'react-router-dom' +import { Lazy } from './features/bundleSplitting' +import { CounterList } from './features/counter/CounterList' +import { PollingToggles } from './features/polling/PollingToggles' +import { PostsManager } from './features/posts/PostsManager' +import { TimeList } from './features/time/TimeList' + +export function App() { + return ( +
+
+
+ + Times | Posts |{' '} + Counter |{' '} + Bundle Splitting + +
+
+ +
+
+
+
+ + } /> + } /> + } /> + } /> + +
+
+ ) +} + +export default App diff --git a/examples/type-portability/bundler/src/app/customModule.ts b/examples/type-portability/bundler/src/app/customModule.ts new file mode 100644 index 0000000000..86565b3084 --- /dev/null +++ b/examples/type-portability/bundler/src/app/customModule.ts @@ -0,0 +1,51 @@ +import type { + Api, + BaseQueryFn, + CoreModule, + EndpointDefinitions, + Module, +} from '@reduxjs/toolkit/query' +import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query' + +export const customModuleName = Symbol('customModule') +export type CustomModule = typeof customModuleName + +// If we remove this, We should get a TypeScript error. +declare module '@reduxjs/toolkit/query' { + export interface ApiModules< + BaseQuery extends BaseQueryFn, + Definitions extends EndpointDefinitions, + ReducerPath extends string, + TagTypes extends string, + > { + [customModuleName]: { + endpoints: { + [K in keyof Definitions]: { + myEndpointProperty: string + } + } + } + } +} + +export const myModule = (): Module => ({ + name: customModuleName, + init(api, options, context) { + // initialize stuff here if you need to + + return { + injectEndpoint(endpoint, definition) { + const anyApi = api as any as Api< + any, + Record, + string, + string, + CustomModule | CoreModule + > + anyApi.endpoints[endpoint].myEndpointProperty = 'test' + }, + } + }, +}) + +export const myCreateApi = buildCreateApi(coreModule(), myModule()) diff --git a/examples/type-portability/bundler/src/app/dynamicMiddleware.ts b/examples/type-portability/bundler/src/app/dynamicMiddleware.ts new file mode 100644 index 0000000000..e5b6067794 --- /dev/null +++ b/examples/type-portability/bundler/src/app/dynamicMiddleware.ts @@ -0,0 +1,10 @@ +import { createDynamicMiddleware } from '@reduxjs/toolkit' + +export const dynamicMiddleware = createDynamicMiddleware() + +export const { addMiddleware, instanceId, middleware, withMiddleware } = + dynamicMiddleware + +export const { withTypes, match, type } = withMiddleware + +export const { withTypes: _withTypes } = addMiddleware diff --git a/examples/type-portability/bundler/src/app/dynamicReactMiddleware.ts b/examples/type-portability/bundler/src/app/dynamicReactMiddleware.ts new file mode 100644 index 0000000000..524c5965e9 --- /dev/null +++ b/examples/type-portability/bundler/src/app/dynamicReactMiddleware.ts @@ -0,0 +1,19 @@ +import { createDynamicMiddleware } from '@reduxjs/toolkit/react' +import { listenerMiddleware } from './listenerMiddleware' + +export const dynamicReactMiddleware = createDynamicMiddleware() + +export const { + addMiddleware, + createDispatchWithMiddlewareHook, + createDispatchWithMiddlewareHookFactory, + instanceId, + middleware, + withMiddleware, +} = dynamicReactMiddleware + +export const { withTypes } = addMiddleware + +export const useDispatchWithMiddleware = createDispatchWithMiddlewareHook( + listenerMiddleware.middleware, +) diff --git a/examples/type-portability/bundler/src/app/hooks.ts b/examples/type-portability/bundler/src/app/hooks.ts new file mode 100644 index 0000000000..4f347f0438 --- /dev/null +++ b/examples/type-portability/bundler/src/app/hooks.ts @@ -0,0 +1,6 @@ +import { useDispatch, useSelector, useStore } from 'react-redux' +import type { AppDispatch, AppStore, RootState } from './store' + +export const useAppDispatch = useDispatch.withTypes() +export const useAppSelector = useSelector.withTypes() +export const useAppStore = useStore.withTypes() diff --git a/examples/type-portability/bundler/src/app/listenerMiddleware.ts b/examples/type-portability/bundler/src/app/listenerMiddleware.ts new file mode 100644 index 0000000000..82a664954c --- /dev/null +++ b/examples/type-portability/bundler/src/app/listenerMiddleware.ts @@ -0,0 +1,10 @@ +import { createListenerMiddleware } from '@reduxjs/toolkit' + +export const listenerMiddleware = createListenerMiddleware() + +export const { clearListeners, middleware, startListening, stopListening } = + listenerMiddleware + +export const { withTypes } = startListening + +export const { withTypes: _withTypes } = stopListening diff --git a/examples/type-portability/bundler/src/app/services/api.ts b/examples/type-portability/bundler/src/app/services/api.ts new file mode 100644 index 0000000000..4ff6afab9e --- /dev/null +++ b/examples/type-portability/bundler/src/app/services/api.ts @@ -0,0 +1,100 @@ +import { + createApi, + fakeBaseQuery, + fetchBaseQuery, + retry, +} from '@reduxjs/toolkit/query/react' +import type { RootState } from '../store' + +export const baseQuery = fetchBaseQuery({ + baseUrl: '/', + prepareHeaders: (headers, { getState }) => { + const { token } = (getState() as RootState).auth + + if (token) { + headers.set('authentication', `Bearer ${token}`) + } + + return headers + }, +}) + +export const baseQueryWithRetry = retry(baseQuery, { maxRetries: 6 }) + +export const apiSlice = createApi({ + reducerPath: 'api', + baseQuery: baseQueryWithRetry, + tagTypes: ['Time', 'Posts', 'Counter'], + endpoints: () => ({}), +}) + +export const enhancedApi = apiSlice.enhanceEndpoints({ + endpoints: () => ({ + getPost: () => 'test', + }), +}) + +export const emptyApi = createApi({ + baseQuery: fakeBaseQuery(), + endpoints: () => ({}), +}) + +export const { + endpoints: _endpoints, + enhanceEndpoints: _enhanceEndpoints, + injectEndpoints: _injectEndpoints, + internalActions: _internalActions, + middleware: _middleware, + reducer: _reducer, + reducerPath: _reducerPath, + usePrefetch: _usePrefetch, + util: _util, +} = apiSlice + +export const { + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = enhancedApi + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { match, type } = updateSubscriptionOptions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util + +export const { match: _match, type: _type } = invalidateTags diff --git a/examples/type-portability/bundler/src/app/services/counter.ts b/examples/type-portability/bundler/src/app/services/counter.ts new file mode 100644 index 0000000000..3efdbb97af --- /dev/null +++ b/examples/type-portability/bundler/src/app/services/counter.ts @@ -0,0 +1,88 @@ +import { apiSlice } from './api' + +export interface CountResponse { + count: number +} + +export const counterApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + getCount: build.query({ + query: () => 'count', + providesTags: ['Counter'], + }), + incrementCount: build.mutation({ + query(amount) { + return { + url: `increment`, + method: 'PUT', + body: { amount }, + } + }, + invalidatesTags: ['Counter'], + }), + decrementCount: build.mutation({ + query(amount) { + return { + url: `decrement`, + method: 'PUT', + body: { amount }, + } + }, + invalidatesTags: ['Counter'], + }), + }), +}) + +export const { + useDecrementCountMutation, + useGetCountQuery, + useIncrementCountMutation, + useLazyGetCountQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = counterApi + +export const { decrementCount, getCount, incrementCount } = endpoints + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { match, type } = updateSubscriptionOptions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util + +export const { match: _match, type: _type } = invalidateTags diff --git a/examples/type-portability/bundler/src/app/services/post.ts b/examples/type-portability/bundler/src/app/services/post.ts new file mode 100644 index 0000000000..f7348ec00d --- /dev/null +++ b/examples/type-portability/bundler/src/app/services/post.ts @@ -0,0 +1,128 @@ +import { apiSlice } from './api' +import type { Post } from './posts' + +export const postApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + addPost: build.mutation>({ + query(body) { + return { + url: `posts`, + method: 'POST', + body, + } + }, + invalidatesTags: ['Posts'], + }), + getPost: build.query({ + query: (id) => `posts/${id}`, + providesTags: (_result, _err, id) => [{ type: 'Posts', id }], + }), + updatePost: build.mutation>({ + query(data) { + const { id, ...body } = data + return { + url: `posts/${id}`, + method: 'PUT', + body, + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + deletePost: build.mutation<{ success: boolean; id: number }, number>({ + query(id) { + return { + url: `posts/${id}`, + method: 'DELETE', + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + }), +}) + +export const { + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = postApi + +export const { addPost, deletePost, getPost, updatePost } = endpoints + +export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useMutation, +} = addPost + +export const { + BaseQuery, + MutationDefinition, + QueryArg, + ReducerPath, + ResultType, + TagTypes, +} = Types + +export const { + type: __type, + Types: _Types, + extraOptions, + invalidatesTags, + onCacheEntryAdded, + onQueryStarted, + providesTags, + query, + queryFn, + structuralSharing, + transformErrorResponse, + transformResponse, +} = MutationDefinition + +export const { fetched_at, id, name: _name } = QueryArg + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { match, type } = updateSubscriptionOptions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util + +export const { match: _match, type: _type } = invalidateTags diff --git a/examples/type-portability/bundler/src/app/services/posts.ts b/examples/type-portability/bundler/src/app/services/posts.ts new file mode 100644 index 0000000000..b57c44dea4 --- /dev/null +++ b/examples/type-portability/bundler/src/app/services/posts.ts @@ -0,0 +1,215 @@ +import { retry } from '@reduxjs/toolkit/query/react' +import { apiSlice } from './api' + +export interface Post { + id: number + name: string + fetched_at: string +} + +export type PostsResponse = Post[] + +export interface User { + first_name: string + last_name: string + email: string + phone: string +} + +export const postsApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + login: build.mutation<{ token: string; user: User }, any>({ + query: (credentials: any) => ({ + url: 'login', + method: 'POST', + body: credentials, + }), + extraOptions: { + backoff: () => { + // We intentionally error once on login, and this breaks out of retrying. The next login attempt will succeed. + retry.fail({ fake: 'error' }) + }, + }, + }), + getPosts: build.query({ + query: () => ({ url: 'posts' }), + providesTags: (result = []) => [ + ...result.map(({ id }) => ({ type: 'Posts', id }) as const), + { type: 'Posts' as const, id: 'LIST' }, + ], + }), + addPost: build.mutation>({ + query: (body) => ({ + url: `posts`, + method: 'POST', + body, + }), + invalidatesTags: [{ type: 'Posts', id: 'LIST' }], + }), + getPost: build.query({ + query: (id) => `posts/${id}`, + providesTags: (_post, _err, id) => [{ type: 'Posts', id }], + }), + updatePost: build.mutation>({ + query(data) { + const { id, ...body } = data + return { + url: `posts/${id}`, + method: 'PUT', + body, + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + deletePost: build.mutation<{ success: boolean; id: number }, number>({ + query(id) { + return { + url: `posts/${id}`, + method: 'DELETE', + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + getErrorProne: build.query<{ success: boolean }, void>({ + query: () => 'error-prone', + }), + }), +}) + +export const { + useAddPostMutation, + useDeletePostMutation, + useGetPostQuery, + useGetPostsQuery, + useLoginMutation, + useUpdatePostMutation, + useGetErrorProneQuery, + useLazyGetErrorProneQuery, + useLazyGetPostQuery, + useLazyGetPostsQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = postsApi + +export const { + addPost, + deletePost, + getErrorProne, + getPost, + getPosts, + login, + updatePost, +} = endpoints + +export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useMutation, +} = addPost + +export const { + Types: _Types, + initiate: _initiate, + matchFulfilled: _matchFulfilled, + matchPending: _matchPending, + matchRejected: _matchRejected, + name: _name, + select: _select, + useMutation: _useMutation, +} = deletePost + +export const { + Types: __Types, + initiate: __initiate, + matchFulfilled: __matchFulfilled, + matchPending: __matchPending, + matchRejected: __matchRejected, + name: __name, + select: __select, + useQueryState, + useLazyQuery, + useLazyQuerySubscription, + useQuery, + useQuerySubscription, +} = getErrorProne + +export const { + Types: ___Types, + initiate: ___initiate, + matchFulfilled: ___matchFulfilled, + matchPending: ___matchPending, + matchRejected: ___matchRejected, + name: ___name, + select: ___select, + useQueryState: ___useQueryState, + useLazyQuery: ___useLazyQuery, + useLazyQuerySubscription: ___useLazyQuerySubscription, + useQuery: ___useQuery, + useQuerySubscription: ___useQuerySubscription, +} = getPost + +const { + Types: ____Types, + initiate: ____initiate, + matchFulfilled: ____matchFulfilled, + matchPending: ____matchPending, + matchRejected: ____matchRejected, + name: ____name, + select: ____select, + useMutation: ____useMutation, +} = login + +export const { + Types: _____Types, + initiate: _____initiate, + matchFulfilled: _____matchFulfilled, + matchPending: _____matchPending, + matchRejected: _____matchRejected, + name: _____name, + select: _____select, + useMutation: _____useMutation, +} = updatePost + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util diff --git a/examples/type-portability/bundler/src/app/services/times.ts b/examples/type-portability/bundler/src/app/services/times.ts new file mode 100644 index 0000000000..4ae2bf1128 --- /dev/null +++ b/examples/type-portability/bundler/src/app/services/times.ts @@ -0,0 +1,77 @@ +import { apiSlice } from './api' + +export interface TimeResponse { + time: string +} + +export const timeApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + getTime: build.query({ + query: (id) => `time/${id}`, + providesTags: (_result, _err, id) => [{ type: 'Time', id }], + }), + }), +}) + +export const { + useLazyGetTimeQuery, + usePrefetch: usePrefetchTime, + useGetTimeQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + util, +} = timeApi + +export const { getTime } = endpoints + +export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useQuery, + useLazyQuery, + useQuerySubscription, + useQueryState, + useLazyQuerySubscription, +} = getTime + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util diff --git a/examples/type-portability/bundler/src/app/store.ts b/examples/type-portability/bundler/src/app/store.ts new file mode 100644 index 0000000000..470fea977b --- /dev/null +++ b/examples/type-portability/bundler/src/app/store.ts @@ -0,0 +1,38 @@ +import { combineSlices, configureStore } from '@reduxjs/toolkit' +import { setupListeners } from '@reduxjs/toolkit/query' +import { authSlice } from '../features/auth/authSlice' +import { pollingSlice } from '../features/polling/pollingSlice' +import { dynamicMiddleware } from './dynamicMiddleware' +import { dynamicReactMiddleware } from './dynamicReactMiddleware' +import { listenerMiddleware } from './listenerMiddleware' +import { apiSlice } from './services/api' + +export const rootReducer = combineSlices(pollingSlice, authSlice, apiSlice) + +export const { inject, selector, withLazyLoadedSlices } = rootReducer + +export const { original } = selector + +export type RootState = ReturnType + +export const setupStore = (preloadedState?: Partial) => + configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware() + .prepend(listenerMiddleware.middleware) + .prepend(dynamicMiddleware.middleware) + .prepend(dynamicReactMiddleware.middleware) + .concat(apiSlice.middleware), + preloadedState, + enhancers: (getDefaultEnhancers) => getDefaultEnhancers(), + }) + +export const store = setupStore() + +setupListeners(store.dispatch) + +export const { dispatch, getState, replaceReducer, subscribe } = store + +export type AppStore = typeof store +export type AppDispatch = typeof store.dispatch diff --git a/examples/type-portability/bundler/src/features/auth/authSlice.ts b/examples/type-portability/bundler/src/features/auth/authSlice.ts new file mode 100644 index 0000000000..b1939e24f6 --- /dev/null +++ b/examples/type-portability/bundler/src/features/auth/authSlice.ts @@ -0,0 +1,56 @@ +import { createSlice } from '@reduxjs/toolkit' +import type { User } from '../../app/services/posts' +import { postsApi } from '../../app/services/posts' + +export const initialState = { + user: null, + token: null, + isAuthenticated: false, +} as { user: null | User; token: string | null; isAuthenticated: boolean } + +export const authSlice = createSlice({ + name: 'auth', + initialState, + reducers: { + logout: () => initialState, + }, + extraReducers: (builder) => { + builder + .addMatcher(postsApi.endpoints.login.matchPending, (state, action) => { + console.log('pending', action) + }) + .addMatcher(postsApi.endpoints.login.matchFulfilled, (state, action) => { + console.log('fulfilled', action) + state.user = action.payload.user + state.token = action.payload.token + state.isAuthenticated = true + }) + .addMatcher(postsApi.endpoints.login.matchRejected, (state, action) => { + console.log('rejected', action) + }) + }, + selectors: { + selectIsAuthenticated: (authState) => authState.isAuthenticated, + }, +}) + +export const { + actions, + caseReducers, + getInitialState, + getSelectors, + injectInto, + name, + reducer, + reducerPath, + selectSlice, + selectors, +} = authSlice + +export const { selectIsAuthenticated } = getSelectors(selectSlice) + +export const { unwrapped } = selectIsAuthenticated + +export const { logout: _logout } = caseReducers + +export const { logout } = authSlice.actions diff --git a/examples/type-portability/bundler/src/features/bundleSplitting/Lazy.tsx b/examples/type-portability/bundler/src/features/bundleSplitting/Lazy.tsx new file mode 100644 index 0000000000..98ef1d0709 --- /dev/null +++ b/examples/type-portability/bundler/src/features/bundleSplitting/Lazy.tsx @@ -0,0 +1,10 @@ +import { Suspense } from 'react' +import { PostsList } from '.' + +export const Lazy = () => { + return ( + loading...}> + + + ) +} diff --git a/examples/type-portability/bundler/src/features/bundleSplitting/Post.tsx b/examples/type-portability/bundler/src/features/bundleSplitting/Post.tsx new file mode 100644 index 0000000000..3328d41f96 --- /dev/null +++ b/examples/type-portability/bundler/src/features/bundleSplitting/Post.tsx @@ -0,0 +1,27 @@ +// import the file that injects "post" to make sure it has been loaded +import { postApi } from '../../app/services/post' + +export function assert( + condition: any, + msg = 'Generic Assertion', +): asserts condition { + if (!condition) { + throw new Error(`Assertion failed: ${msg}`) + } +} + +export const Post = ({ id }: { id: number }) => { + assert(postApi.endpoints.getPost?.useQuery, 'Endpoint `getPost` not loaded!') + + const { data, error } = postApi.endpoints.getPost.useQuery(id) + + return error ? ( + <>there was an error + ) : !data ? ( + <>loading + ) : ( +

{data.name}

+ ) +} + +export default Post diff --git a/examples/type-portability/bundler/src/features/bundleSplitting/PostsList.tsx b/examples/type-portability/bundler/src/features/bundleSplitting/PostsList.tsx new file mode 100644 index 0000000000..632b1068b8 --- /dev/null +++ b/examples/type-portability/bundler/src/features/bundleSplitting/PostsList.tsx @@ -0,0 +1,27 @@ +import { useState } from 'react' +import { Post } from '.' +import { postsApi } from '../../app/services/posts' + +export const PostsList = () => { + const { data, error } = postsApi.endpoints.getPosts.useQuery() + const [selected, select] = useState() + + return error ? ( + <>there was an error + ) : !data ? ( + <>loading + ) : ( + <> + {selected && } +
    + {data.map((post) => ( +
  • + +
  • + ))} +
+ + ) +} + +export default PostsList diff --git a/examples/type-portability/bundler/src/features/bundleSplitting/index.ts b/examples/type-portability/bundler/src/features/bundleSplitting/index.ts new file mode 100644 index 0000000000..3f44977e21 --- /dev/null +++ b/examples/type-portability/bundler/src/features/bundleSplitting/index.ts @@ -0,0 +1,7 @@ +import { lazy } from 'react' + +export const PostsList = lazy(() => import('./PostsList')) + +export const Post = lazy(() => import('./Post')) + +export { Lazy } from './Lazy' diff --git a/examples/type-portability/bundler/src/features/common/Container.tsx b/examples/type-portability/bundler/src/features/common/Container.tsx new file mode 100644 index 0000000000..183436677e --- /dev/null +++ b/examples/type-portability/bundler/src/features/common/Container.tsx @@ -0,0 +1,7 @@ +import type { FC, ReactNode } from 'react' + +export const Container: FC<{ children: ReactNode }> = ({ children }) => ( +
+ {children} +
+) diff --git a/examples/type-portability/bundler/src/features/counter/Counter.tsx b/examples/type-portability/bundler/src/features/counter/Counter.tsx new file mode 100644 index 0000000000..6d0ce6bfc2 --- /dev/null +++ b/examples/type-portability/bundler/src/features/counter/Counter.tsx @@ -0,0 +1,43 @@ +import { useState } from 'react' +import { + useDecrementCountMutation, + useGetCountQuery, + useIncrementCountMutation, +} from '../../app/services/counter' + +export function Counter({ + id, + onRemove, +}: { + id?: string + onRemove?: () => void +}) { + const [pollingInterval, setPollingInterval] = useState(10_000) + const { data } = useGetCountQuery(undefined, { pollingInterval }) + const [increment] = useIncrementCountMutation() + + const [decrement] = useDecrementCountMutation() + + return ( +
+
+ + {data?.count || 0} + + + setPollingInterval(valueAsNumber) + } + /> + {onRemove && } +
+
+ ) +} diff --git a/examples/type-portability/bundler/src/features/counter/CounterList.tsx b/examples/type-portability/bundler/src/features/counter/CounterList.tsx new file mode 100644 index 0000000000..244b8b5283 --- /dev/null +++ b/examples/type-portability/bundler/src/features/counter/CounterList.tsx @@ -0,0 +1,38 @@ +import { nanoid } from '@reduxjs/toolkit' +import { useState } from 'react' +import { Container } from '../common/Container' +import { Counter } from './Counter' + +export const CounterList = () => { + const [counters, setCounters] = useState([]) + + if (!counters.length) { + return ( + +
No counters, why don't you add one?
+
+ +
+
+ ) + } + + return ( + +
+ +
+ {counters.map((id) => ( + setCounters((prev) => prev.filter((el) => el !== id))} + /> + ))} +
+ ) +} diff --git a/examples/type-portability/bundler/src/features/polling/PollingToggles.tsx b/examples/type-portability/bundler/src/features/polling/PollingToggles.tsx new file mode 100644 index 0000000000..90e2f87521 --- /dev/null +++ b/examples/type-portability/bundler/src/features/polling/PollingToggles.tsx @@ -0,0 +1,59 @@ +import type { ReactNode } from 'react' +import { useAppDispatch, useAppSelector } from '../../app/hooks' +import { + selectGlobalPollingEnabled, + selectPollingConfigByApp, + toggleGlobalPolling, + updatePolling, +} from './pollingSlice' + +export const PollingToggleButton = ({ + enabled, + onClick, + children, +}: { + onClick: () => void + enabled: boolean + children?: ReactNode +}) => { + return ( + + ) +} + +export const PollingToggles = () => { + const dispatch = useAppDispatch() + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + const timesPolling = useAppSelector((state) => + selectPollingConfigByApp(state, 'times'), + ) + + return ( +
+ Global Polling Configs +
+ dispatch(toggleGlobalPolling())} + > + Global + + + dispatch( + updatePolling({ app: 'times', enabled: !timesPolling.enabled }), + ) + } + > + Times + +
+
+ ) +} diff --git a/examples/type-portability/bundler/src/features/polling/pollingSlice.ts b/examples/type-portability/bundler/src/features/polling/pollingSlice.ts new file mode 100644 index 0000000000..c55eed9266 --- /dev/null +++ b/examples/type-portability/bundler/src/features/polling/pollingSlice.ts @@ -0,0 +1,95 @@ +import type { PayloadAction } from '@reduxjs/toolkit' +import { createSlice } from '@reduxjs/toolkit' +import type { RootState } from '../../app/store' + +export type PollingConfig = { + enabled: boolean + interval: number +} + +export type SliceState = { + enabled: boolean + apps: { + [key: string]: PollingConfig + } +} + +export const initialState: SliceState = { + enabled: true, + apps: { + counters: { + enabled: true, + interval: 0, + }, + times: { + enabled: true, + interval: 0, + }, + posts: { + enabled: true, + interval: 0, + }, + }, +} + +export type PollingAppKey = keyof (typeof initialState)['apps'] + +export const pollingSlice = createSlice({ + name: 'polling', + initialState, + reducers: (creators) => { + return { + toggleGlobalPolling: creators.reducer((state) => { + state.enabled = !state.enabled + }), + updatePolling( + state, + { + payload, + }: PayloadAction<{ + app: PollingAppKey + enabled?: boolean + interval?: number + }>, + ) { + const { app, ...rest } = payload + state.apps[app] = { + ...state.apps[app], + ...rest, + } + }, + } + }, + selectors: { + selectGlobalPollingEnabled: (pollingState) => pollingState.enabled, + }, +}) + +export const { + actions, + caseReducers, + getInitialState, + getSelectors, + injectInto, + name, + reducer, + reducerPath, + selectSlice, + selectors, +} = pollingSlice + +export const { + toggleGlobalPolling: _toggleGlobalPolling, + updatePolling: _updatePolling, +} = caseReducers + +export const { toggleGlobalPolling, updatePolling } = pollingSlice.actions + +export const { selectGlobalPollingEnabled } = selectors + +export const { unwrapped } = selectGlobalPollingEnabled + +export const selectPollingConfigByApp = ( + state: RootState, + app: PollingAppKey, +) => state.polling.apps[app] diff --git a/examples/type-portability/bundler/src/features/posts/PostDetail.tsx b/examples/type-portability/bundler/src/features/posts/PostDetail.tsx new file mode 100644 index 0000000000..171fd67157 --- /dev/null +++ b/examples/type-portability/bundler/src/features/posts/PostDetail.tsx @@ -0,0 +1,129 @@ +import type { ChangeEvent, FormEventHandler } from 'react' +import { useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import { useAppSelector } from '../../app/hooks' +import { + useDeletePostMutation, + useGetPostQuery, + useUpdatePostMutation, +} from '../../app/services/posts' +import { selectGlobalPollingEnabled } from '../polling/pollingSlice' + +export const EditablePostName = ({ + name: initialName, + onUpdate, + onCancel, + loading = false, +}: { + name: string + onUpdate: (name: string) => void + onCancel: () => void + loading?: boolean +}) => { + const [name, setName] = useState(initialName) + + const handleChange = ({ target: { value } }: ChangeEvent) => + setName(value) + + const handleSubmit: FormEventHandler = (e) => { + e.preventDefault() + onUpdate(name) + } + const handleCancel = () => onCancel() + + return ( +
+
+ + + +
+
+ ) +} + +export const PostJsonDetail = ({ id }: { id: number }) => { + const { data: post } = useGetPostQuery(id) + + return ( +
+
{JSON.stringify(post, null, 2)}
+
+ ) +} + +export const PostDetail = () => { + const { id } = useParams<{ id: any }>() + const navigate = useNavigate() + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + + const [isEditing, setIsEditing] = useState(false) + + const { + data: post, + isFetching, + isLoading, + } = useGetPostQuery(id, { pollingInterval: globalPolling ? 3000 : 0 }) + + const [updatePost, { isLoading: isUpdating }] = useUpdatePostMutation() + const [deletePost, { isLoading: isDeleting }] = useDeletePostMutation() + + if (isLoading) { + return
Loading...
+ } + + if (!post) { + return
Missing post!
+ } + + return ( +
+ {isEditing ? ( + + updatePost({ id, name }) + .then((result) => { + // handle the success! + console.log('Update Result', result) + setIsEditing(false) + }) + .catch((error) => console.error('Update Error', error)) + } + onCancel={() => setIsEditing(false)} + loading={isUpdating} + /> + ) : ( +
+
+

+ {post.name} {isFetching ? '...refetching' : ''} +

+
+ + +
+ )} + +
+ ) +} diff --git a/examples/type-portability/bundler/src/features/posts/PostsManager.tsx b/examples/type-portability/bundler/src/features/posts/PostsManager.tsx new file mode 100644 index 0000000000..7474bee286 --- /dev/null +++ b/examples/type-portability/bundler/src/features/posts/PostsManager.tsx @@ -0,0 +1,141 @@ +import type { ChangeEvent, FormEventHandler } from 'react' +import { useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { Route, Routes, useNavigate } from 'react-router-dom' +import type { Post } from '../../app/services/posts' +import { + useAddPostMutation, + useGetErrorProneQuery, + useGetPostsQuery, + useLoginMutation, +} from '../../app/services/posts' +import { logout, selectIsAuthenticated } from '../auth/authSlice' +import { PostDetail } from './PostDetail' + +export const AddPost = () => { + const initialValue = { name: '' } + const [post, setPost] = useState>(initialValue) + const [addPost, { isLoading }] = useAddPostMutation() + + const handleChange = ({ target }: ChangeEvent) => { + setPost((prev) => ({ + ...prev, + [target.name]: target.value, + })) + } + + const handleSubmit: FormEventHandler = async (e) => { + e.preventDefault() + await addPost(post) + setPost(initialValue) + } + + return ( +
+
+
+ +
+
+ +
+
+
+ ) +} + +export const PostListItem = ({ + data: { name, id }, + onSelect, +}: { + data: Post + onSelect: (id: number) => void +}) => { + return ( +
  • + onSelect(id)}> + {name} + +
  • + ) +} + +export const PostList = () => { + const { data: posts, isLoading } = useGetPostsQuery() + const navigate = useNavigate() + + if (isLoading) { + return
    Loading
    + } + + if (!posts) { + return
    No posts :(
    + } + + return ( +
    + {posts.map((post) => ( + navigate(`/posts/${id}`)} + /> + ))} +
    + ) +} + +export const PostsManager = () => { + const [login] = useLoginMutation() + const [initRetries, setInitRetries] = useState(false) + const { data, error, isFetching } = useGetErrorProneQuery(undefined, { + skip: !initRetries, + }) + const dispatch = useDispatch() + const isAuthenticated = useSelector(selectIsAuthenticated) + + return ( +
    +

    Posts

    + {!isAuthenticated ? ( + + ) : ( + + )} + +
    +
    +
    + +
    + Posts: + +
    + List with duplicate subscription: + +
    +
    + + } /> + +
    +
    +
    + ) +} + +export default PostsManager diff --git a/examples/type-portability/bundler/src/features/time/TimeList.tsx b/examples/type-portability/bundler/src/features/time/TimeList.tsx new file mode 100644 index 0000000000..8544e0aef7 --- /dev/null +++ b/examples/type-portability/bundler/src/features/time/TimeList.tsx @@ -0,0 +1,170 @@ +import { nanoid } from '@reduxjs/toolkit' +import * as React from 'react' +import { useEffect } from 'react' +import { useAppSelector } from '../../app/hooks' +import { useGetTimeQuery, usePrefetchTime } from '../../app/services/times' +import { Container } from '../common/Container' +import { + selectGlobalPollingEnabled, + selectPollingConfigByApp, +} from '../polling/pollingSlice' + +export const timezones: Record = { + '-12:00': '(GMT -12:00) Eniwetok, Kwajalein', + '-11:00': '(GMT -11:00) Midway Island, Samoa', + '-10:00': '(GMT -10:00) Hawaii', + '-09:50': '(GMT -9:30) Taiohae', + '-09:00': '(GMT -9:00) Alaska', + '-08:00': '(GMT -8:00) Pacific Time (US & Canada)', + '-07:00': '(GMT -7:00) Mountain Time (US & Canada)', + '-06:00': '(GMT -6:00) Central Time (US & Canada), Mexico City', + '-05:00': '(GMT -5:00) Eastern Time (US & Canada), Bogota, Lima', + '-04:50': '(GMT -4:30) Caracas', + '-04:00': '(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz', + '-03:50': '(GMT -3:30) Newfoundland', + '-03:00': '(GMT -3:00) Brazil, Buenos Aires, Georgetown', + '-02:00': '(GMT -2:00) Mid-Atlantic', + '-01:00': '(GMT -1:00) Azores, Cape Verde Islands', + '+00:00': '(GMT) Western Europe Time, London, Lisbon, Casablanca', + '+01:00': '(GMT +1:00) Brussels, Copenhagen, Madrid, Paris', + '+02:00': '(GMT +2:00) Kaliningrad, South Africa', + '+03:00': '(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg', + '+03:50': '(GMT +3:30) Tehran', + '+04:00': '(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi', + '+04:50': '(GMT +4:30) Kabul', + '+05:00': '(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent', + '+05:50': '(GMT +5:30) Bombay, Calcutta, Madras, New Delhi', + '+05:75': '(GMT +5:45) Kathmandu, Pokhara', + '+06:00': '(GMT +6:00) Almaty, Dhaka, Colombo', + '+06:50': '(GMT +6:30) Yangon, Mandalay', + '+07:00': '(GMT +7:00) Bangkok, Hanoi, Jakarta', + '+08:00': '(GMT +8:00) Beijing, Perth, Singapore, Hong Kong', + '+08:75': '(GMT +8:45) Eucla', + '+09:00': '(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk', + '+09:50': '(GMT +9:30) Adelaide, Darwin', + '+10:00': '(GMT +10:00) Eastern Australia, Guam, Vladivostok', + '+10:50': '(GMT +10:30) Lord Howe Island', + '+11:00': '(GMT +11:00) Magadan, Solomon Islands, New Caledonia', + '+11:50': '(GMT +11:30) Norfolk Island', + '+12:00': '(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka', + '+12:75': '(GMT +12:45) Chatham Islands', + '+13:00': '(GMT +13:00) Apia, Nukualofa', + '+14:00': '(GMT +14:00) Line Islands, Tokelau', +} + +export const TimeZoneSelector = ({ + onChange, +}: { + onChange: (event: React.ChangeEvent) => void +}) => { + return ( + + ) +} + +export const intervalOptions = [ + { label: '0 - Off', value: 0 }, + { label: '1s', value: 1000 }, + { label: '3s', value: 3000 }, + { label: '5s', value: 5000 }, + { label: '10s', value: 10_000 }, + { label: '1m', value: 60_000 }, +] + +export const TimeDisplay = ({ offset, label }: { offset: string; label: string }) => { + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + const { enabled: timesPolling } = useAppSelector((state) => + selectPollingConfigByApp(state, 'times'), + ) + + const canPoll = globalPolling && timesPolling + + const [pollingInterval, setPollingInterval] = React.useState(0) + const { data, refetch, isFetching } = useGetTimeQuery(offset, { + pollingInterval: canPoll ? pollingInterval : 0, + }) + + return ( +
    +

    + {data?.time && new Date(data.time).toLocaleTimeString()} - {label} +

    +

    + Polling Interval:{' '} + +

    +
    + ) +} + +export const TimeList = () => { + const [times, setTimes] = React.useState<{ [key: string]: string }>({ + [nanoid()]: '-08:00', + }) + const [selectedValue, setSelectedValue] = React.useState('') + + const prefetch = usePrefetchTime('getTime') + + useEffect(() => { + setTimeout(() => { + setTimes((prev) => ({ ...prev, [nanoid()]: '+00:00' })) + }, 1000) + }, []) + + return ( + +

    + Add some times, even duplicates, and watch them automatically refetch in + sync! +

    +

    + Notes: shared queries (aka multiple entries of the same time zone) will + share the lowest polling interval between them that is greater than 0. + If all entries are set to 0, it will stop polling. If you have two + entries with a polling time of 5s and one with 0 - off, it will continue + at 5s until they are removed or 0'd out. +
    + Any new poll starts after the last request has either finished or failed + to prevent slow-running requests to immediately double-trigger. +
    + * Background flashes green when query is running + +

    + setSelectedValue(value)} + /> + +
    + {Object.entries(times).map(([key, tz]) => ( + + ))} +
    + ) +} diff --git a/examples/type-portability/bundler/src/index.tsx b/examples/type-portability/bundler/src/index.tsx new file mode 100644 index 0000000000..82f9531226 --- /dev/null +++ b/examples/type-portability/bundler/src/index.tsx @@ -0,0 +1,23 @@ +import * as React from 'react' +import { createRoot } from 'react-dom/client' +import { Provider } from 'react-redux' +import App from './App' +import { store } from './app/store' + +export 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/type-portability/bundler/tsconfig.json b/examples/type-portability/bundler/tsconfig.json new file mode 100644 index 0000000000..cf66260624 --- /dev/null +++ b/examples/type-portability/bundler/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": false, + "noEmitOnError": true, + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "outDir": "./dist", + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "useDefineForClassFields": true, + "useUnknownInCatchVariables": true, + "verbatimModuleSyntax": true + }, + "include": ["src"] +} diff --git a/examples/type-portability/nodenext-cjs/package.json b/examples/type-portability/nodenext-cjs/package.json new file mode 100644 index 0000000000..79ba210383 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/package.json @@ -0,0 +1,43 @@ +{ + "name": "@examples-type-portability/nodenext-cjs", + "private": true, + "version": "1.0.0", + "description": "testing type portability for moduleResolution NodeNext and type commonjs", + "keywords": [], + "main": "src/index.tsx", + "type": "commonjs", + "dependencies": { + "@reduxjs/toolkit": "workspace:^", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-redux": "^9.1.2", + "react-router-dom": "^6.25.1", + "react-scripts": "5.0.1" + }, + "devDependencies": { + "@types/node": "^20.14.11", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "typescript": "^5.5.4" + }, + "eslintConfig": { + "extends": [ + "react-app" + ], + "rules": { + "react/react-in-jsx-scope": "off" + } + }, + "scripts": { + "clean": "rm -rf dist", + "start": "react-scripts start", + "build": "react-scripts build", + "test": "yarn clean && tsc -p tsconfig.json" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/examples/type-portability/nodenext-cjs/src/App.tsx b/examples/type-portability/nodenext-cjs/src/App.tsx new file mode 100644 index 0000000000..420cd86d8a --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/App.tsx @@ -0,0 +1,47 @@ +import ReactRouterDom = require('react-router-dom') +import bundleSplitting = require('./features/bundleSplitting/index.js') +import CounterListModule = require('./features/counter/CounterList.js') +import PollingTogglesModule = require('./features/polling/PollingToggles.js') +import PostsManagerModule = require('./features/posts/PostsManager.js') +import TimeListModule = require('./features/time/TimeList.js') + +import Link = ReactRouterDom.Link +import Route = ReactRouterDom.Route +import Routes = ReactRouterDom.Routes + +import Lazy = bundleSplitting.Lazy + +const { CounterList } = CounterListModule +const { PollingToggles } = PollingTogglesModule +const { PostsManager } = PostsManagerModule +const { TimeList } = TimeListModule + +function App() { + return ( +
    +
    +
    + + Times | Posts |{' '} + Counter |{' '} + Bundle Splitting + +
    +
    + +
    +
    +
    +
    + + } /> + } /> + } /> + } /> + +
    +
    + ) +} + +export = App diff --git a/examples/type-portability/nodenext-cjs/src/app/customModule.ts b/examples/type-portability/nodenext-cjs/src/app/customModule.ts new file mode 100644 index 0000000000..0f9073321a --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/customModule.ts @@ -0,0 +1,59 @@ +import type { + Api, + BaseQueryFn, + CoreModule, + EndpointDefinitions, + Module, +} from '@reduxjs/toolkit/query' + +import RTKQuery = require('@reduxjs/toolkit/query') + +import coreModule = RTKQuery.coreModule +import buildCreateApi = RTKQuery.buildCreateApi + +namespace customModuleFile { + export const customModuleName = Symbol('customModule') + export type CustomModule = typeof customModuleName + + export const myModule = (): Module => ({ + name: customModuleName, + init(api, options, context) { + // initialize stuff here if you need to + + return { + injectEndpoint(endpoint, definition) { + const anyApi = api as any as Api< + any, + Record, + string, + string, + CustomModule | CoreModule + > + anyApi.endpoints[endpoint].myEndpointProperty = 'test' + }, + } + }, + }) + + export const myCreateApi = buildCreateApi(coreModule(), myModule()) +} + +// If we remove this, We should get a TypeScript error. +declare module '@reduxjs/toolkit/query' { + export interface ApiModules< + BaseQuery extends BaseQueryFn, + Definitions extends EndpointDefinitions, + ReducerPath extends string, + TagTypes extends string, + > { + [customModuleFile.customModuleName]: { + endpoints: { + [K in keyof Definitions]: { + myEndpointProperty: string + } + } + } + } +} + +export = customModuleFile diff --git a/examples/type-portability/nodenext-cjs/src/app/dynamicMiddleware.ts b/examples/type-portability/nodenext-cjs/src/app/dynamicMiddleware.ts new file mode 100644 index 0000000000..28326f5b02 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/dynamicMiddleware.ts @@ -0,0 +1,16 @@ +import ReduxToolkit = require('@reduxjs/toolkit') + +namespace dynamicMiddlewareModule { + import createDynamicMiddleware = ReduxToolkit.createDynamicMiddleware + + export const dynamicMiddleware = createDynamicMiddleware() + + export const { addMiddleware, instanceId, middleware, withMiddleware } = + dynamicMiddleware + + export const { withTypes, match, type } = withMiddleware + + export const { withTypes: _withTypes } = addMiddleware +} + +export = dynamicMiddlewareModule diff --git a/examples/type-portability/nodenext-cjs/src/app/dynamicReactMiddleware.ts b/examples/type-portability/nodenext-cjs/src/app/dynamicReactMiddleware.ts new file mode 100644 index 0000000000..bffc28faf6 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/dynamicReactMiddleware.ts @@ -0,0 +1,27 @@ +import ReduxToolkitReact = require('@reduxjs/toolkit/react') +import listenerMiddlewareModule = require('./listenerMiddleware.js') + +namespace dynamicReactMiddlewareModule { + import createDynamicMiddleware = ReduxToolkitReact.createDynamicMiddleware + + import listenerMiddleware = listenerMiddlewareModule.listenerMiddleware + + export const dynamicReactMiddleware = createDynamicMiddleware() + + export const { + addMiddleware, + createDispatchWithMiddlewareHook, + createDispatchWithMiddlewareHookFactory, + instanceId, + middleware, + withMiddleware, + } = dynamicReactMiddleware + + export const { withTypes } = addMiddleware + + export const useDispatchWithMiddleware = createDispatchWithMiddlewareHook( + listenerMiddleware.middleware, + ) +} + +export = dynamicReactMiddlewareModule diff --git a/examples/type-portability/nodenext-cjs/src/app/hooks.ts b/examples/type-portability/nodenext-cjs/src/app/hooks.ts new file mode 100644 index 0000000000..8931ab9700 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/hooks.ts @@ -0,0 +1,15 @@ +import ReactRedux = require('react-redux') + +import type { AppDispatch, AppStore, RootState } from './store.js' + +namespace hooksModule { + import useDispatch = ReactRedux.useDispatch + import useSelector = ReactRedux.useSelector + import useStore = ReactRedux.useStore + + export const useAppDispatch = useDispatch.withTypes() + export const useAppSelector = useSelector.withTypes() + export const useAppStore = useStore.withTypes() +} + +export = hooksModule diff --git a/examples/type-portability/nodenext-cjs/src/app/listenerMiddleware.ts b/examples/type-portability/nodenext-cjs/src/app/listenerMiddleware.ts new file mode 100644 index 0000000000..40e90db2e5 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/listenerMiddleware.ts @@ -0,0 +1,16 @@ +import ReduxToolkit = require('@reduxjs/toolkit') + +namespace listenerMiddlewareModule { + import createListenerMiddleware = ReduxToolkit.createListenerMiddleware + + export const listenerMiddleware = createListenerMiddleware() + + export const { clearListeners, middleware, startListening, stopListening } = + listenerMiddleware + + export const { withTypes } = startListening + + export const { withTypes: _withTypes } = stopListening +} + +export = listenerMiddlewareModule diff --git a/examples/type-portability/nodenext-cjs/src/app/services/api.ts b/examples/type-portability/nodenext-cjs/src/app/services/api.ts new file mode 100644 index 0000000000..e3325a681f --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/services/api.ts @@ -0,0 +1,105 @@ +import RTKQueryReact = require('@reduxjs/toolkit/query/react') + +import type { RootState } from '../store.js' + +namespace apiModule { + import createApi = RTKQueryReact.createApi + import fetchBaseQuery = RTKQueryReact.fetchBaseQuery + import retry = RTKQueryReact.retry + import fakeBaseQuery = RTKQueryReact.fakeBaseQuery + + export const baseQuery = fetchBaseQuery({ + baseUrl: '/', + prepareHeaders: (headers, { getState }) => { + const { token } = (getState() as RootState).auth + + if (token) { + headers.set('authentication', `Bearer ${token}`) + } + + return headers + }, + }) + + export const baseQueryWithRetry = retry(baseQuery, { maxRetries: 6 }) + + export const apiSlice = createApi({ + reducerPath: 'api', + baseQuery: baseQueryWithRetry, + tagTypes: ['Time', 'Posts', 'Counter'], + endpoints: () => ({}), + }) + + export const enhancedApi = apiSlice.enhanceEndpoints({ + endpoints: () => ({ + getPost: () => 'test', + }), + }) + + export const emptyApi = createApi({ + baseQuery: fakeBaseQuery(), + endpoints: () => ({}), + }) + + export const { + endpoints: _endpoints, + enhanceEndpoints: _enhanceEndpoints, + injectEndpoints: _injectEndpoints, + internalActions: _internalActions, + middleware: _middleware, + reducer: _reducer, + reducerPath: _reducerPath, + usePrefetch: _usePrefetch, + util: _util, + } = apiSlice + + export const { + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, + } = enhancedApi + + export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, + } = internalActions + + export const { match, type } = updateSubscriptionOptions + + export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, + } = util + + export const { match: _match, type: _type } = invalidateTags +} + +export = apiModule diff --git a/examples/type-portability/nodenext-cjs/src/app/services/counter.ts b/examples/type-portability/nodenext-cjs/src/app/services/counter.ts new file mode 100644 index 0000000000..7bea06d050 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/services/counter.ts @@ -0,0 +1,94 @@ +import apiModule = require('./api.js') + +namespace counterModule { + import apiSlice = apiModule.apiSlice + + export interface CountResponse { + count: number + } + + export const counterApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + getCount: build.query({ + query: () => 'count', + providesTags: ['Counter'], + }), + incrementCount: build.mutation({ + query(amount) { + return { + url: `increment`, + method: 'PUT', + body: { amount }, + } + }, + invalidatesTags: ['Counter'], + }), + decrementCount: build.mutation({ + query(amount) { + return { + url: `decrement`, + method: 'PUT', + body: { amount }, + } + }, + invalidatesTags: ['Counter'], + }), + }), + }) + + export const { + useDecrementCountMutation, + useGetCountQuery, + useIncrementCountMutation, + useLazyGetCountQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, + } = counterApi + + export const { decrementCount, getCount, incrementCount } = endpoints + + export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, + } = internalActions + + export const { match, type } = updateSubscriptionOptions + + export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, + } = util + + export const { match: _match, type: _type } = invalidateTags +} + +export = counterModule diff --git a/examples/type-portability/nodenext-cjs/src/app/services/post.ts b/examples/type-portability/nodenext-cjs/src/app/services/post.ts new file mode 100644 index 0000000000..31f49ff169 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/services/post.ts @@ -0,0 +1,135 @@ +import apiModule = require('./api.js') + +import type { Post } from './posts.js' + +namespace postModule { + import apiSlice = apiModule.apiSlice + + export const postApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + addPost: build.mutation>({ + query(body) { + return { + url: `posts`, + method: 'POST', + body, + } + }, + invalidatesTags: ['Posts'], + }), + getPost: build.query({ + query: (id) => `posts/${id}`, + providesTags: (_result, _err, id) => [{ type: 'Posts', id }], + }), + updatePost: build.mutation>({ + query(data) { + const { id, ...body } = data + return { + url: `posts/${id}`, + method: 'PUT', + body, + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + deletePost: build.mutation<{ success: boolean; id: number }, number>({ + query(id) { + return { + url: `posts/${id}`, + method: 'DELETE', + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + }), + }) + + export const { + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, + } = postApi + + export const { addPost, deletePost, getPost, updatePost } = endpoints + + export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useMutation, + } = addPost + + export const { + BaseQuery, + MutationDefinition, + QueryArg, + ReducerPath, + ResultType, + TagTypes, + } = Types + + export const { + type: __type, + Types: _Types, + extraOptions, + invalidatesTags, + onCacheEntryAdded, + onQueryStarted, + providesTags, + query, + queryFn, + structuralSharing, + transformErrorResponse, + transformResponse, + } = MutationDefinition + + export const { fetched_at, id, name: _name } = QueryArg + + export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, + } = internalActions + + export const { match, type } = updateSubscriptionOptions + + export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, + } = util + + export const { match: _match, type: _type } = invalidateTags +} + +export = postModule diff --git a/examples/type-portability/nodenext-cjs/src/app/services/posts.ts b/examples/type-portability/nodenext-cjs/src/app/services/posts.ts new file mode 100644 index 0000000000..2523a7e7ee --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/services/posts.ts @@ -0,0 +1,221 @@ +import RTKQueryReact = require('@reduxjs/toolkit/query/react') +import apiModule = require('./api.js') + +namespace postsModule { + import retry = RTKQueryReact.retry + import apiSlice = apiModule.apiSlice + + export interface Post { + id: number + name: string + fetched_at: string + } + + export type PostsResponse = Post[] + + export interface User { + first_name: string + last_name: string + email: string + phone: string + } + + export const postsApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + login: build.mutation<{ token: string; user: User }, any>({ + query: (credentials: any) => ({ + url: 'login', + method: 'POST', + body: credentials, + }), + extraOptions: { + backoff: () => { + retry.fail({ fake: 'error' }) // We intentionally error once on login, and this breaks out of retrying. The next login attempt will succeed. + }, + }, + }), + getPosts: build.query({ + query: () => ({ url: 'posts' }), + providesTags: (result = []) => [ + ...result.map(({ id }) => ({ type: 'Posts', id }) as const), + { type: 'Posts' as const, id: 'LIST' }, + ], + }), + addPost: build.mutation>({ + query: (body) => ({ + url: `posts`, + method: 'POST', + body, + }), + invalidatesTags: [{ type: 'Posts', id: 'LIST' }], + }), + getPost: build.query({ + query: (id) => `posts/${id}`, + providesTags: (_post, _err, id) => [{ type: 'Posts', id }], + }), + updatePost: build.mutation>({ + query(data) { + const { id, ...body } = data + return { + url: `posts/${id}`, + method: 'PUT', + body, + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + deletePost: build.mutation<{ success: boolean; id: number }, number>({ + query(id) { + return { + url: `posts/${id}`, + method: 'DELETE', + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + getErrorProne: build.query<{ success: boolean }, void>({ + query: () => 'error-prone', + }), + }), + }) + + export const { + useAddPostMutation, + useDeletePostMutation, + useGetPostQuery, + useGetPostsQuery, + useLoginMutation, + useUpdatePostMutation, + useGetErrorProneQuery, + useLazyGetErrorProneQuery, + useLazyGetPostQuery, + useLazyGetPostsQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, + } = postsApi + + export const { + addPost, + deletePost, + getErrorProne, + getPost, + getPosts, + login, + updatePost, + } = endpoints + + export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useMutation, + } = addPost + + export const { + Types: _Types, + initiate: _initiate, + matchFulfilled: _matchFulfilled, + matchPending: _matchPending, + matchRejected: _matchRejected, + name: _name, + select: _select, + useMutation: _useMutation, + } = deletePost + + export const { + Types: __Types, + initiate: __initiate, + matchFulfilled: __matchFulfilled, + matchPending: __matchPending, + matchRejected: __matchRejected, + name: __name, + select: __select, + useQueryState, + useLazyQuery, + useLazyQuerySubscription, + useQuery, + useQuerySubscription, + } = getErrorProne + + export const { + Types: ___Types, + initiate: ___initiate, + matchFulfilled: ___matchFulfilled, + matchPending: ___matchPending, + matchRejected: ___matchRejected, + name: ___name, + select: ___select, + useQueryState: ___useQueryState, + useLazyQuery: ___useLazyQuery, + useLazyQuerySubscription: ___useLazyQuerySubscription, + useQuery: ___useQuery, + useQuerySubscription: ___useQuerySubscription, + } = getPost + + export const { + Types: ____Types, + initiate: ____initiate, + matchFulfilled: ____matchFulfilled, + matchPending: ____matchPending, + matchRejected: ____matchRejected, + name: ____name, + select: ____select, + useMutation: ____useMutation, + } = login + + export const { + Types: _____Types, + initiate: _____initiate, + matchFulfilled: _____matchFulfilled, + matchPending: _____matchPending, + matchRejected: _____matchRejected, + name: _____name, + select: _____select, + useMutation: _____useMutation, + } = updatePost + + export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, + } = internalActions + + export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, + } = util +} + +export = postsModule diff --git a/examples/type-portability/nodenext-cjs/src/app/services/times.ts b/examples/type-portability/nodenext-cjs/src/app/services/times.ts new file mode 100644 index 0000000000..324cbac037 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/services/times.ts @@ -0,0 +1,83 @@ +import apiModule = require('./api.js') + +namespace timesModule { + import apiSlice = apiModule.apiSlice + + export interface TimeResponse { + time: string + } + + export const timeApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + getTime: build.query({ + query: (id) => `time/${id}`, + providesTags: (_result, _err, id) => [{ type: 'Time', id }], + }), + }), + }) + + export const { + useLazyGetTimeQuery, + usePrefetch: usePrefetchTime, + useGetTimeQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + util, + } = timeApi + + export const { getTime } = endpoints + + export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useQuery, + useLazyQuery, + useQuerySubscription, + useQueryState, + useLazyQuerySubscription, + } = getTime + + export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, + } = internalActions + + export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, + } = util +} + +export = timesModule diff --git a/examples/type-portability/nodenext-cjs/src/app/store.ts b/examples/type-portability/nodenext-cjs/src/app/store.ts new file mode 100644 index 0000000000..bf5aaaee47 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/app/store.ts @@ -0,0 +1,52 @@ +import ReduxToolkit = require('@reduxjs/toolkit') +import RTKQuery = require('@reduxjs/toolkit/query') +import authSliceModule = require('../features/auth/authSlice.js') +import pollingSliceModule = require('../features/polling/pollingSlice.js') +import dynamicMiddlewareModule = require('./dynamicMiddleware.js') +import dynamicReactMiddlewareModule = require('./dynamicReactMiddleware.js') +import listenerMiddlewareModule = require('./listenerMiddleware.js') +import apiModule = require('./services/api.js') + +namespace storeModule { + import combineSlices = ReduxToolkit.combineSlices + import configureStore = ReduxToolkit.configureStore + import setupListeners = RTKQuery.setupListeners + import authSlice = authSliceModule.authSlice + import pollingSlice = pollingSliceModule.pollingSlice + import dynamicMiddleware = dynamicMiddlewareModule.dynamicMiddleware + import dynamicReactMiddleware = dynamicReactMiddlewareModule.dynamicReactMiddleware + import listenerMiddleware = listenerMiddlewareModule.listenerMiddleware + import apiSlice = apiModule.apiSlice + + export const rootReducer = combineSlices(pollingSlice, authSlice, apiSlice) + + export const { inject, selector, withLazyLoadedSlices } = rootReducer + + export const { original } = selector + + export type RootState = ReturnType + + export const setupStore = (preloadedState?: Partial) => + configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware() + .prepend(listenerMiddleware.middleware) + .prepend(dynamicMiddleware.middleware) + .prepend(dynamicReactMiddleware.middleware) + .concat(apiSlice.middleware), + preloadedState, + enhancers: (getDefaultEnhancers) => getDefaultEnhancers(), + }) + + export const store = setupStore() + + setupListeners(store.dispatch) + + export const { dispatch, getState, replaceReducer, subscribe } = store + + export type AppStore = typeof store + export type AppDispatch = typeof store.dispatch +} + +export = storeModule diff --git a/examples/type-portability/nodenext-cjs/src/features/auth/authSlice.ts b/examples/type-portability/nodenext-cjs/src/features/auth/authSlice.ts new file mode 100644 index 0000000000..672f945439 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/auth/authSlice.ts @@ -0,0 +1,67 @@ +import ReduxToolkit = require('@reduxjs/toolkit') +import postsModule = require('../../app/services/posts.js') + +import type { User } from '../../app/services/posts.js' + +namespace authSliceModule { + import createSlice = ReduxToolkit.createSlice + import postsApi = postsModule.postsApi + + export const initialState = { + user: null, + token: null, + isAuthenticated: false, + } as { user: null | User; token: string | null; isAuthenticated: boolean } + + export const authSlice = createSlice({ + name: 'auth', + initialState, + reducers: { + logout: () => initialState, + }, + extraReducers: (builder) => { + builder + .addMatcher(postsApi.endpoints.login.matchPending, (state, action) => { + console.log('pending', action) + }) + .addMatcher( + postsApi.endpoints.login.matchFulfilled, + (state, action) => { + console.log('fulfilled', action) + state.user = action.payload.user + state.token = action.payload.token + state.isAuthenticated = true + }, + ) + .addMatcher(postsApi.endpoints.login.matchRejected, (state, action) => { + console.log('rejected', action) + }) + }, + selectors: { + selectIsAuthenticated: (authState) => authState.isAuthenticated, + }, + }) + + export const { + actions, + caseReducers, + getInitialState, + getSelectors, + injectInto, + name, + reducer, + reducerPath, + selectSlice, + selectors, + } = authSlice + + export const { selectIsAuthenticated } = getSelectors(selectSlice) + + export const { unwrapped } = selectIsAuthenticated + + export const { logout: _logout } = caseReducers + + export const { logout } = authSlice.actions +} + +export = authSliceModule diff --git a/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/Lazy.tsx b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/Lazy.tsx new file mode 100644 index 0000000000..e2252604da --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/Lazy.tsx @@ -0,0 +1,17 @@ +import React = require('react') +import bundleSplittingModule = require('./index.js') + +namespace lazyModule { + import Suspense = React.Suspense + import PostsList = bundleSplittingModule.PostsList + + export const Lazy = () => { + return ( + loading...}> + + + ) + } +} + +export = lazyModule diff --git a/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/Post.tsx b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/Post.tsx new file mode 100644 index 0000000000..7da1ff8148 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/Post.tsx @@ -0,0 +1,25 @@ +import postModule = require('../../app/services/post.js') + +import postApi = postModule.postApi + +function assert(condition: any, msg = 'Generic Assertion'): asserts condition { + if (!condition) { + throw new Error(`Assertion failed: ${msg}`) + } +} + +const Post = ({ id }: { id: number }) => { + assert(postApi.endpoints.getPost?.useQuery, 'Endpoint `getPost` not loaded!') + + const { data, error } = postApi.endpoints.getPost.useQuery(id) + + return error ? ( + <>there was an error + ) : !data ? ( + <>loading + ) : ( +

    {data.name}

    + ) +} + +export = Post diff --git a/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/PostsList.tsx b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/PostsList.tsx new file mode 100644 index 0000000000..aaf81ef010 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/PostsList.tsx @@ -0,0 +1,31 @@ +import React = require('react') +import bundleSplittingModule = require('./index.js') +import postsModule = require('../../app/services/posts.js') + +import useState = React.useState +import Post = bundleSplittingModule.Post +import postsApi = postsModule.postsApi + +const PostsList = () => { + const { data, error } = postsApi.endpoints.getPosts.useQuery() + const [selected, select] = useState() + + return error ? ( + <>there was an error + ) : !data ? ( + <>loading + ) : ( + <> + {selected && } +
      + {data.map((post) => ( +
    • + +
    • + ))} +
    + + ) +} + +export = PostsList diff --git a/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/index.ts b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/index.ts new file mode 100644 index 0000000000..6c4bc611d5 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/bundleSplitting/index.ts @@ -0,0 +1,14 @@ +import React = require('react') +import lazyModule = require('./Lazy.js') + +namespace bundleSplitting { + import lazy = React.lazy + + export const PostsList = lazy(() => import('./PostsList.js')) + + export const Post = lazy(() => import('./Post.js')) + + export import Lazy = lazyModule.Lazy +} + +export = bundleSplitting diff --git a/examples/type-portability/nodenext-cjs/src/features/common/Container.tsx b/examples/type-portability/nodenext-cjs/src/features/common/Container.tsx new file mode 100644 index 0000000000..5da44c4e8e --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/common/Container.tsx @@ -0,0 +1,9 @@ +import type { FC, ReactNode } from 'react' + +const Container: FC<{ children: ReactNode }> = ({ children }) => ( +
    + {children} +
    +) + +export = { Container } diff --git a/examples/type-portability/nodenext-cjs/src/features/counter/Counter.tsx b/examples/type-portability/nodenext-cjs/src/features/counter/Counter.tsx new file mode 100644 index 0000000000..33bbe79382 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/counter/Counter.tsx @@ -0,0 +1,39 @@ +import React = require('react') +import counterModule = require('../../app/services/counter.js') + +import useState = React.useState +import useDecrementCountMutation = counterModule.useDecrementCountMutation +import useGetCountQuery = counterModule.useGetCountQuery +import useIncrementCountMutation = counterModule.useIncrementCountMutation + +function Counter({ id, onRemove }: { id?: string; onRemove?: () => void }) { + const [pollingInterval, setPollingInterval] = useState(10_000) + const { data } = useGetCountQuery(undefined, { pollingInterval }) + const [increment] = useIncrementCountMutation() + const [decrement] = useDecrementCountMutation() + + return ( +
    +
    + + {data?.count || 0} + + + setPollingInterval(valueAsNumber) + } + /> + {onRemove && } +
    +
    + ) +} + +export = { Counter } diff --git a/examples/type-portability/nodenext-cjs/src/features/counter/CounterList.tsx b/examples/type-portability/nodenext-cjs/src/features/counter/CounterList.tsx new file mode 100644 index 0000000000..1da85e4290 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/counter/CounterList.tsx @@ -0,0 +1,46 @@ +import ReduxToolkit = require('@reduxjs/toolkit') +import React = require('react') +import ContainerModule = require('../common/Container.js') +import CounterModule = require('./Counter.js') + +import nanoid = ReduxToolkit.nanoid +import useState = React.useState + +const { Container } = ContainerModule +const { Counter } = CounterModule + +const CounterList = () => { + const [counters, setCounters] = useState([]) + + if (!counters.length) { + return ( + +
    No counters, why don't you add one?
    +
    + +
    +
    + ) + } + + return ( + +
    + +
    + {counters.map((id) => ( + setCounters((prev) => prev.filter((el) => el !== id))} + /> + ))} +
    + ) +} + +export = { CounterList } diff --git a/examples/type-portability/nodenext-cjs/src/features/polling/PollingToggles.tsx b/examples/type-portability/nodenext-cjs/src/features/polling/PollingToggles.tsx new file mode 100644 index 0000000000..167b716a94 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/polling/PollingToggles.tsx @@ -0,0 +1,64 @@ +import hooksModule = require('../../app/hooks.js') +import pollingSliceModule = require('./pollingSlice.js') + +import type { ReactNode } from 'react' + +import useAppDispatch = hooksModule.useAppDispatch +import useAppSelector = hooksModule.useAppSelector +import selectGlobalPollingEnabled = pollingSliceModule.selectGlobalPollingEnabled +import selectPollingConfigByApp = pollingSliceModule.selectPollingConfigByApp +import toggleGlobalPolling = pollingSliceModule.toggleGlobalPolling +import updatePolling = pollingSliceModule.updatePolling + +const PollingToggleButton = ({ + enabled, + onClick, + children, +}: { + onClick: () => void + enabled: boolean + children?: ReactNode +}) => { + return ( + + ) +} + +const PollingToggles = () => { + const dispatch = useAppDispatch() + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + const timesPolling = useAppSelector((state) => + selectPollingConfigByApp(state, 'times'), + ) + + return ( +
    + Global Polling Configs +
    + dispatch(toggleGlobalPolling())} + > + Global + + + dispatch( + updatePolling({ app: 'times', enabled: !timesPolling.enabled }), + ) + } + > + Times + +
    +
    + ) +} + +export = { PollingToggleButton, PollingToggles } diff --git a/examples/type-portability/nodenext-cjs/src/features/polling/pollingSlice.ts b/examples/type-portability/nodenext-cjs/src/features/polling/pollingSlice.ts new file mode 100644 index 0000000000..24ffcc115c --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/polling/pollingSlice.ts @@ -0,0 +1,102 @@ +import ReduxToolkit = require('@reduxjs/toolkit') + +import type { PayloadAction } from '@reduxjs/toolkit' +import type { RootState } from '../../app/store.js' + +namespace pollingSliceModule { + import createSlice = ReduxToolkit.createSlice + + export type PollingConfig = { + enabled: boolean + interval: number + } + + export type SliceState = { + enabled: boolean + apps: { + [key: string]: PollingConfig + } + } + + export const initialState: SliceState = { + enabled: true, + apps: { + counters: { + enabled: true, + interval: 0, + }, + times: { + enabled: true, + interval: 0, + }, + posts: { + enabled: true, + interval: 0, + }, + }, + } + + export type PollingAppKey = keyof (typeof initialState)['apps'] + + export const pollingSlice = createSlice({ + name: 'polling', + initialState, + reducers: (creators) => { + return { + toggleGlobalPolling: creators.reducer((state) => { + state.enabled = !state.enabled + }), + updatePolling( + state, + { + payload, + }: PayloadAction<{ + app: PollingAppKey + enabled?: boolean + interval?: number + }>, + ) { + const { app, ...rest } = payload + state.apps[app] = { + ...state.apps[app], + ...rest, + } + }, + } + }, + selectors: { + selectGlobalPollingEnabled: (pollingState) => pollingState.enabled, + }, + }) + + export const { + actions, + caseReducers, + getInitialState, + getSelectors, + injectInto, + name, + reducer, + reducerPath, + selectSlice, + selectors, + } = pollingSlice + + export const { + toggleGlobalPolling: _toggleGlobalPolling, + updatePolling: _updatePolling, + } = caseReducers + + export const { toggleGlobalPolling, updatePolling } = pollingSlice.actions + + export const { selectGlobalPollingEnabled } = selectors + + export const { unwrapped } = selectGlobalPollingEnabled + + export const selectPollingConfigByApp = ( + state: RootState, + app: PollingAppKey, + ) => state.polling.apps[app] +} + +export = pollingSliceModule diff --git a/examples/type-portability/nodenext-cjs/src/features/posts/PostDetail.tsx b/examples/type-portability/nodenext-cjs/src/features/posts/PostDetail.tsx new file mode 100644 index 0000000000..e025a0cd41 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/posts/PostDetail.tsx @@ -0,0 +1,137 @@ +import React = require('react') +import ReactRouterDom = require('react-router-dom') +import hooksModule = require('../../app/hooks.js') +import postsModule = require('../../app/services/posts.js') +import pollingSliceModule = require('../polling/pollingSlice.js') + +import type { ChangeEvent, FormEventHandler } from 'react' + +import useState = React.useState +import useNavigate = ReactRouterDom.useNavigate +import useParams = ReactRouterDom.useParams +import useAppSelector = hooksModule.useAppSelector +import useDeletePostMutation = postsModule.useDeletePostMutation +import useGetPostQuery = postsModule.useGetPostQuery +import useUpdatePostMutation = postsModule.useUpdatePostMutation +import selectGlobalPollingEnabled = pollingSliceModule.selectGlobalPollingEnabled + +const EditablePostName = ({ + name: initialName, + onUpdate, + onCancel, + loading = false, +}: { + name: string + onUpdate: (name: string) => void + onCancel: () => void + loading?: boolean +}) => { + const [name, setName] = useState(initialName) + + const handleChange = ({ target: { value } }: ChangeEvent) => + setName(value) + + const handleSubmit: FormEventHandler = (e) => { + e.preventDefault() + onUpdate(name) + } + const handleCancel = () => onCancel() + + return ( +
    +
    + + + +
    +
    + ) +} + +const PostJsonDetail = ({ id }: { id: number }) => { + const { data: post } = useGetPostQuery(id) + + return ( +
    +
    {JSON.stringify(post, null, 2)}
    +
    + ) +} + +const PostDetail = () => { + const { id } = useParams<{ id: any }>() + const navigate = useNavigate() + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + + const [isEditing, setIsEditing] = useState(false) + + const { + data: post, + isFetching, + isLoading, + } = useGetPostQuery(id, { pollingInterval: globalPolling ? 3000 : 0 }) + + const [updatePost, { isLoading: isUpdating }] = useUpdatePostMutation() + const [deletePost, { isLoading: isDeleting }] = useDeletePostMutation() + + if (isLoading) { + return
    Loading...
    + } + + if (!post) { + return
    Missing post!
    + } + + return ( +
    + {isEditing ? ( + + updatePost({ id, name }) + .then((result) => { + // handle the success! + console.log('Update Result', result) + setIsEditing(false) + }) + .catch((error) => console.error('Update Error', error)) + } + onCancel={() => setIsEditing(false)} + loading={isUpdating} + /> + ) : ( +
    +
    +

    + {post.name} {isFetching ? '...refetching' : ''} +

    +
    + + +
    + )} + +
    + ) +} + +export = { EditablePostName, PostJsonDetail, PostDetail } diff --git a/examples/type-portability/nodenext-cjs/src/features/posts/PostsManager.tsx b/examples/type-portability/nodenext-cjs/src/features/posts/PostsManager.tsx new file mode 100644 index 0000000000..831c0b220f --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/posts/PostsManager.tsx @@ -0,0 +1,152 @@ +import React = require('react') +import ReactRedux = require('react-redux') +import ReactRouterDom = require('react-router-dom') +import postsModule = require('../../app/services/posts.js') +import authSliceModule = require('../auth/authSlice.js') +import PostDetailModule = require('./PostDetail.js') + +import type { ChangeEvent, FormEventHandler } from 'react' +import type { Post } from '../../app/services/posts.js' + +import useState = React.useState +import useDispatch = ReactRedux.useDispatch +import useSelector = ReactRedux.useSelector +import Route = ReactRouterDom.Route +import Routes = ReactRouterDom.Routes +import useNavigate = ReactRouterDom.useNavigate +import useAddPostMutation = postsModule.useAddPostMutation +import useGetErrorProneQuery = postsModule.useGetErrorProneQuery +import useGetPostsQuery = postsModule.useGetPostsQuery +import useLoginMutation = postsModule.useLoginMutation +import logout = authSliceModule.logout +import selectIsAuthenticated = authSliceModule.selectIsAuthenticated + +const { PostDetail } = PostDetailModule + +const AddPost = () => { + const initialValue = { name: '' } + const [post, setPost] = useState>(initialValue) + const [addPost, { isLoading }] = useAddPostMutation() + + const handleChange = ({ target }: ChangeEvent) => { + setPost((prev) => ({ + ...prev, + [target.name]: target.value, + })) + } + + const handleSubmit: FormEventHandler = async (e) => { + e.preventDefault() + await addPost(post) + setPost(initialValue) + } + + return ( +
    +
    +
    + +
    +
    + +
    +
    +
    + ) +} + +const PostListItem = ({ + data: { name, id }, + onSelect, +}: { + data: Post + onSelect: (id: number) => void +}) => { + return ( +
  • + onSelect(id)}> + {name} + +
  • + ) +} + +const PostList = () => { + const { data: posts, isLoading } = useGetPostsQuery() + const navigate = useNavigate() + + if (isLoading) { + return
    Loading
    + } + + if (!posts) { + return
    No posts :(
    + } + + return ( +
    + {posts.map((post) => ( + navigate(`/posts/${id}`)} + /> + ))} +
    + ) +} + +const PostsManager = () => { + const [login] = useLoginMutation() + const [initRetries, setInitRetries] = useState(false) + const { data, error, isFetching } = useGetErrorProneQuery(undefined, { + skip: !initRetries, + }) + const dispatch = useDispatch() + const isAuthenticated = useSelector(selectIsAuthenticated) + + return ( +
    +

    Posts

    + {!isAuthenticated ? ( + + ) : ( + + )} + +
    +
    +
    + +
    + Posts: + +
    + List with duplicate subscription: + +
    +
    + + } /> + +
    +
    +
    + ) +} + +export = { AddPost, PostListItem, PostList, PostsManager } diff --git a/examples/type-portability/nodenext-cjs/src/features/time/TimeList.tsx b/examples/type-portability/nodenext-cjs/src/features/time/TimeList.tsx new file mode 100644 index 0000000000..473633b4d8 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/features/time/TimeList.tsx @@ -0,0 +1,180 @@ +import ReduxToolkit = require('@reduxjs/toolkit') +import React = require('react') +import hooksModule = require('../../app/hooks.js') +import timesModule = require('../../app/services/times.js') +import ContainerModule = require('../common/Container.js') +import pollingSliceModule = require('../polling/pollingSlice.js') + +import nanoid = ReduxToolkit.nanoid +import useState = React.useState +import useEffect = React.useEffect +import useAppSelector = hooksModule.useAppSelector +import useGetTimeQuery = timesModule.useGetTimeQuery +import usePrefetchTime = timesModule.usePrefetchTime + +const { Container } = ContainerModule + +import selectPollingConfigByApp = pollingSliceModule.selectPollingConfigByApp +import selectGlobalPollingEnabled = pollingSliceModule.selectGlobalPollingEnabled + +const timezones: Record = { + '-12:00': '(GMT -12:00) Eniwetok, Kwajalein', + '-11:00': '(GMT -11:00) Midway Island, Samoa', + '-10:00': '(GMT -10:00) Hawaii', + '-09:50': '(GMT -9:30) Taiohae', + '-09:00': '(GMT -9:00) Alaska', + '-08:00': '(GMT -8:00) Pacific Time (US & Canada)', + '-07:00': '(GMT -7:00) Mountain Time (US & Canada)', + '-06:00': '(GMT -6:00) Central Time (US & Canada), Mexico City', + '-05:00': '(GMT -5:00) Eastern Time (US & Canada), Bogota, Lima', + '-04:50': '(GMT -4:30) Caracas', + '-04:00': '(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz', + '-03:50': '(GMT -3:30) Newfoundland', + '-03:00': '(GMT -3:00) Brazil, Buenos Aires, Georgetown', + '-02:00': '(GMT -2:00) Mid-Atlantic', + '-01:00': '(GMT -1:00) Azores, Cape Verde Islands', + '+00:00': '(GMT) Western Europe Time, London, Lisbon, Casablanca', + '+01:00': '(GMT +1:00) Brussels, Copenhagen, Madrid, Paris', + '+02:00': '(GMT +2:00) Kaliningrad, South Africa', + '+03:00': '(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg', + '+03:50': '(GMT +3:30) Tehran', + '+04:00': '(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi', + '+04:50': '(GMT +4:30) Kabul', + '+05:00': '(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent', + '+05:50': '(GMT +5:30) Bombay, Calcutta, Madras, New Delhi', + '+05:75': '(GMT +5:45) Kathmandu, Pokhara', + '+06:00': '(GMT +6:00) Almaty, Dhaka, Colombo', + '+06:50': '(GMT +6:30) Yangon, Mandalay', + '+07:00': '(GMT +7:00) Bangkok, Hanoi, Jakarta', + '+08:00': '(GMT +8:00) Beijing, Perth, Singapore, Hong Kong', + '+08:75': '(GMT +8:45) Eucla', + '+09:00': '(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk', + '+09:50': '(GMT +9:30) Adelaide, Darwin', + '+10:00': '(GMT +10:00) Eastern Australia, Guam, Vladivostok', + '+10:50': '(GMT +10:30) Lord Howe Island', + '+11:00': '(GMT +11:00) Magadan, Solomon Islands, New Caledonia', + '+11:50': '(GMT +11:30) Norfolk Island', + '+12:00': '(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka', + '+12:75': '(GMT +12:45) Chatham Islands', + '+13:00': '(GMT +13:00) Apia, Nukualofa', + '+14:00': '(GMT +14:00) Line Islands, Tokelau', +} + +const TimeZoneSelector = ({ + onChange, +}: { + onChange: (event: React.ChangeEvent) => void +}) => { + return ( + + ) +} + +const intervalOptions = [ + { label: '0 - Off', value: 0 }, + { label: '1s', value: 1000 }, + { label: '3s', value: 3000 }, + { label: '5s', value: 5000 }, + { label: '10s', value: 10_000 }, + { label: '1m', value: 60_000 }, +] + +const TimeDisplay = ({ offset, label }: { offset: string; label: string }) => { + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + const { enabled: timesPolling } = useAppSelector((state) => + selectPollingConfigByApp(state, 'times'), + ) + + const canPoll = globalPolling && timesPolling + + const [pollingInterval, setPollingInterval] = useState(0) + const { data, refetch, isFetching } = useGetTimeQuery(offset, { + pollingInterval: canPoll ? pollingInterval : 0, + }) + + return ( +
    +

    + {data?.time && new Date(data.time).toLocaleTimeString()} - {label} +

    +

    + Polling Interval:{' '} + +

    +
    + ) +} + +const TimeList = () => { + const [times, setTimes] = useState<{ [key: string]: string }>({ + [nanoid()]: '-08:00', + }) + const [selectedValue, setSelectedValue] = useState('') + + const prefetch = usePrefetchTime('getTime') + + useEffect(() => { + setTimeout(() => { + setTimes((prev) => ({ ...prev, [nanoid()]: '+00:00' })) + }, 1000) + }, []) + + return ( + +

    + Add some times, even duplicates, and watch them automatically refetch in + sync! +

    +

    + Notes: shared queries (aka multiple entries of the same time zone) will + share the lowest polling interval between them that is greater than 0. + If all entries are set to 0, it will stop polling. If you have two + entries with a polling time of 5s and one with 0 - off, it will continue + at 5s until they are removed or 0'd out. +
    + Any new poll starts after the last request has either finished or failed + to prevent slow-running requests to immediately double-trigger. +
    + * Background flashes green when query is running + +

    + setSelectedValue(value)} + /> + +
    + {Object.entries(times).map(([key, tz]) => ( + + ))} +
    + ) +} + +export = { timezones, TimeZoneSelector, intervalOptions, TimeDisplay, TimeList } diff --git a/examples/type-portability/nodenext-cjs/src/index.tsx b/examples/type-portability/nodenext-cjs/src/index.tsx new file mode 100644 index 0000000000..8a2b8874dc --- /dev/null +++ b/examples/type-portability/nodenext-cjs/src/index.tsx @@ -0,0 +1,29 @@ +import React = require('react') +import ReactDomClient = require('react-dom/client') +import ReactRedux = require('react-redux') +import App = require('./App.js') +import storeModule = require('./app/store.js') + +import createRoot = ReactDomClient.createRoot +import Provider = ReactRedux.Provider +import store = storeModule.store + +const container = document.getElementById('root') + +export = { container } + +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/type-portability/nodenext-cjs/tsconfig.json b/examples/type-portability/nodenext-cjs/tsconfig.json new file mode 100644 index 0000000000..4287809949 --- /dev/null +++ b/examples/type-portability/nodenext-cjs/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react-jsx", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "noEmit": false, + "noEmitOnError": true, + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "outDir": "./dist", + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "useDefineForClassFields": true, + "useUnknownInCatchVariables": true, + "verbatimModuleSyntax": true + }, + "include": ["src"] +} diff --git a/examples/type-portability/nodenext-esm/package.json b/examples/type-portability/nodenext-esm/package.json new file mode 100644 index 0000000000..95534bc103 --- /dev/null +++ b/examples/type-portability/nodenext-esm/package.json @@ -0,0 +1,43 @@ +{ + "name": "@examples-type-portability/nodenext-esm", + "private": true, + "version": "1.0.0", + "description": "testing type portability for moduleResolution NodeNext and type module", + "keywords": [], + "main": "src/index.tsx", + "type": "module", + "dependencies": { + "@reduxjs/toolkit": "workspace:^", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-redux": "^9.1.2", + "react-router-dom": "^6.25.1", + "react-scripts": "5.0.1" + }, + "devDependencies": { + "@types/node": "^20.14.11", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "typescript": "^5.5.4" + }, + "eslintConfig": { + "extends": [ + "react-app" + ], + "rules": { + "react/react-in-jsx-scope": "off" + } + }, + "scripts": { + "clean": "rm -rf dist", + "start": "react-scripts start", + "build": "react-scripts build", + "test": "yarn clean && tsc -p tsconfig.json" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/examples/type-portability/nodenext-esm/src/App.tsx b/examples/type-portability/nodenext-esm/src/App.tsx new file mode 100644 index 0000000000..8490eff345 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/App.tsx @@ -0,0 +1,36 @@ +import { Link, Route, Routes } from 'react-router-dom' +import { Lazy } from './features/bundleSplitting/index.js' +import { CounterList } from './features/counter/CounterList.js' +import { PollingToggles } from './features/polling/PollingToggles.js' +import { PostsManager } from './features/posts/PostsManager.js' +import { TimeList } from './features/time/TimeList.js' + +export function App() { + return ( +
    +
    +
    + + Times | Posts |{' '} + Counter |{' '} + Bundle Splitting + +
    +
    + +
    +
    +
    +
    + + } /> + } /> + } /> + } /> + +
    +
    + ) +} + +export default App diff --git a/examples/type-portability/nodenext-esm/src/app/customModule.ts b/examples/type-portability/nodenext-esm/src/app/customModule.ts new file mode 100644 index 0000000000..86565b3084 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/customModule.ts @@ -0,0 +1,51 @@ +import type { + Api, + BaseQueryFn, + CoreModule, + EndpointDefinitions, + Module, +} from '@reduxjs/toolkit/query' +import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query' + +export const customModuleName = Symbol('customModule') +export type CustomModule = typeof customModuleName + +// If we remove this, We should get a TypeScript error. +declare module '@reduxjs/toolkit/query' { + export interface ApiModules< + BaseQuery extends BaseQueryFn, + Definitions extends EndpointDefinitions, + ReducerPath extends string, + TagTypes extends string, + > { + [customModuleName]: { + endpoints: { + [K in keyof Definitions]: { + myEndpointProperty: string + } + } + } + } +} + +export const myModule = (): Module => ({ + name: customModuleName, + init(api, options, context) { + // initialize stuff here if you need to + + return { + injectEndpoint(endpoint, definition) { + const anyApi = api as any as Api< + any, + Record, + string, + string, + CustomModule | CoreModule + > + anyApi.endpoints[endpoint].myEndpointProperty = 'test' + }, + } + }, +}) + +export const myCreateApi = buildCreateApi(coreModule(), myModule()) diff --git a/examples/type-portability/nodenext-esm/src/app/dynamicMiddleware.ts b/examples/type-portability/nodenext-esm/src/app/dynamicMiddleware.ts new file mode 100644 index 0000000000..e5b6067794 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/dynamicMiddleware.ts @@ -0,0 +1,10 @@ +import { createDynamicMiddleware } from '@reduxjs/toolkit' + +export const dynamicMiddleware = createDynamicMiddleware() + +export const { addMiddleware, instanceId, middleware, withMiddleware } = + dynamicMiddleware + +export const { withTypes, match, type } = withMiddleware + +export const { withTypes: _withTypes } = addMiddleware diff --git a/examples/type-portability/nodenext-esm/src/app/dynamicReactMiddleware.ts b/examples/type-portability/nodenext-esm/src/app/dynamicReactMiddleware.ts new file mode 100644 index 0000000000..89daa5fbfc --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/dynamicReactMiddleware.ts @@ -0,0 +1,19 @@ +import { createDynamicMiddleware } from '@reduxjs/toolkit/react' +import { listenerMiddleware } from './listenerMiddleware.js' + +export const dynamicReactMiddleware = createDynamicMiddleware() + +export const { + addMiddleware, + createDispatchWithMiddlewareHook, + createDispatchWithMiddlewareHookFactory, + instanceId, + middleware, + withMiddleware, +} = dynamicReactMiddleware + +export const { withTypes } = addMiddleware + +export const useDispatchWithMiddleware = createDispatchWithMiddlewareHook( + listenerMiddleware.middleware, +) diff --git a/examples/type-portability/nodenext-esm/src/app/hooks.ts b/examples/type-portability/nodenext-esm/src/app/hooks.ts new file mode 100644 index 0000000000..c64e08ed4c --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/hooks.ts @@ -0,0 +1,6 @@ +import { useDispatch, useSelector, useStore } from 'react-redux' +import type { AppDispatch, AppStore, RootState } from './store.js' + +export const useAppDispatch = useDispatch.withTypes() +export const useAppSelector = useSelector.withTypes() +export const useAppStore = useStore.withTypes() diff --git a/examples/type-portability/nodenext-esm/src/app/listenerMiddleware.ts b/examples/type-portability/nodenext-esm/src/app/listenerMiddleware.ts new file mode 100644 index 0000000000..82a664954c --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/listenerMiddleware.ts @@ -0,0 +1,10 @@ +import { createListenerMiddleware } from '@reduxjs/toolkit' + +export const listenerMiddleware = createListenerMiddleware() + +export const { clearListeners, middleware, startListening, stopListening } = + listenerMiddleware + +export const { withTypes } = startListening + +export const { withTypes: _withTypes } = stopListening diff --git a/examples/type-portability/nodenext-esm/src/app/services/api.ts b/examples/type-portability/nodenext-esm/src/app/services/api.ts new file mode 100644 index 0000000000..62321936d5 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/services/api.ts @@ -0,0 +1,100 @@ +import { + createApi, + fakeBaseQuery, + fetchBaseQuery, + retry, +} from '@reduxjs/toolkit/query/react' +import type { RootState } from '../store.js' + +export const baseQuery = fetchBaseQuery({ + baseUrl: '/', + prepareHeaders: (headers, { getState }) => { + const { token } = (getState() as RootState).auth + + if (token) { + headers.set('authentication', `Bearer ${token}`) + } + + return headers + }, +}) + +export const baseQueryWithRetry = retry(baseQuery, { maxRetries: 6 }) + +export const apiSlice = createApi({ + reducerPath: 'api', + baseQuery: baseQueryWithRetry, + tagTypes: ['Time', 'Posts', 'Counter'], + endpoints: () => ({}), +}) + +export const enhancedApi = apiSlice.enhanceEndpoints({ + endpoints: () => ({ + getPost: () => 'test', + }), +}) + +export const emptyApi = createApi({ + baseQuery: fakeBaseQuery(), + endpoints: () => ({}), +}) + +export const { + endpoints: _endpoints, + enhanceEndpoints: _enhanceEndpoints, + injectEndpoints: _injectEndpoints, + internalActions: _internalActions, + middleware: _middleware, + reducer: _reducer, + reducerPath: _reducerPath, + usePrefetch: _usePrefetch, + util: _util, +} = apiSlice + +export const { + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = enhancedApi + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { match, type } = updateSubscriptionOptions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util + +export const { match: _match, type: _type } = invalidateTags diff --git a/examples/type-portability/nodenext-esm/src/app/services/counter.ts b/examples/type-portability/nodenext-esm/src/app/services/counter.ts new file mode 100644 index 0000000000..8ecd2fe0ea --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/services/counter.ts @@ -0,0 +1,88 @@ +import { apiSlice } from './api.js' + +export interface CountResponse { + count: number +} + +export const counterApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + getCount: build.query({ + query: () => 'count', + providesTags: ['Counter'], + }), + incrementCount: build.mutation({ + query(amount) { + return { + url: `increment`, + method: 'PUT', + body: { amount }, + } + }, + invalidatesTags: ['Counter'], + }), + decrementCount: build.mutation({ + query(amount) { + return { + url: `decrement`, + method: 'PUT', + body: { amount }, + } + }, + invalidatesTags: ['Counter'], + }), + }), +}) + +export const { + useDecrementCountMutation, + useGetCountQuery, + useIncrementCountMutation, + useLazyGetCountQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = counterApi + +export const { decrementCount, getCount, incrementCount } = endpoints + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { match, type } = updateSubscriptionOptions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util + +export const { match: _match, type: _type } = invalidateTags diff --git a/examples/type-portability/nodenext-esm/src/app/services/post.ts b/examples/type-portability/nodenext-esm/src/app/services/post.ts new file mode 100644 index 0000000000..b706e84eff --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/services/post.ts @@ -0,0 +1,128 @@ +import { apiSlice } from './api.js' +import type { Post } from './posts.js' + +export const postApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + addPost: build.mutation>({ + query(body) { + return { + url: `posts`, + method: 'POST', + body, + } + }, + invalidatesTags: ['Posts'], + }), + getPost: build.query({ + query: (id) => `posts/${id}`, + providesTags: (_result, _err, id) => [{ type: 'Posts', id }], + }), + updatePost: build.mutation>({ + query(data) { + const { id, ...body } = data + return { + url: `posts/${id}`, + method: 'PUT', + body, + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + deletePost: build.mutation<{ success: boolean; id: number }, number>({ + query(id) { + return { + url: `posts/${id}`, + method: 'DELETE', + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + }), +}) + +export const { + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = postApi + +export const { addPost, deletePost, getPost, updatePost } = endpoints + +export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useMutation, +} = addPost + +export const { + BaseQuery, + MutationDefinition, + QueryArg, + ReducerPath, + ResultType, + TagTypes, +} = Types + +export const { + type: __type, + Types: _Types, + extraOptions, + invalidatesTags, + onCacheEntryAdded, + onQueryStarted, + providesTags, + query, + queryFn, + structuralSharing, + transformErrorResponse, + transformResponse, +} = MutationDefinition + +export const { fetched_at, id, name: _name } = QueryArg + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { match, type } = updateSubscriptionOptions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util + +export const { match: _match, type: _type } = invalidateTags diff --git a/examples/type-portability/nodenext-esm/src/app/services/posts.ts b/examples/type-portability/nodenext-esm/src/app/services/posts.ts new file mode 100644 index 0000000000..18fa7a8df7 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/services/posts.ts @@ -0,0 +1,215 @@ +import { retry } from '@reduxjs/toolkit/query/react' +import { apiSlice } from './api.js' + +export interface Post { + id: number + name: string + fetched_at: string +} + +export type PostsResponse = Post[] + +export interface User { + first_name: string + last_name: string + email: string + phone: string +} + +export const postsApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + login: build.mutation<{ token: string; user: User }, any>({ + query: (credentials: any) => ({ + url: 'login', + method: 'POST', + body: credentials, + }), + extraOptions: { + backoff: () => { + // We intentionally error once on login, and this breaks out of retrying. The next login attempt will succeed. + retry.fail({ fake: 'error' }) + }, + }, + }), + getPosts: build.query({ + query: () => ({ url: 'posts' }), + providesTags: (result = []) => [ + ...result.map(({ id }) => ({ type: 'Posts', id }) as const), + { type: 'Posts' as const, id: 'LIST' }, + ], + }), + addPost: build.mutation>({ + query: (body) => ({ + url: `posts`, + method: 'POST', + body, + }), + invalidatesTags: [{ type: 'Posts', id: 'LIST' }], + }), + getPost: build.query({ + query: (id) => `posts/${id}`, + providesTags: (_post, _err, id) => [{ type: 'Posts', id }], + }), + updatePost: build.mutation>({ + query(data) { + const { id, ...body } = data + return { + url: `posts/${id}`, + method: 'PUT', + body, + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + deletePost: build.mutation<{ success: boolean; id: number }, number>({ + query(id) { + return { + url: `posts/${id}`, + method: 'DELETE', + } + }, + invalidatesTags: (post) => [{ type: 'Posts', id: post?.id }], + }), + getErrorProne: build.query<{ success: boolean }, void>({ + query: () => 'error-prone', + }), + }), +}) + +export const { + useAddPostMutation, + useDeletePostMutation, + useGetPostQuery, + useGetPostsQuery, + useLoginMutation, + useUpdatePostMutation, + useGetErrorProneQuery, + useLazyGetErrorProneQuery, + useLazyGetPostQuery, + useLazyGetPostsQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + usePrefetch, + util, +} = postsApi + +export const { + addPost, + deletePost, + getErrorProne, + getPost, + getPosts, + login, + updatePost, +} = endpoints + +export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useMutation, +} = addPost + +export const { + Types: _Types, + initiate: _initiate, + matchFulfilled: _matchFulfilled, + matchPending: _matchPending, + matchRejected: _matchRejected, + name: _name, + select: _select, + useMutation: _useMutation, +} = deletePost + +export const { + Types: __Types, + initiate: __initiate, + matchFulfilled: __matchFulfilled, + matchPending: __matchPending, + matchRejected: __matchRejected, + name: __name, + select: __select, + useQueryState, + useLazyQuery, + useLazyQuerySubscription, + useQuery, + useQuerySubscription, +} = getErrorProne + +export const { + Types: ___Types, + initiate: ___initiate, + matchFulfilled: ___matchFulfilled, + matchPending: ___matchPending, + matchRejected: ___matchRejected, + name: ___name, + select: ___select, + useQueryState: ___useQueryState, + useLazyQuery: ___useLazyQuery, + useLazyQuerySubscription: ___useLazyQuerySubscription, + useQuery: ___useQuery, + useQuerySubscription: ___useQuerySubscription, +} = getPost + +const { + Types: ____Types, + initiate: ____initiate, + matchFulfilled: ____matchFulfilled, + matchPending: ____matchPending, + matchRejected: ____matchRejected, + name: ____name, + select: ____select, + useMutation: ____useMutation, +} = login + +export const { + Types: _____Types, + initiate: _____initiate, + matchFulfilled: _____matchFulfilled, + matchPending: _____matchPending, + matchRejected: _____matchRejected, + name: _____name, + select: _____select, + useMutation: _____useMutation, +} = updatePost + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util diff --git a/examples/type-portability/nodenext-esm/src/app/services/times.ts b/examples/type-portability/nodenext-esm/src/app/services/times.ts new file mode 100644 index 0000000000..ae7278fbed --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/services/times.ts @@ -0,0 +1,77 @@ +import { apiSlice } from './api.js' + +export interface TimeResponse { + time: string +} + +export const timeApi = apiSlice.injectEndpoints({ + endpoints: (build) => ({ + getTime: build.query({ + query: (id) => `time/${id}`, + providesTags: (_result, _err, id) => [{ type: 'Time', id }], + }), + }), +}) + +export const { + useLazyGetTimeQuery, + usePrefetch: usePrefetchTime, + useGetTimeQuery, + endpoints, + enhanceEndpoints, + injectEndpoints, + internalActions, + middleware, + reducer, + reducerPath, + util, +} = timeApi + +export const { getTime } = endpoints + +export const { + Types, + initiate, + matchFulfilled, + matchPending, + matchRejected, + name, + select, + useQuery, + useLazyQuery, + useQuerySubscription, + useQueryState, + useLazyQuerySubscription, +} = getTime + +export const { + internal_getRTKQSubscriptions, + middlewareRegistered, + onFocus, + onFocusLost, + onOffline, + onOnline, + queryResultPatched, + removeMutationResult, + removeQueryResult, + resetApiState: _resetApiState, + subscriptionsUpdated, + unsubscribeQueryResult, + updateProvidedBy, + updateSubscriptionOptions, +} = internalActions + +export const { + getRunningMutationThunk, + getRunningMutationsThunk, + getRunningQueriesThunk, + getRunningQueryThunk, + invalidateTags, + patchQueryData, + prefetch, + resetApiState, + selectCachedArgsForQuery, + selectInvalidatedBy, + updateQueryData, + upsertQueryData, +} = util diff --git a/examples/type-portability/nodenext-esm/src/app/store.ts b/examples/type-portability/nodenext-esm/src/app/store.ts new file mode 100644 index 0000000000..09b0daf87b --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/app/store.ts @@ -0,0 +1,38 @@ +import { combineSlices, configureStore } from '@reduxjs/toolkit' +import { setupListeners } from '@reduxjs/toolkit/query' +import { authSlice } from '../features/auth/authSlice.js' +import { pollingSlice } from '../features/polling/pollingSlice.js' +import { dynamicMiddleware } from './dynamicMiddleware.js' +import { dynamicReactMiddleware } from './dynamicReactMiddleware.js' +import { listenerMiddleware } from './listenerMiddleware.js' +import { apiSlice } from './services/api.js' + +export const rootReducer = combineSlices(pollingSlice, authSlice, apiSlice) + +export const { inject, selector, withLazyLoadedSlices } = rootReducer + +export const { original } = selector + +export type RootState = ReturnType + +export const setupStore = (preloadedState?: Partial) => + configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware() + .prepend(listenerMiddleware.middleware) + .prepend(dynamicMiddleware.middleware) + .prepend(dynamicReactMiddleware.middleware) + .concat(apiSlice.middleware), + preloadedState, + enhancers: (getDefaultEnhancers) => getDefaultEnhancers(), + }) + +export const store = setupStore() + +setupListeners(store.dispatch) + +export const { dispatch, getState, replaceReducer, subscribe } = store + +export type AppStore = typeof store +export type AppDispatch = typeof store.dispatch diff --git a/examples/type-portability/nodenext-esm/src/features/auth/authSlice.ts b/examples/type-portability/nodenext-esm/src/features/auth/authSlice.ts new file mode 100644 index 0000000000..936b6cb0e4 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/auth/authSlice.ts @@ -0,0 +1,56 @@ +import { createSlice } from '@reduxjs/toolkit' +import type { User } from '../../app/services/posts.js' +import { postsApi } from '../../app/services/posts.js' + +export const initialState = { + user: null, + token: null, + isAuthenticated: false, +} as { user: null | User; token: string | null; isAuthenticated: boolean } + +export const authSlice = createSlice({ + name: 'auth', + initialState, + reducers: { + logout: () => initialState, + }, + extraReducers: (builder) => { + builder + .addMatcher(postsApi.endpoints.login.matchPending, (state, action) => { + console.log('pending', action) + }) + .addMatcher(postsApi.endpoints.login.matchFulfilled, (state, action) => { + console.log('fulfilled', action) + state.user = action.payload.user + state.token = action.payload.token + state.isAuthenticated = true + }) + .addMatcher(postsApi.endpoints.login.matchRejected, (state, action) => { + console.log('rejected', action) + }) + }, + selectors: { + selectIsAuthenticated: (authState) => authState.isAuthenticated, + }, +}) + +export const { + actions, + caseReducers, + getInitialState, + getSelectors, + injectInto, + name, + reducer, + reducerPath, + selectSlice, + selectors, +} = authSlice + +export const { selectIsAuthenticated } = getSelectors(selectSlice) + +export const { unwrapped } = selectIsAuthenticated + +export const { logout: _logout } = caseReducers + +export const { logout } = authSlice.actions diff --git a/examples/type-portability/nodenext-esm/src/features/bundleSplitting/Lazy.tsx b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/Lazy.tsx new file mode 100644 index 0000000000..a2614c56a6 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/Lazy.tsx @@ -0,0 +1,10 @@ +import { Suspense } from 'react' +import { PostsList } from './index.js' + +export const Lazy = () => { + return ( + loading...}> + + + ) +} diff --git a/examples/type-portability/nodenext-esm/src/features/bundleSplitting/Post.tsx b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/Post.tsx new file mode 100644 index 0000000000..3d26c035a5 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/Post.tsx @@ -0,0 +1,27 @@ +// import the file that injects "post" to make sure it has been loaded +import { postApi } from '../../app/services/post.js' + +export function assert( + condition: any, + msg = 'Generic Assertion', +): asserts condition { + if (!condition) { + throw new Error(`Assertion failed: ${msg}`) + } +} + +export const Post = ({ id }: { id: number }) => { + assert(postApi.endpoints.getPost?.useQuery, 'Endpoint `getPost` not loaded!') + + const { data, error } = postApi.endpoints.getPost.useQuery(id) + + return error ? ( + <>there was an error + ) : !data ? ( + <>loading + ) : ( +

    {data.name}

    + ) +} + +export default Post diff --git a/examples/type-portability/nodenext-esm/src/features/bundleSplitting/PostsList.tsx b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/PostsList.tsx new file mode 100644 index 0000000000..8eda6f2efa --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/PostsList.tsx @@ -0,0 +1,27 @@ +import { useState } from 'react' +import { postsApi } from '../../app/services/posts.js' +import { Post } from './index.js' + +export const PostsList = () => { + const { data, error } = postsApi.endpoints.getPosts.useQuery() + const [selected, select] = useState() + + return error ? ( + <>there was an error + ) : !data ? ( + <>loading + ) : ( + <> + {selected && } +
      + {data.map((post) => ( +
    • + +
    • + ))} +
    + + ) +} + +export default PostsList diff --git a/examples/type-portability/nodenext-esm/src/features/bundleSplitting/index.ts b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/index.ts new file mode 100644 index 0000000000..a797cf1bfd --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/bundleSplitting/index.ts @@ -0,0 +1,7 @@ +import { lazy } from 'react' + +export const PostsList = lazy(() => import('./PostsList.js')) + +export const Post = lazy(() => import('./Post.js')) + +export { Lazy } from './Lazy.js' diff --git a/examples/type-portability/nodenext-esm/src/features/common/Container.tsx b/examples/type-portability/nodenext-esm/src/features/common/Container.tsx new file mode 100644 index 0000000000..183436677e --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/common/Container.tsx @@ -0,0 +1,7 @@ +import type { FC, ReactNode } from 'react' + +export const Container: FC<{ children: ReactNode }> = ({ children }) => ( +
    + {children} +
    +) diff --git a/examples/type-portability/nodenext-esm/src/features/counter/Counter.tsx b/examples/type-portability/nodenext-esm/src/features/counter/Counter.tsx new file mode 100644 index 0000000000..cf9f1eed54 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/counter/Counter.tsx @@ -0,0 +1,43 @@ +import { useState } from 'react' +import { + useDecrementCountMutation, + useGetCountQuery, + useIncrementCountMutation, +} from '../../app/services/counter.js' + +export function Counter({ + id, + onRemove, +}: { + id?: string + onRemove?: () => void +}) { + const [pollingInterval, setPollingInterval] = useState(10_000) + const { data } = useGetCountQuery(undefined, { pollingInterval }) + const [increment] = useIncrementCountMutation() + + const [decrement] = useDecrementCountMutation() + + return ( +
    +
    + + {data?.count || 0} + + + setPollingInterval(valueAsNumber) + } + /> + {onRemove && } +
    +
    + ) +} diff --git a/examples/type-portability/nodenext-esm/src/features/counter/CounterList.tsx b/examples/type-portability/nodenext-esm/src/features/counter/CounterList.tsx new file mode 100644 index 0000000000..187075924e --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/counter/CounterList.tsx @@ -0,0 +1,38 @@ +import { nanoid } from '@reduxjs/toolkit' +import { useState } from 'react' +import { Container } from '../common/Container.js' +import { Counter } from './Counter.js' + +export const CounterList = () => { + const [counters, setCounters] = useState([]) + + if (!counters.length) { + return ( + +
    No counters, why don't you add one?
    +
    + +
    +
    + ) + } + + return ( + +
    + +
    + {counters.map((id) => ( + setCounters((prev) => prev.filter((el) => el !== id))} + /> + ))} +
    + ) +} diff --git a/examples/type-portability/nodenext-esm/src/features/polling/PollingToggles.tsx b/examples/type-portability/nodenext-esm/src/features/polling/PollingToggles.tsx new file mode 100644 index 0000000000..0250275679 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/polling/PollingToggles.tsx @@ -0,0 +1,59 @@ +import type { ReactNode } from 'react' +import { useAppDispatch, useAppSelector } from '../../app/hooks.js' +import { + selectGlobalPollingEnabled, + selectPollingConfigByApp, + toggleGlobalPolling, + updatePolling, +} from './pollingSlice.js' + +export const PollingToggleButton = ({ + enabled, + onClick, + children, +}: { + onClick: () => void + enabled: boolean + children?: ReactNode +}) => { + return ( + + ) +} + +export const PollingToggles = () => { + const dispatch = useAppDispatch() + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + const timesPolling = useAppSelector((state) => + selectPollingConfigByApp(state, 'times'), + ) + + return ( +
    + Global Polling Configs +
    + dispatch(toggleGlobalPolling())} + > + Global + + + dispatch( + updatePolling({ app: 'times', enabled: !timesPolling.enabled }), + ) + } + > + Times + +
    +
    + ) +} diff --git a/examples/type-portability/nodenext-esm/src/features/polling/pollingSlice.ts b/examples/type-portability/nodenext-esm/src/features/polling/pollingSlice.ts new file mode 100644 index 0000000000..a1daf6da2a --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/polling/pollingSlice.ts @@ -0,0 +1,95 @@ +import type { PayloadAction } from '@reduxjs/toolkit' +import { createSlice } from '@reduxjs/toolkit' +import type { RootState } from '../../app/store.js' + +export type PollingConfig = { + enabled: boolean + interval: number +} + +export type SliceState = { + enabled: boolean + apps: { + [key: string]: PollingConfig + } +} + +export const initialState: SliceState = { + enabled: true, + apps: { + counters: { + enabled: true, + interval: 0, + }, + times: { + enabled: true, + interval: 0, + }, + posts: { + enabled: true, + interval: 0, + }, + }, +} + +export type PollingAppKey = keyof (typeof initialState)['apps'] + +export const pollingSlice = createSlice({ + name: 'polling', + initialState, + reducers: (creators) => { + return { + toggleGlobalPolling: creators.reducer((state) => { + state.enabled = !state.enabled + }), + updatePolling( + state, + { + payload, + }: PayloadAction<{ + app: PollingAppKey + enabled?: boolean + interval?: number + }>, + ) { + const { app, ...rest } = payload + state.apps[app] = { + ...state.apps[app], + ...rest, + } + }, + } + }, + selectors: { + selectGlobalPollingEnabled: (pollingState) => pollingState.enabled, + }, +}) + +export const { + actions, + caseReducers, + getInitialState, + getSelectors, + injectInto, + name, + reducer, + reducerPath, + selectSlice, + selectors, +} = pollingSlice + +export const { + toggleGlobalPolling: _toggleGlobalPolling, + updatePolling: _updatePolling, +} = caseReducers + +export const { toggleGlobalPolling, updatePolling } = pollingSlice.actions + +export const { selectGlobalPollingEnabled } = selectors + +export const { unwrapped } = selectGlobalPollingEnabled + +export const selectPollingConfigByApp = ( + state: RootState, + app: PollingAppKey, +) => state.polling.apps[app] diff --git a/examples/type-portability/nodenext-esm/src/features/posts/PostDetail.tsx b/examples/type-portability/nodenext-esm/src/features/posts/PostDetail.tsx new file mode 100644 index 0000000000..f24988fc4e --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/posts/PostDetail.tsx @@ -0,0 +1,129 @@ +import type { ChangeEvent, FormEventHandler } from 'react' +import { useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import { useAppSelector } from '../../app/hooks.js' +import { + useDeletePostMutation, + useGetPostQuery, + useUpdatePostMutation, +} from '../../app/services/posts.js' +import { selectGlobalPollingEnabled } from '../polling/pollingSlice.js' + +export const EditablePostName = ({ + name: initialName, + onUpdate, + onCancel, + loading = false, +}: { + name: string + onUpdate: (name: string) => void + onCancel: () => void + loading?: boolean +}) => { + const [name, setName] = useState(initialName) + + const handleChange = ({ target: { value } }: ChangeEvent) => + setName(value) + + const handleSubmit: FormEventHandler = (e) => { + e.preventDefault() + onUpdate(name) + } + const handleCancel = () => onCancel() + + return ( +
    +
    + + + +
    +
    + ) +} + +export const PostJsonDetail = ({ id }: { id: number }) => { + const { data: post } = useGetPostQuery(id) + + return ( +
    +
    {JSON.stringify(post, null, 2)}
    +
    + ) +} + +export const PostDetail = () => { + const { id } = useParams<{ id: any }>() + const navigate = useNavigate() + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + + const [isEditing, setIsEditing] = useState(false) + + const { + data: post, + isFetching, + isLoading, + } = useGetPostQuery(id, { pollingInterval: globalPolling ? 3000 : 0 }) + + const [updatePost, { isLoading: isUpdating }] = useUpdatePostMutation() + const [deletePost, { isLoading: isDeleting }] = useDeletePostMutation() + + if (isLoading) { + return
    Loading...
    + } + + if (!post) { + return
    Missing post!
    + } + + return ( +
    + {isEditing ? ( + + updatePost({ id, name }) + .then((result) => { + // handle the success! + console.log('Update Result', result) + setIsEditing(false) + }) + .catch((error) => console.error('Update Error', error)) + } + onCancel={() => setIsEditing(false)} + loading={isUpdating} + /> + ) : ( +
    +
    +

    + {post.name} {isFetching ? '...refetching' : ''} +

    +
    + + +
    + )} + +
    + ) +} diff --git a/examples/type-portability/nodenext-esm/src/features/posts/PostsManager.tsx b/examples/type-portability/nodenext-esm/src/features/posts/PostsManager.tsx new file mode 100644 index 0000000000..3bd5d973c8 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/posts/PostsManager.tsx @@ -0,0 +1,141 @@ +import type { ChangeEvent, FormEventHandler } from 'react' +import { useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { Route, Routes, useNavigate } from 'react-router-dom' +import type { Post } from '../../app/services/posts.js' +import { + useAddPostMutation, + useGetErrorProneQuery, + useGetPostsQuery, + useLoginMutation, +} from '../../app/services/posts.js' +import { logout, selectIsAuthenticated } from '../auth/authSlice.js' +import { PostDetail } from './PostDetail.js' + +export const AddPost = () => { + const initialValue = { name: '' } + const [post, setPost] = useState>(initialValue) + const [addPost, { isLoading }] = useAddPostMutation() + + const handleChange = ({ target }: ChangeEvent) => { + setPost((prev) => ({ + ...prev, + [target.name]: target.value, + })) + } + + const handleSubmit: FormEventHandler = async (e) => { + e.preventDefault() + await addPost(post) + setPost(initialValue) + } + + return ( +
    +
    +
    + +
    +
    + +
    +
    +
    + ) +} + +export const PostListItem = ({ + data: { name, id }, + onSelect, +}: { + data: Post + onSelect: (id: number) => void +}) => { + return ( +
  • + onSelect(id)}> + {name} + +
  • + ) +} + +export const PostList = () => { + const { data: posts, isLoading } = useGetPostsQuery() + const navigate = useNavigate() + + if (isLoading) { + return
    Loading
    + } + + if (!posts) { + return
    No posts :(
    + } + + return ( +
    + {posts.map((post) => ( + navigate(`/posts/${id}`)} + /> + ))} +
    + ) +} + +export const PostsManager = () => { + const [login] = useLoginMutation() + const [initRetries, setInitRetries] = useState(false) + const { data, error, isFetching } = useGetErrorProneQuery(undefined, { + skip: !initRetries, + }) + const dispatch = useDispatch() + const isAuthenticated = useSelector(selectIsAuthenticated) + + return ( +
    +

    Posts

    + {!isAuthenticated ? ( + + ) : ( + + )} + +
    +
    +
    + +
    + Posts: + +
    + List with duplicate subscription: + +
    +
    + + } /> + +
    +
    +
    + ) +} + +export default PostsManager diff --git a/examples/type-portability/nodenext-esm/src/features/time/TimeList.tsx b/examples/type-portability/nodenext-esm/src/features/time/TimeList.tsx new file mode 100644 index 0000000000..8a83194dc8 --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/features/time/TimeList.tsx @@ -0,0 +1,170 @@ +import { nanoid } from '@reduxjs/toolkit' +import * as React from 'react' +import { useEffect } from 'react' +import { useAppSelector } from '../../app/hooks.js' +import { useGetTimeQuery, usePrefetchTime } from '../../app/services/times.js' +import { Container } from '../common/Container.js' +import { + selectGlobalPollingEnabled, + selectPollingConfigByApp, +} from '../polling/pollingSlice.js' + +export const timezones: Record = { + '-12:00': '(GMT -12:00) Eniwetok, Kwajalein', + '-11:00': '(GMT -11:00) Midway Island, Samoa', + '-10:00': '(GMT -10:00) Hawaii', + '-09:50': '(GMT -9:30) Taiohae', + '-09:00': '(GMT -9:00) Alaska', + '-08:00': '(GMT -8:00) Pacific Time (US & Canada)', + '-07:00': '(GMT -7:00) Mountain Time (US & Canada)', + '-06:00': '(GMT -6:00) Central Time (US & Canada), Mexico City', + '-05:00': '(GMT -5:00) Eastern Time (US & Canada), Bogota, Lima', + '-04:50': '(GMT -4:30) Caracas', + '-04:00': '(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz', + '-03:50': '(GMT -3:30) Newfoundland', + '-03:00': '(GMT -3:00) Brazil, Buenos Aires, Georgetown', + '-02:00': '(GMT -2:00) Mid-Atlantic', + '-01:00': '(GMT -1:00) Azores, Cape Verde Islands', + '+00:00': '(GMT) Western Europe Time, London, Lisbon, Casablanca', + '+01:00': '(GMT +1:00) Brussels, Copenhagen, Madrid, Paris', + '+02:00': '(GMT +2:00) Kaliningrad, South Africa', + '+03:00': '(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg', + '+03:50': '(GMT +3:30) Tehran', + '+04:00': '(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi', + '+04:50': '(GMT +4:30) Kabul', + '+05:00': '(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent', + '+05:50': '(GMT +5:30) Bombay, Calcutta, Madras, New Delhi', + '+05:75': '(GMT +5:45) Kathmandu, Pokhara', + '+06:00': '(GMT +6:00) Almaty, Dhaka, Colombo', + '+06:50': '(GMT +6:30) Yangon, Mandalay', + '+07:00': '(GMT +7:00) Bangkok, Hanoi, Jakarta', + '+08:00': '(GMT +8:00) Beijing, Perth, Singapore, Hong Kong', + '+08:75': '(GMT +8:45) Eucla', + '+09:00': '(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk', + '+09:50': '(GMT +9:30) Adelaide, Darwin', + '+10:00': '(GMT +10:00) Eastern Australia, Guam, Vladivostok', + '+10:50': '(GMT +10:30) Lord Howe Island', + '+11:00': '(GMT +11:00) Magadan, Solomon Islands, New Caledonia', + '+11:50': '(GMT +11:30) Norfolk Island', + '+12:00': '(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka', + '+12:75': '(GMT +12:45) Chatham Islands', + '+13:00': '(GMT +13:00) Apia, Nukualofa', + '+14:00': '(GMT +14:00) Line Islands, Tokelau', +} + +export const TimeZoneSelector = ({ + onChange, +}: { + onChange: (event: React.ChangeEvent) => void +}) => { + return ( + + ) +} + +export const intervalOptions = [ + { label: '0 - Off', value: 0 }, + { label: '1s', value: 1000 }, + { label: '3s', value: 3000 }, + { label: '5s', value: 5000 }, + { label: '10s', value: 10_000 }, + { label: '1m', value: 60_000 }, +] + +export const TimeDisplay = ({ offset, label }: { offset: string; label: string }) => { + const globalPolling = useAppSelector(selectGlobalPollingEnabled) + const { enabled: timesPolling } = useAppSelector((state) => + selectPollingConfigByApp(state, 'times'), + ) + + const canPoll = globalPolling && timesPolling + + const [pollingInterval, setPollingInterval] = React.useState(0) + const { data, refetch, isFetching } = useGetTimeQuery(offset, { + pollingInterval: canPoll ? pollingInterval : 0, + }) + + return ( +
    +

    + {data?.time && new Date(data.time).toLocaleTimeString()} - {label} +

    +

    + Polling Interval:{' '} + +

    +
    + ) +} + +export const TimeList = () => { + const [times, setTimes] = React.useState<{ [key: string]: string }>({ + [nanoid()]: '-08:00', + }) + const [selectedValue, setSelectedValue] = React.useState('') + + const prefetch = usePrefetchTime('getTime') + + useEffect(() => { + setTimeout(() => { + setTimes((prev) => ({ ...prev, [nanoid()]: '+00:00' })) + }, 1000) + }, []) + + return ( + +

    + Add some times, even duplicates, and watch them automatically refetch in + sync! +

    +

    + Notes: shared queries (aka multiple entries of the same time zone) will + share the lowest polling interval between them that is greater than 0. + If all entries are set to 0, it will stop polling. If you have two + entries with a polling time of 5s and one with 0 - off, it will continue + at 5s until they are removed or 0'd out. +
    + Any new poll starts after the last request has either finished or failed + to prevent slow-running requests to immediately double-trigger. +
    + * Background flashes green when query is running + +

    + setSelectedValue(value)} + /> + +
    + {Object.entries(times).map(([key, tz]) => ( + + ))} +
    + ) +} diff --git a/examples/type-portability/nodenext-esm/src/index.tsx b/examples/type-portability/nodenext-esm/src/index.tsx new file mode 100644 index 0000000000..c68f27128a --- /dev/null +++ b/examples/type-portability/nodenext-esm/src/index.tsx @@ -0,0 +1,23 @@ +import * as React from 'react' +import { createRoot } from 'react-dom/client' +import { Provider } from 'react-redux' +import App from './App.js' +import { store } from './app/store.js' + +export 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/type-portability/nodenext-esm/tsconfig.json b/examples/type-portability/nodenext-esm/tsconfig.json new file mode 100644 index 0000000000..4287809949 --- /dev/null +++ b/examples/type-portability/nodenext-esm/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react-jsx", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "noEmit": false, + "noEmitOnError": true, + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "outDir": "./dist", + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "useDefineForClassFields": true, + "useUnknownInCatchVariables": true, + "verbatimModuleSyntax": true + }, + "include": ["src"] +} diff --git a/package.json b/package.json index d8606e8cd5..50da5401e4 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "docs", "website", "examples/query/react/*", - "examples/action-listener/*" + "examples/action-listener/*", + "examples/type-portability/*" ], "devDependencies": { "@babel/code-frame": "^7.24.2", @@ -53,9 +54,7 @@ "typescript": "^5.4.3" }, "resolutions": { - "esbuild": "0.19.7", - "jest-snapshot": "29.3.1", - "console-testing-library@0.6.1": "patch:console-testing-library@npm%3A0.6.1#./.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch" + "jest-snapshot": "29.3.1" }, "scripts": { "build": "yarn build:packages", diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index a76f7a9ccb..0acc0a6b33 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -66,7 +66,8 @@ "@typescript-eslint/eslint-plugin": "^6", "@typescript-eslint/parser": "^6", "axios": "^0.19.2", - "console-testing-library": "0.6.1", + "console-testing-library": "patch:console-testing-library@npm%3A0.6.1#~/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch", + "esbuild": "^0.23.0", "esbuild-extra": "^0.3.1", "eslint": "^7.25.0", "eslint-config-prettier": "^9.1.0", @@ -88,8 +89,8 @@ "rimraf": "^3.0.2", "size-limit": "^11.0.1", "tslib": "^1.10.0", - "tsup": "^7.2.0", - "tsx": "^3.12.2", + "tsup": "^8.2.3", + "tsx": "^4.16.2", "typescript": "^5.4.5", "vite-tsconfig-paths": "^4.3.1", "vitest": "^1.6.0", @@ -98,7 +99,7 @@ "scripts": { "clean": "rimraf dist", "run-build": "tsup", - "build": "yarn clean && echo Compiling TS... && yarn tsc -p tsconfig.build.json && yarn run-build", + "build": "yarn clean && yarn run-build && tsx scripts/fixUniqueSymbolExports.mts", "build-only": "yarn clean && yarn run-build", "format": "prettier --write \"(src|examples)/**/*.{ts,tsx}\" \"**/*.md\"", "format:check": "prettier --list-different \"(src|examples)/**/*.{ts,tsx}\" \"docs/*/**.md\"", diff --git a/packages/toolkit/scripts/fixUniqueSymbolExports.mts b/packages/toolkit/scripts/fixUniqueSymbolExports.mts new file mode 100644 index 0000000000..3490d0a197 --- /dev/null +++ b/packages/toolkit/scripts/fixUniqueSymbolExports.mts @@ -0,0 +1,76 @@ +#!/usr/bin/env node --import=tsx + +import fs from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = fileURLToPath(new URL('.', import.meta.url)) + +const entryPointDirectories = ['', 'react', 'query', 'query/react'] + +const typeDefinitionEntryFiles = entryPointDirectories.map((filePath) => + path.resolve(__dirname, '..', 'dist', filePath, 'index.d.ts'), +) + +const filePathsToContentMap = new Map( + await Promise.all( + typeDefinitionEntryFiles.map( + async (filePath) => + [filePath, await fs.readFile(filePath, 'utf-8')] as const, + ), + ), +) + +const main = async () => { + filePathsToContentMap.forEach(async (content, filePath) => { + const exportedUniqueSymbols = new Set() + + console.log(`Fixing \`unique symbol\` exports in ${filePath}`) + + const lines = content.split('\n') + + const allUniqueSymbols = lines + .filter((line) => /declare const (\w+)\: unique symbol;/.test(line)) + .map((line) => line.match(/declare const (\w+)\: unique symbol;/)?.[1]) + + if (allUniqueSymbols.length === 0) { + console.log(`${filePath} does not have any unique symbols.`) + + return + } + + const allNamedExports = lines + .at(-2) + ?.match(/^export \{ (.*) \};$/)?.[1] + .split(', ') + + allNamedExports?.forEach((namedExport) => { + if (allUniqueSymbols.includes(namedExport)) { + exportedUniqueSymbols.add(namedExport) + } + }) + + if (exportedUniqueSymbols.size === 0) { + console.log( + `${filePath} has unique symbols but none of them are exported.`, + ) + + return + } + + let newContent = `${lines.slice(0, -2).join('\n')}\nexport { ${allNamedExports?.filter((namedExport) => !exportedUniqueSymbols.has(namedExport)).join(', ')} };\n` + + exportedUniqueSymbols.forEach((uniqueSymbol) => { + console.log(`Exporting \`${uniqueSymbol}\` from ${filePath}`) + + newContent = newContent.replace( + `declare const ${uniqueSymbol}`, + `export declare const ${uniqueSymbol}`, + ) + }) + + await fs.writeFile(filePath, newContent) + }) +} + +main() diff --git a/packages/toolkit/src/combineSlices.ts b/packages/toolkit/src/combineSlices.ts index 59166ee5ba..26ff173e7d 100644 --- a/packages/toolkit/src/combineSlices.ts +++ b/packages/toolkit/src/combineSlices.ts @@ -1,4 +1,4 @@ -import type { UnknownAction, Reducer, StateFromReducersMapObject } from 'redux' +import type { Reducer, StateFromReducersMapObject, UnknownAction } from 'redux' import { combineReducers } from 'redux' import { nanoid } from './nanoid' import type { diff --git a/packages/toolkit/src/createAction.ts b/packages/toolkit/src/createAction.ts index ea8958288d..4aefdda35f 100644 --- a/packages/toolkit/src/createAction.ts +++ b/packages/toolkit/src/createAction.ts @@ -82,7 +82,7 @@ export type _ActionCreatorWithPreparedPayload< * * @inheritdoc {redux#ActionCreator} */ -export interface BaseActionCreator { +export type BaseActionCreator = { type: T match: (action: unknown) => action is PayloadAction } diff --git a/packages/toolkit/src/createAsyncThunk.ts b/packages/toolkit/src/createAsyncThunk.ts index e7ee39a05a..4534165869 100644 --- a/packages/toolkit/src/createAsyncThunk.ts +++ b/packages/toolkit/src/createAsyncThunk.ts @@ -1,24 +1,16 @@ import type { Dispatch, UnknownAction } from 'redux' -import type { - PayloadAction, - ActionCreatorWithPreparedPayload, -} from './createAction' -import { createAction } from './createAction' import type { ThunkDispatch } from 'redux-thunk' +import type { ActionCreatorWithPreparedPayload } from './createAction' +import { createAction } from './createAction' +import { isAnyOf } from './matchers' +import { nanoid } from './nanoid' import type { - ActionFromMatcher, FallbackIfUnknown, Id, IsAny, IsUnknown, SafePromise, - TypeGuard, } from './tsHelpers' -import { nanoid } from './nanoid' -import { isAnyOf } from './matchers' - -// @ts-ignore we need the import of these types due to a bundling issue. -type _Keep = PayloadAction | ActionCreatorWithPreparedPayload export type BaseThunkAPI< S, @@ -125,11 +117,12 @@ export type AsyncThunkConfig = { rejectedMeta?: unknown } -type GetState = ThunkApiConfig extends { +export type GetState = ThunkApiConfig extends { state: infer State } ? State : unknown + type GetExtra = ThunkApiConfig extends { extra: infer Extra } ? Extra : unknown diff --git a/packages/toolkit/src/createSlice.ts b/packages/toolkit/src/createSlice.ts index 9340bce76a..e3d2c25c56 100644 --- a/packages/toolkit/src/createSlice.ts +++ b/packages/toolkit/src/createSlice.ts @@ -1,5 +1,6 @@ -import type { Action, UnknownAction, Reducer } from 'redux' +import type { Action, Reducer, UnknownAction } from 'redux' import type { Selector } from 'reselect' +import type { InjectConfig } from './combineSlices' import type { ActionCreatorWithoutPayload, PayloadAction, @@ -8,6 +9,14 @@ import type { _ActionCreatorWithPreparedPayload, } from './createAction' import { createAction } from './createAction' +import type { + AsyncThunk, + AsyncThunkConfig, + AsyncThunkOptions, + AsyncThunkPayloadCreator, + OverrideThunkApiConfigs, +} from './createAsyncThunk' +import { createAsyncThunk as _createAsyncThunk } from './createAsyncThunk' import type { ActionMatcherDescriptionCollection, CaseReducer, @@ -17,15 +26,6 @@ import { createReducer } from './createReducer' import type { ActionReducerMapBuilder, TypedActionCreator } from './mapBuilders' import { executeReducerBuilderCallback } from './mapBuilders' import type { Id, TypeGuard } from './tsHelpers' -import type { InjectConfig } from './combineSlices' -import type { - AsyncThunk, - AsyncThunkConfig, - AsyncThunkOptions, - AsyncThunkPayloadCreator, - OverrideThunkApiConfigs, -} from './createAsyncThunk' -import { createAsyncThunk as _createAsyncThunk } from './createAsyncThunk' import { emplace } from './utils' const asyncThunkSymbol = /* @__PURE__ */ Symbol.for( @@ -38,7 +38,7 @@ export const asyncThunkCreator: { [asyncThunkSymbol]: _createAsyncThunk, } -interface InjectIntoConfig extends InjectConfig { +type InjectIntoConfig = InjectConfig & { reducerPath?: NewReducerPath } @@ -135,16 +135,16 @@ export interface Slice< * * Selectors can now be called with an `undefined` value, in which case they use the slice's initial state. */ -interface InjectedSlice< +type InjectedSlice< State = any, CaseReducers extends SliceCaseReducers = SliceCaseReducers, Name extends string = string, ReducerPath extends string = Name, Selectors extends SliceSelectors = SliceSelectors, -> extends Omit< - Slice, - 'getSelectors' | 'selectors' - > { +> = Omit< + Slice, + 'getSelectors' | 'selectors' +> & { /** * Get localised slice selectors (expects to be called with *just* the slice's state as the first parameter) */ @@ -217,8 +217,8 @@ export interface CreateSliceOptions< /** * A callback that receives a *builder* object to define * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`. - * - * + * + * * @example ```ts import { createAction, createSlice, Action } from '@reduxjs/toolkit' @@ -270,15 +270,14 @@ export enum ReducerType { asyncThunk = 'asyncThunk', } -interface ReducerDefinition { +type ReducerDefinition = { _reducerDefinitionType: T } -export interface CaseReducerDefinition< +export type CaseReducerDefinition< S = any, A extends Action = UnknownAction, -> extends CaseReducer, - ReducerDefinition {} +> = CaseReducer & ReducerDefinition /** * A CaseReducer with a `prepare` method. @@ -296,12 +295,12 @@ export interface CaseReducerWithPrepareDefinition< > extends CaseReducerWithPrepare, ReducerDefinition {} -export interface AsyncThunkSliceReducerConfig< +type AsyncThunkSliceReducerConfig< State, ThunkArg extends any, Returned = unknown, ThunkApiConfig extends AsyncThunkConfig = {}, -> { +> = { pending?: CaseReducer< State, ReturnType['pending']> @@ -323,20 +322,15 @@ export interface AsyncThunkSliceReducerConfig< options?: AsyncThunkOptions } -export interface AsyncThunkSliceReducerDefinition< +type AsyncThunkSliceReducerDefinition< State, ThunkArg extends any, Returned = unknown, ThunkApiConfig extends AsyncThunkConfig = {}, -> extends AsyncThunkSliceReducerConfig< - State, - ThunkArg, - Returned, - ThunkApiConfig - >, - ReducerDefinition { - payloadCreator: AsyncThunkPayloadCreator -} +> = AsyncThunkSliceReducerConfig & + ReducerDefinition & { + payloadCreator: AsyncThunkPayloadCreator + } /** * Providing these as part of the config would cause circular types, so we disallow passing them @@ -512,7 +506,7 @@ type ActionCreatorForCaseReducer = CR extends ( */ type SliceDefinedCaseReducers> = { [Type in keyof CaseReducers]: CaseReducers[Type] extends infer Definition - ? Definition extends AsyncThunkSliceReducerDefinition + ? Definition extends AsyncThunkSliceReducerDefinition ? Id< Pick< Required, diff --git a/packages/toolkit/src/dynamicMiddleware/index.ts b/packages/toolkit/src/dynamicMiddleware/index.ts index 2ad15b6c3e..ed151b2979 100644 --- a/packages/toolkit/src/dynamicMiddleware/index.ts +++ b/packages/toolkit/src/dynamicMiddleware/index.ts @@ -1,27 +1,28 @@ -import type { - Middleware, - Dispatch as ReduxDispatch, - UnknownAction, -} from 'redux' +import type { Dispatch, Middleware, UnknownAction } from 'redux' import { compose } from 'redux' import { createAction } from '../createAction' import { isAllOf } from '../matchers' import { nanoid } from '../nanoid' import { emplace, find } from '../utils' import type { - WithMiddleware, AddMiddleware, - MiddlewareEntry, DynamicMiddleware, DynamicMiddlewareInstance, + MiddlewareEntry, + WithMiddleware, +} from './types' +export type { + DynamicMiddlewareInstance, + GetDispatchType as GetDispatch, + MiddlewareApiConfig, } from './types' const createMiddlewareEntry = < State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, + DispatchType extends Dispatch = Dispatch, >( - middleware: Middleware, -): MiddlewareEntry => ({ + middleware: Middleware, +): MiddlewareEntry => ({ id: nanoid(), middleware, applied: new Map(), @@ -34,15 +35,15 @@ const matchInstance = export const createDynamicMiddleware = < State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, ->(): DynamicMiddlewareInstance => { + DispatchType extends Dispatch = Dispatch, +>(): DynamicMiddlewareInstance => { const instanceId = nanoid() - const middlewareMap = new Map>() + const middlewareMap = new Map>() const withMiddleware = Object.assign( createAction( 'dynamicMiddleware/add', - (...middlewares: Middleware[]) => ({ + (...middlewares: Middleware[]) => ({ payload: middlewares, meta: { instanceId, @@ -50,10 +51,12 @@ export const createDynamicMiddleware = < }), ), { withTypes: () => withMiddleware }, - ) as WithMiddleware + ) as WithMiddleware const addMiddleware = Object.assign( - function addMiddleware(...middlewares: Middleware[]) { + function addMiddleware( + ...middlewares: Middleware[] + ) { middlewares.forEach((middleware) => { let entry = find( Array.from(middlewareMap.values()), @@ -66,9 +69,9 @@ export const createDynamicMiddleware = < }) }, { withTypes: () => addMiddleware }, - ) as AddMiddleware + ) as AddMiddleware - const getFinalMiddleware: Middleware<{}, State, Dispatch> = (api) => { + const getFinalMiddleware: Middleware<{}, State, DispatchType> = (api) => { const appliedMiddleware = Array.from(middlewareMap.values()).map((entry) => emplace(entry.applied, api, { insert: () => entry.middleware(api) }), ) @@ -77,7 +80,7 @@ export const createDynamicMiddleware = < const isWithMiddleware = isAllOf(withMiddleware, matchInstance(instanceId)) - const middleware: DynamicMiddleware = + const middleware: DynamicMiddleware = (api) => (next) => (action) => { if (isWithMiddleware(action)) { addMiddleware(...action.payload) diff --git a/packages/toolkit/src/dynamicMiddleware/react/index.ts b/packages/toolkit/src/dynamicMiddleware/react/index.ts index 27fc179a1b..449bdff459 100644 --- a/packages/toolkit/src/dynamicMiddleware/react/index.ts +++ b/packages/toolkit/src/dynamicMiddleware/react/index.ts @@ -1,43 +1,38 @@ import type { - Action as ReduxAction, - UnknownAction, - Dispatch as ReduxDispatch, - Middleware, -} from 'redux' -import type { TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit' + DynamicMiddlewareInstance, + GetDispatch, + GetState, + MiddlewareApiConfig, + TSHelpersExtractDispatchExtensions, +} from '@reduxjs/toolkit' import { createDynamicMiddleware as cDM } from '@reduxjs/toolkit' +import type { Context } from 'react' import type { ReactReduxContextValue } from 'react-redux' import { + createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch, - createDispatchHook, } from 'react-redux' -import type { Context } from 'react' -import type { - DynamicMiddlewareInstance, - GetDispatch, - GetState, - MiddlewareApiConfig, -} from '@reduxjs/toolkit' +import type { Action, Dispatch, Middleware, UnknownAction } from 'redux' export type UseDispatchWithMiddlewareHook< - Middlewares extends Middleware[] = [], + Middlewares extends Middleware[] = [], State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, -> = () => TSHelpersExtractDispatchExtensions & Dispatch + DispatchType extends Dispatch = Dispatch, +> = () => TSHelpersExtractDispatchExtensions & DispatchType export type CreateDispatchWithMiddlewareHook< State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, + DispatchType extends Dispatch = Dispatch, > = { < Middlewares extends [ - Middleware, - ...Middleware[], + Middleware, + ...Middleware[], ], >( ...middlewares: Middlewares - ): UseDispatchWithMiddlewareHook + ): UseDispatchWithMiddlewareHook withTypes< MiddlewareConfig extends MiddlewareApiConfig, >(): CreateDispatchWithMiddlewareHook< @@ -46,35 +41,35 @@ export type CreateDispatchWithMiddlewareHook< > } -type ActionFromDispatch> = - Dispatch extends ReduxDispatch ? Action : never +type ActionFromDispatch> = + DispatchType extends Dispatch ? Action : never -interface ReactDynamicMiddlewareInstance< +type ReactDynamicMiddlewareInstance< State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, -> extends DynamicMiddlewareInstance { + DispatchType extends Dispatch = Dispatch, +> = DynamicMiddlewareInstance & { createDispatchWithMiddlewareHookFactory: ( context?: Context + ActionFromDispatch > | null>, - ) => CreateDispatchWithMiddlewareHook + ) => CreateDispatchWithMiddlewareHook createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook< State, - Dispatch + DispatchType > } export const createDynamicMiddleware = < State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, ->(): ReactDynamicMiddlewareInstance => { - const instance = cDM() + DispatchType extends Dispatch = Dispatch, +>(): ReactDynamicMiddlewareInstance => { + const instance = cDM() const createDispatchWithMiddlewareHookFactory = ( // @ts-ignore context: Context + ActionFromDispatch > | null> = ReactReduxContext, ) => { const useDispatch = @@ -82,7 +77,7 @@ export const createDynamicMiddleware = < ? useDefaultDispatch : createDispatchHook(context) function createDispatchWithMiddlewareHook< - Middlewares extends Middleware[], + Middlewares extends Middleware[], >(...middlewares: Middlewares) { instance.addMiddleware(...middlewares) return useDispatch @@ -91,7 +86,7 @@ export const createDynamicMiddleware = < createDispatchWithMiddlewareHook return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook< State, - Dispatch + DispatchType > } diff --git a/packages/toolkit/src/dynamicMiddleware/types.ts b/packages/toolkit/src/dynamicMiddleware/types.ts index 70590afbcb..ee8c37a21b 100644 --- a/packages/toolkit/src/dynamicMiddleware/types.ts +++ b/packages/toolkit/src/dynamicMiddleware/types.ts @@ -1,60 +1,50 @@ -import type { - Middleware, - Dispatch as ReduxDispatch, - UnknownAction, - MiddlewareAPI, -} from 'redux' +import type { Dispatch, Middleware, MiddlewareAPI, UnknownAction } from 'redux' +import type { BaseActionCreator, PayloadAction } from '../createAction' +import type { GetState } from '../createAsyncThunk' import type { ExtractDispatchExtensions, FallbackIfUnknown } from '../tsHelpers' -import type { PayloadAction, BaseActionCreator } from '../createAction' export type GetMiddlewareApi = MiddlewareAPI< - GetDispatch, + GetDispatchType, GetState > export type MiddlewareApiConfig = { state?: unknown - dispatch?: ReduxDispatch + dispatch?: Dispatch } // TODO: consolidate with cAT helpers? -export type GetState = MiddlewareApiConfig extends { - state: infer State +export type GetDispatchType = MiddlewareApiConfig extends { + dispatch: infer DispatchType } - ? State - : unknown - -export type GetDispatch = MiddlewareApiConfig extends { - dispatch: infer Dispatch -} - ? FallbackIfUnknown - : ReduxDispatch + ? FallbackIfUnknown + : Dispatch export type AddMiddleware< State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, + DispatchType extends Dispatch = Dispatch, > = { - (...middlewares: Middleware[]): void + (...middlewares: Middleware[]): void withTypes(): AddMiddleware< GetState, - GetDispatch + GetDispatchType > } -export interface WithMiddleware< +export type WithMiddleware< State = any, - Dispatch extends ReduxDispatch = ReduxDispatch, -> extends BaseActionCreator< - Middleware[], - 'dynamicMiddleware/add', - { instanceId: string } - > { - []>( + DispatchType extends Dispatch = Dispatch, +> = BaseActionCreator< + Middleware[], + 'dynamicMiddleware/add', + { instanceId: string } +> & { + []>( ...middlewares: Middlewares ): PayloadAction withTypes(): WithMiddleware< GetState, - GetDispatch + GetDispatchType > } @@ -67,27 +57,27 @@ export interface DynamicDispatch { export type MiddlewareEntry< State = unknown, - Dispatch extends ReduxDispatch = ReduxDispatch, + DispatchType extends Dispatch = Dispatch, > = { id: string - middleware: Middleware + middleware: Middleware applied: Map< - MiddlewareAPI, - ReturnType> + MiddlewareAPI, + ReturnType> > } export type DynamicMiddleware< State = unknown, - Dispatch extends ReduxDispatch = ReduxDispatch, -> = Middleware + DispatchType extends Dispatch = Dispatch, +> = Middleware export type DynamicMiddlewareInstance< State = unknown, - Dispatch extends ReduxDispatch = ReduxDispatch, + DispatchType extends Dispatch = Dispatch, > = { - middleware: DynamicMiddleware - addMiddleware: AddMiddleware - withMiddleware: WithMiddleware + middleware: DynamicMiddleware + addMiddleware: AddMiddleware + withMiddleware: WithMiddleware instanceId: string } diff --git a/packages/toolkit/src/entities/models.ts b/packages/toolkit/src/entities/models.ts index efe06450a9..072b8a8894 100644 --- a/packages/toolkit/src/entities/models.ts +++ b/packages/toolkit/src/entities/models.ts @@ -1,8 +1,8 @@ -import type { UncheckedIndexedAccess } from '../uncheckedindexed' import type { Draft } from 'immer' import type { PayloadAction } from '../createAction' +import type { CastAny, Id } from '../tsHelpers' +import type { UncheckedIndexedAccess } from '../uncheckedindexed.js' import type { GetSelectorsOptions } from './state_selectors' -import type { CastAny, Id as Compute } from '../tsHelpers' /** * @public @@ -158,12 +158,12 @@ export interface EntityStateAdapter { /** * @public */ -export interface EntitySelectors { - selectIds: (state: V) => Id[] - selectEntities: (state: V) => Record +export interface EntitySelectors { + selectIds: (state: V) => IdType[] + selectEntities: (state: V) => Record selectAll: (state: V) => T[] selectTotal: (state: V) => number - selectById: (state: V, id: Id) => Compute> + selectById: (state: V, id: IdType) => Id> } /** diff --git a/packages/toolkit/src/entities/state_selectors.ts b/packages/toolkit/src/entities/state_selectors.ts index bd64cf001b..2893c99405 100644 --- a/packages/toolkit/src/entities/state_selectors.ts +++ b/packages/toolkit/src/entities/state_selectors.ts @@ -1,6 +1,6 @@ -import type { CreateSelectorFunction, Selector, createSelector } from 'reselect' +import type { CreateSelectorFunction, Selector } from 'reselect' import { createDraftSafeSelector } from '../createDraftSafeSelector' -import type { EntityState, EntitySelectors, EntityId } from './models' +import type { EntityId, EntitySelectors, EntityState } from './models' type AnyFunction = (...args: any) => any type AnyCreateSelectorFunction = CreateSelectorFunction< @@ -8,7 +8,7 @@ type AnyCreateSelectorFunction = CreateSelectorFunction< (f: F) => F > -export interface GetSelectorsOptions { +export type GetSelectorsOptions = { createSelector?: AnyCreateSelectorFunction } diff --git a/packages/toolkit/src/entities/tests/sorted_state_adapter.test.ts b/packages/toolkit/src/entities/tests/sorted_state_adapter.test.ts index 93cff228f6..042ce37218 100644 --- a/packages/toolkit/src/entities/tests/sorted_state_adapter.test.ts +++ b/packages/toolkit/src/entities/tests/sorted_state_adapter.test.ts @@ -1,20 +1,20 @@ -import type { EntityAdapter, EntityState } from '../models' -import { createEntityAdapter } from '../create_adapter' +import type { PayloadAction } from '@reduxjs/toolkit' import { + configureStore, createAction, createSlice, - configureStore, nanoid, - PayloadAction, } from '@reduxjs/toolkit' +import { createNextState } from '../..' +import { createEntityAdapter } from '../create_adapter' +import type { EntityAdapter, EntityState } from '../models' import type { BookModel } from './fixtures/book' import { - TheGreatGatsby, AClockworkOrange, AnimalFarm, + TheGreatGatsby, TheHobbit, } from './fixtures/book' -import { createNextState } from '../..' describe('Sorted State Adapter', () => { let adapter: EntityAdapter diff --git a/packages/toolkit/src/entities/utils.ts b/packages/toolkit/src/entities/utils.ts index 99a7abebf4..f9f58a6a0c 100644 --- a/packages/toolkit/src/entities/utils.ts +++ b/packages/toolkit/src/entities/utils.ts @@ -1,9 +1,10 @@ -import { Draft, current, isDraft } from 'immer' +import type { Draft } from 'immer' +import { current, isDraft } from 'immer' import type { + DraftableEntityState, + EntityId, IdSelector, Update, - EntityId, - DraftableEntityState, } from './models' export function selectIdValue( diff --git a/packages/toolkit/src/immutableStateInvariantMiddleware.ts b/packages/toolkit/src/immutableStateInvariantMiddleware.ts index 84fc782f56..bd41990e75 100644 --- a/packages/toolkit/src/immutableStateInvariantMiddleware.ts +++ b/packages/toolkit/src/immutableStateInvariantMiddleware.ts @@ -1,4 +1,5 @@ import type { Middleware } from 'redux' +import type { IgnorePaths } from './serializableStateInvariantMiddleware' import { getTimeMeasureUtils } from './utils' type EntryProcessor = (key: string, value: any) => any @@ -60,8 +61,6 @@ function trackProperties( return tracked as TrackedProperty } -type IgnorePaths = readonly (string | RegExp)[] - function detectMutations( isImmutable: IsImmutableFunc, ignoredPaths: IgnorePaths = [], @@ -135,12 +134,12 @@ export interface ImmutableStateInvariantMiddlewareOptions { /** Callback function to check if a value is considered to be immutable. This function is applied recursively to every value contained in the state. - The default implementation will return true for primitive types + The default implementation will return true for primitive types (like numbers, strings, booleans, null and undefined). */ isImmutable?: IsImmutableFunc - /** - An array of dot-separated path strings that match named nodes from + /** + An array of dot-separated path strings that match named nodes from the root state to ignore when checking for immutability. Defaults to undefined */ diff --git a/packages/toolkit/src/index.ts b/packages/toolkit/src/index.ts index 61893b8349..1883310dc2 100644 --- a/packages/toolkit/src/index.ts +++ b/packages/toolkit/src/index.ts @@ -130,6 +130,7 @@ export type { AsyncThunkAction, AsyncThunkPayloadCreatorReturnValue, AsyncThunkPayloadCreator, + GetState, GetThunkAPI, SerializedError, } from './createAsyncThunk' @@ -186,9 +187,10 @@ export { } from './listenerMiddleware/index' export type { + AddMiddleware, + DynamicDispatch, DynamicMiddlewareInstance, - GetDispatch, - GetState, + GetDispatchType as GetDispatch, MiddlewareApiConfig, } from './dynamicMiddleware/types' export { createDynamicMiddleware } from './dynamicMiddleware/index' @@ -202,7 +204,7 @@ export type { AutoBatchOptions } from './autoBatchEnhancer' export { combineSlices } from './combineSlices' -export type { WithSlice } from './combineSlices' +export type { CombinedSliceReducer, WithSlice } from './combineSlices' export type { ExtractDispatchExtensions as TSHelpersExtractDispatchExtensions, diff --git a/packages/toolkit/src/listenerMiddleware/types.ts b/packages/toolkit/src/listenerMiddleware/types.ts index 73a7ef1c0e..e3cba71621 100644 --- a/packages/toolkit/src/listenerMiddleware/types.ts +++ b/packages/toolkit/src/listenerMiddleware/types.ts @@ -1,12 +1,13 @@ import type { + Action, + Dispatch, Middleware, MiddlewareAPI, - Action as ReduxAction, - Dispatch as ReduxDispatch, UnknownAction, } from 'redux' import type { ThunkDispatch } from 'redux-thunk' import type { BaseActionCreator, PayloadAction } from '../createAction' +import type { TypedActionCreator } from '../mapBuilders' import type { TaskAbortError } from './exceptions' /** @@ -20,11 +21,10 @@ export type AbortSignalWithReason = AbortSignal & { reason?: T } */ /** @internal */ -export interface TypedActionCreator { - (...args: any[]): ReduxAction - type: Type - match: MatchFunction -} +type TypedActionCreatorWithMatchFunction = + TypedActionCreator & { + match: MatchFunction + } /** @internal */ export type AnyListenerPredicate = ( @@ -34,11 +34,11 @@ export type AnyListenerPredicate = ( ) => boolean /** @public */ -export type ListenerPredicate = ( +export type ListenerPredicate = ( action: UnknownAction, currentState: State, originalState: State, -) => action is Action +) => action is ActionType /** @public */ export interface ConditionFunction { @@ -143,9 +143,9 @@ export interface ForkOptions { /** @public */ export interface ListenerEffectAPI< State, - Dispatch extends ReduxDispatch, + DispatchType extends Dispatch, ExtraArgument = unknown, -> extends MiddlewareAPI { +> extends MiddlewareAPI { /** * Returns the store state as it existed when the action was originally dispatched, _before_ the reducers ran. * @@ -269,13 +269,13 @@ export interface ListenerEffectAPI< /** @public */ export type ListenerEffect< - Action extends ReduxAction, + ActionType extends Action, State, - Dispatch extends ReduxDispatch, + DispatchType extends Dispatch, ExtraArgument = unknown, > = ( - action: Action, - api: ListenerEffectAPI, + action: ActionType, + api: ListenerEffectAPI, ) => void | Promise /** @@ -311,7 +311,7 @@ export interface CreateListenerMiddlewareOptions { /** @public */ export type ListenerMiddleware< State = unknown, - Dispatch extends ThunkDispatch = ThunkDispatch< + DispatchType extends ThunkDispatch = ThunkDispatch< State, unknown, UnknownAction @@ -319,10 +319,10 @@ export type ListenerMiddleware< ExtraArgument = unknown, > = Middleware< { - (action: ReduxAction<'listenerMiddleware/add'>): UnsubscribeListener + (action: Action<'listenerMiddleware/add'>): UnsubscribeListener }, State, - Dispatch + DispatchType > /** @public */ @@ -331,7 +331,7 @@ export interface ListenerMiddlewareInstance< DispatchType extends ThunkDispatch< StateType, unknown, - ReduxAction + Action > = ThunkDispatch, ExtraArgument = unknown, > { @@ -363,8 +363,8 @@ export type TakePatternOutputWithoutTimeout< State, Predicate extends AnyListenerPredicate, > = - Predicate extends MatchFunction - ? Promise<[Action, State, State]> + Predicate extends MatchFunction + ? Promise<[ActionType, State, State]> : Promise<[UnknownAction, State, State]> /** @public */ @@ -372,8 +372,8 @@ export type TakePatternOutputWithTimeout< State, Predicate extends AnyListenerPredicate, > = - Predicate extends MatchFunction - ? Promise<[Action, State, State] | null> + Predicate extends MatchFunction + ? Promise<[ActionType, State, State] | null> : Promise<[UnknownAction, State, State] | null> /** @public */ @@ -405,17 +405,17 @@ export type UnsubscribeListener = ( * @public * The possible overloads and options for defining a listener. The return type of each function is specified as a generic arg, so the overloads can be reused for multiple different functions */ -export interface AddListenerOverloads< +export type AddListenerOverloads< Return, StateType = unknown, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction >, ExtraArgument = unknown, AdditionalOptions = unknown, -> { +> = { /** Accepts a "listener predicate" that is also a TS type predicate for the action*/ < MiddlewareActionType extends UnknownAction, @@ -439,7 +439,7 @@ export interface AddListenerOverloads< ): Return /** Accepts an RTK action creator, like `incrementByAmount` */ - >( + >( options: { actionCreator: ActionCreatorType type?: never @@ -461,12 +461,7 @@ export interface AddListenerOverloads< type: T matcher?: never predicate?: never - effect: ListenerEffect< - ReduxAction, - StateType, - DispatchType, - ExtraArgument - > + effect: ListenerEffect, StateType, DispatchType, ExtraArgument> } & AdditionalOptions, ): Return @@ -506,7 +501,7 @@ export interface AddListenerOverloads< /** @public */ export type RemoveListenerOverloads< StateType = unknown, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction @@ -521,14 +516,14 @@ export type RemoveListenerOverloads< /** @public */ export interface RemoveListenerAction< - Action extends UnknownAction, + ActionType extends UnknownAction, State, - Dispatch extends ReduxDispatch, + DispatchType extends Dispatch, > { type: 'listenerMiddleware/remove' payload: { type: string - listener: ListenerEffect + listener: ListenerEffect } } @@ -539,7 +534,7 @@ export interface RemoveListenerAction< */ export type TypedAddListener< StateType, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction @@ -577,7 +572,7 @@ export type TypedAddListener< */ withTypes: < OverrideStateType extends StateType, - OverrideDispatchType extends ReduxDispatch = ThunkDispatch< + OverrideDispatchType extends Dispatch = ThunkDispatch< OverrideStateType, unknown, UnknownAction @@ -592,7 +587,7 @@ export type TypedAddListener< */ export type TypedRemoveListener< StateType, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction @@ -630,7 +625,7 @@ export type TypedRemoveListener< */ withTypes: < OverrideStateType extends StateType, - OverrideDispatchType extends ReduxDispatch = ThunkDispatch< + OverrideDispatchType extends Dispatch = ThunkDispatch< OverrideStateType, unknown, UnknownAction @@ -645,7 +640,7 @@ export type TypedRemoveListener< */ export type TypedStartListening< StateType, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction @@ -687,7 +682,7 @@ export type TypedStartListening< */ withTypes: < OverrideStateType extends StateType, - OverrideDispatchType extends ReduxDispatch = ThunkDispatch< + OverrideDispatchType extends Dispatch = ThunkDispatch< OverrideStateType, unknown, UnknownAction @@ -702,7 +697,7 @@ export type TypedStartListening< */ export type TypedStopListening< StateType, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction @@ -738,7 +733,7 @@ export type TypedStopListening< */ withTypes: < OverrideStateType extends StateType, - OverrideDispatchType extends ReduxDispatch = ThunkDispatch< + OverrideDispatchType extends Dispatch = ThunkDispatch< OverrideStateType, unknown, UnknownAction @@ -753,7 +748,7 @@ export type TypedStopListening< */ export type TypedCreateListenerEntry< StateType, - DispatchType extends ReduxDispatch = ThunkDispatch< + DispatchType extends Dispatch = ThunkDispatch< StateType, unknown, UnknownAction @@ -789,7 +784,7 @@ export type TypedCreateListenerEntry< */ withTypes: < OverrideStateType extends StateType, - OverrideDispatchType extends ReduxDispatch = ThunkDispatch< + OverrideDispatchType extends Dispatch = ThunkDispatch< OverrideStateType, unknown, UnknownAction @@ -804,10 +799,10 @@ export type TypedCreateListenerEntry< /** @internal An single listener entry */ export type ListenerEntry< State = unknown, - Dispatch extends ReduxDispatch = ReduxDispatch, + DispatchType extends Dispatch = Dispatch, > = { id: string - effect: ListenerEffect + effect: ListenerEffect unsubscribe: () => void pending: Set type?: string @@ -819,7 +814,7 @@ export type ListenerEntry< * A shorthand form of the accepted args, solely so that `createListenerEntry` has validly-typed conditional logic when checking the options contents */ export type FallbackAddListenerOptions = { - actionCreator?: TypedActionCreator + actionCreator?: TypedActionCreatorWithMatchFunction type?: string matcher?: MatchFunction predicate?: ListenerPredicate @@ -836,4 +831,4 @@ export type GuardedType = T extends (x: any, ...args: any[]) => x is infer T /** @public */ export type ListenerPredicateGuardedActionType = - T extends ListenerPredicate ? Action : never + T extends ListenerPredicate ? ActionType : never diff --git a/packages/toolkit/src/mapBuilders.ts b/packages/toolkit/src/mapBuilders.ts index 560d640888..31ba5b4142 100644 --- a/packages/toolkit/src/mapBuilders.ts +++ b/packages/toolkit/src/mapBuilders.ts @@ -6,7 +6,7 @@ import type { } from './createReducer' import type { TypeGuard } from './tsHelpers' -export interface TypedActionCreator { +export type TypedActionCreator = { (...args: any[]): Action type: Type } diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index 99a24c4e87..5c73e36879 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -1,30 +1,19 @@ +import type { UnknownAction } from '@reduxjs/toolkit' +import type { BaseQueryFn } from './baseQueryTypes' +import type { CombinedState, CoreModule } from './core' +import type { ApiModules } from './core/module' +import type { CreateApiOptions } from './createApi' import type { - EndpointDefinitions, EndpointBuilder, EndpointDefinition, + EndpointDefinitions, UpdateDefinitions, } from './endpointDefinitions' import type { - UnionToIntersection, NoInfer, + UnionToIntersection, WithRequiredProp, } from './tsHelpers' -import type { CoreModule } from './core/module' -import type { CreateApiOptions } from './createApi' -import type { BaseQueryFn } from './baseQueryTypes' -import type { CombinedState } from './core/apiState' -import type { UnknownAction } from '@reduxjs/toolkit' - -export interface ApiModules< - // eslint-disable-next-line @typescript-eslint/no-unused-vars - BaseQuery extends BaseQueryFn, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - Definitions extends EndpointDefinitions, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ReducerPath extends string, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TagTypes extends string, -> {} export type ModuleName = keyof ApiModules diff --git a/packages/toolkit/src/query/core/buildInitiate.ts b/packages/toolkit/src/query/core/buildInitiate.ts index 3823b14d79..ff2ab45456 100644 --- a/packages/toolkit/src/query/core/buildInitiate.ts +++ b/packages/toolkit/src/query/core/buildInitiate.ts @@ -1,52 +1,44 @@ +import type { + SerializedError, + ThunkAction, + UnknownAction, +} from '@reduxjs/toolkit' +import type { Dispatch } from 'redux' +import type { SafePromise } from '../../tsHelpers' +import { asSafePromise } from '../../tsHelpers' +import type { Api, ApiContext } from '../apiTypes' +import type { BaseQueryError, QueryReturnValue } from '../baseQueryTypes' +import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' import type { EndpointDefinitions, - QueryDefinition, MutationDefinition, QueryArgFrom, + QueryDefinition, ResultTypeFrom, } from '../endpointDefinitions' -import { DefinitionType, isQueryDefinition } from '../endpointDefinitions' -import type { QueryThunk, MutationThunk, QueryThunkArg } from './buildThunks' -import type { - UnknownAction, - ThunkAction, - SerializedError, -} from '@reduxjs/toolkit' -import type { SubscriptionOptions, RootState } from './apiState' -import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' -import type { Api, ApiContext } from '../apiTypes' -import type { ApiEndpointQuery } from './module' -import type { BaseQueryError, QueryReturnValue } from '../baseQueryTypes' +import { countObjectKeys, isNotNullish } from '../utils' +import type { SubscriptionOptions } from './apiState' import type { QueryResultSelectorResult } from './buildSelectors' -import type { Dispatch } from 'redux' -import { isNotNullish } from '../utils/isNotNullish' -import { countObjectKeys } from '../utils/countObjectKeys' -import type { SafePromise } from '../../tsHelpers' -import { asSafePromise } from '../../tsHelpers' +import type { MutationThunk, QueryThunk, QueryThunkArg } from './buildThunks' +import type { ApiEndpointQuery } from './module' -declare module './module' { - export interface ApiEndpointQuery< - Definition extends QueryDefinition, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - Definitions extends EndpointDefinitions, - > { - initiate: StartQueryActionCreator - } +export type BuildInitiateApiEndpointQuery< + Definition extends QueryDefinition, +> = { + initiate: StartQueryActionCreator +} - export interface ApiEndpointMutation< - Definition extends MutationDefinition, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - Definitions extends EndpointDefinitions, - > { - initiate: StartMutationActionCreator - } +export type BuildInitiateApiEndpointMutation< + Definition extends MutationDefinition, +> = { + initiate: StartMutationActionCreator } export const forceQueryFnSymbol = Symbol('forceQueryFn') export const isUpsertQuery = (arg: QueryThunkArg) => typeof arg[forceQueryFnSymbol] === 'function' -export interface StartQueryActionCreatorOptions { +export type StartQueryActionCreatorOptions = { subscribe?: boolean forceRefetch?: boolean | number subscriptionOptions?: SubscriptionOptions diff --git a/packages/toolkit/src/query/core/buildMiddleware/cacheCollection.ts b/packages/toolkit/src/query/core/buildMiddleware/cacheCollection.ts index 4ad73cfc4b..881fd9e11d 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/cacheCollection.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/cacheCollection.ts @@ -1,14 +1,12 @@ -import { isAnyOf } from '@reduxjs/toolkit' -import type { BaseQueryFn } from '../../baseQueryTypes' import type { QueryDefinition } from '../../endpointDefinitions' import type { ConfigState, QueryCacheKey } from '../apiState' +import { isAnyOf } from '../rtkImports' import type { + ApiMiddlewareInternalHandler, + InternalHandlerBuilder, QueryStateMeta, SubMiddlewareApi, TimeoutId, - InternalHandlerBuilder, - ApiMiddlewareInternalHandler, - InternalMiddlewareState, } from './types' export type ReferenceCacheCollection = never @@ -16,28 +14,20 @@ export type ReferenceCacheCollection = never function isObjectEmpty(obj: Record) { // Apparently a for..in loop is faster than `Object.keys()` here: // https://stackoverflow.com/a/59787784/62937 - for (let k in obj) { + for (const k in obj) { // If there is at least one key, it's not empty return false } return true } -declare module '../../endpointDefinitions' { - interface QueryExtraOptions< - TagTypes extends string, - ResultType, - QueryArg, - BaseQuery extends BaseQueryFn, - ReducerPath extends string = string, - > { - /** - * Overrides the api-wide definition of `keepUnusedDataFor` for this endpoint only. _(This value is in seconds.)_ - * - * This is how long RTK Query will keep your data cached for **after** the last component unsubscribes. For example, if you query an endpoint, then unmount the component, then mount another component that makes the same request within the given time frame, the most recent value will be served from the cache. - */ - keepUnusedDataFor?: number - } +export type CacheCollectionQueryExtraOptions = { + /** + * Overrides the api-wide definition of `keepUnusedDataFor` for this endpoint only. _(This value is in seconds.)_ + * + * This is how long RTK Query will keep your data cached for **after** the last component unsubscribes. For example, if you query an endpoint, then unmount the component, then mount another component that makes the same request within the given time frame, the most recent value will be served from the cache. + */ + keepUnusedDataFor?: number } // Per https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value , browsers store @@ -59,7 +49,7 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({ const canTriggerUnsubscribe = isAnyOf( unsubscribeQueryResult.match, queryThunk.fulfilled, - queryThunk.rejected + queryThunk.rejected, ) function anySubscriptionsRemainingForKey(queryCacheKey: string) { diff --git a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts index 0a41e0174f..ebbbc727bb 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts @@ -1,7 +1,6 @@ -import { isAsyncThunkAction, isFulfilled } from '../rtkImports' -import type { UnknownAction } from 'redux' -import type { ThunkDispatch } from 'redux-thunk' +import type { ThunkDispatch, UnknownAction } from '@reduxjs/toolkit' import type { BaseQueryFn, BaseQueryMeta } from '../../baseQueryTypes' +import type { BaseEndpointDefinition } from '../../endpointDefinitions' import { DefinitionType } from '../../endpointDefinitions' import type { RootState } from '../apiState' import type { @@ -10,6 +9,7 @@ import type { } from '../buildSelectors' import { getMutationCacheKey } from '../buildSlice' import type { PatchCollection, Recipe } from '../buildThunks' +import { isAsyncThunkAction, isFulfilled } from '../rtkImports' import type { ApiMiddlewareInternalHandler, InternalHandlerBuilder, @@ -19,156 +19,144 @@ import type { export type ReferenceCacheLifecycle = never -declare module '../../endpointDefinitions' { - export interface QueryBaseLifecycleApi< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, - ReducerPath extends string = string, - > extends LifecycleApi { - /** - * Gets the current value of this cache entry. - */ - getCacheEntry(): QueryResultSelectorResult< - { type: DefinitionType.query } & BaseEndpointDefinition< - QueryArg, - BaseQuery, - ResultType - > +export interface QueryBaseLifecycleApi< + QueryArg, + BaseQuery extends BaseQueryFn, + ResultType, + ReducerPath extends string = string, +> extends LifecycleApi { + /** + * Gets the current value of this cache entry. + */ + getCacheEntry(): QueryResultSelectorResult< + { type: DefinitionType.query } & BaseEndpointDefinition< + QueryArg, + BaseQuery, + ResultType > - /** - * Updates the current cache entry value. - * For documentation see `api.util.updateQueryData`. - */ - updateCachedData(updateRecipe: Recipe): PatchCollection - } + > + /** + * Updates the current cache entry value. + * For documentation see `api.util.updateQueryData`. + */ + updateCachedData(updateRecipe: Recipe): PatchCollection +} - export interface MutationBaseLifecycleApi< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, - ReducerPath extends string = string, - > extends LifecycleApi { - /** - * Gets the current value of this cache entry. - */ - getCacheEntry(): MutationResultSelectorResult< - { type: DefinitionType.mutation } & BaseEndpointDefinition< - QueryArg, - BaseQuery, - ResultType - > +export type MutationBaseLifecycleApi< + QueryArg, + BaseQuery extends BaseQueryFn, + ResultType, + ReducerPath extends string = string, +> = LifecycleApi & { + /** + * Gets the current value of this cache entry. + */ + getCacheEntry(): MutationResultSelectorResult< + { type: DefinitionType.mutation } & BaseEndpointDefinition< + QueryArg, + BaseQuery, + ResultType > - } + > +} - export interface LifecycleApi { - /** - * The dispatch method for the store - */ - dispatch: ThunkDispatch - /** - * A method to get the current state - */ - getState(): RootState - /** - * `extra` as provided as `thunk.extraArgument` to the `configureStore` `getDefaultMiddleware` option. - */ - extra: unknown - /** - * A unique ID generated for the mutation - */ - requestId: string - } +type LifecycleApi = { + /** + * The dispatch method for the store + */ + dispatch: ThunkDispatch + /** + * A method to get the current state + */ + getState(): RootState + /** + * `extra` as provided as `thunk.extraArgument` to the `configureStore` `getDefaultMiddleware` option. + */ + extra: unknown + /** + * A unique ID generated for the mutation + */ + requestId: string +} - export interface CacheLifecyclePromises< - ResultType = unknown, - MetaType = unknown, - > { - /** - * Promise that will resolve with the first value for this cache key. - * This allows you to `await` until an actual value is in cache. - * - * If the cache entry is removed from the cache before any value has ever - * been resolved, this Promise will reject with - * `new Error('Promise never resolved before cacheEntryRemoved.')` - * to prevent memory leaks. - * You can just re-throw that error (or not handle it at all) - - * it will be caught outside of `cacheEntryAdded`. - * - * If you don't interact with this promise, it will not throw. - */ - cacheDataLoaded: PromiseWithKnownReason< - { - /** - * The (transformed) query result. - */ - data: ResultType - /** - * The `meta` returned by the `baseQuery` - */ - meta: MetaType - }, - typeof neverResolvedError - > - /** - * Promise that allows you to wait for the point in time when the cache entry - * has been removed from the cache, by not being used/subscribed to any more - * in the application for too long or by dispatching `api.util.resetApiState`. - */ - cacheEntryRemoved: Promise - } +type CacheLifecyclePromises = { + /** + * Promise that will resolve with the first value for this cache key. + * This allows you to `await` until an actual value is in cache. + * + * If the cache entry is removed from the cache before any value has ever + * been resolved, this Promise will reject with + * `new Error('Promise never resolved before cacheEntryRemoved.')` + * to prevent memory leaks. + * You can just re-throw that error (or not handle it at all) - + * it will be caught outside of `cacheEntryAdded`. + * + * If you don't interact with this promise, it will not throw. + */ + cacheDataLoaded: PromiseWithKnownReason< + { + /** + * The (transformed) query result. + */ + data: ResultType + /** + * The `meta` returned by the `baseQuery` + */ + meta: MetaType + }, + typeof neverResolvedError + > + /** + * Promise that allows you to wait for the point in time when the cache entry + * has been removed from the cache, by not being used/subscribed to any more + * in the application for too long or by dispatching `api.util.resetApiState`. + */ + cacheEntryRemoved: Promise +} - export interface QueryCacheLifecycleApi< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, - ReducerPath extends string = string, - > extends QueryBaseLifecycleApi, - CacheLifecyclePromises> {} +export interface QueryCacheLifecycleApi< + QueryArg, + BaseQuery extends BaseQueryFn, + ResultType, + ReducerPath extends string = string, +> extends QueryBaseLifecycleApi, + CacheLifecyclePromises> {} - export interface MutationCacheLifecycleApi< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, - ReducerPath extends string = string, - > extends MutationBaseLifecycleApi< - QueryArg, - BaseQuery, - ResultType, - ReducerPath - >, - CacheLifecyclePromises> {} +export type MutationCacheLifecycleApi< + QueryArg, + BaseQuery extends BaseQueryFn, + ResultType, + ReducerPath extends string = string, +> = MutationBaseLifecycleApi & + CacheLifecyclePromises> - interface QueryExtraOptions< - TagTypes extends string, - ResultType, - QueryArg, - BaseQuery extends BaseQueryFn, - ReducerPath extends string = string, - > { - onCacheEntryAdded?( - arg: QueryArg, - api: QueryCacheLifecycleApi, - ): Promise | void - } +export type CacheLifecycleQueryExtraOptions< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, + ReducerPath extends string = string, +> = { + onCacheEntryAdded?( + arg: QueryArg, + api: QueryCacheLifecycleApi, + ): Promise | void +} - interface MutationExtraOptions< - TagTypes extends string, - ResultType, - QueryArg, - BaseQuery extends BaseQueryFn, - ReducerPath extends string = string, - > { - onCacheEntryAdded?( - arg: QueryArg, - api: MutationCacheLifecycleApi< - QueryArg, - BaseQuery, - ResultType, - ReducerPath - >, - ): Promise | void - } +export type CacheLifecycleMutationExtraOptions< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, + ReducerPath extends string = string, +> = { + onCacheEntryAdded?( + arg: QueryArg, + api: MutationCacheLifecycleApi< + QueryArg, + BaseQuery, + ResultType, + ReducerPath + >, + ): Promise | void } const neverResolvedError = new Error( @@ -274,7 +262,7 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({ const onCacheEntryAdded = endpointDefinition?.onCacheEntryAdded if (!onCacheEntryAdded) return - let lifecycle = {} as CacheLifecycle + const lifecycle = {} as CacheLifecycle const cacheEntryRemoved = new Promise((resolve) => { lifecycle.cacheEntryRemoved = resolve diff --git a/packages/toolkit/src/query/core/buildMiddleware/index.ts b/packages/toolkit/src/query/core/buildMiddleware/index.ts index 4c44107368..737b2fa533 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/index.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/index.ts @@ -4,27 +4,38 @@ import type { ThunkDispatch, UnknownAction, } from '@reduxjs/toolkit' -import { isAction, createAction } from '../rtkImports' - import type { EndpointDefinitions, FullTagDescription, } from '../../endpointDefinitions' import type { QueryStatus, QuerySubState, RootState } from '../apiState' import type { QueryThunkArg } from '../buildThunks' +import { createAction, isAction } from '../rtkImports' +import { buildBatchedActionsHandler } from './batchActions' import { buildCacheCollectionHandler } from './cacheCollection' +import { buildCacheLifecycleHandler } from './cacheLifecycle' +import { buildDevCheckHandler } from './devMiddleware' import { buildInvalidationByTagsHandler } from './invalidationByTags' import { buildPollingHandler } from './polling' +import { buildQueryLifecycleHandler } from './queryLifecycle' import type { BuildMiddlewareInput, InternalHandlerBuilder, InternalMiddlewareState, } from './types' import { buildWindowEventHandler } from './windowEventHandling' -import { buildCacheLifecycleHandler } from './cacheLifecycle' -import { buildQueryLifecycleHandler } from './queryLifecycle' -import { buildDevCheckHandler } from './devMiddleware' -import { buildBatchedActionsHandler } from './batchActions' +export type { ReferenceCacheCollection } from './cacheCollection' +export type { + MutationCacheLifecycleApi, + QueryCacheLifecycleApi, + ReferenceCacheLifecycle, +} from './cacheLifecycle' +export type { + MutationLifecycleApi, + QueryLifecycleApi, + ReferenceQueryLifecycle, +} from './queryLifecycle' +export type { SubscriptionSelectors } from './types' export function buildMiddleware< Definitions extends EndpointDefinitions, @@ -59,7 +70,7 @@ export function buildMiddleware< > = (mwApi) => { let initialized = false - let internalState: InternalMiddlewareState = { + const internalState: InternalMiddlewareState = { currentSubscriptions: {}, } @@ -117,7 +128,7 @@ export function buildMiddleware< ) { // Only run these additional checks if the actions are part of the API slice, // or the action has hydration-related data - for (let handler of handlers) { + for (const handler of handlers) { handler(action, mwApiWithNext, stateBefore) } } diff --git a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts index ebb47b771c..8b899d9202 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts @@ -1,205 +1,196 @@ -import { isPending, isRejected, isFulfilled } from '../rtkImports' import type { BaseQueryError, BaseQueryFn, BaseQueryMeta, } from '../../baseQueryTypes' import { DefinitionType } from '../../endpointDefinitions' -import type { QueryFulfilledRejectionReason } from '../../endpointDefinitions' import type { Recipe } from '../buildThunks' +import { isFulfilled, isPending, isRejected } from '../rtkImports' +import type { + MutationBaseLifecycleApi, + QueryBaseLifecycleApi, +} from './cacheLifecycle' import type { - PromiseWithKnownReason, - PromiseConstructorWithKnownReason, - InternalHandlerBuilder, ApiMiddlewareInternalHandler, + InternalHandlerBuilder, + PromiseConstructorWithKnownReason, + PromiseWithKnownReason, } from './types' export type ReferenceQueryLifecycle = never -declare module '../../endpointDefinitions' { - export interface QueryLifecyclePromises< - ResultType, - BaseQuery extends BaseQueryFn, - > { - /** - * Promise that will resolve with the (transformed) query result. - * - * If the query fails, this promise will reject with the error. - * - * This allows you to `await` for the query to finish. - * - * If you don't interact with this promise, it will not throw. - */ - queryFulfilled: PromiseWithKnownReason< - { - /** - * The (transformed) query result. - */ - data: ResultType - /** - * The `meta` returned by the `baseQuery` - */ - meta: BaseQueryMeta - }, - QueryFulfilledRejectionReason - > - } +type QueryLifecyclePromises = { + /** + * Promise that will resolve with the (transformed) query result. + * + * If the query fails, this promise will reject with the error. + * + * This allows you to `await` for the query to finish. + * + * If you don't interact with this promise, it will not throw. + */ + queryFulfilled: PromiseWithKnownReason< + { + /** + * The (transformed) query result. + */ + data: ResultType + /** + * The `meta` returned by the `baseQuery` + */ + meta: BaseQueryMeta + }, + QueryFulfilledRejectionReason + > +} - type QueryFulfilledRejectionReason = - | { - error: BaseQueryError - /** - * If this is `false`, that means this error was returned from the `baseQuery` or `queryFn` in a controlled manner. - */ - isUnhandledError: false - /** - * The `meta` returned by the `baseQuery` - */ - meta: BaseQueryMeta - } - | { - error: unknown - meta?: undefined - /** - * If this is `true`, that means that this error is the result of `baseQueryFn`, `queryFn`, `transformResponse` or `transformErrorResponse` throwing an error instead of handling it properly. - * There can not be made any assumption about the shape of `error`. - */ - isUnhandledError: true - } +type QueryFulfilledRejectionReason = + | { + error: BaseQueryError + /** + * If this is `false`, that means this error was returned from the `baseQuery` or `queryFn` in a controlled manner. + */ + isUnhandledError: false + /** + * The `meta` returned by the `baseQuery` + */ + meta: BaseQueryMeta + } + | { + error: unknown + meta?: undefined + /** + * If this is `true`, that means that this error is the result of `baseQueryFn`, `queryFn`, `transformResponse` or `transformErrorResponse` throwing an error instead of handling it properly. + * There can not be made any assumption about the shape of `error`. + */ + isUnhandledError: true + } - interface QueryExtraOptions< - TagTypes extends string, - ResultType, - QueryArg, - BaseQuery extends BaseQueryFn, - ReducerPath extends string = string, - > { - /** - * A function that is called when the individual query is started. The function is called with a lifecycle api object containing properties such as `queryFulfilled`, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call). - * - * Can be used to perform side-effects throughout the lifecycle of the query. - * - * @example - * ```ts - * import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' - * import { messageCreated } from './notificationsSlice - * export interface Post { - * id: number - * name: string - * } - * - * const api = createApi({ - * baseQuery: fetchBaseQuery({ - * baseUrl: '/', - * }), - * endpoints: (build) => ({ - * getPost: build.query({ - * query: (id) => `post/${id}`, - * async onQueryStarted(id, { dispatch, queryFulfilled }) { - * // `onStart` side-effect - * dispatch(messageCreated('Fetching posts...')) - * try { - * const { data } = await queryFulfilled - * // `onSuccess` side-effect - * dispatch(messageCreated('Posts received!')) - * } catch (err) { - * // `onError` side-effect - * dispatch(messageCreated('Error fetching posts!')) - * } - * } - * }), - * }), - * }) - * ``` - */ - onQueryStarted?( - arg: QueryArg, - api: QueryLifecycleApi, - ): Promise | void - } +export type QueryLifecycleQueryExtraOptions< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, + ReducerPath extends string = string, +> = { + /** + * A function that is called when the individual query is started. The function is called with a lifecycle api object containing properties such as `queryFulfilled`, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call). + * + * Can be used to perform side-effects throughout the lifecycle of the query. + * + * @example + * ```ts + * import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' + * import { messageCreated } from './notificationsSlice + * export interface Post { + * id: number + * name: string + * } + * + * const api = createApi({ + * baseQuery: fetchBaseQuery({ + * baseUrl: '/', + * }), + * endpoints: (build) => ({ + * getPost: build.query({ + * query: (id) => `post/${id}`, + * async onQueryStarted(id, { dispatch, queryFulfilled }) { + * // `onStart` side-effect + * dispatch(messageCreated('Fetching posts...')) + * try { + * const { data } = await queryFulfilled + * // `onSuccess` side-effect + * dispatch(messageCreated('Posts received!')) + * } catch (err) { + * // `onError` side-effect + * dispatch(messageCreated('Error fetching posts!')) + * } + * } + * }), + * }), + * }) + * ``` + */ + onQueryStarted?( + arg: QueryArg, + api: QueryLifecycleApi, + ): Promise | void +} - interface MutationExtraOptions< - TagTypes extends string, - ResultType, - QueryArg, - BaseQuery extends BaseQueryFn, - ReducerPath extends string = string, - > { - /** - * A function that is called when the individual mutation is started. The function is called with a lifecycle api object containing properties such as `queryFulfilled`, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call). - * - * Can be used for `optimistic updates`. - * - * @example - * - * ```ts - * import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' - * export interface Post { - * id: number - * name: string - * } - * - * const api = createApi({ - * baseQuery: fetchBaseQuery({ - * baseUrl: '/', - * }), - * tagTypes: ['Post'], - * endpoints: (build) => ({ - * getPost: build.query({ - * query: (id) => `post/${id}`, - * providesTags: ['Post'], - * }), - * updatePost: build.mutation & Partial>({ - * query: ({ id, ...patch }) => ({ - * url: `post/${id}`, - * method: 'PATCH', - * body: patch, - * }), - * invalidatesTags: ['Post'], - * async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) { - * const patchResult = dispatch( - * api.util.updateQueryData('getPost', id, (draft) => { - * Object.assign(draft, patch) - * }) - * ) - * try { - * await queryFulfilled - * } catch { - * patchResult.undo() - * } - * }, - * }), - * }), - * }) - * ``` - */ - onQueryStarted?( - arg: QueryArg, - api: MutationLifecycleApi, - ): Promise | void - } +export type QueryLifecycleMutationExtraOptions< + ResultType, + QueryArg, + BaseQuery extends BaseQueryFn, + ReducerPath extends string = string, +> = { + /** + * A function that is called when the individual mutation is started. The function is called with a lifecycle api object containing properties such as `queryFulfilled`, allowing code to be run when a query is started, when it succeeds, and when it fails (i.e. throughout the lifecycle of an individual query/mutation call). + * + * Can be used for `optimistic updates`. + * + * @example + * + * ```ts + * import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' + * export interface Post { + * id: number + * name: string + * } + * + * const api = createApi({ + * baseQuery: fetchBaseQuery({ + * baseUrl: '/', + * }), + * tagTypes: ['Post'], + * endpoints: (build) => ({ + * getPost: build.query({ + * query: (id) => `post/${id}`, + * providesTags: ['Post'], + * }), + * updatePost: build.mutation & Partial>({ + * query: ({ id, ...patch }) => ({ + * url: `post/${id}`, + * method: 'PATCH', + * body: patch, + * }), + * invalidatesTags: ['Post'], + * async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) { + * const patchResult = dispatch( + * api.util.updateQueryData('getPost', id, (draft) => { + * Object.assign(draft, patch) + * }) + * ) + * try { + * await queryFulfilled + * } catch { + * patchResult.undo() + * } + * }, + * }), + * }), + * }) + * ``` + */ + onQueryStarted?( + arg: QueryArg, + api: MutationLifecycleApi, + ): Promise | void +} - export interface QueryLifecycleApi< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, - ReducerPath extends string = string, - > extends QueryBaseLifecycleApi, - QueryLifecyclePromises {} +export interface QueryLifecycleApi< + QueryArg, + BaseQuery extends BaseQueryFn, + ResultType, + ReducerPath extends string = string, +> extends QueryBaseLifecycleApi, + QueryLifecyclePromises {} - export interface MutationLifecycleApi< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, - ReducerPath extends string = string, - > extends MutationBaseLifecycleApi< - QueryArg, - BaseQuery, - ResultType, - ReducerPath - >, - QueryLifecyclePromises {} -} +export type MutationLifecycleApi< + QueryArg, + BaseQuery extends BaseQueryFn, + ResultType, + ReducerPath extends string = string, +> = MutationBaseLifecycleApi & + QueryLifecyclePromises export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({ api, diff --git a/packages/toolkit/src/query/core/buildMiddleware/types.ts b/packages/toolkit/src/query/core/buildMiddleware/types.ts index e2ab377b6c..ecf40d23f0 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/types.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/types.ts @@ -6,7 +6,6 @@ import type { ThunkDispatch, UnknownAction, } from '@reduxjs/toolkit' - import type { Api, ApiContext } from '../../apiTypes' import type { AssertTagTypes, @@ -105,8 +104,10 @@ export interface PromiseConstructorWithKnownReason { ): PromiseWithKnownReason } -export interface PromiseWithKnownReason - extends Omit, 'then' | 'catch'> { +export type PromiseWithKnownReason = Omit< + Promise, + 'then' | 'catch' +> & { /** * Attaches callbacks for the resolution and/or rejection of the Promise. * @param onfulfilled The callback to execute when the Promise is resolved. diff --git a/packages/toolkit/src/query/core/buildSelectors.ts b/packages/toolkit/src/query/core/buildSelectors.ts index 4ca49fc3e4..83fa9c0103 100644 --- a/packages/toolkit/src/query/core/buildSelectors.ts +++ b/packages/toolkit/src/query/core/buildSelectors.ts @@ -1,28 +1,28 @@ -import type { createSelector as _createSelector } from './rtkImports' -import { createNextState } from './rtkImports' -import type { - MutationSubState, - QuerySubState, - RootState as _RootState, - RequestStatusFlags, - QueryCacheKey, - QueryKeys, - QueryState, -} from './apiState' -import { QueryStatus, getRequestStatusFlags } from './apiState' +import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' import type { EndpointDefinitions, - QueryDefinition, MutationDefinition, QueryArgFrom, - TagTypesFrom, + QueryDefinition, ReducerPathFrom, TagDescription, + TagTypesFrom, } from '../endpointDefinitions' import { expandTagDescription } from '../endpointDefinitions' -import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' -import { getMutationCacheKey } from './buildSlice' import { flatten } from '../utils' +import type { + MutationSubState, + QueryCacheKey, + QueryKeys, + QueryState, + QuerySubState, + RequestStatusFlags, + RootState as _RootState, +} from './apiState' +import { QueryStatus, getRequestStatusFlags } from './apiState' +import { getMutationCacheKey } from './buildSlice' +import type { createSelector as _createSelector } from './rtkImports' +import { createNextState } from './rtkImports' export type SkipToken = typeof skipToken /** @@ -49,34 +49,32 @@ export type SkipToken = typeof skipToken */ export const skipToken = /* @__PURE__ */ Symbol.for('RTKQ/skipToken') -declare module './module' { - export interface ApiEndpointQuery< - Definition extends QueryDefinition, - Definitions extends EndpointDefinitions, - > { - select: QueryResultSelectorFactory< - Definition, - _RootState< - Definitions, - TagTypesFrom, - ReducerPathFrom - > +export type BuildSelectorsApiEndpointQuery< + Definition extends QueryDefinition, + Definitions extends EndpointDefinitions, +> = { + select: QueryResultSelectorFactory< + Definition, + _RootState< + Definitions, + TagTypesFrom, + ReducerPathFrom > - } + > +} - export interface ApiEndpointMutation< - Definition extends MutationDefinition, - Definitions extends EndpointDefinitions, - > { - select: MutationResultSelectorFactory< - Definition, - _RootState< - Definitions, - TagTypesFrom, - ReducerPathFrom - > +export type BuildSelectorsApiEndpointMutation< + Definition extends MutationDefinition, + Definitions extends EndpointDefinitions, +> = { + select: MutationResultSelectorFactory< + Definition, + _RootState< + Definitions, + TagTypesFrom, + ReducerPathFrom > - } + > } type QueryResultSelectorFactory< diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index b461ace39d..740a11404a 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -1,17 +1,20 @@ -import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' +import type { + AsyncThunk, + AsyncThunkPayloadCreator, + Draft, + ThunkAction, + ThunkDispatch, + UnknownAction, +} from '@reduxjs/toolkit' +import type { Patch } from 'immer' +import { isDraftable, produceWithPatches } from 'immer' import type { Api, ApiContext } from '../apiTypes' import type { - BaseQueryFn, BaseQueryError, + BaseQueryFn, QueryReturnValue, } from '../baseQueryTypes' -import type { RootState, QueryKeys, QuerySubstateIdentifier } from './apiState' -import { QueryStatus } from './apiState' -import type { - StartQueryActionCreatorOptions, - QueryActionCreatorResult, -} from './buildInitiate' -import { forceQueryFnSymbol, isUpsertQuery } from './buildInitiate' +import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' import type { AssertTagTypes, EndpointDefinition, @@ -20,46 +23,35 @@ import type { QueryArgFrom, QueryDefinition, ResultTypeFrom, - FullTagDescription, } from '../endpointDefinitions' -import { isQueryDefinition } from '../endpointDefinitions' -import { calculateProvidedBy } from '../endpointDefinitions' +import { calculateProvidedBy, isQueryDefinition } from '../endpointDefinitions' +import { HandledError } from '../HandledError' +import type { UnwrapPromise } from '../tsHelpers' +import type { QueryKeys, QuerySubstateIdentifier, RootState } from './apiState' +import { QueryStatus } from './apiState' import type { - AsyncThunkPayloadCreator, - Draft, - UnknownAction, -} from '@reduxjs/toolkit' + QueryActionCreatorResult, + StartQueryActionCreatorOptions, +} from './buildInitiate' +import { forceQueryFnSymbol, isUpsertQuery } from './buildInitiate' +import type { ApiEndpointQuery, PrefetchOptions } from './module' import { + createAsyncThunk, isAllOf, isFulfilled, isPending, isRejected, isRejectedWithValue, - createAsyncThunk, SHOULD_AUTOBATCH, } from './rtkImports' -import type { Patch } from 'immer' -import { isDraftable, produceWithPatches } from 'immer' -import type { ThunkAction, ThunkDispatch, AsyncThunk } from '@reduxjs/toolkit' - -import { HandledError } from '../HandledError' -import type { ApiEndpointQuery, PrefetchOptions } from './module' -import type { UnwrapPromise } from '../tsHelpers' +export type BuildThunksApiEndpointQuery< + Definition extends QueryDefinition, +> = Matchers -declare module './module' { - export interface ApiEndpointQuery< - Definition extends QueryDefinition, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - Definitions extends EndpointDefinitions, - > extends Matchers {} - - export interface ApiEndpointMutation< - Definition extends MutationDefinition, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - Definitions extends EndpointDefinitions, - > extends Matchers {} -} +export type BuildThunksApiEndpointMutation< + Definition extends MutationDefinition, +> = Matchers type EndpointThunk< Thunk extends QueryThunk | MutationThunk, @@ -106,15 +98,14 @@ export interface Matchers< matchRejected: Matcher> } -export interface QueryThunkArg - extends QuerySubstateIdentifier, - StartQueryActionCreatorOptions { - type: 'query' - originalArgs: unknown - endpointName: string -} +export type QueryThunkArg = QuerySubstateIdentifier & + StartQueryActionCreatorOptions & { + type: 'query' + originalArgs: unknown + endpointName: string + } -export interface MutationThunkArg { +type MutationThunkArg = { type: 'mutation' originalArgs: unknown endpointName: string @@ -284,7 +275,7 @@ export function buildThunks< getState() as RootState, ) - let ret: PatchCollection = { + const ret: PatchCollection = { patches: [], inversePatches: [], undo: () => diff --git a/packages/toolkit/src/query/core/index.ts b/packages/toolkit/src/query/core/index.ts index f9765d9f08..a970f20d08 100644 --- a/packages/toolkit/src/query/core/index.ts +++ b/packages/toolkit/src/query/core/index.ts @@ -1,6 +1,50 @@ -import { buildCreateApi, CreateApi } from '../createApi' -import { coreModule, coreModuleName } from './module' +import { buildCreateApi } from '../createApi' +import { coreModule } from './module' -const createApi = /* @__PURE__ */ buildCreateApi(coreModule()) +export const createApi = /* @__PURE__ */ buildCreateApi(coreModule()) -export { createApi, coreModule, coreModuleName } +export { QueryStatus } from './apiState' +export type { + CombinedState, + MutationKeys, + QueryCacheKey, + QueryKeys, + QuerySubState, + RootState, + SubscriptionOptions, +} from './apiState' +export type { + MutationActionCreatorResult, + QueryActionCreatorResult, + StartQueryActionCreatorOptions, +} from './buildInitiate' +export type { + MutationCacheLifecycleApi, + MutationLifecycleApi, + QueryCacheLifecycleApi, + QueryLifecycleApi, + SubscriptionSelectors, +} from './buildMiddleware' +export { skipToken } from './buildSelectors' +export type { + MutationResultSelectorResult, + QueryResultSelectorResult, + SkipToken, +} from './buildSelectors' +export type { SliceActions } from './buildSlice' +export type { + PatchQueryDataThunk, + UpdateQueryDataThunk, + UpsertQueryDataThunk, +} from './buildThunks' +export { coreModuleName } from './module' +export type { + ApiEndpointMutation, + ApiEndpointQuery, + CoreModule, + InternalActions, + PrefetchOptions, + ThunkWithReturnValue, +} from './module' +export { setupListeners } from './setupListeners' +export { buildCreateApi, coreModule } diff --git a/packages/toolkit/src/query/core/module.ts b/packages/toolkit/src/query/core/module.ts index c237c7b298..6ed4d27cc3 100644 --- a/packages/toolkit/src/query/core/module.ts +++ b/packages/toolkit/src/query/core/module.ts @@ -1,12 +1,6 @@ /** * Note: this file should import all other files for type discovery and declaration merging */ -import type { - PatchQueryDataThunk, - UpdateQueryDataThunk, - UpsertQueryDataThunk, -} from './buildThunks' -import { buildThunks } from './buildThunks' import type { ActionCreatorWithPayload, Middleware, @@ -15,41 +9,56 @@ import type { ThunkDispatch, UnknownAction, } from '@reduxjs/toolkit' +import { enablePatches } from 'immer' +import type { Api, Module } from '../apiTypes' +import type { BaseQueryFn } from '../baseQueryTypes' +import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' import type { + AssertTagTypes, EndpointDefinitions, + MutationDefinition, QueryArgFrom, QueryDefinition, - MutationDefinition, - AssertTagTypes, TagDescription, } from '../endpointDefinitions' -import { isQueryDefinition, isMutationDefinition } from '../endpointDefinitions' +import { isMutationDefinition, isQueryDefinition } from '../endpointDefinitions' +import { assertCast, safeAssign } from '../tsHelpers' import type { CombinedState, - QueryKeys, MutationKeys, + QueryKeys, RootState, } from './apiState' -import type { Api, Module } from '../apiTypes' -import { onFocus, onFocusLost, onOnline, onOffline } from './setupListeners' -import { buildSlice } from './buildSlice' -import { buildMiddleware } from './buildMiddleware' -import { buildSelectors } from './buildSelectors' import type { + BuildInitiateApiEndpointMutation, + BuildInitiateApiEndpointQuery, MutationActionCreatorResult, QueryActionCreatorResult, } from './buildInitiate' import { buildInitiate } from './buildInitiate' -import { assertCast, safeAssign } from '../tsHelpers' -import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' +import type { + ReferenceCacheCollection, + ReferenceCacheLifecycle, + ReferenceQueryLifecycle, +} from './buildMiddleware' +import { buildMiddleware } from './buildMiddleware' +import type { + BuildSelectorsApiEndpointMutation, + BuildSelectorsApiEndpointQuery, +} from './buildSelectors' +import { buildSelectors } from './buildSelectors' import type { SliceActions } from './buildSlice' -import type { BaseQueryFn } from '../baseQueryTypes' - -import type { ReferenceCacheLifecycle } from './buildMiddleware/cacheLifecycle' -import type { ReferenceQueryLifecycle } from './buildMiddleware/queryLifecycle' -import type { ReferenceCacheCollection } from './buildMiddleware/cacheCollection' -import { enablePatches } from 'immer' +import { buildSlice } from './buildSlice' +import type { + BuildThunksApiEndpointMutation, + BuildThunksApiEndpointQuery, + PatchQueryDataThunk, + UpdateQueryDataThunk, + UpsertQueryDataThunk, +} from './buildThunks' +import { buildThunks } from './buildThunks' import { createSelector as _createSelector } from './rtkImports' +import { onFocus, onFocusLost, onOffline, onOnline } from './setupListeners' /** * `ifOlderThan` - (default: `false` | `number`) - _number is value in seconds_ @@ -72,318 +81,315 @@ export type CoreModule = | ReferenceQueryLifecycle | ReferenceCacheCollection -export interface ThunkWithReturnValue - extends ThunkAction {} +export type ThunkWithReturnValue = ThunkAction + +export interface ApiModules< + // eslint-disable-next-line @typescript-eslint/no-unused-vars + BaseQuery extends BaseQueryFn, + Definitions extends EndpointDefinitions, + ReducerPath extends string, + TagTypes extends string, +> { + [coreModuleName]: { + /** + * This api's reducer should be mounted at `store[api.reducerPath]`. + * + * @example + * ```ts + * configureStore({ + * reducer: { + * [api.reducerPath]: api.reducer, + * }, + * middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), + * }) + * ``` + */ + reducerPath: ReducerPath + /** + * Internal actions not part of the public API. Note: These are subject to change at any given time. + */ + internalActions: InternalActions + /** + * A standard redux reducer that enables core functionality. Make sure it's included in your store. + * + * @example + * ```ts + * configureStore({ + * reducer: { + * [api.reducerPath]: api.reducer, + * }, + * middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), + * }) + * ``` + */ + reducer: Reducer< + CombinedState, + UnknownAction + > + /** + * This is a standard redux middleware and is responsible for things like polling, garbage collection and a handful of other things. Make sure it's included in your store. + * + * @example + * ```ts + * configureStore({ + * reducer: { + * [api.reducerPath]: api.reducer, + * }, + * middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), + * }) + * ``` + */ + middleware: Middleware< + {}, + RootState, + ThunkDispatch + > + /** + * A collection of utility thunks for various situations. + */ + util: { + /** + * A thunk that (if dispatched) will return a specific running query, identified + * by `endpointName` and `args`. + * If that query is not running, dispatching the thunk will result in `undefined`. + * + * Can be used to await a specific query triggered in any way, + * including via hook calls or manually dispatching `initiate` actions. + * + * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. + */ + getRunningQueryThunk>( + endpointName: EndpointName, + args: QueryArgFrom, + ): ThunkWithReturnValue< + | QueryActionCreatorResult< + Definitions[EndpointName] & { type: 'query' } + > + | undefined + > + + /** + * A thunk that (if dispatched) will return a specific running mutation, identified + * by `endpointName` and `fixedCacheKey` or `requestId`. + * If that mutation is not running, dispatching the thunk will result in `undefined`. + * + * Can be used to await a specific mutation triggered in any way, + * including via hook trigger functions or manually dispatching `initiate` actions. + * + * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. + */ + getRunningMutationThunk>( + endpointName: EndpointName, + fixedCacheKeyOrRequestId: string, + ): ThunkWithReturnValue< + | MutationActionCreatorResult< + Definitions[EndpointName] & { type: 'mutation' } + > + | undefined + > + + /** + * A thunk that (if dispatched) will return all running queries. + * + * Useful for SSR scenarios to await all running queries triggered in any way, + * including via hook calls or manually dispatching `initiate` actions. + * + * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. + */ + getRunningQueriesThunk(): ThunkWithReturnValue< + Array> + > -declare module '../apiTypes' { - export interface ApiModules< - // eslint-disable-next-line @typescript-eslint/no-unused-vars - BaseQuery extends BaseQueryFn, - Definitions extends EndpointDefinitions, - ReducerPath extends string, - TagTypes extends string, - > { - [coreModuleName]: { /** - * This api's reducer should be mounted at `store[api.reducerPath]`. + * A thunk that (if dispatched) will return all running mutations. + * + * Useful for SSR scenarios to await all running mutations triggered in any way, + * including via hook calls or manually dispatching `initiate` actions. + * + * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. + */ + getRunningMutationsThunk(): ThunkWithReturnValue< + Array> + > + + /** + * A Redux thunk that can be used to manually trigger pre-fetching of data. + * + * The thunk accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and a set of options used to determine if the data actually should be re-fetched based on cache staleness. + * + * React Hooks users will most likely never need to use this directly, as the `usePrefetch` hook will dispatch this thunk internally as needed when you call the prefetching function supplied by the hook. * * @example - * ```ts - * configureStore({ - * reducer: { - * [api.reducerPath]: api.reducer, - * }, - * middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), - * }) + * + * ```ts no-transpile + * dispatch(api.util.prefetch('getPosts', undefined, { force: true })) * ``` */ - reducerPath: ReducerPath + prefetch>( + endpointName: EndpointName, + arg: QueryArgFrom, + options: PrefetchOptions, + ): ThunkAction /** - * Internal actions not part of the public API. Note: These are subject to change at any given time. + * A Redux thunk action creator that, when dispatched, creates and applies a set of JSON diff/patch objects to the current state. This immediately updates the Redux state with those changes. + * + * The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and an `updateRecipe` callback function. The callback receives an Immer-wrapped `draft` of the current state, and may modify the draft to match the expected results after the mutation completes successfully. + * + * The thunk executes _synchronously_, and returns an object containing `{patches: Patch[], inversePatches: Patch[], undo: () => void}`. The `patches` and `inversePatches` are generated using Immer's [`produceWithPatches` method](https://immerjs.github.io/immer/patches). + * + * This is typically used as the first step in implementing optimistic updates. The generated `inversePatches` can be used to revert the updates by calling `dispatch(patchQueryData(endpointName, args, inversePatches))`. Alternatively, the `undo` method can be called directly to achieve the same effect. + * + * Note that the first two arguments (`endpointName` and `args`) are used to determine which existing cache entry to update. If no existing cache entry is found, the `updateRecipe` callback will not run. + * + * @example + * + * ```ts + * const patchCollection = dispatch( + * api.util.updateQueryData('getPosts', undefined, (draftPosts) => { + * draftPosts.push({ id: 1, name: 'Teddy' }) + * }) + * ) + * ``` */ - internalActions: InternalActions + updateQueryData: UpdateQueryDataThunk< + Definitions, + RootState + > + /** - * A standard redux reducer that enables core functionality. Make sure it's included in your store. + * A Redux thunk action creator that, when dispatched, acts as an artificial API request to upsert a value into the cache. + * + * The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and the data to upsert. + * + * If no cache entry for that cache key exists, a cache entry will be created and the data added. If a cache entry already exists, this will _overwrite_ the existing cache entry data. + * + * The thunk executes _asynchronously_, and returns a promise that resolves when the store has been updated. + * + * If dispatched while an actual request is in progress, both the upsert and request will be handled as soon as they resolve, resulting in a "last result wins" update behavior. * * @example + * * ```ts - * configureStore({ - * reducer: { - * [api.reducerPath]: api.reducer, - * }, - * middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), - * }) + * await dispatch( + * api.util.upsertQueryData('getPost', {id: 1}, {id: 1, text: "Hello!"}) + * ) * ``` */ - reducer: Reducer< - CombinedState, - UnknownAction + upsertQueryData: UpsertQueryDataThunk< + Definitions, + RootState > /** - * This is a standard redux middleware and is responsible for things like polling, garbage collection and a handful of other things. Make sure it's included in your store. + * A Redux thunk that applies a JSON diff/patch array to the cached data for a given query result. This immediately updates the Redux state with those changes. + * + * The thunk accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and a JSON diff/patch array as produced by Immer's `produceWithPatches`. + * + * This is typically used as the second step in implementing optimistic updates. If a request fails, the optimistically-applied changes can be reverted by dispatching `patchQueryData` with the `inversePatches` that were generated by `updateQueryData` earlier. + * + * In cases where it is desired to simply revert the previous changes, it may be preferable to call the `undo` method returned from dispatching `updateQueryData` instead. * * @example * ```ts - * configureStore({ - * reducer: { - * [api.reducerPath]: api.reducer, - * }, - * middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), - * }) + * const patchCollection = dispatch( + * api.util.updateQueryData('getPosts', undefined, (draftPosts) => { + * draftPosts.push({ id: 1, name: 'Teddy' }) + * }) + * ) + * + * // later + * dispatch( + * api.util.patchQueryData('getPosts', undefined, patchCollection.inversePatches) + * ) + * + * // or + * patchCollection.undo() * ``` */ - middleware: Middleware< - {}, - RootState, - ThunkDispatch + patchQueryData: PatchQueryDataThunk< + Definitions, + RootState > + /** - * A collection of utility thunks for various situations. + * A Redux action creator that can be dispatched to manually reset the api state completely. This will immediately remove all existing cache entries, and all queries will be considered 'uninitialized'. + * + * @example + * + * ```ts + * dispatch(api.util.resetApiState()) + * ``` */ - util: { - /** - * A thunk that (if dispatched) will return a specific running query, identified - * by `endpointName` and `args`. - * If that query is not running, dispatching the thunk will result in `undefined`. - * - * Can be used to await a specific query triggered in any way, - * including via hook calls or manually dispatching `initiate` actions. - * - * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. - */ - getRunningQueryThunk>( - endpointName: EndpointName, - args: QueryArgFrom, - ): ThunkWithReturnValue< - | QueryActionCreatorResult< - Definitions[EndpointName] & { type: 'query' } - > - | undefined - > - - /** - * A thunk that (if dispatched) will return a specific running mutation, identified - * by `endpointName` and `fixedCacheKey` or `requestId`. - * If that mutation is not running, dispatching the thunk will result in `undefined`. - * - * Can be used to await a specific mutation triggered in any way, - * including via hook trigger functions or manually dispatching `initiate` actions. - * - * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. - */ - getRunningMutationThunk>( - endpointName: EndpointName, - fixedCacheKeyOrRequestId: string, - ): ThunkWithReturnValue< - | MutationActionCreatorResult< - Definitions[EndpointName] & { type: 'mutation' } - > - | undefined - > - - /** - * A thunk that (if dispatched) will return all running queries. - * - * Useful for SSR scenarios to await all running queries triggered in any way, - * including via hook calls or manually dispatching `initiate` actions. - * - * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. - */ - getRunningQueriesThunk(): ThunkWithReturnValue< - Array> - > - - /** - * A thunk that (if dispatched) will return all running mutations. - * - * Useful for SSR scenarios to await all running mutations triggered in any way, - * including via hook calls or manually dispatching `initiate` actions. - * - * See https://redux-toolkit.js.org/rtk-query/usage/server-side-rendering for details. - */ - getRunningMutationsThunk(): ThunkWithReturnValue< - Array> - > - - /** - * A Redux thunk that can be used to manually trigger pre-fetching of data. - * - * The thunk accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and a set of options used to determine if the data actually should be re-fetched based on cache staleness. - * - * React Hooks users will most likely never need to use this directly, as the `usePrefetch` hook will dispatch this thunk internally as needed when you call the prefetching function supplied by the hook. - * - * @example - * - * ```ts no-transpile - * dispatch(api.util.prefetch('getPosts', undefined, { force: true })) - * ``` - */ - prefetch>( - endpointName: EndpointName, - arg: QueryArgFrom, - options: PrefetchOptions, - ): ThunkAction - /** - * A Redux thunk action creator that, when dispatched, creates and applies a set of JSON diff/patch objects to the current state. This immediately updates the Redux state with those changes. - * - * The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and an `updateRecipe` callback function. The callback receives an Immer-wrapped `draft` of the current state, and may modify the draft to match the expected results after the mutation completes successfully. - * - * The thunk executes _synchronously_, and returns an object containing `{patches: Patch[], inversePatches: Patch[], undo: () => void}`. The `patches` and `inversePatches` are generated using Immer's [`produceWithPatches` method](https://immerjs.github.io/immer/patches). - * - * This is typically used as the first step in implementing optimistic updates. The generated `inversePatches` can be used to revert the updates by calling `dispatch(patchQueryData(endpointName, args, inversePatches))`. Alternatively, the `undo` method can be called directly to achieve the same effect. - * - * Note that the first two arguments (`endpointName` and `args`) are used to determine which existing cache entry to update. If no existing cache entry is found, the `updateRecipe` callback will not run. - * - * @example - * - * ```ts - * const patchCollection = dispatch( - * api.util.updateQueryData('getPosts', undefined, (draftPosts) => { - * draftPosts.push({ id: 1, name: 'Teddy' }) - * }) - * ) - * ``` - */ - updateQueryData: UpdateQueryDataThunk< - Definitions, - RootState - > - - /** - * A Redux thunk action creator that, when dispatched, acts as an artificial API request to upsert a value into the cache. - * - * The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and the data to upsert. - * - * If no cache entry for that cache key exists, a cache entry will be created and the data added. If a cache entry already exists, this will _overwrite_ the existing cache entry data. - * - * The thunk executes _asynchronously_, and returns a promise that resolves when the store has been updated. - * - * If dispatched while an actual request is in progress, both the upsert and request will be handled as soon as they resolve, resulting in a "last result wins" update behavior. - * - * @example - * - * ```ts - * await dispatch( - * api.util.upsertQueryData('getPost', {id: 1}, {id: 1, text: "Hello!"}) - * ) - * ``` - */ - upsertQueryData: UpsertQueryDataThunk< - Definitions, - RootState - > - /** - * A Redux thunk that applies a JSON diff/patch array to the cached data for a given query result. This immediately updates the Redux state with those changes. - * - * The thunk accepts three arguments: the name of the endpoint we are updating (such as `'getPost'`), the appropriate query arg values to construct the desired cache key, and a JSON diff/patch array as produced by Immer's `produceWithPatches`. - * - * This is typically used as the second step in implementing optimistic updates. If a request fails, the optimistically-applied changes can be reverted by dispatching `patchQueryData` with the `inversePatches` that were generated by `updateQueryData` earlier. - * - * In cases where it is desired to simply revert the previous changes, it may be preferable to call the `undo` method returned from dispatching `updateQueryData` instead. - * - * @example - * ```ts - * const patchCollection = dispatch( - * api.util.updateQueryData('getPosts', undefined, (draftPosts) => { - * draftPosts.push({ id: 1, name: 'Teddy' }) - * }) - * ) - * - * // later - * dispatch( - * api.util.patchQueryData('getPosts', undefined, patchCollection.inversePatches) - * ) - * - * // or - * patchCollection.undo() - * ``` - */ - patchQueryData: PatchQueryDataThunk< - Definitions, - RootState - > - - /** - * A Redux action creator that can be dispatched to manually reset the api state completely. This will immediately remove all existing cache entries, and all queries will be considered 'uninitialized'. - * - * @example - * - * ```ts - * dispatch(api.util.resetApiState()) - * ``` - */ - resetApiState: SliceActions['resetApiState'] - /** - * A Redux action creator that can be used to manually invalidate cache tags for [automated re-fetching](../../usage/automated-refetching.mdx). - * - * The action creator accepts one argument: the cache tags to be invalidated. It returns an action with those tags as a payload, and the corresponding `invalidateTags` action type for the api. - * - * Dispatching the result of this action creator will [invalidate](../../usage/automated-refetching.mdx#invalidating-cache-data) the given tags, causing queries to automatically re-fetch if they are subscribed to cache data that [provides](../../usage/automated-refetching.mdx#providing-cache-data) the corresponding tags. - * - * The array of tags provided to the action creator should be in one of the following formats, where `TagType` is equal to a string provided to the [`tagTypes`](../createApi.mdx#tagtypes) property of the api: - * - * - `[TagType]` - * - `[{ type: TagType }]` - * - `[{ type: TagType, id: number | string }]` - * - * @example - * - * ```ts - * dispatch(api.util.invalidateTags(['Post'])) - * dispatch(api.util.invalidateTags([{ type: 'Post', id: 1 }])) - * dispatch( - * api.util.invalidateTags([ - * { type: 'Post', id: 1 }, - * { type: 'Post', id: 'LIST' }, - * ]) - * ) - * ``` - */ - invalidateTags: ActionCreatorWithPayload< - Array>, - string - > + resetApiState: SliceActions['resetApiState'] + /** + * A Redux action creator that can be used to manually invalidate cache tags for [automated re-fetching](../../usage/automated-refetching.mdx). + * + * The action creator accepts one argument: the cache tags to be invalidated. It returns an action with those tags as a payload, and the corresponding `invalidateTags` action type for the api. + * + * Dispatching the result of this action creator will [invalidate](../../usage/automated-refetching.mdx#invalidating-cache-data) the given tags, causing queries to automatically re-fetch if they are subscribed to cache data that [provides](../../usage/automated-refetching.mdx#providing-cache-data) the corresponding tags. + * + * The array of tags provided to the action creator should be in one of the following formats, where `TagType` is equal to a string provided to the [`tagTypes`](../createApi.mdx#tagtypes) property of the api: + * + * - `[TagType]` + * - `[{ type: TagType }]` + * - `[{ type: TagType, id: number | string }]` + * + * @example + * + * ```ts + * dispatch(api.util.invalidateTags(['Post'])) + * dispatch(api.util.invalidateTags([{ type: 'Post', id: 1 }])) + * dispatch( + * api.util.invalidateTags([ + * { type: 'Post', id: 1 }, + * { type: 'Post', id: 'LIST' }, + * ]) + * ) + * ``` + */ + invalidateTags: ActionCreatorWithPayload< + Array>, + string + > - /** - * A function to select all `{ endpointName, originalArgs, queryCacheKey }` combinations that would be invalidated by a specific set of tags. - * - * Can be used for mutations that want to do optimistic updates instead of invalidating a set of tags, but don't know exactly what they need to update. - */ - selectInvalidatedBy: ( - state: RootState, - tags: ReadonlyArray>, - ) => Array<{ - endpointName: string - originalArgs: any - queryCacheKey: string - }> + /** + * A function to select all `{ endpointName, originalArgs, queryCacheKey }` combinations that would be invalidated by a specific set of tags. + * + * Can be used for mutations that want to do optimistic updates instead of invalidating a set of tags, but don't know exactly what they need to update. + */ + selectInvalidatedBy: ( + state: RootState, + tags: ReadonlyArray>, + ) => Array<{ + endpointName: string + originalArgs: any + queryCacheKey: string + }> - /** - * A function to select all arguments currently cached for a given endpoint. - * - * Can be used for mutations that want to do optimistic updates instead of invalidating a set of tags, but don't know exactly what they need to update. - */ - selectCachedArgsForQuery: >( - state: RootState, - queryName: QueryName, - ) => Array> - } /** - * Endpoints based on the input endpoints provided to `createApi`, containing `select` and `action matchers`. + * A function to select all arguments currently cached for a given endpoint. + * + * Can be used for mutations that want to do optimistic updates instead of invalidating a set of tags, but don't know exactly what they need to update. */ - endpoints: { - [K in keyof Definitions]: Definitions[K] extends QueryDefinition< - any, - any, - any, - any, - any - > - ? ApiEndpointQuery - : Definitions[K] extends MutationDefinition - ? ApiEndpointMutation - : never - } + selectCachedArgsForQuery: >( + state: RootState, + queryName: QueryName, + ) => Array> + } + /** + * Endpoints based on the input endpoints provided to `createApi`, containing `select` and `action matchers`. + */ + endpoints: { + [K in keyof Definitions]: Definitions[K] extends QueryDefinition< + any, + any, + any, + any, + any + > + ? ApiEndpointQuery + : Definitions[K] extends MutationDefinition + ? ApiEndpointMutation + : never } } } @@ -393,7 +399,9 @@ export interface ApiEndpointQuery< Definition extends QueryDefinition, // eslint-disable-next-line @typescript-eslint/no-unused-vars Definitions extends EndpointDefinitions, -> { +> extends BuildThunksApiEndpointQuery, + BuildInitiateApiEndpointQuery, + BuildSelectorsApiEndpointQuery { name: string /** * All of these are `undefined` at runtime, purely to be used in TypeScript declarations! @@ -407,7 +415,9 @@ export interface ApiEndpointMutation< Definition extends MutationDefinition, // eslint-disable-next-line @typescript-eslint/no-unused-vars Definitions extends EndpointDefinitions, -> { +> extends BuildThunksApiEndpointMutation, + BuildInitiateApiEndpointMutation, + BuildSelectorsApiEndpointMutation { name: string /** * All of these are `undefined` at runtime, purely to be used in TypeScript declarations! diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index d0338e25bf..a229d048f2 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -1,34 +1,43 @@ -import type { SerializeQueryArgs } from './defaultSerializeQueryArgs' -import type { QuerySubState, RootState } from './core/apiState' +import type { Api } from '@reduxjs/toolkit/query' import type { + BaseQueryApi, + BaseQueryArg, + BaseQueryError, BaseQueryExtraOptions, BaseQueryFn, + BaseQueryMeta, BaseQueryResult, - BaseQueryArg, - BaseQueryApi, QueryReturnValue, - BaseQueryError, - BaseQueryMeta, } from './baseQueryTypes' +import type { QuerySubState, RootState } from './core' +import type { CacheCollectionQueryExtraOptions } from './core/buildMiddleware/cacheCollection' +import type { + CacheLifecycleMutationExtraOptions, + CacheLifecycleQueryExtraOptions, +} from './core/buildMiddleware/cacheLifecycle' +import type { + QueryLifecycleMutationExtraOptions, + QueryLifecycleQueryExtraOptions, +} from './core/buildMiddleware/queryLifecycle' +import type { SerializeQueryArgs } from './defaultSerializeQueryArgs' +import type { NEVER } from './fakeBaseQuery' import type { + CastAny, HasRequiredProps, MaybePromise, - OmitFromUnion, - CastAny, NonUndefined, + OmitFromUnion, UnwrapPromise, } from './tsHelpers' -import type { NEVER } from './fakeBaseQuery' -import type { Api } from '@reduxjs/toolkit/query' const resultType = /* @__PURE__ */ Symbol() const baseQuery = /* @__PURE__ */ Symbol() -interface EndpointDefinitionWithQuery< +type EndpointDefinitionWithQuery< QueryArg, BaseQuery extends BaseQueryFn, ResultType, -> { +> = { /** * `query` can be a function that returns either a `string` or an `object` which is passed to your `baseQuery`. If you are using [fetchBaseQuery](./fetchBaseQuery), this can return either a `string` or an `object` of properties in `FetchArgs`. If you use your own custom [`baseQuery`](../../rtk-query/usage/customizing-queries), you can customize this behavior to your liking. * @@ -100,11 +109,11 @@ interface EndpointDefinitionWithQuery< structuralSharing?: boolean } -interface EndpointDefinitionWithQueryFn< +type EndpointDefinitionWithQueryFn< QueryArg, BaseQuery extends BaseQueryFn, ResultType, -> { +> = { /** * Can be used in place of `query` as an inline function that bypasses `baseQuery` completely for the endpoint. * @@ -173,11 +182,7 @@ interface EndpointDefinitionWithQueryFn< structuralSharing?: boolean } -export interface BaseEndpointTypes< - QueryArg, - BaseQuery extends BaseQueryFn, - ResultType, -> { +type BaseEndpointTypes = { QueryArg: QueryArg BaseQuery: BaseQuery ResultType: ResultType @@ -236,13 +241,13 @@ export type ResultDescription< | ReadonlyArray> | GetResultDescriptionFn -export interface QueryTypes< +type QueryTypes< QueryArg, BaseQuery extends BaseQueryFn, TagTypes extends string, ResultType, ReducerPath extends string = string, -> extends BaseEndpointTypes { +> = BaseEndpointTypes & { /** * The endpoint definition type. To be used with some internal generic types. * @example @@ -267,8 +272,21 @@ export interface QueryExtraOptions< QueryArg, BaseQuery extends BaseQueryFn, ReducerPath extends string = string, -> { +> extends CacheLifecycleQueryExtraOptions< + ResultType, + QueryArg, + BaseQuery, + ReducerPath + >, + QueryLifecycleQueryExtraOptions< + ResultType, + QueryArg, + BaseQuery, + ReducerPath + >, + CacheCollectionQueryExtraOptions { type: DefinitionType.query + /** * Used by `query` endpoints. Determines which 'tag' is attached to the cached data returned by the query. * Expects an array of tag type strings, an array of objects of tag types with ids, or a function that returns such an array. @@ -510,13 +528,13 @@ export type QueryDefinition< > = BaseEndpointDefinition & QueryExtraOptions -export interface MutationTypes< +type MutationTypes< QueryArg, BaseQuery extends BaseQueryFn, TagTypes extends string, ResultType, ReducerPath extends string = string, -> extends BaseEndpointTypes { +> = BaseEndpointTypes & { /** * The endpoint definition type. To be used with some internal generic types. * @example @@ -541,8 +559,20 @@ export interface MutationExtraOptions< QueryArg, BaseQuery extends BaseQueryFn, ReducerPath extends string = string, -> { +> extends CacheLifecycleMutationExtraOptions< + ResultType, + QueryArg, + BaseQuery, + ReducerPath + >, + QueryLifecycleMutationExtraOptions< + ResultType, + QueryArg, + BaseQuery, + ReducerPath + > { type: DefinitionType.mutation + /** * Used by `mutation` endpoints. Determines which cached data should be either re-fetched or removed from the cache. * Expects the same shapes as `providesTags`. diff --git a/packages/toolkit/src/query/fakeBaseQuery.ts b/packages/toolkit/src/query/fakeBaseQuery.ts index 4e1c4f2270..5e26b3e154 100644 --- a/packages/toolkit/src/query/fakeBaseQuery.ts +++ b/packages/toolkit/src/query/fakeBaseQuery.ts @@ -1,6 +1,6 @@ import type { BaseQueryFn } from './baseQueryTypes' -const _NEVER = /* @__PURE__ */ Symbol() +export const _NEVER = /* @__PURE__ */ Symbol() export type NEVER = typeof _NEVER /** diff --git a/packages/toolkit/src/query/index.ts b/packages/toolkit/src/query/index.ts index ee36153a86..1a985256ab 100644 --- a/packages/toolkit/src/query/index.ts +++ b/packages/toolkit/src/query/index.ts @@ -11,7 +11,7 @@ export type { SubscriptionOptions, } from './core/apiState' export { QueryStatus } from './core/apiState' -export type { Api, ApiContext, ApiModules, Module } from './apiTypes' +export type { Api, ApiContext, Module } from './apiTypes' export type { BaseQueryApi, @@ -19,6 +19,7 @@ export type { BaseQueryFn, } from './baseQueryTypes' export type { + BaseEndpointDefinition, EndpointDefinitions, EndpointDefinition, EndpointBuilder, @@ -50,15 +51,17 @@ export type { export type { QueryActionCreatorResult, MutationActionCreatorResult, + StartQueryActionCreatorOptions, } from './core/buildInitiate' export type { CreateApi, CreateApiOptions } from './createApi' export { buildCreateApi } from './createApi' -export { fakeBaseQuery } from './fakeBaseQuery' +export { _NEVER, fakeBaseQuery } from './fakeBaseQuery' export { copyWithStructuralSharing } from './utils/copyWithStructuralSharing' export { createApi, coreModule, coreModuleName } from './core' export type { ApiEndpointMutation, ApiEndpointQuery, + ApiModules, CoreModule, PrefetchOptions, } from './core/module' diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index 06b7596385..aee59a3d9e 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -9,6 +9,7 @@ import type { ApiContext, ApiEndpointMutation, ApiEndpointQuery, + BaseQueryFn, CoreModule, EndpointDefinitions, MutationActionCreatorResult, @@ -41,10 +42,8 @@ import { useRef, useState, } from 'react' - import { shallowEqual } from 'react-redux' -import type { BaseQueryFn } from '../baseQueryTypes' -import type { SubscriptionSelectors } from '../core/buildMiddleware/types' +import type { SubscriptionSelectors } from '../core' import { defaultSerializeQueryArgs } from '../defaultSerializeQueryArgs' import type { UninitializedValue } from './constants' import { UNINITIALIZED_VALUE } from './constants' @@ -75,9 +74,9 @@ const getUseIsomorphicLayoutEffect = () => export const useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect() -export interface QueryHooks< +export type QueryHooks< Definition extends QueryDefinition, -> { +> = { useQuery: UseQuery useLazyQuery: UseLazyQuery useQuerySubscription: UseQuerySubscription @@ -85,9 +84,9 @@ export interface QueryHooks< useQueryState: UseQueryState } -export interface MutationHooks< +export type MutationHooks< Definition extends MutationDefinition, -> { +> = { useMutation: UseMutation } @@ -138,7 +137,7 @@ export type TypedUseQueryHookResult< > = TypedUseQueryStateResult & TypedUseQuerySubscriptionResult -interface UseQuerySubscriptionOptions extends SubscriptionOptions { +type UseQuerySubscriptionOptions = SubscriptionOptions & { /** * Prevents a query from automatically running. * diff --git a/packages/toolkit/src/query/react/index.ts b/packages/toolkit/src/query/react/index.ts index c979fbe0f2..9708412874 100644 --- a/packages/toolkit/src/query/react/index.ts +++ b/packages/toolkit/src/query/react/index.ts @@ -27,4 +27,5 @@ export type { TypedUseQuerySubscription, TypedUseLazyQuerySubscription, } from './buildHooks' +export { UNINITIALIZED_VALUE } from './constants' export { createApi, reactHooksModule, reactHooksModuleName } diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index b8ba31aafa..0f0816b451 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -4,17 +4,11 @@ import type { EndpointDefinitions, Module, MutationDefinition, + PrefetchOptions, QueryArgFrom, QueryDefinition, + QueryKeys, } from '@reduxjs/toolkit/query' -import { isMutationDefinition, isQueryDefinition } from '../endpointDefinitions' -import { safeAssign } from '../tsHelpers' -import { capitalize } from '../utils' -import type { MutationHooks, QueryHooks } from './buildHooks' -import { buildHooks } from './buildHooks' - -import type { HooksWithUniqueNames } from './namedHooks' - import { batch as rrBatch, useDispatch as rrUseDispatch, @@ -22,9 +16,12 @@ import { useStore as rrUseStore, } from 'react-redux' import { createSelector as _createSelector } from 'reselect' -import type { QueryKeys } from '../core/apiState' -import type { PrefetchOptions } from '../core/module' -import { countObjectKeys } from '../utils/countObjectKeys' +import { isMutationDefinition, isQueryDefinition } from '../endpointDefinitions' +import { safeAssign } from '../tsHelpers' +import { capitalize, countObjectKeys } from '../utils' +import type { MutationHooks, QueryHooks } from './buildHooks' +import { buildHooks } from './buildHooks' +import type { HooksWithUniqueNames } from './namedHooks' export const reactHooksModuleName = /* @__PURE__ */ Symbol() export type ReactHooksModule = typeof reactHooksModuleName diff --git a/packages/toolkit/src/query/utils/index.ts b/packages/toolkit/src/query/utils/index.ts index 46694a2c3f..0eb7c62ce9 100644 --- a/packages/toolkit/src/query/utils/index.ts +++ b/packages/toolkit/src/query/utils/index.ts @@ -1,8 +1,10 @@ +export * from './capitalize' +export * from './copyWithStructuralSharing' +export * from './countObjectKeys' +export * from './flatten' export * from './isAbsoluteUrl' +export * from './isDocumentVisible' +export * from './isNotNullish' +export * from './isOnline' export * from './isValidUrl' export * from './joinUrls' -export * from './flatten' -export * from './capitalize' -export * from './isOnline' -export * from './isDocumentVisible' -export * from './copyWithStructuralSharing' diff --git a/packages/toolkit/src/react/index.ts b/packages/toolkit/src/react/index.ts index 739f7ba477..85e8c6ada4 100644 --- a/packages/toolkit/src/react/index.ts +++ b/packages/toolkit/src/react/index.ts @@ -4,3 +4,4 @@ import { formatProdErrorMessage } from '@reduxjs/toolkit' export * from '@reduxjs/toolkit' export { createDynamicMiddleware } from '../dynamicMiddleware/react' +export type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index' diff --git a/packages/toolkit/src/serializableStateInvariantMiddleware.ts b/packages/toolkit/src/serializableStateInvariantMiddleware.ts index a4dba23562..2d50d59943 100644 --- a/packages/toolkit/src/serializableStateInvariantMiddleware.ts +++ b/packages/toolkit/src/serializableStateInvariantMiddleware.ts @@ -28,7 +28,7 @@ interface NonSerializableValue { value: unknown } -type IgnorePaths = readonly (string | RegExp)[] +export type IgnorePaths = readonly (string | RegExp)[] /** * @public diff --git a/packages/toolkit/src/tsHelpers.ts b/packages/toolkit/src/tsHelpers.ts index 45c90aeaef..ad5222b7b6 100644 --- a/packages/toolkit/src/tsHelpers.ts +++ b/packages/toolkit/src/tsHelpers.ts @@ -169,8 +169,6 @@ export type NoInfer = [T][T extends any ? 0 : never] export type NonUndefined = T extends undefined ? never : T -export type Omit = Pick> - export type WithRequiredProp = Omit & Required> diff --git a/packages/toolkit/tsup.config.ts b/packages/toolkit/tsup.config.ts index d9f34cfc1f..131ff36ba0 100644 --- a/packages/toolkit/tsup.config.ts +++ b/packages/toolkit/tsup.config.ts @@ -187,6 +187,7 @@ export default defineConfig((options) => { const generateTypedefs = name === 'modern' && format === 'esm' return { + name: `${prefix}-${name}`, entry: { [outputFilename]: entryPoint, }, @@ -246,9 +247,60 @@ export default defineConfig((options) => { } }) - return artifactOptions + return artifactOptions satisfies TsupOptions[] }) .flat() + .concat([ + { + name: 'Redux-Toolkit-Type-Definitions', + format: ['cjs'], + tsconfig, + entry: { index: './src/index.ts' }, + external: [/uncheckedindexed/], + dts: { + only: true, + }, + }, + { + name: 'RTK-React-Type-Definitions', + format: ['cjs'], + tsconfig, + entry: { 'react/index': './src/react/index.ts' }, + external: ['@reduxjs/toolkit', /uncheckedindexed/], + dts: { + only: true, + }, + }, + { + name: 'RTK-Query-Type-Definitions', + format: ['cjs'], + tsconfig, + entry: { 'query/index': './src/query/index.ts' }, + external: [ + '@reduxjs/toolkit', + '@reduxjs/toolkit/react', + /uncheckedindexed/, + ], + dts: { + only: true, + }, + }, + { + name: 'RTK-Query-React-Type-Definitions', + format: ['cjs'], + tsconfig, + entry: { 'query/react/index': './src/query/react/index.ts' }, + external: [ + '@reduxjs/toolkit', + '@reduxjs/toolkit/react', + '@reduxjs/toolkit/query', + /uncheckedindexed/, + ], + dts: { + only: true, + }, + }, + ]) return configs }) diff --git a/yarn.lock b/yarn.lock index e50364111f..7c15c8ef0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5002,186 +5002,485 @@ __metadata: languageName: node linkType: hard -"@esbuild-kit/cjs-loader@npm:^2.4.1": - version: 2.4.1 - resolution: "@esbuild-kit/cjs-loader@npm:2.4.1" - dependencies: - "@esbuild-kit/core-utils": "npm:^3.0.0" - get-tsconfig: "npm:^4.2.0" - checksum: 10/a516065907be0ead76ac2199ccb08ff92659ba5e2edb4bb8772b6a63afe4faed7eb45a3b4d87266a68c7c135c3dba971cd087bc6f16c382356e835c7dd3440f5 +"@esbuild/aix-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/aix-ppc64@npm:0.21.5" + conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild-kit/core-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "@esbuild-kit/core-utils@npm:3.0.0" - dependencies: - esbuild: "npm:~0.15.10" - source-map-support: "npm:^0.5.21" - checksum: 10/3964d43576343e3fe01572929993f305da18a658777ec0b03b524cdf06bc218330a5968d4de0eec69a4f2df152cb9097642884b21ecac608823c6c7e640472b7 +"@esbuild/aix-ppc64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/aix-ppc64@npm:0.23.0" + conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild-kit/esm-loader@npm:^2.5.4": - version: 2.5.4 - resolution: "@esbuild-kit/esm-loader@npm:2.5.4" - dependencies: - "@esbuild-kit/core-utils": "npm:^3.0.0" - get-tsconfig: "npm:^4.2.0" - checksum: 10/8f4b4b6470f7afeb58ddc15ddcc4e35a6d25910133f2b21a82a793918c6f8e28768d5cd77b1c90a003f2f1c83cb476b68354580a4e04e83e2da3312afe5b5895 +"@esbuild/android-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-arm64@npm:0.17.19" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/android-arm64@npm:0.19.7" +"@esbuild/android-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm64@npm:0.21.5" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/android-arm@npm:0.19.7" +"@esbuild/android-arm64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/android-arm64@npm:0.23.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-arm@npm:0.17.19" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/android-x64@npm:0.19.7" +"@esbuild/android-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm@npm:0.21.5" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/android-arm@npm:0.23.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-x64@npm:0.17.19" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-x64@npm:0.21.5" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/darwin-arm64@npm:0.19.7" +"@esbuild/android-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/android-x64@npm:0.23.0" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/darwin-arm64@npm:0.17.19" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-arm64@npm:0.21.5" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/darwin-arm64@npm:0.23.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/darwin-x64@npm:0.19.7" +"@esbuild/darwin-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/darwin-x64@npm:0.17.19" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-x64@npm:0.21.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/freebsd-arm64@npm:0.19.7" +"@esbuild/darwin-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/darwin-x64@npm:0.23.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/freebsd-arm64@npm:0.17.19" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-arm64@npm:0.21.5" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/freebsd-x64@npm:0.19.7" +"@esbuild/freebsd-arm64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/freebsd-arm64@npm:0.23.0" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/freebsd-x64@npm:0.17.19" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-x64@npm:0.21.5" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-arm64@npm:0.19.7" +"@esbuild/freebsd-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/freebsd-x64@npm:0.23.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-arm64@npm:0.17.19" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm64@npm:0.21.5" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-arm@npm:0.19.7" +"@esbuild/linux-arm64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-arm64@npm:0.23.0" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-arm@npm:0.17.19" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm@npm:0.21.5" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-arm@npm:0.23.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-ia32@npm:0.19.7" +"@esbuild/linux-ia32@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-ia32@npm:0.17.19" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ia32@npm:0.21.5" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-ia32@npm:0.23.0" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-loong64@npm:0.19.7" +"@esbuild/linux-loong64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-loong64@npm:0.17.19" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-loong64@npm:0.21.5" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-mips64el@npm:0.19.7" +"@esbuild/linux-loong64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-loong64@npm:0.23.0" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-mips64el@npm:0.17.19" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-mips64el@npm:0.21.5" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-mips64el@npm:0.23.0" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-ppc64@npm:0.19.7" +"@esbuild/linux-ppc64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-ppc64@npm:0.17.19" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-riscv64@npm:0.19.7" +"@esbuild/linux-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ppc64@npm:0.21.5" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-ppc64@npm:0.23.0" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-riscv64@npm:0.17.19" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-s390x@npm:0.19.7" +"@esbuild/linux-riscv64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-riscv64@npm:0.21.5" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-riscv64@npm:0.23.0" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-s390x@npm:0.17.19" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-s390x@npm:0.21.5" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-s390x@npm:0.23.0" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/linux-x64@npm:0.19.7" +"@esbuild/linux-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-x64@npm:0.17.19" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-x64@npm:0.21.5" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/linux-x64@npm:0.23.0" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/netbsd-x64@npm:0.19.7" +"@esbuild/netbsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/netbsd-x64@npm:0.17.19" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/openbsd-x64@npm:0.19.7" +"@esbuild/netbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/netbsd-x64@npm:0.21.5" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/netbsd-x64@npm:0.23.0" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/openbsd-arm64@npm:0.23.0" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/openbsd-x64@npm:0.17.19" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/openbsd-x64@npm:0.21.5" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/openbsd-x64@npm:0.23.0" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/sunos-x64@npm:0.19.7" +"@esbuild/sunos-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/sunos-x64@npm:0.17.19" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/sunos-x64@npm:0.21.5" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/sunos-x64@npm:0.23.0" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/win32-arm64@npm:0.19.7" +"@esbuild/win32-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-arm64@npm:0.17.19" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-arm64@npm:0.21.5" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/win32-arm64@npm:0.23.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/win32-ia32@npm:0.19.7" +"@esbuild/win32-ia32@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-ia32@npm:0.17.19" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-ia32@npm:0.21.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.19.7": - version: 0.19.7 - resolution: "@esbuild/win32-x64@npm:0.19.7" +"@esbuild/win32-ia32@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/win32-ia32@npm:0.23.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-x64@npm:0.17.19" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-x64@npm:0.21.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.23.0": + version: 0.23.0 + resolution: "@esbuild/win32-x64@npm:0.23.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -5655,6 +5954,57 @@ __metadata: languageName: unknown linkType: soft +"@examples-type-portability/bundler@workspace:examples/type-portability/bundler": + version: 0.0.0-use.local + resolution: "@examples-type-portability/bundler@workspace:examples/type-portability/bundler" + dependencies: + "@reduxjs/toolkit": "workspace:^" + "@types/node": "npm:^20.14.11" + "@types/react": "npm:^18.3.3" + "@types/react-dom": "npm:^18.3.0" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + react-redux: "npm:^9.1.2" + react-router-dom: "npm:^6.25.1" + react-scripts: "npm:5.0.1" + typescript: "npm:^5.5.4" + languageName: unknown + linkType: soft + +"@examples-type-portability/nodenext-cjs@workspace:examples/type-portability/nodenext-cjs": + version: 0.0.0-use.local + resolution: "@examples-type-portability/nodenext-cjs@workspace:examples/type-portability/nodenext-cjs" + dependencies: + "@reduxjs/toolkit": "workspace:^" + "@types/node": "npm:^20.14.11" + "@types/react": "npm:^18.3.3" + "@types/react-dom": "npm:^18.3.0" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + react-redux: "npm:^9.1.2" + react-router-dom: "npm:^6.25.1" + react-scripts: "npm:5.0.1" + typescript: "npm:^5.5.4" + languageName: unknown + linkType: soft + +"@examples-type-portability/nodenext-esm@workspace:examples/type-portability/nodenext-esm": + version: 0.0.0-use.local + resolution: "@examples-type-portability/nodenext-esm@workspace:examples/type-portability/nodenext-esm" + dependencies: + "@reduxjs/toolkit": "workspace:^" + "@types/node": "npm:^20.14.11" + "@types/react": "npm:^18.3.3" + "@types/react-dom": "npm:^18.3.0" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + react-redux: "npm:^9.1.2" + react-router-dom: "npm:^6.25.1" + react-scripts: "npm:5.0.1" + typescript: "npm:^5.5.4" + languageName: unknown + linkType: soft + "@exodus/schemasafe@npm:^1.0.0-rc.2": version: 1.0.0-rc.6 resolution: "@exodus/schemasafe@npm:1.0.0-rc.6" @@ -6657,18 +7007,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": - version: 0.3.2 - resolution: "@jridgewell/gen-mapping@npm:0.3.2" - dependencies: - "@jridgewell/set-array": "npm:^1.0.1" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 10/7ba0070be1aeda7d7694b09d847c3b95879409b26559b9d7e97a88ec94b838fb380df43ae328ee2d2df4d79e75d7afe6ba315199d18d79aa20839ebdfb739420 - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.5": +"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": version: 0.3.5 resolution: "@jridgewell/gen-mapping@npm:0.3.5" dependencies: @@ -6679,13 +7018,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:3.1.0": - version: 3.1.0 - resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: 10/320ceb37af56953757b28e5b90c34556157676d41e3d0a3ff88769274d62373582bb0f0276a4f2d29c3f4fdd55b82b8be5731f52d391ad2ecae9b321ee1c742d - languageName: node - linkType: hard - "@jridgewell/resolve-uri@npm:^3.0.3": version: 3.0.7 resolution: "@jridgewell/resolve-uri@npm:3.0.7" @@ -6700,13 +7032,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: 10/69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e - languageName: node - linkType: hard - "@jridgewell/set-array@npm:^1.2.1": version: 1.2.1 resolution: "@jridgewell/set-array@npm:1.2.1" @@ -6714,17 +7039,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/source-map@npm:^0.3.2": - version: 0.3.2 - resolution: "@jridgewell/source-map@npm:0.3.2" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.0" - "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 10/1aaa42075bac32a551708025da0c07b11c11fb05ccd10fb70df2cb0db88773338ab0f33f175d9865379cb855bb3b1cda478367747a1087309fda40a7b9214bfa - languageName: node - linkType: hard - -"@jridgewell/source-map@npm:^0.3.3": +"@jridgewell/source-map@npm:^0.3.2, @jridgewell/source-map@npm:^0.3.3": version: 0.3.5 resolution: "@jridgewell/source-map@npm:0.3.5" dependencies: @@ -6734,13 +7049,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14": - version: 1.4.14 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 10/26e768fae6045481a983e48aa23d8fcd23af5da70ebd74b0649000e815e7fbb01ea2bc088c9176b3fffeb9bec02184e58f46125ef3320b30eaa1f4094cfefa38 - languageName: node - linkType: hard - "@jridgewell/sourcemap-codec@npm:^1.4.10": version: 1.4.13 resolution: "@jridgewell/sourcemap-codec@npm:1.4.13" @@ -6765,27 +7073,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.15": - version: 0.3.17 - resolution: "@jridgewell/trace-mapping@npm:0.3.17" - dependencies: - "@jridgewell/resolve-uri": "npm:3.1.0" - "@jridgewell/sourcemap-codec": "npm:1.4.14" - checksum: 10/790d439c9b271d9fc381dc4a837393ab942920245efedd5db20f65a665c0f778637fa623573337d3241ff784ffdb6724bbadf7fa2b61666bcd4884064b02f113 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.20": - version: 0.3.22 - resolution: "@jridgewell/trace-mapping@npm:0.3.22" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10/48d3e3db00dbecb211613649a1849876ba5544a3f41cf5e6b99ea1130272d6cf18591b5b67389bce20f1c871b4ede5900c3b6446a7aab6d0a3b2fe806a834db7 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.7, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -6795,16 +7083,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.7, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.13 - resolution: "@jridgewell/trace-mapping@npm:0.3.13" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.0.3" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - checksum: 10/b563ad016492becc14ec1df0edc0276087049df6974d95594ec2e5215d8ec241159d7f4aecb4e2197154732ba97982988e9accbaf496bc365fbb4506b67929f9 - languageName: node - linkType: hard - "@jsdevtools/ono@npm:^7.1.3": version: 7.1.3 resolution: "@jsdevtools/ono@npm:7.1.3" @@ -7439,7 +7717,7 @@ __metadata: languageName: node linkType: hard -"@reduxjs/toolkit@npm:^1.6.0 || ^2.0.0, @reduxjs/toolkit@workspace:packages/toolkit": +"@reduxjs/toolkit@npm:^1.6.0 || ^2.0.0, @reduxjs/toolkit@workspace:^, @reduxjs/toolkit@workspace:packages/toolkit": version: 0.0.0-use.local resolution: "@reduxjs/toolkit@workspace:packages/toolkit" dependencies: @@ -7460,7 +7738,8 @@ __metadata: "@typescript-eslint/eslint-plugin": "npm:^6" "@typescript-eslint/parser": "npm:^6" axios: "npm:^0.19.2" - console-testing-library: "npm:0.6.1" + console-testing-library: "patch:console-testing-library@npm%3A0.6.1#~/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch" + esbuild: "npm:^0.23.0" esbuild-extra: "npm:^0.3.1" eslint: "npm:^7.25.0" eslint-config-prettier: "npm:^9.1.0" @@ -7486,8 +7765,8 @@ __metadata: rimraf: "npm:^3.0.2" size-limit: "npm:^11.0.1" tslib: "npm:^1.10.0" - tsup: "npm:^7.2.0" - tsx: "npm:^3.12.2" + tsup: "npm:^8.2.3" + tsx: "npm:^4.16.2" typescript: "npm:^5.4.5" vite-tsconfig-paths: "npm:^4.3.1" vitest: "npm:^1.6.0" @@ -7523,6 +7802,13 @@ __metadata: languageName: node linkType: hard +"@remix-run/router@npm:1.18.0": + version: 1.18.0 + resolution: "@remix-run/router@npm:1.18.0" + checksum: 10/f878cf246b94368f431a51363f1d33dc35ad11cb910d930476d988825b024a152de87a7f74f0891c3e7182228f892c7f64f94409aae27084c320338dee82caa1 + languageName: node + linkType: hard + "@rollup/plugin-alias@npm:^3.1.1": version: 3.1.2 resolution: "@rollup/plugin-alias@npm:3.1.2" @@ -7620,93 +7906,114 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.9.3" +"@rollup/rollup-android-arm-eabi@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.19.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-android-arm64@npm:4.9.3" +"@rollup/rollup-android-arm64@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-android-arm64@npm:4.19.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-darwin-arm64@npm:4.9.3" +"@rollup/rollup-darwin-arm64@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.19.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-darwin-x64@npm:4.9.3" +"@rollup/rollup-darwin-x64@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.19.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.9.3" - conditions: os=linux & cpu=arm +"@rollup/rollup-linux-arm-gnueabihf@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.19.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.19.0" + conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.9.3" +"@rollup/rollup-linux-arm64-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.19.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.9.3" +"@rollup/rollup-linux-arm64-musl@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.19.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.9.3" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.19.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.19.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.9.3" +"@rollup/rollup-linux-s390x-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.19.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.19.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.9.3" +"@rollup/rollup-linux-x64-musl@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.19.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.9.3" +"@rollup/rollup-win32-arm64-msvc@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.19.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.9.3" +"@rollup/rollup-win32-ia32-msvc@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.19.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.9.3": - version: 4.9.3 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.9.3" +"@rollup/rollup-win32-x64-msvc@npm:4.19.0": + version: 4.19.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.19.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -8832,10 +9139,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^17.0.5": - version: 17.0.45 - resolution: "@types/node@npm:17.0.45" - checksum: 10/b45fff7270b5e81be19ef91a66b764a8b21473a97a8d211218a52e3426b79ad48f371819ab9153370756b33ba284e5c875463de4d2cf48a472e9098d7f09e8a2 +"@types/node@npm:*, @types/node@npm:^20.11.0, @types/node@npm:^20.11.10, @types/node@npm:^20.14.11": + version: 20.14.11 + resolution: "@types/node@npm:20.14.11" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10/344e1ce1ed16c86ed1c4209ab4d1de67db83dd6b694a6fabe295c47144dde2c58dabddae9f39a0a2bdd246e95f8d141ccfe848e464884b48b8918df4f7788025 languageName: node linkType: hard @@ -8860,21 +9169,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^20.11.0": - version: 20.11.0 - resolution: "@types/node@npm:20.11.0" - dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/8da60a8ccb65181c3d6f7686ddc5f1b1616cafa14d9e520a866adff82c17cc99336a78dd7ce7bee8f54e2332946f678b0e3aa377fbaaf751d3c05b64600872c6 - languageName: node - linkType: hard - -"@types/node@npm:^20.11.10": - version: 20.11.10 - resolution: "@types/node@npm:20.11.10" - dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/41ca9c7e7c95bf070ad747ab266f267f41950e01f5ddda739d0665c2ed39acc45cce46f78e33ffa2bf2dacd74a8493044b967c86358017dacce12958e49db664 +"@types/node@npm:^17.0.5": + version: 17.0.45 + resolution: "@types/node@npm:17.0.45" + checksum: 10/b45fff7270b5e81be19ef91a66b764a8b21473a97a8d211218a52e3426b79ad48f371819ab9153370756b33ba284e5c875463de4d2cf48a472e9098d7f09e8a2 languageName: node linkType: hard @@ -8966,6 +9264,15 @@ __metadata: languageName: node linkType: hard +"@types/react-dom@npm:^18.3.0": + version: 18.3.0 + resolution: "@types/react-dom@npm:18.3.0" + dependencies: + "@types/react": "npm:*" + checksum: 10/6ff53f5a7b7fba952a68e114d3b542ebdc1e87a794234785ebab0bcd9bde7fb4885f21ebaf93d26dc0a1b5b93287f42cad68b78ae04dddf6b20da7aceff0beaf + languageName: node + linkType: hard + "@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.6": version: 5.0.6 resolution: "@types/react-router-config@npm:5.0.6" @@ -9008,6 +9315,16 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.3.3": + version: 18.3.3 + resolution: "@types/react@npm:18.3.3" + dependencies: + "@types/prop-types": "npm:*" + csstype: "npm:^3.0.2" + checksum: 10/68e203b7f1f91d6cf21f33fc7af9d6d228035a26c83f514981e54aa3da695d0ec6af10c277c6336de1dd76c4adbe9563f3a21f80c4462000f41e5f370b46e96c + languageName: node + linkType: hard + "@types/resolve@npm:1.17.1": version: 1.17.1 resolution: "@types/resolve@npm:1.17.1" @@ -10160,17 +10477,12 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 10/e69f7234f2adfeb16db3671429a7c80894105bd7534cb2032acf01bb26e6a847952d11a062d071420b43f8d82e33d2e57f26fe87d9cce0853e8143d8910ff1de - languageName: node - linkType: hard - -"acorn-walk@npm:^8.3.2": - version: 8.3.2 - resolution: "acorn-walk@npm:8.3.2" - checksum: 10/57dbe2fd8cf744f562431775741c5c087196cd7a65ce4ccb3f3981cdfad25cd24ad2bad404997b88464ac01e789a0a61e5e355b2a84876f13deef39fb39686ca +"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.3.2": + version: 8.3.3 + resolution: "acorn-walk@npm:8.3.3" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10/59701dcb7070679622ba8e9c7f37577b4935565747ca0fd7c1c3ad30b3f1b1b008276282664e323b5495eb49f77fa12d3816fd06dc68e18f90fbebe759f71450 languageName: node linkType: hard @@ -10183,39 +10495,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.4, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.1": - version: 8.7.1 - resolution: "acorn@npm:8.7.1" - bin: - acorn: bin/acorn - checksum: 10/60a550c0c1173379a4ed29abd76f8a7f80adccdb8862afc8ce217fd006b7f47e8a035a72f518fcc0ef386334f0f91b6c8140cc51fd51137b8ecedf43663acf9a - languageName: node - linkType: hard - -"acorn@npm:^8.1.0, acorn@npm:^8.8.1": - version: 8.8.1 - resolution: "acorn@npm:8.8.1" - bin: - acorn: bin/acorn - checksum: 10/c77a64b3b695f9e5f0164794462ce7c1909acc1f7d39dcb3f9fce99e82163190e73dab689076ff9eea200505985cbd95f114c4ce1466055baf86a368d5e28bde - languageName: node - linkType: hard - -"acorn@npm:^8.10.0, acorn@npm:^8.9.0": - version: 8.11.3 - resolution: "acorn@npm:8.11.3" - bin: - acorn: bin/acorn - checksum: 10/b688e7e3c64d9bfb17b596e1b35e4da9d50553713b3b3630cf5690f2b023a84eac90c56851e6912b483fe60e8b4ea28b254c07e92f17ef83d72d78745a8352dd - languageName: node - linkType: hard - -"acorn@npm:^8.8.2": - version: 8.8.2 - resolution: "acorn@npm:8.8.2" +"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.11.0, acorn@npm:^8.11.3, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": + version: 8.12.0 + resolution: "acorn@npm:8.12.0" bin: acorn: bin/acorn - checksum: 10/b4e77d56d24d3e11a45d9ac8ae661b4e14a4af04ae33edbf1e6bf910887e5bb352cc60e9ea06a0944880e6b658f58c095d3b54e88e1921cb9319608b51085dd7 + checksum: 10/550cc5033184eb98f7fbe2e9ddadd0f47f065734cc682f25db7a244f52314eb816801b64dec7174effd978045bd1754892731a90b1102b0ede9d17a15cfde138 languageName: node linkType: hard @@ -11491,14 +11776,14 @@ __metadata: languageName: node linkType: hard -"bundle-require@npm:^4.0.0": - version: 4.0.1 - resolution: "bundle-require@npm:4.0.1" +"bundle-require@npm:^5.0.0": + version: 5.0.0 + resolution: "bundle-require@npm:5.0.0" dependencies: load-tsconfig: "npm:^0.2.3" peerDependencies: - esbuild: ">=0.17" - checksum: 10/f11d75a402398de8cc3be30529fe799a338c4b7e4efa58ff37271f3e34425e50d0f9955eaf0be5c4cd6edc2abe2226d75f1610cf56726458fd3b5e061826da50 + esbuild: ">=0.18" + checksum: 10/65909bc785819dea7aede00eea3892d9f5e2a963b89f8fe0bcc97e35803dfe4eaeabb7a80f8b12015f54a7f8ead07b44c1ba8bae8fe2f18888bd11fa982c5bba languageName: node linkType: hard @@ -11523,7 +11808,7 @@ __metadata: languageName: node linkType: hard -"cac@npm:^6.7.12, cac@npm:^6.7.14": +"cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" checksum: 10/002769a0fbfc51c062acd2a59df465a2a947916b02ac50b56c69ec6c018ee99ac3e7f4dd7366334ea847f1ecacf4defaa61bcd2ac283db50156ce1f1d8c8ad42 @@ -11761,8 +12046,8 @@ __metadata: linkType: hard "chai@npm:^4.3.10": - version: 4.4.0 - resolution: "chai@npm:4.4.0" + version: 4.4.1 + resolution: "chai@npm:4.4.1" dependencies: assertion-error: "npm:^1.1.0" check-error: "npm:^1.0.3" @@ -11771,7 +12056,7 @@ __metadata: loupe: "npm:^2.3.6" pathval: "npm:^1.1.1" type-detect: "npm:^4.0.8" - checksum: 10/c6904e4efe00f69261e9a06bce772171b7401a6e7fc07b90baef6c58c25cdd0b667cbd997512615cae7df5624cb6f5fac4f5574f87cf6e9f98ec745f3513239d + checksum: 10/c6d7aba913a67529c68dbec3673f94eb9c586c5474cc5142bd0b587c9c9ec9e5fbaa937e038ecaa6475aea31433752d5fabdd033b9248bde6ae53befcde774ae languageName: node linkType: hard @@ -11998,9 +12283,9 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^3.4.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.3": - version: 3.5.3 - resolution: "chokidar@npm:3.5.3" +"chokidar@npm:^3.4.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.3, chokidar@npm:^3.6.0": + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" dependencies: anymatch: "npm:~3.1.2" braces: "npm:~3.0.2" @@ -12013,7 +12298,7 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: 10/863e3ff78ee7a4a24513d2a416856e84c8e4f5e60efbe03e8ab791af1a183f569b62fc6f6b8044e2804966cb81277ddbbc1dc374fba3265bd609ea8efd62f5b3 + checksum: 10/c327fb07704443f8d15f7b4a7ce93b2f0bc0e6cea07ec28a7570aa22cd51fcf0379df589403976ea956c369f25aa82d84561947e227cd925902e1751371658df languageName: node linkType: hard @@ -12520,6 +12805,13 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.7": + version: 0.1.7 + resolution: "confbox@npm:0.1.7" + checksum: 10/3086687b9a2a70d44d4b40a2d376536fe7e1baec4a2a34261b21b8a836026b419cbf89ded6054216631823e7d63c415dad4b4d53591d6edbb202bb9820dfa6fa + languageName: node + linkType: hard + "configstore@npm:^5.0.1": version: 5.0.1 resolution: "configstore@npm:5.0.1" @@ -12562,6 +12854,13 @@ __metadata: languageName: node linkType: hard +"consola@npm:^3.2.3": + version: 3.2.3 + resolution: "consola@npm:3.2.3" + checksum: 10/02972dcb048c337357a3628438e5976b8e45bcec22fdcfbe9cd17622992953c4d695d5152f141464a02deac769b1d23028e8ac87f56483838df7a6bbf8e0f5a2 + languageName: node + linkType: hard + "console-control-strings@npm:^1.0.0, console-control-strings@npm:~1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" @@ -12580,14 +12879,14 @@ __metadata: languageName: node linkType: hard -"console-testing-library@patch:console-testing-library@npm%3A0.6.1#./.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch::locator=rtk-monorepo%40workspace%3A.": +"console-testing-library@patch:console-testing-library@npm%3A0.6.1#~/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch": version: 0.6.1 - resolution: "console-testing-library@patch:console-testing-library@npm%3A0.6.1#./.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch::version=0.6.1&hash=90f1d4&locator=rtk-monorepo%40workspace%3A." + resolution: "console-testing-library@patch:console-testing-library@npm%3A0.6.1#~/.yarn/patches/console-testing-library-npm-0.6.1-4d9957d402.patch::version=0.6.1&hash=95f56b" dependencies: jest-snapshot: "npm:^26.0.0" pretty-format: "npm:^26.0.0" strip-ansi: "npm:^6.0.0" - checksum: 10/d0e3de3e810ced722530b65d82cc58c62aefbda7c9d4f76ff4770053f4be864af3c76bf0827caf67a9b3020b2aef6c27d5f07cdb8e3ef966a512a94c056b88e5 + checksum: 10/2947f9733979954c144c687260e58cc58f31a5cd911ebadb00e06e9fc0a280d636171f9675f72cc60d7cf5f03323a1f79fadf9965617579e031b326d3565000f languageName: node linkType: hard @@ -13442,15 +13741,15 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": - version: 4.3.4 - resolution: "debug@npm:4.3.4" +"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5": + version: 4.3.5 + resolution: "debug@npm:4.3.5" dependencies: ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true - checksum: 10/0073c3bcbd9cb7d71dd5f6b55be8701af42df3e56e911186dfa46fac3a5b9eb7ce7f377dd1d3be6db8977221f8eb333d945216f645cf56f6b688cd484837d255 + checksum: 10/cb6eab424c410e07813ca1392888589972ce9a32b8829c6508f5e1f25f3c3e70a76731610ae55b4bbe58d1a2fffa1424b30e97fa8d394e49cd2656a9643aedd2 languageName: node linkType: hard @@ -13538,11 +13837,11 @@ __metadata: linkType: hard "deep-eql@npm:^4.1.3": - version: 4.1.3 - resolution: "deep-eql@npm:4.1.3" + version: 4.1.4 + resolution: "deep-eql@npm:4.1.4" dependencies: type-detect: "npm:^4.0.0" - checksum: 10/12ce93ae63de187e77b076d3d51bfc28b11f98910a22c18714cce112791195e86a94f97788180994614b14562a86c9763f67c69f785e4586f806b5df39bf9301 + checksum: 10/f04f4d581f044a824a6322fe4f68fbee4d6780e93fc710cd9852cbc82bfc7010df00f0e05894b848abbe14dc3a25acac44f424e181ae64d12f2ab9d0a875a5ef languageName: node linkType: hard @@ -14437,32 +14736,195 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:0.19.7": - version: 0.19.7 - resolution: "esbuild@npm:0.19.7" - dependencies: - "@esbuild/android-arm": "npm:0.19.7" - "@esbuild/android-arm64": "npm:0.19.7" - "@esbuild/android-x64": "npm:0.19.7" - "@esbuild/darwin-arm64": "npm:0.19.7" - "@esbuild/darwin-x64": "npm:0.19.7" - "@esbuild/freebsd-arm64": "npm:0.19.7" - "@esbuild/freebsd-x64": "npm:0.19.7" - "@esbuild/linux-arm": "npm:0.19.7" - "@esbuild/linux-arm64": "npm:0.19.7" - "@esbuild/linux-ia32": "npm:0.19.7" - "@esbuild/linux-loong64": "npm:0.19.7" - "@esbuild/linux-mips64el": "npm:0.19.7" - "@esbuild/linux-ppc64": "npm:0.19.7" - "@esbuild/linux-riscv64": "npm:0.19.7" - "@esbuild/linux-s390x": "npm:0.19.7" - "@esbuild/linux-x64": "npm:0.19.7" - "@esbuild/netbsd-x64": "npm:0.19.7" - "@esbuild/openbsd-x64": "npm:0.19.7" - "@esbuild/sunos-x64": "npm:0.19.7" - "@esbuild/win32-arm64": "npm:0.19.7" - "@esbuild/win32-ia32": "npm:0.19.7" - "@esbuild/win32-x64": "npm:0.19.7" +"esbuild@npm:^0.21.3, esbuild@npm:~0.21.5": + version: 0.21.5 + resolution: "esbuild@npm:0.21.5" + dependencies: + "@esbuild/aix-ppc64": "npm:0.21.5" + "@esbuild/android-arm": "npm:0.21.5" + "@esbuild/android-arm64": "npm:0.21.5" + "@esbuild/android-x64": "npm:0.21.5" + "@esbuild/darwin-arm64": "npm:0.21.5" + "@esbuild/darwin-x64": "npm:0.21.5" + "@esbuild/freebsd-arm64": "npm:0.21.5" + "@esbuild/freebsd-x64": "npm:0.21.5" + "@esbuild/linux-arm": "npm:0.21.5" + "@esbuild/linux-arm64": "npm:0.21.5" + "@esbuild/linux-ia32": "npm:0.21.5" + "@esbuild/linux-loong64": "npm:0.21.5" + "@esbuild/linux-mips64el": "npm:0.21.5" + "@esbuild/linux-ppc64": "npm:0.21.5" + "@esbuild/linux-riscv64": "npm:0.21.5" + "@esbuild/linux-s390x": "npm:0.21.5" + "@esbuild/linux-x64": "npm:0.21.5" + "@esbuild/netbsd-x64": "npm:0.21.5" + "@esbuild/openbsd-x64": "npm:0.21.5" + "@esbuild/sunos-x64": "npm:0.21.5" + "@esbuild/win32-arm64": "npm:0.21.5" + "@esbuild/win32-ia32": "npm:0.21.5" + "@esbuild/win32-x64": "npm:0.21.5" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b + languageName: node + linkType: hard + +"esbuild@npm:^0.23.0": + version: 0.23.0 + resolution: "esbuild@npm:0.23.0" + dependencies: + "@esbuild/aix-ppc64": "npm:0.23.0" + "@esbuild/android-arm": "npm:0.23.0" + "@esbuild/android-arm64": "npm:0.23.0" + "@esbuild/android-x64": "npm:0.23.0" + "@esbuild/darwin-arm64": "npm:0.23.0" + "@esbuild/darwin-x64": "npm:0.23.0" + "@esbuild/freebsd-arm64": "npm:0.23.0" + "@esbuild/freebsd-x64": "npm:0.23.0" + "@esbuild/linux-arm": "npm:0.23.0" + "@esbuild/linux-arm64": "npm:0.23.0" + "@esbuild/linux-ia32": "npm:0.23.0" + "@esbuild/linux-loong64": "npm:0.23.0" + "@esbuild/linux-mips64el": "npm:0.23.0" + "@esbuild/linux-ppc64": "npm:0.23.0" + "@esbuild/linux-riscv64": "npm:0.23.0" + "@esbuild/linux-s390x": "npm:0.23.0" + "@esbuild/linux-x64": "npm:0.23.0" + "@esbuild/netbsd-x64": "npm:0.23.0" + "@esbuild/openbsd-arm64": "npm:0.23.0" + "@esbuild/openbsd-x64": "npm:0.23.0" + "@esbuild/sunos-x64": "npm:0.23.0" + "@esbuild/win32-arm64": "npm:0.23.0" + "@esbuild/win32-ia32": "npm:0.23.0" + "@esbuild/win32-x64": "npm:0.23.0" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10/d3d91bf9ca73ba33966fc54cabb321eca770a5e2ff5b34d67e4235c94560cfd881803e39fcaa31d842579d10600da5201c5f597f8438679f6db856f75ded7124 + languageName: node + linkType: hard + +"esbuild@npm:~0.17": + version: 0.17.19 + resolution: "esbuild@npm:0.17.19" + dependencies: + "@esbuild/android-arm": "npm:0.17.19" + "@esbuild/android-arm64": "npm:0.17.19" + "@esbuild/android-x64": "npm:0.17.19" + "@esbuild/darwin-arm64": "npm:0.17.19" + "@esbuild/darwin-x64": "npm:0.17.19" + "@esbuild/freebsd-arm64": "npm:0.17.19" + "@esbuild/freebsd-x64": "npm:0.17.19" + "@esbuild/linux-arm": "npm:0.17.19" + "@esbuild/linux-arm64": "npm:0.17.19" + "@esbuild/linux-ia32": "npm:0.17.19" + "@esbuild/linux-loong64": "npm:0.17.19" + "@esbuild/linux-mips64el": "npm:0.17.19" + "@esbuild/linux-ppc64": "npm:0.17.19" + "@esbuild/linux-riscv64": "npm:0.17.19" + "@esbuild/linux-s390x": "npm:0.17.19" + "@esbuild/linux-x64": "npm:0.17.19" + "@esbuild/netbsd-x64": "npm:0.17.19" + "@esbuild/openbsd-x64": "npm:0.17.19" + "@esbuild/sunos-x64": "npm:0.17.19" + "@esbuild/win32-arm64": "npm:0.17.19" + "@esbuild/win32-ia32": "npm:0.17.19" + "@esbuild/win32-x64": "npm:0.17.19" dependenciesMeta: "@esbuild/android-arm": optional: true @@ -14510,7 +14972,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/326b9d98a77c5f2fb9a535b292bdc67c88bdfb4a19d29a221d65fd69f4800faea1f34947e8e6bc25ca3bd5db01f61c6968fec91f8c335e21e29b50330d90bd89 + checksum: 10/86ada7cad6d37a3445858fee31ca39fc6c0436c7c00b2e07b9ce308235be67f36aefe0dda25da9ab08653fde496d1e759d6ad891ce9479f9e1fb4964c8f2a0fa languageName: node linkType: hard @@ -16117,13 +16579,6 @@ __metadata: languageName: node linkType: hard -"get-func-name@npm:^2.0.0": - version: 2.0.0 - resolution: "get-func-name@npm:2.0.0" - checksum: 10/8d82e69f3e7fab9e27c547945dfe5cc0c57fc0adf08ce135dddb01081d75684a03e7a0487466f478872b341d52ac763ae49e660d01ab83741f74932085f693c3 - languageName: node - linkType: hard - "get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2": version: 2.0.2 resolution: "get-func-name@npm:2.0.2" @@ -16217,10 +16672,12 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.2.0": - version: 4.3.0 - resolution: "get-tsconfig@npm:4.3.0" - checksum: 10/e788a593549cd3dd9621f654baf0a62a32066dd56e8d6a7965c574d85725e578a93b6431a888785c8b20ba7166bbb8d6ec5e80df5a67df17d00b2a0b60816672 +"get-tsconfig@npm:^4.7.5": + version: 4.7.6 + resolution: "get-tsconfig@npm:4.7.6" + dependencies: + resolve-pkg-maps: "npm:^1.0.0" + checksum: 10/32da95a89f3ddbabd2a2e36f2a4add51a5e3c2b28f32e3c81494fcdbd43b7d9b42baea77784e62d10f87bb564c5ee908416aabf4c5ca9cdbb2950aa3c247f124 languageName: node linkType: hard @@ -16275,17 +16732,19 @@ __metadata: languageName: node linkType: hard -"glob@npm:7.1.6": - version: 7.1.6 - resolution: "glob@npm:7.1.6" +"glob@npm:^10.3.10": + version: 10.4.5 + resolution: "glob@npm:10.4.5" dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.0.4" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10/7d6ec98bc746980d5fe4d764b9c7ada727e3fbd2a7d85cd96dd95fb18638c9c54a70c692fd2ab5d68a186dc8cd9d6a4192d3df220beed891f687db179c430237 + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10/698dfe11828b7efd0514cd11e573eaed26b2dff611f0400907281ce3eab0c1e56143ef9b35adc7c77ecc71fba74717b510c7c223d34ca8a98ec81777b293d4ac languageName: node linkType: hard @@ -16407,7 +16866,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.1, globby@npm:^11.0.3, globby@npm:^11.0.4, globby@npm:^11.1.0": +"globby@npm:^11.0.1, globby@npm:^11.0.4, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -18426,6 +18885,19 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 + languageName: node + linkType: hard + "jake@npm:^10.8.5": version: 10.8.5 resolution: "jake@npm:10.8.5" @@ -19156,7 +19628,7 @@ __metadata: languageName: node linkType: hard -"joycon@npm:^3.0.1": +"joycon@npm:^3.1.1": version: 3.1.1 resolution: "joycon@npm:3.1.1" checksum: 10/4b36e3479144ec196425f46b3618f8a96ce7e1b658f091a309cd4906215f5b7a402d7df331a3e0a09681381a658d0c5f039cb3cf6907e0a1e17ed847f5d37775 @@ -19450,13 +19922,6 @@ __metadata: languageName: node linkType: hard -"jsonc-parser@npm:^3.2.0": - version: 3.2.0 - resolution: "jsonc-parser@npm:3.2.0" - checksum: 10/bd68b902e5f9394f01da97921f49c5084b2dc03a0c5b4fdb2a429f8d6f292686c1bf87badaeb0a8148d024192a88f5ad2e57b2918ba43fe25cf15f3371db64d4 - languageName: node - linkType: hard - "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -19650,10 +20115,10 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:^3.0.0": - version: 3.0.0 - resolution: "lilconfig@npm:3.0.0" - checksum: 10/55f60f4f9f7b41358cc33875e3696919412683a35aec30c6c60c4f6ecb16fb6d11f7ac856b8458b9b82b21d5f4629649fbfca1de034e8d5b0cc7a70836266db6 +"lilconfig@npm:^3.0.0, lilconfig@npm:^3.1.1": + version: 3.1.2 + resolution: "lilconfig@npm:3.1.2" + checksum: 10/8058403850cfad76d6041b23db23f730e52b6c17a8c28d87b90766639ca0ee40c748a3e85c2d7bd133d572efabff166c4b015e5d25e01fd666cb4b13cfada7f0 languageName: node linkType: hard @@ -20011,16 +20476,7 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^2.3.6": - version: 2.3.6 - resolution: "loupe@npm:2.3.6" - dependencies: - get-func-name: "npm:^2.0.0" - checksum: 10/8e695f3c99d9670d524767bc2bcbf799444b865d1d05e974d6dc53d72863c2ce9990103f311f89f04019f064e5ae7bbe70f3fba030a57d65aacfb951aad34d9f - languageName: node - linkType: hard - -"loupe@npm:^2.3.7": +"loupe@npm:^2.3.6, loupe@npm:^2.3.7": version: 2.3.7 resolution: "loupe@npm:2.3.7" dependencies: @@ -20061,6 +20517,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -20112,11 +20575,11 @@ __metadata: linkType: hard "magic-string@npm:^0.30.5": - version: 0.30.5 - resolution: "magic-string@npm:0.30.5" + version: 0.30.10 + resolution: "magic-string@npm:0.30.10" dependencies: "@jridgewell/sourcemap-codec": "npm:^1.4.15" - checksum: 10/c8a6b25f813215ca9db526f3a407d6dc0bf35429c2b8111d6f1c2cf6cf6afd5e2d9f9cd189416a0e3959e20ecd635f73639f9825c73de1074b29331fe36ace59 + checksum: 10/9f8bf6363a14c98a9d9f32ef833b194702a5c98fb931b05ac511b76f0b06fd30ed92beda6ca3261d2d52d21e39e891ef1136fbd032023f6cbb02d0b7d5767201 languageName: node linkType: hard @@ -20602,6 +21065,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 + languageName: node + linkType: hard + "minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.6 resolution: "minimist@npm:1.2.6" @@ -20683,6 +21155,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10/c25f0ee8196d8e6036661104bacd743785b2599a21de5c516b32b3fa2b83113ac89a2358465bc04956baab37ffb956ae43be679b2262bf7be15fce467ccd7950 + languageName: node + linkType: hard + "minizlib@npm:^2.0.0, minizlib@npm:^2.1.1": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -20713,27 +21192,15 @@ __metadata: languageName: node linkType: hard -"mlly@npm:^1.1.1, mlly@npm:^1.2.0": - version: 1.2.0 - resolution: "mlly@npm:1.2.0" - dependencies: - acorn: "npm:^8.8.2" - pathe: "npm:^1.1.0" - pkg-types: "npm:^1.0.2" - ufo: "npm:^1.1.1" - checksum: 10/5e9432fe6c63893861e1a5da6c67abfe188268ebf1326f82af01adfabad140f56191a6ad4564290cada28af9fde954c25c07d5f524169fe7e8e5d55de4022795 - languageName: node - linkType: hard - -"mlly@npm:^1.4.2": - version: 1.4.2 - resolution: "mlly@npm:1.4.2" +"mlly@npm:^1.4.2, mlly@npm:^1.7.0": + version: 1.7.1 + resolution: "mlly@npm:1.7.1" dependencies: - acorn: "npm:^8.10.0" - pathe: "npm:^1.1.1" - pkg-types: "npm:^1.0.3" - ufo: "npm:^1.3.0" - checksum: 10/ea5dc1a6cb2795cd15c6cdc84bbf431e0649917e673ef4de5d5ace6f74f74f02d22cd3c3faf7f868c3857115d33cccaaf5a070123b9a6c997af06ebeb8ab3bb5 + acorn: "npm:^8.11.3" + pathe: "npm:^1.1.2" + pkg-types: "npm:^1.1.1" + ufo: "npm:^1.5.3" + checksum: 10/c1ef3989e95fb6c6c27a238330897b01f46507020501f45a681f2cae453f982e38dcb0e45aa65f672ea7280945d4a729d266f17a8acb187956f312b0cafddf61 languageName: node linkType: hard @@ -20923,7 +21390,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23, nanoid@npm:^3.3.4": +"nanoid@npm:^3.1.23": version: 3.3.4 resolution: "nanoid@npm:3.3.4" bin: @@ -21898,6 +22365,13 @@ __metadata: languageName: node linkType: hard +"package-json-from-dist@npm:^1.0.0": + version: 1.0.0 + resolution: "package-json-from-dist@npm:1.0.0" + checksum: 10/ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea + languageName: node + linkType: hard + "package-json@npm:^6.3.0": version: 6.5.0 resolution: "package-json@npm:6.5.0" @@ -22144,6 +22618,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10/5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 + languageName: node + linkType: hard + "path-to-regexp@npm:0.1.7": version: 0.1.7 resolution: "path-to-regexp@npm:0.1.7" @@ -22188,17 +22672,10 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^1.1.0": - version: 1.1.0 - resolution: "pathe@npm:1.1.0" - checksum: 10/7cd4e00d9991a2454cccc575fd0ebdd0fe0caf257e5a6690af542d41c63e4d7033e580677395c54e0e4addbd9e297c0ef4e5de02906decc93b48c1a58a1acb0c - languageName: node - linkType: hard - -"pathe@npm:^1.1.1": - version: 1.1.1 - resolution: "pathe@npm:1.1.1" - checksum: 10/603decdf751d511f0df10acb8807eab8cc25c1af529e6149e27166916f19db57235a7d374b125452ba6da4dd0f697656fdaf5a9236b3594929bb371726d31602 +"pathe@npm:^1.1.1, pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10/f201d796351bf7433d147b92c20eb154a4e0ea83512017bf4ec4e492a5d6e738fb45798be4259a61aa81270179fce11026f6ff0d3fa04173041de044defe9d80 languageName: node linkType: hard @@ -22223,10 +22700,10 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0": - version: 1.0.0 - resolution: "picocolors@npm:1.0.0" - checksum: 10/a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981 +"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": + version: 1.0.1 + resolution: "picocolors@npm:1.0.1" + checksum: 10/fa68166d1f56009fc02a34cdfd112b0dd3cf1ef57667ac57281f714065558c01828cdf4f18600ad6851cbe0093952ed0660b1e0156bddf2184b6aaf5817553a5 languageName: node linkType: hard @@ -22265,20 +22742,20 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.1, pirates@npm:^4.0.4": - version: 4.0.5 - resolution: "pirates@npm:4.0.5" - checksum: 10/3728bae0cf6c18c3d25f5449ee8c5bc1a6a83bca688abe0e1654ce8c069bfd408170397cef133ed9ec8b0faeb4093c5c728d0e72ab7b3385256cd87008c40364 - languageName: node - linkType: hard - -"pirates@npm:^4.0.6": +"pirates@npm:^4.0.1, pirates@npm:^4.0.6": version: 4.0.6 resolution: "pirates@npm:4.0.6" checksum: 10/d02dda76f4fec1cbdf395c36c11cf26f76a644f9f9a1bfa84d3167d0d3154d5289aacc72677aa20d599bb4a6937a471de1b65c995e2aea2d8687cbcd7e43ea5f languageName: node linkType: hard +"pirates@npm:^4.0.4": + version: 4.0.5 + resolution: "pirates@npm:4.0.5" + checksum: 10/3728bae0cf6c18c3d25f5449ee8c5bc1a6a83bca688abe0e1654ce8c069bfd408170397cef133ed9ec8b0faeb4093c5c728d0e72ab7b3385256cd87008c40364 + languageName: node + linkType: hard + "pkg-dir@npm:^3.0.0": version: 3.0.0 resolution: "pkg-dir@npm:3.0.0" @@ -22306,25 +22783,14 @@ __metadata: languageName: node linkType: hard -"pkg-types@npm:^1.0.2": - version: 1.0.2 - resolution: "pkg-types@npm:1.0.2" - dependencies: - jsonc-parser: "npm:^3.2.0" - mlly: "npm:^1.1.1" - pathe: "npm:^1.1.0" - checksum: 10/9ff2665aa06a78573598bb04c9e2912f602e89d34c4a6d64a085cf16612a9b49eb87c994b4e337a9e2911f24f994ef43b48a71b288c00f3dc22fa402a2547ec1 - languageName: node - linkType: hard - -"pkg-types@npm:^1.0.3": - version: 1.0.3 - resolution: "pkg-types@npm:1.0.3" +"pkg-types@npm:^1.0.3, pkg-types@npm:^1.1.1": + version: 1.1.1 + resolution: "pkg-types@npm:1.1.1" dependencies: - jsonc-parser: "npm:^3.2.0" - mlly: "npm:^1.2.0" - pathe: "npm:^1.1.0" - checksum: 10/e17e1819ce579c9ea390e4c41a9ed9701d8cff14b463f9577cc4f94688da8917c66dabc40feacd47a21eb3de9b532756a78becd882b76add97053af307c1240a + confbox: "npm:^0.1.7" + mlly: "npm:^1.7.0" + pathe: "npm:^1.1.2" + checksum: 10/225eaf7c0339027e176dd0d34a6d9a1384c21e0aab295e57dfbef1f1b7fc132f008671da7e67553e352b80b17ba38c531c720c914061d277410eef1bdd9d9608 languageName: node linkType: hard @@ -22775,21 +23241,26 @@ __metadata: languageName: node linkType: hard -"postcss-load-config@npm:^4.0.1": - version: 4.0.1 - resolution: "postcss-load-config@npm:4.0.1" +"postcss-load-config@npm:^6.0.1": + version: 6.0.1 + resolution: "postcss-load-config@npm:6.0.1" dependencies: - lilconfig: "npm:^2.0.5" - yaml: "npm:^2.1.1" + lilconfig: "npm:^3.1.1" peerDependencies: + jiti: ">=1.21.0" postcss: ">=8.0.9" - ts-node: ">=9.0.0" + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: + jiti: + optional: true postcss: optional: true - ts-node: + tsx: + optional: true + yaml: optional: true - checksum: 10/d841565bc3638ae4b6854d3046904e054e76fca0aea5cf3e730b47e171e3e0a041ffc5f9b7348b18ea59c5d1e315944fa657b1cf9c573eecb053117b0d31eb8d + checksum: 10/1691cfc94948a9373d4f7b3b7a8500cfaf8cb2dcc2107c14f90f2a711a9892a362b0866894ac5bb723455fa685a15116d9ed3252188689c4502b137c19d6bdc4 languageName: node linkType: hard @@ -23611,25 +24082,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.2.1, postcss@npm:^8.3.11, postcss@npm:^8.3.5, postcss@npm:^8.4.13, postcss@npm:^8.4.14, postcss@npm:^8.4.4, postcss@npm:^8.4.7": - version: 8.4.14 - resolution: "postcss@npm:8.4.14" - dependencies: - nanoid: "npm:^3.3.4" - picocolors: "npm:^1.0.0" - source-map-js: "npm:^1.0.2" - checksum: 10/1940e8d1da04a2ac3e518735ab3e9563e2255bfab14cecc8c11fee97b2a36ac5fee496bccfc7057aaae7ff3accae463cd800d746238cf691bd65a32dba5cb7be - languageName: node - linkType: hard - -"postcss@npm:^8.4.32": - version: 8.4.33 - resolution: "postcss@npm:8.4.33" +"postcss@npm:^8.2.1, postcss@npm:^8.3.11, postcss@npm:^8.3.5, postcss@npm:^8.4.13, postcss@npm:^8.4.14, postcss@npm:^8.4.38, postcss@npm:^8.4.4, postcss@npm:^8.4.7": + version: 8.4.38 + resolution: "postcss@npm:8.4.38" dependencies: nanoid: "npm:^3.3.7" picocolors: "npm:^1.0.0" - source-map-js: "npm:^1.0.2" - checksum: 10/e22a4594c255f26117f38419fb494d7ecab0f596cd409f7aadc8a6173abf180ed7ea970cd13fd366ab12b5840be901d2a09b25197700c2ebcb5a8077326bf519 + source-map-js: "npm:^1.2.0" + checksum: 10/6e44a7ed835ffa9a2b096e8d3e5dfc6bcf331a25c48aeb862dd54e3aaecadf814fa22be224fd308f87d08adf2299164f88c5fd5ab1c4ef6cbd693ceb295377f4 languageName: node linkType: hard @@ -24165,6 +24625,18 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:^18.3.1": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.2" + peerDependencies: + react: ^18.3.1 + checksum: 10/3f4b73a3aa083091173b29812b10394dd06f4ac06aff410b74702cfb3aa29d7b0ced208aab92d5272919b612e5cda21aeb1d54191848cf6e46e9e354f3541f81 + languageName: node + linkType: hard + "react-error-overlay@npm:^6.0.11": version: 6.0.11 resolution: "react-error-overlay@npm:6.0.11" @@ -24303,25 +24775,22 @@ __metadata: languageName: node linkType: hard -"react-redux@npm:^9.1.0": - version: 9.1.0 - resolution: "react-redux@npm:9.1.0" +"react-redux@npm:^9.1.0, react-redux@npm:^9.1.2": + version: 9.1.2 + resolution: "react-redux@npm:9.1.2" dependencies: "@types/use-sync-external-store": "npm:^0.0.3" use-sync-external-store: "npm:^1.0.0" peerDependencies: "@types/react": ^18.2.25 react: ^18.0 - react-native: ">=0.69" redux: ^5.0.0 peerDependenciesMeta: "@types/react": optional: true - react-native: - optional: true redux: optional: true - checksum: 10/e2e5fe1c6965aedf3a80d7d5252ccbe6f231448cc1010ce19036fe8965f996cbafa2f81cacab77e54e75d6a14caa40540b8907459ef36af26b65c14f1bf89d80 + checksum: 10/319b3286f538da7e609ca90fc6762ffae007c5cf75e525a25237ac2feaee63d9cf76fe766817de1fc8f27e7bde825ca409c463037d26dd8e57c435d383f80c50 languageName: node linkType: hard @@ -24409,6 +24878,19 @@ __metadata: languageName: node linkType: hard +"react-router-dom@npm:^6.25.1": + version: 6.25.1 + resolution: "react-router-dom@npm:6.25.1" + dependencies: + "@remix-run/router": "npm:1.18.0" + react-router: "npm:6.25.1" + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + checksum: 10/583a0907156f8f0687817e2cd6fa2678284729fc9cf883acb0bc0a4ade1f76fc68dd771258f6b30a2fdc378a5608b973f7ecb1f7fc752295ad4eba8b2f156a82 + languageName: node + linkType: hard + "react-router@npm:5.3.3, react-router@npm:^5.3.3": version: 5.3.3 resolution: "react-router@npm:5.3.3" @@ -24429,6 +24911,17 @@ __metadata: languageName: node linkType: hard +"react-router@npm:6.25.1": + version: 6.25.1 + resolution: "react-router@npm:6.25.1" + dependencies: + "@remix-run/router": "npm:1.18.0" + peerDependencies: + react: ">=16.8" + checksum: 10/3bfb9754cff279cabcb247f13e66315d02333dae7e251fa8975d0e5cf68ee61793ad040594d2d490a5c995efc542739e7ef80462a69bd3209f64c69086fc7786 + languageName: node + linkType: hard + "react-router@npm:6.3.0": version: 6.3.0 resolution: "react-router@npm:6.3.0" @@ -24537,7 +25030,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.1.0, react@npm:^18.2.0": +"react@npm:^18.1.0, react@npm:^18.2.0, react@npm:^18.3.1": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -24680,16 +25173,7 @@ __metadata: languageName: node linkType: hard -"redux-thunk@npm:^2.4.1": - version: 2.4.1 - resolution: "redux-thunk@npm:2.4.1" - peerDependencies: - redux: ^4 - checksum: 10/b81cdb5fa83dbfb49abc220242dfb9bc76143924d2bf4b62c0730d5dc7eed716b5800e4284e8fed8bd9fc9ea0d7757e5fe8e4a1380e63656782b9f474da25efa - languageName: node - linkType: hard - -"redux-thunk@npm:^2.4.2": +"redux-thunk@npm:^2.4.1, redux-thunk@npm:^2.4.2": version: 2.4.2 resolution: "redux-thunk@npm:2.4.2" peerDependencies: @@ -24707,16 +25191,7 @@ __metadata: languageName: node linkType: hard -"redux@npm:^4.1.2": - version: 4.1.2 - resolution: "redux@npm:4.1.2" - dependencies: - "@babel/runtime": "npm:^7.9.2" - checksum: 10/764a64692f7184fb373dd38bcddbe1581e2c9cd3766a3ad6a5c5d19177db1fb164240f07b97cef40d29a632620b6c5e3a08abd8ea912e4c232b2f31bbd2431e6 - languageName: node - linkType: hard - -"redux@npm:^4.2.0": +"redux@npm:^4.1.2, redux@npm:^4.2.0": version: 4.2.1 resolution: "redux@npm:4.2.1" dependencies: @@ -25153,14 +25628,7 @@ __metadata: languageName: node linkType: hard -"reselect@npm:^4.1.5": - version: 4.1.5 - resolution: "reselect@npm:4.1.5" - checksum: 10/eabf06f34ef316526cb6841cb3fcf0c03a77bec296e03f94e9520d354d539f3f62cfcc50ad07523a74ce21bda9d8009995eca43b60c34b89cb7a264721c81380 - languageName: node - linkType: hard - -"reselect@npm:^4.1.7": +"reselect@npm:^4.1.5, reselect@npm:^4.1.7": version: 4.1.8 resolution: "reselect@npm:4.1.8" checksum: 10/199984d9872f71cd207f4aa6e6fd2bd48d95154f7aa9b3aee3398335f39f5491059e732f28c12e9031d5d434adab2c458dc8af5afb6564d0ad37e1644445e09c @@ -25218,6 +25686,13 @@ __metadata: languageName: node linkType: hard +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 10/0763150adf303040c304009231314d1e84c6e5ebfa2d82b7d94e96a6e82bacd1dcc0b58ae257315f3c8adb89a91d8d0f12928241cba2df1680fbe6f60bf99b0e + languageName: node + linkType: hard + "resolve-url-loader@npm:^4.0.0": version: 4.0.0 resolution: "resolve-url-loader@npm:4.0.0" @@ -25528,37 +26003,26 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.2.5": - version: 3.20.2 - resolution: "rollup@npm:3.20.2" - dependencies: - fsevents: "npm:~2.3.2" - dependenciesMeta: - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 10/996b29d8063ef48b62a366cb9a0624701c927d6d71aefe6d2cd2f55b96aafde81a627585c662442ffc9bac6806150202475e43b4f049f02bcda77b180a6f71c9 - languageName: node - linkType: hard - -"rollup@npm:^4.2.0": - version: 4.9.3 - resolution: "rollup@npm:4.9.3" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.9.3" - "@rollup/rollup-android-arm64": "npm:4.9.3" - "@rollup/rollup-darwin-arm64": "npm:4.9.3" - "@rollup/rollup-darwin-x64": "npm:4.9.3" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.9.3" - "@rollup/rollup-linux-arm64-gnu": "npm:4.9.3" - "@rollup/rollup-linux-arm64-musl": "npm:4.9.3" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.9.3" - "@rollup/rollup-linux-x64-gnu": "npm:4.9.3" - "@rollup/rollup-linux-x64-musl": "npm:4.9.3" - "@rollup/rollup-win32-arm64-msvc": "npm:4.9.3" - "@rollup/rollup-win32-ia32-msvc": "npm:4.9.3" - "@rollup/rollup-win32-x64-msvc": "npm:4.9.3" +"rollup@npm:^4.13.0, rollup@npm:^4.19.0": + version: 4.19.0 + resolution: "rollup@npm:4.19.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.19.0" + "@rollup/rollup-android-arm64": "npm:4.19.0" + "@rollup/rollup-darwin-arm64": "npm:4.19.0" + "@rollup/rollup-darwin-x64": "npm:4.19.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.19.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.19.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.19.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.19.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.19.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.19.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.19.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.19.0" + "@rollup/rollup-linux-x64-musl": "npm:4.19.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.19.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.19.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.19.0" "@types/estree": "npm:1.0.5" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -25572,12 +26036,18 @@ __metadata: optional: true "@rollup/rollup-linux-arm-gnueabihf": optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true "@rollup/rollup-linux-arm64-gnu": optional: true "@rollup/rollup-linux-arm64-musl": optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true "@rollup/rollup-linux-x64-gnu": optional: true "@rollup/rollup-linux-x64-musl": @@ -25592,7 +26062,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/8916c72dd148ec4aa116ff6f28f5baf07c07da689bd3c0b2dd4e6ae80978411f38674b5156decb32d752f3ce49de5882d0aca62a90894ae2cdcd3704605707bb + checksum: 10/a5f56e60d160e727f372fb0b0adbab03c1e5b858df7af62e626459687e6510d5b9685e4badef50bb6ffd916eaf53c1684a8e12ae959dacb8e6930c77a00a0f19 languageName: node linkType: hard @@ -25789,6 +26259,15 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10/e8d68b89d18d5b028223edf090092846868a765a591944760942b77ea1f69b17235f7e956696efbb62c8130ab90af7e0949bfb8eba7896335507317236966bc9 + languageName: node + linkType: hard + "schema-utils@npm:2.7.0": version: 2.7.0 resolution: "schema-utils@npm:2.7.0" @@ -26497,13 +26976,20 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2": +"source-map-js@npm:^1.0.1": version: 1.0.2 resolution: "source-map-js@npm:1.0.2" checksum: 10/38e2d2dd18d2e331522001fc51b54127ef4a5d473f53b1349c5cca2123562400e0986648b52e9407e348eaaed53bce49248b6e2641e6d793ca57cb2c360d6d51 languageName: node linkType: hard +"source-map-js@npm:^1.2.0": + version: 1.2.0 + resolution: "source-map-js@npm:1.2.0" + checksum: 10/74f331cfd2d121c50790c8dd6d3c9de6be21926de80583b23b37029b0f37aefc3e019fa91f9a10a5e120c08135297e1ecf312d561459c45908cb1e0e365f49e5 + languageName: node + linkType: hard + "source-map-loader@npm:^3.0.0": version: 3.0.1 resolution: "source-map-loader@npm:3.0.1" @@ -26537,7 +27023,7 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.17, source-map-support@npm:^0.5.21, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20": +"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.17, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: @@ -27127,13 +27613,13 @@ __metadata: languageName: node linkType: hard -"sucrase@npm:^3.20.3": - version: 3.32.0 - resolution: "sucrase@npm:3.32.0" +"sucrase@npm:^3.35.0": + version: 3.35.0 + resolution: "sucrase@npm:3.35.0" dependencies: "@jridgewell/gen-mapping": "npm:^0.3.2" commander: "npm:^4.0.0" - glob: "npm:7.1.6" + glob: "npm:^10.3.10" lines-and-columns: "npm:^1.1.6" mz: "npm:^2.7.0" pirates: "npm:^4.0.1" @@ -27141,7 +27627,7 @@ __metadata: bin: sucrase: bin/sucrase sucrase-node: bin/sucrase-node - checksum: 10/3f18c8db09fee863fc930b64bad738d8710d7aa56ecf900849e159f12ead68c09565ae7d5cef8341123950a035e95ed4d0f8474418623fb702164f4853bab57f + checksum: 10/bc601558a62826f1c32287d4fdfa4f2c09fe0fec4c4d39d0e257fd9116d7d6227a18309721d4185ec84c9dc1af0d5ec0e05a42a337fbb74fc293e068549aacbe languageName: node linkType: hard @@ -27631,9 +28117,9 @@ __metadata: linkType: hard "tinybench@npm:^2.5.1": - version: 2.5.1 - resolution: "tinybench@npm:2.5.1" - checksum: 10/f64ea142e048edc5010027eca36aff5aef74cd849ab9c6ba6e39475f911309694cb5a7ff894d47216ab4a3abcf4291e4bdc7a57796e96bf5b06e67452b5ac54d + version: 2.8.0 + resolution: "tinybench@npm:2.8.0" + checksum: 10/9731d070bedee6d44f3bb565862c284776e6adfd70d81a051a5c79b77479408509b448ad8d467d538d18bc0ae857b3ead8168d7e98d7f1355f8a0b01aa2f163b languageName: node linkType: hard @@ -27652,9 +28138,9 @@ __metadata: linkType: hard "tinyspy@npm:^2.2.0": - version: 2.2.0 - resolution: "tinyspy@npm:2.2.0" - checksum: 10/bcc5a08c2dc7574d32e6dcc2e760ad95a3cf30249c22799815b6389179427c95573d27d2d965ebc5fca2b6d338c46678cd7337ea2a9cebacee3dc662176b07cb + version: 2.2.1 + resolution: "tinyspy@npm:2.2.1" + checksum: 10/170d6232e87f9044f537b50b406a38fbfd6f79a261cd12b92879947bd340939a833a678632ce4f5c4a6feab4477e9c21cd43faac3b90b68b77dd0536c4149736 languageName: node linkType: hard @@ -28020,29 +28506,34 @@ __metadata: languageName: node linkType: hard -"tsup@npm:^7.2.0": - version: 7.2.0 - resolution: "tsup@npm:7.2.0" +"tsup@npm:^8.2.3": + version: 8.2.3 + resolution: "tsup@npm:8.2.3" dependencies: - bundle-require: "npm:^4.0.0" - cac: "npm:^6.7.12" - chokidar: "npm:^3.5.1" - debug: "npm:^4.3.1" - esbuild: "npm:^0.18.2" - execa: "npm:^5.0.0" - globby: "npm:^11.0.3" - joycon: "npm:^3.0.1" - postcss-load-config: "npm:^4.0.1" + bundle-require: "npm:^5.0.0" + cac: "npm:^6.7.14" + chokidar: "npm:^3.6.0" + consola: "npm:^3.2.3" + debug: "npm:^4.3.5" + esbuild: "npm:^0.23.0" + execa: "npm:^5.1.1" + globby: "npm:^11.1.0" + joycon: "npm:^3.1.1" + picocolors: "npm:^1.0.1" + postcss-load-config: "npm:^6.0.1" resolve-from: "npm:^5.0.0" - rollup: "npm:^3.2.5" + rollup: "npm:^4.19.0" source-map: "npm:0.8.0-beta.0" - sucrase: "npm:^3.20.3" + sucrase: "npm:^3.35.0" tree-kill: "npm:^1.2.2" peerDependencies: + "@microsoft/api-extractor": ^7.36.0 "@swc/core": ^1 postcss: ^8.4.12 - typescript: ">=4.1.0" + typescript: ">=4.5.0" peerDependenciesMeta: + "@microsoft/api-extractor": + optional: true "@swc/core": optional: true postcss: @@ -28052,7 +28543,7 @@ __metadata: bin: tsup: dist/cli-default.js tsup-node: dist/cli-node.js - checksum: 10/dea55a1a8911643f2c040527737c2b9982c03d39311c734fe3675680ad89b390784b9973fa890f1c5c816463930c70be9552801b0e5a58d2aa75b5375936cc8c + checksum: 10/2523611f5879fe408e8cb6d1fbae18d9e7617d2ef47258f6be8c11323c6d5d6aad296f6004d3fa6dc94e5f5b4c70b3eae677ac3d5ce0e9e1e4925715ee8b69b9 languageName: node linkType: hard @@ -28067,20 +28558,19 @@ __metadata: languageName: node linkType: hard -"tsx@npm:^3.12.2": - version: 3.12.2 - resolution: "tsx@npm:3.12.2" +"tsx@npm:^4.16.2": + version: 4.16.2 + resolution: "tsx@npm:4.16.2" dependencies: - "@esbuild-kit/cjs-loader": "npm:^2.4.1" - "@esbuild-kit/core-utils": "npm:^3.0.0" - "@esbuild-kit/esm-loader": "npm:^2.5.4" - fsevents: "npm:~2.3.2" + esbuild: "npm:~0.21.5" + fsevents: "npm:~2.3.3" + get-tsconfig: "npm:^4.7.5" dependenciesMeta: fsevents: optional: true bin: - tsx: dist/cli.js - checksum: 10/cc7cb8e0a38b1d29e30bd601de4734d7816491b38e060febe02564446af32df3732208f5ac721699cb1ad4598406771ae97b53c0db3cf24d5306e98828b99add + tsx: dist/cli.mjs + checksum: 10/841ccbace3dc0c42704bb5c4cea47e1f4cd313aa4719fd4531e5ed40bb862b02349c76f7c56c53b64207eebbb1c2ac2e117482aabfbf197a30fbc0b2584b60be languageName: node linkType: hard @@ -28241,6 +28731,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.5.4": + version: 5.5.4 + resolution: "typescript@npm:5.5.4" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/1689ccafef894825481fc3d856b4834ba3cc185a9c2878f3c76a9a1ef81af04194849840f3c69e7961e2312771471bb3b460ca92561e1d87599b26c37d0ffb6f + languageName: node + linkType: hard + "typescript@npm:~4.2.4": version: 4.2.4 resolution: "typescript@npm:4.2.4" @@ -28311,6 +28811,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^5.5.4#optional!builtin": + version: 5.5.4 + resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=d69c25" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/2c065f0ef81855eac25c9b658a3c9da65ffc005260c12854c2286f40f3667e1b1ecf8bdbdd37b59aa0397920378ce7900bff8cb32e0f1c7af6fd86efc676718c + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A~4.2.4#optional!builtin": version: 4.2.4 resolution: "typescript@patch:typescript@npm%3A4.2.4#optional!builtin::version=4.2.4&hash=334f98" @@ -28338,17 +28848,10 @@ __metadata: languageName: node linkType: hard -"ufo@npm:^1.1.1": - version: 1.1.1 - resolution: "ufo@npm:1.1.1" - checksum: 10/bf07dffb340aefc02c2d55a66f56d561c2238c6862fc2fdea3bb4e9a14719fd967626fbc2e7747e3a2d262b75f1f50dd5b5126192e04563d4baacc8f0e331952 - languageName: node - linkType: hard - -"ufo@npm:^1.3.0": - version: 1.3.2 - resolution: "ufo@npm:1.3.2" - checksum: 10/7133290d495e2b3f9416de69982019e81cff40d28cfd3a07accff1122ee52f23d9165e495a140a1b34b183244e88fc4001cb649591385ecbad1d3d0d2264fa6e +"ufo@npm:^1.5.3": + version: 1.5.3 + resolution: "ufo@npm:1.5.3" + checksum: 10/2b30dddd873c643efecdb58cfe457183cd4d95937ccdacca6942c697b87a2c578232c25a5149fda85436696bf0fdbc213bf2b220874712bc3e58c0fb00a2c950 languageName: node linkType: hard @@ -29053,13 +29556,13 @@ __metadata: linkType: hard "vite@npm:^5.0.0": - version: 5.0.11 - resolution: "vite@npm:5.0.11" + version: 5.3.1 + resolution: "vite@npm:5.3.1" dependencies: - esbuild: "npm:^0.19.3" + esbuild: "npm:^0.21.3" fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.32" - rollup: "npm:^4.2.0" + postcss: "npm:^8.4.38" + rollup: "npm:^4.13.0" peerDependencies: "@types/node": ^18.0.0 || >=20.0.0 less: "*" @@ -29088,7 +29591,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10/f1a8fea35ed9f162d7a10fd13efb2c96637028b0a319d726aeec8b31e20e4d047272bda5df82167618e7774a520236c66f3093ed172802660aec5227814072f4 + checksum: 10/180ca1795389f1ebc0b09f2ce61846943d34df597c4719e68d1d5ecba3e6cbd5b3313a4a321119b18290de3ef543df433659ba8b678de84df152e0386342697f languageName: node linkType: hard @@ -30290,13 +30793,6 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.1.1": - version: 2.3.1 - resolution: "yaml@npm:2.3.1" - checksum: 10/66501d597e43766eb94dc175d28ec8b2c63087d6a78783e59b4218eee32b9172740f9f27d54b7bc0ca8af61422f7134929f9974faeaac99d583787e793852fd2 - languageName: node - linkType: hard - "yargs-parser@npm:20.2.9, yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9"