import type { AsyncData, AsyncDataOptions, KeyOfRes, PickFrom, _Transform, } from 'nuxt/dist/app/composables/asyncData' import type { ProcedureRecord, inferHandlerInput, inferProcedureInput, inferProcedureOutput } from '@trpc/server' import type { TRPCClientErrorLike } from '@trpc/client' import { objectHash } from 'ohash' import { useAsyncData, useNuxtApp, useState } from '#app' // @ts-expect-error: Resolved by Nuxt import type { router } from '~/server/trpc' type AppRouter = typeof router export type inferProcedures< TObj extends ProcedureRecord, > = { [TPath in keyof TObj]: { input: inferProcedureInput output: inferProcedureOutput }; } export type TQueries = AppRouter['_def']['queries'] export type TError = TRPCClientErrorLike export type TQueryValues = inferProcedures export async function useAsyncQuery< TPath extends keyof TQueryValues & string, TOutput extends TQueryValues[TPath]['output'] = TQueryValues[TPath]['output'], Transform extends _Transform = _Transform, PickKeys extends KeyOfRes = KeyOfRes, >( pathAndInput: [path: TPath, ...args: inferHandlerInput], options: AsyncDataOptions = {}, ): Promise, PickKeys>, TError>> { const { $client } = useNuxtApp() const key = `${pathAndInput[0]}-${objectHash(pathAndInput[1] ? JSON.stringify(pathAndInput[1]) : '')}` const serverError = useState(`error-${key}`, () => null) const { error, data, ...rest } = await useAsyncData( key, () => $client.query(...pathAndInput), options, ) if (process.server && error.value && !serverError.value) serverError.value = error.value as any if (data.value) serverError.value = null return { ...rest, data, error: serverError, } as any } export function useClient() { const { $client } = useNuxtApp() return $client }