diff --git a/module.mjs b/module.mjs deleted file mode 100644 index e0c24b6..0000000 --- a/module.mjs +++ /dev/null @@ -1,14 +0,0 @@ -import { defineNuxtModule } from '@nuxt/kit' - -export default defineNuxtModule({ - meta: { - name: 'trpc-nuxt', - configKey: 'trpc', - compatibility: { - nuxt: '^3.0.0-rc.13' - } - }, - setup (_moduleOptions, nuxt) { - nuxt.options.build.transpile.push('trpc-nuxt') - } -}) diff --git a/package.json b/package.json index 4a87ed4..621187f 100644 --- a/package.json +++ b/package.json @@ -9,17 +9,13 @@ ".": { "require": "./dist/index.cjs", "import": "./dist/index.mjs" - }, - "./module": { - "import": "./module.mjs" } }, "main": "./dist/index.mjs", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", "files": [ - "dist", - "module.mjs" + "dist" ], "scripts": { "dev": "concurrently \"pnpm build --watch\" \"pnpm --filter playground dev\"", diff --git a/src/index.ts b/src/index.ts index 3718365..42c2500 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,126 @@ -export * from './server' +import type { ResponseMeta } from '@trpc/server/http' +import { resolveHTTPResponse } from '@trpc/server/http' +import type { + AnyRouter, + ProcedureType, + inferRouterContext, + inferRouterError +} from '@trpc/server' +import { + TRPCError +} from '@trpc/server' +import { createURL } from 'ufo' +import type { H3Event } from 'h3' +import { createError, defineEventHandler, isMethod, readBody } from 'h3' +import type { TRPCResponse } from '@trpc/server/rpc' + +type MaybePromise = T | Promise + +export type CreateContextFn = (event: H3Event) => MaybePromise> + +export interface ResponseMetaFnPayload { + data: TRPCResponse>[] + ctx?: inferRouterContext + paths?: string[] + type: ProcedureType | 'unknown' + errors: TRPCError[] +} + +export type ResponseMetaFn = (opts: ResponseMetaFnPayload) => ResponseMeta + +export interface OnErrorPayload { + error: TRPCError + type: ProcedureType | 'unknown' + path: string | undefined + req: H3Event['req'] + input: unknown + ctx: undefined | inferRouterContext +} + +export type OnErrorFn = (opts: OnErrorPayload) => void + +export interface ResolveHTTPRequestOptions { + router: TRouter + createContext?: CreateContextFn + responseMeta?: ResponseMetaFn + onError?: OnErrorFn + batching?: { + enabled: boolean + } +} + +function getPath (event: H3Event): string | null { + if (typeof event.context.params.trpc === 'string') { return event.context.params.trpc } + + if (Array.isArray(event.context.params.trpc)) { return event.context.params.trpc.join('/') } + + return null +} + +export function createNuxtApiHandler ({ + router, + createContext, + responseMeta, + onError, + batching +}: ResolveHTTPRequestOptions) { + return defineEventHandler(async (event) => { + const { + req, + res + } = event + + const $url = createURL(req.url!) + + const path = getPath(event) + + if (path === null) { + const error = router.getErrorShape({ + error: new TRPCError({ + message: + 'Param "trpc" not found - is the file named `[trpc]`.ts or `[...trpc].ts`?', + code: 'INTERNAL_SERVER_ERROR' + }), + type: 'unknown', + ctx: undefined, + path: undefined, + input: undefined + }) + + throw createError({ + statusCode: 500, + statusMessage: JSON.stringify(error) + }) + } + + const httpResponse = await resolveHTTPResponse({ + batching, + router, + req: { + method: req.method!, + headers: req.headers, + body: isMethod(event, 'GET') ? null : await readBody(event), + query: $url.searchParams + }, + path, + createContext: async () => await createContext?.(event), + responseMeta, + onError: (o) => { + onError?.({ + ...o, + req + }) + } + }) + + const { status, headers, body } = httpResponse + + res.statusCode = status + + headers && Object.keys(headers).forEach((key) => { + res.setHeader(key, headers[key]!) + }) + + return body + }) +} diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index 42c2500..0000000 --- a/src/server.ts +++ /dev/null @@ -1,126 +0,0 @@ -import type { ResponseMeta } from '@trpc/server/http' -import { resolveHTTPResponse } from '@trpc/server/http' -import type { - AnyRouter, - ProcedureType, - inferRouterContext, - inferRouterError -} from '@trpc/server' -import { - TRPCError -} from '@trpc/server' -import { createURL } from 'ufo' -import type { H3Event } from 'h3' -import { createError, defineEventHandler, isMethod, readBody } from 'h3' -import type { TRPCResponse } from '@trpc/server/rpc' - -type MaybePromise = T | Promise - -export type CreateContextFn = (event: H3Event) => MaybePromise> - -export interface ResponseMetaFnPayload { - data: TRPCResponse>[] - ctx?: inferRouterContext - paths?: string[] - type: ProcedureType | 'unknown' - errors: TRPCError[] -} - -export type ResponseMetaFn = (opts: ResponseMetaFnPayload) => ResponseMeta - -export interface OnErrorPayload { - error: TRPCError - type: ProcedureType | 'unknown' - path: string | undefined - req: H3Event['req'] - input: unknown - ctx: undefined | inferRouterContext -} - -export type OnErrorFn = (opts: OnErrorPayload) => void - -export interface ResolveHTTPRequestOptions { - router: TRouter - createContext?: CreateContextFn - responseMeta?: ResponseMetaFn - onError?: OnErrorFn - batching?: { - enabled: boolean - } -} - -function getPath (event: H3Event): string | null { - if (typeof event.context.params.trpc === 'string') { return event.context.params.trpc } - - if (Array.isArray(event.context.params.trpc)) { return event.context.params.trpc.join('/') } - - return null -} - -export function createNuxtApiHandler ({ - router, - createContext, - responseMeta, - onError, - batching -}: ResolveHTTPRequestOptions) { - return defineEventHandler(async (event) => { - const { - req, - res - } = event - - const $url = createURL(req.url!) - - const path = getPath(event) - - if (path === null) { - const error = router.getErrorShape({ - error: new TRPCError({ - message: - 'Param "trpc" not found - is the file named `[trpc]`.ts or `[...trpc].ts`?', - code: 'INTERNAL_SERVER_ERROR' - }), - type: 'unknown', - ctx: undefined, - path: undefined, - input: undefined - }) - - throw createError({ - statusCode: 500, - statusMessage: JSON.stringify(error) - }) - } - - const httpResponse = await resolveHTTPResponse({ - batching, - router, - req: { - method: req.method!, - headers: req.headers, - body: isMethod(event, 'GET') ? null : await readBody(event), - query: $url.searchParams - }, - path, - createContext: async () => await createContext?.(event), - responseMeta, - onError: (o) => { - onError?.({ - ...o, - req - }) - } - }) - - const { status, headers, body } = httpResponse - - res.statusCode = status - - headers && Object.keys(headers).forEach((key) => { - res.setHeader(key, headers[key]!) - }) - - return body - }) -}