import { FastifyRequest, FastifyReply } from 'fastify'; import { prisma } from '../services/prisma'; import { decryptSecrets } from '../services/organization'; export async function injectTenantConfig(request: FastifyRequest, reply: FastifyReply) { const organizationId = request.organizationId; if (!organizationId) { return; // Some routes might not require it, guarded routes will check this later if needed } try { const organization = await prisma.organization.findUnique({ where: { id: organizationId }, include: { phoneNumbers: true } }); if (!organization) { return reply.code(404).send({ error: 'Organization not found' }); } // Reject requests from hard-stopped (suspended) organizations if (organization.isHardStopped) { // Super-admin API key calls always pass (needed for management) const isInternalCall = request.headers['x-api-key'] === process.env.ADMIN_API_KEY; if (!isInternalCall) { return reply.code(402).send({ error: 'Service suspended — payment required', code: 'ORG_SUSPENDED' }); } } // Attach decrypted config to request request.tenantConfig = decryptSecrets(organization); } catch (err) { request.log.error({ err, organizationId }, '[TENANT_MIDDLEWARE] Failed to resolve tenant config'); return reply.code(500).send({ error: 'Internal server error resolving organization' }); } }