Cost/traffic hardening, runtime fallback controls, and PostHog removal (#638)

- Remove PostHog analytics runtime and configuration
- Add API rate limiting (api/_rate-limit.js)
- Harden traffic controls across edge functions
- Add runtime fallback controls and data-loader improvements
- Add military base data scripts (fetch-mirta-bases, fetch-osm-bases)
- Gitignore large raw data files
- Settings playground prototypes
This commit is contained in:
Elie Habib
2026-03-01 11:53:20 +04:00
committed by GitHub
parent cac2a4f5af
commit 36e36d8b57
33 changed files with 2383 additions and 743 deletions

View File

@@ -1,5 +1,7 @@
// Non-sebuf: returns XML/HTML, stays as standalone Vercel function
import { getCorsHeaders, isDisallowedOrigin } from './_cors.js';
import { validateApiKey } from './_api-key.js';
import { checkRateLimit } from './_rate-limit.js';
export const config = { runtime: 'edge' };
@@ -328,10 +330,34 @@ const ALLOWED_DOMAINS = [
export default async function handler(req) {
const corsHeaders = getCorsHeaders(req, 'GET, OPTIONS');
if (isDisallowedOrigin(req)) {
return new Response(JSON.stringify({ error: 'Origin not allowed' }), {
status: 403,
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
}
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return new Response(null, { status: 204, headers: corsHeaders });
}
if (req.method !== 'GET') {
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
status: 405,
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
}
const keyCheck = validateApiKey(req);
if (keyCheck.required && !keyCheck.valid) {
return new Response(JSON.stringify({ error: keyCheck.error }), {
status: 401,
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
}
const rateLimitResponse = await checkRateLimit(req, corsHeaders);
if (rateLimitResponse) return rateLimitResponse;
const requestUrl = new URL(req.url);
const feedUrl = requestUrl.searchParams.get('url');
@@ -415,9 +441,9 @@ export default async function handler(req) {
headers: {
'Content-Type': response.headers.get('content-type') || 'application/xml',
'Cache-Control': isSuccess
? 'public, max-age=120, s-maxage=300, stale-while-revalidate=600'
: 'public, max-age=10, s-maxage=30, stale-while-revalidate=60',
...(isSuccess && { 'CDN-Cache-Control': 'public, s-maxage=300, stale-while-revalidate=600' }),
? 'public, max-age=180, s-maxage=900, stale-while-revalidate=1800, stale-if-error=3600'
: 'public, max-age=15, s-maxage=60, stale-while-revalidate=120',
...(isSuccess && { 'CDN-Cache-Control': 'public, s-maxage=900, stale-while-revalidate=1800, stale-if-error=3600' }),
...corsHeaders,
},
});