From 08bb301456a50f0d4df8cf13f004241b651c1a5d Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 14:02:33 +0700 Subject: [PATCH 01/14] init --- packages/vue-query/.gitignore | 26 ++++++++++++++++++ packages/vue-query/package.json | 47 ++++++++++++++++++++++++++++++++ packages/vue-query/src/index.ts | 3 ++ packages/vue-query/tsconfig.json | 15 ++++++++++ 4 files changed, 91 insertions(+) create mode 100644 packages/vue-query/.gitignore create mode 100644 packages/vue-query/package.json create mode 100644 packages/vue-query/src/index.ts create mode 100644 packages/vue-query/tsconfig.json diff --git a/packages/vue-query/.gitignore b/packages/vue-query/.gitignore new file mode 100644 index 00000000..f3620b55 --- /dev/null +++ b/packages/vue-query/.gitignore @@ -0,0 +1,26 @@ +# Hidden folders and files +.* +!.gitignore +!.*.example + +# Common generated folders +logs/ +node_modules/ +out/ +dist/ +dist-ssr/ +build/ +coverage/ +temp/ + +# Common generated files +*.log +*.log.* +*.tsbuildinfo +*.vitest-temp.json +vite.config.ts.timestamp-* +vitest.config.ts.timestamp-* + +# Common manual ignore files +*.local +*.pem \ No newline at end of file diff --git a/packages/vue-query/package.json b/packages/vue-query/package.json new file mode 100644 index 00000000..4b36537b --- /dev/null +++ b/packages/vue-query/package.json @@ -0,0 +1,47 @@ +{ + "name": "@orpc/vue-query", + "type": "module", + "version": "0.0.0", + "license": "MIT", + "homepage": "https://orpc.unnoq.com", + "repository": { + "type": "git", + "url": "git+https://github.com/unnoq/orpc.git", + "directory": "packages/vue-query" + }, + "keywords": [ + "unnoq", + "orpc", + "vue", + "vue-query", + "tanstack" + ], + "publishConfig": { + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + }, + "./🔒/*": { + "types": "./dist/src/*.d.ts" + } + } + }, + "exports": { + ".": "./src/index.ts", + "./🔒/*": { + "types": "./src/*.ts" + } + }, + "files": [ + "!**/*.map", + "!**/*.tsbuildinfo", + "dist" + ], + "scripts": { + "build": "tsup --clean --sourcemap --entry.index=src/index.ts --format=esm --onSuccess='tsc -b --noCheck'", + "build:watch": "pnpm run build --watch", + "type:check": "tsc -b" + } +} diff --git a/packages/vue-query/src/index.ts b/packages/vue-query/src/index.ts new file mode 100644 index 00000000..2c2d96ee --- /dev/null +++ b/packages/vue-query/src/index.ts @@ -0,0 +1,3 @@ +/** unnoq */ + +export const author = 'unnoq' diff --git a/packages/vue-query/tsconfig.json b/packages/vue-query/tsconfig.json new file mode 100644 index 00000000..b64920aa --- /dev/null +++ b/packages/vue-query/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.lib.json", + "compilerOptions": { + "types": [] + }, + "references": [], + "include": ["src"], + "exclude": [ + "**/*.test.*", + "**/*.test-d.ts", + "**/__tests__/**", + "**/__mocks__/**", + "**/__snapshots__/**" + ] +} From dadd3f8f5d92fae55cfd34b5887dadda7f47df8f Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 14:15:14 +0700 Subject: [PATCH 02/14] utils --- packages/vue-query/package.json | 4 ++ packages/vue-query/src/types.ts | 11 +++ packages/vue-query/src/utils.ts | 21 ++++++ pnpm-lock.yaml | 118 ++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 packages/vue-query/src/types.ts create mode 100644 packages/vue-query/src/utils.ts diff --git a/packages/vue-query/package.json b/packages/vue-query/package.json index 4b36537b..e44d96a1 100644 --- a/packages/vue-query/package.json +++ b/packages/vue-query/package.json @@ -43,5 +43,9 @@ "build": "tsup --clean --sourcemap --entry.index=src/index.ts --format=esm --onSuccess='tsc -b --noCheck'", "build:watch": "pnpm run build --watch", "type:check": "tsc -b" + }, + "peerDependencies": { + "@tanstack/vue-query": ">=5.50.0", + "vue": ">=3.3.0" } } diff --git a/packages/vue-query/src/types.ts b/packages/vue-query/src/types.ts new file mode 100644 index 00000000..a62225dd --- /dev/null +++ b/packages/vue-query/src/types.ts @@ -0,0 +1,11 @@ +import type { ComputedRef, Ref } from 'vue' + +export type MaybeRef = Ref | ComputedRef | T + +export type MaybeRefDeep = MaybeRef< + T extends object + ? { + [K in keyof T]: MaybeRefDeep + } + : T +> diff --git a/packages/vue-query/src/utils.ts b/packages/vue-query/src/utils.ts new file mode 100644 index 00000000..787b0823 --- /dev/null +++ b/packages/vue-query/src/utils.ts @@ -0,0 +1,21 @@ +import type { MaybeRefDeep } from './types' +import { isRef } from 'vue' + +export function deepUnref(value: MaybeRefDeep): T { + if (isRef(value)) { + return deepUnref(value.value) + } + + if (Array.isArray(value)) { + return value.map(deepUnref) as any + } + + if (value && typeof value === 'object') { + return Object.keys(value).reduce((acc, key) => { + (acc as any)[key] = deepUnref((value as any)[key]) + return acc + }, {} as Record) as T + } + + return value as any +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71303044..a8f01ac5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -328,6 +328,15 @@ importers: specifier: ^2.2.1 version: 2.2.1 + packages/vue-query: + dependencies: + '@tanstack/vue-query': + specifier: '>=5.50.0' + version: 5.62.3(vue@3.5.13(typescript@5.7.2)) + vue: + specifier: '>=3.3.0' + version: 3.5.13(typescript@5.7.2) + packages/zod: dependencies: json-schema-typed: @@ -1825,14 +1834,30 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20' + '@tanstack/match-sorter-utils@8.19.4': + resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} + engines: {node: '>=12'} + '@tanstack/query-core@5.59.13': resolution: {integrity: sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ==} + '@tanstack/query-core@5.62.3': + resolution: {integrity: sha512-Jp/nYoz8cnO7kqhOlSv8ke/0MJRJVGuZ0P/JO9KQ+f45mpN90hrerzavyTKeSoT/pOzeoOUkv1Xd0wPsxAWXfg==} + '@tanstack/react-query@5.59.15': resolution: {integrity: sha512-QbVlAkTI78wB4Mqgf2RDmgC0AOiJqer2c5k9STOOSXGv1S6ZkY37r/6UpE8DbQ2Du0ohsdoXgFNEyv+4eDoPEw==} peerDependencies: react: ^18 || ^19 + '@tanstack/vue-query@5.62.3': + resolution: {integrity: sha512-6zU8yR0xKVxb/SilCSVAb0j6+bc++f+YeMA1TnG1qN9zHicWgF9fjtJi86FfIjBnytfFSPwo7Gykp8iId7G9yQ==} + peerDependencies: + '@vue/composition-api': ^1.1.2 + vue: ^2.6.0 || ^3.3.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} @@ -2088,6 +2113,23 @@ packages: '@vue/compiler-ssr@3.5.13': resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/reactivity@3.5.13': + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + + '@vue/runtime-core@3.5.13': + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + + '@vue/runtime-dom@3.5.13': + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + + '@vue/server-renderer@3.5.13': + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} @@ -4384,6 +4426,9 @@ packages: remark@15.0.1: resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + remove-accents@0.5.0: + resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -5034,12 +5079,31 @@ packages: jsdom: optional: true + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + vue-eslint-parser@9.4.3: resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' + vue@3.5.13: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -6568,13 +6632,27 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 3.4.14 + '@tanstack/match-sorter-utils@8.19.4': + dependencies: + remove-accents: 0.5.0 + '@tanstack/query-core@5.59.13': {} + '@tanstack/query-core@5.62.3': {} + '@tanstack/react-query@5.59.15(react@18.3.1)': dependencies: '@tanstack/query-core': 5.59.13 react: 18.3.1 + '@tanstack/vue-query@5.62.3(vue@3.5.13(typescript@5.7.2))': + dependencies: + '@tanstack/match-sorter-utils': 8.19.4 + '@tanstack/query-core': 5.62.3 + '@vue/devtools-api': 6.6.4 + vue: 3.5.13(typescript@5.7.2) + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.2)) + '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.26.2 @@ -6913,6 +6991,30 @@ snapshots: '@vue/compiler-dom': 3.5.13 '@vue/shared': 3.5.13 + '@vue/devtools-api@6.6.4': {} + + '@vue/reactivity@3.5.13': + dependencies: + '@vue/shared': 3.5.13 + + '@vue/runtime-core@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/runtime-dom@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.2))': + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13(typescript@5.7.2) + '@vue/shared@3.5.13': {} '@whatwg-node/fetch@0.10.1': @@ -9820,6 +9922,8 @@ snapshots: transitivePeerDependencies: - supports-color + remove-accents@0.5.0: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -10519,6 +10623,10 @@ snapshots: - supports-color - terser + vue-demi@0.14.10(vue@3.5.13(typescript@5.7.2)): + dependencies: + vue: 3.5.13(typescript@5.7.2) + vue-eslint-parser@9.4.3(eslint@9.15.0(jiti@2.1.0)): dependencies: debug: 4.3.7 @@ -10532,6 +10640,16 @@ snapshots: transitivePeerDependencies: - supports-color + vue@3.5.13(typescript@5.7.2): + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vue/runtime-dom': 3.5.13 + '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.2)) + '@vue/shared': 3.5.13 + optionalDependencies: + typescript: 5.7.2 + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 From 66506868f9b572fe03403fb790af44a6959decf2 Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 15:53:59 +0700 Subject: [PATCH 03/14] wip --- packages/vue-query/package.json | 3 ++ packages/vue-query/src/key.ts | 27 +++++++++++ packages/vue-query/src/procedure-utils.ts | 59 +++++++++++++++++++++++ packages/vue-query/src/types.ts | 41 ++++++++++++++-- packages/vue-query/src/utils.ts | 4 +- packages/vue-query/tsconfig.json | 8 ++- pnpm-lock.yaml | 9 ++++ 7 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 packages/vue-query/src/key.ts create mode 100644 packages/vue-query/src/procedure-utils.ts diff --git a/packages/vue-query/package.json b/packages/vue-query/package.json index e44d96a1..83886b72 100644 --- a/packages/vue-query/package.json +++ b/packages/vue-query/package.json @@ -45,6 +45,9 @@ "type:check": "tsc -b" }, "peerDependencies": { + "@orpc/client": "workspace:*", + "@orpc/contract": "workspace:*", + "@orpc/server": "workspace:*", "@tanstack/vue-query": ">=5.50.0", "vue": ">=3.3.0" } diff --git a/packages/vue-query/src/key.ts b/packages/vue-query/src/key.ts new file mode 100644 index 00000000..d2a41d87 --- /dev/null +++ b/packages/vue-query/src/key.ts @@ -0,0 +1,27 @@ +import type { PartialDeep } from '@orpc/shared' +import type { QueryKey } from '@tanstack/vue-query' + +export type KeyType = 'query' | 'infinite' | 'mutation' | undefined + +export interface BuildKeyOptions { + type?: TType + input?: TType extends 'mutation' ? never : PartialDeep +} + +export function buildKey( + path: string[], + options?: BuildKeyOptions, +): QueryKey { + const withInput + = options?.input !== undefined ? { input: options?.input } : {} + const withType = options?.type !== undefined ? { type: options?.type } : {} + + return [ + '__ORPC__', + path, + { + ...withInput, + ...withType, + }, + ] +} diff --git a/packages/vue-query/src/procedure-utils.ts b/packages/vue-query/src/procedure-utils.ts new file mode 100644 index 00000000..79bc2092 --- /dev/null +++ b/packages/vue-query/src/procedure-utils.ts @@ -0,0 +1,59 @@ +import type { IsEqual } from '@orpc/shared' +import type { QueryKey } from '@tanstack/vue-query' +import type { InfiniteOptions, MutationOptions, QueryOptions } from './types' +import { buildKey } from './key' +import { deepUnref } from './utils' + +/** + * Utils at procedure level + */ +export interface ProcedureUtils { + queryOptions: >( + ...options: [U] | (undefined extends TInput ? [] : never) + ) => IsEqual> extends true + ? { queryKey: QueryKey, queryFn: () => Promise } + : Omit<{ queryKey: QueryKey, queryFn: () => Promise }, keyof U> & U + + infiniteOptions: >( + options: U + ) => Omit<{ queryKey: QueryKey, queryFn: () => Promise, initialPageParam: undefined }, keyof U> & U + + mutationOptions: >( + options?: U + ) => Omit<{ mutationKey: QueryKey, mutationFn: (input: TInput) => Promise }, keyof U> & U +} + +export function createProcedureUtils( + client: (input: TInput) => Promise, + path: string[], +): ProcedureUtils { + return { + queryOptions(...[options]) { + const input = options?.input as any + + return { + queryKey: buildKey(path, { type: 'query', input }), + queryFn: () => client(deepUnref(input)), + ...(options as any), + } + }, + + infiniteOptions(options) { + const input = options.input as any + + return { + queryKey: buildKey(path, { type: 'infinite', input }), + queryFn: ({ pageParam }) => client({ ...deepUnref(input), cursor: pageParam }), + ...(options as any), + } + }, + + mutationOptions(options) { + return { + mutationKey: buildKey(path, { type: 'mutation' }), + mutationFn: input => client(input), + ...(options as any), + } + }, + } +} diff --git a/packages/vue-query/src/types.ts b/packages/vue-query/src/types.ts index a62225dd..e0084dc1 100644 --- a/packages/vue-query/src/types.ts +++ b/packages/vue-query/src/types.ts @@ -1,11 +1,42 @@ -import type { ComputedRef, Ref } from 'vue' +import type { SetOptional } from '@orpc/shared' +import type { DefaultError, MutationObserverOptions, QueryKey, QueryObserverOptions, UseInfiniteQueryOptions } from '@tanstack/vue-query' +import type { MaybeRef, MaybeRefOrGetter } from 'vue' -export type MaybeRef = Ref | ComputedRef | T - -export type MaybeRefDeep = MaybeRef< +export type MaybeDeepRef = MaybeRef< T extends object ? { - [K in keyof T]: MaybeRefDeep + [K in keyof T]: MaybeDeepRef } : T > + +export type NonUndefinedGuard = T extends undefined ? never : T + +export type InferCursor = T extends { cursor?: any } ? T['cursor'] : never + +export type QueryOptions = + & (undefined extends TInput ? { input?: MaybeDeepRef } : { input: MaybeDeepRef }) + & SetOptional<{ + [P in keyof QueryObserverOptions]: P extends 'enabled' + ? MaybeRefOrGetter[P]>> + : MaybeDeepRef[P]> + }, 'queryKey'> + & { + shallow?: MaybeRef + initialData?: NonUndefinedGuard | (() => NonUndefinedGuard) | undefined + } + +export type InfiniteOptions = + & (undefined extends TInput ? { input?: MaybeDeepRef> } : { input: MaybeDeepRef> }) + & SetOptional< + UseInfiniteQueryOptions>, + 'queryKey' | (undefined extends InferCursor ? 'initialPageParam' : never) + > + +export type MutationOptions = + & SetOptional<{ + [P in keyof MutationObserverOptions]: MaybeDeepRef[P]> + }, 'mutationKey' | 'mutationFn'> + & { + shallow?: MaybeRef + } diff --git a/packages/vue-query/src/utils.ts b/packages/vue-query/src/utils.ts index 787b0823..91a2deda 100644 --- a/packages/vue-query/src/utils.ts +++ b/packages/vue-query/src/utils.ts @@ -1,7 +1,7 @@ -import type { MaybeRefDeep } from './types' +import type { MaybeDeepRef } from './types' import { isRef } from 'vue' -export function deepUnref(value: MaybeRefDeep): T { +export function deepUnref(value: MaybeDeepRef): T { if (isRef(value)) { return deepUnref(value.value) } diff --git a/packages/vue-query/tsconfig.json b/packages/vue-query/tsconfig.json index b64920aa..8d7235f7 100644 --- a/packages/vue-query/tsconfig.json +++ b/packages/vue-query/tsconfig.json @@ -3,10 +3,16 @@ "compilerOptions": { "types": [] }, - "references": [], + "references": [ + { "path": "../client" }, + { "path": "../contract" }, + { "path": "../shared" }, + { "path": "../server" } + ], "include": ["src"], "exclude": [ "**/*.test.*", + "**/*.bench.*", "**/*.test-d.ts", "**/__tests__/**", "**/__mocks__/**", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8f01ac5..3c979d57 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -330,6 +330,15 @@ importers: packages/vue-query: dependencies: + '@orpc/client': + specifier: workspace:* + version: link:../client + '@orpc/contract': + specifier: workspace:* + version: link:../contract + '@orpc/server': + specifier: workspace:* + version: link:../server '@tanstack/vue-query': specifier: '>=5.50.0' version: 5.62.3(vue@3.5.13(typescript@5.7.2)) From 0e500c7fbdb054b99f6fe3edcd73bf5d51f00a5b Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 16:38:22 +0700 Subject: [PATCH 04/14] tests --- packages/vue-query/src/index.ts | 10 +- packages/vue-query/src/key.test.ts | 17 ++ packages/vue-query/src/key.ts | 2 + packages/vue-query/src/types.ts | 4 +- .../vue-query/src/utils-general.test-d.ts | 30 +++ packages/vue-query/src/utils-general.test.ts | 17 ++ packages/vue-query/src/utils-general.ts | 20 ++ .../vue-query/src/utils-procedure.test-d.ts | 241 ++++++++++++++++++ .../vue-query/src/utils-procedure.test.ts | 70 +++++ ...{procedure-utils.ts => utils-procedure.ts} | 4 +- packages/vue-query/src/utils-router.test-d.ts | 57 +++++ packages/vue-query/src/utils-router.test.ts | 67 +++++ packages/vue-query/src/utils-router.ts | 56 ++++ packages/vue-query/tests/e2e.test.ts | 60 +++++ packages/vue-query/tests/helpers.ts | 117 +++++++++ 15 files changed, 767 insertions(+), 5 deletions(-) create mode 100644 packages/vue-query/src/key.test.ts create mode 100644 packages/vue-query/src/utils-general.test-d.ts create mode 100644 packages/vue-query/src/utils-general.test.ts create mode 100644 packages/vue-query/src/utils-general.ts create mode 100644 packages/vue-query/src/utils-procedure.test-d.ts create mode 100644 packages/vue-query/src/utils-procedure.test.ts rename packages/vue-query/src/{procedure-utils.ts => utils-procedure.ts} (88%) create mode 100644 packages/vue-query/src/utils-router.test-d.ts create mode 100644 packages/vue-query/src/utils-router.test.ts create mode 100644 packages/vue-query/src/utils-router.ts create mode 100644 packages/vue-query/tests/e2e.test.ts create mode 100644 packages/vue-query/tests/helpers.ts diff --git a/packages/vue-query/src/index.ts b/packages/vue-query/src/index.ts index 2c2d96ee..58c234b8 100644 --- a/packages/vue-query/src/index.ts +++ b/packages/vue-query/src/index.ts @@ -1,3 +1,9 @@ -/** unnoq */ +import { createRouterUtils } from './utils-router' -export const author = 'unnoq' +export * from './key' +export * from './types' +export * from './utils-general' +export * from './utils-procedure' +export * from './utils-router' + +export const createORPCVueQueryUtils = createRouterUtils diff --git a/packages/vue-query/src/key.test.ts b/packages/vue-query/src/key.test.ts new file mode 100644 index 00000000..5fbd7e54 --- /dev/null +++ b/packages/vue-query/src/key.test.ts @@ -0,0 +1,17 @@ +import { buildKey } from './key' + +describe('buildKey', () => { + it('works', () => { + expect(buildKey(['path'])).toEqual(['__ORPC__', ['path'], {}]) + expect(buildKey(['path'], { type: 'query' })).toEqual(['__ORPC__', ['path'], { type: 'query' }]) + + expect(buildKey(['path'], { type: 'query', input: { a: 1 } })) + .toEqual(['__ORPC__', ['path'], { type: 'query', input: { a: 1 } }]) + + expect(buildKey(['path'], { type: 'query', input: undefined })) + .toEqual(['__ORPC__', ['path'], { type: 'query' }]) + + expect(buildKey(['path'], { type: undefined, input: undefined })) + .toEqual(['__ORPC__', ['path'], {}]) + }) +}) diff --git a/packages/vue-query/src/key.ts b/packages/vue-query/src/key.ts index d2a41d87..ba518883 100644 --- a/packages/vue-query/src/key.ts +++ b/packages/vue-query/src/key.ts @@ -1,6 +1,8 @@ import type { PartialDeep } from '@orpc/shared' import type { QueryKey } from '@tanstack/vue-query' +// TODO: this file duplicate with react query + export type KeyType = 'query' | 'infinite' | 'mutation' | undefined export interface BuildKeyOptions { diff --git a/packages/vue-query/src/types.ts b/packages/vue-query/src/types.ts index e0084dc1..7d2e5904 100644 --- a/packages/vue-query/src/types.ts +++ b/packages/vue-query/src/types.ts @@ -34,9 +34,9 @@ export type InfiniteOptions = > export type MutationOptions = - & SetOptional<{ + & { [P in keyof MutationObserverOptions]: MaybeDeepRef[P]> - }, 'mutationKey' | 'mutationFn'> + } & { shallow?: MaybeRef } diff --git a/packages/vue-query/src/utils-general.test-d.ts b/packages/vue-query/src/utils-general.test-d.ts new file mode 100644 index 00000000..1d0210c9 --- /dev/null +++ b/packages/vue-query/src/utils-general.test-d.ts @@ -0,0 +1,30 @@ +import { createGeneralUtils } from './utils-general' + +describe('key', () => { + const utils = createGeneralUtils<{ a: { b: { c: number } } }>([]) + + it('infer correct input type & partial input', () => { + utils.key() + utils.key({}) + utils.key({ type: 'infinite' }) + utils.key({ input: {}, type: 'query' }) + utils.key({ input: {} }) + utils.key({ input: { a: {} } }) + utils.key({ input: { a: { b: {} } } }) + utils.key({ input: { a: { b: { c: 1 } } } }) + + // @ts-expect-error invalid input + utils.key({ input: 123 }) + // @ts-expect-error invalid input + utils.key({ input: { a: { b: { c: '1' } } } }) + + // @ts-expect-error invalid input + utils.key({ type: 'ddd' }) + }) + + it('it prevent pass input when type is mutation', () => { + utils.key({ type: 'mutation' }) + // @ts-expect-error input is not allowed when type is mutation + utils.key({ input: {}, type: 'mutation' }) + }) +}) diff --git a/packages/vue-query/src/utils-general.test.ts b/packages/vue-query/src/utils-general.test.ts new file mode 100644 index 00000000..0d43971e --- /dev/null +++ b/packages/vue-query/src/utils-general.test.ts @@ -0,0 +1,17 @@ +import * as keyModule from './key' +import { createGeneralUtils } from './utils-general' + +const buildKeySpy = vi.spyOn(keyModule, 'buildKey') + +beforeEach(() => { + buildKeySpy.mockClear() +}) + +describe('key', () => { + it('works', () => { + const utils = createGeneralUtils(['path']) + expect(utils.key({ input: 'input', type: 'infinite' })).toEqual(['__ORPC__', ['path'], { input: 'input', type: 'infinite' }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith(['path'], { input: 'input', type: 'infinite' }) + }) +}) diff --git a/packages/vue-query/src/utils-general.ts b/packages/vue-query/src/utils-general.ts new file mode 100644 index 00000000..ecaa92b0 --- /dev/null +++ b/packages/vue-query/src/utils-general.ts @@ -0,0 +1,20 @@ +import type { QueryKey } from '@tanstack/vue-query' +import type { BuildKeyOptions, KeyType } from './key' +import { buildKey } from './key' + +/** + * Utils at any level (procedure or router) + */ +export interface GeneralUtils { + key: (options?: BuildKeyOptions) => QueryKey +} + +export function createGeneralUtils( + path: string[], +): GeneralUtils { + return { + key(options) { + return buildKey(path, options) + }, + } +} diff --git a/packages/vue-query/src/utils-procedure.test-d.ts b/packages/vue-query/src/utils-procedure.test-d.ts new file mode 100644 index 00000000..897aa34d --- /dev/null +++ b/packages/vue-query/src/utils-procedure.test-d.ts @@ -0,0 +1,241 @@ +import type { InfiniteData } from '@tanstack/react-query' +import { useInfiniteQuery, useQuery } from '@tanstack/react-query' +import { createProcedureUtils } from './utils-procedure' + +describe('queryOptions', () => { + const client = vi.fn((input: number | undefined) => Promise.resolve(input?.toString())) + const utils = createProcedureUtils(client, []) + + const client2 = vi.fn((input: number) => Promise.resolve(input.toString())) + const utils2 = createProcedureUtils(client2, []) + + it('infer correct input type', () => { + utils.queryOptions({ input: 1 }) + utils.queryOptions({ input: undefined }) + + // @ts-expect-error invalid input + utils.queryOptions({ input: '1' }) + }) + + it('can be called without argument', () => { + utils.queryOptions() + // @ts-expect-error invalid is required + utils2.queryOptions() + }) + + it('infer correct output type', () => { + const query = useQuery(utils2.queryOptions({ input: 1 })) + + if (query.status === 'success') { + expectTypeOf(query.data).toEqualTypeOf() + } + }) + + it('work with select options', () => { + const query = useQuery(utils2.queryOptions({ + input: 1, + queryFn: () => 1244, + // @ts-expect-error TODO + select(data) { + // @ts-expect-error TODO + expectTypeOf(data).toEqualTypeOf() + + return 'new' as const + }, + })) + + if (query.status === 'success') { + expectTypeOf(query.data).toEqualTypeOf<'new'>() + } + }) +}) + +describe('infiniteOptions', () => { + const getNextPageParam = vi.fn() + + it('cannot use on procedure without input object-able', () => { + const utils = createProcedureUtils({} as (input: number) => Promise, []) + + // @ts-expect-error missing initialPageParam + utils.infiniteOptions({ + input: 123, + getNextPageParam, + }) + + utils.infiniteOptions({ + input: 123, + getNextPageParam, + // @ts-expect-error initialPageParam must be never + initialPageParam: 123, + }) + + utils.infiniteOptions({ + input: 123, + getNextPageParam, + initialPageParam: 123 as never, + }) + }) + + it('infer correct input type', () => { + const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise, []) + + utils.infiniteOptions({ + input: { + limit: 1, + }, + getNextPageParam, + initialPageParam: 1, + }) + utils.infiniteOptions({ + input: { + limit: undefined, + }, + getNextPageParam, + initialPageParam: 1, + + }) + + utils.infiniteOptions({ + input: { + // @ts-expect-error invalid input + limit: 'string', + // cursor will be ignored + cursor: {}, + }, + getNextPageParam, + initialPageParam: 1, + }) + }) + + it('infer correct initialPageParam type', () => { + const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise, []) + + utils.infiniteOptions({ + input: {}, + getNextPageParam, + initialPageParam: 1, + }) + + utils.infiniteOptions({ + input: {}, + getNextPageParam, + // @ts-expect-error initialPageParam must be number + initialPageParam: '234', + }) + + // @ts-expect-error initialPageParam is required + utils.infiniteOptions({ + input: {}, + getNextPageParam, + }) + }) + + it('initialPageParam can be optional', () => { + const utils = createProcedureUtils({} as (input: { limit?: number, cursor?: number }) => Promise, []) + + utils.infiniteOptions({ + input: {}, + getNextPageParam, + }) + + const utils2 = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise, []) + + // @ts-expect-error initialPageParam is required + utils2.infiniteOptions({ + input: {}, + getNextPageParam, + }) + }) + + it('input can be optional', () => { + const utils = createProcedureUtils({} as (input: { limit?: number, cursor?: number } | undefined) => Promise, []) + + utils.infiniteOptions({ + getNextPageParam, + }) + + const utils2 = createProcedureUtils({} as (input: { limit?: number, cursor?: number }) => Promise, []) + + // @ts-expect-error input is required + utils2.infiniteOptions({ + getNextPageParam, + }) + }) + + it('infer correct output type', () => { + const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise, []) + const query = useInfiniteQuery(utils.infiniteOptions({ + input: { + limit: 1, + }, + getNextPageParam: () => 1, + initialPageParam: 1, + })) + + if (query.status === 'success') { + expectTypeOf(query.data).toEqualTypeOf>() + } + }) + + it('work with select options', () => { + const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise, []) + const query = useInfiniteQuery(utils.infiniteOptions({ + input: { + limit: 1, + }, + getNextPageParam, + initialPageParam: 1, + select(data) { + expectTypeOf(data).toEqualTypeOf>() + + return 'new' as const + }, + })) + + if (query.status === 'success') { + expectTypeOf(query.data).toEqualTypeOf<'new'>() + } + }) +}) + +describe('mutationOptions', () => { + const client = vi.fn((input: number) => Promise.resolve(input.toString())) + const utils = createProcedureUtils(client, []) + + it('infer correct input type', () => { + const option = utils.mutationOptions({ + // @ts-expect-error TODO + onSuccess: (data, input) => { + // @ts-expect-error TODO + expectTypeOf(input).toEqualTypeOf() + }, + }) + + option.mutationFn!(1) + + // @ts-expect-error invalid input + option.mutationFn!('1') + // @ts-expect-error invalid input + option.mutationFn!() + }) + + it('infer correct output type', () => { + const option = utils.mutationOptions({ + // @ts-expect-error TODO + onSuccess: (data, input) => { + // @ts-expect-error TODO + expectTypeOf(input).toEqualTypeOf() + // @ts-expect-error TODO + expectTypeOf(data).toEqualTypeOf() + }, + }) + + expectTypeOf(option.mutationFn!(1)).toEqualTypeOf>() + }) + + it('can be called without argument', () => { + const option = utils.mutationOptions() + + expectTypeOf(option.mutationFn).toMatchTypeOf<(input: number) => Promise>() + }) +}) diff --git a/packages/vue-query/src/utils-procedure.test.ts b/packages/vue-query/src/utils-procedure.test.ts new file mode 100644 index 00000000..bfa12c58 --- /dev/null +++ b/packages/vue-query/src/utils-procedure.test.ts @@ -0,0 +1,70 @@ +import * as keyModule from './key' +import { createProcedureUtils } from './utils-procedure' + +const buildKeySpy = vi.spyOn(keyModule, 'buildKey') + +beforeEach(() => { + buildKeySpy.mockClear() +}) + +describe('queryOptions', () => { + const client = vi.fn((input: number | undefined) => Promise.resolve(input?.toString())) + const utils = createProcedureUtils(client, ['ping']) + + it('works', async () => { + const options = utils.queryOptions({ input: 1 }) + + expect(options.queryKey).toEqual(['__ORPC__', ['ping'], { type: 'query', input: 1 }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input: 1 }) + + client.mockResolvedValueOnce('__mocked__') + await expect((options as any).queryFn()).resolves.toEqual('__mocked__') + expect(client).toHaveBeenCalledTimes(1) + expect(client).toBeCalledWith(1) + }) +}) + +describe('infiniteOptions', () => { + const getNextPageParam = vi.fn() + + it('works ', async () => { + const client = vi.fn<(input: { limit?: number, cursor: number | undefined }) => Promise>() + const utils = createProcedureUtils(client, []) + + const options = utils.infiniteOptions({ + input: { limit: 5 }, + getNextPageParam, + initialPageParam: 1, + }) + + expect(options.initialPageParam).toEqual(1) + expect(options.queryKey).toEqual(['__ORPC__', [], { type: 'infinite', input: { limit: 5 } }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: { limit: 5 } }) + + client.mockResolvedValueOnce('__mocked__') + await expect((options as any).queryFn({ pageParam: 1 })).resolves.toEqual('__mocked__') + expect(client).toHaveBeenCalledTimes(1) + expect(client).toBeCalledWith({ limit: 5, cursor: 1 }) + }) + + it('works without initialPageParam', async () => { + const client = vi.fn<(input: { limit?: number, cursor: number | undefined }) => Promise>() + const utils = createProcedureUtils(client, []) + + const options = utils.infiniteOptions({ + input: { limit: 5 }, + getNextPageParam, + }) + + expect(options.queryKey).toEqual(['__ORPC__', [], { type: 'infinite', input: { limit: 5 } }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: { limit: 5 } }) + + client.mockResolvedValueOnce('__mocked__') + await expect((options as any).queryFn({ pageParam: undefined })).resolves.toEqual('__mocked__') + expect(client).toHaveBeenCalledTimes(1) + expect(client).toBeCalledWith({ limit: 5, cursor: undefined }) + }) +}) diff --git a/packages/vue-query/src/procedure-utils.ts b/packages/vue-query/src/utils-procedure.ts similarity index 88% rename from packages/vue-query/src/procedure-utils.ts rename to packages/vue-query/src/utils-procedure.ts index 79bc2092..9c1f604e 100644 --- a/packages/vue-query/src/procedure-utils.ts +++ b/packages/vue-query/src/utils-procedure.ts @@ -20,7 +20,9 @@ export interface ProcedureUtils { mutationOptions: >( options?: U - ) => Omit<{ mutationKey: QueryKey, mutationFn: (input: TInput) => Promise }, keyof U> & U + ) => IsEqual> extends true + ? { mutationKey: QueryKey, mutationFn: (input: TInput) => Promise } + : Omit<{ mutationKey: QueryKey, mutationFn: (input: TInput) => Promise }, keyof U> & U } export function createProcedureUtils( diff --git a/packages/vue-query/src/utils-router.test-d.ts b/packages/vue-query/src/utils-router.test-d.ts new file mode 100644 index 00000000..41d89c73 --- /dev/null +++ b/packages/vue-query/src/utils-router.test-d.ts @@ -0,0 +1,57 @@ +import { oc } from '@orpc/contract' +import { os } from '@orpc/server' +import { z } from 'zod' +import { createGeneralUtils } from './utils-general' +import { createProcedureUtils } from './utils-procedure' +import { createRouterUtils } from './utils-router' + +const pingContract = oc.input(z.object({ name: z.string() })).output(z.string()) +const pongContract = oc.input(z.number()).output(z.string()) +const contractRouter = oc.router({ + ping: pingContract, + pong: pongContract, +}) + +const ping = os.contract(pingContract).func(({ name }) => `ping ${name}`) +const pong = os.contract(pongContract).func(num => `pong ${num}`) + +const router = os.contract(contractRouter).router({ + ping, + pong: os.lazy(() => Promise.resolve({ default: pong })), +}) + +describe('with contract router', () => { + it('build correct types', () => { + const utils = createRouterUtils({} as any) + + const generalUtils = createGeneralUtils([]) + const pingUtils = createProcedureUtils(ping, []) + const pingGeneralUtils = createGeneralUtils<{ name: string }>(['ping']) + const pongUtils = createProcedureUtils(pong, []) + const pongGeneralUtils = createGeneralUtils(['ping']) + + expectTypeOf(utils).toMatchTypeOf() + expectTypeOf(utils.ping).toMatchTypeOf() + expectTypeOf(utils.ping).toMatchTypeOf() + expectTypeOf(utils.pong).toMatchTypeOf() + expectTypeOf(utils.pong).toMatchTypeOf() + }) +}) + +describe('with router', () => { + it('build correct types', () => { + const utils = createRouterUtils({} as any) + + const generalUtils = createGeneralUtils([]) + const pingUtils = createProcedureUtils(ping, []) + const pingGeneralUtils = createGeneralUtils<{ name: string }>(['ping']) + const pongUtils = createProcedureUtils(pong, []) + const pongGeneralUtils = createGeneralUtils(['ping']) + + expectTypeOf(utils).toMatchTypeOf() + expectTypeOf(utils.ping).toMatchTypeOf() + expectTypeOf(utils.ping).toMatchTypeOf() + expectTypeOf(utils.pong).toMatchTypeOf() + expectTypeOf(utils.pong).toMatchTypeOf() + }) +}) diff --git a/packages/vue-query/src/utils-router.test.ts b/packages/vue-query/src/utils-router.test.ts new file mode 100644 index 00000000..ecbb2bcb --- /dev/null +++ b/packages/vue-query/src/utils-router.test.ts @@ -0,0 +1,67 @@ +import * as generalUtilsModule from './utils-general' +import * as procedureUtilsModule from './utils-procedure' +import { createRouterUtils } from './utils-router' + +const procedureUtilsSpy = vi.spyOn(procedureUtilsModule, 'createProcedureUtils') +const generalUtilsSpy = vi.spyOn(generalUtilsModule, 'createGeneralUtils') + +beforeEach(() => { + procedureUtilsSpy.mockClear() + generalUtilsSpy.mockClear() +}) + +describe('router utils', () => { + it('works', () => { + const client = vi.fn() as any + client.ping = vi.fn() + client.ping.peng = vi.fn() + + const utils = createRouterUtils(client) as any + + expect(generalUtilsSpy).toHaveBeenCalledTimes(1) + expect(generalUtilsSpy).toHaveBeenCalledWith([]) + expect(procedureUtilsSpy).toHaveBeenCalledTimes(1) + expect(procedureUtilsSpy).toHaveBeenCalledWith(client, []) + + expect(typeof utils.key).toEqual('function') + expect(typeof utils.queryOptions).toEqual('function') + + generalUtilsSpy.mockClear() + procedureUtilsSpy.mockClear() + void utils.ping + + expect(generalUtilsSpy).toHaveBeenCalledTimes(1) + expect(generalUtilsSpy).toHaveBeenCalledWith(['ping']) + expect(procedureUtilsSpy).toHaveBeenCalledTimes(1) + expect(procedureUtilsSpy).toHaveBeenCalledWith(client.ping, ['ping']) + + expect(typeof utils.ping.key).toEqual('function') + expect(typeof utils.ping.queryOptions).toEqual('function') + + generalUtilsSpy.mockClear() + procedureUtilsSpy.mockClear() + void utils.ping.peng + + expect(generalUtilsSpy).toHaveBeenCalledTimes(2) + expect(generalUtilsSpy).toHaveBeenNthCalledWith(1, ['ping']) + expect(generalUtilsSpy).toHaveBeenNthCalledWith(2, ['ping', 'peng']) + + expect(procedureUtilsSpy).toHaveBeenCalledTimes(2) + expect(procedureUtilsSpy).toHaveBeenNthCalledWith(1, client.ping, ['ping']) + expect(procedureUtilsSpy).toHaveBeenNthCalledWith(2, client.ping.peng, ['ping', 'peng']) + + expect(typeof utils.ping.peng.key).toEqual('function') + expect(typeof utils.ping.peng.queryOptions).toEqual('function') + }) + + it('can custom base path', () => { + const client = vi.fn() as any + + const utils = createRouterUtils(client, ['base']) as any + + expect(generalUtilsSpy).toHaveBeenCalledTimes(1) + expect(generalUtilsSpy).toHaveBeenCalledWith(['base']) + expect(procedureUtilsSpy).toHaveBeenCalledTimes(1) + expect(procedureUtilsSpy).toHaveBeenCalledWith(client, ['base']) + }) +}) diff --git a/packages/vue-query/src/utils-router.ts b/packages/vue-query/src/utils-router.ts new file mode 100644 index 00000000..9f427983 --- /dev/null +++ b/packages/vue-query/src/utils-router.ts @@ -0,0 +1,56 @@ +import type { ContractProcedure, ContractRouter, SchemaInput, SchemaOutput } from '@orpc/contract' +import type { Lazy, Procedure, Router } from '@orpc/server' +import { createGeneralUtils, type GeneralUtils } from './utils-general' +import { createProcedureUtils, type ProcedureUtils } from './utils-procedure' + +export type RouterUtils | ContractRouter> = { + [K in keyof T]: T[K] extends + | ContractProcedure + | Procedure + | Lazy> + ? + & ProcedureUtils, SchemaOutput> + & GeneralUtils> + : T[K] extends Router | ContractRouter + ? RouterUtils + : never +} & GeneralUtils + +/** + * @param client - The client create form `@orpc/client` + * @param path - The base path for query key + */ +export function createRouterUtils | ContractRouter>( + client: any, // TODO typed + path: string[] = [], +): RouterUtils { + const generalUtils = createGeneralUtils(path) + const procedureUtils = createProcedureUtils(client, path) + + const recursive = new Proxy({ + ...generalUtils, + ...procedureUtils, + }, { + get(target, prop) { + const value = Reflect.get(target, prop) + + if (typeof prop !== 'string') { + return value + } + + const nextUtils = createRouterUtils(client[prop], [...path, prop]) + + if (typeof value !== 'function') { + return nextUtils + } + + return new Proxy(value, { + get(_, prop) { + return Reflect.get(nextUtils, prop) + }, + }) + }, + }) + + return recursive as any +} diff --git a/packages/vue-query/tests/e2e.test.ts b/packages/vue-query/tests/e2e.test.ts new file mode 100644 index 00000000..b8a08082 --- /dev/null +++ b/packages/vue-query/tests/e2e.test.ts @@ -0,0 +1,60 @@ +import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/vue-query' +import { orpc, queryClient } from './helpers' + +beforeEach(() => { + queryClient.clear() +}) + +describe('useQuery', () => { + it('works - onSuccess', async () => { + // @ts-expect-error -- TODO + const query = useQuery(orpc.ping.queryOptions(), queryClient) + + expect(queryClient.isFetching({ queryKey: orpc.key() })).toEqual(1) + expect(queryClient.isFetching({ queryKey: orpc.ping.key() })).toEqual(1) + expect(queryClient.isFetching({ queryKey: orpc.ping.key({ type: 'mutation' }) })).toEqual(0) + + await vi.waitFor(() => expect(query.data.value).toEqual('pong')) + + expect(queryClient.getQueryData(orpc.ping.key({ type: 'query' }))).toEqual('pong') + }) + + it('works - onError', async () => { + // @ts-expect-error -- invalid input + const query = useQuery(orpc.user.create.queryOptions({ input: {} }), queryClient) + + await vi.waitFor(() => expect(query.error.value).toEqual(new Error('Validation input failed'))) + + expect(queryClient.getQueryData(orpc.ping.key({ type: 'query' }))).toEqual(undefined) + }) +}) + +describe('useInfiniteQuery', () => { + it('works - onSuccess', async () => { + const query = useInfiniteQuery(orpc.user.list.infiniteOptions({ + input: {}, + getNextPageParam: lastPage => lastPage.nextCursor, + }), queryClient) + + await vi.waitFor(() => expect(query.data.value?.pages.length).toEqual(1)) + + query.fetchNextPage() + + await vi.waitFor(() => expect(query.data.value?.pages.length).toEqual(2)) + }) +}) + +describe('useMutation', () => { + it('works - onSuccess', async () => { + const query = useMutation(orpc.ping.mutationOptions(), queryClient) + + expect(queryClient.isFetching({ queryKey: orpc.ping.key({ type: 'mutation' }) })).toEqual(0) + + query.mutate({}) + + expect(queryClient.isMutating({ mutationKey: orpc.ping.key() })).toEqual(1) + expect(queryClient.isMutating({ mutationKey: orpc.ping.key({ type: 'mutation' }) })).toEqual(1) + + await vi.waitFor(() => expect(query.data.value).toEqual('pong')) + }) +}) diff --git a/packages/vue-query/tests/helpers.ts b/packages/vue-query/tests/helpers.ts new file mode 100644 index 00000000..40285abb --- /dev/null +++ b/packages/vue-query/tests/helpers.ts @@ -0,0 +1,117 @@ +import { createORPCClient } from '@orpc/client' +import { os } from '@orpc/server' +import { createORPCHandler, handleFetchRequest } from '@orpc/server/fetch' +import { QueryClient } from '@tanstack/vue-query' +import { z } from 'zod' +import { createORPCVueQueryUtils } from '../src' + +export const orpcServer = os + +export const ping = orpcServer.func(() => 'pong') + +export const UserSchema = z + .object({ data: z.object({ id: z.string(), name: z.string() }) }) + .transform(data => data.data) +export const UserFindInputSchema = z + .object({ id: z.string() }) + .transform(data => ({ data })) + +export const userFind = orpcServer + .input(UserFindInputSchema) + .output(UserSchema) + .func((input) => { + return { + data: { + id: input.data.id, + name: `name-${input.data.id}`, + }, + } + }) + +export const UserListInputSchema = z + .object({ + keyword: z.string().optional(), + cursor: z.number().default(0), + }) + .transform(data => ({ data })) +export const UserListOutputSchema = z + .object({ + data: z.object({ + nextCursor: z.number(), + users: z.array(UserSchema), + }), + }) + .transform(data => data.data) +export const userList = orpcServer + .input(UserListInputSchema) + .output(UserListOutputSchema) + .func((input) => { + return { + data: { + nextCursor: input.data.cursor + 2, + users: [ + { + data: { + id: `id-${input.data.cursor}`, + name: `number-${input.data.cursor}`, + }, + }, + { + data: { + id: `id-${input.data.cursor + 1}`, + name: `number-${input.data.cursor + 1}`, + }, + }, + ], + }, + } + }) + +export const UserCreateInputSchema = z + .object({ name: z.string() }) + .transform(data => ({ data })) +export const userCreate = orpcServer + .input(UserCreateInputSchema) + .output(UserSchema) + .func((input) => { + return { + data: { + id: '28aa6286-48e9-4f23-adea-3486c86acd55', + name: input.data.name, + }, + } + }) + +export const appRouter = orpcServer.router({ + ping, + user: { + find: userFind, + list: userList, + create: userCreate, + }, +}) + +export const orpcClient = createORPCClient({ + baseURL: 'http://localhost:3000', + + async fetch(...args) { + await new Promise(resolve => setTimeout(resolve, 100)) + const request = new Request(...args) + + return handleFetchRequest({ + router: appRouter, + request, + handlers: [createORPCHandler()], + }) + }, +}) + +export const orpc = createORPCVueQueryUtils(orpcClient) + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, +}) From 10764b28bb9bbe76fd61478f65ab8dac6c72cdd7 Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 18:52:14 +0700 Subject: [PATCH 05/14] tests --- .../vue-query/src/utils-procedure.test-d.ts | 23 +++++-------------- packages/vue-query/tests/e2e.test.ts | 1 - 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/vue-query/src/utils-procedure.test-d.ts b/packages/vue-query/src/utils-procedure.test-d.ts index 897aa34d..0f429c92 100644 --- a/packages/vue-query/src/utils-procedure.test-d.ts +++ b/packages/vue-query/src/utils-procedure.test-d.ts @@ -1,5 +1,5 @@ -import type { InfiniteData } from '@tanstack/react-query' -import { useInfiniteQuery, useQuery } from '@tanstack/react-query' +import type { InfiniteData } from '@tanstack/vue-query' +import { useInfiniteQuery, useQuery } from '@tanstack/vue-query' import { createProcedureUtils } from './utils-procedure' describe('queryOptions', () => { @@ -26,27 +26,20 @@ describe('queryOptions', () => { it('infer correct output type', () => { const query = useQuery(utils2.queryOptions({ input: 1 })) - if (query.status === 'success') { - expectTypeOf(query.data).toEqualTypeOf() - } + expectTypeOf(query.data.value).toEqualTypeOf() }) it('work with select options', () => { const query = useQuery(utils2.queryOptions({ input: 1, - queryFn: () => 1244, - // @ts-expect-error TODO select(data) { - // @ts-expect-error TODO expectTypeOf(data).toEqualTypeOf() return 'new' as const }, })) - if (query.status === 'success') { - expectTypeOf(query.data).toEqualTypeOf<'new'>() - } + expectTypeOf(query.data.value).toEqualTypeOf<'new' | undefined>() }) }) @@ -172,9 +165,7 @@ describe('infiniteOptions', () => { initialPageParam: 1, })) - if (query.status === 'success') { - expectTypeOf(query.data).toEqualTypeOf>() - } + expectTypeOf(query.data.value).toEqualTypeOf | undefined>() }) it('work with select options', () => { @@ -192,9 +183,7 @@ describe('infiniteOptions', () => { }, })) - if (query.status === 'success') { - expectTypeOf(query.data).toEqualTypeOf<'new'>() - } + expectTypeOf(query.data.value).toEqualTypeOf<'new' | undefined>() }) }) diff --git a/packages/vue-query/tests/e2e.test.ts b/packages/vue-query/tests/e2e.test.ts index b8a08082..622e2e34 100644 --- a/packages/vue-query/tests/e2e.test.ts +++ b/packages/vue-query/tests/e2e.test.ts @@ -7,7 +7,6 @@ beforeEach(() => { describe('useQuery', () => { it('works - onSuccess', async () => { - // @ts-expect-error -- TODO const query = useQuery(orpc.ping.queryOptions(), queryClient) expect(queryClient.isFetching({ queryKey: orpc.key() })).toEqual(1) From 3e2f9b35dfb64846fc6e14a93fb33563a8cad0cc Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 19:11:33 +0700 Subject: [PATCH 06/14] fix --- .../vue-query/src/utils-procedure.test-d.ts | 18 +++++++++++------- packages/vue-query/src/utils-procedure.ts | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/vue-query/src/utils-procedure.test-d.ts b/packages/vue-query/src/utils-procedure.test-d.ts index 0f429c92..02b816d8 100644 --- a/packages/vue-query/src/utils-procedure.test-d.ts +++ b/packages/vue-query/src/utils-procedure.test-d.ts @@ -1,4 +1,4 @@ -import type { InfiniteData } from '@tanstack/vue-query' +import type { InfiniteData, QueryKey } from '@tanstack/vue-query' import { useInfiniteQuery, useQuery } from '@tanstack/vue-query' import { createProcedureUtils } from './utils-procedure' @@ -18,7 +18,10 @@ describe('queryOptions', () => { }) it('can be called without argument', () => { - utils.queryOptions() + const options = utils.queryOptions() + + expectTypeOf(options.queryKey).toEqualTypeOf() + expectTypeOf(options.queryFn).toEqualTypeOf<() => Promise>() // @ts-expect-error invalid is required utils2.queryOptions() }) @@ -35,11 +38,11 @@ describe('queryOptions', () => { select(data) { expectTypeOf(data).toEqualTypeOf() - return 'new' as const + return { value: 123 } }, })) - expectTypeOf(query.data.value).toEqualTypeOf<'new' | undefined>() + expectTypeOf(query.data.value).toEqualTypeOf<{ value: number } | undefined>() }) }) @@ -179,11 +182,11 @@ describe('infiniteOptions', () => { select(data) { expectTypeOf(data).toEqualTypeOf>() - return 'new' as const + return { value: 123 } }, })) - expectTypeOf(query.data.value).toEqualTypeOf<'new' | undefined>() + expectTypeOf(query.data.value).toEqualTypeOf<{ value: number } | undefined>() }) }) @@ -219,12 +222,13 @@ describe('mutationOptions', () => { }, }) - expectTypeOf(option.mutationFn!(1)).toEqualTypeOf>() + expectTypeOf(option.mutationFn).toEqualTypeOf<(input: number) => Promise>() }) it('can be called without argument', () => { const option = utils.mutationOptions() + expectTypeOf(option.mutationKey).toEqualTypeOf() expectTypeOf(option.mutationFn).toMatchTypeOf<(input: number) => Promise>() }) }) diff --git a/packages/vue-query/src/utils-procedure.ts b/packages/vue-query/src/utils-procedure.ts index 9c1f604e..7a32918e 100644 --- a/packages/vue-query/src/utils-procedure.ts +++ b/packages/vue-query/src/utils-procedure.ts @@ -8,9 +8,9 @@ import { deepUnref } from './utils' * Utils at procedure level */ export interface ProcedureUtils { - queryOptions: >( + queryOptions: >( ...options: [U] | (undefined extends TInput ? [] : never) - ) => IsEqual> extends true + ) => IsEqual> extends true ? { queryKey: QueryKey, queryFn: () => Promise } : Omit<{ queryKey: QueryKey, queryFn: () => Promise }, keyof U> & U From 640a9490dec61d8b36357962c8b049495af6b2c9 Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 19:45:54 +0700 Subject: [PATCH 07/14] ref --- .../vue-query/src/utils-general.test-d.ts | 10 +++++ packages/vue-query/src/utils-general.test.ts | 10 +++++ packages/vue-query/src/utils-general.ts | 6 ++- .../vue-query/src/utils-procedure.test-d.ts | 34 ++++++++++++++- .../vue-query/src/utils-procedure.test.ts | 41 +++++++++++++++++++ packages/vue-query/tests/e2e.test.ts | 36 ++++++++++++++++ packages/vue-query/tests/helpers.ts | 8 +--- 7 files changed, 135 insertions(+), 10 deletions(-) diff --git a/packages/vue-query/src/utils-general.test-d.ts b/packages/vue-query/src/utils-general.test-d.ts index 1d0210c9..ebae4042 100644 --- a/packages/vue-query/src/utils-general.test-d.ts +++ b/packages/vue-query/src/utils-general.test-d.ts @@ -1,3 +1,4 @@ +import { ref } from 'vue' import { createGeneralUtils } from './utils-general' describe('key', () => { @@ -13,11 +14,18 @@ describe('key', () => { utils.key({ input: { a: { b: {} } } }) utils.key({ input: { a: { b: { c: 1 } } } }) + utils.key({ type: ref('infinite'), input: { a: ref({ b: ref({ c: 1 }) }) } }) + // @ts-expect-error invalid input utils.key({ input: 123 }) // @ts-expect-error invalid input utils.key({ input: { a: { b: { c: '1' } } } }) + // @ts-expect-error invalid input + utils.key({ input: ref(123) }) + // @ts-expect-error invalid type + utils.key({ type: ref(123) }) + // @ts-expect-error invalid input utils.key({ type: 'ddd' }) }) @@ -26,5 +34,7 @@ describe('key', () => { utils.key({ type: 'mutation' }) // @ts-expect-error input is not allowed when type is mutation utils.key({ input: {}, type: 'mutation' }) + // @ts-expect-error input is not allowed when type is mutation + utils.key({ input: ref({}), type: 'mutation' }) }) }) diff --git a/packages/vue-query/src/utils-general.test.ts b/packages/vue-query/src/utils-general.test.ts index 0d43971e..367a7940 100644 --- a/packages/vue-query/src/utils-general.test.ts +++ b/packages/vue-query/src/utils-general.test.ts @@ -1,3 +1,4 @@ +import { ref } from 'vue' import * as keyModule from './key' import { createGeneralUtils } from './utils-general' @@ -14,4 +15,13 @@ describe('key', () => { expect(buildKeySpy).toHaveBeenCalledTimes(1) expect(buildKeySpy).toHaveBeenCalledWith(['path'], { input: 'input', type: 'infinite' }) }) + + it('works with ref', () => { + const utils = createGeneralUtils(['path']) + expect(utils.key({ input: ref({ + value: ref('input'), + }), type: 'infinite' })).toEqual(['__ORPC__', ['path'], { input: { value: 'input' }, type: 'infinite' }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith(['path'], { input: { value: 'input' }, type: 'infinite' }) + }) }) diff --git a/packages/vue-query/src/utils-general.ts b/packages/vue-query/src/utils-general.ts index ecaa92b0..cc667594 100644 --- a/packages/vue-query/src/utils-general.ts +++ b/packages/vue-query/src/utils-general.ts @@ -1,12 +1,14 @@ import type { QueryKey } from '@tanstack/vue-query' import type { BuildKeyOptions, KeyType } from './key' +import type { MaybeDeepRef } from './types' import { buildKey } from './key' +import { deepUnref } from './utils' /** * Utils at any level (procedure or router) */ export interface GeneralUtils { - key: (options?: BuildKeyOptions) => QueryKey + key: (options?: MaybeDeepRef>) => QueryKey } export function createGeneralUtils( @@ -14,7 +16,7 @@ export function createGeneralUtils( ): GeneralUtils { return { key(options) { - return buildKey(path, options) + return buildKey(path, deepUnref(options as any)) }, } } diff --git a/packages/vue-query/src/utils-procedure.test-d.ts b/packages/vue-query/src/utils-procedure.test-d.ts index 02b816d8..a67001f7 100644 --- a/packages/vue-query/src/utils-procedure.test-d.ts +++ b/packages/vue-query/src/utils-procedure.test-d.ts @@ -1,5 +1,6 @@ import type { InfiniteData, QueryKey } from '@tanstack/vue-query' import { useInfiniteQuery, useQuery } from '@tanstack/vue-query' +import { ref } from 'vue' import { createProcedureUtils } from './utils-procedure' describe('queryOptions', () => { @@ -11,10 +12,14 @@ describe('queryOptions', () => { it('infer correct input type', () => { utils.queryOptions({ input: 1 }) + utils.queryOptions({ input: ref(1) }) utils.queryOptions({ input: undefined }) + utils.queryOptions({ input: ref(undefined) }) // @ts-expect-error invalid input utils.queryOptions({ input: '1' }) + // @ts-expect-error invalid input + utils.queryOptions({ input: ref('1') }) }) it('can be called without argument', () => { @@ -88,7 +93,21 @@ describe('infiniteOptions', () => { }, getNextPageParam, initialPageParam: 1, + }) + utils.infiniteOptions({ + input: { + limit: ref(1), + }, + getNextPageParam, + initialPageParam: 1, + }) + utils.infiniteOptions({ + input: { + limit: undefined, + }, + getNextPageParam, + initialPageParam: 1, }) utils.infiniteOptions({ @@ -112,6 +131,12 @@ describe('infiniteOptions', () => { initialPageParam: 1, }) + utils.infiniteOptions({ + input: {}, + getNextPageParam, + initialPageParam: ref(1), + }) + utils.infiniteOptions({ input: {}, getNextPageParam, @@ -119,6 +144,13 @@ describe('infiniteOptions', () => { initialPageParam: '234', }) + utils.infiniteOptions({ + input: {}, + getNextPageParam, + // @ts-expect-error initialPageParam must be number + initialPageParam: ref('234'), + }) + // @ts-expect-error initialPageParam is required utils.infiniteOptions({ input: {}, @@ -175,7 +207,7 @@ describe('infiniteOptions', () => { const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise, []) const query = useInfiniteQuery(utils.infiniteOptions({ input: { - limit: 1, + limit: ref(1), }, getNextPageParam, initialPageParam: 1, diff --git a/packages/vue-query/src/utils-procedure.test.ts b/packages/vue-query/src/utils-procedure.test.ts index bfa12c58..faa98e47 100644 --- a/packages/vue-query/src/utils-procedure.test.ts +++ b/packages/vue-query/src/utils-procedure.test.ts @@ -1,3 +1,4 @@ +import { ref } from 'vue' import * as keyModule from './key' import { createProcedureUtils } from './utils-procedure' @@ -11,6 +12,10 @@ describe('queryOptions', () => { const client = vi.fn((input: number | undefined) => Promise.resolve(input?.toString())) const utils = createProcedureUtils(client, ['ping']) + beforeEach(() => { + client.mockClear() + }) + it('works', async () => { const options = utils.queryOptions({ input: 1 }) @@ -23,6 +28,20 @@ describe('queryOptions', () => { expect(client).toHaveBeenCalledTimes(1) expect(client).toBeCalledWith(1) }) + + it('works with ref', async () => { + const input = ref(1) + const options = utils.queryOptions({ input }) + + expect(options.queryKey).toEqual(['__ORPC__', ['ping'], { type: 'query', input }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input }) + + client.mockResolvedValueOnce('__mocked__') + await expect((options as any).queryFn()).resolves.toEqual('__mocked__') + expect(client).toHaveBeenCalledTimes(1) + expect(client).toBeCalledWith(1) + }) }) describe('infiniteOptions', () => { @@ -67,4 +86,26 @@ describe('infiniteOptions', () => { expect(client).toHaveBeenCalledTimes(1) expect(client).toBeCalledWith({ limit: 5, cursor: undefined }) }) + + it('works with ref', async () => { + const client = vi.fn<(input: { limit?: number, cursor: number | undefined }) => Promise>() + const utils = createProcedureUtils(client, []) + + const input = ref({ limit: ref(5) }) + const options = utils.infiniteOptions({ + input, + getNextPageParam, + initialPageParam: 1, + }) + + expect(options.initialPageParam).toEqual(1) + expect(options.queryKey).toEqual(['__ORPC__', [], { type: 'infinite', input }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input }) + + client.mockResolvedValueOnce('__mocked__') + await expect((options as any).queryFn({ pageParam: 1 })).resolves.toEqual('__mocked__') + expect(client).toHaveBeenCalledTimes(1) + expect(client).toBeCalledWith({ limit: 5, cursor: 1 }) + }) }) diff --git a/packages/vue-query/tests/e2e.test.ts b/packages/vue-query/tests/e2e.test.ts index 622e2e34..ee6018a3 100644 --- a/packages/vue-query/tests/e2e.test.ts +++ b/packages/vue-query/tests/e2e.test.ts @@ -1,4 +1,5 @@ import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/vue-query' +import { ref } from 'vue' import { orpc, queryClient } from './helpers' beforeEach(() => { @@ -18,6 +19,20 @@ describe('useQuery', () => { expect(queryClient.getQueryData(orpc.ping.key({ type: 'query' }))).toEqual('pong') }) + it('works - with ref', async () => { + const id = ref('id-1') + + const query = useQuery(orpc.user.find.queryOptions({ + input: ref({ id }), + }), queryClient) + + await vi.waitFor(() => expect(query.data.value).toEqual({ id: 'id-1', name: 'name-id-1' })) + + id.value = 'id-2' + + await vi.waitFor(() => expect(query.data.value).toEqual({ id: 'id-2', name: 'name-id-2' })) + }) + it('works - onError', async () => { // @ts-expect-error -- invalid input const query = useQuery(orpc.user.create.queryOptions({ input: {} }), queryClient) @@ -41,6 +56,27 @@ describe('useInfiniteQuery', () => { await vi.waitFor(() => expect(query.data.value?.pages.length).toEqual(2)) }) + + it('works - with ref', async () => { + const keyword = ref('keyword-1') + + const query = useInfiniteQuery(orpc.user.list.infiniteOptions({ + input: { keyword }, + getNextPageParam: lastPage => lastPage.nextCursor, + }), queryClient) + + await vi.waitFor(() => expect(query.data.value?.pages.length).toEqual(1)) + expect(query.data.value?.pages[0]!.users[0]?.name).toEqual('number-keyword-1') + + query.fetchNextPage() + + await vi.waitFor(() => expect(query.data.value?.pages.length).toEqual(2)) + expect(query.data.value?.pages[1]!.users[0]?.name).toEqual('number-keyword-1') + + keyword.value = 'keyword-2' + + await vi.waitFor(() => expect(query.data.value?.pages[0]!.users[0]?.name).toEqual('number-keyword-2')) + }) }) describe('useMutation', () => { diff --git a/packages/vue-query/tests/helpers.ts b/packages/vue-query/tests/helpers.ts index 40285abb..3f7c366c 100644 --- a/packages/vue-query/tests/helpers.ts +++ b/packages/vue-query/tests/helpers.ts @@ -53,13 +53,7 @@ export const userList = orpcServer { data: { id: `id-${input.data.cursor}`, - name: `number-${input.data.cursor}`, - }, - }, - { - data: { - id: `id-${input.data.cursor + 1}`, - name: `number-${input.data.cursor + 1}`, + name: `number-${input.data.keyword}`, }, }, ], From bb53c150f94a4f789c83819b0605d0145e479b30 Mon Sep 17 00:00:00 2001 From: unnoq Date: Tue, 10 Dec 2024 20:29:26 +0700 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=A4=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/shared/src/function.ts | 1 + packages/shared/src/index.ts | 2 +- packages/vue-query/src/types.ts | 14 ++++++++------ packages/vue-query/src/utils-procedure.test-d.ts | 5 ----- 4 files changed, 10 insertions(+), 12 deletions(-) create mode 100644 packages/shared/src/function.ts diff --git a/packages/shared/src/function.ts b/packages/shared/src/function.ts new file mode 100644 index 00000000..6368c0af --- /dev/null +++ b/packages/shared/src/function.ts @@ -0,0 +1 @@ +export type AnyFunction = (...args: any[]) => any diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index da24ae73..e316a271 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,5 +1,5 @@ +export * from './function' export * from './hook' - export * from './json' export * from './object' export * from './value' diff --git a/packages/vue-query/src/types.ts b/packages/vue-query/src/types.ts index 7d2e5904..7f370f66 100644 --- a/packages/vue-query/src/types.ts +++ b/packages/vue-query/src/types.ts @@ -1,13 +1,15 @@ -import type { SetOptional } from '@orpc/shared' +import type { AnyFunction, SetOptional } from '@orpc/shared' import type { DefaultError, MutationObserverOptions, QueryKey, QueryObserverOptions, UseInfiniteQueryOptions } from '@tanstack/vue-query' import type { MaybeRef, MaybeRefOrGetter } from 'vue' export type MaybeDeepRef = MaybeRef< - T extends object - ? { - [K in keyof T]: MaybeDeepRef - } - : T + T extends AnyFunction + ? T + : T extends object + ? { + [K in keyof T]: MaybeDeepRef + } + : T > export type NonUndefinedGuard = T extends undefined ? never : T diff --git a/packages/vue-query/src/utils-procedure.test-d.ts b/packages/vue-query/src/utils-procedure.test-d.ts index a67001f7..338d173f 100644 --- a/packages/vue-query/src/utils-procedure.test-d.ts +++ b/packages/vue-query/src/utils-procedure.test-d.ts @@ -228,9 +228,7 @@ describe('mutationOptions', () => { it('infer correct input type', () => { const option = utils.mutationOptions({ - // @ts-expect-error TODO onSuccess: (data, input) => { - // @ts-expect-error TODO expectTypeOf(input).toEqualTypeOf() }, }) @@ -245,11 +243,8 @@ describe('mutationOptions', () => { it('infer correct output type', () => { const option = utils.mutationOptions({ - // @ts-expect-error TODO onSuccess: (data, input) => { - // @ts-expect-error TODO expectTypeOf(input).toEqualTypeOf() - // @ts-expect-error TODO expectTypeOf(data).toEqualTypeOf() }, }) From bc57ad2b84366bf58b47ed0cc68338d984dd66b2 Mon Sep 17 00:00:00 2001 From: unnoq Date: Wed, 11 Dec 2024 19:35:53 +0700 Subject: [PATCH 09/14] useQueries tests --- packages/vue-query/tests/e2e.test.ts | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/vue-query/tests/e2e.test.ts b/packages/vue-query/tests/e2e.test.ts index ee6018a3..fddf58a6 100644 --- a/packages/vue-query/tests/e2e.test.ts +++ b/packages/vue-query/tests/e2e.test.ts @@ -1,4 +1,4 @@ -import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/vue-query' +import { useInfiniteQuery, useMutation, useQueries, useQuery } from '@tanstack/vue-query' import { ref } from 'vue' import { orpc, queryClient } from './helpers' @@ -93,3 +93,30 @@ describe('useMutation', () => { await vi.waitFor(() => expect(query.data.value).toEqual('pong')) }) }) + +describe('useQueries', () => { + it('works - onSuccess', async () => { + const query = useQueries({ + queries: [ + orpc.user.find.queryOptions({ + input: { id: '0' }, + }), + orpc.user.list.queryOptions({ + input: {}, + }), + ], + }, queryClient) + + await vi.waitFor(() => expect(queryClient.isFetching({ queryKey: orpc.key() })).toEqual(2)) + await vi.waitFor(() => expect(query.value[0].status).toEqual('success')) + await vi.waitFor(() => expect(query.value[1].status).toEqual('success')) + + expect(query.value[0].data).toEqual({ id: '0', name: 'name-0' }) + expect(query.value[1].data).toEqual({ + users: [ + { id: 'id-0', name: 'number-undefined' }, + ], + nextCursor: 2, + }) + }) +}) From a6467cb8e83913316d14b019bb9ba5764b130804 Mon Sep 17 00:00:00 2001 From: unnoq Date: Wed, 11 Dec 2024 19:40:21 +0700 Subject: [PATCH 10/14] type clients --- packages/vue-query/src/utils-procedure.test-d.ts | 7 +++++-- packages/vue-query/src/utils-procedure.test.ts | 5 ++++- packages/vue-query/src/utils-procedure.ts | 3 ++- packages/vue-query/src/utils-router.ts | 7 ++++--- packages/vue-query/tests/helpers.ts | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/vue-query/src/utils-procedure.test-d.ts b/packages/vue-query/src/utils-procedure.test-d.ts index 338d173f..0a0fff05 100644 --- a/packages/vue-query/src/utils-procedure.test-d.ts +++ b/packages/vue-query/src/utils-procedure.test-d.ts @@ -1,10 +1,13 @@ +import type { Caller } from '@orpc/server' import type { InfiniteData, QueryKey } from '@tanstack/vue-query' import { useInfiniteQuery, useQuery } from '@tanstack/vue-query' import { ref } from 'vue' import { createProcedureUtils } from './utils-procedure' describe('queryOptions', () => { - const client = vi.fn((input: number | undefined) => Promise.resolve(input?.toString())) + const client = vi.fn >( + (...[input]) => Promise.resolve(input?.toString()), + ) const utils = createProcedureUtils(client, []) const client2 = vi.fn((input: number) => Promise.resolve(input.toString())) @@ -176,7 +179,7 @@ describe('infiniteOptions', () => { }) it('input can be optional', () => { - const utils = createProcedureUtils({} as (input: { limit?: number, cursor?: number } | undefined) => Promise, []) + const utils = createProcedureUtils({} as Caller<{ limit?: number, cursor?: number } | undefined, string>, []) utils.infiniteOptions({ getNextPageParam, diff --git a/packages/vue-query/src/utils-procedure.test.ts b/packages/vue-query/src/utils-procedure.test.ts index faa98e47..a3aab120 100644 --- a/packages/vue-query/src/utils-procedure.test.ts +++ b/packages/vue-query/src/utils-procedure.test.ts @@ -1,3 +1,4 @@ +import type { Caller } from '@orpc/server' import { ref } from 'vue' import * as keyModule from './key' import { createProcedureUtils } from './utils-procedure' @@ -9,7 +10,9 @@ beforeEach(() => { }) describe('queryOptions', () => { - const client = vi.fn((input: number | undefined) => Promise.resolve(input?.toString())) + const client = vi.fn>( + (...[input]) => Promise.resolve(input?.toString()), + ) const utils = createProcedureUtils(client, ['ping']) beforeEach(() => { diff --git a/packages/vue-query/src/utils-procedure.ts b/packages/vue-query/src/utils-procedure.ts index 7a32918e..5241bfba 100644 --- a/packages/vue-query/src/utils-procedure.ts +++ b/packages/vue-query/src/utils-procedure.ts @@ -1,3 +1,4 @@ +import type { Caller } from '@orpc/server' import type { IsEqual } from '@orpc/shared' import type { QueryKey } from '@tanstack/vue-query' import type { InfiniteOptions, MutationOptions, QueryOptions } from './types' @@ -26,7 +27,7 @@ export interface ProcedureUtils { } export function createProcedureUtils( - client: (input: TInput) => Promise, + client: Caller, path: string[], ): ProcedureUtils { return { diff --git a/packages/vue-query/src/utils-router.ts b/packages/vue-query/src/utils-router.ts index 9f427983..1a34a815 100644 --- a/packages/vue-query/src/utils-router.ts +++ b/packages/vue-query/src/utils-router.ts @@ -1,3 +1,4 @@ +import type { RouterClient } from '@orpc/client' import type { ContractProcedure, ContractRouter, SchemaInput, SchemaOutput } from '@orpc/contract' import type { Lazy, Procedure, Router } from '@orpc/server' import { createGeneralUtils, type GeneralUtils } from './utils-general' @@ -21,11 +22,11 @@ export type RouterUtils | ContractRouter> = { * @param path - The base path for query key */ export function createRouterUtils | ContractRouter>( - client: any, // TODO typed + client: RouterClient, path: string[] = [], ): RouterUtils { const generalUtils = createGeneralUtils(path) - const procedureUtils = createProcedureUtils(client, path) + const procedureUtils = createProcedureUtils(client as any, path) const recursive = new Proxy({ ...generalUtils, @@ -38,7 +39,7 @@ export function createRouterUtils | ContractRouter>( return value } - const nextUtils = createRouterUtils(client[prop], [...path, prop]) + const nextUtils = createRouterUtils((client as any)[prop], [...path, prop]) if (typeof value !== 'function') { return nextUtils diff --git a/packages/vue-query/tests/helpers.ts b/packages/vue-query/tests/helpers.ts index 3f7c366c..4aab9850 100644 --- a/packages/vue-query/tests/helpers.ts +++ b/packages/vue-query/tests/helpers.ts @@ -100,7 +100,7 @@ export const orpcClient = createORPCClient({ }, }) -export const orpc = createORPCVueQueryUtils(orpcClient) +export const orpc = createORPCVueQueryUtils(orpcClient) export const queryClient = new QueryClient({ defaultOptions: { From 0d25b80d35e53e444bc17e47ace484743290a71f Mon Sep 17 00:00:00 2001 From: unnoq Date: Wed, 11 Dec 2024 19:45:57 +0700 Subject: [PATCH 11/14] signal --- .../vue-query/src/utils-procedure.test.ts | 23 +++++++++++-------- packages/vue-query/src/utils-procedure.ts | 4 ++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/vue-query/src/utils-procedure.test.ts b/packages/vue-query/src/utils-procedure.test.ts index a3aab120..adb9aee8 100644 --- a/packages/vue-query/src/utils-procedure.test.ts +++ b/packages/vue-query/src/utils-procedure.test.ts @@ -5,6 +5,9 @@ import { createProcedureUtils } from './utils-procedure' const buildKeySpy = vi.spyOn(keyModule, 'buildKey') +const controller = new AbortController() +const signal = controller.signal + beforeEach(() => { buildKeySpy.mockClear() }) @@ -27,9 +30,9 @@ describe('queryOptions', () => { expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input: 1 }) client.mockResolvedValueOnce('__mocked__') - await expect((options as any).queryFn()).resolves.toEqual('__mocked__') + await expect((options as any).queryFn({ signal })).resolves.toEqual('__mocked__') expect(client).toHaveBeenCalledTimes(1) - expect(client).toBeCalledWith(1) + expect(client).toBeCalledWith(1, { signal }) }) it('works with ref', async () => { @@ -41,9 +44,9 @@ describe('queryOptions', () => { expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input }) client.mockResolvedValueOnce('__mocked__') - await expect((options as any).queryFn()).resolves.toEqual('__mocked__') + await expect((options as any).queryFn({ signal })).resolves.toEqual('__mocked__') expect(client).toHaveBeenCalledTimes(1) - expect(client).toBeCalledWith(1) + expect(client).toBeCalledWith(1, { signal }) }) }) @@ -66,9 +69,9 @@ describe('infiniteOptions', () => { expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: { limit: 5 } }) client.mockResolvedValueOnce('__mocked__') - await expect((options as any).queryFn({ pageParam: 1 })).resolves.toEqual('__mocked__') + await expect((options as any).queryFn({ pageParam: 1, signal })).resolves.toEqual('__mocked__') expect(client).toHaveBeenCalledTimes(1) - expect(client).toBeCalledWith({ limit: 5, cursor: 1 }) + expect(client).toBeCalledWith({ limit: 5, cursor: 1 }, { signal }) }) it('works without initialPageParam', async () => { @@ -85,9 +88,9 @@ describe('infiniteOptions', () => { expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: { limit: 5 } }) client.mockResolvedValueOnce('__mocked__') - await expect((options as any).queryFn({ pageParam: undefined })).resolves.toEqual('__mocked__') + await expect((options as any).queryFn({ pageParam: undefined, signal })).resolves.toEqual('__mocked__') expect(client).toHaveBeenCalledTimes(1) - expect(client).toBeCalledWith({ limit: 5, cursor: undefined }) + expect(client).toBeCalledWith({ limit: 5, cursor: undefined }, { signal }) }) it('works with ref', async () => { @@ -107,8 +110,8 @@ describe('infiniteOptions', () => { expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input }) client.mockResolvedValueOnce('__mocked__') - await expect((options as any).queryFn({ pageParam: 1 })).resolves.toEqual('__mocked__') + await expect((options as any).queryFn({ pageParam: 1, signal })).resolves.toEqual('__mocked__') expect(client).toHaveBeenCalledTimes(1) - expect(client).toBeCalledWith({ limit: 5, cursor: 1 }) + expect(client).toBeCalledWith({ limit: 5, cursor: 1 }, { signal }) }) }) diff --git a/packages/vue-query/src/utils-procedure.ts b/packages/vue-query/src/utils-procedure.ts index 5241bfba..05bdf0c6 100644 --- a/packages/vue-query/src/utils-procedure.ts +++ b/packages/vue-query/src/utils-procedure.ts @@ -36,7 +36,7 @@ export function createProcedureUtils( return { queryKey: buildKey(path, { type: 'query', input }), - queryFn: () => client(deepUnref(input)), + queryFn: ({ signal }) => client(deepUnref(input), { signal }), ...(options as any), } }, @@ -46,7 +46,7 @@ export function createProcedureUtils( return { queryKey: buildKey(path, { type: 'infinite', input }), - queryFn: ({ pageParam }) => client({ ...deepUnref(input), cursor: pageParam }), + queryFn: ({ pageParam, signal }) => client({ ...deepUnref(input), cursor: pageParam }, { signal }), ...(options as any), } }, From 8979a1af08dcad8ede76bd0d9ae7c855d50c966a Mon Sep 17 00:00:00 2001 From: unnoq Date: Wed, 11 Dec 2024 20:11:41 +0700 Subject: [PATCH 12/14] test: mutationOptions --- .../vue-query/src/utils-procedure.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/vue-query/src/utils-procedure.test.ts b/packages/vue-query/src/utils-procedure.test.ts index adb9aee8..1d7db37b 100644 --- a/packages/vue-query/src/utils-procedure.test.ts +++ b/packages/vue-query/src/utils-procedure.test.ts @@ -115,3 +115,27 @@ describe('infiniteOptions', () => { expect(client).toBeCalledWith({ limit: 5, cursor: 1 }, { signal }) }) }) + +describe('mutationOptions', () => { + const client = vi.fn>( + (...[input]) => Promise.resolve(input?.toString()), + ) + const utils = createProcedureUtils(client, ['ping']) + + beforeEach(() => { + client.mockClear() + }) + + it('works', async () => { + const options = utils.mutationOptions() + + expect(options.mutationKey).toEqual(['__ORPC__', ['ping'], { type: 'mutation' }]) + expect(buildKeySpy).toHaveBeenCalledTimes(1) + expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'mutation' }) + + client.mockResolvedValueOnce('__mocked__') + await expect(options.mutationFn(1)).resolves.toEqual('__mocked__') + expect(client).toHaveBeenCalledTimes(1) + expect(client).toBeCalledWith(1) + }) +}) From 956c8f55173d85e17b2006440601689b71bd0247 Mon Sep 17 00:00:00 2001 From: unnoq Date: Wed, 11 Dec 2024 20:26:34 +0700 Subject: [PATCH 13/14] fix queryKey ref problem make buildKey cannot work well --- packages/vue-query/src/utils-procedure.test.ts | 14 +++++++------- packages/vue-query/src/utils-procedure.ts | 10 ++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/vue-query/src/utils-procedure.test.ts b/packages/vue-query/src/utils-procedure.test.ts index 1d7db37b..962a2125 100644 --- a/packages/vue-query/src/utils-procedure.test.ts +++ b/packages/vue-query/src/utils-procedure.test.ts @@ -25,7 +25,7 @@ describe('queryOptions', () => { it('works', async () => { const options = utils.queryOptions({ input: 1 }) - expect(options.queryKey).toEqual(['__ORPC__', ['ping'], { type: 'query', input: 1 }]) + expect(options.queryKey.value).toEqual(['__ORPC__', ['ping'], { type: 'query', input: 1 }]) expect(buildKeySpy).toHaveBeenCalledTimes(1) expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input: 1 }) @@ -39,9 +39,9 @@ describe('queryOptions', () => { const input = ref(1) const options = utils.queryOptions({ input }) - expect(options.queryKey).toEqual(['__ORPC__', ['ping'], { type: 'query', input }]) + expect(options.queryKey.value).toEqual(['__ORPC__', ['ping'], { type: 'query', input: 1 }]) expect(buildKeySpy).toHaveBeenCalledTimes(1) - expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input }) + expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query', input: 1 }) client.mockResolvedValueOnce('__mocked__') await expect((options as any).queryFn({ signal })).resolves.toEqual('__mocked__') @@ -64,7 +64,7 @@ describe('infiniteOptions', () => { }) expect(options.initialPageParam).toEqual(1) - expect(options.queryKey).toEqual(['__ORPC__', [], { type: 'infinite', input: { limit: 5 } }]) + expect(options.queryKey.value).toEqual(['__ORPC__', [], { type: 'infinite', input: { limit: 5 } }]) expect(buildKeySpy).toHaveBeenCalledTimes(1) expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: { limit: 5 } }) @@ -83,7 +83,7 @@ describe('infiniteOptions', () => { getNextPageParam, }) - expect(options.queryKey).toEqual(['__ORPC__', [], { type: 'infinite', input: { limit: 5 } }]) + expect(options.queryKey.value).toEqual(['__ORPC__', [], { type: 'infinite', input: { limit: 5 } }]) expect(buildKeySpy).toHaveBeenCalledTimes(1) expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: { limit: 5 } }) @@ -105,9 +105,9 @@ describe('infiniteOptions', () => { }) expect(options.initialPageParam).toEqual(1) - expect(options.queryKey).toEqual(['__ORPC__', [], { type: 'infinite', input }]) + expect(options.queryKey.value).toEqual(['__ORPC__', [], { type: 'infinite', input: input.value }]) expect(buildKeySpy).toHaveBeenCalledTimes(1) - expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input }) + expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite', input: input.value }) client.mockResolvedValueOnce('__mocked__') await expect((options as any).queryFn({ pageParam: 1, signal })).resolves.toEqual('__mocked__') diff --git a/packages/vue-query/src/utils-procedure.ts b/packages/vue-query/src/utils-procedure.ts index 05bdf0c6..4d897884 100644 --- a/packages/vue-query/src/utils-procedure.ts +++ b/packages/vue-query/src/utils-procedure.ts @@ -1,7 +1,9 @@ import type { Caller } from '@orpc/server' import type { IsEqual } from '@orpc/shared' import type { QueryKey } from '@tanstack/vue-query' +import type { ComputedRef } from 'vue' import type { InfiniteOptions, MutationOptions, QueryOptions } from './types' +import { computed } from 'vue' import { buildKey } from './key' import { deepUnref } from './utils' @@ -13,11 +15,11 @@ export interface ProcedureUtils { ...options: [U] | (undefined extends TInput ? [] : never) ) => IsEqual> extends true ? { queryKey: QueryKey, queryFn: () => Promise } - : Omit<{ queryKey: QueryKey, queryFn: () => Promise }, keyof U> & U + : Omit<{ queryKey: ComputedRef, queryFn: () => Promise }, keyof U> & U infiniteOptions: >( options: U - ) => Omit<{ queryKey: QueryKey, queryFn: () => Promise, initialPageParam: undefined }, keyof U> & U + ) => Omit<{ queryKey: ComputedRef, queryFn: () => Promise, initialPageParam: undefined }, keyof U> & U mutationOptions: >( options?: U @@ -35,7 +37,7 @@ export function createProcedureUtils( const input = options?.input as any return { - queryKey: buildKey(path, { type: 'query', input }), + queryKey: computed(() => buildKey(path, { type: 'query', input: deepUnref(input) })), queryFn: ({ signal }) => client(deepUnref(input), { signal }), ...(options as any), } @@ -45,7 +47,7 @@ export function createProcedureUtils( const input = options.input as any return { - queryKey: buildKey(path, { type: 'infinite', input }), + queryKey: computed(() => buildKey(path, { type: 'infinite', input: deepUnref(input) })), queryFn: ({ pageParam, signal }) => client({ ...deepUnref(input), cursor: pageParam }, { signal }), ...(options as any), } From 2c5c87232d0388d4fb7cd91eb483fb93ff635841 Mon Sep 17 00:00:00 2001 From: unnoq Date: Wed, 11 Dec 2024 21:01:39 +0700 Subject: [PATCH 14/14] docs --- .../content/content/docs/client/vue-query.mdx | 101 ++ apps/content/content/docs/comparisons.mdx | 4 +- apps/content/content/home/landing.mdx | 6 +- apps/content/examples/vue-query.ts | 4 + apps/content/package.json | 7 +- apps/content/tsconfig.json | 1 + packages/next/package.json | 2 +- packages/react-query/package.json | 2 +- packages/react/package.json | 2 +- pnpm-lock.yaml | 862 +++++++----------- 10 files changed, 445 insertions(+), 546 deletions(-) create mode 100644 apps/content/content/docs/client/vue-query.mdx create mode 100644 apps/content/examples/vue-query.ts diff --git a/apps/content/content/docs/client/vue-query.mdx b/apps/content/content/docs/client/vue-query.mdx new file mode 100644 index 00000000..1fc476b8 --- /dev/null +++ b/apps/content/content/docs/client/vue-query.mdx @@ -0,0 +1,101 @@ +--- +title: Vue Query +description: Simplify Vue Query usage with minimal integration using ORPC and TanStack Query +--- + +## Installation + +```package-install +@orpc/client @orpc/vue-query @tanstack/vue-query +``` + +## Setup + +```ts twoslash +import { createORPCVueQueryUtils } from '@orpc/vue-query'; +import { createORPCClient } from '@orpc/client'; +import type { router } from 'examples/server'; + +// Create an ORPC client +export const client = createORPCClient({ + baseURL: 'http://localhost:3000/api', +}); + +// Create Vue Query utilities for ORPC +export const orpc = createORPCVueQueryUtils(client); + +// @noErrors +orpc.getting. +// ^| +``` + +## Multiple ORPC Instances + +To prevent conflicts when using multiple ORPC instances, you can provide a unique base path to `createORPCVueQueryUtils`. + +```tsx twoslash +import { createORPCVueQueryUtils } from '@orpc/vue-query' + +// Create separate ORPC instances with unique base paths +const userORPC = createORPCVueQueryUtils('fake-client' as any, ['__user-api__']) +const postORPC = createORPCVueQueryUtils('fake-client' as any, ['__post-api__']) +``` + +This ensures that each instance manages its own set of query keys and avoids any conflicts. + +## Usage + +### Standard Queries and Mutations + +```ts twoslash +import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query' +import { orpc } from 'examples/vue-query' + +// Fetch data +const { data: gettingData } = useQuery(orpc.getting.queryOptions({ input: { name: 'unnoq' } })) + +// Perform mutations +const { mutate: postMutate } = useMutation(orpc.post.create.mutationOptions()) + +// Invalidate queries +const queryClient = useQueryClient() +queryClient.invalidateQueries({ queryKey: orpc.key() }) // Invalidate all queries +queryClient.invalidateQueries({ queryKey: orpc.post.find.key({ input: { id: 'example' } }) }) // Specific queries +``` + +> **Note**: This library enhances [TanStack Query](https://tanstack.com/query/latest) by managing query keys and functions for you, providing a seamless developer experience. + + +## Infinite Queries + +Infinite queries require a `cursor` in the input field for pagination. + +```ts twoslash +import { os } from '@orpc/server'; +import { z } from 'zod'; +import { createORPCVueQueryUtils } from '@orpc/vue-query'; +import { useInfiniteQuery } from '@tanstack/vue-query'; + +const router = { + user: { + list: os + .input(z.object({ cursor: z.number(), limit: z.number() })) + .func((input) => ({ + nextCursor: input.cursor + input.limit, + users: [], // Fetch your actual data here + })), + }, +}; + +const orpc = createORPCVueQueryUtils('fake-client' as any); + +const query = useInfiniteQuery( + orpc.user.list.infiniteOptions({ + input: { limit: 10 }, + getNextPageParam: (lastPage) => lastPage.nextCursor, + initialPageParam: 0, + }) +); + +console.log(query.data.value); +``` diff --git a/apps/content/content/docs/comparisons.mdx b/apps/content/content/docs/comparisons.mdx index 03d8c408..cf6c885e 100644 --- a/apps/content/content/docs/comparisons.mdx +++ b/apps/content/content/docs/comparisons.mdx @@ -15,10 +15,8 @@ This comparison table helps you understand how oRPC differs from other popular T | End-to-end Type Safety | ✅ | ✅ | ✅ | Full TypeScript type inference from backend to frontend | | SSR Support | ✅ | ✅ | ✅ | Server-side rendering compatibility | | React Query Integration | ✅ | ✅ | 🟡 | Native support for React Query/TanStack Query | -| Vue Query Integration | 🛑 | 🛑 | 🟡 | Native support for Vue Query/TanStack Query | +| Vue Query Integration | ✅ | 🛑 | 🟡 | Native support for Vue Query/TanStack Query | | Contract-First Development | ✅ | 🛑 | ✅ | API definitions before implementation | | File Operations | ✅ | 🟡 | 🟡 | Built-in support for file uploads/downloads | | OpenAPI support | ✅ | 🟡 | 🟡 | Generation and consumption of OpenAPI specs | | Server actions support | ✅ | ✅ | 🛑 | React/Next.js Actions compatibility | - -> In the future, we'll implement full Tanstack query support for Vue, Svelte, Solid, ... \ No newline at end of file diff --git a/apps/content/content/home/landing.mdx b/apps/content/content/home/landing.mdx index 64edb66d..638fc89c 100644 --- a/apps/content/content/home/landing.mdx +++ b/apps/content/content/home/landing.mdx @@ -56,9 +56,7 @@ Our [Vanilla Client](/docs/client/vanilla) is fully typed and doesn't rely on ge ## Seamless Integration with TanStack Query -```tsx -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; - +```ts // Fetch data with oRPC const { data, status } = useQuery( orpc.post.find.queryOptions({ input: { id: 'example' } }) @@ -85,7 +83,7 @@ mutate({ }); ``` -Learn more about [React Query Integration](/docs/client/react-query). +We now support [React Query Integration](/docs/client/react-query) and [Vue Query Integration](/docs/client/vue-query). ## Access via OpenAPI Standard diff --git a/apps/content/examples/vue-query.ts b/apps/content/examples/vue-query.ts new file mode 100644 index 00000000..71dee123 --- /dev/null +++ b/apps/content/examples/vue-query.ts @@ -0,0 +1,4 @@ +import type { router } from 'examples/server' +import { createORPCVueQueryUtils } from '@orpc/vue-query' + +export const orpc = createORPCVueQueryUtils('fake-client' as any) diff --git a/apps/content/package.json b/apps/content/package.json index 0d25ebd5..d0b84c76 100644 --- a/apps/content/package.json +++ b/apps/content/package.json @@ -28,10 +28,13 @@ "@orpc/react": "workspace:*", "@orpc/react-query": "workspace:*", "@orpc/server": "workspace:*", + "@orpc/vue-query": "workspace:*", "@orpc/zod": "workspace:*", + "@tanstack/react-query": "^5.62.7", + "@tanstack/vue-query": "^5.62.7", "@types/express": "^5.0.0", "@types/mdx": "^2.0.13", - "@types/node": "22.9.0", + "@types/node": "^22.9.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@whatwg-node/server": "^0.9.55", @@ -39,7 +42,7 @@ "express": "^4.21.1", "postcss": "^8.4.48", "tailwindcss": "^3.4.14", - "typescript": "^5.6.3", + "typescript": "5.7.2", "zod": "^3.23.8" } } diff --git a/apps/content/tsconfig.json b/apps/content/tsconfig.json index fb4c05b4..c64376c9 100644 --- a/apps/content/tsconfig.json +++ b/apps/content/tsconfig.json @@ -31,6 +31,7 @@ { "path": "../../packages/client" }, { "path": "../../packages/react" }, { "path": "../../packages/react-query" }, + { "path": "../../packages/vue-query" }, { "path": "../../packages/zod" }, { "path": "../../packages/next" } ], diff --git a/packages/next/package.json b/packages/next/package.json index e16076f8..7675c078 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -58,6 +58,6 @@ "@orpc/shared": "workspace:*" }, "devDependencies": { - "zod": "^3.21.4" + "zod": "^3.23.8" } } diff --git a/packages/react-query/package.json b/packages/react-query/package.json index e3e066ac..c23fa98c 100644 --- a/packages/react-query/package.json +++ b/packages/react-query/package.json @@ -55,6 +55,6 @@ "@orpc/shared": "workspace:*" }, "devDependencies": { - "zod": "^3.21.4" + "zod": "^3.23.8" } } diff --git a/packages/react/package.json b/packages/react/package.json index f5374a93..32eb5969 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -45,7 +45,7 @@ "@orpc/client": "workspace:*", "@orpc/contract": "workspace:*", "@orpc/server": "workspace:*", - "@tanstack/react-query": ">=5.59.0", + "@tanstack/react-query": ">=5.55.0", "react": ">=18.3.0" }, "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe95e096..7b999dcc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,19 +61,19 @@ importers: dependencies: fumadocs-core: specifier: 14.4.0 - version: 14.4.0(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.4.0(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) fumadocs-docgen: specifier: ^1.3.2 - version: 1.3.2(typescript@5.6.3) + version: 1.3.2(typescript@5.7.2) fumadocs-mdx: specifier: 11.1.1 - version: 11.1.1(acorn@8.13.0)(fumadocs-core@14.4.0(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + version: 11.1.1(acorn@8.14.0)(fumadocs-core@14.4.0(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) fumadocs-twoslash: specifier: ^2.0.1 - version: 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(fumadocs-ui@14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.14))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(shiki@1.22.2)(typescript@5.6.3) + version: 2.0.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(fumadocs-ui@14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.16))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(shiki@1.24.2)(typescript@5.7.2) fumadocs-ui: specifier: 14.4.0 - version: 14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.14) + version: 14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.16) geist: specifier: ^1.3.1 version: 1.3.1(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) @@ -108,9 +108,18 @@ importers: '@orpc/server': specifier: workspace:* version: link:../../packages/server + '@orpc/vue-query': + specifier: workspace:* + version: link:../../packages/vue-query '@orpc/zod': specifier: workspace:* version: link:../../packages/zod + '@tanstack/react-query': + specifier: ^5.62.7 + version: 5.62.7(react@18.3.1) + '@tanstack/vue-query': + specifier: ^5.62.7 + version: 5.62.7(vue@3.5.13(typescript@5.7.2)) '@types/express': specifier: ^5.0.0 version: 5.0.0 @@ -118,7 +127,7 @@ importers: specifier: ^2.0.13 version: 2.0.13 '@types/node': - specifier: 22.9.0 + specifier: ^22.9.0 version: 22.9.0 '@types/react': specifier: ^18.3.12 @@ -128,25 +137,25 @@ importers: version: 18.3.1 '@whatwg-node/server': specifier: ^0.9.55 - version: 0.9.55 + version: 0.9.61 autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.49) express: specifier: ^4.21.1 - version: 4.21.1 + version: 4.21.2 postcss: specifier: ^8.4.48 version: 8.4.49 tailwindcss: specifier: ^3.4.14 - version: 3.4.14 + version: 3.4.16 typescript: - specifier: ^5.6.3 - version: 5.6.3 + specifier: 5.7.2 + version: 5.7.2 zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 packages/client: dependencies: @@ -168,7 +177,7 @@ importers: version: link:../openapi zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 packages/contract: dependencies: @@ -177,7 +186,7 @@ importers: version: link:../shared zod: specifier: '>=3.23.0' - version: 3.23.8 + version: 3.24.1 packages/next: dependencies: @@ -198,8 +207,8 @@ importers: version: 18.3.1 devDependencies: zod: - specifier: ^3.21.4 - version: 3.23.8 + specifier: ^3.23.8 + version: 3.24.1 packages/openapi: dependencies: @@ -233,10 +242,10 @@ importers: version: 2.6.0(openapi-types@12.1.3) hono: specifier: ^4.6.12 - version: 4.6.12 + version: 4.6.13 zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 packages/react: dependencies: @@ -253,15 +262,15 @@ importers: specifier: workspace:* version: link:../shared '@tanstack/react-query': - specifier: '>=5.59.0' - version: 5.59.15(react@18.3.1) + specifier: '>=5.55.0' + version: 5.62.7(react@18.3.1) react: specifier: '>=18.3.0' version: 18.3.1 devDependencies: zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 packages/react-query: dependencies: @@ -279,14 +288,14 @@ importers: version: link:../shared '@tanstack/react-query': specifier: '>=5.59.0' - version: 5.59.15(react@18.3.1) + version: 5.62.7(react@18.3.1) react: specifier: '>=18.3.0' version: 18.3.1 devDependencies: zod: - specifier: ^3.21.4 - version: 3.23.8 + specifier: ^3.23.8 + version: 3.24.1 packages/server: dependencies: @@ -304,7 +313,7 @@ importers: version: link:../zod zod: specifier: '>=3.23.0' - version: 3.23.8 + version: 3.24.1 devDependencies: '@orpc/openapi': specifier: workspace:* @@ -320,10 +329,10 @@ importers: version: 12.1.0 type-fest: specifier: ^4.26.1 - version: 4.26.1 + version: 4.30.0 zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 packages/transformer: dependencies: @@ -347,14 +356,14 @@ importers: version: 5.1.3 zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 devDependencies: '@anatine/zod-mock': specifier: ^3.13.4 - version: 3.13.4(@faker-js/faker@8.4.1)(zod@3.23.8) + version: 3.13.4(@faker-js/faker@8.4.1)(zod@3.24.1) superjson: specifier: ^2.2.1 - version: 2.2.1 + version: 2.2.2 packages/vue-query: dependencies: @@ -369,7 +378,7 @@ importers: version: link:../server '@tanstack/vue-query': specifier: '>=5.50.0' - version: 5.62.3(vue@3.5.13(typescript@5.7.2)) + version: 5.62.7(vue@3.5.13(typescript@5.7.2)) vue: specifier: '>=3.3.0' version: 3.5.13(typescript@5.7.2) @@ -384,58 +393,13 @@ importers: version: 5.1.3 zod: specifier: ^3.23.8 - version: 3.23.8 + version: 3.24.1 packages: '@adobe/css-tools@4.4.0': resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} - '@algolia/cache-browser-local-storage@4.24.0': - resolution: {integrity: sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==} - - '@algolia/cache-common@4.24.0': - resolution: {integrity: sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==} - - '@algolia/cache-in-memory@4.24.0': - resolution: {integrity: sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==} - - '@algolia/client-account@4.24.0': - resolution: {integrity: sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==} - - '@algolia/client-analytics@4.24.0': - resolution: {integrity: sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==} - - '@algolia/client-common@4.24.0': - resolution: {integrity: sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==} - - '@algolia/client-personalization@4.24.0': - resolution: {integrity: sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==} - - '@algolia/client-search@4.24.0': - resolution: {integrity: sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==} - - '@algolia/logger-common@4.24.0': - resolution: {integrity: sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==} - - '@algolia/logger-console@4.24.0': - resolution: {integrity: sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==} - - '@algolia/recommend@4.24.0': - resolution: {integrity: sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==} - - '@algolia/requester-browser-xhr@4.24.0': - resolution: {integrity: sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==} - - '@algolia/requester-common@4.24.0': - resolution: {integrity: sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==} - - '@algolia/requester-node-http@4.24.0': - resolution: {integrity: sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==} - - '@algolia/transporter@4.24.0': - resolution: {integrity: sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==} - '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -513,10 +477,6 @@ packages: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.7': - resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} @@ -526,10 +486,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.25.9': - resolution: {integrity: sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.26.0': resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} engines: {node: '>=6.9.0'} @@ -1086,8 +1042,8 @@ packages: '@floating-ui/core@1.6.8': resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} - '@floating-ui/dom@1.6.11': - resolution: {integrity: sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==} + '@floating-ui/dom@1.6.12': + resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==} '@floating-ui/react-dom@2.1.2': resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} @@ -1098,8 +1054,8 @@ packages: '@floating-ui/utils@0.2.8': resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} - '@formatjs/intl-localematcher@0.5.7': - resolution: {integrity: sha512-GGFtfHGQVFe/niOZp24Kal5b2i36eE2bNL0xi9Sg/yd0TR8aLjcteApZdHmismP5QQax1cMnZM9yWySUUjJteA==} + '@formatjs/intl-localematcher@0.5.9': + resolution: {integrity: sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -1341,8 +1297,8 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@orama/orama@3.0.1': - resolution: {integrity: sha512-18hl0MiCLmumODHjrLzSdTb1Ny3Dh8tn44jwgx0LksCdvVAsr3jQvfr+hwrE7bVkap0wPELb/dnuJjvupKxheQ==} + '@orama/orama@3.0.3': + resolution: {integrity: sha512-M1LPYzAh7cZgujrrU2MCqVaVsYMfTVvskBcgc2Oc78ppTtlr9rXfZxKC8VPguIf78jxOeJUOspG/Lueo4vAZBQ==} engines: {node: '>= 16.0.0'} '@pkgjs/parseargs@0.11.0': @@ -1598,8 +1554,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-scroll-area@1.2.0': - resolution: {integrity: sha512-q2jMBdsJ9zB7QG6ngQNzNwlvxLQqONyL58QbEGwuyRZZb/ARQwk3uQVbCF7GvQVOtV6EU/pDxAw3zRzJZI3rpQ==} + '@radix-ui/react-scroll-area@1.2.1': + resolution: {integrity: sha512-FnM1fHfCtEZ1JkyfH/1oMiTcFBQvHKl4vD9WnpwkLgtF+UmnXMCad6ECPTaAjcDjam+ndOEJWgHyKDGNteWSHw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -1833,26 +1789,26 @@ packages: '@rushstack/ts-command-line@4.22.8': resolution: {integrity: sha512-XbFjOoV7qZHJnSuFUHv0pKaFA4ixyCuki+xMjsMfDwfvQjs5MYG0IK5COal3tRnG7KCDe2l/G+9LrzYE/RJhgg==} - '@shikijs/core@1.22.2': - resolution: {integrity: sha512-bvIQcd8BEeR1yFvOYv6HDiyta2FFVePbzeowf5pPS1avczrPK+cjmaxxh0nx5QzbON7+Sv0sQfQVciO7bN72sg==} + '@shikijs/core@1.24.2': + resolution: {integrity: sha512-BpbNUSKIwbKrRRA+BQj0BEWSw+8kOPKDJevWeSE/xIqGX7K0xrCZQ9kK0nnEQyrzsUoka1l81ZtJ2mGaCA32HQ==} - '@shikijs/engine-javascript@1.22.2': - resolution: {integrity: sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==} + '@shikijs/engine-javascript@1.24.2': + resolution: {integrity: sha512-EqsmYBJdLEwEiO4H+oExz34a5GhhnVp+jH9Q/XjPjmBPc6TE/x4/gD0X3i0EbkKKNqXYHHJTJUpOLRQNkEzS9Q==} - '@shikijs/engine-oniguruma@1.22.2': - resolution: {integrity: sha512-GIZPAGzQOy56mGvWMoZRPggn0dTlBf1gutV5TdceLCZlFNqWmuc7u+CzD0Gd9vQUTgLbrt0KLzz6FNprqYAxlA==} + '@shikijs/engine-oniguruma@1.24.2': + resolution: {integrity: sha512-ZN6k//aDNWRJs1uKB12pturKHh7GejKugowOFGAuG7TxDRLod1Bd5JhpOikOiFqPmKjKEPtEA6mRCf7q3ulDyQ==} - '@shikijs/rehype@1.22.2': - resolution: {integrity: sha512-A0RHgiYR5uiHvddwHehBN9j8PhOvfT6/GebSTWrapur6M+fD/4i3mlfUv7aFK4b+4GQ1R42L8fC5N98whZjNcg==} + '@shikijs/rehype@1.24.2': + resolution: {integrity: sha512-G4Ks9y2FKwiIrRMIi3GGauyar2F05Ww9e4fbbzE/n2hTBGIcZ2e6KGlBNkDwNvVOGyyAsCpwHQFBMYgd30ZQ3Q==} - '@shikijs/twoslash@1.22.2': - resolution: {integrity: sha512-4R3A7aH/toZgtlveXHKk01nIsvn8hjAfPJ1aT550zcV4qK6vK/tfaEyYtaljOaY1wig2l5+8sKjNSEz3PcSiEw==} + '@shikijs/twoslash@1.24.2': + resolution: {integrity: sha512-zcwYUNdSQDKquF1t+XrtoXM+lx9rCldAkZnT+e5fULKlLT6F8/F9fwICGhBm9lWp5/U4NptH+YcJUdvFOR0SRg==} - '@shikijs/types@1.22.2': - resolution: {integrity: sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==} + '@shikijs/types@1.24.2': + resolution: {integrity: sha512-bdeWZiDtajGLG9BudI0AHet0b6e7FbR0EsE4jpGaI0YwHm/XJunI9+3uZnzFtX65gsyJ6ngCIWUfA4NWRPnBkQ==} - '@shikijs/vscode-textmate@9.3.0': - resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} + '@shikijs/vscode-textmate@9.3.1': + resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==} '@stylistic/eslint-plugin@2.11.0': resolution: {integrity: sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw==} @@ -1875,19 +1831,16 @@ packages: resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} engines: {node: '>=12'} - '@tanstack/query-core@5.59.13': - resolution: {integrity: sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ==} - - '@tanstack/query-core@5.62.3': - resolution: {integrity: sha512-Jp/nYoz8cnO7kqhOlSv8ke/0MJRJVGuZ0P/JO9KQ+f45mpN90hrerzavyTKeSoT/pOzeoOUkv1Xd0wPsxAWXfg==} + '@tanstack/query-core@5.62.7': + resolution: {integrity: sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==} - '@tanstack/react-query@5.59.15': - resolution: {integrity: sha512-QbVlAkTI78wB4Mqgf2RDmgC0AOiJqer2c5k9STOOSXGv1S6ZkY37r/6UpE8DbQ2Du0ohsdoXgFNEyv+4eDoPEw==} + '@tanstack/react-query@5.62.7': + resolution: {integrity: sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==} peerDependencies: react: ^18 || ^19 - '@tanstack/vue-query@5.62.3': - resolution: {integrity: sha512-6zU8yR0xKVxb/SilCSVAb0j6+bc++f+YeMA1TnG1qN9zHicWgF9fjtJi86FfIjBnytfFSPwo7Gykp8iId7G9yQ==} + '@tanstack/vue-query@5.62.7': + resolution: {integrity: sha512-FVSnVw2fw9BHciCbWWSfPMB3PRtGHbGf4Q1Gq7mFlieojiKZBF5Nz5AKFQLKs+IGnrVDTKqfU8ojjPfthPTYxQ==} peerDependencies: '@vue/composition-api': ^1.1.2 vue: ^2.6.0 || ^3.3.0 @@ -1948,8 +1901,8 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/express-serve-static-core@5.0.1': - resolution: {integrity: sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==} + '@types/express-serve-static-core@5.0.2': + resolution: {integrity: sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==} '@types/express@5.0.0': resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==} @@ -2078,8 +2031,8 @@ packages: peerDependencies: typescript: '*' - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@ungap/structured-clone@1.2.1': + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} '@vitest/coverage-v8@2.1.3': resolution: {integrity: sha512-2OJ3c7UPoFSmBZwqD2VEkUw6A/tzPF0LmW0ZZhhB8PFxuc+9IBG/FaSM+RLEenc7ljzFvGN+G0nGQoZnh7sy2A==} @@ -2170,16 +2123,20 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@whatwg-node/disposablestack@0.0.5': + resolution: {integrity: sha512-9lXugdknoIequO4OYvIjhygvfSEgnO8oASLqLelnDhkRjgBZhc39shC3QSlZuyDO9bgYSIVa2cHAiN+St3ty4w==} + engines: {node: '>=18.0.0'} + '@whatwg-node/fetch@0.10.1': resolution: {integrity: sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==} engines: {node: '>=18.0.0'} - '@whatwg-node/node-fetch@0.7.2': - resolution: {integrity: sha512-OAAEIbyspvQwkcRGutYN3D0a+hzQogvcZ7I3hf6vg742ZEq52yMJTGtkwjl3KZRmzzUltd/oEMxEGsXFLjnuLQ==} + '@whatwg-node/node-fetch@0.7.5': + resolution: {integrity: sha512-t7kGrt2fdfNvzy1LCAE9/OnIyMtizgFhgJmk7iLJwQsLmR7S86F8Q4aDRPbCfo7pISJP6Fx/tPdfFNjHS23WTA==} engines: {node: '>=18.0.0'} - '@whatwg-node/server@0.9.55': - resolution: {integrity: sha512-FW04dJZfgBGaGoHQosCTeSOXKksCVzMLMV5YZPMpUfEmkH8VeDjCIMguvw2cKgrjnLjwQ1J3irLg2eNQbLxLNg==} + '@whatwg-node/server@0.9.61': + resolution: {integrity: sha512-MKMs5U2ySnsjV2RaFZM9xszbA6CeRFczVf3iITb2xpHtbBJx4G1HPt09SedFloJ3xiJxbguoBzAQnv6DZEoAWA==} engines: {node: '>=18.0.0'} accepts@1.3.8: @@ -2191,11 +2148,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.13.0: - resolution: {integrity: sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} @@ -2230,12 +2182,6 @@ packages: ajv@8.13.0: resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - - algoliasearch@4.24.0: - resolution: {integrity: sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==} - ansi-escapes@7.0.0: resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} engines: {node: '>=18'} @@ -2365,8 +2311,12 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} call-me-maybe@1.0.2: @@ -2430,8 +2380,8 @@ packages: resolution: {integrity: sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==} engines: {node: '>=8'} - class-variance-authority@0.7.0: - resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} @@ -2452,8 +2402,8 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - clsx@2.0.0: - resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} code-block-writer@13.0.3: @@ -2537,10 +2487,6 @@ packages: core-js-compat@3.39.0: resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2652,6 +2598,10 @@ packages: resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} engines: {node: '>=4'} + dunder-proto@1.0.0: + resolution: {integrity: sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2661,6 +2611,9 @@ packages: electron-to-chromium@1.5.43: resolution: {integrity: sha512-NxnmFBHDl5Sachd2P46O7UJiMaMHMLSofoIWVJq3mj8NJgG0umiSeljAVP9lGzjI0UDLJJ5jjoGjcrB8RSbjLQ==} + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -2693,8 +2646,8 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} es-errors@1.3.0: @@ -3041,8 +2994,8 @@ packages: estree-util-to-js@2.0.0: resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} - estree-util-value-to-estree@3.1.2: - resolution: {integrity: sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==} + estree-util-value-to-estree@3.2.1: + resolution: {integrity: sha512-Vt2UOjyPbNQQgT5eJh+K5aATti0OjCIAGc9SgMdOFYbohuifsWclR74l0iZTJwePMgWYdX1hlVS+dedH9XV8kw==} estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} @@ -3072,8 +3025,8 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} - express@4.21.1: - resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} extend-shallow@2.0.1: @@ -3108,9 +3061,6 @@ packages: fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - fast-uri@3.0.3: - resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} - fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -3214,11 +3164,11 @@ packages: fumadocs-core: ^14.0.0 next: 14.x.x || 15.x.x - fumadocs-twoslash@2.0.1: - resolution: {integrity: sha512-rpc4yci9sSslsmuS3KRp7ByqXFvffpSSMnmCPsByLnHY0t+aUFut7YAfvqJPyALPpj/si9ghaPJG/T1fcrL0uA==} + fumadocs-twoslash@2.0.2: + resolution: {integrity: sha512-3oIy6FaJPrvBV6UqHu3/+CfYPaTtFI2C8S0+EbCc3GvQEBmKXdsNDMbTMBn6hf6YvQrUajgW2mRRJ1JGSVRVuA==} peerDependencies: fumadocs-ui: ^13.0.0 || ^14.0.0 - react: '>= 18' + react: 18.x.x || 19.x.x shiki: 1.x.x fumadocs-typescript@3.0.2: @@ -3253,8 +3203,8 @@ packages: resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} engines: {node: '>=18'} - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + get-intrinsic@1.2.5: + resolution: {integrity: sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==} engines: {node: '>= 0.4'} get-nonce@1.0.1: @@ -3299,8 +3249,9 @@ packages: resolution: {integrity: sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==} engines: {node: '>=18'} - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -3322,12 +3273,8 @@ packages: has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} hasown@2.0.2: @@ -3349,8 +3296,8 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - hono@4.6.12: - resolution: {integrity: sha512-eHtf4kSDNw6VVrdbd5IQi16r22m3s7mWPLd7xOMhg1a/Yyb1A0qpUFq8xYMX4FMuDe1nTKeMX5rTx7Nmw+a+Ag==} + hono@4.6.13: + resolution: {integrity: sha512-haV0gaMdSjy9URCRN9hxBPlqHa7fMm/T72kAImIxvw4eQLbNz1rgjN4hHElLJSieDiNuiIAXC//cC6YGz2KCbg==} engines: {node: '>=16.9.0'} hosted-git-info@2.8.9: @@ -3640,12 +3587,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - - lilconfig@3.1.2: - resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} lines-and-columns@1.2.4: @@ -3741,9 +3684,6 @@ packages: mdast-util-find-and-replace@3.0.1: resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==} - mdast-util-from-markdown@2.0.1: - resolution: {integrity: sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==} - mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} @@ -3998,8 +3938,8 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - next-themes@0.4.3: - resolution: {integrity: sha512-nG84VPkTdUHR2YeD89YchvV4I9RbiMAql3GiLEQlPvq1ioaqPaIReK+yMRdg/zgiXws620qS1rU30TiWmmG9lA==} + next-themes@0.4.4: + resolution: {integrity: sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==} peerDependencies: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc @@ -4085,8 +4025,8 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - oniguruma-to-js@0.4.3: - resolution: {integrity: sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==} + oniguruma-to-es@0.7.0: + resolution: {integrity: sha512-HRaRh09cE0gRS3+wi2zxekB+I5L8C/gN60S+vb11eADHUaB/q4u8wGGOX3GvwvitG8ixaeycZfeoyruKQzUgNg==} openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} @@ -4172,8 +4112,8 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -4182,9 +4122,6 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4345,11 +4282,11 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-medium-image-zoom@5.2.10: - resolution: {integrity: sha512-JBYf4u0zsocezIDtrjwStD+8sX+c8XuLsdz+HxPbojRj0sCicua0XOQKysuPetoFyX+YgStfj+vEtZ+699O/pg==} + react-medium-image-zoom@5.2.12: + resolution: {integrity: sha512-BbQ9jLBFxu6z+viH5tzQzAGqHOJQoYUM7iT1KUkamWKOO6vR1pC33os7LGLrHvOcyySMw74rUdoUCXFdeglwCQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-remove-scroll-bar@2.3.6: resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} @@ -4427,8 +4364,14 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regex@4.3.3: - resolution: {integrity: sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==} + regex-recursion@4.3.0: + resolution: {integrity: sha512-5LcLnizwjcQ2ALfOj95MjcatxyqF5RPySx9yT+PaXu3Gox2vyAtLDjHB8NTJLtMGkvyau6nI3CfpwFCjPUIs/A==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@5.0.2: + resolution: {integrity: sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==} regexp-ast-analysis@0.7.1: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} @@ -4580,8 +4523,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.22.2: - resolution: {integrity: sha512-3IZau0NdGKXhH2bBlUk4w1IHNxPh6A5B2sUpyY+8utLu2j/h1QpFkAaUA1bAMxOWWGtTWcAh531vnS4NJKS/lA==} + shiki@1.24.2: + resolution: {integrity: sha512-TR1fi6mkRrzW+SKT5G6uKuc32Dj2EEa7Kj0k8kGqiBINb+C1TiflVOiT9ta6GqOJtC4fraxO5SLUaKBcSY38Fg==} short-unique-id@5.2.0: resolution: {integrity: sha512-cMGfwNyfDZ/nzJ2k2M+ClthBIh//GlZl1JEf47Uoa9XR11bz8Pa2T2wQO4bVrRdH48LrIDWJahQziKo3MjhsWg==} @@ -4754,8 +4697,8 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true - superjson@2.2.1: - resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} + superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} engines: {node: '>=16'} supports-color@7.2.0: @@ -4781,11 +4724,11 @@ packages: resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} engines: {node: ^14.18.0 || >=16.0.0} - tailwind-merge@2.5.4: - resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} + tailwind-merge@2.5.5: + resolution: {integrity: sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==} - tailwindcss@3.4.14: - resolution: {integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==} + tailwindcss@3.4.16: + resolution: {integrity: sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==} engines: {node: '>=14.0.0'} hasBin: true @@ -4945,8 +4888,8 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} - type-fest@4.26.1: - resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} + type-fest@4.30.0: + resolution: {integrity: sha512-G6zXWS1dLj6eagy6sVhOMQiLtJdxQBHIA9Z6HFUNLOlr6MFOgzV8wvmidtPONfPtEUv0uZsy77XJNzTAfwPDaA==} engines: {node: '>=16'} type-is@1.6.18: @@ -4958,11 +4901,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.7.2: resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} @@ -5252,8 +5190,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -5262,97 +5200,6 @@ snapshots: '@adobe/css-tools@4.4.0': {} - '@algolia/cache-browser-local-storage@4.24.0': - dependencies: - '@algolia/cache-common': 4.24.0 - optional: true - - '@algolia/cache-common@4.24.0': - optional: true - - '@algolia/cache-in-memory@4.24.0': - dependencies: - '@algolia/cache-common': 4.24.0 - optional: true - - '@algolia/client-account@4.24.0': - dependencies: - '@algolia/client-common': 4.24.0 - '@algolia/client-search': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true - - '@algolia/client-analytics@4.24.0': - dependencies: - '@algolia/client-common': 4.24.0 - '@algolia/client-search': 4.24.0 - '@algolia/requester-common': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true - - '@algolia/client-common@4.24.0': - dependencies: - '@algolia/requester-common': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true - - '@algolia/client-personalization@4.24.0': - dependencies: - '@algolia/client-common': 4.24.0 - '@algolia/requester-common': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true - - '@algolia/client-search@4.24.0': - dependencies: - '@algolia/client-common': 4.24.0 - '@algolia/requester-common': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true - - '@algolia/logger-common@4.24.0': - optional: true - - '@algolia/logger-console@4.24.0': - dependencies: - '@algolia/logger-common': 4.24.0 - optional: true - - '@algolia/recommend@4.24.0': - dependencies: - '@algolia/cache-browser-local-storage': 4.24.0 - '@algolia/cache-common': 4.24.0 - '@algolia/cache-in-memory': 4.24.0 - '@algolia/client-common': 4.24.0 - '@algolia/client-search': 4.24.0 - '@algolia/logger-common': 4.24.0 - '@algolia/logger-console': 4.24.0 - '@algolia/requester-browser-xhr': 4.24.0 - '@algolia/requester-common': 4.24.0 - '@algolia/requester-node-http': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true - - '@algolia/requester-browser-xhr@4.24.0': - dependencies: - '@algolia/requester-common': 4.24.0 - optional: true - - '@algolia/requester-common@4.24.0': - optional: true - - '@algolia/requester-node-http@4.24.0': - dependencies: - '@algolia/requester-common': 4.24.0 - optional: true - - '@algolia/transporter@4.24.0': - dependencies: - '@algolia/cache-common': 4.24.0 - '@algolia/logger-common': 4.24.0 - '@algolia/requester-common': 4.24.0 - optional: true - '@alloc/quick-lru@5.2.0': {} '@ampproject/remapping@2.3.0': @@ -5360,11 +5207,11 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@anatine/zod-mock@3.13.4(@faker-js/faker@8.4.1)(zod@3.23.8)': + '@anatine/zod-mock@3.13.4(@faker-js/faker@8.4.1)(zod@3.24.1)': dependencies: '@faker-js/faker': 8.4.1 randexp: 0.5.3 - zod: 3.23.8 + zod: 3.24.1 '@antfu/eslint-config@3.9.2(@eslint-react/eslint-plugin@1.16.2(eslint@9.15.0(jiti@2.1.0))(typescript@5.7.2))(@typescript-eslint/utils@8.15.0(eslint@9.15.0(jiti@2.1.0))(typescript@5.7.2))(@vue/compiler-sfc@3.5.13)(eslint-plugin-format@0.1.2(eslint@9.15.0(jiti@2.1.0)))(eslint-plugin-react-hooks@5.0.0(eslint@9.15.0(jiti@2.1.0)))(eslint-plugin-react-refresh@0.4.14(eslint@9.15.0(jiti@2.1.0)))(eslint@9.15.0(jiti@2.1.0))(typescript@5.7.2)(vitest@2.1.3)': dependencies: @@ -5435,18 +5282,12 @@ snapshots: '@babel/helper-string-parser@7.24.8': {} - '@babel/helper-validator-identifier@7.24.7': {} - '@babel/helper-validator-identifier@7.25.9': {} '@babel/parser@7.25.6': dependencies: '@babel/types': 7.25.6 - '@babel/runtime@7.25.9': - dependencies: - regenerator-runtime: 0.14.1 - '@babel/runtime@7.26.0': dependencies: regenerator-runtime: 0.14.1 @@ -5454,7 +5295,7 @@ snapshots: '@babel/types@7.25.6': dependencies: '@babel/helper-string-parser': 7.24.8 - '@babel/helper-validator-identifier': 7.24.7 + '@babel/helper-validator-identifier': 7.25.9 to-fast-properties: 2.0.0 '@bcoe/v8-coverage@0.2.3': {} @@ -5877,20 +5718,20 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.8 - '@floating-ui/dom@1.6.11': + '@floating-ui/dom@1.6.12': dependencies: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 '@floating-ui/react-dom@2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/dom': 1.6.11 + '@floating-ui/dom': 1.6.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) '@floating-ui/utils@0.2.8': {} - '@formatjs/intl-localematcher@0.5.7': + '@formatjs/intl-localematcher@0.5.9': dependencies: tslib: 2.8.0 @@ -6016,7 +5857,7 @@ snapshots: '@kamilkisiela/fast-url-parser@1.1.4': {} - '@mdx-js/mdx@3.1.0(acorn@8.13.0)': + '@mdx-js/mdx@3.1.0(acorn@8.14.0)': dependencies: '@types/estree': 1.0.6 '@types/estree-jsx': 1.0.5 @@ -6030,7 +5871,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.2 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.0(acorn@8.13.0) + recma-jsx: 1.0.0(acorn@8.14.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.0 @@ -6123,7 +5964,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@orama/orama@3.0.1': {} + '@orama/orama@3.0.3': {} '@pkgjs/parseargs@0.11.0': optional: true @@ -6383,7 +6224,7 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 - '@radix-ui/react-scroll-area@1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-scroll-area@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/number': 1.1.0 '@radix-ui/primitive': 1.1.0 @@ -6480,12 +6321,12 @@ snapshots: '@radix-ui/rect@1.1.0': {} - '@readme/better-ajv-errors@1.6.0(ajv@8.17.1)': + '@readme/better-ajv-errors@1.6.0(ajv@8.13.0)': dependencies: '@babel/code-frame': 7.26.2 '@babel/runtime': 7.26.0 '@humanwhocodes/momoa': 2.0.4 - ajv: 8.17.1 + ajv: 8.13.0 chalk: 4.1.2 json-to-ast: 2.1.0 jsonpointer: 5.0.1 @@ -6502,11 +6343,11 @@ snapshots: dependencies: '@apidevtools/swagger-methods': 3.0.2 '@jsdevtools/ono': 7.1.3 - '@readme/better-ajv-errors': 1.6.0(ajv@8.17.1) + '@readme/better-ajv-errors': 1.6.0(ajv@8.13.0) '@readme/json-schema-ref-parser': 1.2.0 '@readme/openapi-schemas': 3.1.0 - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) call-me-maybe: 1.0.2 openapi-types: 12.1.3 @@ -6598,50 +6439,50 @@ snapshots: - '@types/node' optional: true - '@shikijs/core@1.22.2': + '@shikijs/core@1.24.2': dependencies: - '@shikijs/engine-javascript': 1.22.2 - '@shikijs/engine-oniguruma': 1.22.2 - '@shikijs/types': 1.22.2 - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/engine-javascript': 1.24.2 + '@shikijs/engine-oniguruma': 1.24.2 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 hast-util-to-html: 9.0.3 - '@shikijs/engine-javascript@1.22.2': + '@shikijs/engine-javascript@1.24.2': dependencies: - '@shikijs/types': 1.22.2 - '@shikijs/vscode-textmate': 9.3.0 - oniguruma-to-js: 0.4.3 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 + oniguruma-to-es: 0.7.0 - '@shikijs/engine-oniguruma@1.22.2': + '@shikijs/engine-oniguruma@1.24.2': dependencies: - '@shikijs/types': 1.22.2 - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 - '@shikijs/rehype@1.22.2': + '@shikijs/rehype@1.24.2': dependencies: - '@shikijs/types': 1.22.2 + '@shikijs/types': 1.24.2 '@types/hast': 3.0.4 hast-util-to-string: 3.0.1 - shiki: 1.22.2 + shiki: 1.24.2 unified: 11.0.5 unist-util-visit: 5.0.0 - '@shikijs/twoslash@1.22.2(typescript@5.6.3)': + '@shikijs/twoslash@1.24.2(typescript@5.7.2)': dependencies: - '@shikijs/core': 1.22.2 - '@shikijs/types': 1.22.2 - twoslash: 0.2.12(typescript@5.6.3) + '@shikijs/core': 1.24.2 + '@shikijs/types': 1.24.2 + twoslash: 0.2.12(typescript@5.7.2) transitivePeerDependencies: - supports-color - typescript - '@shikijs/types@1.22.2': + '@shikijs/types@1.24.2': dependencies: - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 - '@shikijs/vscode-textmate@9.3.0': {} + '@shikijs/vscode-textmate@9.3.1': {} '@stylistic/eslint-plugin@2.11.0(eslint@9.15.0(jiti@2.1.0))(typescript@5.7.2)': dependencies: @@ -6661,31 +6502,29 @@ snapshots: dependencies: tslib: 2.8.0 - '@tailwindcss/typography@0.5.15(tailwindcss@3.4.14)': + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.16)': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.14 + tailwindcss: 3.4.16 '@tanstack/match-sorter-utils@8.19.4': dependencies: remove-accents: 0.5.0 - '@tanstack/query-core@5.59.13': {} + '@tanstack/query-core@5.62.7': {} - '@tanstack/query-core@5.62.3': {} - - '@tanstack/react-query@5.59.15(react@18.3.1)': + '@tanstack/react-query@5.62.7(react@18.3.1)': dependencies: - '@tanstack/query-core': 5.59.13 + '@tanstack/query-core': 5.62.7 react: 18.3.1 - '@tanstack/vue-query@5.62.3(vue@3.5.13(typescript@5.7.2))': + '@tanstack/vue-query@5.62.7(vue@3.5.13(typescript@5.7.2))': dependencies: '@tanstack/match-sorter-utils': 8.19.4 - '@tanstack/query-core': 5.62.3 + '@tanstack/query-core': 5.62.7 '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.7.2) vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.2)) @@ -6713,7 +6552,7 @@ snapshots: '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.25.9 + '@babel/runtime': 7.26.0 '@testing-library/dom': 10.4.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -6757,7 +6596,7 @@ snapshots: '@types/estree@1.0.6': {} - '@types/express-serve-static-core@5.0.1': + '@types/express-serve-static-core@5.0.2': dependencies: '@types/node': 22.9.0 '@types/qs': 6.9.17 @@ -6767,7 +6606,7 @@ snapshots: '@types/express@5.0.0': dependencies: '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 5.0.1 + '@types/express-serve-static-core': 5.0.2 '@types/qs': 6.9.17 '@types/serve-static': 1.15.7 @@ -6911,14 +6750,14 @@ snapshots: '@typescript-eslint/types': 8.15.0 eslint-visitor-keys: 4.2.0 - '@typescript/vfs@1.6.0(typescript@5.6.3)': + '@typescript/vfs@1.6.0(typescript@5.7.2)': dependencies: debug: 4.3.7 - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@ungap/structured-clone@1.2.0': {} + '@ungap/structured-clone@1.2.1': {} '@vitest/coverage-v8@2.1.3(vitest@2.1.3)': dependencies: @@ -7054,20 +6893,26 @@ snapshots: '@vue/shared@3.5.13': {} + '@whatwg-node/disposablestack@0.0.5': + dependencies: + tslib: 2.8.0 + '@whatwg-node/fetch@0.10.1': dependencies: - '@whatwg-node/node-fetch': 0.7.2 + '@whatwg-node/node-fetch': 0.7.5 urlpattern-polyfill: 10.0.0 - '@whatwg-node/node-fetch@0.7.2': + '@whatwg-node/node-fetch@0.7.5': dependencies: '@kamilkisiela/fast-url-parser': 1.1.4 + '@whatwg-node/disposablestack': 0.0.5 busboy: 1.6.0 fast-querystring: 1.1.2 tslib: 2.8.0 - '@whatwg-node/server@0.9.55': + '@whatwg-node/server@0.9.61': dependencies: + '@whatwg-node/disposablestack': 0.0.5 '@whatwg-node/fetch': 0.10.1 tslib: 2.8.0 @@ -7076,16 +6921,10 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.13.0): - dependencies: - acorn: 8.13.0 - acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 - acorn@8.13.0: {} - acorn@8.14.0: {} agent-base@7.1.1: @@ -7097,11 +6936,6 @@ snapshots: ajv-draft-04@1.0.0(ajv@8.13.0): optionalDependencies: ajv: 8.13.0 - optional: true - - ajv-draft-04@1.0.0(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 ajv-formats@3.0.1(ajv@8.13.0): optionalDependencies: @@ -7129,33 +6963,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - optional: true - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.0.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - algoliasearch@4.24.0: - dependencies: - '@algolia/cache-browser-local-storage': 4.24.0 - '@algolia/cache-common': 4.24.0 - '@algolia/cache-in-memory': 4.24.0 - '@algolia/client-account': 4.24.0 - '@algolia/client-analytics': 4.24.0 - '@algolia/client-common': 4.24.0 - '@algolia/client-personalization': 4.24.0 - '@algolia/client-search': 4.24.0 - '@algolia/logger-common': 4.24.0 - '@algolia/logger-console': 4.24.0 - '@algolia/recommend': 4.24.0 - '@algolia/requester-browser-xhr': 4.24.0 - '@algolia/requester-common': 4.24.0 - '@algolia/requester-node-http': 4.24.0 - '@algolia/transporter': 4.24.0 - optional: true ansi-escapes@7.0.0: dependencies: @@ -7278,12 +7085,16 @@ snapshots: cac@6.7.14: {} - call-bind@1.0.7: + call-bind-apply-helpers@1.0.1: dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.5 set-function-length: 1.2.2 call-me-maybe@1.0.2: {} @@ -7344,9 +7155,9 @@ snapshots: ci-info@4.1.0: {} - class-variance-authority@0.7.0: + class-variance-authority@0.7.1: dependencies: - clsx: 2.0.0 + clsx: 2.1.1 clean-regexp@1.0.0: dependencies: @@ -7369,7 +7180,7 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - clsx@2.0.0: {} + clsx@2.1.1: {} code-block-writer@13.0.3: {} @@ -7435,12 +7246,6 @@ snapshots: dependencies: browserslist: 4.24.2 - cross-spawn@7.0.3: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -7486,9 +7291,9 @@ snapshots: define-data-property@1.1.4: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.2.0 delayed-stream@1.0.0: {} @@ -7521,12 +7326,20 @@ snapshots: drange@1.1.1: {} + dunder-proto@1.0.0: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} ee-first@1.1.1: {} electron-to-chromium@1.5.43: {} + emoji-regex-xs@1.0.0: {} + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -7550,9 +7363,7 @@ snapshots: dependencies: is-arrayish: 0.2.1 - es-define-property@1.0.0: - dependencies: - get-intrinsic: 1.2.4 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -7568,7 +7379,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.13.0 + acorn: 8.14.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.2 @@ -8078,8 +7889,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.13.0 - acorn-jsx: 5.3.2(acorn@8.13.0) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -8118,7 +7929,7 @@ snapshots: astring: 1.9.0 source-map: 0.7.4 - estree-util-value-to-estree@3.1.2: + estree-util-value-to-estree@3.2.1: dependencies: '@types/estree': 1.0.6 @@ -8141,7 +7952,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -8163,7 +7974,7 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 - express@4.21.1: + express@4.21.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 @@ -8184,7 +7995,7 @@ snapshots: methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.12 proxy-addr: 2.0.7 qs: 6.13.0 range-parser: 1.2.1 @@ -8229,8 +8040,6 @@ snapshots: dependencies: fast-decode-uri-component: 1.0.1 - fast-uri@3.0.3: {} - fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -8308,11 +8117,11 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@14.4.0(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + fumadocs-core@14.4.0(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@formatjs/intl-localematcher': 0.5.7 - '@orama/orama': 3.0.1 - '@shikijs/rehype': 1.22.2 + '@formatjs/intl-localematcher': 0.5.9 + '@orama/orama': 3.0.3 + '@shikijs/rehype': 1.24.2 github-slugger: 2.0.0 hast-util-to-estree: 3.1.0 hast-util-to-jsx-runtime: 2.3.2 @@ -8322,10 +8131,9 @@ snapshots: remark: 15.0.1 remark-gfm: 4.0.0 scroll-into-view-if-needed: 3.1.0 - shiki: 1.22.2 + shiki: 1.24.2 unist-util-visit: 5.0.0 optionalDependencies: - algoliasearch: 4.24.0 next: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8333,47 +8141,47 @@ snapshots: - '@types/react' - supports-color - fumadocs-docgen@1.3.2(typescript@5.6.3): + fumadocs-docgen@1.3.2(typescript@5.7.2): dependencies: - estree-util-value-to-estree: 3.1.2 - fumadocs-typescript: 3.0.2(typescript@5.6.3) + estree-util-value-to-estree: 3.2.1 + fumadocs-typescript: 3.0.2(typescript@5.7.2) hast-util-to-estree: 3.1.0 npm-to-yarn: 3.0.0 ts-morph: 24.0.0 unist-util-visit: 5.0.0 - zod: 3.23.8 + zod: 3.24.1 transitivePeerDependencies: - supports-color - typescript - fumadocs-mdx@11.1.1(acorn@8.13.0)(fumadocs-core@14.4.0(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): + fumadocs-mdx@11.1.1(acorn@8.14.0)(fumadocs-core@14.4.0(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: - '@mdx-js/mdx': 3.1.0(acorn@8.13.0) + '@mdx-js/mdx': 3.1.0(acorn@8.14.0) chokidar: 4.0.1 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 esbuild: 0.24.0 - estree-util-value-to-estree: 3.1.2 + estree-util-value-to-estree: 3.2.1 fast-glob: 3.3.2 - fumadocs-core: 14.4.0(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + fumadocs-core: 14.4.0(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) gray-matter: 4.0.3 micromatch: 4.0.8 next: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - zod: 3.23.8 + zod: 3.24.1 transitivePeerDependencies: - acorn - supports-color - fumadocs-twoslash@2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(fumadocs-ui@14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.14))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(shiki@1.22.2)(typescript@5.6.3): + fumadocs-twoslash@2.0.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(fumadocs-ui@14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.16))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(shiki@1.24.2)(typescript@5.7.2): dependencies: '@radix-ui/react-popover': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@shikijs/twoslash': 1.22.2(typescript@5.6.3) - fumadocs-ui: 14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.14) + '@shikijs/twoslash': 1.24.2(typescript@5.7.2) + fumadocs-ui: 14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.16) mdast-util-from-markdown: 2.0.2 mdast-util-gfm: 3.0.0 mdast-util-to-hast: 13.2.0 react: 18.3.1 - shiki: 1.22.2 - tailwind-merge: 2.5.4 + shiki: 1.24.2 + tailwind-merge: 2.5.5 transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -8381,7 +8189,7 @@ snapshots: - supports-color - typescript - fumadocs-typescript@3.0.2(typescript@5.6.3): + fumadocs-typescript@3.0.2(typescript@5.7.2): dependencies: '@types/node': 22.8.1 fast-glob: 3.3.2 @@ -8389,13 +8197,13 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-gfm: 3.0.0 mdast-util-to-hast: 13.2.0 - shiki: 1.22.2 + shiki: 1.24.2 ts-morph: 24.0.0 - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - fumadocs-ui@14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.14): + fumadocs-ui@14.4.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.16): dependencies: '@radix-ui/react-accordion': 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-collapsible': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -8403,21 +8211,21 @@ snapshots: '@radix-ui/react-direction': 1.1.0(@types/react@18.3.12)(react@18.3.1) '@radix-ui/react-navigation-menu': 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-popover': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-scroll-area': 1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-scroll-area': 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1) '@radix-ui/react-tabs': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tailwindcss/typography': 0.5.15(tailwindcss@3.4.14) - class-variance-authority: 0.7.0 - fumadocs-core: 14.4.0(@types/react@18.3.12)(algoliasearch@4.24.0)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tailwindcss/typography': 0.5.15(tailwindcss@3.4.16) + class-variance-authority: 0.7.1 + fumadocs-core: 14.4.0(@types/react@18.3.12)(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) lucide-react: 0.456.0(react@18.3.1) next: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - next-themes: 0.4.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next-themes: 0.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-medium-image-zoom: 5.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - tailwind-merge: 2.5.4 + react-medium-image-zoom: 5.2.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tailwind-merge: 2.5.5 optionalDependencies: - tailwindcss: 3.4.14 + tailwindcss: 3.4.16 transitivePeerDependencies: - '@oramacloud/client' - '@types/react' @@ -8435,12 +8243,15 @@ snapshots: get-east-asian-width@1.3.0: {} - get-intrinsic@1.2.4: + get-intrinsic@1.2.5: dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 + gopd: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 get-nonce@1.0.1: {} @@ -8480,9 +8291,7 @@ snapshots: globals@15.12.0: {} - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.4 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -8501,11 +8310,9 @@ snapshots: has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.0 - - has-proto@1.0.3: {} + es-define-property: 1.0.1 - has-symbols@1.0.3: {} + has-symbols@1.1.0: {} hasown@2.0.2: dependencies: @@ -8574,7 +8381,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 - hono@4.6.12: {} + hono@4.6.13: {} hosted-git-info@2.8.9: {} @@ -8821,7 +8628,7 @@ snapshots: jsonc-eslint-parser@2.4.0: dependencies: - acorn: 8.13.0 + acorn: 8.14.0 eslint-visitor-keys: 3.4.3 espree: 9.6.1 semver: 7.6.3 @@ -8846,9 +8653,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lilconfig@2.1.0: {} - - lilconfig@3.1.2: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -8858,7 +8663,7 @@ snapshots: commander: 12.1.0 debug: 4.3.7 execa: 8.0.1 - lilconfig: 3.1.2 + lilconfig: 3.1.3 listr2: 8.2.5 micromatch: 4.0.8 pidtree: 0.6.0 @@ -8955,23 +8760,6 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - mdast-util-from-markdown@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.0.2 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.0 - micromark-util-decode-numeric-character-reference: 2.0.1 - micromark-util-decode-string: 2.0.0 - micromark-util-normalize-identifier: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color - mdast-util-from-markdown@2.0.2: dependencies: '@types/mdast': 4.0.4 @@ -9052,7 +8840,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.1 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 transitivePeerDependencies: - supports-color @@ -9065,7 +8853,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.1 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 parse-entities: 4.0.1 stringify-entities: 4.0.4 @@ -9090,7 +8878,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.1 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 transitivePeerDependencies: - supports-color @@ -9104,7 +8892,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.2.0 + '@ungap/structured-clone': 1.2.1 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.0 trim-lines: 3.0.1 @@ -9257,8 +9045,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.13.0 - acorn-jsx: 5.3.2(acorn@8.13.0) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) micromark-extension-mdx-expression: 3.0.0 micromark-extension-mdx-jsx: 3.0.1 micromark-extension-mdx-md: 2.0.0 @@ -9473,7 +9261,7 @@ snapshots: negotiator@1.0.0: {} - next-themes@0.4.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-themes@0.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9554,15 +9342,17 @@ snapshots: dependencies: mimic-function: 5.0.1 - oniguruma-to-js@0.4.3: + oniguruma-to-es@0.7.0: dependencies: - regex: 4.3.3 + emoji-regex-xs: 1.0.0 + regex: 5.0.2 + regex-recursion: 4.3.0 openapi-types@12.1.3: {} openapi3-ts@4.4.0: dependencies: - yaml: 2.5.1 + yaml: 2.6.0 optionator@0.9.4: dependencies: @@ -9645,14 +9435,12 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-to-regexp@0.1.10: {} + path-to-regexp@0.1.12: {} pathe@1.1.2: {} pathval@2.0.0: {} - picocolors@1.1.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -9687,14 +9475,14 @@ snapshots: postcss-load-config@4.0.2(postcss@8.4.49): dependencies: - lilconfig: 3.1.2 + lilconfig: 3.1.3 yaml: 2.6.0 optionalDependencies: postcss: 8.4.49 postcss-load-config@6.0.1(jiti@2.1.0)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.6.0): dependencies: - lilconfig: 3.1.2 + lilconfig: 3.1.3 optionalDependencies: jiti: 2.1.0 postcss: 8.4.49 @@ -9787,7 +9575,7 @@ snapshots: react-is@17.0.2: {} - react-medium-image-zoom@5.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-medium-image-zoom@5.2.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9853,9 +9641,9 @@ snapshots: estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.0(acorn@8.13.0): + recma-jsx@1.0.0(acorn@8.14.0): dependencies: - acorn-jsx: 5.3.2(acorn@8.13.0) + acorn-jsx: 5.3.2(acorn@8.14.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -9888,7 +9676,15 @@ snapshots: regenerator-runtime@0.14.1: {} - regex@4.3.3: {} + regex-recursion@4.3.0: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@5.0.2: + dependencies: + regex-utilities: 2.3.0 regexp-ast-analysis@0.7.1: dependencies: @@ -9930,7 +9726,7 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.1 + mdast-util-from-markdown: 2.0.2 micromark-util-types: 2.0.0 unified: 11.0.5 transitivePeerDependencies: @@ -10084,8 +9880,8 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.2.5 + gopd: 1.2.0 has-property-descriptors: 1.0.2 setprototypeof@1.2.0: {} @@ -10123,22 +9919,22 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.22.2: + shiki@1.24.2: dependencies: - '@shikijs/core': 1.22.2 - '@shikijs/engine-javascript': 1.22.2 - '@shikijs/engine-oniguruma': 1.22.2 - '@shikijs/types': 1.22.2 - '@shikijs/vscode-textmate': 9.3.0 + '@shikijs/core': 1.24.2 + '@shikijs/engine-javascript': 1.24.2 + '@shikijs/engine-oniguruma': 1.24.2 + '@shikijs/types': 1.24.2 + '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 short-unique-id@5.2.0: {} side-channel@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 object-inspect: 1.13.3 siginfo@2.0.0: {} @@ -10289,7 +10085,7 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - superjson@2.2.1: + superjson@2.2.2: dependencies: copy-anything: 3.0.5 @@ -10315,9 +10111,9 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.8.0 - tailwind-merge@2.5.4: {} + tailwind-merge@2.5.5: {} - tailwindcss@3.4.14: + tailwindcss@3.4.16: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -10328,7 +10124,7 @@ snapshots: glob-parent: 6.0.2 is-glob: 4.0.3 jiti: 1.21.6 - lilconfig: 2.1.0 + lilconfig: 3.1.3 micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 @@ -10444,7 +10240,7 @@ snapshots: esbuild: 0.23.1 execa: 5.1.1 joycon: 3.1.1 - picocolors: 1.1.0 + picocolors: 1.1.1 postcss-load-config: 6.0.1(jiti@2.1.0)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.6.0) resolve-from: 5.0.0 rollup: 4.22.5 @@ -10472,11 +10268,11 @@ snapshots: twoslash-protocol@0.2.12: {} - twoslash@0.2.12(typescript@5.6.3): + twoslash@0.2.12(typescript@5.7.2): dependencies: - '@typescript/vfs': 1.6.0(typescript@5.6.3) + '@typescript/vfs': 1.6.0(typescript@5.7.2) twoslash-protocol: 0.2.12 - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -10490,7 +10286,7 @@ snapshots: type-fest@0.8.1: {} - type-fest@4.26.1: {} + type-fest@4.30.0: {} type-is@1.6.18: dependencies: @@ -10500,8 +10296,6 @@ snapshots: typescript@5.4.2: optional: true - typescript@5.6.3: {} - typescript@5.7.2: {} ufo@1.5.4: {} @@ -10780,6 +10574,6 @@ snapshots: yocto-queue@0.1.0: {} - zod@3.23.8: {} + zod@3.24.1: {} zwitch@2.0.4: {}