a cache for slack profile pictures and emojis
at main 1.6 kB view raw
1/** 2 * Analytics wrapper utility to eliminate boilerplate in route handlers 3 */ 4 5import type { SlackCache } from "../cache"; 6 7// Cache will be injected by the route system 8 9export type AnalyticsRecorder = (statusCode: number) => Promise<void>; 10export type RouteHandlerWithAnalytics = ( 11 request: Request, 12 recordAnalytics: AnalyticsRecorder, 13) => Promise<Response> | Response; 14 15/** 16 * Creates analytics wrapper with injected cache 17 */ 18export function createAnalyticsWrapper(cache: SlackCache) { 19 return function withAnalytics( 20 path: string, 21 method: string, 22 handler: RouteHandlerWithAnalytics, 23 ) { 24 return async (request: Request): Promise<Response> => { 25 const startTime = Date.now(); 26 27 const recordAnalytics: AnalyticsRecorder = async (statusCode: number) => { 28 const userAgent = request.headers.get("user-agent") || ""; 29 const ipAddress = 30 request.headers.get("x-forwarded-for") || 31 request.headers.get("x-real-ip") || 32 "unknown"; 33 34 // Use the actual request URL for dynamic paths, fallback to provided path 35 const analyticsPath = path.includes(":") ? request.url : path; 36 37 await cache.recordRequest( 38 analyticsPath, 39 method, 40 statusCode, 41 userAgent, 42 ipAddress, 43 Date.now() - startTime, 44 ); 45 }; 46 47 return handler(request, recordAnalytics); 48 }; 49 }; 50} 51 52/** 53 * Type-safe analytics wrapper that automatically infers path and method 54 */ 55export function createAnalyticsHandler( 56 cache: SlackCache, 57 path: string, 58 method: string, 59) { 60 return (handler: RouteHandlerWithAnalytics) => 61 createAnalyticsWrapper(cache)(path, method, handler); 62}