import type { OpenApiSpecOptions } from '@pipeline-builder/api-core'; import { type Express } from 'express'; import { type IdempotencyStore } from './idempotency-middleware.js'; import { SSEManager } from '../http/sse-connection-manager.js'; /** * Options for creating an Express application */ export interface CreateAppOptions { /** Enable CORS (default: true) */ enableCors?: boolean; /** Enable Helmet security headers (default: true) */ enableHelmet?: boolean; /** Enable rate limiting (default: true) */ enableRateLimit?: boolean; /** Enable JSON body parsing (default: true) */ enableJsonBody?: boolean; /** JSON body size limit (default: '1mb') */ jsonLimit?: string; /** * Path prefixes the global JSON body parser must NOT touch — for routes that need * the raw body (e.g. a Stripe webhook whose HMAC is computed over the exact bytes). * Without this the global parser consumes the body first and a later `express.raw()` * on the same path is a no-op, breaking signature verification. */ jsonBodyExclude?: string[]; /** Enable URL-encoded body parsing (default: true) */ enableUrlEncoded?: boolean; /** URL-encoded body size limit (default: '1mb') */ urlEncodedLimit?: string; /** Custom SSE manager instance */ sseManager?: SSEManager; /** * Serve the per-request build-log stream: `POST /logs/ticket` + * `GET /logs/:requestId`, a log ticket store, the cross-pod relay, and * `ctx.log` frames pushed to SSE. Default false — a service without it has no * `/logs` routes and `ctx.log` only writes to the logger. */ logStream?: boolean; /** Health check dependency checker — if provided, /health reports dependency status */ checkDependencies?: () => Promise>; /** Enable OpenAPI spec at /docs/openapi.json and Swagger UI at /docs (default: true) */ /** * Serve the OpenAPI spec at `/docs/openapi.json` and Swagger UI at `/docs`. * * Defaults to OFF under `NODE_ENV=production`: the routes are registered above * the rate limiter and were never auth-gated, so in production they published * the full route + schema inventory of every service to anyone who could reach * the port. Only the CSP was tightened for production before, not the route. * Pass `true` explicitly to serve them in production anyway. */ enableOpenApi?: boolean; /** OpenAPI spec customization options */ openApiOptions?: OpenApiSpecOptions; /** Enable gzip/deflate response compression (default: true) */ enableCompression?: boolean; /** * Idempotency replay-cache backend for keyed mutation retries. When omitted, * createApp auto-wires the shared env Redis store (multi-replica dedup) if * Redis is configured, else keeps the in-memory default (single-replica). * Pass an explicit store to inject a bespoke backend (e.g. a service's own * ioredis connection). */ idempotencyStore?: IdempotencyStore; /** * Extra warmup callbacks invoked by `GET /warmup` in addition to the * default Postgres ping. Use for services that depend on Mongo, Redis, * SQS, etc. — pre-warming opens connection pools before real traffic * arrives. Each callback should resolve when its dependency is ready; * any rejection causes /warmup to return 503. */ warmupHooks?: Array<() => Promise>; } /** * Result of creating an Express application */ export interface CreateAppResult { /** Configured Express application */ app: Express; /** SSE manager instance */ sseManager: SSEManager; } /** * Create and configure an Express application with common middleware * * Sets up: * - CORS with configured origins * - Helmet security headers * - Rate limiting * - JSON and URL-encoded body parsing * - Trust proxy settings * - Health check endpoint (/health) * - Metrics endpoint (/metrics) * - SSE logs endpoint (/logs/:requestId) — only with `logStream: true` * * @param options - Configuration options * @returns Configured Express app and SSE manager * * @example * ```typescript * const { app, sseManager } = createApp(); * * app.post('/api/resource', requireAuth, async (req, res) => { * // Your route handler * }); * * startServer(app, { name: 'My Service' }); * ``` */ export declare function createApp(options?: CreateAppOptions): CreateAppResult;