import * as Sentry from '@sentry/nextjs'; import { fetchRequestHandler } from '@trpc/server/adapters/fetch'; import { appRouter, createContext } from '@linkder/api'; import { db } from '@linkder/db'; import { resolveSession } from '@/server/session'; /** * The HTTP entry point. A future React Native app talks to exactly this URL with * the same generated client, which is the whole reason the API is tRPC rather * than server actions. */ function handler(req: Request) { return fetchRequestHandler({ endpoint: '/api/trpc', req, router: appRouter, createContext: () => createContext({ req, db, resolveSession, ip: req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? null, }), onError({ error, path, type }) { // Client errors are expected; server errors are ours and must be visible. // Reporting BAD_REQUEST or UNAUTHORIZED to Bugsink would bury the real // failures under a stream of ordinary validation and sign-in noise. if (error.code !== 'INTERNAL_SERVER_ERROR') return; console.error(`tRPC ${path ?? ''} failed:`, error.cause ?? error); Sentry.captureException(error.cause ?? error, { tags: { trpcPath: path ?? 'unknown', trpcType: type }, // NOT the input: a procedure's input is where phone numbers and OTP // codes live. The path plus the stack is enough to find the bug. fingerprint: ['trpc', path ?? 'unknown', error.code], }); }, }); } export { handler as GET, handler as POST };