| |
| |
| |
| |
| |
| |
| |
| import { CHROME_UA } from './constants'; |
| import { cachedFetchJson } from './redis'; |
| import { getAcledAccessToken } from './acled-auth'; |
|
|
| const ACLED_API_URL = 'https://acleddata.com/api/acled/read'; |
| const ACLED_CACHE_TTL = 900; |
| const ACLED_TIMEOUT_MS = 15_000; |
|
|
| export interface AcledRawEvent { |
| event_id_cnty?: string; |
| event_type?: string; |
| sub_event_type?: string; |
| country?: string; |
| location?: string; |
| latitude?: string; |
| longitude?: string; |
| event_date?: string; |
| fatalities?: string; |
| source?: string; |
| actor1?: string; |
| actor2?: string; |
| admin1?: string; |
| notes?: string; |
| tags?: string; |
| } |
|
|
| interface FetchAcledOptions { |
| eventTypes: string; |
| startDate: string; |
| endDate: string; |
| country?: string; |
| limit?: number; |
| } |
|
|
| |
| |
| |
| |
| |
| export async function fetchAcledCached(opts: FetchAcledOptions): Promise<AcledRawEvent[]> { |
| const token = await getAcledAccessToken(); |
| if (!token) return []; |
|
|
| const cacheKey = `acled:shared:${opts.eventTypes}:${opts.startDate}:${opts.endDate}:${opts.country || 'all'}:${opts.limit || 500}`; |
| const result = await cachedFetchJson<AcledRawEvent[]>(cacheKey, ACLED_CACHE_TTL, async () => { |
| const params = new URLSearchParams({ |
| event_type: opts.eventTypes, |
| event_date: `${opts.startDate}|${opts.endDate}`, |
| event_date_where: 'BETWEEN', |
| limit: String(opts.limit || 500), |
| _format: 'json', |
| }); |
| if (opts.country) params.set('country', opts.country); |
|
|
| const resp = await fetch(`${ACLED_API_URL}?${params}`, { |
| headers: { |
| Accept: 'application/json', |
| Authorization: `Bearer ${token}`, |
| 'User-Agent': CHROME_UA, |
| }, |
| signal: AbortSignal.timeout(ACLED_TIMEOUT_MS), |
| }); |
|
|
| if (!resp.ok) throw new Error(`ACLED API error: ${resp.status}`); |
| const data = (await resp.json()) as { data?: AcledRawEvent[]; message?: string; error?: string }; |
| if (data.message || data.error) throw new Error(data.message || data.error || 'ACLED API error'); |
|
|
| const events = data.data || []; |
| return events.length > 0 ? events : null; |
| }); |
| return result || []; |
| } |
|
|