import bcrypt from 'bcryptjs'; import { sql } from '@vercel/postgres'; import { generateUniqueSlug } from '../../../lib/slug-utils.js'; import { generateToken } from '../auth-utils.js'; export default async function handler(req, res) { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // Handle preflight requests if (req.method === 'OPTIONS') { res.status(200).end(); return; } if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } try { const { email, password, firstName, lastName, username, profileImage } = req.body; // Validate required fields if (!email || !password || !firstName || !lastName || !username) { return res.status(400).json({ error: 'All fields are required' }); } if (password.length < 6) { return res.status(400).json({ error: 'Password must be at least 6 characters' }); } // Validate username if (username.length < 3) { return res.status(400).json({ error: 'Username must be at least 3 characters' }); } if (!/^[a-zA-Z0-9_]+$/.test(username)) { return res.status(400).json({ error: 'Username can only contain letters, numbers, and underscores' }); } // Check if user already exists (email or username) const existingUser = await sql` SELECT id FROM users WHERE email = ${email} OR username = ${username} `; if (existingUser.rows.length > 0) { // Check which field conflicts const conflictUser = await sql` SELECT email, username FROM users WHERE email = ${email} OR username = ${username} `; const conflict = conflictUser.rows[0]; if (conflict.email === email) { return res.status(409).json({ error: 'Email already exists' }); } else { return res.status(409).json({ error: 'Username already taken' }); } } // Hash password const hashedPassword = await bcrypt.hash(password, 12); // Create user with all fields const result = await sql` INSERT INTO users ( email, password, first_name, last_name, username, profile_image_url, role ) VALUES ( ${email}, ${hashedPassword}, ${firstName}, ${lastName}, ${username}, ${profileImage || null}, ${'user'} ) RETURNING id, email, first_name, last_name, username, profile_image_url, role, created_at `; const user = result.rows[0]; // Create the automatic "All My Cards" collection for the new user try { // Get existing slugs to ensure uniqueness const existingSlugsData = await sql`SELECT slug FROM collections WHERE slug IS NOT NULL`; const existingSlugs = (existingSlugsData.rows || []).map(row => row.slug); // Generate unique slug for "All My Cards" const uniqueSlug = await generateUniqueSlug("All My Cards", existingSlugs); // Create the special collection const collectionResult = await sql` INSERT INTO collections ( name, description, tcg, is_public, user_id, slug, is_system_collection, created_at, updated_at ) VALUES ( 'All My Cards', 'Automatically contains all cards you mark as owned. This collection cannot be deleted or made public.', 'All', false, ${user.id}, ${uniqueSlug}, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP ) RETURNING id `; const collection = collectionResult.rows[0]; // Create owner permission for the collection await sql` INSERT INTO collection_permissions (collection_id, user_id, role, status, created_at) VALUES (${collection.id}, ${user.id}, 'owner', 'active', CURRENT_TIMESTAMP) `; console.log(`✅ Created "All My Cards" collection for user ${user.email} (ID: ${collection.id})`); } catch (collectionError) { console.error('Error creating "All My Cards" collection:', collectionError); // Don't fail the registration if collection creation fails } // Generate JWT token const token = generateToken({ id: user.id, email: user.email, role: user.role }); // Return user data without password const userResponse = { id: user.id, email: user.email, firstName: user.first_name, lastName: user.last_name, username: user.username, profileImage: user.profile_image_url, role: user.role, createdAt: user.created_at }; res.status(201).json({ success: true, user: userResponse, token }); } catch (error) { console.error('Registration error:', error); res.status(500).json({ error: 'Internal server error' }); } }