| 1 | import type { Metadata } from 'next'; |
1 | import type { Metadata } from 'next'; |
| |
2 | +import { unstable_cache } from 'next/cache'; |
| 2 | |
3 | |
| 3 | import Link from 'next/link'; |
4 | import Link from 'next/link'; |
| 4 | import { readFile } from 'node:fs/promises'; |
5 | import { readFile } from 'node:fs/promises'; |
| 13 | |
14 | |
| 14 | export const metadata: Metadata = { title: 'Data & methodology', description: 'Coverage by category, source and connector; RareIndex methodology; exports and API access.' }; |
15 | export const metadata: Metadata = { title: 'Data & methodology', description: 'Coverage by category, source and connector; RareIndex methodology; exports and API access.' }; |
| 15 | // Coverage aggregates over millions of rows take ~70 s: prerender at build (staticPageGenerationTimeout raised), then hourly ISR. |
16 | // Coverage aggregates over millions of rows take ~70 s: prerender at build (staticPageGenerationTimeout raised), then hourly ISR. |
| 16 | −export const revalidate = 3600; |
17 | +// Rendered on demand and cached for an hour at runtime: the coverage aggregates run over millions of |
| |
18 | +// rows and exceeded the 240 s prerender budget at build time, which broke deployments. |
| |
19 | +export const dynamic = 'force-dynamic'; |
| |
20 | +const loadDataPage = unstable_cache(async () => Promise.all([getSiteStats(), getConnectorCoverage(), getFxCoverage(), getMarketRows()]), ['data-page-v1'], { revalidate: 3600 }); |
| 17 | |
21 | |
| 18 | async function loadMethodology(): Promise<string> { |
22 | async function loadMethodology(): Promise<string> { |
| 19 | const candidates = [path.resolve(process.cwd(), '../../docs/METHODOLOGY.md'), path.resolve(process.cwd(), 'docs/METHODOLOGY.md'), path.resolve(process.cwd(), '../docs/METHODOLOGY.md')]; |
23 | const candidates = [path.resolve(process.cwd(), '../../docs/METHODOLOGY.md'), path.resolve(process.cwd(), 'docs/METHODOLOGY.md'), path.resolve(process.cwd(), '../docs/METHODOLOGY.md')]; |
| 49 | } |
53 | } |
| 50 | |
54 | |
| 51 | export default async function DataPage() { |
55 | export default async function DataPage() { |
| 52 | − const [stats, connectors, fx, rows, md] = await Promise.all([getSiteStats(), getConnectorCoverage(), getFxCoverage(), getMarketRows(), loadMethodology()]); |
56 | + const [[stats, connectors, fx, rows], md] = await Promise.all([loadDataPage(), loadMethodology()]); |
| 53 | const active = rows.filter((r) => r.counts.assets > 0); |
57 | const active = rows.filter((r) => r.counts.assets > 0); |
| 54 | return ( |
58 | return ( |
| 55 | <div> |
59 | <div> |