Skip to content

Commit f8ba179

Browse files
committed
Fix previousSpec property name and lazy rate limiting
- Fix property name mismatch: playground now passes previousSpec instead of previousTree to match what useUIStream hook expects - Make rate limiting lazy-initialized to avoid runtime errors when Redis env vars (KV_REST_API_URL, KV_REST_API_TOKEN) are not set - Rate limiting gracefully becomes a no-op when Redis is unavailable
1 parent e3f3ef9 commit f8ba179

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

apps/web/app/api/generate/route.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,19 @@ export async function POST(req: Request) {
4444
}
4545

4646
const { prompt, context } = await req.json();
47-
const previousTree = context?.previousTree;
47+
const previousSpec = context?.previousSpec;
4848

4949
const sanitizedPrompt = String(prompt || "").slice(0, MAX_PROMPT_LENGTH);
5050

5151
// Build the user prompt, including previous tree for iteration
5252
let userPrompt = sanitizedPrompt;
5353
if (
54-
previousTree &&
55-
previousTree.root &&
56-
Object.keys(previousTree.elements || {}).length > 0
54+
previousSpec &&
55+
previousSpec.root &&
56+
Object.keys(previousSpec.elements || {}).length > 0
5757
) {
5858
userPrompt = `CURRENT UI STATE (already loaded, DO NOT recreate existing elements):
59-
${JSON.stringify(previousTree, null, 2)}
59+
${JSON.stringify(previousSpec, null, 2)}
6060
6161
USER REQUEST: ${sanitizedPrompt}
6262

apps/web/components/playground.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function Playground() {
5050
// Track the currently generating version ID
5151
const generatingVersionIdRef = useRef<string | null>(null);
5252

53-
// Track the current tree for use as previousTree in next generation
53+
// Track the current tree for use as previousSpec in next generation
5454
const currentTreeRef = useRef<Spec | null>(null);
5555

5656
const {
@@ -163,7 +163,7 @@ export function Playground() {
163163
setStreamLines([]); // Reset stream lines for new generation
164164

165165
// Pass the current tree as context so the API can iterate on it
166-
await send(inputValue.trim(), { previousTree: currentTreeRef.current });
166+
await send(inputValue.trim(), { previousSpec: currentTreeRef.current });
167167
}, [inputValue, isStreaming, send]);
168168

169169
const handleKeyDown = useCallback(

apps/web/lib/rate-limit.ts

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,54 @@
11
import { Ratelimit } from "@upstash/ratelimit";
22
import { Redis } from "@upstash/redis";
33

4-
const redis = new Redis({
5-
url: process.env.KV_REST_API_URL!,
6-
token: process.env.KV_REST_API_TOKEN!,
7-
});
4+
// Lazy initialization to avoid errors when Redis env vars are not configured
5+
let _minuteRateLimit: Ratelimit | null = null;
6+
let _dailyRateLimit: Ratelimit | null = null;
7+
8+
function getRedis(): Redis | null {
9+
const url = process.env.KV_REST_API_URL;
10+
const token = process.env.KV_REST_API_TOKEN;
11+
12+
if (!url || !token) {
13+
return null;
14+
}
15+
16+
return new Redis({ url, token });
17+
}
18+
19+
// No-op rate limiter for when Redis is not configured
20+
const noopRateLimiter = {
21+
limit: async () => ({ success: true, limit: 0, remaining: 0, reset: 0 }),
22+
};
823

924
// 10 requests per minute (sliding window)
10-
export const minuteRateLimit = new Ratelimit({
11-
redis,
12-
limiter: Ratelimit.slidingWindow(10, "1 m"),
13-
prefix: "ratelimit:minute",
14-
});
25+
export const minuteRateLimit = {
26+
limit: async (identifier: string) => {
27+
if (!_minuteRateLimit) {
28+
const redis = getRedis();
29+
if (!redis) return noopRateLimiter.limit();
30+
_minuteRateLimit = new Ratelimit({
31+
redis,
32+
limiter: Ratelimit.slidingWindow(10, "1 m"),
33+
prefix: "ratelimit:minute",
34+
});
35+
}
36+
return _minuteRateLimit.limit(identifier);
37+
},
38+
};
1539

1640
// 100 requests per day (fixed window)
17-
export const dailyRateLimit = new Ratelimit({
18-
redis,
19-
limiter: Ratelimit.fixedWindow(100, "1 d"),
20-
prefix: "ratelimit:daily",
21-
});
41+
export const dailyRateLimit = {
42+
limit: async (identifier: string) => {
43+
if (!_dailyRateLimit) {
44+
const redis = getRedis();
45+
if (!redis) return noopRateLimiter.limit();
46+
_dailyRateLimit = new Ratelimit({
47+
redis,
48+
limiter: Ratelimit.fixedWindow(100, "1 d"),
49+
prefix: "ratelimit:daily",
50+
});
51+
}
52+
return _dailyRateLimit.limit(identifier);
53+
},
54+
};

0 commit comments

Comments
 (0)