UNPKG

unleash-server

Version:

Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.

151 lines • 7.08 kB
import express from 'express'; import compression from 'compression'; import favicon from 'serve-favicon'; import cookieParser from 'cookie-parser'; import path from 'path'; import errorHandler from 'errorhandler'; import { responseTimeMetrics, corsOriginMiddleware, } from './middleware/index.js'; import rbacMiddleware from './middleware/rbac-middleware.js'; import apiTokenMiddleware from './middleware/api-token-middleware.js'; import { IAuthType } from './types/option.js'; import IndexRouter from './routes/index.js'; import requestLogger from './middleware/request-logger.js'; import demoAuthentication from './middleware/demo-authentication.js'; import ossAuthentication from './middleware/oss-authentication.js'; import noAuthentication, { noApiToken, } from './middleware/no-authentication.js'; import secureHeaders from './middleware/secure-headers.js'; import { loadIndexHTML, findPublicFolder } from './util/index.js'; import patMiddleware from './middleware/pat-middleware.js'; import maintenanceMiddleware from './features/maintenance/maintenance-middleware.js'; import { unless } from './middleware/unless-middleware.js'; import { catchAllErrorHandler } from './middleware/catch-all-error-handler.js'; import NotFoundError from './error/notfound-error.js'; import { bearerTokenMiddleware } from './middleware/bearer-token-middleware.js'; import { auditAccessMiddleware } from './middleware/index.js'; import { originMiddleware } from './middleware/origin-middleware.js'; export default async function getApp(config, stores, services, unleashSession, db) { const app = express(); const baseUriPath = config.server.baseUriPath || ''; const publicFolder = config.publicFolder || findPublicFolder(); const indexHTML = await loadIndexHTML(config, publicFolder); const logger = config.getLogger('lib/app.ts'); app.set('trust proxy', true); app.disable('x-powered-by'); app.set('port', config.server.port); app.locals.baseUriPath = baseUriPath; if (config.server.serverMetrics && config.eventBus) { app.use(responseTimeMetrics(config.eventBus, config.flagResolver, services.instanceStatsService)); } app.use(requestLogger(config)); app.use(`${baseUriPath}/api`, bearerTokenMiddleware(config)); // We only need bearer token compatibility on /api paths. if (typeof config.preHook === 'function') { config.preHook(app, config, services, db); } if (!config.server.disableCompression) { app.use(compression()); } app.use(cookieParser()); app.use((req, res, next) => { req.url = req.url.replace(/\/+/g, '/'); next(); }); app.use(`${baseUriPath}/api/admin/features-batch`, express.json({ strict: false, limit: '500kB' })); app.use(unless(`${baseUriPath}/api/admin/features-batch`, express.json({ strict: false }))); if (unleashSession) { app.use(unleashSession); } app.use(secureHeaders(config)); app.use(express.urlencoded({ extended: true })); app.use(favicon(path.join(publicFolder, 'favicon.ico'))); app.use(baseUriPath, favicon(path.join(publicFolder, 'favicon.ico'))); app.use(baseUriPath, express.static(publicFolder, { index: false })); if (config.enableOAS && services.openApiService) { services.openApiService.useDocs(app); } app.use(`${baseUriPath}/api/frontend*`, corsOriginMiddleware(services, config)); app.options(`${baseUriPath}/api/streaming*`, corsOriginMiddleware(services, config)); app.use(baseUriPath, patMiddleware(config, services)); switch (config.authentication.type) { case IAuthType.OPEN_SOURCE: { app.use(baseUriPath, apiTokenMiddleware(config, services)); ossAuthentication(app, config.getLogger, config.server.baseUriPath); break; } case IAuthType.ENTERPRISE: { app.use(baseUriPath, apiTokenMiddleware(config, services)); if (config.authentication.customAuthHandler) { config.authentication.customAuthHandler(app, config, services); } break; } case IAuthType.HOSTED: { app.use(baseUriPath, apiTokenMiddleware(config, services)); if (config.authentication.customAuthHandler) { config.authentication.customAuthHandler(app, config, services); } break; } case IAuthType.DEMO: { app.use(baseUriPath, apiTokenMiddleware(config, services)); demoAuthentication(app, config.server.baseUriPath, services, config); break; } case IAuthType.CUSTOM: { app.use(baseUriPath, apiTokenMiddleware(config, services)); if (config.authentication.customAuthHandler) { config.authentication.customAuthHandler(app, config, services); } break; } case IAuthType.NONE: { logger.warn('The AuthType=none option for Unleash is no longer recommended and will be removed in version 6.'); noApiToken(baseUriPath, app); app.use(baseUriPath, apiTokenMiddleware(config, services)); noAuthentication(baseUriPath, app); break; } default: { app.use(baseUriPath, apiTokenMiddleware(config, services)); demoAuthentication(app, config.server.baseUriPath, services, config); break; } } app.use(baseUriPath, rbacMiddleware(config, stores, services.accessService)); app.use(`${baseUriPath}/api/admin`, originMiddleware(config)); app.use(`${baseUriPath}/api/admin`, auditAccessMiddleware(config)); app.use(`${baseUriPath}/api/admin`, maintenanceMiddleware(config, services.maintenanceService)); if (typeof config.preRouterHook === 'function') { config.preRouterHook(app, config, services, stores, db); } // Setup API routes app.use(`${baseUriPath}/`, new IndexRouter(config, services, stores, db).router); if (process.env.NODE_ENV !== 'production') { app.use(errorHandler()); } else { app.use(catchAllErrorHandler(config.getLogger)); } app.get(`${baseUriPath}`, (req, res) => { res.set('Content-Type', 'text/html'); res.send(indexHTML); }); // handle all API 404s app.use(`${baseUriPath}/api`, (req, res) => { const error = new NotFoundError(`The path you were looking for (${baseUriPath}/api${req.path}) is not available.`); res.status(error.statusCode).send(error); return; }); app.get(`${baseUriPath}/*`, (req, res) => { res.set('Content-Type', 'text/html'); const requestPath = path.parse(req.url); // appropriately return 404 requests for assets with an extension (js, css, etc) if (requestPath.ext !== '' && requestPath.ext !== 'html') { res.set('Cache-Control', 'no-cache'); res.status(404).send(indexHTML); return; } res.send(indexHTML); }); return app; } //# sourceMappingURL=app.js.map