import { Either, FourOhFourActivityImpl, HealthCheckActivityImpl, type HealthChecker, HealthCheckOutput, type IFourOhFourActivity, type IHealthCheckActivity, type ITraceable, PenguenoRequest, Server, type ServerTrace, } from '@emprespresso/pengueno'; import { Storage } from '../storage/index.js'; import { ListRoutesActivityImpl, RegisterRouteActivityImpl, TokenGenerateActivityImpl, WebhookActivityImpl, type IListRoutesActivity, type IRegisterRouteActivity, type ITokenGenerateActivity, type IWebhookActivity, } from '../activity/index.js'; import { TokenSigner } from '../token/index.js'; const defaultHealthCheck: HealthChecker = async (input) => { void input.get(); return Either.right(HealthCheckOutput.YAASSSLAYQUEEN); }; export class PosthookServer implements Server { constructor( storage: Storage, signer: TokenSigner, healthCheck: HealthChecker = defaultHealthCheck, private readonly healthCheckActivity: IHealthCheckActivity = new HealthCheckActivityImpl(healthCheck), private readonly registerRouteActivity: IRegisterRouteActivity = new RegisterRouteActivityImpl(storage), private readonly webhookActivity: IWebhookActivity = new WebhookActivityImpl(storage, signer), private readonly tokenGenerateActivity: ITokenGenerateActivity = new TokenGenerateActivityImpl(storage, signer), private readonly listRoutesActivity: IListRoutesActivity = new ListRoutesActivityImpl(storage), private readonly fourOhFourActivity: IFourOhFourActivity = new FourOhFourActivityImpl(), ) {} public serve(req: ITraceable) { const url = new URL(req.get().req.url); const { pathname } = url; // === Public Routes (/) === // Health check endpoint if (pathname === '/health') { return this.healthCheckActivity.checkHealth(req); } // Token generation endpoint - /hook/{routeName}/token const tokenMatch = pathname.match(/^\/hook\/([^/]+)\/token$/); if (tokenMatch && req.get().req.method === 'GET') { const routeName = tokenMatch[1]; return this.tokenGenerateActivity.generateToken(routeName)(req); } // Dynamic webhook endpoints - /hook/{routeName} const hookMatch = pathname.match(/^\/hook\/([^/]+)$/); if (hookMatch && req.get().req.method === 'POST') { const routeName = hookMatch[1]; return this.webhookActivity.processWebhook(routeName)(req); } // === Admin Routes (/admin) - Put behind OAuth proxy === // Admin endpoints for route management if (pathname === '/admin/routes' && req.get().req.method === 'POST') { return this.registerRouteActivity.registerRoute(req); } if (pathname === '/admin/routes' && req.get().req.method === 'GET') { return this.listRoutesActivity.listRoutes(req); } // 404 for everything else return this.fourOhFourActivity.fourOhFour(req); } }