mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
Audit and raise every cache/poll under 5 min to reduce upstream API pressure and Vercel function invocations across 31 files: Frontend polling: markets 4→8min, crypto 4→8min, predictions 5→10min, natural 5→1hr, cableHealth 5→2hr, oref 10s→2min, maritime 30s→5min, IntelligenceGapBadge 1→3min. Circuit breakers: PizzINT 2→30min, aviation 5→20min, seismology/weather/ outages/statuses/wildfires 5→30min, military-vessels/flights/GDACS/ maritime/polymarket/GDELT 5→10min, chokepoint 5→20min. Server Redis: market-quotes 2→8min, stablecoins 2→8min/5→10min, vessel-snapshot 10s→5min, earthquakes 5→30min, sector 5→10min, predictions/crypto/commodities 5→10min, outages/statuses 5→30min, macro-signals/chokepoints 5→15min, aviation-sim 5→15min. CDN edge: market RPCs fast→medium, infra/seismology fast→slow.
115 lines
3.1 KiB
TypeScript
115 lines
3.1 KiB
TypeScript
import { createCircuitBreaker } from '@/utils';
|
|
|
|
export interface GDACSEvent {
|
|
id: string;
|
|
eventType: 'EQ' | 'FL' | 'TC' | 'VO' | 'WF' | 'DR';
|
|
name: string;
|
|
description: string;
|
|
alertLevel: 'Green' | 'Orange' | 'Red';
|
|
country: string;
|
|
coordinates: [number, number];
|
|
fromDate: Date;
|
|
severity: string;
|
|
url: string;
|
|
}
|
|
|
|
interface GDACSFeature {
|
|
geometry: {
|
|
type: string;
|
|
coordinates: [number, number];
|
|
};
|
|
properties: {
|
|
eventtype: string;
|
|
eventid: number;
|
|
name: string;
|
|
description: string;
|
|
alertlevel: string;
|
|
country: string;
|
|
fromdate: string;
|
|
severitydata?: {
|
|
severity: number;
|
|
severitytext: string;
|
|
severityunit: string;
|
|
};
|
|
url: {
|
|
report: string;
|
|
};
|
|
};
|
|
}
|
|
|
|
interface GDACSResponse {
|
|
features: GDACSFeature[];
|
|
}
|
|
|
|
const GDACS_API = 'https://www.gdacs.org/gdacsapi/api/events/geteventlist/MAP';
|
|
const breaker = createCircuitBreaker<GDACSEvent[]>({ name: 'GDACS', cacheTtlMs: 10 * 60 * 1000, persistCache: true });
|
|
|
|
const EVENT_TYPE_NAMES: Record<string, string> = {
|
|
EQ: 'Earthquake',
|
|
FL: 'Flood',
|
|
TC: 'Tropical Cyclone',
|
|
VO: 'Volcano',
|
|
WF: 'Wildfire',
|
|
DR: 'Drought',
|
|
};
|
|
|
|
export async function fetchGDACSEvents(): Promise<GDACSEvent[]> {
|
|
return breaker.execute(async () => {
|
|
const response = await fetch(GDACS_API, {
|
|
headers: { 'Accept': 'application/json' }
|
|
});
|
|
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
|
|
const data: GDACSResponse = await response.json();
|
|
|
|
const seen = new Set<string>();
|
|
return data.features
|
|
.filter(f => {
|
|
if (!f.geometry || f.geometry.type !== 'Point') return false;
|
|
const key = `${f.properties.eventtype}-${f.properties.eventid}`;
|
|
if (seen.has(key)) return false;
|
|
seen.add(key);
|
|
return true;
|
|
})
|
|
.filter(f => f.properties.alertlevel !== 'Green')
|
|
.slice(0, 100)
|
|
.map(f => ({
|
|
id: `gdacs-${f.properties.eventtype}-${f.properties.eventid}`,
|
|
eventType: f.properties.eventtype as GDACSEvent['eventType'],
|
|
name: f.properties.name,
|
|
description: f.properties.description || EVENT_TYPE_NAMES[f.properties.eventtype] || f.properties.eventtype,
|
|
alertLevel: f.properties.alertlevel as GDACSEvent['alertLevel'],
|
|
country: f.properties.country,
|
|
coordinates: f.geometry.coordinates,
|
|
fromDate: new Date(f.properties.fromdate),
|
|
severity: f.properties.severitydata?.severitytext || '',
|
|
url: f.properties.url?.report || '',
|
|
}));
|
|
}, []);
|
|
}
|
|
|
|
export function getGDACSStatus(): string {
|
|
return breaker.getStatus();
|
|
}
|
|
|
|
export function getEventTypeIcon(type: GDACSEvent['eventType']): string {
|
|
switch (type) {
|
|
case 'EQ': return '🌍';
|
|
case 'FL': return '🌊';
|
|
case 'TC': return '🌀';
|
|
case 'VO': return '🌋';
|
|
case 'WF': return '🔥';
|
|
case 'DR': return '☀️';
|
|
default: return '⚠️';
|
|
}
|
|
}
|
|
|
|
export function getAlertColor(level: GDACSEvent['alertLevel']): [number, number, number, number] {
|
|
switch (level) {
|
|
case 'Red': return [255, 0, 0, 200];
|
|
case 'Orange': return [255, 140, 0, 180];
|
|
default: return [255, 200, 0, 160];
|
|
}
|
|
}
|