Compare commits

..

19 Commits

Author SHA1 Message Date
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
9 changed files with 169 additions and 34 deletions

View File

@@ -101,7 +101,7 @@ const {
## 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 +143,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.1.8",
"packageManager": "pnpm@7.1.1",
"license": "MIT",
"main": "./dist/module.cjs",
@@ -36,7 +36,6 @@
"@trpc/client": "^9.23.3",
"@trpc/server": "^9.23.2",
"defu": "^6.0.0",
"fs-extra": "^10.1.0",
"h3": "^0.7.8",
"pathe": "^0.3.0",
"ufo": "^0.8.4"
@@ -45,7 +44,6 @@
"@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",
"eslint": "^8.14.0",
"nuxt": "^3.0.0-rc.3",

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,5 +1,8 @@
import * as trpc from '@trpc/server'
import type { inferAsyncReturnType } from '@trpc/server'
import { z } from 'zod'
import type { CompatibilityEvent } from 'h3'
import { useCookies } from 'h3'
const baseURL = 'https://jsonplaceholder.typicode.com'
@@ -12,7 +15,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`)
@@ -33,3 +36,18 @@ export const router = trpc.router()
})
},
})
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('Headers', event.req.headers)
return {
}
}
type Context = inferAsyncReturnType<typeof createContext>

13
pnpm-lock.yaml generated
View File

@@ -10,11 +10,9 @@ importers:
'@nuxt/module-builder': latest
'@trpc/client': ^9.23.3
'@trpc/server': ^9.23.2
'@types/fs-extra': ^9.0.13
bumpp: ^7.1.1
defu: ^6.0.0
eslint: ^8.14.0
fs-extra: ^10.1.0
h3: ^0.7.8
nuxt: ^3.0.0-rc.3
ohash: ^0.1.0
@@ -29,7 +27,6 @@ importers:
'@trpc/client': 9.23.4_@trpc+server@9.23.4
'@trpc/server': 9.23.4
defu: 6.0.0
fs-extra: 10.1.0
h3: 0.7.8
pathe: 0.3.0
ufo: 0.8.4
@@ -37,7 +34,6 @@ importers:
'@antfu/eslint-config': 0.23.1_eslint@8.15.0
'@antfu/ni': 0.16.2
'@nuxt/module-builder': 0.1.7
'@types/fs-extra': 9.0.13
bumpp: 7.1.1
eslint: 8.15.0
nuxt: 3.0.0-rc.3
@@ -945,12 +941,6 @@ packages:
resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==}
dev: true
/@types/fs-extra/9.0.13:
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
dependencies:
'@types/node': 17.0.34
dev: true
/@types/jsdom/16.2.14:
resolution: {integrity: sha512-6BAy1xXEmMuHeAJ4Fv4yXKwBDTGTOseExKE3OaHiNycdHdZw59KfYzrt0DkDluvwmik1HRt6QS7bImxUmpSy+w==}
dependencies:
@@ -3216,6 +3206,7 @@ packages:
graceful-fs: 4.2.10
jsonfile: 6.1.0
universalify: 2.0.0
dev: true
/fs-memo/1.2.0:
resolution: {integrity: sha512-YEexkCpL4j03jn5SxaMHqcO6IuWuqm8JFUYhyCep7Ao89JIYmB8xoKhK7zXXJ9cCaNXpyNH5L3QtAmoxjoHW2w==}
@@ -3930,6 +3921,7 @@ packages:
universalify: 2.0.0
optionalDependencies:
graceful-fs: 4.2.10
dev: true
/jsx-ast-utils/3.3.0:
resolution: {integrity: sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q==}
@@ -6333,6 +6325,7 @@ packages:
/universalify/2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
engines: {node: '>= 10.0.0'}
dev: true
/unplugin/0.6.3:
resolution: {integrity: sha512-CoW88FQfCW/yabVc4bLrjikN9HC8dEvMU4O7B6K2jsYMPK0l6iAnd9dpJwqGcmXJKRCU9vwSsy653qg+RK0G6A==}

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,8 +1,8 @@
import { fileURLToPath } from 'url'
import { join } from 'pathe'
import { join, resolve } from 'pathe'
import { defu } from 'defu'
import { addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit'
import { addPluginTemplate, addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit'
export interface ModuleOptions {
baseURL: string
@@ -23,7 +23,7 @@ export default defineNuxtModule<ModuleOptions>({
nuxt.options.build.transpile.push(runtimeDir, '#build/trpc-client', '#build/trpc-handler')
const handlerPath = join(nuxt.options.buildDir, 'trpc-handler.ts')
nuxt.options.build.transpile.push(handlerPath)
const trpcOptionsPath = join(nuxt.options.rootDir, 'server/trpc')
// Final resolved configuration
const finalConfig = nuxt.options.runtimeConfig.public.trpc = defu(nuxt.options.runtimeConfig.public.trpc, {
@@ -48,18 +48,22 @@ export default defineNuxtModule<ModuleOptions>({
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
export const useClient = () => {
const { $client } = useNuxtApp()
return $client
}
`
},
})
addPluginTemplate({
src: resolve(runtimeDir, 'plugin.ts'),
write: true,
options: {
url: `${finalConfig.baseURL}${finalConfig.trpcURL}`,
},
})
addTemplate({
filename: 'trpc-handler.ts',
write: true,
@@ -67,7 +71,7 @@ export default defineNuxtModule<ModuleOptions>({
return `
import { createTRPCHandler } from 'trpc-nuxt/api'
import { useRuntimeConfig } from '#imports'
import * as functions from '~/server/trpc'
import * as functions from '${trpcOptionsPath}'
const { trpc: { trpcURL } } = useRuntimeConfig().public

View File

@@ -9,12 +9,12 @@ import type { ProcedureRecord, inferHandlerInput, inferProcedureInput, inferProc
import type { TRPCClientErrorLike } from '@trpc/client'
import { objectHash } from 'ohash'
import { useAsyncData, useState } from '#app'
import { useClient } from '#build/trpc-client'
// @ts-expect-error: Resolved by Nuxt
import type { router } from '~/server/trpc'
type AppRouter = typeof router
type inferProcedures<
export type inferProcedures<
TObj extends ProcedureRecord<any, any, any, any, any, any>,
> = {
[TPath in keyof TObj]: {
@@ -23,10 +23,10 @@ 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']>
export async function useAsyncQuery<
TPath extends keyof TQueryValues & string,
@@ -37,12 +37,12 @@ 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 { $client } = useNuxtApp()
const key = `${pathAndInput[0]}-${objectHash(pathAndInput[1] ? JSON.stringify(pathAndInput[1]) : '')}`
const serverError = useState<TError | null>(`error-${key}`, () => null)
const { error, data, ...rest } = await useAsyncData(
key,
() => client.query(...pathAndInput),
() => $client.query(...pathAndInput),
options,
)

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

@@ -0,0 +1,18 @@
import * as trpc from '@trpc/client'
import { defineNuxtPlugin, useRequestHeaders } from '#app'
import type { router } from '~/server/trpc'
const options = JSON.parse('<%= JSON.stringify(options) %>')
export default defineNuxtPlugin(() => {
const client = trpc.createTRPCClient<typeof router>({
url: options.url as string,
headers: useRequestHeaders(),
})
return {
provide: {
client,
},
}
})