forked from Stellar-split/split-app
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathroute.ts
More file actions
59 lines (50 loc) · 2.01 KB
/
Copy pathroute.ts
File metadata and controls
59 lines (50 loc) · 2.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { NextResponse } from "next/server";
/**
* Fiat currencies the UI can display. Keep in sync with FIAT_CURRENCIES in
* UserPreferencesContext. Not exported — Next.js route modules may only export
* route config fields and HTTP method handlers.
*/
const SUPPORTED_CURRENCIES = ["usd", "eur", "gbp", "brl"] as const;
/**
* CoinGecko coin id for the asset invoices are denominated in.
*
* StellarSplit invoices are denominated in USDC (`usd-coin`), not XLM — pointing
* this at `stellar` would render a fiat line that does not match the amount
* beside it. Override per-deployment if that ever changes.
*/
const COIN_ID = process.env.NEXT_PUBLIC_RATE_COIN_ID ?? "usd-coin";
const COINGECKO_URL =
`https://api.coingecko.com/api/v3/simple/price` +
`?ids=${encodeURIComponent(COIN_ID)}&vs_currencies=${SUPPORTED_CURRENCIES.join(",")}`;
// Rates are refetched by clients every 60s; cache server-side for the same
// window so a burst of clients does not hammer CoinGecko's free tier.
export const revalidate = 60;
export async function GET() {
try {
const upstream = await fetch(COINGECKO_URL, {
headers: { accept: "application/json" },
next: { revalidate },
});
if (!upstream.ok) {
return NextResponse.json(
{ error: `Rate provider responded ${upstream.status}` },
{ status: 502 }
);
}
const data = (await upstream.json()) as Record<string, Record<string, number>>;
const rates = data[COIN_ID];
if (!rates || typeof rates.usd !== "number") {
return NextResponse.json(
{ error: "Rate provider returned an unexpected payload" },
{ status: 502 }
);
}
return NextResponse.json(
{ coin: COIN_ID, rates, fetchedAt: Date.now() },
{ headers: { "Cache-Control": "public, max-age=60, stale-while-revalidate=120" } }
);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
return NextResponse.json({ error: `Rate provider unreachable: ${message}` }, { status: 502 });
}
}