Last active
June 1, 2025 11:57
-
-
Save ThimoDEV/27eb1dba1fb447e43175f08093e5e99d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Make a file named: defineNitroTRPCEventHandler.ts | |
import { | |
type AnyRouter, | |
type ProcedureType, | |
type TRPCError, | |
type inferRouterContext, | |
type inferRouterError, | |
} from "@trpc/server"; | |
import { type ResponseMeta } from "@trpc/server/http"; | |
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; | |
import { TRPCResponse } from "@trpc/server/rpc"; | |
import { | |
type H3Event, | |
defineEventHandler, | |
isMethod, | |
readBody | |
} from "h3"; | |
import { MaybePromise } from "/types/promise"; | |
import { getPath } from "/utils/internals"; | |
export type CreateContextFn< | |
TRouter extends AnyRouter, | |
= ( | |
event: H3Event | |
) => MaybePromise<inferRouterContext>; | |
export interface ResponseMetaFnPayload< | |
TRouter extends AnyRouter, | |
{ | |
data: TRPCResponse< | |
unknown, | |
inferRouterError | |
[]; | |
ctx?: inferRouterContext; | |
paths?: readonly string[]; | |
type: ProcedureType | "unknown"; | |
errors: TRPCError[]; | |
} | |
export type ResponseMetaFn< | |
TRouter extends AnyRouter, | |
= ( | |
opts: ResponseMetaFnPayload | |
) => ResponseMeta; | |
export interface OnErrorPayload< | |
TRouter extends AnyRouter, | |
{ | |
error: TRPCError; | |
type: ProcedureType | "unknown"; | |
path: string | undefined; | |
req: Request; | |
input: unknown; | |
ctx: undefined | inferRouterContext; | |
} | |
export type OnErrorFn = | |
(opts: OnErrorPayload) => void; | |
export const defineNitroTRPCEventHandler = < | |
TRouter extends AnyRouter, | |
({ | |
router, | |
createContext, | |
responseMeta, | |
onError, | |
}: { | |
router: TRouter; | |
createContext?: ( | |
e: H3Event | |
) => | |
| inferRouterContext | |
| Promise<inferRouterContext>; | |
responseMeta?: ResponseMetaFn; | |
onError?: OnErrorFn; | |
}) => { | |
return defineEventHandler(async (event) => { | |
const req = new Request( | |
getRequestURL(event), | |
{ | |
method: event.method, | |
headers: event.headers, | |
body: isMethod(event, "GET") | |
? undefined | |
: await readBody(event), | |
} | |
); | |
return fetchRequestHandler({ | |
req, | |
router, | |
endpoint: getPath(event), | |
createContext: createContext | |
? () => createContext(event) | |
: undefined, | |
responseMeta, | |
onError, | |
}); | |
}); | |
}; | |
Place below code in a file internals.ts in the utils folder in nitro | |
import { TRPCError } from "@trpc/server"; | |
import { type H3Event } from "h3"; | |
export const getPath = ( | |
event: H3Event | |
): string => { | |
const params = event.context.params; | |
if (!params) { | |
// Throw an error if the trpc parameter is not a string or an array: | |
throw new TRPCError({ | |
code: "INTERNAL_SERVER_ERROR", | |
message: | |
"Please ensure that the trpc parameter is defined in your routes file e.g., ./routes/[trpc].ts", | |
cause: "Nitro Routing Configuration", | |
}); | |
} | |
if (typeof params.trpc === "string") { | |
return params.trpc; | |
} | |
if (typeof params.trpc === "string") { | |
return params.trpc; | |
} | |
// Throw an error if the trpc parameter is not a string or an array: | |
throw new TRPCError({ | |
code: "INTERNAL_SERVER_ERROR", | |
message: | |
"Please ensure that the trpc parameter is defined in your routes file e.g., ./routes/[trpc].ts", | |
cause: "Nitro Routing Configuration", | |
}); | |
}; | |
Make a folder and file in: trpc/appRouter.ts | |
import { | |
protectedProcedure, | |
publicProcedure, | |
router, | |
} from "~~/src/lib/trpc"; | |
export const appRouter = router({ | |
healthCheck: publicProcedure.query(() => "OK"), | |
privateData: protectedProcedure.query( | |
({ ctx }) => ({ | |
message: "This is private", | |
user: ctx.session.user, | |
}) | |
), | |
}); | |
export type AppRouter = typeof appRouter; | |
Add a folder/file in: lib/trpc.ts | |
import { | |
initTRPC, | |
TRPCError, | |
} from "@trpc/server"; | |
import type { Context } from "./context"; | |
import superjson from "superjson"; | |
const t = initTRPC.context().create({ | |
transformer: superjson, | |
}); | |
export const router = t.router; | |
export const publicProcedure = t.procedure; | |
export const protectedProcedure = t.procedure.use( | |
({ ctx, next }) => { | |
if (!ctx.session) { | |
throw new TRPCError({ | |
code: "UNAUTHORIZED", | |
message: "Authentication required", | |
}); | |
} | |
return next({ | |
ctx: { ...ctx, session: ctx.session }, | |
}); | |
} | |
); | |
Create a file in: lib/context.ts | |
import type { H3Event } from "h3"; | |
import { auth } from "./auth"; | |
export async function createContext( | |
event: H3Event | |
) { | |
const session = await auth.api.getSession({ | |
headers: event.headers, | |
}); | |
return { session, event }; | |
} | |
export type Context = Awaited<ReturnType; | |
export type MaybePromise = T | Promise; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment