Files
cc-platform-core/server/index.js
2026-03-26 15:00:49 -04:00

134 lines
4.3 KiB
JavaScript

/**
* @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,
};