import type { AsyncData, AsyncDataOptions, KeyOfRes, PickFrom, _Transform, } from 'nuxt/dist/app/composables/asyncData' import type { ProcedureRecord, inferHandlerInput, inferProcedureInput, inferProcedureOutput } from '@trpc/server' import type { TRPCClient, TRPCClientErrorLike } from '@trpc/client' import { objectHash } from 'ohash' import type { Ref } from 'vue' import { useAsyncData, useNuxtApp, useState } from '#app' import type { router } from '~/server/trpc' type MaybeRef = T | Ref 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 /** * Calculates the key used for `useAsyncData` call * @param pathAndInput */ export function getQueryKey< TPath extends keyof TQueryValues & string, >(pathAndInput: [path: TPath, ...args: inferHandlerInput]) { return `${pathAndInput[0]}-${objectHash(pathAndInput[1] ? JSON.stringify(pathAndInput[1]) : '')}` } 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 = getQueryKey(pathAndInput) const result = await useAsyncData( key, () => $client.query(...pathAndInput), // @ts-expect-error: Internal options, ) return result as any } export function useClient(): TRPCClient { const { $client } = useNuxtApp() return $client } export function useClientHeaders(initialValue: MaybeRef> = {}): Ref> { return useState('trpc-nuxt-header', () => initialValue) }