mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
Akamai CDN blocks both Vercel and Railway IPs, making the feed unreachable from any cloud infrastructure. Guardian already provides UK news coverage.
123 lines
3.4 KiB
JavaScript
123 lines
3.4 KiB
JavaScript
export const config = { runtime: 'edge' };
|
|
|
|
// Fetch with timeout
|
|
async function fetchWithTimeout(url, options, timeoutMs = 15000) {
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
try {
|
|
const response = await fetch(url, { ...options, signal: controller.signal });
|
|
return response;
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|
|
|
|
// Allowed RSS feed domains for security
|
|
const ALLOWED_DOMAINS = [
|
|
'feeds.bbci.co.uk',
|
|
'www.theguardian.com',
|
|
'feeds.npr.org',
|
|
'news.google.com',
|
|
'www.aljazeera.com',
|
|
'rss.cnn.com',
|
|
'hnrss.org',
|
|
'feeds.arstechnica.com',
|
|
'www.theverge.com',
|
|
'www.cnbc.com',
|
|
'feeds.marketwatch.com',
|
|
'www.defenseone.com',
|
|
'breakingdefense.com',
|
|
'www.bellingcat.com',
|
|
'techcrunch.com',
|
|
'huggingface.co',
|
|
'www.technologyreview.com',
|
|
'rss.arxiv.org',
|
|
'export.arxiv.org',
|
|
'www.federalreserve.gov',
|
|
'www.sec.gov',
|
|
'www.whitehouse.gov',
|
|
'www.state.gov',
|
|
'www.defense.gov',
|
|
'home.treasury.gov',
|
|
'www.justice.gov',
|
|
'tools.cdc.gov',
|
|
'www.fema.gov',
|
|
'www.dhs.gov',
|
|
'www.thedrive.com',
|
|
'krebsonsecurity.com',
|
|
'finance.yahoo.com',
|
|
'thediplomat.com',
|
|
'venturebeat.com',
|
|
'foreignpolicy.com',
|
|
'www.ft.com',
|
|
'openai.com',
|
|
'www.reutersagency.com',
|
|
'feeds.reuters.com',
|
|
'rsshub.app',
|
|
'www.cfr.org',
|
|
'www.csis.org',
|
|
'www.politico.com',
|
|
'www.brookings.edu',
|
|
'layoffs.fyi',
|
|
'www.defensenews.com',
|
|
'www.foreignaffairs.com',
|
|
'www.atlanticcouncil.org',
|
|
];
|
|
|
|
export default async function handler(req) {
|
|
const requestUrl = new URL(req.url);
|
|
const feedUrl = requestUrl.searchParams.get('url');
|
|
|
|
if (!feedUrl) {
|
|
return new Response(JSON.stringify({ error: 'Missing url parameter' }), {
|
|
status: 400,
|
|
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
|
|
});
|
|
}
|
|
|
|
try {
|
|
const parsedUrl = new URL(feedUrl);
|
|
|
|
// Security: Check if domain is allowed
|
|
if (!ALLOWED_DOMAINS.includes(parsedUrl.hostname)) {
|
|
return new Response(JSON.stringify({ error: 'Domain not allowed' }), {
|
|
status: 403,
|
|
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
|
|
});
|
|
}
|
|
|
|
// Google News is slow - use longer timeout
|
|
const isGoogleNews = feedUrl.includes('news.google.com');
|
|
const timeout = isGoogleNews ? 20000 : 12000;
|
|
|
|
const response = await fetchWithTimeout(feedUrl, {
|
|
headers: {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
'Accept': 'application/rss+xml, application/xml, text/xml, */*',
|
|
'Accept-Language': 'en-US,en;q=0.9',
|
|
},
|
|
}, timeout);
|
|
|
|
const data = await response.text();
|
|
return new Response(data, {
|
|
status: response.status,
|
|
headers: {
|
|
'Content-Type': 'application/xml',
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Cache-Control': 'public, max-age=300',
|
|
},
|
|
});
|
|
} catch (error) {
|
|
const isTimeout = error.name === 'AbortError';
|
|
console.error('RSS proxy error:', feedUrl, error.message);
|
|
return new Response(JSON.stringify({
|
|
error: isTimeout ? 'Feed timeout' : 'Failed to fetch feed',
|
|
details: error.message,
|
|
url: feedUrl
|
|
}), {
|
|
status: isTimeout ? 504 : 502,
|
|
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
|
|
});
|
|
}
|
|
}
|