Compare commits

...

25 Commits

Author SHA1 Message Date
25e09b2e30 Update example and playground dependencies 2023-08-31 14:11:23 +02:00
0612716187 Update dependencies 2023-08-31 13:56:19 +02:00
wobsoriano
55712e3027 chore(release): v0.10.12 2023-08-23 14:18:33 -07:00
wobsoriano
0fec55a3ae refactor: explicitly copy headers to custom fetcher 2023-08-23 14:18:12 -07:00
wobsoriano
8f9e398ae2 fix: expect ofetch missing error response type 2023-08-23 14:12:29 -07:00
wobsoriano
092e3495fd build(deps): bump ofetch to 1.3.2 2023-08-23 13:44:22 -07:00
wobsoriano
230422bb16 docs: fix incorrect syntax 2023-08-23 12:49:09 -07:00
wobsoriano
057c8f8d3a docs: fix missing title 2023-08-23 12:48:32 -07:00
wobsoriano
9808375f31 docs: add response caching page 2023-08-23 12:46:22 -07:00
wobsoriano
8e893a2e30 chore(release): v0.10.11 2023-08-22 10:52:53 -07:00
wobsoriano
f74273190f bump local deps 2023-08-22 10:52:41 -07:00
wobsoriano
283400d41a chore(deps): bump ohash to 1.1.3 2023-08-22 10:51:54 -07:00
wobsoriano
5221dc0515 chore(deps): bump ofetch to 1.2.0 2023-08-22 10:51:29 -07:00
wobsoriano
299ae558ab fix: add missing useLazyQuery type 2023-08-22 10:48:44 -07:00
wobsoriano
f7eeb104b3 docs: bump @nuxt-themes/docus to 1.14.6 2023-08-22 10:36:36 -07:00
wobsoriano
c5c762190b chore(release): v0.10.10 2023-08-20 22:57:35 -07:00
wobsoriano
93cb44288c feat: add useLazyQuery composable 2023-08-20 22:57:31 -07:00
wobsoriano
ede749414d chore(release): v0.10.9 2023-08-20 22:51:01 -07:00
wobsoriano
f2bcf9b68b feat: add custom query key option 2023-08-20 22:50:48 -07:00
wobsoriano
4289dcbfab chore(release): v0.10.8 2023-08-20 22:30:24 -07:00
wobsoriano
dc317c2ded build: bump local deps 2023-08-20 21:57:59 -07:00
wobsoriano
3db0b31d31 refactor: use stand-alone getErrorShape 2023-08-20 21:55:25 -07:00
wobsoriano
f86ebcd6d6 docs: add handler param description 2023-08-20 21:48:39 -07:00
wobsoriano
252f6108cf refactor: use built-in getRequestURL from h3 instead of ufo 2023-08-20 21:41:57 -07:00
wobsoriano
3a395a7d4a build(deps): bump h3 to 1.8.0 2023-08-20 21:36:23 -07:00
15 changed files with 3015 additions and 1009 deletions

View File

@@ -1,6 +1,94 @@
# Changelog # Changelog
## v0.10.12
[compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.11...v0.10.12)
### 🩹 Fixes
- Expect ofetch missing error response type ([8f9e398](https://github.com/wobsoriano/trpc-nuxt/commit/8f9e398))
### 💅 Refactors
- Explicitly copy headers to custom fetcher ([0fec55a](https://github.com/wobsoriano/trpc-nuxt/commit/0fec55a))
### 📖 Documentation
- Add response caching page ([9808375](https://github.com/wobsoriano/trpc-nuxt/commit/9808375))
- Fix missing title ([057c8f8](https://github.com/wobsoriano/trpc-nuxt/commit/057c8f8))
- Fix incorrect syntax ([230422b](https://github.com/wobsoriano/trpc-nuxt/commit/230422b))
### 📦 Build
- **deps:** Bump ofetch to 1.3.2 ([092e349](https://github.com/wobsoriano/trpc-nuxt/commit/092e349))
### ❤️ Contributors
- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))
## v0.10.11
[compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.10...v0.10.11)
### 🩹 Fixes
- Add missing useLazyQuery type ([299ae55](https://github.com/wobsoriano/trpc-nuxt/commit/299ae55))
### 📖 Documentation
- Bump @nuxt-themes/docus to 1.14.6 ([f7eeb10](https://github.com/wobsoriano/trpc-nuxt/commit/f7eeb10))
### ❤️ Contributors
- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))
## v0.10.10
[compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.9...v0.10.10)
### 🚀 Enhancements
- Add useLazyQuery composable ([93cb442](https://github.com/wobsoriano/trpc-nuxt/commit/93cb442))
### ❤️ Contributors
- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))
## v0.10.9
[compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.8...v0.10.9)
### 🚀 Enhancements
- Add custom query key option ([f2bcf9b](https://github.com/wobsoriano/trpc-nuxt/commit/f2bcf9b))
### ❤️ Contributors
- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))
## v0.10.8
[compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.7...v0.10.8)
### 💅 Refactors
- Use built-in getRequestURL from h3 instead of ufo ([252f610](https://github.com/wobsoriano/trpc-nuxt/commit/252f610))
- Use stand-alone getErrorShape ([3db0b31](https://github.com/wobsoriano/trpc-nuxt/commit/3db0b31))
### 📖 Documentation
- Add handler param description ([f86ebcd](https://github.com/wobsoriano/trpc-nuxt/commit/f86ebcd))
### 📦 Build
- **deps:** Bump h3 to 1.8.0 ([3a395a7](https://github.com/wobsoriano/trpc-nuxt/commit/3a395a7))
- Bump local deps ([dc317c2](https://github.com/wobsoriano/trpc-nuxt/commit/dc317c2))
### ❤️ Contributors
- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))
## v0.10.7 ## v0.10.7
[compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.6...v0.10.7) [compare changes](https://github.com/wobsoriano/trpc-nuxt/compare/v0.10.6...v0.10.7)

View File

@@ -0,0 +1,51 @@
---
title: Response Caching
---
## Response Caching
Your server responses must [satisfy some criteria](https://vercel.com/docs/concepts/functions/serverless-functions/edge-caching) in order for them to be cached (i.e. by Vercel's Edge Network). Please refer to [this section of the tRPC.io documentation](https://trpc.io/docs/caching) for more information.
The `createNuxtApiHandler` function conveniently allows you to specify a `responseMeta` function.
```ts [server/api/trpc/[trpc].ts]
import { createNuxtApiHandler } from 'trpc-nuxt'
import { appRouter } from '~/server/trpc/routers'
export default createNuxtApiHandler({
router: appRouter,
/**
* @link https://trpc.io/docs/caching#api-response-caching
*/
responseMeta(opts) {
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: {
'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
},
})
```
You can also take advantage of Nitro's [Cache API](https://nitro.unjs.io/guide/cache#cache-api) if doing server-side calls:
```ts
import { appRouter } from '@/server/trpc/routers'
const caller = appRouter.createCaller({})
export default cachedEventHandler(async (event) => {
const { name } = getQuery(event)
const greeting = await caller.greeting({ name })
return {
greeting
}
}, {
swr: true, maxAge: 10
})
```

View File

@@ -8,7 +8,7 @@
"preview": "nuxi preview" "preview": "nuxi preview"
}, },
"devDependencies": { "devDependencies": {
"@nuxt-themes/docus": "^1.14.3", "@nuxt-themes/docus": "^1.14.6",
"@nuxtlabs/github-module": "^1.6.3", "@nuxtlabs/github-module": "^1.6.3",
"nuxt": "3.6.5" "nuxt": "3.6.5"
} }

View File

@@ -2,21 +2,21 @@
"name": "nuxt-app", "name": "nuxt-app",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "nuxt build", "build": "nuxi build",
"dev": "nuxt dev", "dev": "nuxi dev",
"generate": "nuxt generate", "generate": "nuxi generate",
"preview": "nuxt preview", "preview": "nuxi preview",
"postinstall": "nuxt prepare" "postinstall": "nuxi prepare"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/devtools": "latest", "@nuxt/devtools": "latest",
"@types/node": "^20.4.2", "@types/node": "20.5.7",
"nuxt": "^3.6.5" "nuxt": "^3.7.0"
}, },
"dependencies": { "dependencies": {
"@trpc/client": "^10.35.0", "@trpc/client": "^10.38.1",
"@trpc/server": "^10.35.0", "@trpc/server": "^10.38.1",
"trpc-nuxt": "workspace:*", "trpc-nuxt": "workspace:*",
"zod": "^3.21.4" "zod": "^3.22.2"
} }
} }

View File

@@ -3,7 +3,7 @@
"description": "End-to-end typesafe APIs in Nuxt applications.", "description": "End-to-end typesafe APIs in Nuxt applications.",
"type": "module", "type": "module",
"packageManager": "pnpm@8.6.9", "packageManager": "pnpm@8.6.9",
"version": "0.10.7", "version": "0.10.12",
"license": "MIT", "license": "MIT",
"sideEffects": false, "sideEffects": false,
"exports": { "exports": {
@@ -35,24 +35,23 @@
"update-deps": "taze -w && pnpm i" "update-deps": "taze -w && pnpm i"
}, },
"peerDependencies": { "peerDependencies": {
"@trpc/client": "^10.26.0", "@trpc/client": "^10.38.1",
"@trpc/server": "^10.26.0" "@trpc/server": "^10.38.1"
}, },
"dependencies": { "dependencies": {
"h3": "^1.7.1", "h3": "^1.8.1",
"ofetch": "^1.1.1", "ofetch": "^1.3.3",
"ohash": "^1.1.2", "ohash": "^1.1.3"
"ufo": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/eslint-config": "^0.1.1", "@nuxt/eslint-config": "^0.2.0",
"@trpc/client": "^10.35.0", "@trpc/client": "^10.38.1",
"@trpc/server": "^10.35.0", "@trpc/server": "^10.38.1",
"changelogen": "^0.5.4", "changelogen": "^0.5.5",
"eslint": "^8.45.0", "eslint": "^8.48.0",
"taze": "^0.11.2", "taze": "^0.11.2",
"tsup": "7.1.0", "tsup": "7.2.0",
"typescript": "^5.1.6" "typescript": "^5.2.2"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
@@ -75,7 +74,9 @@
], ],
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"nuxt": "3.6.5" "nuxt": "3.7.0",
"@trpc/client": "10.38.1",
"@trpc/server": "10.38.1"
} }
} }
} }

View File

@@ -2,21 +2,21 @@
"name": "playground", "name": "playground",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "nuxt build", "build": "nuxi build",
"dev": "nuxt dev", "dev": "nuxi dev",
"generate": "nuxt generate", "generate": "nuxi generate",
"preview": "nuxt preview", "preview": "nuxi preview",
"postinstall": "nuxt prepare" "postinstall": "nuxi prepare"
}, },
"dependencies": { "dependencies": {
"@trpc/client": "^10.35.0", "@trpc/client": "10.38.1",
"@trpc/server": "^10.35.0", "@trpc/server": "10.38.1",
"superjson": "^1.13.1", "superjson": "^1.13.1",
"trpc-nuxt": "workspace:*", "trpc-nuxt": "workspace:*",
"zod": "^3.21.4" "zod": "^3.22.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.4.2", "@types/node": "20.5.7",
"nuxt": "3.6.5" "nuxt": "3.7.0"
} }
} }

View File

@@ -17,7 +17,7 @@ const addTodo = async () => {
} }
} }
const { data: todos, pending, error, refresh } = await $client.todo.getTodos.useQuery() const { data: todos, pending, error, refresh } = await $client.todo.getTodos.useLazyQuery()
</script> </script>
<template> <template>

View File

@@ -1,6 +1,6 @@
import { createNuxtApiHandler } from 'trpc-nuxt' import { createNuxtApiHandler } from 'trpc-nuxt'
import { appRouter } from '@/server/trpc/routers' import { appRouter } from '../../trpc/routers'
import { createContext } from '@/server/trpc/context' import { createContext } from '../../trpc/context'
export default createNuxtApiHandler({ export default createNuxtApiHandler({
router: appRouter, router: appRouter,

View File

@@ -1,5 +1,6 @@
import { z } from 'zod' import { z } from 'zod'
import { publicProcedure, router } from '../trpc' import { publicProcedure, router } from '../trpc'
import { $fetch } from 'ofetch'
const baseURL = 'https://jsonplaceholder.typicode.com' const baseURL = 'https://jsonplaceholder.typicode.com'

View File

@@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

3727
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -40,8 +40,8 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: stri
const [input, otherOptions] = args const [input, otherOptions] = args
if (lastArg === 'useQuery') { if (['useQuery', 'useLazyQuery'].includes(lastArg)) {
const { trpc, ...asyncDataOptions } = otherOptions || {} as any const { trpc, queryKey: customQueryKey, ...asyncDataOptions } = otherOptions || {} as any
let controller: AbortController let controller: AbortController
@@ -54,13 +54,17 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: stri
controller = typeof AbortController !== 'undefined' ? new AbortController() : {} as AbortController controller = typeof AbortController !== 'undefined' ? new AbortController() : {} as AbortController
} }
const queryKey = getQueryKey(path, unref(input)) const queryKey = customQueryKey || getQueryKey(path, unref(input))
const watch = isRef(input) ? [...(asyncDataOptions.watch || []), input] : asyncDataOptions.watch
const isLazy = lastArg === 'useLazyQuery' ? true : (asyncDataOptions.lazy || false)
return useAsyncData(queryKey, () => (client as any)[path].query(unref(input), { return useAsyncData(queryKey, () => (client as any)[path].query(unref(input), {
signal: controller?.signal, signal: controller?.signal,
...trpc ...trpc
}), { }), {
...asyncDataOptions, ...asyncDataOptions,
watch: isRef(input) ? [...(asyncDataOptions.watch || []), input] : asyncDataOptions.watch watch,
lazy: isLazy
}) })
} }

View File

@@ -14,6 +14,7 @@ function customFetch(input: RequestInfo | URL, init?: RequestInit & { method: 'G
}) })
.then(response => ({ .then(response => ({
...response, ...response,
headers: response.headers,
json: () => Promise.resolve(response._data) json: () => Promise.resolve(response._data)
})) }))
} }

View File

@@ -53,13 +53,36 @@ type DecorateProcedure<
> = TProcedure extends AnyQueryProcedure > = TProcedure extends AnyQueryProcedure
? { ? {
useQuery: < useQuery: <
ResT = inferTransformedProcedureOutput<TProcedure>, ResT = inferTransformedProcedureOutput<TProcedure>,
DataE = TRPCClientErrorLike<TProcedure>, DataE = TRPCClientErrorLike<TProcedure>,
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
>( >(
input: MaybeRef<inferProcedureInput<TProcedure>>, input: MaybeRef<inferProcedureInput<TProcedure>>,
opts?: AsyncDataOptions<ResT, DataT, PickKeys> & { trpc?: TRPCRequestOptions }, opts?: AsyncDataOptions<ResT, DataT, PickKeys> & {
trpc?: TRPCRequestOptions
/**
* The custom unique key to use.
* @see https://nuxt.com/docs/api/composables/use-async-data#params
*/
queryKey?: string
},
) => AsyncData<PickFrom<DataT, PickKeys> | null, DataE>,
useLazyQuery: <
ResT = inferTransformedProcedureOutput<TProcedure>,
DataE = TRPCClientErrorLike<TProcedure>,
DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
>(
input: MaybeRef<inferProcedureInput<TProcedure>>,
opts?: Omit<AsyncDataOptions<ResT, DataT, PickKeys>, 'lazy'> & {
trpc?: TRPCRequestOptions
/**
* The custom unique key to use.
* @see https://nuxt.com/docs/api/composables/use-async-data#params
*/
queryKey?: string
},
) => AsyncData<PickFrom<DataT, PickKeys> | null, DataE>, ) => AsyncData<PickFrom<DataT, PickKeys> | null, DataE>,
query: Resolver<TProcedure> query: Resolver<TProcedure>
} : TProcedure extends AnyMutationProcedure ? { } : TProcedure extends AnyMutationProcedure ? {

View File

@@ -9,10 +9,10 @@ import type {
import { import {
TRPCError TRPCError
} from '@trpc/server' } from '@trpc/server'
import { createURL } from 'ufo'
import type { H3Event } from 'h3' import type { H3Event } from 'h3'
import { createError, defineEventHandler, isMethod, readBody } from 'h3' import { createError, defineEventHandler, getRequestURL, isMethod, readBody } from 'h3'
import type { TRPCResponse } from '@trpc/server/rpc' import type { TRPCResponse } from '@trpc/server/rpc'
import { getErrorShape } from '@trpc/server/shared'
type MaybePromise<T> = T | Promise<T> type MaybePromise<T> = T | Promise<T>
@@ -40,9 +40,25 @@ export interface OnErrorPayload<TRouter extends AnyRouter> {
export type OnErrorFn<TRouter extends AnyRouter> = (opts: OnErrorPayload<TRouter>) => void export type OnErrorFn<TRouter extends AnyRouter> = (opts: OnErrorPayload<TRouter>) => void
export interface ResolveHTTPRequestOptions<TRouter extends AnyRouter> { export interface ResolveHTTPRequestOptions<TRouter extends AnyRouter> {
/**
* The tRPC router to use.
* @see https://trpc.io/docs/router
*/
router: TRouter router: TRouter
/**
* An async function that returns the tRPC context.
* @see https://trpc.io/docs/context
*/
createContext?: CreateContextFn<TRouter> createContext?: CreateContextFn<TRouter>
/**
* A function that returns the response meta.
* @see https://trpc.io/docs/caching#using-responsemeta-to-cache-responses
*/
responseMeta?: ResponseMetaFn<TRouter> responseMeta?: ResponseMetaFn<TRouter>
/**
* A function that is called when an error occurs.
* @see https://trpc.io/docs/error-handling#handling-errors
*/
onError?: OnErrorFn<TRouter> onError?: OnErrorFn<TRouter>
batching?: { batching?: {
enabled: boolean enabled: boolean
@@ -74,15 +90,16 @@ export function createNuxtApiHandler<TRouter extends AnyRouter> ({
res res
} = event.node } = event.node
const $url = createURL(req.url!) const $url = getRequestURL(event)
const path = getPath(event) const path = getPath(event)
if (path === null) { if (path === null) {
const error = router.getErrorShape({ const error = getErrorShape({
config: router._def._config,
error: new TRPCError({ error: new TRPCError({
message: message:
'Param "trpc" not found - is the file named `[trpc]`.ts or `[...trpc].ts`?', 'Query "trpc" not found - is the file named `[trpc]`.ts or `[...trpc].ts`?',
code: 'INTERNAL_SERVER_ERROR' code: 'INTERNAL_SERVER_ERROR'
}), }),
type: 'unknown', type: 'unknown',