my website at ewancroft.uk
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 82 lines 3.3 kB view raw
1import type { Handle } from '@sveltejs/kit'; 2import { PUBLIC_CORS_ALLOWED_ORIGINS } from '$env/static/public'; 3import { HTTP_CACHE_HEADERS } from '$lib/config/cache.config'; 4 5/** 6 * Global request handler with CORS support 7 * 8 * CORS headers are dynamically configured via the PUBLIC_CORS_ALLOWED_ORIGINS environment variable. 9 * Set it to a comma-separated list of allowed origins, or "*" to allow all origins. 10 */ 11export const handle: Handle = async ({ event, resolve }) => { 12 // Handle OPTIONS preflight requests for CORS 13 if (event.request.method === 'OPTIONS' && event.url.pathname.startsWith('/api/')) { 14 const origin = event.request.headers.get('origin'); 15 const allowedOrigins = 16 PUBLIC_CORS_ALLOWED_ORIGINS?.split(',').map((o: string) => o.trim()) || []; 17 18 const headers: Record<string, string> = { 19 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 20 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 21 'Access-Control-Max-Age': '86400' 22 }; 23 24 if (allowedOrigins.includes('*')) { 25 headers['Access-Control-Allow-Origin'] = '*'; 26 } else if (origin && allowedOrigins.includes(origin)) { 27 headers['Access-Control-Allow-Origin'] = origin; 28 headers['Vary'] = 'Origin'; 29 } 30 31 return new Response(null, { status: 204, headers }); 32 } 33 34 const response = await resolve(event, { 35 filterSerializedResponseHeaders: (name) => { 36 return name === 'content-type' || name === 'cache-control' || name.startsWith('x-'); 37 } 38 }); 39 40 // Add HTTP caching headers for better performance and reduced timeouts 41 // Layout data (root route) is cached aggressively since profile/site info changes infrequently 42 if (!event.url.pathname.startsWith('/api/') && event.url.pathname !== '/webhook') { 43 // Root layout loads profile and site info - cache aggressively 44 if (event.url.pathname === '/' || event.url.pathname === '') { 45 response.headers.set('Cache-Control', HTTP_CACHE_HEADERS.LAYOUT); 46 } 47 // Blog listing pages 48 else if (event.url.pathname.startsWith('/blog') || event.url.pathname.startsWith('/archive')) { 49 response.headers.set('Cache-Control', HTTP_CACHE_HEADERS.BLOG_LISTING); 50 } 51 // Individual blog post pages 52 else if (event.url.pathname.match(/^\/[a-z0-9-]+$/)) { 53 response.headers.set('Cache-Control', HTTP_CACHE_HEADERS.BLOG_POST); 54 } 55 // Other pages get moderate caching 56 else { 57 response.headers.set('Cache-Control', HTTP_CACHE_HEADERS.LAYOUT); 58 } 59 } 60 61 // Add CORS headers for API routes 62 if (event.url.pathname.startsWith('/api/')) { 63 const origin = event.request.headers.get('origin'); 64 const allowedOrigins = 65 PUBLIC_CORS_ALLOWED_ORIGINS?.split(',').map((o: string) => o.trim()) || []; 66 67 // If * is specified, allow any origin 68 if (allowedOrigins.includes('*')) { 69 response.headers.set('Access-Control-Allow-Origin', '*'); 70 } else if (origin && allowedOrigins.includes(origin)) { 71 // Only set the specific origin if it's in the allowed list 72 response.headers.set('Access-Control-Allow-Origin', origin); 73 response.headers.set('Vary', 'Origin'); 74 } 75 76 response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); 77 response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); 78 response.headers.set('Access-Control-Max-Age', '86400'); // 24 hours 79 } 80 81 return response; 82};