Compare commits

..

35 Commits

Author SHA1 Message Date
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
10 changed files with 178 additions and 52 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.16",
"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,12 +1,12 @@
<script setup lang="ts">
const client = useClient()
const { $client } = useNuxtApp()
const { data: todos, pending, error, refresh } = await useAsyncQuery(['getTodos'])
const addTodo = async () => {
const title = Math.random().toString(36).slice(2, 7)
try {
const result = await client.mutation('addTodo', {
const result = await $client.mutation('addTodo', {
id: Date.now(),
userId: 69,
title,

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(x)
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 { addPlugin, addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit'
export interface ModuleOptions {
baseURL: string
@@ -20,10 +20,10 @@ export default defineNuxtModule<ModuleOptions>({
},
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.rootDir, 'server/trpc')
// Final resolved configuration
const finalConfig = nuxt.options.runtimeConfig.public.trpc = defu(nuxt.options.runtimeConfig.public.trpc, {
@@ -33,7 +33,7 @@ export default defineNuxtModule<ModuleOptions>({
nuxt.hook('autoImports:extend', (imports) => {
imports.push(
{ name: 'useClient', from: '#build/trpc-client' },
{ name: 'useClient', from: join(runtimeDir, 'client') },
{ name: 'useAsyncQuery', from: join(runtimeDir, 'client') },
)
})
@@ -43,22 +43,7 @@ export default defineNuxtModule<ModuleOptions>({
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',
@@ -66,14 +51,11 @@ export default defineNuxtModule<ModuleOptions>({
getContents() {
return `
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
trpcURL: '${finalConfig.trpcURL}'
})
`
},

View File

@@ -6,15 +6,15 @@ 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 { useAsyncData, useNuxtApp, useState } from '#app'
// @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,
)
@@ -58,3 +58,8 @@ export async function useAsyncQuery<
error: serverError,
} as any
}
export function useClient(): TRPCClient<AppRouter> {
const { $client } = useNuxtApp()
return $client
}

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

@@ -0,0 +1,26 @@
import * as trpc from '@trpc/client'
// @ts-expect-error: Resolved by Nuxt
import { defineNuxtPlugin, useRequestHeaders, useRuntimeConfig } from '#app'
import type { router } from '~/server/trpc'
declare type AppRouter = typeof router
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig().public.trpc
const client = trpc.createTRPCClient<AppRouter>({
url: `${config.baseURL}${config.trpcURL}`,
headers: useRequestHeaders(),
})
return {
provide: {
client,
},
}
})
declare module '#app' {
interface NuxtApp {
$client: trpc.TRPCClient<AppRouter>
}
}