diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-06-22 13:21:03 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-06-22 13:21:03 +0200 |
| commit | faca97f1ae1ba870673347f98557191fcd5c123a (patch) | |
| tree | 4c245e85f07677bb8545dd4068bca1b156e853d6 /apps/web/src/app/api | |
| parent | ceb253f5853e5f8f813b970c09cc5edceb6f9727 (diff) | |
| download | opencut-faca97f1ae1ba870673347f98557191fcd5c123a.tar.gz | |
add upstash rate limiting
Diffstat (limited to 'apps/web/src/app/api')
| -rw-r--r-- | apps/web/src/app/api/waitlist/route.ts | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/apps/web/src/app/api/waitlist/route.ts b/apps/web/src/app/api/waitlist/route.ts new file mode 100644 index 00000000..e949ea65 --- /dev/null +++ b/apps/web/src/app/api/waitlist/route.ts @@ -0,0 +1,67 @@ +import { NextRequest, NextResponse } from "next/server";
+import { db } from "@/lib/db";
+import { waitlist } from "@/lib/db/schema";
+import { eq } from "drizzle-orm";
+import { nanoid } from "nanoid";
+import { waitlistRateLimit } from "@/lib/rate-limit";
+
+export async function POST(request: NextRequest) {
+ // Rate limit check
+ const identifier = request.headers.get("x-forwarded-for") ?? "127.0.0.1";
+ const { success } = await waitlistRateLimit.limit(identifier);
+
+ if (!success) {
+ return NextResponse.json(
+ { error: "Too many requests. Please try again later." },
+ { status: 429 }
+ );
+ }
+
+ try {
+ const { email } = await request.json();
+
+ if (!email || typeof email !== "string") {
+ return NextResponse.json({ error: "Email is required" }, { status: 400 });
+ }
+
+ // Validate email format
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(email)) {
+ return NextResponse.json(
+ { error: "Invalid email format" },
+ { status: 400 }
+ );
+ }
+
+ // Check if email already exists
+ const existingEmail = await db
+ .select()
+ .from(waitlist)
+ .where(eq(waitlist.email, email.toLowerCase()))
+ .limit(1);
+
+ if (existingEmail.length > 0) {
+ return NextResponse.json(
+ { error: "Email already registered" },
+ { status: 409 }
+ );
+ }
+
+ // Add to waitlist
+ await db.insert(waitlist).values({
+ id: nanoid(),
+ email: email.toLowerCase(),
+ });
+
+ return NextResponse.json(
+ { message: "Successfully joined waitlist!" },
+ { status: 201 }
+ );
+ } catch (error) {
+ console.error("Waitlist signup error:", error);
+ return NextResponse.json(
+ { error: "Internal server error" },
+ { status: 500 }
+ );
+ }
+}
|
