Compare commits

..

74 Commits

Author SHA1 Message Date
Robert Soriano
5cfef32baa release v0.2.5 2022-08-14 12:38:56 -07:00
Robert Soriano
8497289c65 update readme 2022-08-14 12:38:31 -07:00
Robert Soriano
224c4b317b move ohash to deps 2022-08-14 12:29:04 -07:00
Robert Soriano
d5d6780ca8 bump ohash 2022-08-14 12:28:03 -07:00
Robert Soriano
252d0f6692 feat(deps): bump vueuse from 8.9.3 to 9.1.0 2022-08-14 12:27:10 -07:00
Robert Soriano
d022710591 bump dev deps 2022-08-14 12:26:33 -07:00
Robert Soriano
a926968f13 feat(deps): bump @nuxt/kit from 3.0.0-rc.5 to 3.0.0-rc.8 2022-08-14 12:25:48 -07:00
Robert Soriano
a8eba5ab8d feat(deps): bump @trpc/server from 9.26.0 to 9.27.0 2022-08-14 12:25:14 -07:00
Robert Soriano
5871528d67 feat(deps): bump @trpc/client from 9.26.0 to 9.27.0 2022-08-14 12:24:52 -07:00
Robert Soriano
def9d0b19d volta pin node@16 2022-08-14 12:24:20 -07:00
Robert Soriano
34f50fc4d6 chore(deps): bump pnpm to 7.5.0 2022-07-14 19:04:19 -07:00
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
11 changed files with 1928 additions and 1708 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

@@ -15,6 +15,8 @@ End-to-end typesafe APIs with [tRPC.io](https://trpc.io/) in Nuxt applications.
</figure>
</p>
**⚠️ Currently works on Node v16 until [this issue](https://github.com/trpc/trpc/issues/2420) gets fixed.**
## Install
```bash
@@ -29,10 +31,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,6 +101,20 @@ 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`:

View File

@@ -1,8 +1,8 @@
{
"name": "trpc-nuxt",
"type": "module",
"version": "0.1.15",
"packageManager": "pnpm@7.1.1",
"version": "0.2.5",
"packageManager": "pnpm@7.5.0",
"license": "MIT",
"main": "./dist/module.cjs",
"types": "./dist/types.d.ts",
@@ -32,28 +32,37 @@
"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.8",
"@trpc/client": "^9.27.0",
"@trpc/server": "^9.27.0",
"@vueuse/core": "^9.1.0",
"@vueuse/nuxt": "^9.1.0",
"dedent": "^0.7.0",
"defu": "^6.0.0",
"h3": "^0.7.8",
"h3": "^0.7.10",
"ohash": "^0.1.5",
"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",
"bumpp": "^7.1.1",
"@nuxt/module-builder": "^0.1.7",
"@types/dedent": "^0.7.0",
"bumpp": "^7.2.0",
"eslint": "^8.14.0",
"nuxt": "^3.0.0-rc.3",
"ohash": "^0.1.0",
"pnpm": "^7.1.1",
"superjson": "^1.9.1",
"nuxt": "3.0.0-rc.8",
"pnpm": "^7.5.0",
"trpc-nuxt": "workspace:*",
"zod": "^3.16.0"
},
"eslintConfig": {
"extends": "@antfu"
"extends": "@antfu",
"rules": {
"no-console": "warn"
}
},
"volta": {
"node": "16.14.2"
}
}

View File

@@ -1,12 +1,18 @@
<script setup lang="ts">
const { $client } = useNuxtApp()
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)
try {
const result = await $client.mutation('addTodo', {
const result = await client.mutation('addTodo', {
id: Date.now(),
userId: 69,
title,
@@ -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

@@ -2,7 +2,6 @@ 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'
@@ -30,6 +29,7 @@ export const router = trpc.router<Context>()
.mutation('addTodo', {
input: TodoShape,
async resolve(req) {
console.log(req.input)
return await $fetch<Todo>(`${baseURL}/todos`, {
method: 'POST',
body: req.input,
@@ -42,8 +42,8 @@ export async function createContext(event: CompatibilityEvent) {
// 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)
// const x = useCookies(event)
console.log(event.req.headers)
return {

3438
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

@@ -1,12 +1,13 @@
import { fileURLToPath } from 'url'
import { join, resolve } from 'pathe'
import { defu } from 'defu'
import dedent from 'dedent'
import { addPlugin, 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,30 +17,33 @@ 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-handler')
const handlerPath = join(nuxt.options.buildDir, 'trpc-handler.ts')
const trpcOptionsPath = join(nuxt.options.rootDir, 'server/trpc')
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: join(runtimeDir, '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,
})
@@ -49,16 +53,13 @@ export default defineNuxtModule<ModuleOptions>({
filename: 'trpc-handler.ts',
write: true,
getContents() {
return `
return dedent`
import { createTRPCHandler } from 'trpc-nuxt/api'
import { useRuntimeConfig } from '#imports'
import * as functions from '${trpcOptionsPath}'
const { trpc: { trpcURL } } = useRuntimeConfig().public
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

@@ -8,10 +8,13 @@ import type {
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 { useStorage } from '@vueuse/core'
import { useAsyncData, useNuxtApp, useState } from '#app'
// @ts-expect-error: Resolved by Nuxt
import type { router } from '~/server/trpc'
type MaybeRef<T> = T | Ref<T>
type AppRouter = typeof router
export type inferProcedures<
@@ -28,6 +31,16 @@ export type TError = TRPCClientErrorLike<AppRouter>
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,
TOutput extends TQueryValues[TPath]['output'] = TQueryValues[TPath]['output'],
@@ -38,11 +51,12 @@ export async function useAsyncQuery<
options: AsyncDataOptions<TOutput, Transform, PickKeys> = {},
): Promise<AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, TError>> {
const { $client } = useNuxtApp()
const key = `${pathAndInput[0]}-${objectHash(pathAndInput[1] ? JSON.stringify(pathAndInput[1]) : '')}`
const key = getQueryKey(pathAndInput)
const serverError = useState<TError | null>(`error-${key}`, () => null)
const { error, data, ...rest } = await useAsyncData(
key,
() => $client.query(...pathAndInput),
// @ts-expect-error: Internal
options,
)
@@ -63,3 +77,7 @@ 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)
}

View File

@@ -1,22 +1,29 @@
import * as trpc from '@trpc/client'
// @ts-expect-error: Resolved by Nuxt
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(() => {
export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig().public.trpc
const headers = useRequestHeaders()
const otherHeaders = useClientHeaders()
const client = trpc.createTRPCClient<AppRouter>({
url: `${config.baseURL}${config.trpcURL}`,
headers: useRequestHeaders(),
url: `${config.baseURL}${config.endpoint}`,
headers: () => {
if (nuxtApp.ssrContext) {
return {
...unref(otherHeaders),
...headers,
}
}
return {}
},
})
return {
provide: {
client,
},
}
nuxtApp.provide('client', client)
})
declare module '#app' {