/** * @cc-platform/server — Main entry point for the shared server foundation * * Provides a createPlatformServer() factory that sets up Express, HTTP server, * auth middleware, CORS, JSON parsing, and health endpoint — the common * boilerplate that is structurally identical across all platform services. * * Also re-exports all sub-modules for convenient access. * * Usage: * const { * createPlatformServer, * createWebSocketManager, * createDatabase, * setupGracefulShutdown, * createRateLimiter, * createProxyEndpoint, * } = require('@cc-platform/server'); * * const { app, server, start } = createPlatformServer({ * serviceName: 'inventory-manager', * port: 3001, * }); * * // Add service-specific routes * app.get('/api/items', (req, res) => { ... }); * * // Set up WebSocket, DB, etc. * const wsManager = createWebSocketManager(server, { ... }); * const db = createDatabase('/data/inventory.db', { schema: '...' }); * * // Start listening * start(); */ 'use strict'; const express = require('express'); const http = require('http'); const { createAuthMiddleware } = require('./auth'); const { createWebSocketManager } = require('./websocket'); const { createDatabase } = require('./db'); const { proxyRequest, createProxyEndpoint } = require('./proxy'); const { createHealthEndpoint } = require('./health'); const { setupGracefulShutdown } = require('./shutdown'); const { createRateLimiter } = require('./rate'); /** * @typedef {Object} PlatformServerOptions * @property {string} [serviceName] Service identifier for logs and health endpoint * @property {number} [port] Listen port (default: env.PORT || 3001) * @property {string} [host] Listen host (default: env.HOST || '0.0.0.0') * @property {string} [apiKey] API key for auth (default: env.API_KEY) * @property {string} [jsonLimit] Express JSON body limit (default: '5mb') * @property {boolean} [cors] Enable CORS (default: true) * @property {string} [corsOrigin] CORS origin (default: '*') * @property {boolean} [rateLimit] Enable rate limiting (default: true) * @property {Object} [rateLimitOpts] Rate limiter options * @property {Function} [healthExtras] Returns additional health check fields */ /** * Create a fully configured Express + HTTP server with platform defaults. * * @param {PlatformServerOptions} opts - Configuration options * @returns {{ app, server, auth, start, port, host }} */ function createPlatformServer(opts = {}) { const app = express(); const server = http.createServer(app); const port = opts.port || process.env.PORT || 3001; const host = opts.host || process.env.HOST || '0.0.0.0'; const apiKey = opts.apiKey || process.env.API_KEY || ''; const serviceName = opts.serviceName || 'platform'; // --- Standard middleware --- app.use(express.json({ limit: opts.jsonLimit || '5mb' })); // CORS if (opts.cors !== false) { app.use((_req, res, next) => { res.header('Access-Control-Allow-Origin', opts.corsOrigin || '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key'); if (_req.method === 'OPTIONS') return res.sendStatus(204); next(); }); } // Auth middleware — protect non-GET methods by default const auth = createAuthMiddleware(apiKey); app.use(auth.protectMutations); // Rate limiting if (opts.rateLimit !== false) { const limiter = createRateLimiter(opts.rateLimitOpts || {}); app.use(limiter); } // Health endpoint createHealthEndpoint(app, { serviceName, getExtras: opts.healthExtras, }); // --- Start --- function start(callback) { server.listen(port, host, () => { console.log(`[${serviceName}] Server listening on ${host}:${port}`); if (apiKey) console.log(`[${serviceName}] API key authentication enabled`); if (callback) callback(); }); } return { app, server, auth, start, port, host }; } module.exports = { // Server factory createPlatformServer, // Sub-modules createAuthMiddleware, createWebSocketManager, createDatabase, proxyRequest, createProxyEndpoint, createHealthEndpoint, setupGracefulShutdown, createRateLimiter, };