Files
worldmonitor/api/eia/[[...path]].js
Elie Habib c353cf2070 Reduce egress costs, add PWA support, fix Polymarket and Railway relay
Egress optimization:
- Add s-maxage + stale-while-revalidate to all API endpoints for Vercel CDN caching
- Add vercel.json with immutable caching for hashed assets
- Add gzip compression to sidecar responses >1KB
- Add gzip to Railway RSS responses (4 paths previously uncompressed)
- Increase polling intervals: markets/crypto 60s→120s, ETF/macro/stablecoins 60s→180s
- Remove hardcoded Railway URL from theater-posture.js (now env-var only)

PWA / Service Worker:
- Add vite-plugin-pwa with autoUpdate strategy
- Cache map tiles (CacheFirst), fonts (StaleWhileRevalidate), static assets
- NetworkOnly for all /api/* routes (real-time data must be fresh)
- Manual SW registration (web only, skip Tauri)
- Add offline fallback page
- Replace manual manifest with plugin-generated manifest

Polymarket fix:
- Route dev proxy through production Vercel (bypasses JA3 blocking)
- Add 4th fallback tier: production URL as absolute fallback

Desktop/Sidecar:
- Dual-backend cache (_upstash-cache.js): Redis cloud + in-memory+file desktop
- Settings window OK/Cancel redesign
- Runtime config and secret injection improvements
2026-02-14 19:53:04 +04:00

136 lines
3.6 KiB
JavaScript

// EIA (Energy Information Administration) API proxy
// Keeps API key server-side
export const config = { runtime: 'edge' };
function getCorsOrigin(req) {
const origin = req.headers.get('origin') || '';
// Allow *.worldmonitor.app and localhost
if (
origin.endsWith('.worldmonitor.app') ||
origin === 'https://worldmonitor.app' ||
origin.startsWith('http://localhost:')
) {
return origin;
}
return 'https://worldmonitor.app';
}
export default async function handler(req) {
const corsOrigin = getCorsOrigin(req);
// Only allow GET and OPTIONS methods
if (req.method !== 'GET' && req.method !== 'OPTIONS') {
return Response.json({ error: 'Method not allowed' }, {
status: 405,
headers: { 'Access-Control-Allow-Origin': corsOrigin },
});
}
const url = new URL(req.url);
const path = url.pathname.replace('/api/eia', '');
const apiKey = process.env.EIA_API_KEY;
if (!apiKey) {
return Response.json({
configured: false,
skipped: true,
reason: 'EIA_API_KEY not configured',
}, {
status: 200,
headers: { 'Access-Control-Allow-Origin': corsOrigin },
});
}
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': corsOrigin,
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
});
}
// Health check
if (path === '/health' || path === '') {
return Response.json({ configured: true }, {
headers: { 'Access-Control-Allow-Origin': corsOrigin },
});
}
// Petroleum data endpoint
if (path === '/petroleum') {
try {
const series = {
wti: 'PET.RWTC.W',
brent: 'PET.RBRTE.W',
production: 'PET.WCRFPUS2.W',
inventory: 'PET.WCESTUS1.W',
};
const results = {};
// Fetch all series in parallel
const fetchPromises = Object.entries(series).map(async ([key, seriesId]) => {
try {
const response = await fetch(
`https://api.eia.gov/v2/seriesid/${seriesId}?api_key=${apiKey}&num=2`,
{ headers: { 'Accept': 'application/json' } }
);
if (!response.ok) return null;
const data = await response.json();
const values = data?.response?.data || [];
if (values.length >= 1) {
return {
key,
data: {
current: values[0]?.value,
previous: values[1]?.value || values[0]?.value,
date: values[0]?.period,
unit: values[0]?.unit,
}
};
}
} catch (e) {
console.error(`[EIA] Failed to fetch ${key}:`, e.message);
}
return null;
});
const fetchResults = await Promise.all(fetchPromises);
for (const result of fetchResults) {
if (result) {
results[result.key] = result.data;
}
}
return Response.json(results, {
headers: {
'Access-Control-Allow-Origin': corsOrigin,
'Cache-Control': 'public, max-age=1800, s-maxage=1800, stale-while-revalidate=300', // 30 min cache
},
});
} catch (error) {
console.error('[EIA] Fetch error:', error);
return Response.json({
error: 'Failed to fetch EIA data',
}, {
status: 500,
headers: { 'Access-Control-Allow-Origin': corsOrigin },
});
}
}
return Response.json({ error: 'Not found' }, {
status: 404,
headers: { 'Access-Control-Allow-Origin': corsOrigin },
});
}