/** * API Route Helper Functions * * This module provides utility functions for creating API route configurations. */ import type { IRouteConfig, IRouteMatch, IRouteAction } from '../../models/route-types.js'; import { mergeRouteConfigs } from '../route-utils.js'; import { createHttpRoute } from './http-helpers.js'; import { createHttpsTerminateRoute } from './https-helpers.js'; /** * Create an API route configuration * @param domains Domain(s) to match * @param apiPath API base path (e.g., "/api") * @param target Target host and port * @param options Additional route options * @returns Route configuration object */ export function createApiRoute( domains: string | string[], apiPath: string, target: { host: string | string[]; port: number }, options: { useTls?: boolean; certificate?: 'auto' | { key: string; cert: string }; addCorsHeaders?: boolean; httpPort?: number | number[]; httpsPort?: number | number[]; name?: string; [key: string]: any; } = {} ): IRouteConfig { // Normalize API path const normalizedPath = apiPath.startsWith('/') ? apiPath : `/${apiPath}`; const pathWithWildcard = normalizedPath.endsWith('/') ? `${normalizedPath}*` : `${normalizedPath}/*`; // Create route match const match: IRouteMatch = { ports: options.useTls ? (options.httpsPort || 443) : (options.httpPort || 80), domains, path: pathWithWildcard }; // Create route action const action: IRouteAction = { type: 'forward', targets: [target] }; // Add TLS configuration if using HTTPS if (options.useTls) { action.tls = { mode: 'terminate', certificate: options.certificate || 'auto' }; } // Add CORS headers if requested const headers: Record> = {}; if (options.addCorsHeaders) { headers.response = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 'Access-Control-Max-Age': '86400' }; } // Create the route config return { match, action, headers: Object.keys(headers).length > 0 ? headers : undefined, name: options.name || `API Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`, priority: options.priority || 100, // Higher priority for specific path matches ...options }; } /** * Create an API Gateway route pattern * @param domains Domain(s) to match * @param apiBasePath Base path for API endpoints (e.g., '/api') * @param target Target host and port * @param options Additional route options * @returns API route configuration */ export function createApiGatewayRoute( domains: string | string[], apiBasePath: string, target: { host: string | string[]; port: number }, options: { useTls?: boolean; certificate?: 'auto' | { key: string; cert: string }; addCorsHeaders?: boolean; [key: string]: any; } = {} ): IRouteConfig { // Normalize apiBasePath to ensure it starts with / and doesn't end with / const normalizedPath = apiBasePath.startsWith('/') ? apiBasePath : `/${apiBasePath}`; // Add wildcard to path to match all API endpoints const apiPath = normalizedPath.endsWith('/') ? `${normalizedPath}*` : `${normalizedPath}/*`; // Create base route const baseRoute = options.useTls ? createHttpsTerminateRoute(domains, target, { certificate: options.certificate || 'auto' }) : createHttpRoute(domains, target); // Add API-specific configurations const apiRoute: Partial = { match: { ...baseRoute.match, path: apiPath }, name: options.name || `API Gateway: ${apiPath} -> ${Array.isArray(target.host) ? target.host.join(', ') : target.host}:${target.port}`, priority: options.priority || 100 // Higher priority for specific path matching }; // Add CORS headers if requested if (options.addCorsHeaders) { apiRoute.headers = { response: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 'Access-Control-Max-Age': '86400' } }; } return mergeRouteConfigs(baseRoute, apiRoute); }