SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%

web: /data rendered on demand with a 1 h runtime cache (build-time prerender exceeded 240 s); worker: min ask only from the representative variant

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 13 days ago (Sep 11, 2026) parent 38928e5

2 changed files +7 −3

modified apps/web/src/app/data/page.tsx +6 −2
@@ -1,4 +1,5 @@
1 1 import type { Metadata } from 'next';
2 +import { unstable_cache } from 'next/cache';
2 3
3 4 import Link from 'next/link';
4 5 import { readFile } from 'node:fs/promises';
@@ -13,7 +14,10 @@ import { catName, humanize } from '@/lib/taxonomy';
13 14
14 15 export const metadata: Metadata = { title: 'Data & methodology', description: 'Coverage by category, source and connector; RareIndex methodology; exports and API access.' };
15 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 22 async function loadMethodology(): Promise<string> {
19 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,7 +53,7 @@ function inline(s: string): string {
49 53 }
50 54
51 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 57 const active = rows.filter((r) => r.counts.assets > 0);
54 58 return (
55 59 <div>
modified workers/valuation/run.ts +1 −1
@@ -231,7 +231,7 @@ export async function valueAsset(assetId: string, opts: { now?: Date; rebuildHis
231 231 volume30dUsd: sales30d ? validSales.filter((s) => now.getTime() - s.saleDate.getTime() <= 30 * DAY).reduce((a, s) => a + Number(s.priceUsd), 0) : null,
232 232 activeListings: activeAll.count,
233 233 // lowest ask of the representative variant (comparable to the headline RIV); all variants otherwise
234 − minAskUsd: repActive?.minAsk ?? activeAll.minAsk,
234 + minAskUsd: repActive?.minAsk ?? (rep ? null : activeAll.minAsk), // never a graded slab's ask next to a raw RIV
235 235 observationsCount: obsCount?.n ?? 0,
236 236 sourcesCount,
237 237 liquidityScore: liq,
238 238