fix: harden degraded source handling
All checks were successful
Codex Template Compliance / template-compliance (pull_request) Successful in 7s
Build / test-and-image (pull_request) Successful in 53s

This commit is contained in:
2026-07-07 21:16:24 +02:00
parent cd19c857f3
commit 62d9c680b7
10 changed files with 199 additions and 33 deletions

View File

@@ -10,11 +10,13 @@ const BASE = 'https://api.gdeltproject.org/api/v2';
// Search recent global events/articles by keyword
export async function searchEvents(query = '', opts = {}) {
const {
mode = 'ArtList', // ArtList, TimelineVol, TimelineVolInfo, TimelineTone, TimelineLang, TimelineSourceCountry
mode = 'artlist',
maxRecords = 75,
timespan = '24h', // e.g. "24h", "7d", "3m"
format = 'json',
sortBy = 'DateDesc', // DateDesc, DateAsc, ToneDesc, ToneAsc
sortBy = 'datedesc',
timeout = 12000,
retries = 0,
} = opts;
// If no query, use broad geopolitical terms
@@ -28,7 +30,7 @@ export async function searchEvents(query = '', opts = {}) {
sort: sortBy,
});
return safeFetch(`${BASE}/doc/doc?${params}`);
return safeFetch(`${BASE}/doc/doc?${params}`, { timeout, retries, source: 'GDELT' });
}
// Get tone/sentiment timeline for a topic
@@ -60,6 +62,8 @@ export async function geoEvents(query = '', opts = {}) {
timespan = '24h',
format = 'GeoJSON',
maxPoints = 500,
timeout = 8000,
retries = 0,
} = opts;
const q = query || 'conflict OR military OR protest OR explosion';
@@ -71,7 +75,7 @@ export async function geoEvents(query = '', opts = {}) {
maxpoints: String(maxPoints),
});
return safeFetch(`${BASE}/geo/geo?${params}`);
return safeFetch(`${BASE}/geo/geo?${params}`, { timeout, retries, source: 'GDELT' });
}
// Compact article for briefing
@@ -94,7 +98,7 @@ export async function briefing() {
// Single broad query to stay within rate limits
const all = await searchEvents(
'conflict OR military OR economy OR crisis OR war OR sanctions OR tariff OR strike OR outbreak',
{ maxRecords: 50, timespan: '24h' }
{ maxRecords: 50, timespan: '24h', timeout: 12000, retries: 0 }
);
const articles = (all?.articles || []).map(compactArticle);
@@ -108,7 +112,7 @@ export async function briefing() {
await delay(5500);
let geoPoints = [];
try {
const geo = await geoEvents('conflict OR military OR protest OR crisis', { maxPoints: 30, timespan: '24h' });
const geo = await geoEvents('conflict OR military OR protest OR crisis', { maxPoints: 30, timespan: '24h', timeout: 8000, retries: 0 });
geoPoints = (geo?.features || []).filter(f => f.geometry?.coordinates).map(f => ({
lat: f.geometry.coordinates[1],
lon: f.geometry.coordinates[0],