"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = registerHandler; const crypto_1 = __importDefault(require("crypto")); const drive_1 = require("../services/drive"); const mailer_1 = require("../services/mailer"); const validate_1 = require("../utils/validate"); const owners_1 = require("../utils/owners"); async function registerHandler(req, res) { try { const { user, pass, email, bio, nickname, dob, country } = req.body || {}; const host = req.body?.host || req.query?.host || ""; const usernameCheck = (0, validate_1.validateUsername)(String(user || "")); if (!usernameCheck.ok) return res.status(400).json({ success: false, message: usernameCheck.message }); const emailCheck = (0, validate_1.validateEmail)(String(email || "")); if (!emailCheck.ok) return res.status(400).json({ success: false, message: emailCheck.message }); const passCheck = (0, validate_1.validatePassword)(String(pass || "")); if (!passCheck.ok) return res.status(400).json({ success: false, message: passCheck.message }); const normalizedEmail = String(email).trim().toLowerCase(); // Enforce: ONE account per email const existing = await (0, drive_1.getAllUsers)(); const emailTaken = existing.some(u => (u.email || "").trim().toLowerCase() === normalizedEmail); if (emailTaken) { return res.status(409).json({ success: false, message: "An account with this email already exists" }); } const formattedUsername = (0, validate_1.cleanUsername)(user); const usernameTaken = existing.some(u => u.username === formattedUsername); if (usernameTaken) { return res.status(409).json({ success: false, message: "Username already taken" }); } const files = req.files; const avatarBuffer = files?.["avatar"]?.[0]?.buffer ?? null; const coverBuffer = files?.["cover"]?.[0]?.buffer ?? null; const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; const userId = Date.now() + Math.floor(Math.random() * 1000); const otp = Math.floor(100000 + Math.random() * 900000).toString(); const generatedToken = crypto_1.default.randomBytes(32).toString("hex"); const userData = { id: userId, user: String(user), username: formattedUsername, pass: String(pass), email: normalizedEmail, bio: bio || "", nickname: nickname || user, dob: dob || "", country: country || "", timezone, verified: false, verifyOtp: otp, token: generatedToken, createdAt: Date.now(), role: (0, owners_1.roleForEmail)(normalizedEmail) || "user", level: 0, xp: 0, achievements: [], bannedUntil: null, }; await (0, drive_1.registerUserToDrive)(userData, avatarBuffer, coverBuffer); // Best-effort send the verification email immediately. // Prefer the public web host (the user's browser URL) so the link works // outside the Replit container. Fall back to API_PUBLIC_BASE then localhost. const port = process.env.PORT || 8081; const apiBase = (host && /^https?:\/\//.test(host) ? host.replace(/\/$/, "") : null) || process.env.API_PUBLIC_BASE || `http://localhost:${port}`; const verifyLink = `${apiBase}/exocore/api/auth/verify?username=${encodeURIComponent(formattedUsername)}&otp=${otp}&host=${encodeURIComponent(host)}`; (0, mailer_1.sendVerifyEmail)(normalizedEmail, verifyLink, userData.nickname).catch(() => { }); return res.status(200).json({ success: true, message: "Account created. Check your email to verify.", data: { id: userId, username: formattedUsername, email: normalizedEmail, nickname: userData.nickname, verified: false, token: generatedToken, }, }); } catch (err) { if (err?.message === "ALREADY_EXISTS") { return res.status(409).json({ success: false, message: "Username already taken" }); } console.error("[register] error:", err); return res.status(500).json({ success: false, message: "Registration failed", error: err?.message }); } }