/** * POST /api/analyzer/analyses/:id/share * * Body: { recipientEmail: string, note?: string } * * Records a share row in analyzer_shares. Email send is deferred to phase 8 * — this endpoint validates the recipient domain against ALLOWED_SHARE_DOMAINS * and persists the audit row. The share is "pending delivery" until phase 8 * wires up nodemailer. */ import { NextRequest, NextResponse } from 'next/server'; import { requireAuth } from '@/lib/auth-utils'; import { ShareAnalysisRequest } from '@/lib/types/analyzer'; import { createShare, getAnalysisById, } from '@/lib/services/analyzer/persistence'; function getAllowedDomains(): string[] { const raw = process.env.ALLOWED_SHARE_DOMAINS ?? ''; return raw .split(',') .map((d) => d.trim().toLowerCase()) .filter((d) => d.length > 0); } export async function POST( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { const { session, error } = await requireAuth(); if (error) return error; const { id } = await params; const body = await request.json().catch(() => ({})); const result = ShareAnalysisRequest.safeParse(body); if (!result.success) { return NextResponse.json( { error: 'Invalid request body', details: result.error.issues }, { status: 400 } ); } const { recipientEmail, note } = result.data; const allowedDomains = getAllowedDomains(); if (allowedDomains.length === 0) { return NextResponse.json( { error: 'Sharing is not configured', message: 'ALLOWED_SHARE_DOMAINS env var is empty.', }, { status: 503 } ); } const domain = recipientEmail.split('@')[1]?.toLowerCase(); if (!domain || !allowedDomains.includes(domain)) { return NextResponse.json( { error: 'Recipient domain is not allowed', message: `Allowed domains: ${allowedDomains.join(', ')}`, }, { status: 403 } ); } // Confirm the analysis exists. const analysis = await getAnalysisById(id); if (!analysis) { return NextResponse.json({ error: 'Analysis not found' }, { status: 404 }); } const userId = (session?.user as { id: string }).id; const share = await createShare({ analysis_id: id, shared_by_user_id: userId, shared_with_email: recipientEmail, note, }); return NextResponse.json({ share: { id: share.id, analysisId: id, sharedWithEmail: recipientEmail, sharedAt: share.shared_at, note: note ?? null, }, }); }