From fa5090e300316076d4960155eb9bafb40c1b4b15 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 10:32:58 +0000 Subject: [PATCH 01/17] add argument validation --- packages/toolkit/package.json | 2 + .../toolkit/src/query/core/buildThunks.ts | 7 +- .../toolkit/src/query/endpointDefinitions.ts | 14 + packages/toolkit/src/query/standardSchema.ts | 82 + .../toolkit/src/query/tests/createApi.test.ts | 41 + yarn.lock | 1671 +++++++++++++++-- 6 files changed, 1680 insertions(+), 137 deletions(-) create mode 100644 packages/toolkit/src/query/standardSchema.ts diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index b8df1c9108..844c2f623c 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -99,6 +99,7 @@ "tsup": "^8.2.3", "tsx": "^4.19.0", "typescript": "^5.8.2", + "valibot": "^1.0.0", "vite-tsconfig-paths": "^4.3.1", "vitest": "^1.6.0", "yargs": "^15.3.1" @@ -124,6 +125,7 @@ "react" ], "dependencies": { + "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 81ca5d38a7..9702eee2ef 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -65,6 +65,7 @@ import { isRejectedWithValue, SHOULD_AUTOBATCH, } from './rtkImports' +import { parseWithSchema } from '../standardSchema' export type BuildThunksApiEndpointQuery< Definition extends QueryDefinition, @@ -562,7 +563,11 @@ export function buildThunks< finalQueryArg: unknown, ): Promise { let result: QueryReturnValue - const { extraOptions } = endpointDefinition + const { extraOptions, argSchema } = endpointDefinition + + if (argSchema) { + await parseWithSchema(argSchema, finalQueryArg) + } if (forceQueryFn) { // upsertQueryData relies on this to pass in the user-provided value diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index d0ced56637..737f5731db 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -37,6 +37,7 @@ import type { UnwrapPromise, } from './tsHelpers' import { isNotNullish } from './utils' +import type { StandardSchemaV1 } from './standardSchema' const resultType = /* @__PURE__ */ Symbol() const baseQuery = /* @__PURE__ */ Symbol() @@ -115,6 +116,9 @@ type EndpointDefinitionWithQuery< * @see https://redux-toolkit.js.org/api/other-exports#copywithstructuralsharing */ structuralSharing?: boolean + + /** A schema for the result *before* it's passed to `transformResponse` */ + rawResultSchema?: StandardSchemaV1> } type EndpointDefinitionWithQueryFn< @@ -175,6 +179,7 @@ type EndpointDefinitionWithQueryFn< query?: never transformResponse?: never transformErrorResponse?: never + rawResultSchema?: never /** * Defaults to `true`. * @@ -206,6 +211,15 @@ export type BaseEndpointDefinition< : EndpointDefinitionWithQuery) | EndpointDefinitionWithQueryFn ) & { + /** A schema for the arguments to be passed to the `query` or `queryFn` */ + argSchema?: StandardSchemaV1 + + /** A schema for the result (including `transformResponse` if provided) */ + resultSchema?: StandardSchemaV1 + + /** A schema for the error object returned by the `query` or `queryFn` */ + errorSchema?: StandardSchemaV1> + /* phantom type */ [resultType]?: ResultType /* phantom type */ diff --git a/packages/toolkit/src/query/standardSchema.ts b/packages/toolkit/src/query/standardSchema.ts new file mode 100644 index 0000000000..d90b9d736f --- /dev/null +++ b/packages/toolkit/src/query/standardSchema.ts @@ -0,0 +1,82 @@ +import { SchemaError } from '@standard-schema/utils' + +/** The Standard Schema interface. */ +export interface StandardSchemaV1 { + /** The Standard Schema properties. */ + readonly '~standard': StandardSchemaV1.Props +} + +export declare namespace StandardSchemaV1 { + /** The Standard Schema properties interface. */ + export interface Props { + /** The version number of the standard. */ + readonly version: 1 + /** The vendor name of the schema library. */ + readonly vendor: string + /** Validates unknown input values. */ + readonly validate: ( + value: unknown, + ) => Result | Promise> + /** Inferred types associated with the schema. */ + readonly types?: Types | undefined + } + + /** The result interface of the validate function. */ + export type Result = SuccessResult | FailureResult + + /** The result interface if validation succeeds. */ + export interface SuccessResult { + /** The typed output value. */ + readonly value: Output + /** The non-existent issues. */ + readonly issues?: undefined + } + + /** The result interface if validation fails. */ + export interface FailureResult { + /** The issues of failed validation. */ + readonly issues: ReadonlyArray + } + + /** The issue interface of the failure output. */ + export interface Issue { + /** The error message of the issue. */ + readonly message: string + /** The path of the issue, if any. */ + readonly path?: ReadonlyArray | undefined + } + + /** The path segment interface of the issue. */ + export interface PathSegment { + /** The key representing a path segment. */ + readonly key: PropertyKey + } + + /** The Standard Schema types interface. */ + export interface Types { + /** The input type of the schema. */ + readonly input: Input + /** The output type of the schema. */ + readonly output: Output + } + + /** Infers the input type of a Standard Schema. */ + export type InferInput = NonNullable< + Schema['~standard']['types'] + >['input'] + + /** Infers the output type of a Standard Schema. */ + export type InferOutput = NonNullable< + Schema['~standard']['types'] + >['output'] +} + +export async function parseWithSchema( + schema: Schema, + data: unknown, +): Promise> { + let result = schema['~standard'].validate(data) + if (result instanceof Promise) result = await result + if (result.issues) throw new SchemaError(result.issues) + return result.value +} diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index a9898e74a7..0d90dfd583 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -4,6 +4,7 @@ import { getSerializedHeaders, setupApiStore, } from '@internal/tests/utils/helpers' +import type { SerializedError } from '@reduxjs/toolkit' import { configureStore, createAction, createReducer } from '@reduxjs/toolkit' import type { DefinitionsFromApi, @@ -15,6 +16,7 @@ import type { import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' import { HttpResponse, delay, http } from 'msw' import nodeFetch from 'node-fetch' +import * as v from 'valibot' beforeAll(() => { vi.stubEnv('NODE_ENV', 'development') @@ -1187,3 +1189,42 @@ describe('timeout behavior', () => { }) }) }) + +describe('endpoint schemas', () => { + test("can be used to validate the endpoint's arguments", async () => { + server.use( + http.get('https://example.com/success/1', () => HttpResponse.json({})), + ) + + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query({ + query: ({ id }) => `/success/${id}`, + argSchema: v.object({ id: v.number() }), + }), + }), + }) + + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate({ id: 1 }), + ) + + expect(result?.error).toBeUndefined() + + const invalidResult = await storeRef.store.dispatch( + // @ts-expect-error + api.endpoints.query.initiate({ id: '1' }), + ) + + expect(invalidResult?.error).toEqual({ + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + }) + }) +}) diff --git a/yarn.lock b/yarn.lock index a5a6bff0dc..a3d3a30e57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -536,7 +536,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.26.2, @babel/code-frame@npm:^7.8.3": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.2, @babel/code-frame@npm:^7.8.3": version: 7.26.2 resolution: "@babel/code-frame@npm:7.26.2" dependencies: @@ -547,6 +547,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.18.6": + version: 7.24.2 + resolution: "@babel/code-frame@npm:7.24.2" + dependencies: + "@babel/highlight": "npm:^7.24.2" + picocolors: "npm:^1.0.0" + checksum: 10/7db8f5b36ffa3f47a37f58f61e3d130b9ecad21961f3eede7e2a4ac2c7e4a5efb6e9d03a810c669bc986096831b6c0dfc2c3082673d93351b82359c1b03e0590 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.26.5, @babel/compat-data@npm:^7.26.8": version: 7.26.8 resolution: "@babel/compat-data@npm:7.26.8" @@ -591,7 +601,33 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.12.13, @babel/generator@npm:^7.14.0, @babel/generator@npm:^7.24.1, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.10, @babel/generator@npm:^7.7.2": +"@babel/generator@npm:^7.12.13, @babel/generator@npm:^7.14.0, @babel/generator@npm:^7.24.1, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.26.3, @babel/generator@npm:^7.7.2": + version: 7.26.3 + resolution: "@babel/generator@npm:7.26.3" + dependencies: + "@babel/parser": "npm:^7.26.3" + "@babel/types": "npm:^7.26.3" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10/c1d8710cc1c52af9d8d67f7d8ea775578aa500887b327d2a81e27494764a6ef99e438dd7e14cf7cd3153656492ee27a8362980dc438087c0ca39d4e75532c638 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.25.9": + version: 7.26.2 + resolution: "@babel/generator@npm:7.26.2" + dependencies: + "@babel/parser": "npm:^7.26.2" + "@babel/types": "npm:^7.26.0" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10/71ace82b5b07a554846a003624bfab93275ccf73cdb9f1a37a4c1094bf9dc94bb677c67e8b8c939dbd6c5f0eda2e8f268aa2b0d9c3b9511072565660e717e045 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.26.10": version: 7.26.10 resolution: "@babel/generator@npm:7.26.10" dependencies: @@ -723,7 +759,14 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.26.5, @babel/helper-plugin-utils@npm:^7.8.0": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.25.9 + resolution: "@babel/helper-plugin-utils@npm:7.25.9" + checksum: 10/e347d87728b1ab10b6976d46403941c8f9008c045ea6d99997a7ffca7b852dc34b6171380f7b17edf94410e0857ff26f3a53d8618f11d73744db86e8ca9b8c64 + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.26.5": version: 7.26.5 resolution: "@babel/helper-plugin-utils@npm:7.26.5" checksum: 10/1cc0fd8514da3bb249bed6c27227696ab5e84289749d7258098701cffc0c599b7f61ec40dd332f8613030564b79899d9826813c96f966330bcfc7145a8377857 @@ -775,6 +818,20 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.24.1 + resolution: "@babel/helper-string-parser@npm:7.24.1" + checksum: 10/04c0ede77b908b43e6124753b48bc485528112a9335f0a21a226bff1ace75bb6e64fab24c85cb4b1610ef3494dacd1cb807caeb6b79a7b36c43d48c289b35949 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-string-parser@npm:7.24.8" + checksum: 10/6d1bf8f27dd725ce02bdc6dffca3c95fb9ab8a06adc2edbd9c1c9d68500274230d1a609025833ed81981eff560045b6b38f7b4c6fb1ab19fc90e5004e3932535 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-string-parser@npm:7.25.9" @@ -789,6 +846,20 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 10/df882d2675101df2d507b95b195ca2f86a3ef28cb711c84f37e79ca23178e13b9f0d8b522774211f51e40168bf5142be4c1c9776a150cddb61a0d5bf3e95750b + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-identifier@npm:7.24.7" + checksum: 10/86875063f57361471b531dbc2ea10bbf5406e12b06d249b03827d361db4cad2388c6f00936bcd9dc86479f7e2c69ea21412c2228d4b3672588b754b70a449d4b + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-option@npm:7.25.9" @@ -829,6 +900,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.2": + version: 7.24.2 + resolution: "@babel/highlight@npm:7.24.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/4555124235f34403bb28f55b1de58edf598491cc181c75f8afc8fe529903cb598cd52fe3bf2faab9bc1f45c299681ef0e44eea7a848bb85c500c5a4fe13f54f6 + languageName: node + linkType: hard + "@babel/parser@npm:7.12.16": version: 7.12.16 resolution: "@babel/parser@npm:7.12.16" @@ -838,7 +921,54 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.13, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.26.10, @babel/parser@npm:^7.26.9, @babel/parser@npm:^7.3.3": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.26.3, @babel/parser@npm:^7.3.3": + version: 7.26.3 + resolution: "@babel/parser@npm:7.26.3" + dependencies: + "@babel/types": "npm:^7.26.3" + bin: + parser: ./bin/babel-parser.js + checksum: 10/e7e3814b2dc9ee3ed605d38223471fa7d3a84cbe9474d2b5fa7ac57dc1ddf75577b1fd3a93bf7db8f41f28869bda795cddd80223f980be23623b6434bf4c88a8 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.12.13": + version: 7.24.1 + resolution: "@babel/parser@npm:7.24.1" + bin: + parser: ./bin/babel-parser.js + checksum: 10/561d9454091e07ecfec3828ce79204c0fc9d24e17763f36181c6984392be4ca6b79c8225f2224fdb7b1b3b70940e243368c8f83ac77ec2dc20f46d3d06bd6795 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.18.10": + version: 7.19.4 + resolution: "@babel/parser@npm:7.19.4" + bin: + parser: ./bin/babel-parser.js + checksum: 10/3024c7566c6326cb656385020e5abce13b89036769f82e328319ce0f426f933e70285df66a8af89b0afad0b0e28956cbe0901f3b4ed017719a95fef44d8bca42 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.20.7": + version: 7.24.8 + resolution: "@babel/parser@npm:7.24.8" + bin: + parser: ./bin/babel-parser.js + checksum: 10/e44b8327da46e8659bc9fb77f66e2dc4364dd66495fb17d046b96a77bf604f0446f1e9a89cf2f011d78fc3f5cdfbae2e9e0714708e1c985988335683b2e781ef + languageName: node + linkType: hard + +"@babel/parser@npm:^7.23.0": + version: 7.23.6 + resolution: "@babel/parser@npm:7.23.6" + bin: + parser: ./bin/babel-parser.js + checksum: 10/6be3a63d3c9d07b035b5a79c022327cb7e16cbd530140ecb731f19a650c794c315a72c699a22413ebeafaff14aa8f53435111898d59e01a393d741b85629fa7d + languageName: node + linkType: hard + +"@babel/parser@npm:^7.24.7, @babel/parser@npm:^7.26.10, @babel/parser@npm:^7.26.9": version: 7.26.10 resolution: "@babel/parser@npm:7.26.10" dependencies: @@ -849,6 +979,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/parser@npm:7.26.2" + dependencies: + "@babel/types": "npm:^7.26.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10/8baee43752a3678ad9f9e360ec845065eeee806f1fdc8e0f348a8a0e13eef0959dabed4a197c978896c493ea205c804d0a1187cc52e4a1ba017c7935bab4983d + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.9": version: 7.25.9 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.9" @@ -2179,7 +2320,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0, @babel/template@npm:^7.25.9, @babel/template@npm:^7.26.9, @babel/template@npm:^7.3.3": +"@babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0, @babel/template@npm:^7.25.9, @babel/template@npm:^7.26.9": version: 7.26.9 resolution: "@babel/template@npm:7.26.9" dependencies: @@ -2190,18 +2331,29 @@ __metadata: languageName: node linkType: hard -"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3, @babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.25.3, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.26.5, @babel/traverse@npm:^7.26.8, @babel/traverse@npm:^7.26.9, @babel/traverse@npm:^7.7.2": - version: 7.26.10 - resolution: "@babel/traverse@npm:7.26.10" +"@babel/template@npm:^7.3.3": + version: 7.18.10 + resolution: "@babel/template@npm:7.18.10" + dependencies: + "@babel/code-frame": "npm:^7.18.6" + "@babel/parser": "npm:^7.18.10" + "@babel/types": "npm:^7.18.10" + checksum: 10/b5d02b484a9afebf74e9757fd16bc794a1608561a2e2bf8d2fb516858cf58e2fec5687c39053a8c5360e968609fc29a5c8efc0cf53ba3daee06d1cf49b4f78fb + languageName: node + linkType: hard + +"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3, @babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.25.3, @babel/traverse@npm:^7.7.2": + version: 7.26.4 + resolution: "@babel/traverse@npm:7.26.4" dependencies: "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.10" - "@babel/parser": "npm:^7.26.10" - "@babel/template": "npm:^7.26.9" - "@babel/types": "npm:^7.26.10" + "@babel/generator": "npm:^7.26.3" + "@babel/parser": "npm:^7.26.3" + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.26.3" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10/e9c77390ce93d1f79fb0d83fc7c67282314ba73fa746ec3cf78e999b2dcda340e200a4fc9d8c5c4ca08f183e1aea2a5c0eb6e4ce802e43c4b10124dbc7d4e748 + checksum: 10/30c81a80d66fc39842814bc2e847f4705d30f3859156f130d90a0334fe1d53aa81eed877320141a528ecbc36448acc0f14f544a7d410fa319d1c3ab63b50b58f languageName: node linkType: hard @@ -2222,6 +2374,36 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/traverse@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/generator": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/7431614d76d4a053e429208db82f2846a415833f3d9eb2e11ef72eeb3c64dfd71f4a4d983de1a4a047b36165a1f5a64de8ca2a417534cc472005c740ffcb9c6a + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.26.5, @babel/traverse@npm:^7.26.8, @babel/traverse@npm:^7.26.9": + version: 7.26.10 + resolution: "@babel/traverse@npm:7.26.10" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.10" + "@babel/parser": "npm:^7.26.10" + "@babel/template": "npm:^7.26.9" + "@babel/types": "npm:^7.26.10" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/e9c77390ce93d1f79fb0d83fc7c67282314ba73fa746ec3cf78e999b2dcda340e200a4fc9d8c5c4ca08f183e1aea2a5c0eb6e4ce802e43c4b10124dbc7d4e748 + languageName: node + linkType: hard + "@babel/types@npm:7.12.13": version: 7.12.13 resolution: "@babel/types@npm:7.12.13" @@ -2233,7 +2415,38 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.13, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.26.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.13, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.26.3, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.26.3 + resolution: "@babel/types@npm:7.26.3" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10/c31d0549630a89abfa11410bf82a318b0c87aa846fbf5f9905e47ba5e2aa44f41cc746442f105d622c519e4dc532d35a8d8080460ff4692f9fc7485fbf3a00eb + languageName: node + linkType: hard + +"@babel/types@npm:^7.18.10": + version: 7.24.0 + resolution: "@babel/types@npm:7.24.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: 10/a0b4875ce2e132f9daff0d5b27c7f4c4fcc97f2b084bdc5834e92c9d32592778489029e65d99d00c406da612d87b72d7a236c0afccaa1435c028d0c94c9b6da4 + languageName: node + linkType: hard + +"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/types@npm:7.26.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10/40780741ecec886ed9edae234b5eb4976968cc70d72b4e5a40d55f83ff2cc457de20f9b0f4fe9d858350e43dab0ea496e7ef62e2b2f08df699481a76df02cd6e + languageName: node + linkType: hard + +"@babel/types@npm:^7.26.10, @babel/types@npm:^7.26.9": version: 7.26.10 resolution: "@babel/types@npm:7.26.10" dependencies: @@ -2243,6 +2456,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.3.0": + version: 7.24.8 + resolution: "@babel/types@npm:7.24.8" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.8" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10/29b080b2753c22ee5e2455ff767a971443245d945dea4d1b3130e036dcdf0949a89539a581753c68d03d2f2f2325244ee0f91fb83dabee1cbac5db5246838137 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -6748,6 +6972,17 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.0": + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10/81587b3c4dd8e6c60252122937cea0c637486311f4ed208b52b62aae2e7a87598f63ec330e6cd0984af494bfb16d3f0d60d3b21d7e5b4aedd2602ff3fe9d32e2 + languageName: node + linkType: hard + "@jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": version: 0.3.8 resolution: "@jridgewell/gen-mapping@npm:0.3.8" @@ -6773,6 +7008,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/source-map@npm:^0.3.2": + version: 0.3.5 + resolution: "@jridgewell/source-map@npm:0.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.0" + "@jridgewell/trace-mapping": "npm:^0.3.9" + checksum: 10/73838ac43235edecff5efc850c0d759704008937a56b1711b28c261e270fe4bf2dc06d0b08663aeb1ab304f81f6de4f5fb844344403cf53ba7096967a9953cae + languageName: node + linkType: hard + "@jridgewell/source-map@npm:^0.3.3": version: 0.3.6 resolution: "@jridgewell/source-map@npm:0.3.6" @@ -6800,7 +7045,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -7822,6 +8067,7 @@ __metadata: "@phryneas/ts-version": "npm:^1.0.2" "@size-limit/file": "npm:^11.0.1" "@size-limit/webpack": "npm:^11.0.1" + "@standard-schema/utils": "npm:^0.3.0" "@testing-library/dom": "npm:^10.4.0" "@testing-library/react": "npm:^16.0.1" "@testing-library/react-render-stream": "npm:^1.0.3" @@ -7869,6 +8115,7 @@ __metadata: tsup: "npm:^8.2.3" tsx: "npm:^4.19.0" typescript: "npm:^5.8.2" + valibot: "npm:^1.0.0" vite-tsconfig-paths: "npm:^4.3.1" vitest: "npm:^1.6.0" yargs: "npm:^15.3.1" @@ -8532,6 +8779,13 @@ __metadata: languageName: node linkType: hard +"@standard-schema/utils@npm:^0.3.0": + version: 0.3.0 + resolution: "@standard-schema/utils@npm:0.3.0" + checksum: 10/7084f875d322792f2e0a5904009434c8374b9345b09ba89828b68fd56fa3c2b366d35bf340d9e8c72736ef01793c2f70d350c372ed79845dc3566c58d34b4b51 + languageName: node + linkType: hard + "@styled-system/core@npm:5.1.2": version: 5.1.2 resolution: "@styled-system/core@npm:5.1.2" @@ -9195,7 +9449,7 @@ __metadata: languageName: node linkType: hard -"@testing-library/react@npm:^16.0.1, @testing-library/react@npm:^16.1.0": +"@testing-library/react@npm:^16.0.1": version: 16.2.0 resolution: "@testing-library/react@npm:16.2.0" dependencies: @@ -9215,6 +9469,26 @@ __metadata: languageName: node linkType: hard +"@testing-library/react@npm:^16.1.0": + version: 16.1.0 + resolution: "@testing-library/react@npm:16.1.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + peerDependencies: + "@testing-library/dom": ^10.0.0 + "@types/react": ^18.0.0 || ^19.0.0 + "@types/react-dom": ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10/2a20e0dbfadbc93d45a84e82281ed47deed54a6a5fc1461a523172d7fbc0481e8502cf98a2080f38aba94290b3d745671a1c9e320e6f76ad6afcca67c580b963 + languageName: node + linkType: hard + "@testing-library/user-event@npm:^14.5.2": version: 14.6.1 resolution: "@testing-library/user-event@npm:14.6.1" @@ -9331,7 +9605,16 @@ __metadata: languageName: node linkType: hard -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.4, @types/babel__traverse@npm:^7.0.6": +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": + version: 7.11.1 + resolution: "@types/babel__traverse@npm:7.11.1" + dependencies: + "@babel/types": "npm:^7.3.0" + checksum: 10/8df08f5ed92e2983978e7db38281e67c811028cfbd1b1b8740f6a93ba3c382bb126b45b248538409e4106dd3280d0d81da399b43173e5a5444de535ef47f07c2 + languageName: node + linkType: hard + +"@types/babel__traverse@npm:^7.0.4": version: 7.20.6 resolution: "@types/babel__traverse@npm:7.20.6" dependencies: @@ -9449,7 +9732,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.6, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": +"@types/estree@npm:*, @types/estree@npm:1.0.6, @types/estree@npm:^1.0.6": version: 1.0.6 resolution: "@types/estree@npm:1.0.6" checksum: 10/9d35d475095199c23e05b431bcdd1f6fec7380612aed068b14b2a08aa70494de8a9026765a5a91b1073f636fb0368f6d8973f518a31391d519e20c59388ed88d @@ -9463,6 +9746,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 10/7de6d928dd4010b0e20c6919e1a6c27b61f8d4567befa89252055fad503d587ecb9a1e3eab1b1901f923964d7019796db810b7fd6430acb26c32866d126fd408 + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^5.0.0": version: 5.0.6 resolution: "@types/express-serve-static-core@npm:5.0.6" @@ -9661,13 +9951,20 @@ __metadata: languageName: node linkType: hard -"@types/js-levenshtein@npm:^1.1.0, @types/js-levenshtein@npm:^1.1.1": +"@types/js-levenshtein@npm:^1.1.0": version: 1.1.3 resolution: "@types/js-levenshtein@npm:1.1.3" checksum: 10/eb338696da976925ea8448a42d775d7615a14323dceeb08909f187d0b3d3b4c1f67a1c36ef586b1c2318b70ab141bba8fc58311ba1c816711704605aec09db8b languageName: node linkType: hard +"@types/js-levenshtein@npm:^1.1.1": + version: 1.1.1 + resolution: "@types/js-levenshtein@npm:1.1.1" + checksum: 10/1d1ff1ee2ad551909e47f3ce19fcf85b64dc5146d3b531c8d26fc775492d36e380b32cf5ef68ff301e812c3b00282f37aac579ebb44498b94baff0ace7509769 + languageName: node + linkType: hard + "@types/js-yaml@npm:^4.0.0": version: 4.0.9 resolution: "@types/js-yaml@npm:4.0.9" @@ -9685,7 +9982,14 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": + version: 7.0.11 + resolution: "@types/json-schema@npm:7.0.11" + checksum: 10/e50864a93f4dcb9de64c0c605d836f5416341c824d7a8cde1aa15a5fc68bed44b33cdcb2e04e5098339e9121848378f2d0cc5b124dec41c89203c6f67d6f344a + languageName: node + linkType: hard + +"@types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.15": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7 @@ -10044,10 +10348,17 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.9, @types/semver@npm:^7.5.0": - version: 7.5.8 - resolution: "@types/semver@npm:7.5.8" - checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178 +"@types/semver@npm:^7.3.12, @types/semver@npm:^7.5.0": + version: 7.5.6 + resolution: "@types/semver@npm:7.5.6" + checksum: 10/e77282b17f74354e17e771c0035cccb54b94cc53d0433fa7e9ba9d23fd5d7edcd14b6c8b7327d58bbd89e83b1c5eda71dfe408e06b929007e2b89586e9b63459 + languageName: node + linkType: hard + +"@types/semver@npm:^7.3.9": + version: 7.3.9 + resolution: "@types/semver@npm:7.3.9" + checksum: 10/872d9689bed8bba950b9ad9ba4a61e9770f13d5dde93ab50db6aa7474593c5b50c766c95f1e0b31f75f06da5322fb217668b5b749f1759008ea6018e62082293 languageName: node linkType: hard @@ -10203,6 +10514,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.5.1": + version: 8.5.3 + resolution: "@types/ws@npm:8.5.3" + dependencies: + "@types/node": "npm:*" + checksum: 10/08aac698ce6480b532d8311f790a8744ae489ccdd98f374cfe4b8245855439825c64b031abcbba4f30fb280da6cc2b02a4e261e16341d058ffaeecaa24ba2bd3 + languageName: node + linkType: hard + "@types/ws@npm:^8.5.5": version: 8.18.0 resolution: "@types/ws@npm:8.18.0" @@ -10931,13 +11251,20 @@ __metadata: languageName: node linkType: hard -"@xmldom/xmldom@npm:^0.7.2, @xmldom/xmldom@npm:^0.7.5": +"@xmldom/xmldom@npm:^0.7.2": version: 0.7.13 resolution: "@xmldom/xmldom@npm:0.7.13" checksum: 10/a359d15fe3c24fe85a1e1b3bc4cfd23d4f014fb8aa382aa445cccaac545e42958b75e386dd4853c76d82036401400b8d5e33cbcbfb6af7cdadeba769eae6122a languageName: node linkType: hard +"@xmldom/xmldom@npm:^0.7.5": + version: 0.7.5 + resolution: "@xmldom/xmldom@npm:0.7.5" + checksum: 10/83c0959b482459af03f11b426bc3cdf82554ee8306af474d3cf2b1cf37043e87228e35bbb71cd8221ed69116c7a67ac2b1c36cf9f3310115d97554ba7b99628e + languageName: node + linkType: hard + "@xtuc/ieee754@npm:^1.2.0": version: 1.2.0 resolution: "@xtuc/ieee754@npm:1.2.0" @@ -11036,12 +11363,48 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.7.0, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.14.1 - resolution: "acorn@npm:8.14.1" +"acorn@npm:^8.0.0, acorn@npm:^8.14.0, acorn@npm:^8.7.0": + version: 8.14.0 + resolution: "acorn@npm:8.14.0" + bin: + acorn: bin/acorn + checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2 + languageName: node + linkType: hard + +"acorn@npm:^8.0.4, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0": + version: 8.7.1 + resolution: "acorn@npm:8.7.1" + bin: + acorn: bin/acorn + checksum: 10/60a550c0c1173379a4ed29abd76f8a7f80adccdb8862afc8ce217fd006b7f47e8a035a72f518fcc0ef386334f0f91b6c8140cc51fd51137b8ecedf43663acf9a + languageName: node + linkType: hard + +"acorn@npm:^8.11.0": + version: 8.12.1 + resolution: "acorn@npm:8.12.1" + bin: + acorn: bin/acorn + checksum: 10/d08c2d122bba32d0861e0aa840b2ee25946c286d5dc5990abca991baf8cdbfbe199b05aacb221b979411a2fea36f83e26b5ac4f6b4e0ce49038c62316c1848f0 + languageName: node + linkType: hard + +"acorn@npm:^8.8.2": + version: 8.8.2 + resolution: "acorn@npm:8.8.2" + bin: + acorn: bin/acorn + checksum: 10/b4e77d56d24d3e11a45d9ac8ae661b4e14a4af04ae33edbf1e6bf910887e5bb352cc60e9ea06a0944880e6b658f58c095d3b54e88e1921cb9319608b51085dd7 + languageName: node + linkType: hard + +"acorn@npm:^8.9.0": + version: 8.11.3 + resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: 10/d1379bbee224e8d44c3c3946e6ba6973e999fbdd4e22e41c3455d7f9b6f72f7ce18d3dc218002e1e48eea789539cf1cb6d1430c81838c6744799c712fb557d92 + checksum: 10/b688e7e3c64d9bfb17b596e1b35e4da9d50553713b3b3630cf5690f2b023a84eac90c56851e6912b483fe60e8b4ea28b254c07e92f17ef83d72d78745a8352dd languageName: node linkType: hard @@ -11071,6 +11434,15 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:^7.0.2": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: "npm:^4.3.4" + checksum: 10/c478fec8f79953f118704d007a38f2a185458853f5c45579b9669372bd0e12602e88dc2ad0233077831504f7cd6fcc8251c383375bba5eaaf563b102938bda26 + languageName: node + linkType: hard + "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.3 resolution: "agent-base@npm:7.1.3" @@ -11619,6 +11991,22 @@ __metadata: languageName: node linkType: hard +"arraybuffer.prototype.slice@npm:^1.0.3": + version: 1.0.3 + resolution: "arraybuffer.prototype.slice@npm:1.0.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.3" + es-errors: "npm:^1.2.1" + get-intrinsic: "npm:^1.2.3" + is-array-buffer: "npm:^3.0.4" + is-shared-array-buffer: "npm:^1.0.2" + checksum: 10/0221f16c1e3ec7b67da870ee0e1f12b825b5f9189835392b59a22990f715827561a4f4cd5330dc7507de272d8df821be6cd4b0cb569babf5ea4be70e365a2f3d + languageName: node + linkType: hard + "arraybuffer.prototype.slice@npm:^1.0.4": version: 1.0.4 resolution: "arraybuffer.prototype.slice@npm:1.0.4" @@ -12421,6 +12809,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.16.6, browserslist@npm:^4.20.3": + version: 4.23.2 + resolution: "browserslist@npm:4.23.2" + dependencies: + caniuse-lite: "npm:^1.0.30001640" + electron-to-chromium: "npm:^1.4.820" + node-releases: "npm:^2.0.14" + update-browserslist-db: "npm:^1.1.0" + bin: + browserslist: cli.js + checksum: 10/326a98b1c39bcc9a99b197f15790dc28e122b1aead3257c837421899377ac96239123f26868698085b3d9be916d72540602738e1f857e86a387e810af3fda6e5 + languageName: node + linkType: hard + "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -12567,7 +12969,7 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": +"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.8": version: 1.0.8 resolution: "call-bind@npm:1.0.8" dependencies: @@ -12579,6 +12981,19 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.7": + version: 1.0.7 + resolution: "call-bind@npm:1.0.7" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + set-function-length: "npm:^1.2.1" + checksum: 10/cd6fe658e007af80985da5185bff7b55e12ef4c2b6f41829a26ed1eef254b1f1c12e3dfd5b2b068c6ba8b86aba62390842d81752e67dcbaec4f6f76e7113b6b7 + languageName: node + linkType: hard + "call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": version: 1.0.4 resolution: "call-bound@npm:1.0.4" @@ -12678,7 +13093,28 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001616, caniuse-lite@npm:^1.0.30001688, caniuse-lite@npm:^1.0.30001702": +"caniuse-lite@npm:^1.0.0": + version: 1.0.30001687 + resolution: "caniuse-lite@npm:1.0.30001687" + checksum: 10/0b6a064d5df185ec60b842dba5a27d2c54a66967b7f89571bfd0a8256f0863b1f2a910da6a19ed1b8f534bedf0663cae90309a4a6899bba2286205d459b32f95 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001616, caniuse-lite@npm:^1.0.30001688": + version: 1.0.30001688 + resolution: "caniuse-lite@npm:1.0.30001688" + checksum: 10/2125e900af866ee211c66beca01220c98e72c8a91d25c87b8ab456d3916f56fb1be5feef72556bca746da7aa852fc0118a04669f5ec2e6511eb77c960479e1c0 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001640": + version: 1.0.30001641 + resolution: "caniuse-lite@npm:1.0.30001641" + checksum: 10/d60df2662fcae31efc8f36451929640e9630bb2e936f7449166dc70dcc4a757f6d86a5a089eed763b58354d684404b175e6c8790a9fd95c48abed1fcb7c26225 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001702": version: 1.0.30001705 resolution: "caniuse-lite@npm:1.0.30001705" checksum: 10/2bc019c29af827c099df8d4510a2ec23be9fbd9dc9ce988a97d9f6cf30d1eb71479d9d22663bd7ed2255124998ceaf85edf4382219175a22f68ff3b6471a41cc @@ -13356,10 +13792,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:*": - version: 13.1.0 - resolution: "commander@npm:13.1.0" - checksum: 10/d3b4b79e6be8471ddadacbb8cd441fe82154d7da7393b50e76165a9e29ccdb74fa911a186437b9a211d0fc071db6051915c94fb8ef16d77511d898e9dbabc6af +"commander@npm:*, commander@npm:^8.3.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 10/6b7b5d334483ce24bd73c5dac2eab901a7dbb25fd983ea24a1eeac6e7166bb1967f641546e8abf1920afbde86a45fbfe5812fbc69d0dc451bb45ca416a12a3a3 languageName: node linkType: hard @@ -13412,13 +13848,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^8.3.0": - version: 8.3.0 - resolution: "commander@npm:8.3.0" - checksum: 10/6b7b5d334483ce24bd73c5dac2eab901a7dbb25fd983ea24a1eeac6e7166bb1967f641546e8abf1920afbde86a45fbfe5812fbc69d0dc451bb45ca416a12a3a3 - languageName: node - linkType: hard - "common-path-prefix@npm:^3.0.0": version: 3.0.0 resolution: "common-path-prefix@npm:3.0.0" @@ -13959,6 +14388,15 @@ __metadata: languageName: node linkType: hard +"css-declaration-sorter@npm:^6.3.0": + version: 6.3.0 + resolution: "css-declaration-sorter@npm:6.3.0" + peerDependencies: + postcss: ^8.0.9 + checksum: 10/bb8a2fba9554521d020564da86da43511ae01fb488cb6f35900d400d876beaaa743042994808eed0cff6d60b01593d3af57bf1bb8f53a14bacdd2ad1dec00999 + languageName: node + linkType: hard + "css-declaration-sorter@npm:^6.3.1": version: 6.4.1 resolution: "css-declaration-sorter@npm:6.4.1" @@ -14263,6 +14701,45 @@ __metadata: languageName: node linkType: hard +"cssnano-preset-default@npm:^5.2.12": + version: 5.2.12 + resolution: "cssnano-preset-default@npm:5.2.12" + dependencies: + css-declaration-sorter: "npm:^6.3.0" + cssnano-utils: "npm:^3.1.0" + postcss-calc: "npm:^8.2.3" + postcss-colormin: "npm:^5.3.0" + postcss-convert-values: "npm:^5.1.2" + postcss-discard-comments: "npm:^5.1.2" + postcss-discard-duplicates: "npm:^5.1.0" + postcss-discard-empty: "npm:^5.1.1" + postcss-discard-overridden: "npm:^5.1.0" + postcss-merge-longhand: "npm:^5.1.6" + postcss-merge-rules: "npm:^5.1.2" + postcss-minify-font-values: "npm:^5.1.0" + postcss-minify-gradients: "npm:^5.1.1" + postcss-minify-params: "npm:^5.1.3" + postcss-minify-selectors: "npm:^5.2.1" + postcss-normalize-charset: "npm:^5.1.0" + postcss-normalize-display-values: "npm:^5.1.0" + postcss-normalize-positions: "npm:^5.1.1" + postcss-normalize-repeat-style: "npm:^5.1.1" + postcss-normalize-string: "npm:^5.1.0" + postcss-normalize-timing-functions: "npm:^5.1.0" + postcss-normalize-unicode: "npm:^5.1.0" + postcss-normalize-url: "npm:^5.1.0" + postcss-normalize-whitespace: "npm:^5.1.1" + postcss-ordered-values: "npm:^5.1.3" + postcss-reduce-initial: "npm:^5.1.0" + postcss-reduce-transforms: "npm:^5.1.0" + postcss-svgo: "npm:^5.1.0" + postcss-unique-selectors: "npm:^5.1.1" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/5866842e6d9c99c3e71ff5b6c73224beac45a461b32151d8dc6a3ec8abc68b3d439b0c41c29704f9a8b4441f9e85ead159809ebfd55c3ca9aae6e86048b1b2c1 + languageName: node + linkType: hard + "cssnano-preset-default@npm:^5.2.14": version: 5.2.14 resolution: "cssnano-preset-default@npm:5.2.14" @@ -14360,7 +14837,7 @@ __metadata: languageName: node linkType: hard -"cssnano@npm:^5.0.1, cssnano@npm:^5.0.6": +"cssnano@npm:^5.0.1": version: 5.1.15 resolution: "cssnano@npm:5.1.15" dependencies: @@ -14373,6 +14850,19 @@ __metadata: languageName: node linkType: hard +"cssnano@npm:^5.0.6": + version: 5.1.12 + resolution: "cssnano@npm:5.1.12" + dependencies: + cssnano-preset-default: "npm:^5.2.12" + lilconfig: "npm:^2.0.3" + yaml: "npm:^1.10.2" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/5314c56e9d2a14f46be35f60516347c8281bd06252101336535c0738dcbceb05dc2e3fdabb8892dba335afa35cb2faa0918a4a354f418a381052d0cc5b140a97 + languageName: node + linkType: hard + "cssnano@npm:^6.0.1, cssnano@npm:^6.1.2": version: 6.1.2 resolution: "cssnano@npm:6.1.2" @@ -14492,6 +14982,17 @@ __metadata: languageName: node linkType: hard +"data-view-buffer@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-buffer@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10/5919a39a18ee919573336158fd162fdf8ada1bc23a139f28543fd45fac48e0ea4a3ad3bfde91de124d4106e65c4a7525f6a84c20ba0797ec890a77a96d13a82a + languageName: node + linkType: hard + "data-view-buffer@npm:^1.0.2": version: 1.0.2 resolution: "data-view-buffer@npm:1.0.2" @@ -14503,6 +15004,17 @@ __metadata: languageName: node linkType: hard +"data-view-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10/f33c65e58d8d0432ad79761f2e8a579818d724b5dc6dc4e700489b762d963ab30873c0f1c37d8f2ed12ef51c706d1195f64422856d25f067457aeec50cc40aac + languageName: node + linkType: hard + "data-view-byte-length@npm:^1.0.2": version: 1.0.2 resolution: "data-view-byte-length@npm:1.0.2" @@ -14514,6 +15026,17 @@ __metadata: languageName: node linkType: hard +"data-view-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "data-view-byte-offset@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10/96f34f151bf02affb7b9f98762fb7aca1dd5f4553cb57b80bce750ca609c15d33ca659568ef1d422f7e35680736cbccb893a3d4b012760c758c1446bbdc4c6db + languageName: node + linkType: hard + "data-view-byte-offset@npm:^1.0.1": version: 1.0.1 resolution: "data-view-byte-offset@npm:1.0.1" @@ -14564,15 +15087,15 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, 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.7, debug@npm:^4.4.0": - version: 4.4.0 - resolution: "debug@npm:4.4.0" +"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.5 + resolution: "debug@npm:4.3.5" dependencies: - ms: "npm:^2.1.3" + ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true - checksum: 10/1847944c2e3c2c732514b93d11886575625686056cd765336212dc15de2d2b29612b6cd80e1afba767bb8e1803b778caf9973e98169ef1a24a7a7009e1820367 + checksum: 10/cb6eab424c410e07813ca1392888589972ce9a32b8829c6508f5e1f25f3c3e70a76731610ae55b4bbe58d1a2fffa1424b30e97fa8d394e49cd2656a9643aedd2 languageName: node linkType: hard @@ -14606,6 +15129,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.0.0, debug@npm:^4.3.7, debug@npm:^4.4.0": + version: 4.4.0 + resolution: "debug@npm:4.4.0" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10/1847944c2e3c2c732514b93d11886575625686056cd765336212dc15de2d2b29612b6cd80e1afba767bb8e1803b778caf9973e98169ef1a24a7a7009e1820367 + languageName: node + linkType: hard + "decamelize@npm:^1.2.0": version: 1.2.0 resolution: "decamelize@npm:1.2.0" @@ -14788,7 +15323,7 @@ __metadata: languageName: node linkType: hard -"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": +"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.1": version: 1.2.1 resolution: "define-properties@npm:1.2.1" dependencies: @@ -15293,6 +15828,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.820": + version: 1.4.827 + resolution: "electron-to-chromium@npm:1.4.827" + checksum: 10/7fa44aeebc5548874d33e417579d998d8e9a3d7b07fae22429ee7de5866c73b3158d56969146df3dcf44a222dcd91972ee786d0427f461e0c98bff79e408e782 + languageName: node + linkType: hard + "electron-to-chromium@npm:^1.5.73": version: 1.5.119 resolution: "electron-to-chromium@npm:1.5.119" @@ -15454,7 +15996,149 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.2, es-abstract@npm:^1.17.5, es-abstract@npm:^1.19.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9": +"es-abstract@npm:^1.17.2, es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1, es-abstract@npm:^1.19.5": + version: 1.20.1 + resolution: "es-abstract@npm:1.20.1" + dependencies: + call-bind: "npm:^1.0.2" + es-to-primitive: "npm:^1.2.1" + function-bind: "npm:^1.1.1" + function.prototype.name: "npm:^1.1.5" + get-intrinsic: "npm:^1.1.1" + get-symbol-description: "npm:^1.0.0" + has: "npm:^1.0.3" + has-property-descriptors: "npm:^1.0.0" + has-symbols: "npm:^1.0.3" + internal-slot: "npm:^1.0.3" + is-callable: "npm:^1.2.4" + is-negative-zero: "npm:^2.0.2" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.2" + is-string: "npm:^1.0.7" + is-weakref: "npm:^1.0.2" + object-inspect: "npm:^1.12.0" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.2" + regexp.prototype.flags: "npm:^1.4.3" + string.prototype.trimend: "npm:^1.0.5" + string.prototype.trimstart: "npm:^1.0.5" + unbox-primitive: "npm:^1.0.2" + checksum: 10/33fca95bb5af8fc662e5314d9328bbfc1fac7b506b97e2c0b100cb8b143ec4250f93e27708b0c2df19cbf1778092a7cce2f08a375fe86c04bea6feb03fbb478d + languageName: node + linkType: hard + +"es-abstract@npm:^1.17.5, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5": + version: 1.23.5 + resolution: "es-abstract@npm:1.23.5" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + arraybuffer.prototype.slice: "npm:^1.0.3" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + data-view-buffer: "npm:^1.0.1" + data-view-byte-length: "npm:^1.0.1" + data-view-byte-offset: "npm:^1.0.0" + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-set-tostringtag: "npm:^2.0.3" + es-to-primitive: "npm:^1.2.1" + function.prototype.name: "npm:^1.1.6" + get-intrinsic: "npm:^1.2.4" + get-symbol-description: "npm:^1.0.2" + globalthis: "npm:^1.0.4" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.0.3" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.2" + internal-slot: "npm:^1.0.7" + is-array-buffer: "npm:^3.0.4" + is-callable: "npm:^1.2.7" + is-data-view: "npm:^1.0.1" + is-negative-zero: "npm:^2.0.3" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.3" + is-string: "npm:^1.0.7" + is-typed-array: "npm:^1.1.13" + is-weakref: "npm:^1.0.2" + object-inspect: "npm:^1.13.3" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.5" + regexp.prototype.flags: "npm:^1.5.3" + safe-array-concat: "npm:^1.1.2" + safe-regex-test: "npm:^1.0.3" + string.prototype.trim: "npm:^1.2.9" + string.prototype.trimend: "npm:^1.0.8" + string.prototype.trimstart: "npm:^1.0.8" + typed-array-buffer: "npm:^1.0.2" + typed-array-byte-length: "npm:^1.0.1" + typed-array-byte-offset: "npm:^1.0.2" + typed-array-length: "npm:^1.0.6" + unbox-primitive: "npm:^1.0.2" + which-typed-array: "npm:^1.1.15" + checksum: 10/2170afde7e1d2497586ad74176c2e12196db947fb1b3287fc097781a871b75ebe3aef5247e951e3bb3972a830b8d0eaa82a509518836a6d9f9fb4934b9294467 + languageName: node + linkType: hard + +"es-abstract@npm:^1.23.6": + version: 1.23.8 + resolution: "es-abstract@npm:1.23.8" + dependencies: + array-buffer-byte-length: "npm:^1.0.2" + arraybuffer.prototype.slice: "npm:^1.0.4" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + data-view-buffer: "npm:^1.0.2" + data-view-byte-length: "npm:^1.0.2" + data-view-byte-offset: "npm:^1.0.1" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-set-tostringtag: "npm:^2.0.3" + es-to-primitive: "npm:^1.3.0" + function.prototype.name: "npm:^1.1.8" + get-intrinsic: "npm:^1.2.6" + get-symbol-description: "npm:^1.1.0" + globalthis: "npm:^1.0.4" + gopd: "npm:^1.2.0" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + internal-slot: "npm:^1.1.0" + is-array-buffer: "npm:^3.0.5" + is-callable: "npm:^1.2.7" + is-data-view: "npm:^1.0.2" + is-regex: "npm:^1.2.1" + is-shared-array-buffer: "npm:^1.0.4" + is-string: "npm:^1.1.1" + is-typed-array: "npm:^1.1.15" + is-weakref: "npm:^1.1.0" + math-intrinsics: "npm:^1.1.0" + object-inspect: "npm:^1.13.3" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.7" + own-keys: "npm:^1.0.0" + regexp.prototype.flags: "npm:^1.5.3" + safe-array-concat: "npm:^1.1.3" + safe-push-apply: "npm:^1.0.0" + safe-regex-test: "npm:^1.1.0" + string.prototype.trim: "npm:^1.2.10" + string.prototype.trimend: "npm:^1.0.9" + string.prototype.trimstart: "npm:^1.0.8" + typed-array-buffer: "npm:^1.0.3" + typed-array-byte-length: "npm:^1.0.3" + typed-array-byte-offset: "npm:^1.0.4" + typed-array-length: "npm:^1.0.7" + unbox-primitive: "npm:^1.1.0" + which-typed-array: "npm:^1.1.18" + checksum: 10/28423ac051f545aea19014c8e7f723eb494b4ed393063fe839d6229a9602adc2d575dad2d44a03adc28969903f3cac1eaf5f520caffe447d3b87fd126ba69228 + languageName: node + linkType: hard + +"es-abstract@npm:^1.23.9": version: 1.23.9 resolution: "es-abstract@npm:1.23.9" dependencies: @@ -15527,7 +16211,7 @@ __metadata: languageName: node linkType: hard -"es-errors@npm:^1.3.0": +"es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": version: 1.3.0 resolution: "es-errors@npm:1.3.0" checksum: 10/96e65d640156f91b707517e8cdc454dd7d47c32833aa3e85d79f24f9eb7ea85f39b63e36216ef0114996581969b59fe609a94e30316b08f5f4df1d44134cf8d5 @@ -15612,7 +16296,7 @@ __metadata: languageName: node linkType: hard -"es-to-primitive@npm:^1.3.0": +"es-to-primitive@npm:^1.2.1, es-to-primitive@npm:^1.3.0": version: 1.3.0 resolution: "es-to-primitive@npm:1.3.0" dependencies: @@ -15855,6 +16539,13 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.1.2": + version: 3.1.2 + resolution: "escalade@npm:3.1.2" + checksum: 10/a1e07fea2f15663c30e40b9193d658397846ffe28ce0a3e4da0d8e485fedfeca228ab846aee101a05015829adf39f9934ff45b2a3fca47bed37a29646bd05cd3 + languageName: node + linkType: hard + "escape-goat@npm:^2.0.0": version: 2.1.1 resolution: "escape-goat@npm:2.1.1" @@ -17481,13 +18172,25 @@ __metadata: languageName: node linkType: hard -"function-bind@npm:^1.1.2": +"function-bind@npm:^1.1.1, function-bind@npm:^1.1.2": version: 1.1.2 resolution: "function-bind@npm:1.1.2" checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 languageName: node linkType: hard +"function.prototype.name@npm:^1.1.5": + version: 1.1.5 + resolution: "function.prototype.name@npm:1.1.5" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.19.0" + functions-have-names: "npm:^1.2.2" + checksum: 10/5d426e5a38ac41747bcfce6191e0ec818ed18678c16cfc36b5d1ca87f56ff98c4ce958ee2c1ea2a18dc3da989844a37b1065311e2d2ae4cf12da8f82418b686b + languageName: node + linkType: hard + "function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": version: 1.1.8 resolution: "function.prototype.name@npm:1.1.8" @@ -17509,7 +18212,7 @@ __metadata: languageName: node linkType: hard -"functions-have-names@npm:^1.2.3": +"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" checksum: 10/0ddfd3ed1066a55984aaecebf5419fbd9344a5c38dd120ffb0739fac4496758dcf371297440528b115e4367fc46e3abc86a2cc0ff44612181b175ae967a11a05 @@ -17546,7 +18249,37 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": +"get-intrinsic@npm:^1.1.0": + version: 1.2.2 + resolution: "get-intrinsic@npm:1.2.2" + dependencies: + function-bind: "npm:^1.1.2" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10/aa96db4f809734d26d49b59bc8669d73a0ae792da561514e987735573a1dfaede516cd102f217a078ea2b42d4c4fb1f83d487932cb15d49826b726cc9cd4470b + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6": + version: 1.2.6 + resolution: "get-intrinsic@npm:1.2.6" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + dunder-proto: "npm:^1.0.0" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + function-bind: "npm:^1.1.2" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.0.0" + checksum: 10/a1ffae6d7893a6fa0f4d1472adbc85095edd6b3b0943ead97c3738539cecb19d422ff4d48009eed8c3c27ad678c2b1e38a83b1a1e96b691d13ed8ecefca1068d + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": version: 1.3.0 resolution: "get-intrinsic@npm:1.3.0" dependencies: @@ -17564,6 +18297,35 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.2.3": + version: 1.2.5 + resolution: "get-intrinsic@npm:1.2.5" + dependencies: + call-bind-apply-helpers: "npm:^1.0.0" + dunder-proto: "npm:^1.0.0" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + checksum: 10/3f124f0e811326dab513b5478e4744e0fa95427752d78b28881c22de2b9d6aac1a08a7930cb700bbb327acf9662a06131e65a66c8bb6ccc9bbc6d956a7c7cefd + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.4": + version: 1.2.4 + resolution: "get-intrinsic@npm:1.2.4" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10/85bbf4b234c3940edf8a41f4ecbd4e25ce78e5e6ad4e24ca2f77037d983b9ef943fd72f00f3ee97a49ec622a506b67db49c36246150377efcda1c9eb03e5f06d + languageName: node + linkType: hard + "get-nonce@npm:^1.0.0": version: 1.0.1 resolution: "get-nonce@npm:1.0.1" @@ -17627,6 +18389,27 @@ __metadata: languageName: node linkType: hard +"get-symbol-description@npm:^1.0.0": + version: 1.0.0 + resolution: "get-symbol-description@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.1.1" + checksum: 10/7e5f298afe0f0872747dce4a949ce490ebc5d6dd6aefbbe5044543711c9b19a4dfaebdbc627aee99e1299d58a435b2fbfa083458c1d58be6dc03a3bada24d359 + languageName: node + linkType: hard + +"get-symbol-description@npm:^1.0.2": + version: 1.0.2 + resolution: "get-symbol-description@npm:1.0.2" + dependencies: + call-bind: "npm:^1.0.5" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + checksum: 10/e1cb53bc211f9dbe9691a4f97a46837a553c4e7caadd0488dc24ac694db8a390b93edd412b48dcdd0b4bbb4c595de1709effc75fc87c0839deedc6968f5bd973 + languageName: node + linkType: hard + "get-symbol-description@npm:^1.1.0": version: 1.1.0 resolution: "get-symbol-description@npm:1.1.0" @@ -17712,7 +18495,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -17728,6 +18511,21 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.3.7": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.3.5" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10/38bdb2c9ce75eb5ed168f309d4ed05b0798f640b637034800a6bf306f39d35409bf278b0eaaffaec07591085d3acb7184a201eae791468f0f617771c2486a6a8 + languageName: node + linkType: hard + "glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -18012,10 +18810,17 @@ __metadata: languageName: node linkType: hard -"graphql@npm:^15.4.0, graphql@npm:^15.5.0, graphql@npm:^15.5.1": - version: 15.10.1 - resolution: "graphql@npm:15.10.1" - checksum: 10/49177f52c1fbac022866d39bb15040122da4c3ccd12644233b20edfcb1f76aa92aa92f2a82af4668101d8f726112fda111cb11a12feb05635cd689443a7aafb8 +"graphql@npm:^15.4.0, graphql@npm:^15.5.1": + version: 15.9.0 + resolution: "graphql@npm:15.9.0" + checksum: 10/ce1f50672bcb369395d07a47048bcbb429ed1ce06dbcafb7a0999df791cb7aa7206be21497907973dbc8a01df3cd7f632f43c583f248538f186f5adfa1a0d1c5 + languageName: node + linkType: hard + +"graphql@npm:^15.5.0": + version: 15.5.0 + resolution: "graphql@npm:15.5.0" + checksum: 10/77e750f639b681ce24fd07aa199e22ffd9399fce7613dd26d1ec1cc67be5fb3c1f608ef267a47f61be7b70019dbbac602ef796a6d93e3d9ec3583d3c2694f7c3 languageName: node linkType: hard @@ -18109,7 +18914,14 @@ __metadata: languageName: node linkType: hard -"has-proto@npm:^1.2.0": +"has-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "has-proto@npm:1.0.1" + checksum: 10/eab2ab0ed1eae6d058b9bbc4c1d99d2751b29717be80d02fd03ead8b62675488de0c7359bc1fdd4b87ef6fd11e796a9631ad4d7452d9324fdada70158c2e5be7 + languageName: node + linkType: hard + +"has-proto@npm:^1.0.3, has-proto@npm:^1.2.0": version: 1.2.0 resolution: "has-proto@npm:1.2.0" dependencies: @@ -18148,7 +18960,16 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.2": +"has@npm:^1.0.3": + version: 1.0.3 + resolution: "has@npm:1.0.3" + dependencies: + function-bind: "npm:^1.1.1" + checksum: 10/a449f3185b1d165026e8d25f6a8c3390bd25c201ff4b8c1aaf948fc6a5fcfd6507310b8c00c13a3325795ea9791fcc3d79d61eafa313b5750438fc19183df57b + languageName: node + linkType: hard + +"hasown@npm:^2.0.0, hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -18649,7 +19470,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2, https-proxy-agent@npm:^7.0.5": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" dependencies: @@ -18659,6 +19480,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.2": + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab + languageName: node + linkType: hard + "human-signals@npm:^1.1.1": version: 1.1.1 resolution: "human-signals@npm:1.1.1" @@ -18781,10 +19612,17 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.0.4, ignore@npm:^5.1.1, ignore@npm:^5.1.4, ignore@npm:^5.2.0, ignore@npm:^5.2.4": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 +"ignore@npm:^5.0.4, ignore@npm:^5.1.1, ignore@npm:^5.1.4, ignore@npm:^5.2.0": + version: 5.3.1 + resolution: "ignore@npm:5.3.1" + checksum: 10/0a884c2fbc8c316f0b9f92beaf84464253b73230a4d4d286697be45fca081199191ca33e1c2e82d9e5f851f5e9a48a78e25a35c951e7eb41e59f150db3530065 + languageName: node + linkType: hard + +"ignore@npm:^5.2.4": + version: 5.3.0 + resolution: "ignore@npm:5.3.0" + checksum: 10/51594355cea4c6ad6b28b3b85eb81afa7b988a1871feefd7062baf136c95aa06760ee934fa9590e43d967bd377ce84a4cf6135fbeb6063e063f1182a0e9a3bcd languageName: node linkType: hard @@ -18813,13 +19651,20 @@ __metadata: languageName: node linkType: hard -"immer@npm:^9.0.21, immer@npm:^9.0.7": +"immer@npm:^9.0.21": version: 9.0.21 resolution: "immer@npm:9.0.21" checksum: 10/8455d6b4dc8abfe40f06eeec9bcc944d147c81279424c0f927a4d4905ae34e5af19ab6da60bcc700c14f51c452867d7089b3b9236f5a9a2248e39b4a09ee89de languageName: node linkType: hard +"immer@npm:^9.0.7": + version: 9.0.7 + resolution: "immer@npm:9.0.7" + checksum: 10/59d28834943d17153864a4c52c7c21c776b7c8e0aa75411c1e278aabe1f4a54080aca163df715c078bc77d77dc2d156ec212e5113903b155fc5e344ab2714696 + languageName: node + linkType: hard + "immutable@npm:^3.8.2": version: 3.8.2 resolution: "immutable@npm:3.8.2" @@ -19031,7 +19876,7 @@ __metadata: languageName: node linkType: hard -"inquirer@npm:^8.1.1, inquirer@npm:^8.2.0": +"inquirer@npm:^8.1.1": version: 8.2.6 resolution: "inquirer@npm:8.2.6" dependencies: @@ -19054,6 +19899,50 @@ __metadata: languageName: node linkType: hard +"inquirer@npm:^8.2.0": + version: 8.2.2 + resolution: "inquirer@npm:8.2.2" + dependencies: + ansi-escapes: "npm:^4.2.1" + chalk: "npm:^4.1.1" + cli-cursor: "npm:^3.1.0" + cli-width: "npm:^3.0.0" + external-editor: "npm:^3.0.3" + figures: "npm:^3.0.0" + lodash: "npm:^4.17.21" + mute-stream: "npm:0.0.8" + ora: "npm:^5.4.1" + run-async: "npm:^2.4.0" + rxjs: "npm:^7.5.5" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + through: "npm:^2.3.6" + checksum: 10/1f36989370f79c9260b1eb84d7c7ce6decd7a616542443713d8ca7d4578c8f26169202824ae593509cfd8548140e6e32dfd11fcedebb026d828722e926af961c + languageName: node + linkType: hard + +"internal-slot@npm:^1.0.3": + version: 1.0.3 + resolution: "internal-slot@npm:1.0.3" + dependencies: + get-intrinsic: "npm:^1.1.0" + has: "npm:^1.0.3" + side-channel: "npm:^1.0.4" + checksum: 10/1c6d22f7977b325e51387191a992a553bf7c380db548a32c09bbb4563a799d739d3ef629841234290a032dc555ca7e89178e8a35404dad77b55f2676be8a1ba2 + languageName: node + linkType: hard + +"internal-slot@npm:^1.0.7": + version: 1.0.7 + resolution: "internal-slot@npm:1.0.7" + dependencies: + es-errors: "npm:^1.3.0" + hasown: "npm:^2.0.0" + side-channel: "npm:^1.0.4" + checksum: 10/3e66720508831153ecf37d13def9f6856f9f2960989ec8a0a0476c98f887fca9eff0163127466485cb825c900c2d6fc601aa9117b7783b90ffce23a71ea5d053 + languageName: node + linkType: hard + "internal-slot@npm:^1.1.0": version: 1.1.0 resolution: "internal-slot@npm:1.1.0" @@ -19215,6 +20104,13 @@ __metadata: languageName: node linkType: hard +"is-callable@npm:^1.2.4": + version: 1.2.4 + resolution: "is-callable@npm:1.2.4" + checksum: 10/4e3d8c08208475e74a4108a9dc44dbcb74978782e38a1d1b55388342a4824685765d95917622efa2ca1483f7c4dbec631dd979cbb3ebd239f57a75c83a46d99f + languageName: node + linkType: hard + "is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" @@ -19427,6 +20323,20 @@ __metadata: languageName: node linkType: hard +"is-negative-zero@npm:^2.0.2": + version: 2.0.2 + resolution: "is-negative-zero@npm:2.0.2" + checksum: 10/edbec1a9e6454d68bf595a114c3a72343d2d0be7761d8173dae46c0b73d05bb8fe9398c85d121e7794a66467d2f40b4a610b0be84cd804262d234fc634c86131 + languageName: node + linkType: hard + +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10/8fe5cffd8d4fb2ec7b49d657e1691889778d037494c6f40f4d1a524cadd658b4b53ad7b6b73a59bcb4b143ae9a3d15829af864b2c0f9d65ac1e678c4c80f17e5 + languageName: node + linkType: hard + "is-node-process@npm:^1.0.1, is-node-process@npm:^1.2.0": version: 1.2.0 resolution: "is-node-process@npm:1.2.0" @@ -19620,6 +20530,15 @@ __metadata: languageName: node linkType: hard +"is-shared-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "is-shared-array-buffer@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.7" + checksum: 10/bc5402900dc62b96ebb2548bf5b0a0bcfacc2db122236fe3ab3b3e3c884293a0d5eb777e73f059bcbf8dc8563bb65eae972fee0fb97e38a9ae27c8678f62bcfe + languageName: node + linkType: hard + "is-ssh@npm:^1.3.0": version: 1.4.1 resolution: "is-ssh@npm:1.4.1" @@ -19926,6 +20845,19 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^2.3.5": + version: 2.3.6 + resolution: "jackspeak@npm:2.3.6" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10/6e6490d676af8c94a7b5b29b8fd5629f21346911ebe2e32931c2a54210134408171c24cee1a109df2ec19894ad04a429402a8438cbf5cc2794585d35428ace76 + languageName: node + linkType: hard + "jackspeak@npm:^3.1.2": version: 3.4.3 resolution: "jackspeak@npm:3.4.3" @@ -20976,16 +21908,7 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^3.0.2": - version: 3.1.0 - resolution: "jsesc@npm:3.1.0" - bin: - jsesc: bin/jsesc - checksum: 10/20bd37a142eca5d1794f354db8f1c9aeb54d85e1f5c247b371de05d23a9751ecd7bd3a9c4fc5298ea6fa09a100dafb4190fa5c98c6610b75952c3487f3ce7967 - languageName: node - linkType: hard - -"jsesc@npm:~3.0.2": +"jsesc@npm:^3.0.2, jsesc@npm:~3.0.2": version: 3.0.2 resolution: "jsesc@npm:3.0.2" bin: @@ -21853,6 +22776,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.2.0 + resolution: "lru-cache@npm:10.2.0" + checksum: 10/502ec42c3309c0eae1ce41afca471f831c278566d45a5273a0c51102dee31e0e250a62fa9029c3370988df33a14188a38e682c16143b794de78668de3643e302 + languageName: node + linkType: hard + "lz-string@npm:^1.5.0": version: 1.5.0 resolution: "lz-string@npm:1.5.0" @@ -22019,7 +22949,7 @@ __metadata: languageName: node linkType: hard -"math-intrinsics@npm:^1.1.0": +"math-intrinsics@npm:^1.0.0, math-intrinsics@npm:^1.1.0": version: 1.1.0 resolution: "math-intrinsics@npm:1.1.0" checksum: 10/11df2eda46d092a6035479632e1ec865b8134bdfc4bd9e571a656f4191525404f13a283a515938c3a8de934dbfd9c09674d9da9fa831e6eb7e22b50b197d2edd @@ -23319,7 +24249,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:9.0.3": +"minimatch@npm:9.0.3, minimatch@npm:^9.0.1": version: 9.0.3 resolution: "minimatch@npm:9.0.3" dependencies: @@ -23710,7 +24640,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23, nanoid@npm:^3.3.8": +"nanoid@npm:^3.1.23": version: 3.3.10 resolution: "nanoid@npm:3.3.10" bin: @@ -23719,6 +24649,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.7": + version: 3.3.8 + resolution: "nanoid@npm:3.3.8" + bin: + nanoid: bin/nanoid.cjs + checksum: 10/2d1766606cf0d6f47b6f0fdab91761bb81609b2e3d367027aff45e6ee7006f660fb7e7781f4a34799fe6734f1268eeed2e37a5fdee809ade0c2d4eb11b0f9c40 + languageName: node + linkType: hard + "nanoid@npm:^5.1.0": version: 5.1.4 resolution: "nanoid@npm:5.1.4" @@ -23942,6 +24881,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 10/0f7607ec7db5ef1dc616899a5f24ae90c869b6a54c2d4f36ff6d84a282ab9343c7ff3ca3670fe4669171bb1e8a9b3e286e1ef1c131f09a83d70554f855d54f24 + languageName: node + linkType: hard + "node-releases@npm:^2.0.19": version: 2.0.19 resolution: "node-releases@npm:2.0.19" @@ -24209,6 +25155,13 @@ __metadata: languageName: node linkType: hard +"object-inspect@npm:^1.12.0": + version: 1.12.2 + resolution: "object-inspect@npm:1.12.2" + checksum: 10/aa11100d45fa919b36448347d4f7c8a78b0247886881db56a2026b512c4042a9749e64894519b00a4db8c6e2b713a965b5ceaa3b59324aeb3da007c54a33bc58 + languageName: node + linkType: hard + "object-inspect@npm:^1.13.3": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -24247,6 +25200,18 @@ __metadata: languageName: node linkType: hard +"object.assign@npm:^4.1.2, object.assign@npm:^4.1.5": + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" + dependencies: + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + has-symbols: "npm:^1.0.3" + object-keys: "npm:^1.1.1" + checksum: 10/dbb22da4cda82e1658349ea62b80815f587b47131b3dd7a4ab7f84190ab31d206bbd8fe7e26ae3220c55b65725ac4529825f6142154211220302aa6b1518045d + languageName: node + linkType: hard + "object.entries@npm:^1.1.8": version: 1.1.9 resolution: "object.entries@npm:1.1.9" @@ -24485,14 +25450,21 @@ __metadata: languageName: node linkType: hard -"outvariant@npm:^1.2.0, outvariant@npm:^1.2.1, outvariant@npm:^1.4.0, outvariant@npm:^1.4.2, outvariant@npm:^1.4.3": +"outvariant@npm:^1.2.0, outvariant@npm:^1.4.3": version: 1.4.3 resolution: "outvariant@npm:1.4.3" checksum: 10/3a7582745850cb344d49641867a4c080858c54f4091afd91b9c0765ba6e471c2bc841348f0fff344845ddd0a4db42fd5d68c6f7ebaf32d4b676a3a9987b2488a languageName: node linkType: hard -"own-keys@npm:^1.0.1": +"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0, outvariant@npm:^1.4.2": + version: 1.4.2 + resolution: "outvariant@npm:1.4.2" + checksum: 10/f16ba035fb65d1cbe7d2e06693dd42183c46bc8456713d9ddb5182d067defa7d78217edab0a2d3e173d3bacd627b2bd692195c7087c225b82548fbf52c677b38 + languageName: node + linkType: hard + +"own-keys@npm:^1.0.0, own-keys@npm:^1.0.1": version: 1.0.1 resolution: "own-keys@npm:1.0.1" dependencies: @@ -24937,6 +25909,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.10.1": + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" + dependencies: + lru-cache: "npm:^9.1.1 || ^10.0.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10/eebfb8304fef1d4f7e1486df987e4fd77413de4fce16508dea69fcf8eb318c09a6b15a7a2f4c22877cec1cb7ecbd3071d18ca9de79eeece0df874a00f1f0bdc8 + languageName: node + linkType: hard + "path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" @@ -25075,13 +26057,20 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.1, pirates@npm:^4.0.4, 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" @@ -25312,6 +26301,20 @@ __metadata: languageName: node linkType: hard +"postcss-colormin@npm:^5.3.0": + version: 5.3.0 + resolution: "postcss-colormin@npm:5.3.0" + dependencies: + browserslist: "npm:^4.16.6" + caniuse-api: "npm:^3.0.0" + colord: "npm:^2.9.1" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/3d3e3cc25071407fb73d68541ca1039ebd154fceb649041461a8a3cab0400cc89b42dbb34a4eeaf573be4ba2370ce23af5e01aff5e03a8d72275f40605577212 + languageName: node + linkType: hard + "postcss-colormin@npm:^5.3.1": version: 5.3.1 resolution: "postcss-colormin@npm:5.3.1" @@ -25340,6 +26343,18 @@ __metadata: languageName: node linkType: hard +"postcss-convert-values@npm:^5.1.2": + version: 5.1.2 + resolution: "postcss-convert-values@npm:5.1.2" + dependencies: + browserslist: "npm:^4.20.3" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/54bbf702164a50407ff318e7877661b72acdc8e04c293a884cb258b2ed58483bcae7ce31fdc3e74e4bdd48262e1799230947684b3732f92c75b4aeb6943544a7 + languageName: node + linkType: hard + "postcss-convert-values@npm:^5.1.3": version: 5.1.3 resolution: "postcss-convert-values@npm:5.1.3" @@ -25872,6 +26887,18 @@ __metadata: languageName: node linkType: hard +"postcss-merge-longhand@npm:^5.1.6": + version: 5.1.6 + resolution: "postcss-merge-longhand@npm:5.1.6" + dependencies: + postcss-value-parser: "npm:^4.2.0" + stylehacks: "npm:^5.1.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/990efea68de63c88ea6c6f9017a03d9907bd05cf3ff35384bd3c334aba020ad5179f466a24554b4c538243773af984d555a9c81669b4483e5d7722522aa0fe04 + languageName: node + linkType: hard + "postcss-merge-longhand@npm:^5.1.7": version: 5.1.7 resolution: "postcss-merge-longhand@npm:5.1.7" @@ -25896,6 +26923,20 @@ __metadata: languageName: node linkType: hard +"postcss-merge-rules@npm:^5.1.2": + version: 5.1.2 + resolution: "postcss-merge-rules@npm:5.1.2" + dependencies: + browserslist: "npm:^4.16.6" + caniuse-api: "npm:^3.0.0" + cssnano-utils: "npm:^3.1.0" + postcss-selector-parser: "npm:^6.0.5" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/2eb44c7bcbc6f04a4799f67f3978242eef39f43f7fa2c33727fdcb15773d17c7228aa1766bb74d3187023ae0b65d467e63684ada4b0b431f00bba790c5ec9a44 + languageName: node + linkType: hard + "postcss-merge-rules@npm:^5.1.4": version: 5.1.4 resolution: "postcss-merge-rules@npm:5.1.4" @@ -25972,6 +27013,19 @@ __metadata: languageName: node linkType: hard +"postcss-minify-params@npm:^5.1.3": + version: 5.1.3 + resolution: "postcss-minify-params@npm:5.1.3" + dependencies: + browserslist: "npm:^4.16.6" + cssnano-utils: "npm:^3.1.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/2d218f6b82474310c866b690210595a5e6a4c695f174f9100b018adb4a171bd67b1adaba26c241b3d41a4ea0f4962e0f5a77cf12ae60d9db76f80b0c7cbd6bcd + languageName: node + linkType: hard + "postcss-minify-params@npm:^5.1.4": version: 5.1.4 resolution: "postcss-minify-params@npm:5.1.4" @@ -26246,6 +27300,18 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-unicode@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-normalize-unicode@npm:5.1.0" + dependencies: + browserslist: "npm:^4.16.6" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/3570c90050f190811b5dbf7b4cf4f30f0b627c1ba5fbe5ad332e8b0aa7ef14b3d0aa2af1cb1074d0267aec8c9771e28866d867c8a8a0c433b6c34e50445f9c16 + languageName: node + linkType: hard + "postcss-normalize-unicode@npm:^5.1.1": version: 5.1.1 resolution: "postcss-normalize-unicode@npm:5.1.1" @@ -26589,6 +27655,18 @@ __metadata: languageName: node linkType: hard +"postcss-reduce-initial@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-reduce-initial@npm:5.1.0" + dependencies: + browserslist: "npm:^4.16.6" + caniuse-api: "npm:^3.0.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/56a784fb69ae17edbdb7b9fd93dc36c7ff52889f86153017a47216ec792de23b22a8c3f6a4a5dc6fed88bb13c88b47a5f7b4a8fd8d3f2edee0cab07db5e0f057 + languageName: node + linkType: hard + "postcss-reduce-initial@npm:^5.1.2": version: 5.1.2 resolution: "postcss-reduce-initial@npm:5.1.2" @@ -26666,7 +27744,17 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9, postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2": +"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": + version: 6.0.10 + resolution: "postcss-selector-parser@npm:6.0.10" + dependencies: + cssesc: "npm:^3.0.0" + util-deprecate: "npm:^1.0.2" + checksum: 10/f8ad9beb764a64b51a8027650e745a44ed7198f0b968b823db9563a54990924bcf9eb6fb59fbbb7eb05a89b2b6a24b81b2b7d60ecadda15b04a0024c7663f436 + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2": version: 6.1.2 resolution: "postcss-selector-parser@npm:6.1.2" dependencies: @@ -26769,14 +27857,25 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.2.1, postcss@npm:^8.3.5, postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.26, postcss@npm:^8.4.33, postcss@npm:^8.4.38, postcss@npm:^8.4.4, postcss@npm:^8.4.43, postcss@npm:^8.4.47": - version: 8.5.3 - resolution: "postcss@npm:8.5.3" +"postcss@npm:^8.2.1, postcss@npm:^8.3.5, postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.26, postcss@npm:^8.4.33, postcss@npm:^8.4.4, postcss@npm:^8.4.43, postcss@npm:^8.4.47": + version: 8.4.49 + resolution: "postcss@npm:8.4.49" dependencies: - nanoid: "npm:^3.3.8" + nanoid: "npm:^3.3.7" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/6d7e21a772e8b05bf102636918654dac097bac013f0dc8346b72ac3604fc16829646f94ea862acccd8f82e910b00e2c11c1f0ea276543565d278c7ca35516a7c + checksum: 10/28fe1005b1339870e0a5006375ba5ac1213fd69800f79e7db09c398e074421ba6e162898e94f64942fed554037fd292db3811d87835d25ab5ef7f3c9daacb6ca + languageName: node + linkType: hard + +"postcss@npm:^8.4.38": + 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.2.0" + checksum: 10/6e44a7ed835ffa9a2b096e8d3e5dfc6bcf331a25c48aeb862dd54e3aaecadf814fa22be224fd308f87d08adf2299164f88c5fd5ab1c4ef6cbd693ceb295377f4 languageName: node linkType: hard @@ -26810,7 +27909,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.2.1, prettier@npm:^3.2.5, prettier@npm:^3.3.3": +"prettier@npm:^3.2.1": version: 3.5.3 resolution: "prettier@npm:3.5.3" bin: @@ -26819,6 +27918,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.2.5, prettier@npm:^3.3.3": + version: 3.4.2 + resolution: "prettier@npm:3.4.2" + bin: + prettier: bin/prettier.cjs + checksum: 10/a3e806fb0b635818964d472d35d27e21a4e17150c679047f5501e1f23bd4aa806adf660f0c0d35214a210d5d440da6896c2e86156da55f221a57938278dc326e + languageName: node + linkType: hard + "pretty-bytes@npm:^3.0.0": version: 3.0.1 resolution: "pretty-bytes@npm:3.0.1" @@ -27398,7 +28506,7 @@ __metadata: languageName: node linkType: hard -"react-fast-compare@npm:^3.2.0, react-fast-compare@npm:^3.2.2": +"react-fast-compare@npm:^3.2.0": version: 3.2.2 resolution: "react-fast-compare@npm:3.2.2" checksum: 10/a6826180ba75cefba1c8d3ac539735f9b627ca05d3d307fe155487f5d0228d376dac6c9708d04a283a7b9f9aee599b637446635b79c8c8753d0b4eece56c125c @@ -27421,16 +28529,19 @@ __metadata: languageName: node linkType: hard -"react-helmet-async@npm:*": - version: 2.0.5 - resolution: "react-helmet-async@npm:2.0.5" +"react-helmet-async@npm:*, react-helmet-async@npm:^1.3.0": + version: 1.3.0 + resolution: "react-helmet-async@npm:1.3.0" dependencies: + "@babel/runtime": "npm:^7.12.5" invariant: "npm:^2.2.4" - react-fast-compare: "npm:^3.2.2" + prop-types: "npm:^15.7.2" + react-fast-compare: "npm:^3.2.0" shallowequal: "npm:^1.1.0" peerDependencies: react: ^16.6.0 || ^17.0.0 || ^18.0.0 - checksum: 10/03a8fbf4779c90899012809da09a6b174a2e11e2db4c7f4e61672903dd4e2f3bb732619da4254fc874c502251a07c8da01c752ed7d6df429c7718cf8451d176a + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + checksum: 10/73d6383dd5d5794cad3837cf6b71d7e23afa6f3ba745e50a9d0d6bf42ff0ab175e4292f250ffe757f4bd782e64c37c4583fb884340cd63891deb33e144628661 languageName: node linkType: hard @@ -27450,22 +28561,6 @@ __metadata: languageName: node linkType: hard -"react-helmet-async@npm:^1.3.0": - version: 1.3.0 - resolution: "react-helmet-async@npm:1.3.0" - dependencies: - "@babel/runtime": "npm:^7.12.5" - invariant: "npm:^2.2.4" - prop-types: "npm:^15.7.2" - react-fast-compare: "npm:^3.2.0" - shallowequal: "npm:^1.1.0" - peerDependencies: - react: ^16.6.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 - checksum: 10/73d6383dd5d5794cad3837cf6b71d7e23afa6f3ba745e50a9d0d6bf42ff0ab175e4292f250ffe757f4bd782e64c37c4583fb884340cd63891deb33e144628661 - languageName: node - linkType: hard - "react-icons@npm:3.11.0": version: 3.11.0 resolution: "react-icons@npm:3.11.0" @@ -28213,6 +29308,17 @@ __metadata: languageName: node linkType: hard +"regexp.prototype.flags@npm:^1.4.1, regexp.prototype.flags@npm:^1.4.3": + version: 1.4.3 + resolution: "regexp.prototype.flags@npm:1.4.3" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.1.3" + functions-have-names: "npm:^1.2.2" + checksum: 10/3cde7cd22f0cf9d04db0b77c825b14824c6e7d2ec77e17e8dba707ad1b3c70bb3f2ac5b4cad3c0932045ba61cb2fd1b8ef84a49140e952018bdae065cc001670 + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.3": version: 1.5.4 resolution: "regexp.prototype.flags@npm:1.5.4" @@ -29248,14 +30354,7 @@ __metadata: languageName: node linkType: hard -"sax@npm:^1.2.4": - version: 1.4.1 - resolution: "sax@npm:1.4.1" - checksum: 10/b1c784b545019187b53a0c28edb4f6314951c971e2963a69739c6ce222bfbc767e54d320e689352daba79b7d5e06d22b5d7113b99336219d6e93718e2f99d335 - languageName: node - linkType: hard - -"sax@npm:~1.2.4": +"sax@npm:^1.2.4, sax@npm:~1.2.4": version: 1.2.4 resolution: "sax@npm:1.2.4" checksum: 10/09b79ff6dc09689a24323352117c94593c69db348997b2af0edbd82fa08aba47d778055bf9616b57285bb73d25d790900c044bf631a8f10c8252412e3f3fe5dd @@ -29590,7 +30689,7 @@ __metadata: languageName: node linkType: hard -"set-function-length@npm:^1.2.2": +"set-function-length@npm:^1.2.1, set-function-length@npm:^1.2.2": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" dependencies: @@ -29957,7 +31056,7 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:5, socks-proxy-agent@npm:^5.0.0": +"socks-proxy-agent@npm:5": version: 5.0.1 resolution: "socks-proxy-agent@npm:5.0.1" dependencies: @@ -29968,6 +31067,17 @@ __metadata: languageName: node linkType: hard +"socks-proxy-agent@npm:^5.0.0": + version: 5.0.0 + resolution: "socks-proxy-agent@npm:5.0.0" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + socks: "npm:^2.3.3" + checksum: 10/c9f13e0c46f51403f07b0c034ba075e685643e5a1fb851c9e20393dff465afb0bc71bd760fc7e914d0b57792cff3eeef4eb86b6da7696afee453decb796cab8c + languageName: node + linkType: hard + "socks-proxy-agent@npm:^8.0.3": version: 8.0.5 resolution: "socks-proxy-agent@npm:8.0.5" @@ -30010,6 +31120,13 @@ __metadata: 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.2 resolution: "source-map-loader@npm:3.0.2" @@ -30056,13 +31173,20 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.7.0, source-map@npm:^0.7.3": +"source-map@npm:^0.7.0": version: 0.7.4 resolution: "source-map@npm:0.7.4" checksum: 10/a0f7c9b797eda93139842fd28648e868a9a03ea0ad0d9fa6602a0c1f17b7fb6a7dcca00c144476cccaeaae5042e99a285723b1a201e844ad67221bf5d428f1dc languageName: node linkType: hard +"source-map@npm:^0.7.3": + version: 0.7.3 + resolution: "source-map@npm:0.7.3" + checksum: 10/89c388902a1d94c897c3343b70d161a7f3cd86997512ad563274b8e25c8fd9d8633d9ed320ee89a435cdd77066fe460241b5aa45417b25d1baeb8205cefd4fa2 + languageName: node + linkType: hard + "sourcemap-codec@npm:^1.4.8": version: 1.4.8 resolution: "sourcemap-codec@npm:1.4.8" @@ -30368,7 +31492,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.matchall@npm:^4.0.12, string.prototype.matchall@npm:^4.0.6": +"string.prototype.matchall@npm:^4.0.12": version: 4.0.12 resolution: "string.prototype.matchall@npm:4.0.12" dependencies: @@ -30389,6 +31513,22 @@ __metadata: languageName: node linkType: hard +"string.prototype.matchall@npm:^4.0.6": + version: 4.0.7 + resolution: "string.prototype.matchall@npm:4.0.7" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.19.1" + get-intrinsic: "npm:^1.1.1" + has-symbols: "npm:^1.0.3" + internal-slot: "npm:^1.0.3" + regexp.prototype.flags: "npm:^1.4.1" + side-channel: "npm:^1.0.4" + checksum: 10/c3ddbe1341658bdbe54df05ee370d76efa8db8de9eb30d537f97319e3925fedca99f13804572c19903d730f3ea9e03e194384d175d24a43d2f848f7c6ccf7a54 + languageName: node + linkType: hard + "string.prototype.repeat@npm:^1.0.0": version: 1.0.0 resolution: "string.prototype.repeat@npm:1.0.0" @@ -30414,6 +31554,29 @@ __metadata: languageName: node linkType: hard +"string.prototype.trim@npm:^1.2.9": + version: 1.2.9 + resolution: "string.prototype.trim@npm:1.2.9" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.0" + es-object-atoms: "npm:^1.0.0" + checksum: 10/b2170903de6a2fb5a49bb8850052144e04b67329d49f1343cdc6a87cb24fb4e4b8ad00d3e273a399b8a3d8c32c89775d93a8f43cb42fbff303f25382079fb58a + languageName: node + linkType: hard + +"string.prototype.trimend@npm:^1.0.5": + version: 1.0.5 + resolution: "string.prototype.trimend@npm:1.0.5" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.1.4" + es-abstract: "npm:^1.19.5" + checksum: 10/14e660a4bda6a2a2280ea9bb1ca445aaeeb7a88c08272b107d13b98a4322b62954de47bb3f7cea46f281b6028fb8581e83d3e61ef14999127848834e31b4168c + languageName: node + linkType: hard + "string.prototype.trimend@npm:^1.0.8, string.prototype.trimend@npm:^1.0.9": version: 1.0.9 resolution: "string.prototype.trimend@npm:1.0.9" @@ -30426,6 +31589,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimstart@npm:^1.0.5": + version: 1.0.5 + resolution: "string.prototype.trimstart@npm:1.0.5" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.1.4" + es-abstract: "npm:^1.19.5" + checksum: 10/194a07b04a651ab1a31efa2ae8a7681270d3cc76f2566fe593d94cc6c89130d32c5972ee53cdf7cd5f9801f519874cb265b3c971a7342dfdd674a3a3908143f2 + languageName: node + linkType: hard + "string.prototype.trimstart@npm:^1.0.8": version: 1.0.8 resolution: "string.prototype.trimstart@npm:1.0.8" @@ -30637,6 +31811,18 @@ __metadata: languageName: node linkType: hard +"stylehacks@npm:^5.1.0": + version: 5.1.0 + resolution: "stylehacks@npm:5.1.0" + dependencies: + browserslist: "npm:^4.16.6" + postcss-selector-parser: "npm:^6.0.4" + peerDependencies: + postcss: ^8.2.15 + checksum: 10/e6c0d318286db8bf1dd3fa633798f6772cd3888e010e8224ba271cb8ff2b41a64bbebf938a2f7cacad7e319c4c963648fe9e9376c564229bd6029ee4d4f57c3f + languageName: node + linkType: hard + "stylehacks@npm:^5.1.1": version: 5.1.1 resolution: "stylehacks@npm:5.1.1" @@ -31045,9 +32231,23 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.0.0, terser@npm:^5.10.0, terser@npm:^5.15.0, terser@npm:^5.15.1, terser@npm:^5.31.1, terser@npm:^5.7.0": - version: 5.39.0 - resolution: "terser@npm:5.39.0" +"terser@npm:^5.0.0, terser@npm:^5.10.0, terser@npm:^5.7.0": + version: 5.14.1 + resolution: "terser@npm:5.14.1" + dependencies: + "@jridgewell/source-map": "npm:^0.3.2" + acorn: "npm:^8.5.0" + commander: "npm:^2.20.0" + source-map-support: "npm:~0.5.20" + bin: + terser: bin/terser + checksum: 10/f24bb5c4194d650c0ee2b36307dc07bbcfd0b9d83d4174c63a0ceb88d739423dc984f17869af9e3d71a3173f15baf5e368186c29046f519d432158ee9207e1d0 + languageName: node + linkType: hard + +"terser@npm:^5.15.0, terser@npm:^5.15.1, terser@npm:^5.31.1": + version: 5.37.0 + resolution: "terser@npm:5.37.0" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -31055,7 +32255,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10/d84aff642398329f7179bbeaca28cac76a86100e2372d98d39d9b86c48023b6b9f797d983d6e7c0610b3f957c53d01ada1befa25d625614cb2ccd20714f1e98b + checksum: 10/3afacf7c38c47a5a25dbe1ba2e7aafd61166474d4377ec0af490bd41ab3686ab12679818d5fe4a3e7f76efee26f639c92ac334940c378bbc31176520a38379c3 languageName: node linkType: hard @@ -31542,7 +32742,14 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2, tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.8.1": +"tslib@npm:^2, tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 10/bd26c22d36736513980091a1e356378e8b662ded04204453d353a7f34a4c21ed0afc59b5f90719d4ba756e581a162ecbf93118dc9c6be5acf70aa309188166ca + languageName: node + linkType: hard + +"tslib@npm:^2.6.0, tslib@npm:^2.8.1": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7 @@ -31733,13 +32940,20 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.26.1, type-fest@npm:^4.9.0": +"type-fest@npm:^4.26.1": version: 4.37.0 resolution: "type-fest@npm:4.37.0" checksum: 10/882cf05374d7c635cbbbc50cb89863dad3d27a77c426d062144ba32b23a44087193213c5bbd64f3ab8be04215005c950286567be06fecca9d09c66abd290ef01 languageName: node linkType: hard +"type-fest@npm:^4.9.0": + version: 4.31.0 + resolution: "type-fest@npm:4.31.0" + checksum: 10/e7e849845bf33e1237c3ff0d5ed00a251a807e3321ffe75278dd56a7d3c385badfe09180057c2d0b93cf7429432b8e7061b6ccf4cc468720d8f69073d2b1bed2 + languageName: node + linkType: hard + "type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -31750,6 +32964,17 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-buffer@npm:1.0.2" + dependencies: + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + is-typed-array: "npm:^1.1.13" + checksum: 10/02ffc185d29c6df07968272b15d5319a1610817916ec8d4cd670ded5d1efe72901541ff2202fcc622730d8a549c76e198a2f74e312eabbfb712ed907d45cbb0b + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.3": version: 1.0.3 resolution: "typed-array-buffer@npm:1.0.3" @@ -31761,6 +32986,19 @@ __metadata: languageName: node linkType: hard +"typed-array-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "typed-array-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + checksum: 10/e4a38329736fe6a73b52a09222d4a9e8de14caaa4ff6ad8e55217f6705b017d9815b7284c85065b3b8a7704e226ccff1372a72b78c2a5b6b71b7bf662308c903 + languageName: node + linkType: hard + "typed-array-byte-length@npm:^1.0.3": version: 1.0.3 resolution: "typed-array-byte-length@npm:1.0.3" @@ -31774,6 +33012,21 @@ __metadata: languageName: node linkType: hard +"typed-array-byte-offset@npm:^1.0.2": + version: 1.0.3 + resolution: "typed-array-byte-offset@npm:1.0.3" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + reflect.getprototypeof: "npm:^1.0.6" + checksum: 10/6c3bfba026616e656278a062dd5232d80fbb156b792045e698ecb0260a4c6e77e82412d6c8049f4e58bb66f509c90aacad09f02d4b5b8a4e67cf9c423a563be9 + languageName: node + linkType: hard + "typed-array-byte-offset@npm:^1.0.4": version: 1.0.4 resolution: "typed-array-byte-offset@npm:1.0.4" @@ -31789,7 +33042,7 @@ __metadata: languageName: node linkType: hard -"typed-array-length@npm:^1.0.7": +"typed-array-length@npm:^1.0.6, typed-array-length@npm:^1.0.7": version: 1.0.7 resolution: "typed-array-length@npm:1.0.7" dependencies: @@ -31888,6 +33141,18 @@ __metadata: languageName: node linkType: hard +"unbox-primitive@npm:^1.0.2": + version: 1.0.2 + resolution: "unbox-primitive@npm:1.0.2" + dependencies: + call-bind: "npm:^1.0.2" + has-bigints: "npm:^1.0.2" + has-symbols: "npm:^1.0.3" + which-boxed-primitive: "npm:^1.0.2" + checksum: 10/06e1ee41c1095e37281cb71a975cb3350f7cb470a0665d2576f02cc9564f623bd90cfc0183693b8a7fdf2d242963dcc3010b509fa3ac683f540c765c0f3e7e43 + languageName: node + linkType: hard + "unbox-primitive@npm:^1.1.0": version: 1.1.0 resolution: "unbox-primitive@npm:1.1.0" @@ -32146,6 +33411,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.0": + version: 1.1.0 + resolution: "update-browserslist-db@npm:1.1.0" + dependencies: + escalade: "npm:^3.1.2" + picocolors: "npm:^1.0.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10/d70b9efeaf4601aadb1a4f6456a7a5d9118e0063d995866b8e0c5e0cf559482671dab6ce7b079f9536b06758a344fbd83f974b965211e1c6e8d1958540b0c24c + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.1.1": version: 1.1.3 resolution: "update-browserslist-db@npm:1.1.3" @@ -32398,6 +33677,18 @@ __metadata: languageName: node linkType: hard +"valibot@npm:^1.0.0": + version: 1.0.0 + resolution: "valibot@npm:1.0.0" + peerDependencies: + typescript: ">=5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/3a46878a7cfb41e4538d7ae4b3ee255ca27b717f428f46bff00fa242ac6176b91ecb491200bb092ac24cba8bae96d852799b1c504eb566ee9e01987a18c498f7 + languageName: node + linkType: hard + "valid-url@npm:1.0.9, valid-url@npm:^1.0.9": version: 1.0.9 resolution: "valid-url@npm:1.0.9" @@ -32866,6 +34157,21 @@ __metadata: languageName: node linkType: hard +"webpack-dev-middleware@npm:^5.3.1": + version: 5.3.3 + resolution: "webpack-dev-middleware@npm:5.3.3" + dependencies: + colorette: "npm:^2.0.10" + memfs: "npm:^3.4.3" + mime-types: "npm:^2.1.31" + range-parser: "npm:^1.2.1" + schema-utils: "npm:^4.0.0" + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: 10/31a2f7a11e58a76bdcde1eb8da310b6643844d9b442f9916f48be5b46c103f23490c393c32a9af501ce68226fbb018b811f5a956635ed60a03f9481a4bcd6c76 + languageName: node + linkType: hard + "webpack-dev-middleware@npm:^5.3.4": version: 5.3.4 resolution: "webpack-dev-middleware@npm:5.3.4" @@ -32881,7 +34187,7 @@ __metadata: languageName: node linkType: hard -"webpack-dev-server@npm:^4.15.2, webpack-dev-server@npm:^4.6.0": +"webpack-dev-server@npm:^4.15.2": version: 4.15.2 resolution: "webpack-dev-server@npm:4.15.2" dependencies: @@ -32928,6 +34234,50 @@ __metadata: languageName: node linkType: hard +"webpack-dev-server@npm:^4.6.0": + version: 4.11.1 + resolution: "webpack-dev-server@npm:4.11.1" + dependencies: + "@types/bonjour": "npm:^3.5.9" + "@types/connect-history-api-fallback": "npm:^1.3.5" + "@types/express": "npm:^4.17.13" + "@types/serve-index": "npm:^1.9.1" + "@types/serve-static": "npm:^1.13.10" + "@types/sockjs": "npm:^0.3.33" + "@types/ws": "npm:^8.5.1" + ansi-html-community: "npm:^0.0.8" + bonjour-service: "npm:^1.0.11" + chokidar: "npm:^3.5.3" + colorette: "npm:^2.0.10" + compression: "npm:^1.7.4" + connect-history-api-fallback: "npm:^2.0.0" + default-gateway: "npm:^6.0.3" + express: "npm:^4.17.3" + graceful-fs: "npm:^4.2.6" + html-entities: "npm:^2.3.2" + http-proxy-middleware: "npm:^2.0.3" + ipaddr.js: "npm:^2.0.1" + open: "npm:^8.0.9" + p-retry: "npm:^4.5.0" + rimraf: "npm:^3.0.2" + schema-utils: "npm:^4.0.0" + selfsigned: "npm:^2.1.1" + serve-index: "npm:^1.9.1" + sockjs: "npm:^0.3.24" + spdy: "npm:^4.0.2" + webpack-dev-middleware: "npm:^5.3.1" + ws: "npm:^8.4.2" + peerDependencies: + webpack: ^4.37.0 || ^5.0.0 + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack-dev-server: bin/webpack-dev-server.js + checksum: 10/469d99694527b91a13d1f979c9a0a6e1c06d02ff8ca0169335b79332f319a5f8b37e74ef1a784a75e8fdd7e4b58c0dc1fa5db878ded66b77b9de61949c5c06b2 + languageName: node + linkType: hard + "webpack-manifest-plugin@npm:^4.0.2": version: 4.1.1 resolution: "webpack-manifest-plugin@npm:4.1.1" @@ -33221,7 +34571,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18": +"which-typed-array@npm:^1.1.13": version: 1.1.19 resolution: "which-typed-array@npm:1.1.19" dependencies: @@ -33236,6 +34586,33 @@ __metadata: languageName: node linkType: hard +"which-typed-array@npm:^1.1.15": + version: 1.1.16 + resolution: "which-typed-array@npm:1.1.16" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + checksum: 10/7106e94729632cdcedc94080442872392806b3364225156952981777f46b75d2e3b13813b5d935bdb2ac8523f8758fcf3513f7e1ed44a8e10d6c4f1029c3fa7d + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18": + version: 1.1.18 + resolution: "which-typed-array@npm:1.1.18" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + for-each: "npm:^0.3.3" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + checksum: 10/11eed801b2bd08cdbaecb17aff381e0fb03526532f61acc06e6c7b9370e08062c33763a51f27825f13fdf34aabd0df6104007f4e8f96e6eaef7db0ce17a26d6e + languageName: node + linkType: hard + "which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1" @@ -33322,13 +34699,20 @@ __metadata: languageName: node linkType: hard -"word-wrap@npm:^1.2.5, word-wrap@npm:~1.2.3": +"word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" checksum: 10/1ec6f6089f205f83037be10d0c4b34c9183b0b63fca0834a5b3cee55dd321429d73d40bb44c8fc8471b5203d6e8f8275717f49a8ff4b2b0ab41d7e1b563e0854 languageName: node linkType: hard +"word-wrap@npm:~1.2.3": + version: 1.2.3 + resolution: "word-wrap@npm:1.2.3" + checksum: 10/08a677e1578b9cc367a03d52bc51b6869fec06303f68d29439e4ed647257411f857469990c31066c1874678937dac737c9f8f20d3fd59918fb86b7d926a76b15 + languageName: node + linkType: hard + "workbox-background-sync@npm:6.6.0": version: 6.6.0 resolution: "workbox-background-sync@npm:6.6.0" @@ -33681,6 +35065,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.4.2": + version: 8.8.0 + resolution: "ws@npm:8.8.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10/39b41baa17d51025aee4843eba54fcdd3c570bbed7a0a67b441ac44ba8c9cf4b4c9323a61f1718228f4b71a190bef4cecc7ae991657f3c61c725c1d5674a5cf3 + languageName: node + linkType: hard + "xdg-basedir@npm:^4.0.0": version: 4.0.0 resolution: "xdg-basedir@npm:4.0.0" From bac32062f9ee49af36bd87094101f154d7a1d611 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 14:53:27 +0000 Subject: [PATCH 02/17] add result, error, and meta schemas --- .../toolkit/src/query/core/buildThunks.ts | 90 ++++++++---- .../toolkit/src/query/endpointDefinitions.ts | 9 +- .../toolkit/src/query/tests/createApi.test.ts | 130 +++++++++++++++++- 3 files changed, 198 insertions(+), 31 deletions(-) diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 9702eee2ef..927d7515b2 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -503,10 +503,13 @@ export function buildThunks< }, ) => { const endpointDefinition = endpointDefinitions[arg.endpointName] + const { metaSchema } = endpointDefinition try { - let transformResponse: TransformCallback = - getTransformCallbackForEndpoint(endpointDefinition, 'transformResponse') + let transformResponse = getTransformCallbackForEndpoint( + endpointDefinition, + 'transformResponse', + ) const baseQueryApi = { signal, @@ -563,11 +566,10 @@ export function buildThunks< finalQueryArg: unknown, ): Promise { let result: QueryReturnValue - const { extraOptions, argSchema } = endpointDefinition + const { extraOptions, argSchema, rawResultSchema, resultSchema } = + endpointDefinition - if (argSchema) { - await parseWithSchema(argSchema, finalQueryArg) - } + if (argSchema) await parseWithSchema(argSchema, finalQueryArg) if (forceQueryFn) { // upsertQueryData relies on this to pass in the user-provided value @@ -622,12 +624,25 @@ export function buildThunks< if (result.error) throw new HandledError(result.error, result.meta) - const transformedResponse = await transformResponse( - result.data, + let { data } = result + + if (rawResultSchema) { + data = await parseWithSchema(rawResultSchema, result.data) + } + + let transformedResponse = await transformResponse( + data, result.meta, finalQueryArg, ) + if (resultSchema) { + transformedResponse = await parseWithSchema( + resultSchema, + transformedResponse, + ) + } + return { ...result, data: transformedResponse, @@ -717,6 +732,13 @@ export function buildThunks< finalQueryReturnValue = await executeRequest(arg.originalArgs) } + if (metaSchema && finalQueryReturnValue.meta) { + finalQueryReturnValue.meta = await parseWithSchema( + metaSchema, + finalQueryReturnValue.meta, + ) + } + // console.log('Final result: ', transformedData) return fulfillWithValue( finalQueryReturnValue.data, @@ -726,25 +748,43 @@ export function buildThunks< }), ) } catch (error) { - let catchedError = error - if (catchedError instanceof HandledError) { - let transformErrorResponse: TransformCallback = - getTransformCallbackForEndpoint( - endpointDefinition, - 'transformErrorResponse', - ) + let caughtError = error + if (caughtError instanceof HandledError) { + let transformErrorResponse = getTransformCallbackForEndpoint( + endpointDefinition, + 'transformErrorResponse', + ) + const { rawErrorSchema, errorSchema } = endpointDefinition + + let { value, meta } = caughtError + + if (rawErrorSchema) { + value = await parseWithSchema(rawErrorSchema, value) + } + + if (metaSchema) { + meta = await parseWithSchema(metaSchema, meta) + } try { + let transformedErrorResponse = await transformErrorResponse( + value, + meta, + arg.originalArgs, + ) + if (errorSchema) { + transformedErrorResponse = await parseWithSchema( + errorSchema, + transformedErrorResponse, + ) + } + return rejectWithValue( - await transformErrorResponse( - catchedError.value, - catchedError.meta, - arg.originalArgs, - ), - addShouldAutoBatch({ baseQueryMeta: catchedError.meta }), + transformedErrorResponse, + addShouldAutoBatch({ baseQueryMeta: meta }), ) } catch (e) { - catchedError = e + caughtError = e } } if ( @@ -754,12 +794,12 @@ export function buildThunks< console.error( `An unhandled error occurred processing a request for the endpoint "${arg.endpointName}". In the case of an unhandled error, no tags will be "provided" or "invalidated".`, - catchedError, + caughtError, ) } else { - console.error(catchedError) + console.error(caughtError) } - throw catchedError + throw caughtError } } diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 737f5731db..7a3b30f021 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -119,6 +119,9 @@ type EndpointDefinitionWithQuery< /** A schema for the result *before* it's passed to `transformResponse` */ rawResultSchema?: StandardSchemaV1> + + /** A schema for the error object returned by the `query` or `queryFn`, *before* it's passed to `transformErrorResponse` */ + rawErrorSchema?: StandardSchemaV1> } type EndpointDefinitionWithQueryFn< @@ -180,6 +183,7 @@ type EndpointDefinitionWithQueryFn< transformResponse?: never transformErrorResponse?: never rawResultSchema?: never + rawErrorSchema?: never /** * Defaults to `true`. * @@ -217,9 +221,12 @@ export type BaseEndpointDefinition< /** A schema for the result (including `transformResponse` if provided) */ resultSchema?: StandardSchemaV1 - /** A schema for the error object returned by the `query` or `queryFn` */ + /** A schema for the error object returned by the `query` or `queryFn` (including `transformErrorResponse` if provided) */ errorSchema?: StandardSchemaV1> + /** A schema for the `meta` property returned by the `query` or `queryFn` */ + metaSchema?: StandardSchemaV1> + /* phantom type */ [resultType]?: ResultType /* phantom type */ diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index 0d90dfd583..bc3d62e61e 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -8,6 +8,7 @@ import type { SerializedError } from '@reduxjs/toolkit' import { configureStore, createAction, createReducer } from '@reduxjs/toolkit' import type { DefinitionsFromApi, + FetchBaseQueryError, FetchBaseQueryMeta, OverrideResultType, SerializeQueryArgs, @@ -28,6 +29,7 @@ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(noop) afterEach(() => { vi.clearAllMocks() + server.resetHandlers() }) afterAll(() => { @@ -1192,15 +1194,11 @@ describe('timeout behavior', () => { describe('endpoint schemas', () => { test("can be used to validate the endpoint's arguments", async () => { - server.use( - http.get('https://example.com/success/1', () => HttpResponse.json({})), - ) - const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), endpoints: (build) => ({ query: build.query({ - query: ({ id }) => `/success/${id}`, + query: ({ id }) => `/post/${id}`, argSchema: v.object({ id: v.number() }), }), }), @@ -1227,4 +1225,126 @@ describe('endpoint schemas', () => { stack: expect.any(String), }) }) + test("can be used to validate the endpoint's raw result", async () => { + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/success', + rawResultSchema: v.object({ value: v.literal('success!') }), + }), + }), + }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) + expect(result?.error).toEqual({ + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + }) + }) + test("can be used to validate the endpoint's final result", async () => { + server.use( + http.get('https://example.com/success/', () => + HttpResponse.json({ success: true }), + ), + ) + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/success', + transformResponse: () => ({ success: false }), + resultSchema: v.object({ success: v.literal(true) }), + }), + }), + }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) + expect(result?.error).toEqual({ + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + }) + }) + test("can be used to validate the endpoint's raw error result", async () => { + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/error', + rawErrorSchema: v.object({ + status: v.pipe(v.number(), v.minValue(400), v.maxValue(499)), + data: v.unknown(), + }), + }), + }), + }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) + expect(result?.error).toEqual({ + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + }) + }) + test("can be used to validate the endpoint's final error result", async () => { + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/error', + transformErrorResponse: (error): FetchBaseQueryError => ({ + status: 'CUSTOM_ERROR', + data: error, + error: 'whoops', + }), + errorSchema: v.object({ + status: v.literal('CUSTOM_ERROR'), + error: v.literal('oh no'), + data: v.unknown(), + }), + }), + }), + }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) + expect(result?.error).toEqual({ + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + }) + }) + test("can be used to validate the endpoint's meta result", async () => { + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/success', + metaSchema: v.object({ + request: v.instance(Request), + response: v.instance(Response), + timestamp: v.number(), + }), + }), + }), + }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) + expect(result?.error).toEqual({ + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + }) + }) }) From b3780fe71fdac14b372bcde17aee272e4ed3b8ed Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 14:59:46 +0000 Subject: [PATCH 03/17] declare error shape once --- .../toolkit/src/query/tests/createApi.test.ts | 47 +++++-------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index bc3d62e61e..8df175fb69 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -1193,6 +1193,12 @@ describe('timeout behavior', () => { }) describe('endpoint schemas', () => { + const serializedSchemaError = { + name: 'SchemaError', + message: expect.any(String), + stack: expect.any(String), + } satisfies SerializedError + test("can be used to validate the endpoint's arguments", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), @@ -1219,11 +1225,7 @@ describe('endpoint schemas', () => { api.endpoints.query.initiate({ id: '1' }), ) - expect(invalidResult?.error).toEqual({ - name: 'SchemaError', - message: expect.any(String), - stack: expect.any(String), - }) + expect(invalidResult?.error).toEqual(serializedSchemaError) }) test("can be used to validate the endpoint's raw result", async () => { const api = createApi({ @@ -1239,18 +1241,9 @@ describe('endpoint schemas', () => { withoutTestLifecycles: true, }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual({ - name: 'SchemaError', - message: expect.any(String), - stack: expect.any(String), - }) + expect(result?.error).toEqual(serializedSchemaError) }) test("can be used to validate the endpoint's final result", async () => { - server.use( - http.get('https://example.com/success/', () => - HttpResponse.json({ success: true }), - ), - ) const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), endpoints: (build) => ({ @@ -1265,11 +1258,7 @@ describe('endpoint schemas', () => { withoutTestLifecycles: true, }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual({ - name: 'SchemaError', - message: expect.any(String), - stack: expect.any(String), - }) + expect(result?.error).toEqual(serializedSchemaError) }) test("can be used to validate the endpoint's raw error result", async () => { const api = createApi({ @@ -1288,11 +1277,7 @@ describe('endpoint schemas', () => { withoutTestLifecycles: true, }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual({ - name: 'SchemaError', - message: expect.any(String), - stack: expect.any(String), - }) + expect(result?.error).toEqual(serializedSchemaError) }) test("can be used to validate the endpoint's final error result", async () => { const api = createApi({ @@ -1317,11 +1302,7 @@ describe('endpoint schemas', () => { withoutTestLifecycles: true, }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual({ - name: 'SchemaError', - message: expect.any(String), - stack: expect.any(String), - }) + expect(result?.error).toEqual(serializedSchemaError) }) test("can be used to validate the endpoint's meta result", async () => { const api = createApi({ @@ -1341,10 +1322,6 @@ describe('endpoint schemas', () => { withoutTestLifecycles: true, }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual({ - name: 'SchemaError', - message: expect.any(String), - stack: expect.any(String), - }) + expect(result?.error).toEqual(serializedSchemaError) }) }) From 78beee3e5fc5e04de3a9d3b9a3dc5296b698d06a Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 15:28:41 +0000 Subject: [PATCH 04/17] add type tests --- .../src/query/tests/createApi.test-d.ts | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 2b1dc64d9e..bce4ebe109 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -11,6 +11,8 @@ import type { TagTypesFromApi, } from '@reduxjs/toolkit/query' import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' +import * as v from 'valibot' +import type { Post } from './mocks/handlers' describe('type tests', () => { test('sensible defaults', () => { @@ -373,5 +375,72 @@ describe('type tests', () => { >() }) }) + describe('endpoint schemas', () => { + test('schemas must match', () => { + const postSchema = v.object({ + id: v.number(), + title: v.string(), + body: v.string(), + }) satisfies v.GenericSchema + const errorSchema = v.object({ + status: v.number(), + data: v.unknown(), + }) satisfies v.GenericSchema + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query({ + query: ({ id }) => `/post/${id}`, + argSchema: v.object({ id: v.number() }), + resultSchema: postSchema, + errorSchema, + }), + bothMismatch: build.query({ + query: ({ id }) => `/post/${id}`, + // @ts-expect-error wrong schema + argSchema: v.object({ id: v.string() }), + // @ts-expect-error wrong schema + resultSchema: v.object({ id: v.string() }), + // @ts-expect-error wrong schema + errorSchema: v.object({ status: v.string() }), + }), + inputMismatch: build.query({ + query: ({ id }) => `/post/${id}`, + // @ts-expect-error can't expect different input + argSchema: v.object({ + id: v.pipe(v.string(), v.transform(Number), v.number()), + }), + // @ts-expect-error can't expect different input + resultSchema: v.object({ + ...postSchema.entries, + id: v.pipe(v.string(), v.transform(Number)), + }) satisfies v.GenericSchema, + // @ts-expect-error can't expect different input + errorSchema: v.object({ + status: v.pipe(v.string(), v.transform(Number)), + data: v.unknown(), + }) satisfies v.GenericSchema, + }), + outputMismatch: build.query({ + query: ({ id }) => `/post/${id}`, + // @ts-expect-error can't provide different output + argSchema: v.object({ + id: v.pipe(v.number(), v.transform(String)), + }), + // @ts-expect-error can't provide different output + resultSchema: v.object({ + ...postSchema.entries, + id: v.pipe(v.number(), v.transform(String)), + }) satisfies v.GenericSchema, + // @ts-expect-error can't provide different output + errorSchema: v.object({ + status: v.pipe(v.number(), v.transform(String)), + data: v.unknown(), + }) satisfies v.GenericSchema, + }), + }), + }) + }) + }) }) }) From a317fc3c3d5d1c2c59196b33c91f3950012057bc Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 15:32:59 +0000 Subject: [PATCH 05/17] pull types from spec instead of inlining --- packages/toolkit/package.json | 1 + .../toolkit/src/query/endpointDefinitions.ts | 2 +- packages/toolkit/src/query/standardSchema.ts | 72 +------------------ yarn.lock | 8 +++ 4 files changed, 11 insertions(+), 72 deletions(-) diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index 844c2f623c..3412bf5ae1 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -125,6 +125,7 @@ "react" ], "dependencies": { + "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 7a3b30f021..005c2ed56d 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -1,4 +1,5 @@ import type { Api } from '@reduxjs/toolkit/query' +import type { StandardSchemaV1 } from '@standard-schema/spec' import type { BaseQueryApi, BaseQueryArg, @@ -37,7 +38,6 @@ import type { UnwrapPromise, } from './tsHelpers' import { isNotNullish } from './utils' -import type { StandardSchemaV1 } from './standardSchema' const resultType = /* @__PURE__ */ Symbol() const baseQuery = /* @__PURE__ */ Symbol() diff --git a/packages/toolkit/src/query/standardSchema.ts b/packages/toolkit/src/query/standardSchema.ts index d90b9d736f..b85677efbb 100644 --- a/packages/toolkit/src/query/standardSchema.ts +++ b/packages/toolkit/src/query/standardSchema.ts @@ -1,76 +1,6 @@ +import type { StandardSchemaV1 } from '@standard-schema/spec' import { SchemaError } from '@standard-schema/utils' -/** The Standard Schema interface. */ -export interface StandardSchemaV1 { - /** The Standard Schema properties. */ - readonly '~standard': StandardSchemaV1.Props -} - -export declare namespace StandardSchemaV1 { - /** The Standard Schema properties interface. */ - export interface Props { - /** The version number of the standard. */ - readonly version: 1 - /** The vendor name of the schema library. */ - readonly vendor: string - /** Validates unknown input values. */ - readonly validate: ( - value: unknown, - ) => Result | Promise> - /** Inferred types associated with the schema. */ - readonly types?: Types | undefined - } - - /** The result interface of the validate function. */ - export type Result = SuccessResult | FailureResult - - /** The result interface if validation succeeds. */ - export interface SuccessResult { - /** The typed output value. */ - readonly value: Output - /** The non-existent issues. */ - readonly issues?: undefined - } - - /** The result interface if validation fails. */ - export interface FailureResult { - /** The issues of failed validation. */ - readonly issues: ReadonlyArray - } - - /** The issue interface of the failure output. */ - export interface Issue { - /** The error message of the issue. */ - readonly message: string - /** The path of the issue, if any. */ - readonly path?: ReadonlyArray | undefined - } - - /** The path segment interface of the issue. */ - export interface PathSegment { - /** The key representing a path segment. */ - readonly key: PropertyKey - } - - /** The Standard Schema types interface. */ - export interface Types { - /** The input type of the schema. */ - readonly input: Input - /** The output type of the schema. */ - readonly output: Output - } - - /** Infers the input type of a Standard Schema. */ - export type InferInput = NonNullable< - Schema['~standard']['types'] - >['input'] - - /** Infers the output type of a Standard Schema. */ - export type InferOutput = NonNullable< - Schema['~standard']['types'] - >['output'] -} - export async function parseWithSchema( schema: Schema, data: unknown, diff --git a/yarn.lock b/yarn.lock index a3d3a30e57..e136656620 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8067,6 +8067,7 @@ __metadata: "@phryneas/ts-version": "npm:^1.0.2" "@size-limit/file": "npm:^11.0.1" "@size-limit/webpack": "npm:^11.0.1" + "@standard-schema/spec": "npm:^1.0.0" "@standard-schema/utils": "npm:^0.3.0" "@testing-library/dom": "npm:^10.4.0" "@testing-library/react": "npm:^16.0.1" @@ -8779,6 +8780,13 @@ __metadata: languageName: node linkType: hard +"@standard-schema/spec@npm:^1.0.0": + version: 1.0.0 + resolution: "@standard-schema/spec@npm:1.0.0" + checksum: 10/aee780cc1431888ca4b9aba9b24ffc8f3073fc083acc105e3951481478a2f4dc957796931b2da9e2d8329584cf211e4542275f188296c1cdff3ed44fd93a8bc8 + languageName: node + linkType: hard + "@standard-schema/utils@npm:^0.3.0": version: 0.3.0 resolution: "@standard-schema/utils@npm:0.3.0" From ffc9f495908e17842131243ec526a66c5f8b3fc7 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 15:38:40 +0000 Subject: [PATCH 06/17] assign argSchema result --- packages/toolkit/src/query/core/buildThunks.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 927d7515b2..0833fd1e48 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -569,7 +569,9 @@ export function buildThunks< const { extraOptions, argSchema, rawResultSchema, resultSchema } = endpointDefinition - if (argSchema) await parseWithSchema(argSchema, finalQueryArg) + if (argSchema) { + finalQueryArg = await parseWithSchema(argSchema, finalQueryArg) + } if (forceQueryFn) { // upsertQueryData relies on this to pass in the user-provided value From f3add0153248610f8f4ef4fcce2e0051bdcadd5d Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 15:43:23 +0000 Subject: [PATCH 07/17] move common option to common options section --- .../toolkit/src/query/endpointDefinitions.ts | 40 +++++++------------ 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 005c2ed56d..39c449498a 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -103,19 +103,6 @@ type EndpointDefinitionWithQuery< meta: BaseQueryMeta, arg: QueryArg, ): unknown - /** - * Defaults to `true`. - * - * Most apps should leave this setting on. The only time it can be a performance issue - * is if an API returns extremely large amounts of data (e.g. 10,000 rows per request) and - * you're unable to paginate it. - * - * For details of how this works, please see the below. When it is set to `false`, - * every request will cause subscribed components to rerender, even when the data has not changed. - * - * @see https://redux-toolkit.js.org/api/other-exports#copywithstructuralsharing - */ - structuralSharing?: boolean /** A schema for the result *before* it's passed to `transformResponse` */ rawResultSchema?: StandardSchemaV1> @@ -184,19 +171,6 @@ type EndpointDefinitionWithQueryFn< transformErrorResponse?: never rawResultSchema?: never rawErrorSchema?: never - /** - * Defaults to `true`. - * - * Most apps should leave this setting on. The only time it can be a performance issue - * is if an API returns extremely large amounts of data (e.g. 10,000 rows per request) and - * you're unable to paginate it. - * - * For details of how this works, please see the below. When it is set to `false`, - * every request will cause subscribed components to rerender, even when the data has not changed. - * - * @see https://redux-toolkit.js.org/api/other-exports#copywithstructuralsharing - */ - structuralSharing?: boolean } type BaseEndpointTypes = { @@ -227,6 +201,20 @@ export type BaseEndpointDefinition< /** A schema for the `meta` property returned by the `query` or `queryFn` */ metaSchema?: StandardSchemaV1> + /** + * Defaults to `true`. + * + * Most apps should leave this setting on. The only time it can be a performance issue + * is if an API returns extremely large amounts of data (e.g. 10,000 rows per request) and + * you're unable to paginate it. + * + * For details of how this works, please see the below. When it is set to `false`, + * every request will cause subscribed components to rerender, even when the data has not changed. + * + * @see https://redux-toolkit.js.org/api/other-exports#copywithstructuralsharing + */ + structuralSharing?: boolean + /* phantom type */ [resultType]?: ResultType /* phantom type */ From ba3a795bebda29f79ca5aac95e21927fae5d864c Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 15:49:37 +0000 Subject: [PATCH 08/17] tweak test --- packages/toolkit/src/query/tests/createApi.test-d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index bce4ebe109..2a7c8dc25c 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -417,8 +417,8 @@ describe('type tests', () => { }) satisfies v.GenericSchema, // @ts-expect-error can't expect different input errorSchema: v.object({ + ...errorSchema.entries, status: v.pipe(v.string(), v.transform(Number)), - data: v.unknown(), }) satisfies v.GenericSchema, }), outputMismatch: build.query({ @@ -434,8 +434,8 @@ describe('type tests', () => { }) satisfies v.GenericSchema, // @ts-expect-error can't provide different output errorSchema: v.object({ + ...errorSchema.entries, status: v.pipe(v.number(), v.transform(String)), - data: v.unknown(), }) satisfies v.GenericSchema, }), }), From 553a7e9ea4a6fd4714913da7659a386b2980c225 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 15:53:35 +0000 Subject: [PATCH 09/17] add metaSchema type test --- .../src/query/tests/createApi.test-d.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 2a7c8dc25c..58c057b741 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -4,6 +4,7 @@ import { configureStore } from '@reduxjs/toolkit' import type { DefinitionsFromApi, FetchBaseQueryError, + FetchBaseQueryMeta, MutationDefinition, OverrideResultType, QueryDefinition, @@ -386,6 +387,10 @@ describe('type tests', () => { status: v.number(), data: v.unknown(), }) satisfies v.GenericSchema + const metaSchema = v.object({ + request: v.instance(Request), + response: v.optional(v.instance(Response)), + }) satisfies v.GenericSchema createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), endpoints: (build) => ({ @@ -394,6 +399,7 @@ describe('type tests', () => { argSchema: v.object({ id: v.number() }), resultSchema: postSchema, errorSchema, + metaSchema, }), bothMismatch: build.query({ query: ({ id }) => `/post/${id}`, @@ -403,6 +409,8 @@ describe('type tests', () => { resultSchema: v.object({ id: v.string() }), // @ts-expect-error wrong schema errorSchema: v.object({ status: v.string() }), + // @ts-expect-error wrong schema + metaSchema: v.object({ request: v.string() }), }), inputMismatch: build.query({ query: ({ id }) => `/post/${id}`, @@ -420,6 +428,14 @@ describe('type tests', () => { ...errorSchema.entries, status: v.pipe(v.string(), v.transform(Number)), }) satisfies v.GenericSchema, + // @ts-expect-error can't expect different input + metaSchema: v.object({ + ...metaSchema.entries, + request: v.pipe( + v.string(), + v.transform((url) => new Request(url)), + ), + }) satisfies v.GenericSchema, }), outputMismatch: build.query({ query: ({ id }) => `/post/${id}`, @@ -437,6 +453,14 @@ describe('type tests', () => { ...errorSchema.entries, status: v.pipe(v.number(), v.transform(String)), }) satisfies v.GenericSchema, + // @ts-expect-error can't provide different output + metaSchema: v.object({ + ...metaSchema.entries, + request: v.pipe( + v.instance(Request), + v.transform((r) => r.url), + ), + }) satisfies v.GenericSchema, }), }), }) From a42b5f7d1a2b6a44dfd7ab62804a1e1fa90b7e71 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 16:02:16 +0000 Subject: [PATCH 10/17] add test for inference from schemas --- .../src/query/tests/createApi.test-d.ts | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 58c057b741..8f020070a9 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -377,26 +377,27 @@ describe('type tests', () => { }) }) describe('endpoint schemas', () => { + const argSchema = v.object({ id: v.number() }) + const postSchema = v.object({ + id: v.number(), + title: v.string(), + body: v.string(), + }) satisfies v.GenericSchema + const errorSchema = v.object({ + status: v.number(), + data: v.unknown(), + }) satisfies v.GenericSchema + const metaSchema = v.object({ + request: v.instance(Request), + response: v.optional(v.instance(Response)), + }) satisfies v.GenericSchema test('schemas must match', () => { - const postSchema = v.object({ - id: v.number(), - title: v.string(), - body: v.string(), - }) satisfies v.GenericSchema - const errorSchema = v.object({ - status: v.number(), - data: v.unknown(), - }) satisfies v.GenericSchema - const metaSchema = v.object({ - request: v.instance(Request), - response: v.optional(v.instance(Response)), - }) satisfies v.GenericSchema createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), endpoints: (build) => ({ query: build.query({ query: ({ id }) => `/post/${id}`, - argSchema: v.object({ id: v.number() }), + argSchema, resultSchema: postSchema, errorSchema, metaSchema, @@ -465,6 +466,23 @@ describe('type tests', () => { }), }) }) + test('schemas as a source of inference', () => { + const api = createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query({ + query: ({ id }) => `/post/${id}`, + argSchema, + resultSchema: postSchema, + }), + }), + }) + + expectTypeOf(api.endpoints.query.Types.QueryArg).toEqualTypeOf<{ + id: number + }>() + expectTypeOf(api.endpoints.query.Types.ResultType).toEqualTypeOf() + }) }) }) }) From 150a286d60b672d988406ef9d1a84efa02c01809 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 16:26:07 +0000 Subject: [PATCH 11/17] resultSchema -> responseSchema --- packages/toolkit/src/query/core/buildThunks.ts | 10 +++++----- packages/toolkit/src/query/endpointDefinitions.ts | 6 +++--- .../toolkit/src/query/tests/createApi.test-d.ts | 13 ++++++------- packages/toolkit/src/query/tests/createApi.test.ts | 4 ++-- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 0833fd1e48..c0574d3f61 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -566,7 +566,7 @@ export function buildThunks< finalQueryArg: unknown, ): Promise { let result: QueryReturnValue - const { extraOptions, argSchema, rawResultSchema, resultSchema } = + const { extraOptions, argSchema, rawResponseSchema, responseSchema } = endpointDefinition if (argSchema) { @@ -628,8 +628,8 @@ export function buildThunks< let { data } = result - if (rawResultSchema) { - data = await parseWithSchema(rawResultSchema, result.data) + if (rawResponseSchema) { + data = await parseWithSchema(rawResponseSchema, result.data) } let transformedResponse = await transformResponse( @@ -638,9 +638,9 @@ export function buildThunks< finalQueryArg, ) - if (resultSchema) { + if (responseSchema) { transformedResponse = await parseWithSchema( - resultSchema, + responseSchema, transformedResponse, ) } diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 39c449498a..a622184068 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -105,7 +105,7 @@ type EndpointDefinitionWithQuery< ): unknown /** A schema for the result *before* it's passed to `transformResponse` */ - rawResultSchema?: StandardSchemaV1> + rawResponseSchema?: StandardSchemaV1> /** A schema for the error object returned by the `query` or `queryFn`, *before* it's passed to `transformErrorResponse` */ rawErrorSchema?: StandardSchemaV1> @@ -169,7 +169,7 @@ type EndpointDefinitionWithQueryFn< query?: never transformResponse?: never transformErrorResponse?: never - rawResultSchema?: never + rawResponseSchema?: never rawErrorSchema?: never } @@ -193,7 +193,7 @@ export type BaseEndpointDefinition< argSchema?: StandardSchemaV1 /** A schema for the result (including `transformResponse` if provided) */ - resultSchema?: StandardSchemaV1 + responseSchema?: StandardSchemaV1 /** A schema for the error object returned by the `query` or `queryFn` (including `transformErrorResponse` if provided) */ errorSchema?: StandardSchemaV1> diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 8f020070a9..d2a2e62ce1 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -398,7 +398,7 @@ describe('type tests', () => { query: build.query({ query: ({ id }) => `/post/${id}`, argSchema, - resultSchema: postSchema, + responseSchema: postSchema, errorSchema, metaSchema, }), @@ -407,7 +407,7 @@ describe('type tests', () => { // @ts-expect-error wrong schema argSchema: v.object({ id: v.string() }), // @ts-expect-error wrong schema - resultSchema: v.object({ id: v.string() }), + responseSchema: v.object({ id: v.string() }), // @ts-expect-error wrong schema errorSchema: v.object({ status: v.string() }), // @ts-expect-error wrong schema @@ -420,7 +420,7 @@ describe('type tests', () => { id: v.pipe(v.string(), v.transform(Number), v.number()), }), // @ts-expect-error can't expect different input - resultSchema: v.object({ + responseSchema: v.object({ ...postSchema.entries, id: v.pipe(v.string(), v.transform(Number)), }) satisfies v.GenericSchema, @@ -445,7 +445,7 @@ describe('type tests', () => { id: v.pipe(v.number(), v.transform(String)), }), // @ts-expect-error can't provide different output - resultSchema: v.object({ + responseSchema: v.object({ ...postSchema.entries, id: v.pipe(v.number(), v.transform(String)), }) satisfies v.GenericSchema, @@ -471,9 +471,8 @@ describe('type tests', () => { baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), endpoints: (build) => ({ query: build.query({ - query: ({ id }) => `/post/${id}`, - argSchema, - resultSchema: postSchema, + query: ({ id }: { id: number }) => `/post/${id}`, + responseSchema: postSchema, }), }), }) diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index 8df175fb69..d2182570d6 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -1233,7 +1233,7 @@ describe('endpoint schemas', () => { endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/success', - rawResultSchema: v.object({ value: v.literal('success!') }), + rawResponseSchema: v.object({ value: v.literal('success!') }), }), }), }) @@ -1250,7 +1250,7 @@ describe('endpoint schemas', () => { query: build.query<{ success: boolean }, void>({ query: () => '/success', transformResponse: () => ({ success: false }), - resultSchema: v.object({ success: v.literal(true) }), + responseSchema: v.object({ success: v.literal(true) }), }), }), }) From 244620b5d76c3ce3ec27b8a3dfa73d3eb4714be2 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 16:32:25 +0000 Subject: [PATCH 12/17] add argSchema inference test --- .../toolkit/src/query/tests/createApi.test-d.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index d2a2e62ce1..316051038c 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -474,6 +474,14 @@ describe('type tests', () => { query: ({ id }: { id: number }) => `/post/${id}`, responseSchema: postSchema, }), + query2: build.query({ + query: (arg) => { + expectTypeOf(arg).toEqualTypeOf<{ id: number }>() + return `/post/${arg.id}` + }, + argSchema, + responseSchema: postSchema, + }), }), }) @@ -481,6 +489,13 @@ describe('type tests', () => { id: number }>() expectTypeOf(api.endpoints.query.Types.ResultType).toEqualTypeOf() + + expectTypeOf(api.endpoints.query2.Types.QueryArg).toEqualTypeOf<{ + id: number + }>() + expectTypeOf( + api.endpoints.query2.Types.ResultType, + ).toEqualTypeOf() }) }) }) From ad885ad01284c869d66cf213ce13c390517615aa Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 16:50:59 +0000 Subject: [PATCH 13/17] errorSchema -> errorResponse --- packages/toolkit/src/query/core/buildThunks.ts | 11 ++++++----- packages/toolkit/src/query/endpointDefinitions.ts | 6 +++--- .../toolkit/src/query/tests/createApi.test-d.ts | 14 +++++++------- packages/toolkit/src/query/tests/createApi.test.ts | 4 ++-- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index c0574d3f61..bbfead5a32 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -756,12 +756,13 @@ export function buildThunks< endpointDefinition, 'transformErrorResponse', ) - const { rawErrorSchema, errorSchema } = endpointDefinition + const { rawErrorResponseSchema, errorResponseSchema } = + endpointDefinition let { value, meta } = caughtError - if (rawErrorSchema) { - value = await parseWithSchema(rawErrorSchema, value) + if (rawErrorResponseSchema) { + value = await parseWithSchema(rawErrorResponseSchema, value) } if (metaSchema) { @@ -774,9 +775,9 @@ export function buildThunks< meta, arg.originalArgs, ) - if (errorSchema) { + if (errorResponseSchema) { transformedErrorResponse = await parseWithSchema( - errorSchema, + errorResponseSchema, transformedErrorResponse, ) } diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index a622184068..8f18c9ad67 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -108,7 +108,7 @@ type EndpointDefinitionWithQuery< rawResponseSchema?: StandardSchemaV1> /** A schema for the error object returned by the `query` or `queryFn`, *before* it's passed to `transformErrorResponse` */ - rawErrorSchema?: StandardSchemaV1> + rawErrorResponseSchema?: StandardSchemaV1> } type EndpointDefinitionWithQueryFn< @@ -170,7 +170,7 @@ type EndpointDefinitionWithQueryFn< transformResponse?: never transformErrorResponse?: never rawResponseSchema?: never - rawErrorSchema?: never + rawErrorResponseSchema?: never } type BaseEndpointTypes = { @@ -196,7 +196,7 @@ export type BaseEndpointDefinition< responseSchema?: StandardSchemaV1 /** A schema for the error object returned by the `query` or `queryFn` (including `transformErrorResponse` if provided) */ - errorSchema?: StandardSchemaV1> + errorResponseSchema?: StandardSchemaV1> /** A schema for the `meta` property returned by the `query` or `queryFn` */ metaSchema?: StandardSchemaV1> diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 316051038c..8de98ab605 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -383,7 +383,7 @@ describe('type tests', () => { title: v.string(), body: v.string(), }) satisfies v.GenericSchema - const errorSchema = v.object({ + const errorResponseSchema = v.object({ status: v.number(), data: v.unknown(), }) satisfies v.GenericSchema @@ -399,7 +399,7 @@ describe('type tests', () => { query: ({ id }) => `/post/${id}`, argSchema, responseSchema: postSchema, - errorSchema, + errorResponseSchema, metaSchema, }), bothMismatch: build.query({ @@ -409,7 +409,7 @@ describe('type tests', () => { // @ts-expect-error wrong schema responseSchema: v.object({ id: v.string() }), // @ts-expect-error wrong schema - errorSchema: v.object({ status: v.string() }), + errorResponseSchema: v.object({ status: v.string() }), // @ts-expect-error wrong schema metaSchema: v.object({ request: v.string() }), }), @@ -425,8 +425,8 @@ describe('type tests', () => { id: v.pipe(v.string(), v.transform(Number)), }) satisfies v.GenericSchema, // @ts-expect-error can't expect different input - errorSchema: v.object({ - ...errorSchema.entries, + errorResponseSchema: v.object({ + ...errorResponseSchema.entries, status: v.pipe(v.string(), v.transform(Number)), }) satisfies v.GenericSchema, // @ts-expect-error can't expect different input @@ -450,8 +450,8 @@ describe('type tests', () => { id: v.pipe(v.number(), v.transform(String)), }) satisfies v.GenericSchema, // @ts-expect-error can't provide different output - errorSchema: v.object({ - ...errorSchema.entries, + errorResponseSchema: v.object({ + ...errorResponseSchema.entries, status: v.pipe(v.number(), v.transform(String)), }) satisfies v.GenericSchema, // @ts-expect-error can't provide different output diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index d2182570d6..110afc23b3 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -1266,7 +1266,7 @@ describe('endpoint schemas', () => { endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/error', - rawErrorSchema: v.object({ + rawErrorResponseSchema: v.object({ status: v.pipe(v.number(), v.minValue(400), v.maxValue(499)), data: v.unknown(), }), @@ -1290,7 +1290,7 @@ describe('endpoint schemas', () => { data: error, error: 'whoops', }), - errorSchema: v.object({ + errorResponseSchema: v.object({ status: v.literal('CUSTOM_ERROR'), error: v.literal('oh no'), data: v.unknown(), From 02807798bc07722806f7972892eb8019c535ee62 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 18:21:24 +0000 Subject: [PATCH 14/17] add inference of raw result type from schema (or specifying from a third type parameter) --- packages/toolkit/src/query/core/apiState.ts | 14 ++-- .../core/buildMiddleware/cacheLifecycle.ts | 12 ++- .../toolkit/src/query/endpointDefinitions.ts | 75 ++++++++++++++----- .../src/query/tests/createApi.test-d.ts | 18 ++++- 4 files changed, 89 insertions(+), 30 deletions(-) diff --git a/packages/toolkit/src/query/core/apiState.ts b/packages/toolkit/src/query/core/apiState.ts index d73584e11e..d566bf7ade 100644 --- a/packages/toolkit/src/query/core/apiState.ts +++ b/packages/toolkit/src/query/core/apiState.ts @@ -184,7 +184,7 @@ export type MutationKeys = { }[keyof Definitions] type BaseQuerySubState< - D extends BaseEndpointDefinition, + D extends BaseEndpointDefinition, DataType = ResultTypeFrom, > = { /** @@ -222,7 +222,7 @@ type BaseQuerySubState< } export type QuerySubState< - D extends BaseEndpointDefinition, + D extends BaseEndpointDefinition, DataType = ResultTypeFrom, > = Id< | ({ @@ -252,7 +252,7 @@ export type QuerySubState< export type InfiniteQueryDirection = 'forward' | 'backward' export type InfiniteQuerySubState< - D extends BaseEndpointDefinition, + D extends BaseEndpointDefinition, > = D extends InfiniteQueryDefinition ? QuerySubState, PageParamFrom>> & { @@ -260,7 +260,9 @@ export type InfiniteQuerySubState< } : never -type BaseMutationSubState> = { +type BaseMutationSubState< + D extends BaseEndpointDefinition, +> = { requestId: string data?: ResultTypeFrom error?: @@ -273,7 +275,9 @@ type BaseMutationSubState> = { fulfilledTimeStamp?: number } -export type MutationSubState> = +export type MutationSubState< + D extends BaseEndpointDefinition, +> = | (({ status: QueryStatus.fulfilled } & WithRequiredProp< diff --git a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts index 1ec2a86327..b7d203ddde 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts @@ -1,5 +1,9 @@ import type { ThunkDispatch, UnknownAction } from '@reduxjs/toolkit' -import type { BaseQueryFn, BaseQueryMeta } from '../../baseQueryTypes' +import type { + BaseQueryFn, + BaseQueryMeta, + BaseQueryResult, +} from '../../baseQueryTypes' import type { BaseEndpointDefinition } from '../../endpointDefinitions' import { DefinitionType } from '../../endpointDefinitions' import type { QueryCacheKey, RootState } from '../apiState' @@ -32,7 +36,8 @@ export interface QueryBaseLifecycleApi< { type: DefinitionType.query } & BaseEndpointDefinition< QueryArg, BaseQuery, - ResultType + ResultType, + BaseQueryResult > > /** @@ -55,7 +60,8 @@ export type MutationBaseLifecycleApi< { type: DefinitionType.mutation } & BaseEndpointDefinition< QueryArg, BaseQuery, - ResultType + ResultType, + BaseQueryResult > > } diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 8f18c9ad67..70205a3f5f 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -46,6 +46,7 @@ type EndpointDefinitionWithQuery< QueryArg, BaseQuery extends BaseQueryFn, ResultType, + RawResultType extends BaseQueryResult, > = { /** * `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. @@ -91,7 +92,7 @@ type EndpointDefinitionWithQuery< * A function to manipulate the data returned by a query or mutation. */ transformResponse?( - baseQueryReturnValue: BaseQueryResult, + baseQueryReturnValue: RawResultType, meta: BaseQueryMeta, arg: QueryArg, ): ResultType | Promise @@ -105,7 +106,7 @@ type EndpointDefinitionWithQuery< ): unknown /** A schema for the result *before* it's passed to `transformResponse` */ - rawResponseSchema?: StandardSchemaV1> + rawResponseSchema?: StandardSchemaV1 /** A schema for the error object returned by the `query` or `queryFn`, *before* it's passed to `transformErrorResponse` */ rawErrorResponseSchema?: StandardSchemaV1> @@ -183,10 +184,16 @@ export type BaseEndpointDefinition< QueryArg, BaseQuery extends BaseQueryFn, ResultType, + RawResultType extends BaseQueryResult = BaseQueryResult, > = ( | ([CastAny, {}>] extends [NEVER] ? never - : EndpointDefinitionWithQuery) + : EndpointDefinitionWithQuery< + QueryArg, + BaseQuery, + ResultType, + RawResultType + >) | EndpointDefinitionWithQueryFn ) & { /** A schema for the arguments to be passed to the `query` or `queryFn` */ @@ -550,7 +557,8 @@ export type QueryDefinition< TagTypes extends string, ResultType, ReducerPath extends string = string, -> = BaseEndpointDefinition & + RawResultType extends BaseQueryResult = BaseQueryResult, +> = BaseEndpointDefinition & QueryExtraOptions export type InfiniteQueryTypes< @@ -743,12 +751,14 @@ export type InfiniteQueryDefinition< TagTypes extends string, ResultType, ReducerPath extends string = string, + RawResultType extends BaseQueryResult = BaseQueryResult, > = // Infinite query endpoints receive `{queryArg, pageParam}` BaseEndpointDefinition< InfiniteQueryCombinedArg, BaseQuery, - ResultType + ResultType, + RawResultType > & InfiniteQueryExtraOptions< TagTypes, @@ -876,7 +886,8 @@ export type MutationDefinition< TagTypes extends string, ResultType, ReducerPath extends string = string, -> = BaseEndpointDefinition & + RawResultType extends BaseQueryResult = BaseQueryResult, +> = BaseEndpointDefinition & MutationExtraOptions export type EndpointDefinition< @@ -952,9 +963,21 @@ export type EndpointBuilder< *}); *``` */ - query( + query< + ResultType, + QueryArg, + RawResultType extends + BaseQueryResult = BaseQueryResult, + >( definition: OmitFromUnion< - QueryDefinition, + QueryDefinition< + QueryArg, + BaseQuery, + TagTypes, + ResultType, + ReducerPath, + RawResultType + >, 'type' >, ): QueryDefinition @@ -984,14 +1007,20 @@ export type EndpointBuilder< * }); * ``` */ - mutation( + mutation< + ResultType, + QueryArg, + RawResultType extends + BaseQueryResult = BaseQueryResult, + >( definition: OmitFromUnion< MutationDefinition< QueryArg, BaseQuery, TagTypes, ResultType, - ReducerPath + ReducerPath, + RawResultType >, 'type' >, @@ -1058,27 +1087,31 @@ export function expandTagDescription( return typeof description === 'string' ? { type: description } : description } -export type QueryArgFrom> = - D extends BaseEndpointDefinition ? QA : never +export type QueryArgFrom> = + D extends BaseEndpointDefinition ? QA : never // Just extracting `QueryArg` from `BaseEndpointDefinition` // doesn't sufficiently match here. // We need to explicitly match against `InfiniteQueryDefinition` export type InfiniteQueryArgFrom< - D extends BaseEndpointDefinition, -> = D extends InfiniteQueryDefinition ? QA : never + D extends BaseEndpointDefinition, +> = + D extends InfiniteQueryDefinition + ? QA + : never export type QueryArgFromAnyQuery< - D extends BaseEndpointDefinition, + D extends BaseEndpointDefinition, > = - D extends InfiniteQueryDefinition + D extends InfiniteQueryDefinition ? InfiniteQueryArgFrom : D extends QueryDefinition ? QueryArgFrom : never -export type ResultTypeFrom> = - D extends BaseEndpointDefinition ? RT : unknown +export type ResultTypeFrom< + D extends BaseEndpointDefinition, +> = D extends BaseEndpointDefinition ? RT : unknown export type ReducerPathFrom< D extends EndpointDefinition, @@ -1088,9 +1121,11 @@ export type TagTypesFrom> = D extends EndpointDefinition ? RP : unknown export type PageParamFrom< - D extends InfiniteQueryDefinition, + D extends InfiniteQueryDefinition, > = - D extends InfiniteQueryDefinition ? PP : unknown + D extends InfiniteQueryDefinition + ? PP + : unknown export type InfiniteQueryCombinedArg = { queryArg: QueryArg diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 8de98ab605..96bcef5946 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -1,6 +1,6 @@ import { setupApiStore } from '@internal/tests/utils/helpers' -import type { SerializedError } from '@reduxjs/toolkit' -import { configureStore } from '@reduxjs/toolkit' +import type { EntityState, SerializedError } from '@reduxjs/toolkit' +import { configureStore, createEntityAdapter } from '@reduxjs/toolkit' import type { DefinitionsFromApi, FetchBaseQueryError, @@ -467,6 +467,7 @@ describe('type tests', () => { }) }) test('schemas as a source of inference', () => { + const postAdapter = createEntityAdapter() const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), endpoints: (build) => ({ @@ -482,6 +483,14 @@ describe('type tests', () => { argSchema, responseSchema: postSchema, }), + query3: build.query({ + query: (_arg: void) => `/posts`, + rawResponseSchema: v.array(postSchema), + transformResponse: (posts) => { + expectTypeOf(posts).toEqualTypeOf() + return postAdapter.getInitialState(undefined, posts) + }, + }), }), }) @@ -496,6 +505,11 @@ describe('type tests', () => { expectTypeOf( api.endpoints.query2.Types.ResultType, ).toEqualTypeOf() + + expectTypeOf(api.endpoints.query3.Types.QueryArg).toEqualTypeOf() + expectTypeOf(api.endpoints.query3.Types.ResultType).toEqualTypeOf< + EntityState + >() }) }) }) From ccd70e4e625e5dc394690397fcae138fadca12d1 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 20:28:11 +0000 Subject: [PATCH 15/17] add api level and endpoint level handlers for schema failures --- .../toolkit/src/query/core/buildThunks.ts | 125 +++++++++++------- packages/toolkit/src/query/core/module.ts | 2 + packages/toolkit/src/query/createApi.ts | 3 + .../toolkit/src/query/endpointDefinitions.ts | 15 +++ packages/toolkit/src/query/standardSchema.ts | 18 ++- .../toolkit/src/query/tests/createApi.test.ts | 81 ++++++++++++ 6 files changed, 195 insertions(+), 49 deletions(-) diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index bbfead5a32..5e5f221f2f 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -28,6 +28,8 @@ import type { QueryDefinition, ResultDescription, ResultTypeFrom, + SchemaFailureHandler, + SchemaFailureInfo, } from '../endpointDefinitions' import { calculateProvidedBy, @@ -65,7 +67,7 @@ import { isRejectedWithValue, SHOULD_AUTOBATCH, } from './rtkImports' -import { parseWithSchema } from '../standardSchema' +import { parseWithSchema, NamedSchemaError } from '../standardSchema' export type BuildThunksApiEndpointQuery< Definition extends QueryDefinition, @@ -339,6 +341,7 @@ export function buildThunks< api, assertTagType, selectors, + onSchemaFailure, }: { baseQuery: BaseQuery reducerPath: ReducerPath @@ -347,6 +350,7 @@ export function buildThunks< api: Api assertTagType: AssertTagTypes selectors: AllSelectors + onSchemaFailure: SchemaFailureHandler | undefined }) { type State = RootState @@ -570,7 +574,11 @@ export function buildThunks< endpointDefinition if (argSchema) { - finalQueryArg = await parseWithSchema(argSchema, finalQueryArg) + finalQueryArg = await parseWithSchema( + argSchema, + finalQueryArg, + 'argSchema', + ) } if (forceQueryFn) { @@ -629,7 +637,11 @@ export function buildThunks< let { data } = result if (rawResponseSchema) { - data = await parseWithSchema(rawResponseSchema, result.data) + data = await parseWithSchema( + rawResponseSchema, + result.data, + 'rawResponseSchema', + ) } let transformedResponse = await transformResponse( @@ -642,6 +654,7 @@ export function buildThunks< transformedResponse = await parseWithSchema( responseSchema, transformedResponse, + 'responseSchema', ) } @@ -738,6 +751,7 @@ export function buildThunks< finalQueryReturnValue.meta = await parseWithSchema( metaSchema, finalQueryReturnValue.meta, + 'metaSchema', ) } @@ -750,59 +764,78 @@ export function buildThunks< }), ) } catch (error) { - let caughtError = error - if (caughtError instanceof HandledError) { - let transformErrorResponse = getTransformCallbackForEndpoint( - endpointDefinition, - 'transformErrorResponse', - ) - const { rawErrorResponseSchema, errorResponseSchema } = - endpointDefinition + try { + let caughtError = error + if (caughtError instanceof HandledError) { + let transformErrorResponse = getTransformCallbackForEndpoint( + endpointDefinition, + 'transformErrorResponse', + ) + const { rawErrorResponseSchema, errorResponseSchema } = + endpointDefinition - let { value, meta } = caughtError + let { value, meta } = caughtError - if (rawErrorResponseSchema) { - value = await parseWithSchema(rawErrorResponseSchema, value) - } + if (rawErrorResponseSchema) { + value = await parseWithSchema( + rawErrorResponseSchema, + value, + 'rawErrorResponseSchema', + ) + } - if (metaSchema) { - meta = await parseWithSchema(metaSchema, meta) - } + if (metaSchema) { + meta = await parseWithSchema(metaSchema, meta, 'metaSchema') + } - try { - let transformedErrorResponse = await transformErrorResponse( - value, - meta, - arg.originalArgs, - ) - if (errorResponseSchema) { - transformedErrorResponse = await parseWithSchema( - errorResponseSchema, + try { + let transformedErrorResponse = await transformErrorResponse( + value, + meta, + arg.originalArgs, + ) + if (errorResponseSchema) { + transformedErrorResponse = await parseWithSchema( + errorResponseSchema, + transformedErrorResponse, + 'errorResponseSchema', + ) + } + + return rejectWithValue( transformedErrorResponse, + addShouldAutoBatch({ baseQueryMeta: meta }), ) + } catch (e) { + caughtError = e } - - return rejectWithValue( - transformedErrorResponse, - addShouldAutoBatch({ baseQueryMeta: meta }), - ) - } catch (e) { - caughtError = e } - } - if ( - typeof process !== 'undefined' && - process.env.NODE_ENV !== 'production' - ) { - console.error( - `An unhandled error occurred processing a request for the endpoint "${arg.endpointName}". + if ( + typeof process !== 'undefined' && + process.env.NODE_ENV !== 'production' + ) { + console.error( + `An unhandled error occurred processing a request for the endpoint "${arg.endpointName}". In the case of an unhandled error, no tags will be "provided" or "invalidated".`, - caughtError, - ) - } else { - console.error(caughtError) + caughtError, + ) + } else { + console.error(caughtError) + } + throw caughtError + } catch (error) { + if (error instanceof NamedSchemaError) { + const info: SchemaFailureInfo = { + endpoint: arg.endpointName, + arg: arg.originalArgs, + type: arg.type, + queryCacheKey: arg.type === 'query' ? arg.queryCacheKey : undefined, + } + endpointDefinition.onSchemaFailure?.(error, info) + onSchemaFailure?.(error, info) + } + throw error } - throw caughtError } } diff --git a/packages/toolkit/src/query/core/module.ts b/packages/toolkit/src/query/core/module.ts index 63a1e8479f..21769a2573 100644 --- a/packages/toolkit/src/query/core/module.ts +++ b/packages/toolkit/src/query/core/module.ts @@ -516,6 +516,7 @@ export const coreModule = ({ refetchOnFocus, refetchOnReconnect, invalidationBehavior, + onSchemaFailure, }, context, ) { @@ -582,6 +583,7 @@ export const coreModule = ({ serializeQueryArgs, assertTagType, selectors, + onSchemaFailure, }) const { reducer, actions: sliceActions } = buildSlice({ diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index 9112baffc8..528474ed69 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -6,6 +6,7 @@ import { defaultSerializeQueryArgs } from './defaultSerializeQueryArgs' import type { EndpointBuilder, EndpointDefinitions, + SchemaFailureHandler, } from './endpointDefinitions' import { DefinitionType, @@ -212,6 +213,8 @@ export interface CreateApiOptions< NoInfer, NoInfer > + + onSchemaFailure?: SchemaFailureHandler } export type CreateApi = { diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 70205a3f5f..0b592523b8 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -38,10 +38,23 @@ import type { UnwrapPromise, } from './tsHelpers' import { isNotNullish } from './utils' +import type { NamedSchemaError } from './standardSchema' const resultType = /* @__PURE__ */ Symbol() const baseQuery = /* @__PURE__ */ Symbol() +export interface SchemaFailureInfo { + endpoint: string + arg: any + type: 'query' | 'mutation' + queryCacheKey?: string +} + +export type SchemaFailureHandler = ( + error: NamedSchemaError, + info: SchemaFailureInfo, +) => void + type EndpointDefinitionWithQuery< QueryArg, BaseQuery extends BaseQueryFn, @@ -222,6 +235,8 @@ export type BaseEndpointDefinition< */ structuralSharing?: boolean + onSchemaFailure?: SchemaFailureHandler + /* phantom type */ [resultType]?: ResultType /* phantom type */ diff --git a/packages/toolkit/src/query/standardSchema.ts b/packages/toolkit/src/query/standardSchema.ts index b85677efbb..e85e6b7e2a 100644 --- a/packages/toolkit/src/query/standardSchema.ts +++ b/packages/toolkit/src/query/standardSchema.ts @@ -1,12 +1,24 @@ import type { StandardSchemaV1 } from '@standard-schema/spec' import { SchemaError } from '@standard-schema/utils' +export class NamedSchemaError extends SchemaError { + constructor( + issues: readonly StandardSchemaV1.Issue[], + public readonly value: any, + public readonly schemaName: string, + ) { + super(issues) + } +} + export async function parseWithSchema( schema: Schema, data: unknown, + schemaName: string, ): Promise> { - let result = schema['~standard'].validate(data) - if (result instanceof Promise) result = await result - if (result.issues) throw new SchemaError(result.issues) + const result = await schema['~standard'].validate(data) + if (result.issues) { + throw new NamedSchemaError(result.issues, data, schemaName) + } return result.value } diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index 110afc23b3..e107cf1d13 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -18,6 +18,8 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' import { HttpResponse, delay, http } from 'msw' import nodeFetch from 'node-fetch' import * as v from 'valibot' +import type { SchemaFailureHandler } from '../endpointDefinitions' +import { NamedSchemaError } from '../standardSchema' beforeAll(() => { vi.stubEnv('NODE_ENV', 'development') @@ -1199,13 +1201,44 @@ describe('endpoint schemas', () => { stack: expect.any(String), } satisfies SerializedError + const onSchemaFailureGlobal = vi.fn>() + const onSchemaFailureEndpoint = vi.fn>() + afterEach(() => { + onSchemaFailureGlobal.mockClear() + onSchemaFailureEndpoint.mockClear() + }) + + function expectFailureHandlersToHaveBeenCalled({ + schemaName, + value, + arg, + }: { + schemaName: string + value: unknown + arg: unknown + }) { + for (const handler of [onSchemaFailureGlobal, onSchemaFailureEndpoint]) { + expect(handler).toHaveBeenCalledOnce() + const [taggedError, info] = handler.mock.calls[0] + expect(taggedError).toBeInstanceOf(NamedSchemaError) + expect(taggedError.issues.length).toBeGreaterThan(0) + expect(taggedError.value).toEqual(value) + expect(taggedError.schemaName).toBe(schemaName) + expect(info.endpoint).toBe('query') + expect(info.type).toBe('query') + expect(info.arg).toEqual(arg) + } + } + test("can be used to validate the endpoint's arguments", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, endpoints: (build) => ({ query: build.query({ query: ({ id }) => `/post/${id}`, argSchema: v.object({ id: v.number() }), + onSchemaFailure: onSchemaFailureEndpoint, }), }), }) @@ -1226,14 +1259,21 @@ describe('endpoint schemas', () => { ) expect(invalidResult?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'argSchema', + value: { id: '1' }, + arg: { id: '1' }, + }) }) test("can be used to validate the endpoint's raw result", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/success', rawResponseSchema: v.object({ value: v.literal('success!') }), + onSchemaFailure: onSchemaFailureEndpoint, }), }), }) @@ -1242,15 +1282,22 @@ describe('endpoint schemas', () => { }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'rawResponseSchema', + value: { value: 'success' }, + arg: undefined, + }) }) test("can be used to validate the endpoint's final result", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/success', transformResponse: () => ({ success: false }), responseSchema: v.object({ success: v.literal(true) }), + onSchemaFailure: onSchemaFailureEndpoint, }), }), }) @@ -1259,10 +1306,17 @@ describe('endpoint schemas', () => { }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) expect(result?.error).toEqual(serializedSchemaError) + + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'responseSchema', + value: { success: false }, + arg: undefined, + }) }) test("can be used to validate the endpoint's raw error result", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/error', @@ -1270,6 +1324,7 @@ describe('endpoint schemas', () => { status: v.pipe(v.number(), v.minValue(400), v.maxValue(499)), data: v.unknown(), }), + onSchemaFailure: onSchemaFailureEndpoint, }), }), }) @@ -1278,10 +1333,16 @@ describe('endpoint schemas', () => { }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'rawErrorResponseSchema', + value: { status: 500, data: { value: 'error' } }, + arg: undefined, + }) }) test("can be used to validate the endpoint's final error result", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/error', @@ -1295,6 +1356,7 @@ describe('endpoint schemas', () => { error: v.literal('oh no'), data: v.unknown(), }), + onSchemaFailure: onSchemaFailureEndpoint, }), }), }) @@ -1303,10 +1365,20 @@ describe('endpoint schemas', () => { }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'errorResponseSchema', + value: { + status: 'CUSTOM_ERROR', + error: 'whoops', + data: { status: 500, data: { value: 'error' } }, + }, + arg: undefined, + }) }) test("can be used to validate the endpoint's meta result", async () => { const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, endpoints: (build) => ({ query: build.query<{ success: boolean }, void>({ query: () => '/success', @@ -1315,6 +1387,7 @@ describe('endpoint schemas', () => { response: v.instance(Response), timestamp: v.number(), }), + onSchemaFailure: onSchemaFailureEndpoint, }), }), }) @@ -1323,5 +1396,13 @@ describe('endpoint schemas', () => { }) const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'metaSchema', + value: { + request: expect.any(Request), + response: expect.any(Response), + }, + arg: undefined, + }) }) }) From de309e9de38cd3ce37dd49f7d39be9eaf9f516aa Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 26 Feb 2025 20:38:54 +0000 Subject: [PATCH 16/17] export NamedSchemaError --- packages/toolkit/src/query/index.ts | 4 ++++ .../toolkit/src/query/tests/createApi.test.ts | 17 ++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/toolkit/src/query/index.ts b/packages/toolkit/src/query/index.ts index 1d89d7a3bc..609e0d10d5 100644 --- a/packages/toolkit/src/query/index.ts +++ b/packages/toolkit/src/query/index.ts @@ -46,6 +46,8 @@ export type { ResultDescription, TagTypesFromApi, UpdateDefinitions, + SchemaFailureHandler, + SchemaFailureInfo, } from './endpointDefinitions' export { fetchBaseQuery } from './fetchBaseQuery' export type { @@ -98,3 +100,5 @@ export type { NoInfer as TSHelpersNoInfer, Override as TSHelpersOverride, } from './tsHelpers' + +export { NamedSchemaError } from './standardSchema' diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index e107cf1d13..0366e21ab9 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -14,12 +14,15 @@ import type { SerializeQueryArgs, TagTypesFromApi, } from '@reduxjs/toolkit/query' -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' +import { + createApi, + fetchBaseQuery, + NamedSchemaError, +} from '@reduxjs/toolkit/query' import { HttpResponse, delay, http } from 'msw' import nodeFetch from 'node-fetch' import * as v from 'valibot' import type { SchemaFailureHandler } from '../endpointDefinitions' -import { NamedSchemaError } from '../standardSchema' beforeAll(() => { vi.stubEnv('NODE_ENV', 'development') @@ -1219,11 +1222,11 @@ describe('endpoint schemas', () => { }) { for (const handler of [onSchemaFailureGlobal, onSchemaFailureEndpoint]) { expect(handler).toHaveBeenCalledOnce() - const [taggedError, info] = handler.mock.calls[0] - expect(taggedError).toBeInstanceOf(NamedSchemaError) - expect(taggedError.issues.length).toBeGreaterThan(0) - expect(taggedError.value).toEqual(value) - expect(taggedError.schemaName).toBe(schemaName) + const [namedError, info] = handler.mock.calls[0] + expect(namedError).toBeInstanceOf(NamedSchemaError) + expect(namedError.issues.length).toBeGreaterThan(0) + expect(namedError.value).toEqual(value) + expect(namedError.schemaName).toBe(schemaName) expect(info.endpoint).toBe('query') expect(info.type).toBe('query') expect(info.arg).toEqual(arg) From 23c00ee3ceaf7cd56cc063daa8da07c7701d7b6d Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Sun, 30 Mar 2025 21:48:33 +0100 Subject: [PATCH 17/17] added skipSchemaValidation flag --- .../toolkit/src/query/core/buildThunks.ts | 19 +- packages/toolkit/src/query/core/module.ts | 2 + packages/toolkit/src/query/createApi.ts | 1 + .../toolkit/src/query/endpointDefinitions.ts | 1 + .../toolkit/src/query/tests/createApi.test.ts | 481 +++++++++++++----- 5 files changed, 359 insertions(+), 145 deletions(-) diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 5e5f221f2f..58df44398e 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -342,6 +342,7 @@ export function buildThunks< assertTagType, selectors, onSchemaFailure, + skipSchemaValidation: globalSkipSchemaValidation, }: { baseQuery: BaseQuery reducerPath: ReducerPath @@ -351,6 +352,7 @@ export function buildThunks< assertTagType: AssertTagTypes selectors: AllSelectors onSchemaFailure: SchemaFailureHandler | undefined + skipSchemaValidation: boolean | undefined }) { type State = RootState @@ -507,7 +509,8 @@ export function buildThunks< }, ) => { const endpointDefinition = endpointDefinitions[arg.endpointName] - const { metaSchema } = endpointDefinition + const { metaSchema, skipSchemaValidation = globalSkipSchemaValidation } = + endpointDefinition try { let transformResponse = getTransformCallbackForEndpoint( @@ -573,7 +576,7 @@ export function buildThunks< const { extraOptions, argSchema, rawResponseSchema, responseSchema } = endpointDefinition - if (argSchema) { + if (argSchema && !skipSchemaValidation) { finalQueryArg = await parseWithSchema( argSchema, finalQueryArg, @@ -636,7 +639,7 @@ export function buildThunks< let { data } = result - if (rawResponseSchema) { + if (rawResponseSchema && !skipSchemaValidation) { data = await parseWithSchema( rawResponseSchema, result.data, @@ -650,7 +653,7 @@ export function buildThunks< finalQueryArg, ) - if (responseSchema) { + if (responseSchema && !skipSchemaValidation) { transformedResponse = await parseWithSchema( responseSchema, transformedResponse, @@ -747,7 +750,7 @@ export function buildThunks< finalQueryReturnValue = await executeRequest(arg.originalArgs) } - if (metaSchema && finalQueryReturnValue.meta) { + if (metaSchema && !skipSchemaValidation && finalQueryReturnValue.meta) { finalQueryReturnValue.meta = await parseWithSchema( metaSchema, finalQueryReturnValue.meta, @@ -776,7 +779,7 @@ export function buildThunks< let { value, meta } = caughtError - if (rawErrorResponseSchema) { + if (rawErrorResponseSchema && !skipSchemaValidation) { value = await parseWithSchema( rawErrorResponseSchema, value, @@ -784,7 +787,7 @@ export function buildThunks< ) } - if (metaSchema) { + if (metaSchema && !skipSchemaValidation) { meta = await parseWithSchema(metaSchema, meta, 'metaSchema') } @@ -794,7 +797,7 @@ export function buildThunks< meta, arg.originalArgs, ) - if (errorResponseSchema) { + if (errorResponseSchema && !skipSchemaValidation) { transformedErrorResponse = await parseWithSchema( errorResponseSchema, transformedErrorResponse, diff --git a/packages/toolkit/src/query/core/module.ts b/packages/toolkit/src/query/core/module.ts index 21769a2573..d3e3a8b0a1 100644 --- a/packages/toolkit/src/query/core/module.ts +++ b/packages/toolkit/src/query/core/module.ts @@ -517,6 +517,7 @@ export const coreModule = ({ refetchOnReconnect, invalidationBehavior, onSchemaFailure, + skipSchemaValidation, }, context, ) { @@ -584,6 +585,7 @@ export const coreModule = ({ assertTagType, selectors, onSchemaFailure, + skipSchemaValidation, }) const { reducer, actions: sliceActions } = buildSlice({ diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index 528474ed69..31fde60be8 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -215,6 +215,7 @@ export interface CreateApiOptions< > onSchemaFailure?: SchemaFailureHandler + skipSchemaValidation?: boolean } export type CreateApi = { diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 0b592523b8..693b0d7b00 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -236,6 +236,7 @@ export type BaseEndpointDefinition< structuralSharing?: boolean onSchemaFailure?: SchemaFailureHandler + skipSchemaValidation?: boolean /* phantom type */ [resultType]?: ResultType diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index 0366e21ab9..6b1e8a093f 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -1233,179 +1233,386 @@ describe('endpoint schemas', () => { } } - test("can be used to validate the endpoint's arguments", async () => { - const api = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), - onSchemaFailure: onSchemaFailureGlobal, - endpoints: (build) => ({ - query: build.query({ - query: ({ id }) => `/post/${id}`, - argSchema: v.object({ id: v.number() }), - onSchemaFailure: onSchemaFailureEndpoint, + describe('argSchema', () => { + const makeApi = ({ + globalSkip, + endpointSkip, + }: { globalSkip?: boolean; endpointSkip?: boolean } = {}) => + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, + skipSchemaValidation: globalSkip, + endpoints: (build) => ({ + query: build.query({ + query: ({ id }) => `/post/${id}`, + argSchema: v.object({ id: v.number() }), + onSchemaFailure: onSchemaFailureEndpoint, + skipSchemaValidation: endpointSkip, + }), }), - }), + }) + test("can be used to validate the endpoint's arguments", async () => { + const api = makeApi() + + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate({ id: 1 }), + ) + + expect(result?.error).toBeUndefined() + + const invalidResult = await storeRef.store.dispatch( + // @ts-expect-error + api.endpoints.query.initiate({ id: '1' }), + ) + + expect(invalidResult?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'argSchema', + value: { id: '1' }, + arg: { id: '1' }, + }) }) + test('can be skipped globally', async () => { + const api = makeApi({ globalSkip: true }) - const storeRef = setupApiStore(api, undefined, { - withoutTestLifecycles: true, + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + + const result = await storeRef.store.dispatch( + // @ts-expect-error + api.endpoints.query.initiate({ id: '1' }), + ) + + expect(result?.error).toBeUndefined() }) + test('can be skipped on the endpoint', async () => { + const api = makeApi({ endpointSkip: true }) - const result = await storeRef.store.dispatch( - api.endpoints.query.initiate({ id: 1 }), - ) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) - expect(result?.error).toBeUndefined() + const result = await storeRef.store.dispatch( + // @ts-expect-error + api.endpoints.query.initiate({ id: '1' }), + ) - const invalidResult = await storeRef.store.dispatch( - // @ts-expect-error - api.endpoints.query.initiate({ id: '1' }), - ) + expect(result?.error).toBeUndefined() + }) + // we only need to test this once + test('endpoint overrides global skip', async () => { + const api = makeApi({ globalSkip: true, endpointSkip: false }) + + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) - expect(invalidResult?.error).toEqual(serializedSchemaError) - expectFailureHandlersToHaveBeenCalled({ - schemaName: 'argSchema', - value: { id: '1' }, - arg: { id: '1' }, + const result = await storeRef.store.dispatch( + // @ts-expect-error + api.endpoints.query.initiate({ id: '1' }), + ) + + expect(result?.error).toEqual(serializedSchemaError) }) }) - test("can be used to validate the endpoint's raw result", async () => { - const api = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), - onSchemaFailure: onSchemaFailureGlobal, - endpoints: (build) => ({ - query: build.query<{ success: boolean }, void>({ - query: () => '/success', - rawResponseSchema: v.object({ value: v.literal('success!') }), - onSchemaFailure: onSchemaFailureEndpoint, + describe('rawResponseSchema', () => { + const makeApi = ({ + globalSkip, + endpointSkip, + }: { globalSkip?: boolean; endpointSkip?: boolean } = {}) => + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, + skipSchemaValidation: globalSkip, + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/success', + rawResponseSchema: v.object({ value: v.literal('success!') }), + onSchemaFailure: onSchemaFailureEndpoint, + skipSchemaValidation: endpointSkip, + }), }), - }), + }) + test("can be used to validate the endpoint's raw result", async () => { + const api = makeApi() + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'rawResponseSchema', + value: { value: 'success' }, + arg: undefined, + }) }) - const storeRef = setupApiStore(api, undefined, { - withoutTestLifecycles: true, + test('can be skipped globally', async () => { + const api = makeApi({ globalSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toBeUndefined() }) - const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual(serializedSchemaError) - expectFailureHandlersToHaveBeenCalled({ - schemaName: 'rawResponseSchema', - value: { value: 'success' }, - arg: undefined, + test('can be skipped on the endpoint', async () => { + const api = makeApi({ endpointSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toBeUndefined() }) }) - test("can be used to validate the endpoint's final result", async () => { - const api = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), - onSchemaFailure: onSchemaFailureGlobal, - endpoints: (build) => ({ - query: build.query<{ success: boolean }, void>({ - query: () => '/success', - transformResponse: () => ({ success: false }), - responseSchema: v.object({ success: v.literal(true) }), - onSchemaFailure: onSchemaFailureEndpoint, + describe('responseSchema', () => { + const makeApi = ({ + globalSkip, + endpointSkip, + }: { globalSkip?: boolean; endpointSkip?: boolean } = {}) => + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, + skipSchemaValidation: globalSkip, + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/success', + transformResponse: () => ({ success: false }), + responseSchema: v.object({ success: v.literal(true) }), + onSchemaFailure: onSchemaFailureEndpoint, + skipSchemaValidation: endpointSkip, + }), }), - }), + }) + test("can be used to validate the endpoint's final result", async () => { + const api = makeApi() + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toEqual(serializedSchemaError) + + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'responseSchema', + value: { success: false }, + arg: undefined, + }) }) - const storeRef = setupApiStore(api, undefined, { - withoutTestLifecycles: true, + test('can be skipped globally', async () => { + const api = makeApi({ globalSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toBeUndefined() }) - const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual(serializedSchemaError) - - expectFailureHandlersToHaveBeenCalled({ - schemaName: 'responseSchema', - value: { success: false }, - arg: undefined, + test('can be skipped on the endpoint', async () => { + const api = makeApi({ endpointSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toBeUndefined() }) }) - test("can be used to validate the endpoint's raw error result", async () => { - const api = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), - onSchemaFailure: onSchemaFailureGlobal, - endpoints: (build) => ({ - query: build.query<{ success: boolean }, void>({ - query: () => '/error', - rawErrorResponseSchema: v.object({ - status: v.pipe(v.number(), v.minValue(400), v.maxValue(499)), - data: v.unknown(), + describe('rawErrorResponseSchema', () => { + const makeApi = ({ + globalSkip, + endpointSkip, + }: { globalSkip?: boolean; endpointSkip?: boolean } = {}) => + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, + skipSchemaValidation: globalSkip, + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/error', + rawErrorResponseSchema: v.object({ + status: v.pipe(v.number(), v.minValue(400), v.maxValue(499)), + data: v.unknown(), + }), + onSchemaFailure: onSchemaFailureEndpoint, + skipSchemaValidation: endpointSkip, }), - onSchemaFailure: onSchemaFailureEndpoint, }), - }), + }) + test("can be used to validate the endpoint's raw error result", async () => { + const api = makeApi() + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'rawErrorResponseSchema', + value: { status: 500, data: { value: 'error' } }, + arg: undefined, + }) }) - const storeRef = setupApiStore(api, undefined, { - withoutTestLifecycles: true, + test('can be skipped globally', async () => { + const api = makeApi({ globalSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).not.toEqual(serializedSchemaError) }) - const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual(serializedSchemaError) - expectFailureHandlersToHaveBeenCalled({ - schemaName: 'rawErrorResponseSchema', - value: { status: 500, data: { value: 'error' } }, - arg: undefined, + test('can be skipped on the endpoint', async () => { + const api = makeApi({ endpointSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).not.toEqual(serializedSchemaError) }) }) - test("can be used to validate the endpoint's final error result", async () => { - const api = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), - onSchemaFailure: onSchemaFailureGlobal, - endpoints: (build) => ({ - query: build.query<{ success: boolean }, void>({ - query: () => '/error', - transformErrorResponse: (error): FetchBaseQueryError => ({ - status: 'CUSTOM_ERROR', - data: error, - error: 'whoops', - }), - errorResponseSchema: v.object({ - status: v.literal('CUSTOM_ERROR'), - error: v.literal('oh no'), - data: v.unknown(), + describe('errorResponseSchema', () => { + const makeApi = ({ + globalSkip, + endpointSkip, + }: { globalSkip?: boolean; endpointSkip?: boolean } = {}) => + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, + skipSchemaValidation: globalSkip, + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/error', + transformErrorResponse: (error): FetchBaseQueryError => ({ + status: 'CUSTOM_ERROR', + data: error, + error: 'whoops', + }), + errorResponseSchema: v.object({ + status: v.literal('CUSTOM_ERROR'), + error: v.literal('oh no'), + data: v.unknown(), + }), + onSchemaFailure: onSchemaFailureEndpoint, + skipSchemaValidation: endpointSkip, }), - onSchemaFailure: onSchemaFailureEndpoint, }), - }), + }) + test("can be used to validate the endpoint's final error result", async () => { + const api = makeApi() + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'errorResponseSchema', + value: { + status: 'CUSTOM_ERROR', + error: 'whoops', + data: { status: 500, data: { value: 'error' } }, + }, + arg: undefined, + }) }) - const storeRef = setupApiStore(api, undefined, { - withoutTestLifecycles: true, + test('can be skipped globally', async () => { + const api = makeApi({ globalSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).not.toEqual(serializedSchemaError) }) - const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual(serializedSchemaError) - expectFailureHandlersToHaveBeenCalled({ - schemaName: 'errorResponseSchema', - value: { - status: 'CUSTOM_ERROR', - error: 'whoops', - data: { status: 500, data: { value: 'error' } }, - }, - arg: undefined, + test('can be skipped on the endpoint', async () => { + const api = makeApi({ endpointSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).not.toEqual(serializedSchemaError) }) }) - test("can be used to validate the endpoint's meta result", async () => { - const api = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), - onSchemaFailure: onSchemaFailureGlobal, - endpoints: (build) => ({ - query: build.query<{ success: boolean }, void>({ - query: () => '/success', - metaSchema: v.object({ - request: v.instance(Request), - response: v.instance(Response), - timestamp: v.number(), + describe('metaSchema', () => { + const makeApi = ({ + globalSkip, + endpointSkip, + }: { globalSkip?: boolean; endpointSkip?: boolean } = {}) => + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + onSchemaFailure: onSchemaFailureGlobal, + skipSchemaValidation: globalSkip, + endpoints: (build) => ({ + query: build.query<{ success: boolean }, void>({ + query: () => '/success', + metaSchema: v.object({ + request: v.instance(Request), + response: v.instance(Response), + timestamp: v.number(), + }), + onSchemaFailure: onSchemaFailureEndpoint, + skipSchemaValidation: endpointSkip, }), - onSchemaFailure: onSchemaFailureEndpoint, }), - }), + }) + test("can be used to validate the endpoint's meta result", async () => { + const api = makeApi() + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toEqual(serializedSchemaError) + expectFailureHandlersToHaveBeenCalled({ + schemaName: 'metaSchema', + value: { + request: expect.any(Request), + response: expect.any(Response), + }, + arg: undefined, + }) }) - const storeRef = setupApiStore(api, undefined, { - withoutTestLifecycles: true, + test('can be skipped globally', async () => { + const api = makeApi({ globalSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toBeUndefined() }) - const result = await storeRef.store.dispatch(api.endpoints.query.initiate()) - expect(result?.error).toEqual(serializedSchemaError) - expectFailureHandlersToHaveBeenCalled({ - schemaName: 'metaSchema', - value: { - request: expect.any(Request), - response: expect.any(Response), - }, - arg: undefined, + test('can be skipped on the endpoint', async () => { + const api = makeApi({ endpointSkip: true }) + const storeRef = setupApiStore(api, undefined, { + withoutTestLifecycles: true, + }) + const result = await storeRef.store.dispatch( + api.endpoints.query.initiate(), + ) + expect(result?.error).toBeUndefined() }) }) })