File size: 1,432 Bytes
cfc59e4
bede2fc
598f0d5
cfc59e4
2b62b0c
 
cfc59e4
 
 
 
 
bede2fc
 
 
 
 
 
 
 
 
 
 
 
 
cfc59e4
bede2fc
cfc59e4
 
 
 
 
 
 
 
 
 
 
 
 
 
598f0d5
bede2fc
 
 
 
 
 
598f0d5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import { initTRPC, TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { logger } from "./logger";
import type { Context } from "./context";
import { db } from "@pram/db";
import { user } from "@pram/db";

export const t = initTRPC.context<Context>().create();

export const router = t.router;

// Global logging for all procedures
const baseProcedure = t.procedure.use(({ ctx, path, type, next }) => {
  const start = Date.now();
  logger.info(`${type.toUpperCase()} ${path}`, { userId: ctx.session?.user.id });
  return next().finally(() => {
    logger.info(`${type.toUpperCase()} ${path} completed`, {
      userId: ctx.session?.user.id,
      durationMs: Date.now() - start,
    });
  });
});

export const publicProcedure = baseProcedure;

export const protectedProcedure = baseProcedure.use(({ ctx, next }) => {
  if (!ctx.session) {
    throw new TRPCError({
      code: "UNAUTHORIZED",
      message: "Authentication required",
      cause: "No session",
    });
  }
  return next({
    ctx: {
      ...ctx,
      session: ctx.session,
    },
  });
});

export const adminProcedure = protectedProcedure.use(async ({ ctx, next }) => {
  const [u] = await db.select().from(user).where(eq(user.id, ctx.session.user.id)).limit(1);
  if (!u || u.role !== "admin") {
    throw new TRPCError({ code: "FORBIDDEN", message: "Admin access required" });
  }
  return next({ ctx: { ...ctx, adminUser: u } });
});