Skip to content

Commit 8b63261

Browse files
[fix] Store page SSG fix (#313)
1 parent b8871ce commit 8b63261

File tree

6 files changed

+224
-186
lines changed

6 files changed

+224
-186
lines changed

web/src/app/api/agents/route.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import { unstable_cache } from 'next/cache'
66

77
import { logger } from '@/util/logger'
88

9-
// Enable static generation for API route
9+
// ISR Configuration for API route
1010
export const revalidate = 600 // Cache for 10 minutes
11-
export const dynamic = 'force-static' // Force static generation
12-
export const fetchCache = 'force-cache' // Use cached data when possible
11+
export const dynamic = 'force-static'
1312

1413
// Cached function for expensive agent aggregations
1514
const getCachedAgents = unstable_cache(
@@ -253,8 +252,8 @@ const getCachedAgents = unstable_cache(
253252
},
254253
['agents-data'],
255254
{
256-
revalidate,
257-
tags: ['agents'],
255+
revalidate: 600, // 10 minutes
256+
tags: ['agents', 'api'],
258257
}
259258
)
260259

web/src/app/store/agents-data.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { unstable_cache } from 'next/cache'
2+
3+
// Types
4+
interface AgentData {
5+
id: string
6+
name: string
7+
description?: string
8+
publisher: {
9+
id: string
10+
name: string
11+
verified: boolean
12+
avatar_url?: string | null
13+
}
14+
version: string
15+
created_at: string
16+
usage_count?: number
17+
weekly_spent?: number
18+
total_spent?: number
19+
avg_cost_per_invocation?: number
20+
unique_users?: number
21+
last_used?: string
22+
version_stats?: Record<string, any>
23+
tags?: string[]
24+
}
25+
26+
// Server-side data fetching function with ISR
27+
export const getAgentsData = unstable_cache(
28+
async (): Promise<AgentData[]> => {
29+
const baseUrl =
30+
process.env.NEXT_PUBLIC_CODEBUFF_APP_URL || 'http://localhost:3000'
31+
32+
try {
33+
const response = await fetch(`${baseUrl}/api/agents`, {
34+
headers: {
35+
'User-Agent': 'Codebuff-Store-Static',
36+
},
37+
// Configure fetch-level caching
38+
next: {
39+
revalidate: 600, // 10 minutes
40+
tags: ['agents', 'store'],
41+
},
42+
})
43+
44+
if (!response.ok) {
45+
console.error(
46+
'Failed to fetch agents:',
47+
response.status,
48+
response.statusText
49+
)
50+
return []
51+
}
52+
53+
return await response.json()
54+
} catch (error) {
55+
console.error('Error fetching agents data:', error)
56+
return []
57+
}
58+
},
59+
['store-agents-data'],
60+
{
61+
revalidate: 600, // Cache for 10 minutes
62+
tags: ['agents', 'store'],
63+
}
64+
)
65+
66+
// Helper function for on-demand revalidation (can be used in webhooks/admin actions)
67+
export async function revalidateAgentsData() {
68+
const { revalidateTag } = await import('next/cache')
69+
revalidateTag('agents')
70+
revalidateTag('store')
71+
}

web/src/app/store/page.tsx

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Metadata } from 'next'
2-
import { unstable_cache } from 'next/cache'
2+
import { Suspense } from 'react'
33
import AgentStoreClient from './store-client'
4+
import { getAgentsData } from './agents-data'
45

56
// Types
67
interface AgentData {
@@ -42,35 +43,6 @@ interface PublisherProfileResponse {
4243
avatar_url?: string | null
4344
}
4445

45-
// Cache the agents data with 60 second revalidation
46-
const getCachedAgentsData = unstable_cache(
47-
async (): Promise<AgentData[]> => {
48-
const baseUrl =
49-
process.env.NEXT_PUBLIC_CODEBUFF_APP_URL || 'http://localhost:3000'
50-
const response = await fetch(`${baseUrl}/api/agents`, {
51-
headers: {
52-
'User-Agent': 'Codebuff-Store-Static',
53-
},
54-
})
55-
56-
if (!response.ok) {
57-
console.error(
58-
'Failed to fetch agents:',
59-
response.status,
60-
response.statusText
61-
)
62-
return []
63-
}
64-
65-
return await response.json()
66-
},
67-
['store-agents-data'],
68-
{
69-
revalidate: 60, // Revalidate every 60 seconds
70-
tags: ['agents', 'store'],
71-
}
72-
)
73-
7446
export const metadata: Metadata = {
7547
title: 'Agent Store | Codebuff',
7648
description: 'Browse all published AI agents. Run, compose, or fork them.',
@@ -81,18 +53,22 @@ export const metadata: Metadata = {
8153
},
8254
}
8355

84-
// Enable static site generation with ISR
85-
export const revalidate = 60 * 10 // Revalidate every 10 minutes
56+
// ISR Configuration - revalidate every 10 minutes
57+
export const revalidate = 600
8658
export const dynamic = 'force-static'
87-
export const fetchCache = 'force-cache'
8859

8960
interface StorePageProps {
9061
searchParams: { [key: string]: string | string[] | undefined }
9162
}
9263

93-
export default async function StorePage({ searchParams }: StorePageProps) {
94-
// Fetch agents data at build time
95-
const agentsData = await getCachedAgentsData()
64+
// Server Component for fetching and rendering agents data
65+
async function AgentsDataProvider({
66+
searchParams,
67+
}: {
68+
searchParams: StorePageProps['searchParams']
69+
}) {
70+
// Fetch agents data with ISR
71+
const agentsData = await getAgentsData()
9672

9773
// For static generation, we don't pass session data
9874
// The client will handle authentication state
@@ -107,3 +83,36 @@ export default async function StorePage({ searchParams }: StorePageProps) {
10783
/>
10884
)
10985
}
86+
87+
// Loading component for better UX
88+
function AgentsLoading() {
89+
return (
90+
<div className="container mx-auto py-8 px-4">
91+
<div className="max-w-7xl mx-auto">
92+
<div className="mb-12">
93+
<h1 className="text-4xl font-bold text-white mb-2">Agent Store</h1>
94+
<p className="text-xl text-muted-foreground">
95+
Browse all published AI agents. Run, compose, or fork them.
96+
</p>
97+
</div>
98+
99+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
100+
{Array.from({ length: 6 }).map((_, i) => (
101+
<div
102+
key={i}
103+
className="h-[220px] bg-card/50 border rounded-lg animate-pulse"
104+
/>
105+
))}
106+
</div>
107+
</div>
108+
</div>
109+
)
110+
}
111+
112+
export default async function StorePage({ searchParams }: StorePageProps) {
113+
return (
114+
<Suspense fallback={<AgentsLoading />}>
115+
<AgentsDataProvider searchParams={searchParams} />
116+
</Suspense>
117+
)
118+
}

web/src/components/navbar/client-auth-nav.tsx

Lines changed: 0 additions & 96 deletions
This file was deleted.

0 commit comments

Comments
 (0)