File size: 3,447 Bytes
303f049 | 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { signupSchema, getClientIp } from '@/lib/validation';
import {
hashPassword,
createSession,
generateApiKey,
SESSION_COOKIE_NAME,
} from '@/lib/auth';
import { authRateLimit } from '@/lib/rate-limit';
import { logActivity } from '@/lib/activity';
export async function POST(request: NextRequest) {
try {
// ── Rate Limit ────────────────────────────────────────────────────
const ip = getClientIp(request);
const { allowed, retryAfterMs } = await authRateLimit(`auth:${ip}`);
if (!allowed) {
return NextResponse.json(
{ error: 'Too many signup attempts. Please try again later.' },
{
status: 429,
headers: { 'Retry-After': String(Math.ceil(retryAfterMs / 1000)) },
}
);
}
// ── Parse & Validate Body ─────────────────────────────────────────
const body = await request.json();
const parsed = signupSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: parsed.error.issues[0].message },
{ status: 400 }
);
}
const { name, email, password } = parsed.data;
// ── Check if Email Exists ─────────────────────────────────────────
const existing = await db.user.findUnique({ where: { email } });
if (existing) {
return NextResponse.json(
{ error: 'An account with this email already exists' },
{ status: 409 }
);
}
// ── Hash Password & Generate API Key ──────────────────────────────
const [hashedPassword, apiKey] = await Promise.all([
hashPassword(password),
generateApiKey(),
]);
// ── Create User ───────────────────────────────────────────────────
const user = await db.user.create({
data: {
name,
email,
password: hashedPassword,
apiKey,
plan: 'free',
},
});
// ── Create Session ────────────────────────────────────────────────
const token = await createSession(user.id);
// ── Set Cookie & Respond ──────────────────────────────────────────
const response = NextResponse.json({
user: {
id: user.id,
email: user.email,
name: user.name,
plan: user.plan,
createdAt: user.createdAt,
},
});
response.cookies.set(SESSION_COOKIE_NAME, token, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
maxAge: 7 * 24 * 60 * 60, // 7 days
});
logActivity(user.id, 'signup', 'Account created', user.email);
return response;
} catch (error) {
console.error('[SIGNUP_ERROR]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
} |