feat(backend): add tRPC with Hono adapter

- Add @trpc/server, @hono/trpc-server, zod dependencies
- Create tRPC context with BetterAuth session
- Create router with publicProcedure and protectedProcedure
- Mount tRPC at /trpc/* via Hono adapter

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2026-01-25 22:19:05 +00:00
parent 0db6cae82b
commit aff9464245
6 changed files with 70 additions and 2 deletions

View File

@@ -12,9 +12,12 @@
"@aris/core": "workspace:*",
"@aris/source-location": "workspace:*",
"@aris/source-weatherkit": "workspace:*",
"@hono/trpc-server": "^0.3",
"@trpc/server": "^11",
"better-auth": "^1",
"hono": "^4",
"pg": "^8"
"pg": "^8",
"zod": "^3"
},
"devDependencies": {
"@types/pg": "^8"

View File

@@ -1,6 +1,9 @@
import { trpcServer } from "@hono/trpc-server"
import { Hono } from "hono"
import { registerAuthHandlers } from "./auth/http.ts"
import { createContext } from "./trpc/context.ts"
import { appRouter } from "./trpc/router.ts"
const app = new Hono()
@@ -8,6 +11,14 @@ app.get("/health", (c) => c.json({ status: "ok" }))
registerAuthHandlers(app)
app.use(
"/trpc/*",
trpcServer({
router: appRouter,
createContext,
}),
)
export default {
port: 3000,
fetch: app.fetch,

View File

@@ -0,0 +1,14 @@
import type { FetchCreateContextFnOptions } from "@trpc/server/adapters/fetch"
import { auth } from "../auth/index.ts"
export async function createContext(opts: FetchCreateContextFnOptions) {
const session = await auth.api.getSession({ headers: opts.req.headers })
return {
user: session?.user ?? null,
session: session?.session ?? null,
}
}
export type Context = Awaited<ReturnType<typeof createContext>>

View File

@@ -0,0 +1,5 @@
import { router } from "./trpc.ts"
export const appRouter = router({})
export type AppRouter = typeof appRouter

View File

@@ -0,0 +1,22 @@
import { initTRPC, TRPCError } from "@trpc/server"
import type { Context } from "./context.ts"
const t = initTRPC.context<Context>().create()
export const router = t.router
export const publicProcedure = t.procedure
const isAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.user || !ctx.session) {
throw new TRPCError({ code: "UNAUTHORIZED" })
}
return next({
ctx: {
user: ctx.user,
session: ctx.session,
},
})
})
export const protectedProcedure = t.procedure.use(isAuthed)