/** * AC verification for Passo 4: * requireRole('ADMIN') returns FORBIDDEN for OPERATOR, passes for ADMIN. * * Uses createCallerFactory with in-memory contexts — no DB or HTTP required. */ import { TRPCError } from '@trpc/server'; import { router, createCallerFactory, requireRole } from '../packages/api/src/trpc.js'; import type { Context } from '../packages/api/src/context.js'; function makeCtx(role: 'ADMIN' | 'OPERATOR'): Context { return { user: { id: 'u1', email: `${role.toLowerCase()}@demo.local`, role, tenantId: 't1' }, // db / prisma / logger are not touched by the role check, use minimal stubs db: {} as Context['db'], prisma: {} as Context['prisma'], tenantId: 't1', headers: new Headers(), logger: console as unknown as Context['logger'], }; } const testRouter = router({ adminOnly: requireRole('ADMIN').query(() => ({ ok: true })), }); const createCaller = createCallerFactory(testRouter); async function main() { // OPERATOR must be rejected with FORBIDDEN try { await createCaller(makeCtx('OPERATOR')).adminOnly(); throw new Error('Expected FORBIDDEN but call succeeded'); } catch (err) { if (err instanceof TRPCError && err.code === 'FORBIDDEN') { console.log('OPERATOR → FORBIDDEN ✓'); } else { throw err; } } // ADMIN must succeed const result = await createCaller(makeCtx('ADMIN')).adminOnly(); if (!result.ok) throw new Error('ADMIN call returned unexpected result'); console.log('ADMIN → ok ✓'); console.log('\nRole middleware AC PASSED'); } main().catch((err) => { console.error('Role middleware AC FAILED:', err); process.exit(1); });