diff options
| author | Elizabeth Hunt <me@liz.coffee> | 2025-12-14 20:36:24 -0800 |
|---|---|---|
| committer | Elizabeth Hunt <me@liz.coffee> | 2025-12-14 20:36:24 -0800 |
| commit | 6bf57766feb8321f860baf300140563cd9539053 (patch) | |
| tree | d80ff78c2a7f4dbea79f9ee850542aee1b735ef4 /src/server | |
| download | posthook-6bf57766feb8321f860baf300140563cd9539053.tar.gz posthook-6bf57766feb8321f860baf300140563cd9539053.zip | |
Init
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/index.ts | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/server/index.ts b/src/server/index.ts new file mode 100644 index 0000000..0747680 --- /dev/null +++ b/src/server/index.ts @@ -0,0 +1,84 @@ +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<PenguenoRequest, ServerTrace>) { + 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); + } +} |
