3 comics per week

This commit is contained in:
Riccardo Giorato
2026-01-29 16:55:54 +01:00
parent 6ed91fffec
commit 7ad2e1b9b7
4 changed files with 12 additions and 37 deletions
+8 -33
View File
@@ -1,9 +1,6 @@
import { type NextRequest, NextResponse } from "next/server"; import { type NextRequest, NextResponse } from "next/server";
import { auth } from "@clerk/nextjs/server"; import { auth } from "@clerk/nextjs/server";
import { freeTierRateLimit } from "@/lib/rate-limit"; import { freeTierRateLimit } from "@/lib/rate-limit";
import { db } from "@/lib/db";
import { stories } from "@/lib/schema";
import { gte } from "drizzle-orm";
export async function POST(request: NextRequest) { export async function POST(request: NextRequest) {
try { try {
@@ -27,36 +24,14 @@ export async function POST(request: NextRequest) {
}); });
} }
// For free tier, check rate limit status // For free tier, check rate limit status via Redis
try { const limitResult = await freeTierRateLimit.getRemaining(userId);
// Try to check remaining without consuming
const limitResult = await freeTierRateLimit.getRemaining(userId);
return NextResponse.json({ return NextResponse.json({
hasApiKey: false, hasApiKey: false,
creditsRemaining: limitResult.remaining, creditsRemaining: limitResult.remaining,
resetTime: limitResult.reset, resetTime: limitResult.reset,
}); });
} catch (error) {
console.error("Rate limit check error:", error);
// Fallback to database check
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
const recentStories = await db
.select()
.from(stories)
.where(gte(stories.createdAt, sevenDaysAgo))
.limit(1);
const hasUsedCredit = recentStories.length > 0;
return NextResponse.json({
hasApiKey: false,
creditsRemaining: hasUsedCredit ? 0 : 1,
resetTime: hasUsedCredit ? sevenDaysAgo.getTime() + 7 * 24 * 60 * 60 * 1000 : null,
});
}
} catch (error) { } catch (error) {
console.error("Error in check-credits API:", error); console.error("Error in check-credits API:", error);
return NextResponse.json( return NextResponse.json(
@@ -68,4 +43,4 @@ export async function POST(request: NextRequest) {
{ status: 500 } { status: 500 }
); );
} }
} }
@@ -204,7 +204,7 @@ export function StoryEditorClient() {
setShowApiModal(true); setShowApiModal(true);
toast({ toast({
title: "No credits remaining", title: "No credits remaining",
description: "You get 1 credit weekly. Add an API key for unlimited generation.", description: "You get 3 credits weekly. Add an API key for unlimited generation.",
variant: "destructive", variant: "destructive",
}); });
} }
+1 -1
View File
@@ -73,7 +73,7 @@ export function ApiKeyModal({ isOpen, onClose, onSubmit }: ApiKeyModalProps) {
<DialogDescription className="text-center text-muted-foreground"> <DialogDescription className="text-center text-muted-foreground">
{existingKey {existingKey
? "Update your Together API key or add a new one. You can also delete your existing key." ? "Update your Together API key or add a new one. You can also delete your existing key."
: "You've used your weekly credit! Add your Together API key for unlimited generation."} : "You've used all your weekly credits! Add your Together API key for unlimited generation."}
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
+2 -2
View File
@@ -6,10 +6,10 @@ const redis = new Redis({
token: process.env.UPSTASH_REDIS_REST_TOKEN!, token: process.env.UPSTASH_REDIS_REST_TOKEN!,
}) })
// Free tier: 1 comic per week (fixed window) // Free tier: 3 comics per week (fixed window)
export const freeTierRateLimit = new Ratelimit({ export const freeTierRateLimit = new Ratelimit({
redis, redis,
limiter: Ratelimit.fixedWindow(1, "7 d"), limiter: Ratelimit.fixedWindow(3, "7 d"),
analytics: true, analytics: true,
prefix: "ratelimit:free-comics", prefix: "ratelimit:free-comics",
}) })