fix: add Resend for password reset emails + install F1-F2 deps
- Wire Resend to /api/auth/reset-request with fallback for dev - Install: sharp, recharts, next-pwa, resend, @react-pdf/renderer, @types/sharp Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
c459b4411a
commit
c787caa821
3 changed files with 4902 additions and 14 deletions
|
|
@ -11,6 +11,7 @@
|
|||
"@auth/drizzle-adapter": "^1.11.2",
|
||||
"@aws-sdk/client-s3": "^3.1045.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.1045.0",
|
||||
"@react-pdf/renderer": "^4.5.1",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"chart.js": "^4.5.1",
|
||||
"date-fns": "^4.1.0",
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
"nanoid": "^5.1.11",
|
||||
"next": "16.2.6",
|
||||
"next-auth": "5.0.0-beta.31",
|
||||
"next-pwa": "^5.6.0",
|
||||
"nodemailer": "^7.0.13",
|
||||
"openai": "^6.37.0",
|
||||
"postgres": "^3.4.9",
|
||||
|
|
@ -26,6 +28,9 @@
|
|||
"react": "19.2.4",
|
||||
"react-chartjs-2": "^5.3.1",
|
||||
"react-dom": "19.2.4",
|
||||
"recharts": "^3.8.1",
|
||||
"resend": "^6.12.3",
|
||||
"sharp": "^0.34.5",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -34,6 +39,7 @@
|
|||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/sharp": "^0.32.0",
|
||||
"drizzle-kit": "^0.31.10",
|
||||
"tailwindcss": "^4",
|
||||
"tsx": "^4.21.0",
|
||||
|
|
|
|||
4875
pnpm-lock.yaml
generated
4875
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -2,6 +2,11 @@ import { NextResponse } from "next/server";
|
|||
import { sql } from "@/db";
|
||||
import { rateLimit, getClientIp, getRateLimitKey } from "@/lib/rate-limit";
|
||||
import { randomBytes } from "crypto";
|
||||
import { Resend } from "resend";
|
||||
|
||||
const RESEND_API_KEY = process.env.RESEND_API_KEY;
|
||||
const EMAIL_FROM = process.env.EMAIL_FROM || "Tia <noreply@tia.manohargupta.com>";
|
||||
const RESET_URL = process.env.NEXT_PUBLIC_APP_URL || "https://tia.manohargupta.com";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const ip = getClientIp(request);
|
||||
|
|
@ -36,8 +41,34 @@ export async function POST(request: Request) {
|
|||
[user.id, token, expiresAt.toISOString()]
|
||||
);
|
||||
|
||||
// In production, send email with reset link
|
||||
console.log(`[RESET-TOKEN] user=${user.id} email=${email} token=reset_${token} expires=${expiresAt.toISOString()}`);
|
||||
const resetLink = `${RESET_URL}/reset-password?token=${token}`;
|
||||
|
||||
// Send email via Resend if API key is configured
|
||||
if (RESEND_API_KEY) {
|
||||
try {
|
||||
const resend = new Resend(RESEND_API_KEY);
|
||||
await resend.emails.send({
|
||||
from: EMAIL_FROM,
|
||||
to: email,
|
||||
subject: "Reset your Tia password",
|
||||
html: `
|
||||
<div style="font-family: system-ui, sans-serif; max-width: 500px; margin: 0 auto;">
|
||||
<h2>Reset your Tia password</h2>
|
||||
<p>Click the button below to reset your password. This link expires in 1 hour.</p>
|
||||
<a href="${resetLink}" style="display: inline-block; background: #2563eb; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; margin: 16px 0;">Reset Password</a>
|
||||
<p style="color: #6b7280; font-size: 14px;">If you didn't request this, you can safely ignore this email.</p>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
console.log(`[RESET-EMAIL-SENT] user=${user.id} email=${email}`);
|
||||
} catch (emailError) {
|
||||
console.error("[RESET-EMAIL-FAILED]", emailError);
|
||||
}
|
||||
} else {
|
||||
// Development fallback
|
||||
console.log(`[RESET-TOKEN] user=${user.id} email=${email} token=reset_${token} expires=${expiresAt.toISOString()}`);
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: "If email exists, reset link sent" });
|
||||
} catch (error) {
|
||||
console.error("Reset request error:", error);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue