···
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
// Check subscription status
-
const subscription = db
-
.query<{ status: string }, [number]>(
-
"SELECT status FROM subscriptions WHERE user_id = ? AND status IN ('active', 'trialing', 'past_due') ORDER BY created_at DESC LIMIT 1",
-
// Get notification preferences
-
.query<{ email_notifications_enabled: number }, [number]>(
-
"SELECT email_notifications_enabled FROM users WHERE id = ?",
-
created_at: user.created_at,
-
has_subscription: !!subscription,
-
email_verified: isEmailVerified(user.id),
-
email_notifications_enabled: prefs?.email_notifications_enabled === 1,
"/api/passkeys/register/options": {
···
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const sessions = getUserSessionsForUser(user.id);
-
sessions: sessions.map((s) => ({
-
ip_address: s.ip_address,
-
user_agent: s.user_agent,
-
created_at: s.created_at,
-
expires_at: s.expires_at,
-
is_current: s.id === sessionId,
-
const currentSessionId = getSessionFromRequest(req);
-
if (!currentSessionId) {
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(currentSessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "delete-session", {
-
ip: { max: 20, windowSeconds: 60 * 60 },
-
if (rateLimitError) return rateLimitError;
-
const body = await req.json();
-
const targetSessionId = body.sessionId;
-
if (!targetSessionId) {
-
{ error: "Session ID required" },
-
// Prevent deleting current session
-
if (targetSessionId === currentSessionId) {
-
{ error: "Cannot kill current session. Use logout instead." },
-
// Verify the session belongs to the user
-
const targetSession = getSession(targetSessionId);
-
if (!targetSession || targetSession.user_id !== user.id) {
-
return Response.json({ error: "Session not found" }, { status: 404 });
-
deleteSession(targetSessionId);
-
return Response.json({ success: true });
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "delete-user", {
-
ip: { max: 3, windowSeconds: 60 * 60 },
-
if (rateLimitError) return rateLimitError;
-
await deleteUser(user.id);
-
"session=; HttpOnly; Secure; Path=/; Max-Age=0; SameSite=Lax",
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "update-email", {
-
ip: { max: 5, windowSeconds: 60 * 60 },
-
if (rateLimitError) return rateLimitError;
-
const body = await req.json();
-
const { email } = body;
-
return Response.json({ error: "Email required" }, { status: 400 });
-
// Check if email is already in use
-
const existingUser = getUserByEmail(email);
-
{ error: "Email already in use" },
-
// Create email change token
-
const token = createEmailChangeToken(user.id, email);
-
// Send verification email to the CURRENT address
-
const origin = process.env.ORIGIN || "http://localhost:3000";
-
const verifyUrl = `${origin}/api/user/email/verify?token=${token}`;
-
subject: "Verify your email change",
-
html: emailChangeTemplate({
-
currentEmail: user.email,
-
message: `Verification email sent to ${user.email}`,
-
"[Email] Failed to send email change verification:",
-
{ error: "Failed to send verification email" },
···
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "update-password", {
-
ip: { max: 5, windowSeconds: 60 * 60 },
-
if (rateLimitError) return rateLimitError;
-
const body = await req.json();
-
const { password } = body;
-
return Response.json({ error: "Password required" }, { status: 400 });
-
// Validate password format (client-side hashed PBKDF2)
-
const passwordValidation = validatePasswordHash(password);
-
if (!passwordValidation.valid) {
-
{ error: passwordValidation.error },
-
await updateUserPassword(user.id, password);
-
return Response.json({ success: true });
-
{ error: "Failed to update password" },
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "update-name", {
-
ip: { max: 10, windowSeconds: 5 * 60 },
-
if (rateLimitError) return rateLimitError;
-
const body = await req.json();
-
return Response.json({ error: "Name required" }, { status: 400 });
-
updateUserName(user.id, name);
-
return Response.json({ success: true });
-
{ error: "Failed to update name" },
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "update-avatar", {
-
ip: { max: 10, windowSeconds: 5 * 60 },
-
if (rateLimitError) return rateLimitError;
-
const body = await req.json();
-
const { avatar } = body;
-
return Response.json({ error: "Avatar required" }, { status: 400 });
-
updateUserAvatar(user.id, avatar);
-
return Response.json({ success: true });
-
{ error: "Failed to update avatar" },
"/api/user/notifications": {
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
-
const rateLimitError = enforceRateLimit(req, "update-notifications", {
-
ip: { max: 10, windowSeconds: 5 * 60 },
-
if (rateLimitError) return rateLimitError;
-
const body = await req.json();
-
const { email_notifications_enabled } = body;
-
if (typeof email_notifications_enabled !== "boolean") {
-
{ error: "email_notifications_enabled must be a boolean" },
-
"UPDATE users SET email_notifications_enabled = ? WHERE id = ?",
-
[email_notifications_enabled ? 1 : 0, user.id],
-
return Response.json({ success: true });
-
{ error: "Failed to update notification settings" },
"/api/billing/checkout": {
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
const { polar } = await import("./lib/polar");
···
return Response.json({ url: checkout.url });
-
console.error("Failed to create checkout:", error);
-
{ error: "Failed to create checkout session" },
"/api/billing/subscription": {
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
// Get subscription from database
···
return Response.json({ subscription });
-
console.error("Failed to fetch subscription:", error);
-
{ error: "Failed to fetch subscription" },
-
const sessionId = getSessionFromRequest(req);
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
-
const user = getUserBySession(sessionId);
-
return Response.json({ error: "Invalid session" }, { status: 401 });
const { polar } = await import("./lib/polar");
// Get subscription to find customer ID
···
return Response.json({ url: session.customerPortalUrl });
-
console.error("Failed to create portal session:", error);
-
{ error: "Failed to create portal session" },
···
+
const user = requireAuth(req);
+
// Check subscription status
+
const subscription = db
+
.query<{ status: string }, [number]>(
+
"SELECT status FROM subscriptions WHERE user_id = ? AND status IN ('active', 'trialing', 'past_due') ORDER BY created_at DESC LIMIT 1",
+
// Get notification preferences
+
.query<{ email_notifications_enabled: number }, [number]>(
+
"SELECT email_notifications_enabled FROM users WHERE id = ?",
+
created_at: user.created_at,
+
has_subscription: !!subscription,
+
email_verified: isEmailVerified(user.id),
+
email_notifications_enabled: prefs?.email_notifications_enabled === 1,
+
return handleError(err);
"/api/passkeys/register/options": {
···
+
const sessionId = getSessionFromRequest(req);
+
return Response.json({ error: "Not authenticated" }, { status: 401 });
+
const user = getUserBySession(sessionId);
+
return Response.json({ error: "Invalid session" }, { status: 401 });
+
const sessions = getUserSessionsForUser(user.id);
+
sessions: sessions.map((s) => ({
+
ip_address: s.ip_address,
+
user_agent: s.user_agent,
+
created_at: s.created_at,
+
expires_at: s.expires_at,
+
is_current: s.id === sessionId,
+
return handleError(err);
+
const currentSessionId = getSessionFromRequest(req);
+
if (!currentSessionId) {
+
return Response.json({ error: "Not authenticated" }, { status: 401 });
+
const user = getUserBySession(currentSessionId);
+
return Response.json({ error: "Invalid session" }, { status: 401 });
+
const rateLimitError = enforceRateLimit(req, "delete-session", {
+
ip: { max: 20, windowSeconds: 60 * 60 },
+
if (rateLimitError) return rateLimitError;
+
const body = await req.json();
+
const targetSessionId = body.sessionId;
+
if (!targetSessionId) {
+
{ error: "Session ID required" },
+
// Prevent deleting current session
+
if (targetSessionId === currentSessionId) {
+
{ error: "Cannot kill current session. Use logout instead." },
+
// Verify the session belongs to the user
+
const targetSession = getSession(targetSessionId);
+
if (!targetSession || targetSession.user_id !== user.id) {
+
return Response.json({ error: "Session not found" }, { status: 404 });
+
deleteSession(targetSessionId);
+
return Response.json({ success: true });
+
return handleError(err);
+
const user = requireAuth(req);
+
const rateLimitError = enforceRateLimit(req, "delete-user", {
+
ip: { max: 3, windowSeconds: 60 * 60 },
+
if (rateLimitError) return rateLimitError;
+
await deleteUser(user.id);
+
"session=; HttpOnly; Secure; Path=/; Max-Age=0; SameSite=Lax",
+
return handleError(err);
+
const user = requireAuth(req);
+
const rateLimitError = enforceRateLimit(req, "update-email", {
+
ip: { max: 5, windowSeconds: 60 * 60 },
+
if (rateLimitError) return rateLimitError;
+
const body = await req.json();
+
const { email } = body;
+
return Response.json({ error: "Email required" }, { status: 400 });
+
// Check if email is already in use
+
const existingUser = getUserByEmail(email);
+
{ error: "Email already in use" },
+
// Create email change token
+
const token = createEmailChangeToken(user.id, email);
+
// Send verification email to the CURRENT address
+
const origin = process.env.ORIGIN || "http://localhost:3000";
+
const verifyUrl = `${origin}/api/user/email/verify?token=${token}`;
+
subject: "Verify your email change",
+
html: emailChangeTemplate({
+
currentEmail: user.email,
+
message: `Verification email sent to ${user.email}`,
+
"[Email] Failed to send email change verification:",
+
{ error: "Failed to send verification email" },
+
return handleError(err);
···
+
const user = requireAuth(req);
+
const rateLimitError = enforceRateLimit(req, "update-password", {
+
ip: { max: 5, windowSeconds: 60 * 60 },
+
if (rateLimitError) return rateLimitError;
+
const body = await req.json();
+
const { password } = body;
+
return Response.json({ error: "Password required" }, { status: 400 });
+
// Validate password format (client-side hashed PBKDF2)
+
const passwordValidation = validatePasswordHash(password);
+
if (!passwordValidation.valid) {
+
{ error: passwordValidation.error },
+
await updateUserPassword(user.id, password);
+
return Response.json({ success: true });
+
{ error: "Failed to update password" },
+
return handleError(err);
+
const user = requireAuth(req);
+
const rateLimitError = enforceRateLimit(req, "update-name", {
+
ip: { max: 10, windowSeconds: 5 * 60 },
+
if (rateLimitError) return rateLimitError;
+
const body = await req.json();
+
return Response.json({ error: "Name required" }, { status: 400 });
+
updateUserName(user.id, name);
+
return Response.json({ success: true });
+
{ error: "Failed to update name" },
+
return handleError(err);
+
const user = requireAuth(req);
+
const rateLimitError = enforceRateLimit(req, "update-avatar", {
+
ip: { max: 10, windowSeconds: 5 * 60 },
+
if (rateLimitError) return rateLimitError;
+
const body = await req.json();
+
const { avatar } = body;
+
return Response.json({ error: "Avatar required" }, { status: 400 });
+
updateUserAvatar(user.id, avatar);
+
return Response.json({ success: true });
+
{ error: "Failed to update avatar" },
+
return handleError(err);
"/api/user/notifications": {
+
const user = requireAuth(req);
+
const rateLimitError = enforceRateLimit(req, "update-notifications", {
+
ip: { max: 10, windowSeconds: 5 * 60 },
+
if (rateLimitError) return rateLimitError;
+
const body = await req.json();
+
const { email_notifications_enabled } = body;
+
if (typeof email_notifications_enabled !== "boolean") {
+
{ error: "email_notifications_enabled must be a boolean" },
+
"UPDATE users SET email_notifications_enabled = ? WHERE id = ?",
+
[email_notifications_enabled ? 1 : 0, user.id],
+
return Response.json({ success: true });
+
{ error: "Failed to update notification settings" },
+
return handleError(err);
"/api/billing/checkout": {
+
const user = requireAuth(req);
const { polar } = await import("./lib/polar");
···
return Response.json({ url: checkout.url });
+
return handleError(err);
"/api/billing/subscription": {
+
const user = requireAuth(req);
// Get subscription from database
···
return Response.json({ subscription });
+
return handleError(err);
+
const user = requireAuth(req);
const { polar } = await import("./lib/polar");
// Get subscription to find customer ID
···
return Response.json({ url: session.customerPortalUrl });
+
return handleError(err);