import { NextRequest, NextResponse } from 'next/server'; import { downloadArtifact, getArtifact } from '@/features/foundation/document-artifact/server/service'; import { auditCrmSecurityEvent, buildCrmSecurityContext, canViewQuotationPricing } from '@/features/crm/security/server/service'; import { PERMISSIONS } from '@/lib/auth/rbac'; import { AuthError, requireOrganizationAccess } from '@/lib/auth/session'; type Params = { params: Promise<{ id: string }>; }; export async function GET(_request: NextRequest, { params }: Params) { try { const { id } = await params; const { organization, session, membership } = await requireOrganizationAccess({ permission: PERMISSIONS.crmDocumentArtifactDownload }); const securityContext = buildCrmSecurityContext({ organizationId: organization.id, userId: session.user.id, membership }); const artifact = await getArtifact(id, organization.id); if ( artifact.entityType === 'quotation' && artifact.artifactType === 'approved_pdf' && !canViewQuotationPricing(securityContext) ) { await auditCrmSecurityEvent({ organizationId: organization.id, userId: session.user.id, action: 'pricing_hidden', entityType: artifact.entityType, entityId: artifact.entityId, reason: 'Approved quotation artifact download requires pricing visibility', metadata: { artifactId: artifact.id } }); return NextResponse.json({ message: 'Forbidden' }, { status: 403 }); } const { object } = await downloadArtifact({ artifactId: id, organizationId: organization.id, userId: session.user.id, auditDownload: true }); return new NextResponse(object.body, { headers: { 'Content-Type': object.contentType, 'Content-Disposition': `inline; filename="${object.fileName || 'artifact'}"` } }); } catch (error) { if (error instanceof AuthError) { return NextResponse.json({ message: error.message }, { status: error.status }); } return NextResponse.json({ message: 'Unable to download document artifact' }, { status: 500 }); } }