Compare commits

..

96 Commits

Author SHA1 Message Date
Robert Soriano
9fe1469eba release v0.2.4 2022-07-14 19:03:09 -07:00
Robert Soriano
e48d7cd42c feat(deps): bump @nuxt/kit from 3.0.0-rc.4 to 3.0.0-rc.5 2022-07-14 19:02:54 -07:00
Robert Soriano
2b517ad77b release v0.2.3 2022-07-14 11:19:28 -07:00
Robert Soriano
77ee994e13 update deps 2022-07-14 11:19:19 -07:00
Robert Soriano
67a8a2a3ed feat(deps): bump ufo from 0.8.4 to 0.8.5 2022-07-14 11:19:01 -07:00
Robert Soriano
556b5c8e08 feat(deps): bump @vueuse/nuxt from 8.7.4 to 8.9.3 2022-07-14 11:18:37 -07:00
Robert Soriano
85154f12d7 feat(deps): bump @vueuse/core from 8.7.4 to 8.9.3 2022-07-14 11:18:21 -07:00
Robert Soriano
26ce46e12b feat(deps): bump @trpc/server from 9.25.3 to 9.26.0 2022-07-14 11:17:51 -07:00
Robert Soriano
c2cfd9a214 feat(deps): bump @trpc/client from 9.25.3 to 9.26.0 2022-07-14 11:17:34 -07:00
Robert Soriano
f736545128 ci: add release workflow 2022-07-14 11:16:43 -07:00
Robert Soriano
59a9eb5f95 fix playground workspace 2022-07-05 20:24:40 -07:00
Robert Soriano
48fc19076f Update README.md 2022-06-23 10:03:48 -07:00
Robert Soriano
6b83e5d4ea chore(deps): bump @trpc/server to 9.25.3 2022-06-18 21:06:25 -07:00
Robert Soriano
0358a258d7 chore(deps): bump @trpc/client to 9.25.3 2022-06-18 21:06:11 -07:00
Robert Soriano
8e7f33c9d2 chore(deps): bump h3 to 0.7.10 2022-06-18 21:05:48 -07:00
Robert Soriano
b8f4af2df3 chore(deps): bump @vueuse/nuxt to 8.7.4 2022-06-18 21:05:15 -07:00
Robert Soriano
666751678c chore(deps): bump @vueuse/core to 8.7.4 2022-06-18 21:04:56 -07:00
Robert Soriano
cab89aaa66 chore(deps): bump bumpp to 7.2.0 2022-06-18 21:04:17 -07:00
Robert Soriano
4c9850fafc chore(deps): add @types/dedent 2022-06-18 21:02:44 -07:00
Robert Soriano
07693009f8 release v0.2.2 2022-06-16 06:49:32 -07:00
Robert Soriano
dceade155c chore(deps): bump nuxt to 3.0.0-rc.4 2022-06-16 06:48:56 -07:00
Robert Soriano
4012249f09 chore(deps): bump h3 to 0.7.9 2022-06-16 06:48:20 -07:00
Robert Soriano
38eda2c4d6 chore(deps): bump @trpc/client to 9.25.2 2022-06-16 06:47:39 -07:00
Robert Soriano
9468af75f4 chore(deps): bump @trpc/server to 9.25.2 2022-06-16 06:47:18 -07:00
Robert Soriano
ea24a67a6d chore(deps): bump @nuxt/kit to 3.0.0-rc.4 2022-06-16 06:46:35 -07:00
Robert Soriano
5e8d04741c release v0.2.1 2022-06-13 18:51:41 -07:00
Robert Soriano
1032e65a0d refactor: remove unused import in playground 2022-06-13 18:51:35 -07:00
Robert Soriano
f261d3feeb Merge pull request #12 from cawa-93/patch-1
fix: auto-import `getQueryKey`
2022-06-13 18:49:07 -07:00
Alex Kozack
b1ca09e986 fix: auto-import getQueryKey 2022-06-13 12:06:03 +03:00
Robert Soriano
b804429fc0 update readme 2022-06-12 23:32:55 -07:00
Robert Soriano
7df64296ff update readme 2022-06-12 23:32:41 -07:00
Robert Soriano
a53d823f5e release v0.2.0 2022-06-12 23:30:07 -07:00
Robert Soriano
feef3dde6b update readme 2022-06-12 23:30:03 -07:00
Robert Soriano
82ee2ce672 refactor!: replace trpcURL option with endpoint 2022-06-12 23:29:28 -07:00
Robert Soriano
f62a13766a update readme 2022-06-12 23:19:55 -07:00
Robert Soriano
c7888e81ed refactor: use addAutoImport 2022-06-12 23:18:38 -07:00
Robert Soriano
c77eb68f5d refactor: rename endpoint option 2022-06-12 23:17:13 -07:00
Robert Soriano
333539569c refactor: lint 2022-06-12 23:16:01 -07:00
Robert Soriano
e5c40f183b Merge pull request #7 from cawa-93/feat/extract-get-query-key
feat: extract `getQueryKey` helper
2022-06-12 23:08:21 -07:00
Robert Soriano
977a9e1465 release v0.1.24 2022-06-05 17:05:34 -07:00
Robert Soriano
2620379e02 feat: allow changing of src dir 2022-06-05 17:05:13 -07:00
Robert Soriano
e4f42d5322 Merge pull request #10 from nicolesmileyface/feat/support-src-dir
use nuxt srcDir instead of rootDir
2022-06-05 17:02:41 -07:00
Cole Hollant
ad28a9124e use nuxt srcDir instead of rootDir 2022-06-05 11:55:25 -04:00
cawa-93
273bda980b feat: extract getQueryKey helper
This method will be useful to get a key that can be used to reset the internal nuxt cache
2022-05-31 15:20:21 +03:00
Robert Soriano
9c8509f79c release v0.1.23 2022-05-27 08:53:18 -07:00
Robert Soriano
2ce29137ce fix: unimported composable 2022-05-27 08:41:14 -07:00
Robert Soriano
e9c5307e23 release v0.1.22 2022-05-27 01:10:10 -07:00
Robert Soriano
bbdabf544c fix: type inference bug with vueuse 2022-05-27 01:10:06 -07:00
Robert Soriano
aed10ac5b8 release v0.1.21 2022-05-27 00:56:58 -07:00
Robert Soriano
4b2c714658 fix: remove module export 2022-05-27 00:56:53 -07:00
Robert Soriano
43e9fefdbd release v0.1.20 2022-05-26 13:48:57 -07:00
Robert Soriano
dabda23976 export module id 2022-05-26 13:48:53 -07:00
Robert Soriano
af89f32275 release v0.1.19 2022-05-26 07:27:20 -07:00
Robert Soriano
1f27b871fb fix: unref import from vue 2022-05-26 07:21:42 -07:00
Robert Soriano
281e4c05a0 release v0.1.18 2022-05-24 10:01:23 -07:00
Robert Soriano
38ac520b97 fix: server storage and incorrect imports 2022-05-24 10:01:19 -07:00
Robert Soriano
96ebff619e release v0.1.17 2022-05-24 09:55:59 -07:00
Robert Soriano
f668e4a9b4 docs: update readme 2022-05-24 09:55:35 -07:00
Robert Soriano
58b0165557 update readme 2022-05-24 09:55:05 -07:00
Robert Soriano
3b5e35ef68 feat: add composable for custom client headers 2022-05-24 09:46:15 -07:00
Robert Soriano
48152ead8d refactor: remove some comments 2022-05-24 06:43:42 -07:00
Robert Soriano
7f44e049c0 release v0.1.16 2022-05-23 12:41:55 -07:00
Robert Soriano
5a71bbf1fe refactor: use trpc url from config 2022-05-23 12:41:49 -07:00
Robert Soriano
285487e9bf release v0.1.15 2022-05-23 11:24:10 -07:00
Robert Soriano
2cfa64fcc6 fix: unresolvable runtime config 2022-05-23 11:24:07 -07:00
Robert Soriano
eea5733dcd release v0.1.14 2022-05-23 11:09:16 -07:00
Robert Soriano
71bbbf2b86 fix: trpc client composable type 2022-05-23 11:08:52 -07:00
Robert Soriano
2b57ab8791 release v0.1.13 2022-05-23 11:06:58 -07:00
Robert Soriano
f8edd769f0 fix: trpc client composable type 2022-05-23 11:06:51 -07:00
Robert Soriano
419ef34de6 release v0.1.12 2022-05-23 11:03:53 -07:00
Robert Soriano
30c76b5859 fix: client type declaration 2022-05-23 11:03:50 -07:00
Robert Soriano
2575beae5d release v0.1.11 2022-05-23 10:42:19 -07:00
Robert Soriano
b09d1af30d fix: client type declaration 2022-05-23 10:42:16 -07:00
Robert Soriano
610e441db7 release v0.1.10 2022-05-23 10:31:53 -07:00
Robert Soriano
959b370729 fix: unable to resolve nuxt instance 2022-05-23 10:31:48 -07:00
Robert Soriano
c1c4e67694 release v0.1.9 2022-05-23 10:26:02 -07:00
Robert Soriano
779221d9e6 refactor: plugin arrangement 2022-05-23 10:25:34 -07:00
Robert Soriano
986b661e99 release v0.1.8 2022-05-23 10:04:13 -07:00
Robert Soriano
77325a6699 fix: headers missing 2022-05-23 10:04:06 -07:00
Robert Soriano
6dcb4ce8a6 refactor: remove useless transpiled build 2022-05-20 14:26:45 -07:00
Robert Soriano
c95d46f43a release v0.1.7 2022-05-20 11:44:02 -07:00
Robert Soriano
2844cc0bbd refactor: remove helper types 2022-05-20 11:43:58 -07:00
Robert Soriano
aeb2e1b8e3 docs: add inference helpers recipe 2022-05-20 11:42:40 -07:00
Robert Soriano
68d9eb2461 release v0.1.6 2022-05-20 11:30:09 -07:00
Robert Soriano
109a07a42d feat: add helper types 2022-05-20 11:30:04 -07:00
Robert Soriano
7775e59b0c release v0.1.5 2022-05-20 11:26:48 -07:00
Robert Soriano
c23af214a3 remove helpers 2022-05-20 11:26:43 -07:00
Robert Soriano
7851846ad5 release v0.1.4 2022-05-20 11:22:30 -07:00
Robert Soriano
f9b0aa002e refactor: type helpers 2022-05-20 11:22:19 -07:00
Robert Soriano
eb1bd0c700 feat: add trpc type helpers 2022-05-20 11:07:12 -07:00
Robert Soriano
47ba58c0b7 release v0.1.3 2022-05-20 10:19:55 -07:00
Robert Soriano
a458ed9b3f refactor: use full path for router type 2022-05-20 10:08:53 -07:00
Robert Soriano
09d043d49b docs: add recommended ide setup 2022-05-20 10:04:48 -07:00
Robert Soriano
3e47e2a389 Update README.md 2022-05-20 09:14:40 -07:00
Robert Soriano
f8d82c4af1 remove unused module 2022-05-20 08:18:29 -07:00
Robert Soriano
e31578bf97 refactor: remove unused transpile 2022-05-20 00:58:27 -07:00
13 changed files with 1621 additions and 1579 deletions

22
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16.x
- run: npx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

View File

@@ -29,10 +29,10 @@ export default defineNuxtConfig({
modules: ['trpc-nuxt'],
trpc: {
baseURL: 'http://localhost:3000', // defaults to http://localhost:3000
trpcURL: '/api/trpc', // defaults to /api/trpc
endpoint: '/trpc', // defaults to /trpc
},
typescript: {
strict: true // set this to true to make input/output types work
strict: true // required to make input/output types work
}
})
```
@@ -99,9 +99,23 @@ const {
})
```
## useClientHeaders
A composable that lets you add additional properties to pass to the tRPC Client. It uses `useStorage` from [@vueuse/core](https://vueuse.org/core/usestorage).
```ts
const headers = useClientHeaders()
const { data: token } = await useAsyncQuery(['auth.login', { username, password }])
headers.value.Authorization = `Bearer ${token}`
// All client calls will now include the Authorization header.
```
## Options
trpc-nuxt accepts the following options exposed under `~/server/trpc.index.ts`:
trpc-nuxt accepts the following options exposed under `~/server/trpc/index.ts`:
```ts
import * as trpc from '@trpc/server'
@@ -143,9 +157,14 @@ export const onError = (payload: OnErrorPayload<typeof router>) => {
- [Merging Routers](/recipes/merging-routers.md)
- [Error Handling](/recipes/error-handling.md)
- [Error Formatting](/recipes/error-formatting.md)
- [Inference Helpers](/recipes/inference-helpers.md)
Learn more about tRPC.io [here](https://trpc.io/docs).
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
## License
MIT

View File

@@ -1,7 +1,7 @@
{
"name": "trpc-nuxt",
"type": "module",
"version": "0.1.2",
"version": "0.2.4",
"packageManager": "pnpm@7.1.1",
"license": "MIT",
"main": "./dist/module.cjs",
@@ -32,30 +32,34 @@
"prepare": "nuxi prepare playground"
},
"dependencies": {
"@nuxt/kit": "^3.0.0-rc.3",
"@trpc/client": "^9.23.3",
"@trpc/server": "^9.23.2",
"@nuxt/kit": "3.0.0-rc.5",
"@trpc/client": "^9.26.0",
"@trpc/server": "^9.26.0",
"@vueuse/core": "^8.9.3",
"@vueuse/nuxt": "^8.9.3",
"dedent": "^0.7.0",
"defu": "^6.0.0",
"fs-extra": "^10.1.0",
"h3": "^0.7.8",
"h3": "^0.7.10",
"pathe": "^0.3.0",
"ufo": "^0.8.4"
"ufo": "^0.8.5"
},
"devDependencies": {
"@antfu/eslint-config": "^0.23.1",
"@antfu/ni": "^0.16.2",
"@nuxt/module-builder": "latest",
"@types/fs-extra": "^9.0.13",
"bumpp": "^7.1.1",
"@types/dedent": "^0.7.0",
"bumpp": "^7.2.0",
"eslint": "^8.14.0",
"nuxt": "^3.0.0-rc.3",
"nuxt": "3.0.0-rc.4",
"ohash": "^0.1.0",
"pnpm": "^7.1.1",
"superjson": "^1.9.1",
"trpc-nuxt": "workspace:*",
"zod": "^3.16.0"
},
"eslintConfig": {
"extends": "@antfu"
"extends": "@antfu",
"rules": {
"no-console": "warn"
}
}
}

View File

@@ -0,0 +1,19 @@
<script setup lang="ts">
const counter = useCookie('counter')
counter.value = counter.value || Math.round(Math.random() * 1000)
</script>
<template>
<div>
<h1> Counter: {{ counter || '-' }}</h1>
<button @click="counter = null">
reset
</button>
<button @click="counter--">
-
</button>
<button @click="counter++">
+
</button>
</div>
</template>

View File

@@ -1,7 +1,13 @@
<script setup lang="ts">
const client = useClient()
const headers = useClientHeaders()
const { data: todos, pending, error, refresh } = await useAsyncQuery(['getTodos'])
const addHeader = () => {
// headers.value.cookie = 'counter=69'
console.log(headers.value)
}
const addTodo = async () => {
const title = Math.random().toString(36).slice(2, 7)
@@ -27,7 +33,7 @@ const addTodo = async () => {
<div v-else-if="error?.data?.code">
Error: {{ error.data.code }}
</div>
<div v-else>
<div v-else-if="todos">
<ul>
<li v-for="t in todos.slice(0, 10)" :key="t.id">
<NuxtLink :class="{ completed: t.completed }" :to="`/todo/${t.id}`">
@@ -41,6 +47,9 @@ const addTodo = async () => {
<button @click="() => refresh()">
Refresh
</button>
<button @click="addHeader">
Add header
</button>
</div>
</template>

View File

@@ -1,5 +1,7 @@
import * as trpc from '@trpc/server'
import type { inferAsyncReturnType } from '@trpc/server'
import { z } from 'zod'
import type { CompatibilityEvent } from 'h3'
const baseURL = 'https://jsonplaceholder.typicode.com'
@@ -12,7 +14,7 @@ const TodoShape = z.object({
export type Todo = z.infer<typeof TodoShape>
export const router = trpc.router()
export const router = trpc.router<Context>()
.query('getTodos', {
async resolve() {
return await $fetch<Todo[]>(`${baseURL}/todos`)
@@ -27,9 +29,25 @@ export const router = trpc.router()
.mutation('addTodo', {
input: TodoShape,
async resolve(req) {
console.log(req.input)
return await $fetch<Todo>(`${baseURL}/todos`, {
method: 'POST',
body: req.input,
})
},
})
export async function createContext(event: CompatibilityEvent) {
// Create your context based on the request object
// Will be available as `ctx` in all your resolvers
// This is just an example of something you'd might want to do in your ctx fn
// const x = useCookies(event)
console.log(event.req.headers)
return {
}
}
type Context = inferAsyncReturnType<typeof createContext>

2845
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,2 @@
packages:
- playground/*
- playground

View File

@@ -0,0 +1,80 @@
## Inference Helpers
`@trpc/server` exports the following helper types to assist with inferring these types from the `router` exported in `~/server/trpc/index.ts`:
- `inferProcedureOutput<TProcedure>`
- `inferProcedureInput<TProcedure>`
- `inferSubscriptionOutput<TRouter, TPath>`
```ts
// ~/utils/trpc.ts
import type { router } from '~/server/trpc/index.ts'
type AppRouter = typeof router
/**
* Enum containing all api query paths
*/
export type TQuery = keyof AppRouter['_def']['queries']
/**
* Enum containing all api mutation paths
*/
export type TMutation = keyof AppRouter['_def']['mutations']
/**
* Enum containing all api subscription paths
*/
export type TSubscription = keyof AppRouter['_def']['subscriptions']
/**
* This is a helper method to infer the output of a query resolver
* @example type HelloOutput = InferQueryOutput<'hello'>
*/
export type InferQueryOutput<TRouteKey extends TQuery> = inferProcedureOutput<
AppRouter['_def']['queries'][TRouteKey]
>
/**
* This is a helper method to infer the input of a query resolver
* @example type HelloInput = InferQueryInput<'hello'>
*/
export type InferQueryInput<TRouteKey extends TQuery> = inferProcedureInput<
AppRouter['_def']['queries'][TRouteKey]
>
/**
* This is a helper method to infer the output of a mutation resolver
* @example type HelloOutput = InferMutationOutput<'hello'>
*/
export type InferMutationOutput<TRouteKey extends TMutation> =
inferProcedureOutput<AppRouter['_def']['mutations'][TRouteKey]>
/**
* This is a helper method to infer the input of a mutation resolver
* @example type HelloInput = InferMutationInput<'hello'>
*/
export type InferMutationInput<TRouteKey extends TMutation> =
inferProcedureInput<AppRouter['_def']['mutations'][TRouteKey]>
/**
* This is a helper method to infer the output of a subscription resolver
* @example type HelloOutput = InferSubscriptionOutput<'hello'>
*/
export type InferSubscriptionOutput<TRouteKey extends TSubscription> =
inferProcedureOutput<AppRouter['_def']['subscriptions'][TRouteKey]>
/**
* This is a helper method to infer the asynchronous output of a subscription resolver
* @example type HelloAsyncOutput = InferAsyncSubscriptionOutput<'hello'>
*/
export type InferAsyncSubscriptionOutput<TRouteKey extends TSubscription> =
inferSubscriptionOutput<AppRouter, TRouteKey>
/**
* This is a helper method to infer the input of a subscription resolver
* @example type HelloInput = InferSubscriptionInput<'hello'>
*/
export type InferSubscriptionInput<TRouteKey extends TSubscription> =
inferProcedureInput<AppRouter['_def']['subscriptions'][TRouteKey]>
```

View File

@@ -1,12 +1,13 @@
import { fileURLToPath } from 'url'
import { join } from 'pathe'
import { join, resolve } from 'pathe'
import { defu } from 'defu'
import dedent from 'dedent'
import { addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit'
import { addAutoImport, addPlugin, addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit'
export interface ModuleOptions {
baseURL: string
trpcURL: string
endpoint: string
}
export default defineNuxtModule<ModuleOptions>({
@@ -16,64 +17,49 @@ export default defineNuxtModule<ModuleOptions>({
},
defaults: {
baseURL: 'http://localhost:3000',
trpcURL: '/api/trpc',
endpoint: '/trpc',
},
async setup(options, nuxt) {
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
nuxt.options.build.transpile.push(runtimeDir, '#build/trpc-client', '#build/trpc-handler')
nuxt.options.build.transpile.push(runtimeDir, '#build/trpc-handler')
const handlerPath = join(nuxt.options.buildDir, 'trpc-handler.ts')
nuxt.options.build.transpile.push(handlerPath)
const trpcOptionsPath = join(nuxt.options.srcDir, 'server/trpc')
// Add vueuse
nuxt.options.modules.push('@vueuse/nuxt')
// Final resolved configuration
const finalConfig = nuxt.options.runtimeConfig.public.trpc = defu(nuxt.options.runtimeConfig.public.trpc, {
baseURL: options.baseURL,
trpcURL: options.trpcURL,
endpoint: options.endpoint,
})
nuxt.hook('autoImports:extend', (imports) => {
imports.push(
{ name: 'useClient', from: '#build/trpc-client' },
{ name: 'useAsyncQuery', from: join(runtimeDir, 'client') },
)
})
addAutoImport([
{ name: 'useClient', from: join(runtimeDir, 'client') },
{ name: 'useAsyncQuery', from: join(runtimeDir, 'client') },
{ name: 'useClientHeaders', from: join(runtimeDir, 'client') },
{ name: 'getQueryKey', from: join(runtimeDir, 'client') },
])
addServerHandler({
route: `${finalConfig.trpcURL}/*`,
route: `${finalConfig.endpoint}/*`,
handler: handlerPath,
})
addTemplate({
filename: 'trpc-client.ts',
write: true,
getContents() {
return `
import * as trpc from '@trpc/client'
import type { router } from '~/server/trpc'
const client = trpc.createTRPCClient<typeof router>({
url: '${finalConfig.baseURL}${finalConfig.trpcURL}',
})
export const useClient = () => client
`
},
})
addPlugin(resolve(runtimeDir, 'plugin'))
addTemplate({
filename: 'trpc-handler.ts',
write: true,
getContents() {
return `
return dedent`
import { createTRPCHandler } from 'trpc-nuxt/api'
import { useRuntimeConfig } from '#imports'
import * as functions from '~/server/trpc'
const { trpc: { trpcURL } } = useRuntimeConfig().public
import * as functions from '${trpcOptionsPath}'
export default createTRPCHandler({
...functions,
trpcURL
endpoint: '${finalConfig.endpoint}'
})
`
},

View File

@@ -42,13 +42,13 @@ export function createTRPCHandler<Router extends AnyRouter>({
createContext,
responseMeta,
onError,
trpcURL,
endpoint,
}: {
router: Router
createContext?: CreateContextFn<Router>
responseMeta?: ResponseMetaFn<Router>
onError?: OnErrorFn<Router>
trpcURL: string
endpoint: string
}) {
return defineEventHandler(async (event) => {
const {
@@ -56,17 +56,17 @@ export function createTRPCHandler<Router extends AnyRouter>({
res,
} = event
const $url = createURL(req.url)
const $url = createURL(req.url!)
const httpResponse = await resolveHTTPResponse({
router,
req: {
method: req.method,
method: req.method!,
headers: req.headers,
body: isMethod(event, 'GET') ? null : await useBody(event),
query: $url.searchParams,
},
path: $url.pathname.substring(trpcURL.length + 1),
path: $url.pathname.substring(endpoint.length + 1),
createContext: async () => createContext?.(event),
responseMeta,
onError: (o) => {
@@ -81,8 +81,8 @@ export function createTRPCHandler<Router extends AnyRouter>({
res.statusCode = status
Object.keys(headers).forEach((key) => {
res.setHeader(key, headers[key])
headers && Object.keys(headers).forEach((key) => {
res.setHeader(key, headers[key]!)
})
return body

View File

@@ -6,15 +6,18 @@ import type {
_Transform,
} from 'nuxt/dist/app/composables/asyncData'
import type { ProcedureRecord, inferHandlerInput, inferProcedureInput, inferProcedureOutput } from '@trpc/server'
import type { TRPCClientErrorLike } from '@trpc/client'
import type { TRPCClient, TRPCClientErrorLike } from '@trpc/client'
import { objectHash } from 'ohash'
import { useAsyncData, useState } from '#app'
import { useClient } from '#build/trpc-client'
import type { Ref } from 'vue'
import { useStorage } from '@vueuse/core'
import { useAsyncData, useNuxtApp, useState } from '#app'
import type { router } from '~/server/trpc'
type MaybeRef<T> = T | Ref<T>
type AppRouter = typeof router
type inferProcedures<
export type inferProcedures<
TObj extends ProcedureRecord<any, any, any, any, any, any>,
> = {
[TPath in keyof TObj]: {
@@ -23,10 +26,20 @@ type inferProcedures<
};
}
type TQueries = AppRouter['_def']['queries']
type TError = TRPCClientErrorLike<AppRouter>
export type TQueries = AppRouter['_def']['queries']
export type TError = TRPCClientErrorLike<AppRouter>
type TQueryValues = inferProcedures<AppRouter['_def']['queries']>
export type TQueryValues = inferProcedures<AppRouter['_def']['queries']>
/**
* Calculates the key used for `useAsyncData` call
* @param pathAndInput
*/
export function getQueryKey<
TPath extends keyof TQueryValues & string,
>(pathAndInput: [path: TPath, ...args: inferHandlerInput<TQueries[TPath]>]) {
return `${pathAndInput[0]}-${objectHash(pathAndInput[1] ? JSON.stringify(pathAndInput[1]) : '')}`
}
export async function useAsyncQuery<
TPath extends keyof TQueryValues & string,
@@ -37,12 +50,13 @@ export async function useAsyncQuery<
pathAndInput: [path: TPath, ...args: inferHandlerInput<TQueries[TPath]>],
options: AsyncDataOptions<TOutput, Transform, PickKeys> = {},
): Promise<AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, TError>> {
const client = useClient()
const key = `${pathAndInput[0]}-${objectHash(pathAndInput[1] ? JSON.stringify(pathAndInput[1]) : '')}`
const { $client } = useNuxtApp()
const key = getQueryKey(pathAndInput)
const serverError = useState<TError | null>(`error-${key}`, () => null)
const { error, data, ...rest } = await useAsyncData(
key,
() => client.query(...pathAndInput),
() => $client.query(...pathAndInput),
// @ts-expect-error: Internal
options,
)
@@ -58,3 +72,12 @@ export async function useAsyncQuery<
error: serverError,
} as any
}
export function useClient(): TRPCClient<AppRouter> {
const { $client } = useNuxtApp()
return $client
}
export function useClientHeaders(initialValue: MaybeRef<Record<string, any>> = {}): Ref<Record<string, any>> {
return useStorage('trpc-nuxt-header', initialValue)
}

33
src/runtime/plugin.ts Normal file
View File

@@ -0,0 +1,33 @@
import * as trpc from '@trpc/client'
import { unref } from 'vue'
import { useClientHeaders } from './client'
import { defineNuxtPlugin, useRequestHeaders, useRuntimeConfig } from '#app'
import type { router } from '~/server/trpc'
declare type AppRouter = typeof router
export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig().public.trpc
const headers = useRequestHeaders()
const otherHeaders = useClientHeaders()
const client = trpc.createTRPCClient<AppRouter>({
url: `${config.baseURL}${config.endpoint}`,
headers: () => {
if (nuxtApp.ssrContext) {
return {
...unref(otherHeaders),
...headers,
}
}
return {}
},
})
nuxtApp.provide('client', client)
})
declare module '#app' {
interface NuxtApp {
$client: trpc.TRPCClient<AppRouter>
}
}