an atproto based link aggregator
1import { type Handle } from '@sveltejs/kit';
2import { getCurrentDid } from '$lib/server/auth';
3import { checkRateLimit, getRateLimitKey, getRateLimitConfig } from '$lib/server/rate-limit';
4
5// Ingester runs as a separate process on the LiteFS primary machine
6// See src/ingester/main.ts and fly.ingester.toml
7
8export const handle: Handle = async ({ event, resolve }) => {
9 // Load the current user's DID from session cookie
10 const did = await getCurrentDid(event.cookies);
11 event.locals.did = did;
12
13 // Apply rate limiting to API routes
14 const path = event.url.pathname;
15 if (path.startsWith('/api/')) {
16 const ip = event.getClientAddress();
17 const key = getRateLimitKey(ip, path, did);
18 const config = getRateLimitConfig(path);
19 const { allowed, remaining, resetAt } = checkRateLimit(key, config);
20
21 if (!allowed) {
22 const retryAfter = Math.ceil((resetAt - Date.now()) / 1000);
23 return new Response(JSON.stringify({ error: 'Too many requests' }), {
24 status: 429,
25 headers: {
26 'Content-Type': 'application/json',
27 'Retry-After': String(retryAfter),
28 'X-RateLimit-Remaining': '0',
29 'X-RateLimit-Reset': String(resetAt)
30 }
31 });
32 }
33
34 // Add rate limit headers to response
35 const response = await resolve(event);
36 response.headers.set('X-RateLimit-Remaining', String(remaining));
37 response.headers.set('X-RateLimit-Reset', String(resetAt));
38 return response;
39 }
40
41 return resolve(event);
42};