Compare commits

...

37 Commits

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

View File

@@ -29,10 +29,10 @@ export default defineNuxtConfig({
modules: ['trpc-nuxt'], modules: ['trpc-nuxt'],
trpc: { trpc: {
baseURL: 'http://localhost:3000', // defaults to http://localhost:3000 baseURL: 'http://localhost:3000', // defaults to http://localhost:3000
trpcURL: '/api/trpc', // defaults to /api/trpc endpoint: '/trpc', // defaults to /trpc
}, },
typescript: { typescript: {
strict: true // set this to true to make input/output types work strict: true // required to make input/output types work
} }
}) })
``` ```
@@ -111,7 +111,7 @@ const { data: token } = await useAsyncQuery(['auth.login', { username, password
headers.value.Authorization = `Bearer ${token}` headers.value.Authorization = `Bearer ${token}`
// All client calls will now include the Authorization header. // All client calls will now include the Authorization header.
// For SSR, please follow this until I found a solution https://github.com/trpc/trpc/discussions/1686 // For SSR, please follow this link https://github.com/trpc/trpc/discussions/1686
``` ```
## Options ## Options

View File

@@ -1,7 +1,7 @@
{ {
"name": "trpc-nuxt", "name": "trpc-nuxt",
"type": "module", "type": "module",
"version": "0.1.17", "version": "0.2.2",
"packageManager": "pnpm@7.1.1", "packageManager": "pnpm@7.1.1",
"license": "MIT", "license": "MIT",
"main": "./dist/module.cjs", "main": "./dist/module.cjs",
@@ -32,13 +32,14 @@
"prepare": "nuxi prepare playground" "prepare": "nuxi prepare playground"
}, },
"dependencies": { "dependencies": {
"@nuxt/kit": "^3.0.0-rc.3", "@nuxt/kit": "^3.0.0-rc.4",
"@trpc/client": "^9.23.3", "@trpc/client": "^9.25.2",
"@trpc/server": "^9.23.2", "@trpc/server": "^9.25.2",
"@vueuse/core": "^8.5.0", "@vueuse/core": "^8.6.0",
"@vueuse/nuxt": "^8.5.0", "@vueuse/nuxt": "^8.6.0",
"dedent": "^0.7.0",
"defu": "^6.0.0", "defu": "^6.0.0",
"h3": "^0.7.8", "h3": "^0.7.9",
"pathe": "^0.3.0", "pathe": "^0.3.0",
"ufo": "^0.8.4" "ufo": "^0.8.4"
}, },
@@ -48,14 +49,16 @@
"@nuxt/module-builder": "latest", "@nuxt/module-builder": "latest",
"bumpp": "^7.1.1", "bumpp": "^7.1.1",
"eslint": "^8.14.0", "eslint": "^8.14.0",
"nuxt": "^3.0.0-rc.3", "nuxt": "3.0.0-rc.4",
"ohash": "^0.1.0", "ohash": "^0.1.0",
"pnpm": "^7.1.1", "pnpm": "^7.1.1",
"superjson": "^1.9.1",
"trpc-nuxt": "workspace:*", "trpc-nuxt": "workspace:*",
"zod": "^3.16.0" "zod": "^3.16.0"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "@antfu" "extends": "@antfu",
"rules": {
"no-console": "warn"
}
} }
} }

View File

@@ -1,10 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
const client = useClient() const client = useClient()
const headers = useClientHeader({ authorization: 'asdada' }) const headers = useClientHeaders()
const { data: todos, pending, error, refresh } = await useAsyncQuery(['getTodos']) const { data: todos, pending, error, refresh } = await useAsyncQuery(['getTodos'])
console.log(headers.value)
const addHeader = () => { const addHeader = () => {
// headers.value.cookie = 'counter=69' // headers.value.cookie = 'counter=69'
console.log(headers.value) console.log(headers.value)

View File

@@ -2,7 +2,6 @@ import * as trpc from '@trpc/server'
import type { inferAsyncReturnType } from '@trpc/server' import type { inferAsyncReturnType } from '@trpc/server'
import { z } from 'zod' import { z } from 'zod'
import type { CompatibilityEvent } from 'h3' import type { CompatibilityEvent } from 'h3'
import { useCookies } from 'h3'
const baseURL = 'https://jsonplaceholder.typicode.com' const baseURL = 'https://jsonplaceholder.typicode.com'
@@ -30,6 +29,7 @@ export const router = trpc.router<Context>()
.mutation('addTodo', { .mutation('addTodo', {
input: TodoShape, input: TodoShape,
async resolve(req) { async resolve(req) {
console.log(req.input)
return await $fetch<Todo>(`${baseURL}/todos`, { return await $fetch<Todo>(`${baseURL}/todos`, {
method: 'POST', method: 'POST',
body: req.input, body: req.input,

2078
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,14 @@
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
import { join, resolve } from 'pathe' import { join, resolve } from 'pathe'
import { defu } from 'defu' import { defu } from 'defu'
// @ts-expect-error: No types
import dedent from 'dedent'
import { addPlugin, addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit' import { addAutoImport, addPlugin, addServerHandler, addTemplate, defineNuxtModule } from '@nuxt/kit'
export interface ModuleOptions { export interface ModuleOptions {
baseURL: string baseURL: string
trpcURL: string endpoint: string
} }
export default defineNuxtModule<ModuleOptions>({ export default defineNuxtModule<ModuleOptions>({
@@ -16,14 +18,14 @@ export default defineNuxtModule<ModuleOptions>({
}, },
defaults: { defaults: {
baseURL: 'http://localhost:3000', baseURL: 'http://localhost:3000',
trpcURL: '/api/trpc', endpoint: '/trpc',
}, },
async setup(options, nuxt) { async setup(options, nuxt) {
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url)) const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
nuxt.options.build.transpile.push(runtimeDir, '#build/trpc-handler') nuxt.options.build.transpile.push(runtimeDir, '#build/trpc-handler')
const handlerPath = join(nuxt.options.buildDir, 'trpc-handler.ts') 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 // Add vueuse
nuxt.options.modules.push('@vueuse/nuxt') nuxt.options.modules.push('@vueuse/nuxt')
@@ -31,19 +33,18 @@ export default defineNuxtModule<ModuleOptions>({
// Final resolved configuration // Final resolved configuration
const finalConfig = nuxt.options.runtimeConfig.public.trpc = defu(nuxt.options.runtimeConfig.public.trpc, { const finalConfig = nuxt.options.runtimeConfig.public.trpc = defu(nuxt.options.runtimeConfig.public.trpc, {
baseURL: options.baseURL, baseURL: options.baseURL,
trpcURL: options.trpcURL, endpoint: options.endpoint,
}) })
nuxt.hook('autoImports:extend', (imports) => { addAutoImport([
imports.push( { name: 'useClient', from: join(runtimeDir, 'client') },
{ name: 'useClient', from: join(runtimeDir, 'client') }, { name: 'useAsyncQuery', from: join(runtimeDir, 'client') },
{ name: 'useAsyncQuery', from: join(runtimeDir, 'client') }, { name: 'useClientHeaders', from: join(runtimeDir, 'client') },
{ name: 'useClientHeader', from: join(runtimeDir, 'client') }, { name: 'getQueryKey', from: join(runtimeDir, 'client') },
) ])
})
addServerHandler({ addServerHandler({
route: `${finalConfig.trpcURL}/*`, route: `${finalConfig.endpoint}/*`,
handler: handlerPath, handler: handlerPath,
}) })
@@ -53,13 +54,13 @@ export default defineNuxtModule<ModuleOptions>({
filename: 'trpc-handler.ts', filename: 'trpc-handler.ts',
write: true, write: true,
getContents() { getContents() {
return ` return dedent`
import { createTRPCHandler } from 'trpc-nuxt/api' import { createTRPCHandler } from 'trpc-nuxt/api'
import * as functions from '${trpcOptionsPath}' import * as functions from '${trpcOptionsPath}'
export default createTRPCHandler({ export default createTRPCHandler({
...functions, ...functions,
trpcURL: '${finalConfig.trpcURL}' endpoint: '${finalConfig.endpoint}'
}) })
` `
}, },

View File

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

View File

@@ -8,11 +8,13 @@ import type {
import type { ProcedureRecord, inferHandlerInput, inferProcedureInput, inferProcedureOutput } from '@trpc/server' import type { ProcedureRecord, inferHandlerInput, inferProcedureInput, inferProcedureOutput } from '@trpc/server'
import type { TRPCClient, TRPCClientErrorLike } from '@trpc/client' import type { TRPCClient, TRPCClientErrorLike } from '@trpc/client'
import { objectHash } from 'ohash' import { objectHash } from 'ohash'
import type { MaybeRef } from '@vueuse/core' import type { Ref } from 'vue'
import { useStorage } from '@vueuse/core' import { useStorage } from '@vueuse/core'
import { useAsyncData, useNuxtApp, useState } from '#app' import { useAsyncData, useNuxtApp, useState } from '#app'
import type { router } from '~/server/trpc' import type { router } from '~/server/trpc'
type MaybeRef<T> = T | Ref<T>
type AppRouter = typeof router type AppRouter = typeof router
export type inferProcedures< export type inferProcedures<
@@ -30,12 +32,15 @@ export type TError = TRPCClientErrorLike<AppRouter>
export type TQueryValues = inferProcedures<AppRouter['_def']['queries']> export type TQueryValues = inferProcedures<AppRouter['_def']['queries']>
/** /**
* Additional header properties to pass to tRPC client. * Calculates the key used for `useAsyncData` call
* * @param pathAndInput
* @see https://trpc.io/docs/vanilla
* @param pathAndInput tRPC client path and input.
* @param options Options to pass to useAsyncData.
*/ */
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< export async function useAsyncQuery<
TPath extends keyof TQueryValues & string, TPath extends keyof TQueryValues & string,
TOutput extends TQueryValues[TPath]['output'] = TQueryValues[TPath]['output'], TOutput extends TQueryValues[TPath]['output'] = TQueryValues[TPath]['output'],
@@ -46,7 +51,7 @@ export async function useAsyncQuery<
options: AsyncDataOptions<TOutput, Transform, PickKeys> = {}, options: AsyncDataOptions<TOutput, Transform, PickKeys> = {},
): Promise<AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, TError>> { ): Promise<AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, TError>> {
const { $client } = useNuxtApp() 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 serverError = useState<TError | null>(`error-${key}`, () => null)
const { error, data, ...rest } = await useAsyncData( const { error, data, ...rest } = await useAsyncData(
key, key,
@@ -68,22 +73,11 @@ export async function useAsyncQuery<
} as any } as any
} }
/**
* tRPC Client.
*
* @see https://trpc.io/docs/vanilla
*/
export function useClient(): TRPCClient<AppRouter> { export function useClient(): TRPCClient<AppRouter> {
const { $client } = useNuxtApp() const { $client } = useNuxtApp()
return $client return $client
} }
/** export function useClientHeaders(initialValue: MaybeRef<Record<string, any>> = {}): Ref<Record<string, any>> {
* Additional header properties to pass to tRPC client. return useStorage('trpc-nuxt-header', initialValue)
*
* @see https://github.com/trpc/trpc/discussions/1686
* @param initialValue
*/
export function useClientHeaders(initialValue?: MaybeRef<Record<string, any>>) {
return useStorage('trpc-nuxt-header', initialValue || {})
} }

View File

@@ -1,4 +1,6 @@
import * as trpc from '@trpc/client' import * as trpc from '@trpc/client'
import { unref } from 'vue'
import { useClientHeaders } from './client'
import { defineNuxtPlugin, useRequestHeaders, useRuntimeConfig } from '#app' import { defineNuxtPlugin, useRequestHeaders, useRuntimeConfig } from '#app'
import type { router } from '~/server/trpc' import type { router } from '~/server/trpc'
@@ -7,17 +9,12 @@ declare type AppRouter = typeof router
export default defineNuxtPlugin((nuxtApp) => { export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig().public.trpc const config = useRuntimeConfig().public.trpc
const headers = useRequestHeaders() const headers = useRequestHeaders()
const otherHeaders = useClientHeaders()
const client = trpc.createTRPCClient<AppRouter>({ const client = trpc.createTRPCClient<AppRouter>({
url: `${config.baseURL}${config.trpcURL}`, url: `${config.baseURL}${config.endpoint}`,
headers: () => { headers: () => {
let otherHeaders = {}
if (!process.server) {
const key = 'trpc-nuxt-header'
otherHeaders = JSON.parse(localStorage.getItem(key) || JSON.stringify({}))
}
return { return {
...otherHeaders, ...unref(otherHeaders),
...headers, ...headers,
} }
}, },