@autofleet/super-express 8.3.10-beta-859c5e8b.0 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,`__esModule`,{value:!0});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:crypto`);c=s(c);let l=require(`express`);l=s(l);let u=require(`@autofleet/nitur`);const d={bodyParser:`1000mb`,helmet:!0,morgan:!0,stats:!0,tracing:!0,eagerLoadUserPermissions:!0};var f=`8.3.10-beta-859c5e8b.0`;function p({logger:e,...t}){let n=(0,l.default)();n.set(`query parser`,!1),n.use((e,t,n)=>(e.query=void 0,n()),l.default.query({parameterLimit:1/0,arrayLimit:1/0}));let r={...d,...t},i;if(r.morgan){let t=require(`morgan`);e.debug(`[SuperExpress] formatting is enabled ✅`),n.use(t((t,n,r)=>{let i={method:t.method(n,r),url:t.url(n,r)??`unknown URL`,status:t.status(n,r),contentLength:t.res(n,r,`content-length`),responseTime:t[`response-time`](n,r)??`0`,userAgent:t[`user-agent`](n,r)};e.info(i.url,{httpRequest:{status:i.status,requestUrl:i.url,requestMethod:i.method,responseSize:i.contentLength,latency:{seconds:Number.parseInt(i.responseTime,10)/1e3,nanos:Number.parseInt(i.responseTime,10)*1e6},userAgent:i.userAgent}})}))}if(r.helmet?(e.debug(`[SuperExpress] security is enabled ✅`),n.use((e,t,n)=>{let r=c.default.randomBytes(16).toString(`base64`);t.locals.cspNonce=r;let i={"Content-Security-Policy":`default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${r}';script-src-attr 'none';style-src 'self' https: 'nonce-${r}';upgrade-insecure-requests`,"Cross-Origin-Opener-Policy":`same-origin`,"Cross-Origin-Resource-Policy":`same-origin`,"Origin-Agent-Cluster":`?1`,"Referrer-Policy":`no-referrer`,"Strict-Transport-Security":`max-age=15552000; includeSubDomains`,"X-Content-Type-Options":`nosniff`,"X-DNS-Prefetch-Control":`off`,"X-Download-Options":`noopen`,"X-Frame-Options":`SAMEORIGIN`,"X-Permitted-Cross-Domain-Policies":`none`,"X-XSS-Protection":`0`};t.set(i),n()}),n.disable(`x-powered-by`)):e.warn(`[SuperExpress] security headers are disabled 😨`),r.bodyParser){e.debug(`[SuperExpress] body-parser is enabled ✅`);let t=typeof r.bodyParser==`string`?r.bodyParser:`1000mb`;n.use(l.default.json({limit:t}))}else e.debug(`[SuperExpress] body-parser is disabled ❌`);if(r.healthManagerOptions&&(i=new u.HealthManager({...r.healthManagerOptions,logger:e}),n.get(`/alive`,async(e,t)=>{try{let e=await i.aliveCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),n.get(`/ready`,async(e,t)=>{try{let e=await i.readyCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),e.debug(`[SuperExpress] added /alive and /ready endpoints with HealthManager ✅`)),r.stats){let t=new Date;n.get(`/stats`,(e,n)=>{n.json({name:r.name||`default-name`,version:r.version||`default-version`,serverRunningSince:t})}),e.debug(`[SuperExpress] added /stats endpoint ✅`)}if(r.tracing){let{enableTracing:t,middleware:i}=require(`@autofleet/zehut`);t({logger:e}),n.use(i({eagerLoadUserPermissions:r.eagerLoadUserPermissions})),e.debug(`[SuperExpress] tracing is enabled ✅`)}let a=n.listen.bind(n);return n.listen=function(t,n){let r=process.env.NODE_ENV===`production`;e.debug(`[SuperExpress] is started with version ${f||`unknown`}`),e.debug(`[SuperExpress] will listen on port ${t}`),e.debug(`[SuperExpress] production mode: ${r}`);let o=a(t,n);return i&&(i.attachServer({connection:o}),e.debug(`[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅`)),o},Object.assign(n,{nativeListen:a})}var m=p;exports.default=m,exports.superExpress=p;
1
+ Object.defineProperty(exports,`__esModule`,{value:!0});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:crypto`);c=s(c);let l=require(`express`);l=s(l);let u=require(`@autofleet/nitur`);const d={bodyParser:`1000mb`,helmet:!0,morgan:!0,stats:!0,tracing:!0,eagerLoadUserPermissions:!0};var f=`8.4.0`;function p({logger:e,...t}){let n=(0,l.default)();n.set(`query parser`,!1),n.use((e,t,n)=>(e.query=void 0,n()),l.default.query({parameterLimit:1/0,arrayLimit:1/0}));let r={...d,...t},i;if(r.morgan){let t=require(`morgan`);e.debug(`[SuperExpress] formatting is enabled ✅`),n.use(t((t,n,r)=>{let i={method:t.method(n,r),url:t.url(n,r)??`unknown URL`,status:t.status(n,r),contentLength:t.res(n,r,`content-length`),responseTime:t[`response-time`](n,r)??`0`,userAgent:t[`user-agent`](n,r)};e.info(i.url,{httpRequest:{status:i.status,requestUrl:i.url,requestMethod:i.method,responseSize:i.contentLength,latency:{seconds:Number.parseInt(i.responseTime,10)/1e3,nanos:Number.parseInt(i.responseTime,10)*1e6},userAgent:i.userAgent}})}))}if(r.helmet?(e.debug(`[SuperExpress] security is enabled ✅`),n.use((e,t,n)=>{let r=c.default.randomBytes(16).toString(`base64`);t.locals.cspNonce=r;let i={"Content-Security-Policy":`default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${r}';script-src-attr 'none';style-src 'self' https: 'nonce-${r}';upgrade-insecure-requests`,"Cross-Origin-Opener-Policy":`same-origin`,"Cross-Origin-Resource-Policy":`same-origin`,"Origin-Agent-Cluster":`?1`,"Referrer-Policy":`no-referrer`,"Strict-Transport-Security":`max-age=15552000; includeSubDomains`,"X-Content-Type-Options":`nosniff`,"X-DNS-Prefetch-Control":`off`,"X-Download-Options":`noopen`,"X-Frame-Options":`SAMEORIGIN`,"X-Permitted-Cross-Domain-Policies":`none`,"X-XSS-Protection":`0`};t.set(i),n()}),n.disable(`x-powered-by`)):e.warn(`[SuperExpress] security headers are disabled 😨`),r.bodyParser){e.debug(`[SuperExpress] body-parser is enabled ✅`);let t=typeof r.bodyParser==`string`?r.bodyParser:`1000mb`;n.use(l.default.json({limit:t}))}else e.debug(`[SuperExpress] body-parser is disabled ❌`);if(r.healthManagerOptions&&(i=new u.HealthManager({...r.healthManagerOptions,logger:e}),n.get(`/alive`,async(e,t)=>{try{let e=await i.aliveCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),n.get(`/ready`,async(e,t)=>{try{let e=await i.readyCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),e.debug(`[SuperExpress] added /alive and /ready endpoints with HealthManager ✅`)),r.stats){let t=new Date;n.get(`/stats`,(e,n)=>{n.json({name:r.name||`default-name`,version:r.version||`default-version`,serverRunningSince:t})}),e.debug(`[SuperExpress] added /stats endpoint ✅`)}if(r.tracing){let{enableTracing:t,middleware:i}=require(`@autofleet/zehut`);t({logger:e}),n.use(i({eagerLoadUserPermissions:r.eagerLoadUserPermissions})),e.debug(`[SuperExpress] tracing is enabled ✅`)}let a=n.listen.bind(n);return n.listen=function(t,n){let r=process.env.NODE_ENV===`production`;e.debug(`[SuperExpress] is started with version ${f||`unknown`}`),e.debug(`[SuperExpress] will listen on port ${t}`),e.debug(`[SuperExpress] production mode: ${r}`);let o=a(t,n);return i&&(i.attachServer({connection:o}),e.debug(`[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅`)),o},Object.assign(n,{nativeListen:a})}var m=p;exports.default=m,exports.superExpress=p;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["defaultOptions: Omit<Options, 'logger'>","healthManager: HealthManager","crypto","HealthManager","error: any","nativeListen: typeof app['listen']"],"sources":["../config/default-options.ts","../package.json","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { HealthManagerOptions } from '@autofleet/nitur';\n\n/** Options to customize the behavior of the SuperExpress application. */\nexport interface Options {\n /** The name of the application. @default 'default-name' */\n name?: string;\n /** The version of the application. @default 'default-version' */\n version?: string;\n /** Enables or disables body parser middleware. if given a string, will be used as the limit for body size @default '1000mb' */\n bodyParser?: boolean | string;\n /** Enables or disables security headers middleware. @default true */\n helmet?: boolean;\n /** Enables or disables HTTP request logging middleware. @default true */\n morgan?: boolean;\n /** Enables or disables the stats endpoint middleware. @default true */\n stats?: boolean;\n /** Enables or disables request tracing middleware. @default true */\n tracing?: boolean;\n /** Enables or disables eager loading of user permissions for tracing middleware. @default true */\n eagerLoadUserPermissions?: boolean;\n /** The servers logger instance. */\n logger: LoggerInstanceManager;\n /** HealthManager options to create a HealthManager instance for application health and graceful shutdown */\n healthManagerOptions?: Omit<HealthManagerOptions, 'logger'>;\n}\n\nexport const defaultOptions: Omit<Options, 'logger'> = {\n bodyParser: '1000mb',\n helmet: true,\n morgan: true,\n stats: true,\n tracing: true,\n eagerLoadUserPermissions: true,\n} satisfies Omit<Options, 'logger'>;\n","","import type { Server } from 'node:http';\nimport crypto from 'node:crypto';\nimport express from 'express';\nimport { HealthManager } from '@autofleet/nitur';\nimport { defaultOptions, type Options } from '../config/default-options.js';\nimport { version } from '../package.json' with { type: 'json' };\n\n/** Extended express.Application interface which includes nativeListen and the overridden listen method. */\ninterface SuperExpressApp extends Omit<express.Application, 'listen'> {\n /** Original express listen method. */\n nativeListen: express.Application['listen'];\n\n /**\n * Overridden listen method to add custom behavior.\n * @param port - The port number to listen on.\n * @param cb - Optional callback function to execute after the server starts listening.\n */\n listen(port: number, cb?: () => void): Server;\n}\n\n/**\n * Creates a new SuperExpress application with the given options.\n * @param options Optional settings to customize the application.\n * @returns A SuperExpress application instance.\n */\nexport function superExpress({ logger, ...options }: Options): SuperExpressApp {\n const app = express();\n // REMOVE query parameter limit, as it can cause issues with large payloads: https://github.com/expressjs/express/issues/5878\n // Additionally, remove the `arrayLimit` behavior, which changed in `qs@6.14.1` to 20, to solve a CVE, while being a breaking change. See https://github.com/ljharb/qs/issues/537\n app.set('query parser', false);\n app.use((req, _res, next) => (req.query = undefined!, next()), express.query({ parameterLimit: Infinity, arrayLimit: Infinity }));\n const mergedOptions = { ...defaultOptions, ...options };\n\n // Create HealthManager instance if options are provided\n let healthManager: HealthManager;\n\n /** Formatting */\n if (mergedOptions.morgan) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const morgan = require('morgan') as typeof import('morgan');\n logger.debug('[SuperExpress] formatting is enabled ✅');\n app.use(morgan((tokens, req, res) => {\n const values = {\n method: tokens.method(req, res),\n url: tokens.url(req, res) ?? 'unknown URL',\n status: tokens.status(req, res),\n contentLength: tokens.res(req, res, 'content-length'),\n responseTime: tokens['response-time'](req, res) ?? '0',\n userAgent: tokens['user-agent'](req, res),\n };\n logger.info(values.url, {\n httpRequest: {\n status: values.status,\n requestUrl: values.url,\n requestMethod: values.method,\n responseSize: values.contentLength,\n latency: {\n seconds: Number.parseInt(values.responseTime, 10) / 1_000,\n nanos: Number.parseInt(values.responseTime, 10) * 1_000_000,\n },\n userAgent: values.userAgent,\n },\n });\n return undefined;\n }));\n }\n /** Security */\n if (mergedOptions.helmet) {\n logger.debug('[SuperExpress] security is enabled ✅');\n // this is what helmet does by default. https://helmetjs.github.io/faq/you-might-not-need-helmet/\n\n // Middleware to generate nonce per request and set security headers\n app.use((_req, res, next) => {\n // Generate a random nonce for this request\n const nonce = crypto.randomBytes(16).toString('base64');\n\n // Store nonce in res.locals so it can be accessed in templates\n res.locals.cspNonce = nonce;\n\n const HEADERS = {\n 'Content-Security-Policy':\n // eslint-disable-next-line @stylistic/max-len\n `default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${nonce}';script-src-attr 'none';style-src 'self' https: 'nonce-${nonce}';upgrade-insecure-requests`,\n 'Cross-Origin-Opener-Policy': 'same-origin',\n 'Cross-Origin-Resource-Policy': 'same-origin',\n 'Origin-Agent-Cluster': '?1',\n 'Referrer-Policy': 'no-referrer',\n 'Strict-Transport-Security': 'max-age=15552000; includeSubDomains',\n 'X-Content-Type-Options': 'nosniff',\n 'X-DNS-Prefetch-Control': 'off',\n 'X-Download-Options': 'noopen',\n 'X-Frame-Options': 'SAMEORIGIN',\n 'X-Permitted-Cross-Domain-Policies': 'none',\n 'X-XSS-Protection': '0',\n };\n\n res.set(HEADERS);\n next();\n });\n app.disable('x-powered-by');\n } else {\n logger.warn('[SuperExpress] security headers are disabled 😨');\n }\n /** Body Parser */\n if (mergedOptions.bodyParser) {\n logger.debug('[SuperExpress] body-parser is enabled ✅');\n const limit = typeof mergedOptions.bodyParser === 'string' ? mergedOptions.bodyParser : '1000mb';\n app.use(express.json({ limit }));\n } else {\n logger.debug('[SuperExpress] body-parser is disabled ❌');\n }\n /** Alive/Ready Endpoints */\n if (mergedOptions.healthManagerOptions) {\n healthManager = new HealthManager({\n ...mergedOptions.healthManagerOptions,\n logger,\n });\n\n app.get('/alive', async (_req, res) => {\n try {\n const result = await healthManager.aliveCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n app.get('/ready', async (_req, res) => {\n try {\n const result = await healthManager.readyCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n logger.debug('[SuperExpress] added /alive and /ready endpoints with HealthManager ✅');\n }\n /** Stats Endpoint */\n if (mergedOptions.stats) {\n const serverRunningSince = new Date();\n app.get('/stats', (_req, res) => {\n res.json({\n name: mergedOptions.name || 'default-name',\n version: mergedOptions.version || 'default-version',\n serverRunningSince,\n });\n });\n logger.debug('[SuperExpress] added /stats endpoint ✅');\n }\n /** Tracing */\n if (mergedOptions.tracing) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { enableTracing, middleware } = require('@autofleet/zehut') as typeof import('@autofleet/zehut');\n enableTracing({ logger });\n\n app.use(middleware({\n eagerLoadUserPermissions: mergedOptions.eagerLoadUserPermissions,\n }));\n logger.debug('[SuperExpress] tracing is enabled ✅');\n }\n\n const nativeListen: typeof app['listen'] = app.listen.bind(app);\n app.listen = function (port: number, callback?: () => void) {\n const isProd = process.env.NODE_ENV === 'production';\n logger.debug(`[SuperExpress] is started with version ${version || 'unknown'}`);\n logger.debug(`[SuperExpress] will listen on port ${port}`);\n logger.debug(`[SuperExpress] production mode: ${isProd}`);\n\n const server = nativeListen(port, callback);\n\n // Attach server to HealthManager for graceful shutdown (if provided)\n if (healthManager) {\n healthManager.attachServer({ connection: server });\n logger.debug('[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅');\n }\n\n return server;\n } as typeof app['listen'];\n\n return Object.assign(app, { nativeListen }) as SuperExpressApp;\n}\n\nexport default superExpress;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["defaultOptions: Omit<Options, 'logger'>","healthManager: HealthManager","crypto","HealthManager","error: any","nativeListen: typeof app['listen']"],"sources":["../config/default-options.ts","../package.json","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { HealthManagerOptions } from '@autofleet/nitur';\n\n/** Options to customize the behavior of the SuperExpress application. */\nexport interface Options {\n /** The name of the application. @default 'default-name' */\n name?: string;\n /** The version of the application. @default 'default-version' */\n version?: string;\n /** Enables or disables body parser middleware. if given a string, will be used as the limit for body size @default '1000mb' */\n bodyParser?: boolean | string;\n /** Enables or disables security headers middleware. @default true */\n helmet?: boolean;\n /** Enables or disables HTTP request logging middleware. @default true */\n morgan?: boolean;\n /** Enables or disables the stats endpoint middleware. @default true */\n stats?: boolean;\n /** Enables or disables request tracing middleware. @default true */\n tracing?: boolean;\n /** Enables or disables eager loading of user permissions for tracing middleware. @default true */\n eagerLoadUserPermissions?: boolean;\n /** The servers logger instance. */\n logger: LoggerInstanceManager;\n /** HealthManager options to create a HealthManager instance for application health and graceful shutdown */\n healthManagerOptions?: Omit<HealthManagerOptions, 'logger'>;\n}\n\nexport const defaultOptions: Omit<Options, 'logger'> = {\n bodyParser: '1000mb',\n helmet: true,\n morgan: true,\n stats: true,\n tracing: true,\n eagerLoadUserPermissions: true,\n} satisfies Omit<Options, 'logger'>;\n","","import type { Server } from 'node:http';\nimport crypto from 'node:crypto';\nimport express from 'express';\nimport { HealthManager } from '@autofleet/nitur';\nimport { defaultOptions, type Options } from '../config/default-options.js';\nimport { version } from '../package.json' with { type: 'json' };\n\n/** Extended express.Application interface which includes nativeListen and the overridden listen method. */\ninterface SuperExpressApp extends Omit<express.Application, 'listen'> {\n /** Original express listen method. */\n nativeListen: express.Application['listen'];\n\n /**\n * Overridden listen method to add custom behavior.\n * @param port - The port number to listen on.\n * @param cb - Optional callback function to execute after the server starts listening.\n */\n listen(port: number, cb?: () => void): Server;\n}\n\n/**\n * Creates a new SuperExpress application with the given options.\n * @param options Optional settings to customize the application.\n * @returns A SuperExpress application instance.\n */\nexport function superExpress({ logger, ...options }: Options): SuperExpressApp {\n const app = express();\n // REMOVE query parameter limit, as it can cause issues with large payloads: https://github.com/expressjs/express/issues/5878\n // Additionally, remove the `arrayLimit` behavior, which changed in `qs@6.14.1` to 20, to solve a CVE, while being a breaking change. See https://github.com/ljharb/qs/issues/537\n app.set('query parser', false);\n app.use((req, _res, next) => (req.query = undefined!, next()), express.query({ parameterLimit: Infinity, arrayLimit: Infinity }));\n const mergedOptions = { ...defaultOptions, ...options };\n\n // Create HealthManager instance if options are provided\n let healthManager: HealthManager;\n\n /** Formatting */\n if (mergedOptions.morgan) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const morgan = require('morgan') as typeof import('morgan');\n logger.debug('[SuperExpress] formatting is enabled ✅');\n app.use(morgan((tokens, req, res) => {\n const values = {\n method: tokens.method(req, res),\n url: tokens.url(req, res) ?? 'unknown URL',\n status: tokens.status(req, res),\n contentLength: tokens.res(req, res, 'content-length'),\n responseTime: tokens['response-time'](req, res) ?? '0',\n userAgent: tokens['user-agent'](req, res),\n };\n logger.info(values.url, {\n httpRequest: {\n status: values.status,\n requestUrl: values.url,\n requestMethod: values.method,\n responseSize: values.contentLength,\n latency: {\n seconds: Number.parseInt(values.responseTime, 10) / 1_000,\n nanos: Number.parseInt(values.responseTime, 10) * 1_000_000,\n },\n userAgent: values.userAgent,\n },\n });\n return undefined;\n }));\n }\n /** Security */\n if (mergedOptions.helmet) {\n logger.debug('[SuperExpress] security is enabled ✅');\n // this is what helmet does by default. https://helmetjs.github.io/faq/you-might-not-need-helmet/\n\n // Middleware to generate nonce per request and set security headers\n app.use((_req, res, next) => {\n // Generate a random nonce for this request\n const nonce = crypto.randomBytes(16).toString('base64');\n\n // Store nonce in res.locals so it can be accessed in templates\n res.locals.cspNonce = nonce;\n\n const HEADERS = {\n 'Content-Security-Policy':\n // eslint-disable-next-line @stylistic/max-len\n `default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${nonce}';script-src-attr 'none';style-src 'self' https: 'nonce-${nonce}';upgrade-insecure-requests`,\n 'Cross-Origin-Opener-Policy': 'same-origin',\n 'Cross-Origin-Resource-Policy': 'same-origin',\n 'Origin-Agent-Cluster': '?1',\n 'Referrer-Policy': 'no-referrer',\n 'Strict-Transport-Security': 'max-age=15552000; includeSubDomains',\n 'X-Content-Type-Options': 'nosniff',\n 'X-DNS-Prefetch-Control': 'off',\n 'X-Download-Options': 'noopen',\n 'X-Frame-Options': 'SAMEORIGIN',\n 'X-Permitted-Cross-Domain-Policies': 'none',\n 'X-XSS-Protection': '0',\n };\n\n res.set(HEADERS);\n next();\n });\n app.disable('x-powered-by');\n } else {\n logger.warn('[SuperExpress] security headers are disabled 😨');\n }\n /** Body Parser */\n if (mergedOptions.bodyParser) {\n logger.debug('[SuperExpress] body-parser is enabled ✅');\n const limit = typeof mergedOptions.bodyParser === 'string' ? mergedOptions.bodyParser : '1000mb';\n app.use(express.json({ limit }));\n } else {\n logger.debug('[SuperExpress] body-parser is disabled ❌');\n }\n /** Alive/Ready Endpoints */\n if (mergedOptions.healthManagerOptions) {\n healthManager = new HealthManager({\n ...mergedOptions.healthManagerOptions,\n logger,\n });\n\n app.get('/alive', async (_req, res) => {\n try {\n const result = await healthManager.aliveCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n app.get('/ready', async (_req, res) => {\n try {\n const result = await healthManager.readyCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n logger.debug('[SuperExpress] added /alive and /ready endpoints with HealthManager ✅');\n }\n /** Stats Endpoint */\n if (mergedOptions.stats) {\n const serverRunningSince = new Date();\n app.get('/stats', (_req, res) => {\n res.json({\n name: mergedOptions.name || 'default-name',\n version: mergedOptions.version || 'default-version',\n serverRunningSince,\n });\n });\n logger.debug('[SuperExpress] added /stats endpoint ✅');\n }\n /** Tracing */\n if (mergedOptions.tracing) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { enableTracing, middleware } = require('@autofleet/zehut') as typeof import('@autofleet/zehut');\n enableTracing({ logger });\n\n app.use(middleware({\n eagerLoadUserPermissions: mergedOptions.eagerLoadUserPermissions,\n }));\n logger.debug('[SuperExpress] tracing is enabled ✅');\n }\n\n const nativeListen: typeof app['listen'] = app.listen.bind(app);\n app.listen = function (port: number, callback?: () => void) {\n const isProd = process.env.NODE_ENV === 'production';\n logger.debug(`[SuperExpress] is started with version ${version || 'unknown'}`);\n logger.debug(`[SuperExpress] will listen on port ${port}`);\n logger.debug(`[SuperExpress] production mode: ${isProd}`);\n\n const server = nativeListen(port, callback);\n\n // Attach server to HealthManager for graceful shutdown (if provided)\n if (healthManager) {\n healthManager.attachServer({ connection: server });\n logger.debug('[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅');\n }\n\n return server;\n } as typeof app['listen'];\n\n return Object.assign(app, { nativeListen }) as SuperExpressApp;\n}\n\nexport default superExpress;\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{createRequire as e}from"node:module";import t from"node:crypto";import n from"express";import{HealthManager as r}from"@autofleet/nitur";var i=e(import.meta.url);const a={bodyParser:`1000mb`,helmet:!0,morgan:!0,stats:!0,tracing:!0,eagerLoadUserPermissions:!0};var o=`8.3.10-beta-859c5e8b.0`;function s({logger:e,...s}){let c=n();c.set(`query parser`,!1),c.use((e,t,n)=>(e.query=void 0,n()),n.query({parameterLimit:1/0,arrayLimit:1/0}));let l={...a,...s},u;if(l.morgan){let t=i(`morgan`);e.debug(`[SuperExpress] formatting is enabled ✅`),c.use(t((t,n,r)=>{let i={method:t.method(n,r),url:t.url(n,r)??`unknown URL`,status:t.status(n,r),contentLength:t.res(n,r,`content-length`),responseTime:t[`response-time`](n,r)??`0`,userAgent:t[`user-agent`](n,r)};e.info(i.url,{httpRequest:{status:i.status,requestUrl:i.url,requestMethod:i.method,responseSize:i.contentLength,latency:{seconds:Number.parseInt(i.responseTime,10)/1e3,nanos:Number.parseInt(i.responseTime,10)*1e6},userAgent:i.userAgent}})}))}if(l.helmet?(e.debug(`[SuperExpress] security is enabled ✅`),c.use((e,n,r)=>{let i=t.randomBytes(16).toString(`base64`);n.locals.cspNonce=i;let a={"Content-Security-Policy":`default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${i}';script-src-attr 'none';style-src 'self' https: 'nonce-${i}';upgrade-insecure-requests`,"Cross-Origin-Opener-Policy":`same-origin`,"Cross-Origin-Resource-Policy":`same-origin`,"Origin-Agent-Cluster":`?1`,"Referrer-Policy":`no-referrer`,"Strict-Transport-Security":`max-age=15552000; includeSubDomains`,"X-Content-Type-Options":`nosniff`,"X-DNS-Prefetch-Control":`off`,"X-Download-Options":`noopen`,"X-Frame-Options":`SAMEORIGIN`,"X-Permitted-Cross-Domain-Policies":`none`,"X-XSS-Protection":`0`};n.set(a),r()}),c.disable(`x-powered-by`)):e.warn(`[SuperExpress] security headers are disabled 😨`),l.bodyParser){e.debug(`[SuperExpress] body-parser is enabled ✅`);let t=typeof l.bodyParser==`string`?l.bodyParser:`1000mb`;c.use(n.json({limit:t}))}else e.debug(`[SuperExpress] body-parser is disabled ❌`);if(l.healthManagerOptions&&(u=new r({...l.healthManagerOptions,logger:e}),c.get(`/alive`,async(e,t)=>{try{let e=await u.aliveCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),c.get(`/ready`,async(e,t)=>{try{let e=await u.readyCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),e.debug(`[SuperExpress] added /alive and /ready endpoints with HealthManager ✅`)),l.stats){let t=new Date;c.get(`/stats`,(e,n)=>{n.json({name:l.name||`default-name`,version:l.version||`default-version`,serverRunningSince:t})}),e.debug(`[SuperExpress] added /stats endpoint ✅`)}if(l.tracing){let{enableTracing:t,middleware:n}=i(`@autofleet/zehut`);t({logger:e}),c.use(n({eagerLoadUserPermissions:l.eagerLoadUserPermissions})),e.debug(`[SuperExpress] tracing is enabled ✅`)}let d=c.listen.bind(c);return c.listen=function(t,n){let r=process.env.NODE_ENV===`production`;e.debug(`[SuperExpress] is started with version ${o||`unknown`}`),e.debug(`[SuperExpress] will listen on port ${t}`),e.debug(`[SuperExpress] production mode: ${r}`);let i=d(t,n);return u&&(u.attachServer({connection:i}),e.debug(`[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅`)),i},Object.assign(c,{nativeListen:d})}var c=s;export{c as default,s as superExpress};
1
+ import{createRequire as e}from"node:module";import t from"node:crypto";import n from"express";import{HealthManager as r}from"@autofleet/nitur";var i=e(import.meta.url);const a={bodyParser:`1000mb`,helmet:!0,morgan:!0,stats:!0,tracing:!0,eagerLoadUserPermissions:!0};var o=`8.4.0`;function s({logger:e,...s}){let c=n();c.set(`query parser`,!1),c.use((e,t,n)=>(e.query=void 0,n()),n.query({parameterLimit:1/0,arrayLimit:1/0}));let l={...a,...s},u;if(l.morgan){let t=i(`morgan`);e.debug(`[SuperExpress] formatting is enabled ✅`),c.use(t((t,n,r)=>{let i={method:t.method(n,r),url:t.url(n,r)??`unknown URL`,status:t.status(n,r),contentLength:t.res(n,r,`content-length`),responseTime:t[`response-time`](n,r)??`0`,userAgent:t[`user-agent`](n,r)};e.info(i.url,{httpRequest:{status:i.status,requestUrl:i.url,requestMethod:i.method,responseSize:i.contentLength,latency:{seconds:Number.parseInt(i.responseTime,10)/1e3,nanos:Number.parseInt(i.responseTime,10)*1e6},userAgent:i.userAgent}})}))}if(l.helmet?(e.debug(`[SuperExpress] security is enabled ✅`),c.use((e,n,r)=>{let i=t.randomBytes(16).toString(`base64`);n.locals.cspNonce=i;let a={"Content-Security-Policy":`default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${i}';script-src-attr 'none';style-src 'self' https: 'nonce-${i}';upgrade-insecure-requests`,"Cross-Origin-Opener-Policy":`same-origin`,"Cross-Origin-Resource-Policy":`same-origin`,"Origin-Agent-Cluster":`?1`,"Referrer-Policy":`no-referrer`,"Strict-Transport-Security":`max-age=15552000; includeSubDomains`,"X-Content-Type-Options":`nosniff`,"X-DNS-Prefetch-Control":`off`,"X-Download-Options":`noopen`,"X-Frame-Options":`SAMEORIGIN`,"X-Permitted-Cross-Domain-Policies":`none`,"X-XSS-Protection":`0`};n.set(a),r()}),c.disable(`x-powered-by`)):e.warn(`[SuperExpress] security headers are disabled 😨`),l.bodyParser){e.debug(`[SuperExpress] body-parser is enabled ✅`);let t=typeof l.bodyParser==`string`?l.bodyParser:`1000mb`;c.use(n.json({limit:t}))}else e.debug(`[SuperExpress] body-parser is disabled ❌`);if(l.healthManagerOptions&&(u=new r({...l.healthManagerOptions,logger:e}),c.get(`/alive`,async(e,t)=>{try{let e=await u.aliveCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),c.get(`/ready`,async(e,t)=>{try{let e=await u.readyCheck();t.status(e.statusCode).json({status:e.status})}catch(e){let n=e.body?.()||{status:`ERROR`,errors:[e.message]};t.status(e.statusCode||503).json(n)}}),e.debug(`[SuperExpress] added /alive and /ready endpoints with HealthManager ✅`)),l.stats){let t=new Date;c.get(`/stats`,(e,n)=>{n.json({name:l.name||`default-name`,version:l.version||`default-version`,serverRunningSince:t})}),e.debug(`[SuperExpress] added /stats endpoint ✅`)}if(l.tracing){let{enableTracing:t,middleware:n}=i(`@autofleet/zehut`);t({logger:e}),c.use(n({eagerLoadUserPermissions:l.eagerLoadUserPermissions})),e.debug(`[SuperExpress] tracing is enabled ✅`)}let d=c.listen.bind(c);return c.listen=function(t,n){let r=process.env.NODE_ENV===`production`;e.debug(`[SuperExpress] is started with version ${o||`unknown`}`),e.debug(`[SuperExpress] will listen on port ${t}`),e.debug(`[SuperExpress] production mode: ${r}`);let i=d(t,n);return u&&(u.attachServer({connection:i}),e.debug(`[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅`)),i},Object.assign(c,{nativeListen:d})}var c=s;export{c as default,s as superExpress};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["defaultOptions: Omit<Options, 'logger'>","healthManager: HealthManager","error: any","nativeListen: typeof app['listen']"],"sources":["../config/default-options.ts","../package.json","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { HealthManagerOptions } from '@autofleet/nitur';\n\n/** Options to customize the behavior of the SuperExpress application. */\nexport interface Options {\n /** The name of the application. @default 'default-name' */\n name?: string;\n /** The version of the application. @default 'default-version' */\n version?: string;\n /** Enables or disables body parser middleware. if given a string, will be used as the limit for body size @default '1000mb' */\n bodyParser?: boolean | string;\n /** Enables or disables security headers middleware. @default true */\n helmet?: boolean;\n /** Enables or disables HTTP request logging middleware. @default true */\n morgan?: boolean;\n /** Enables or disables the stats endpoint middleware. @default true */\n stats?: boolean;\n /** Enables or disables request tracing middleware. @default true */\n tracing?: boolean;\n /** Enables or disables eager loading of user permissions for tracing middleware. @default true */\n eagerLoadUserPermissions?: boolean;\n /** The servers logger instance. */\n logger: LoggerInstanceManager;\n /** HealthManager options to create a HealthManager instance for application health and graceful shutdown */\n healthManagerOptions?: Omit<HealthManagerOptions, 'logger'>;\n}\n\nexport const defaultOptions: Omit<Options, 'logger'> = {\n bodyParser: '1000mb',\n helmet: true,\n morgan: true,\n stats: true,\n tracing: true,\n eagerLoadUserPermissions: true,\n} satisfies Omit<Options, 'logger'>;\n","","import type { Server } from 'node:http';\nimport crypto from 'node:crypto';\nimport express from 'express';\nimport { HealthManager } from '@autofleet/nitur';\nimport { defaultOptions, type Options } from '../config/default-options.js';\nimport { version } from '../package.json' with { type: 'json' };\n\n/** Extended express.Application interface which includes nativeListen and the overridden listen method. */\ninterface SuperExpressApp extends Omit<express.Application, 'listen'> {\n /** Original express listen method. */\n nativeListen: express.Application['listen'];\n\n /**\n * Overridden listen method to add custom behavior.\n * @param port - The port number to listen on.\n * @param cb - Optional callback function to execute after the server starts listening.\n */\n listen(port: number, cb?: () => void): Server;\n}\n\n/**\n * Creates a new SuperExpress application with the given options.\n * @param options Optional settings to customize the application.\n * @returns A SuperExpress application instance.\n */\nexport function superExpress({ logger, ...options }: Options): SuperExpressApp {\n const app = express();\n // REMOVE query parameter limit, as it can cause issues with large payloads: https://github.com/expressjs/express/issues/5878\n // Additionally, remove the `arrayLimit` behavior, which changed in `qs@6.14.1` to 20, to solve a CVE, while being a breaking change. See https://github.com/ljharb/qs/issues/537\n app.set('query parser', false);\n app.use((req, _res, next) => (req.query = undefined!, next()), express.query({ parameterLimit: Infinity, arrayLimit: Infinity }));\n const mergedOptions = { ...defaultOptions, ...options };\n\n // Create HealthManager instance if options are provided\n let healthManager: HealthManager;\n\n /** Formatting */\n if (mergedOptions.morgan) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const morgan = require('morgan') as typeof import('morgan');\n logger.debug('[SuperExpress] formatting is enabled ✅');\n app.use(morgan((tokens, req, res) => {\n const values = {\n method: tokens.method(req, res),\n url: tokens.url(req, res) ?? 'unknown URL',\n status: tokens.status(req, res),\n contentLength: tokens.res(req, res, 'content-length'),\n responseTime: tokens['response-time'](req, res) ?? '0',\n userAgent: tokens['user-agent'](req, res),\n };\n logger.info(values.url, {\n httpRequest: {\n status: values.status,\n requestUrl: values.url,\n requestMethod: values.method,\n responseSize: values.contentLength,\n latency: {\n seconds: Number.parseInt(values.responseTime, 10) / 1_000,\n nanos: Number.parseInt(values.responseTime, 10) * 1_000_000,\n },\n userAgent: values.userAgent,\n },\n });\n return undefined;\n }));\n }\n /** Security */\n if (mergedOptions.helmet) {\n logger.debug('[SuperExpress] security is enabled ✅');\n // this is what helmet does by default. https://helmetjs.github.io/faq/you-might-not-need-helmet/\n\n // Middleware to generate nonce per request and set security headers\n app.use((_req, res, next) => {\n // Generate a random nonce for this request\n const nonce = crypto.randomBytes(16).toString('base64');\n\n // Store nonce in res.locals so it can be accessed in templates\n res.locals.cspNonce = nonce;\n\n const HEADERS = {\n 'Content-Security-Policy':\n // eslint-disable-next-line @stylistic/max-len\n `default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${nonce}';script-src-attr 'none';style-src 'self' https: 'nonce-${nonce}';upgrade-insecure-requests`,\n 'Cross-Origin-Opener-Policy': 'same-origin',\n 'Cross-Origin-Resource-Policy': 'same-origin',\n 'Origin-Agent-Cluster': '?1',\n 'Referrer-Policy': 'no-referrer',\n 'Strict-Transport-Security': 'max-age=15552000; includeSubDomains',\n 'X-Content-Type-Options': 'nosniff',\n 'X-DNS-Prefetch-Control': 'off',\n 'X-Download-Options': 'noopen',\n 'X-Frame-Options': 'SAMEORIGIN',\n 'X-Permitted-Cross-Domain-Policies': 'none',\n 'X-XSS-Protection': '0',\n };\n\n res.set(HEADERS);\n next();\n });\n app.disable('x-powered-by');\n } else {\n logger.warn('[SuperExpress] security headers are disabled 😨');\n }\n /** Body Parser */\n if (mergedOptions.bodyParser) {\n logger.debug('[SuperExpress] body-parser is enabled ✅');\n const limit = typeof mergedOptions.bodyParser === 'string' ? mergedOptions.bodyParser : '1000mb';\n app.use(express.json({ limit }));\n } else {\n logger.debug('[SuperExpress] body-parser is disabled ❌');\n }\n /** Alive/Ready Endpoints */\n if (mergedOptions.healthManagerOptions) {\n healthManager = new HealthManager({\n ...mergedOptions.healthManagerOptions,\n logger,\n });\n\n app.get('/alive', async (_req, res) => {\n try {\n const result = await healthManager.aliveCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n app.get('/ready', async (_req, res) => {\n try {\n const result = await healthManager.readyCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n logger.debug('[SuperExpress] added /alive and /ready endpoints with HealthManager ✅');\n }\n /** Stats Endpoint */\n if (mergedOptions.stats) {\n const serverRunningSince = new Date();\n app.get('/stats', (_req, res) => {\n res.json({\n name: mergedOptions.name || 'default-name',\n version: mergedOptions.version || 'default-version',\n serverRunningSince,\n });\n });\n logger.debug('[SuperExpress] added /stats endpoint ✅');\n }\n /** Tracing */\n if (mergedOptions.tracing) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { enableTracing, middleware } = require('@autofleet/zehut') as typeof import('@autofleet/zehut');\n enableTracing({ logger });\n\n app.use(middleware({\n eagerLoadUserPermissions: mergedOptions.eagerLoadUserPermissions,\n }));\n logger.debug('[SuperExpress] tracing is enabled ✅');\n }\n\n const nativeListen: typeof app['listen'] = app.listen.bind(app);\n app.listen = function (port: number, callback?: () => void) {\n const isProd = process.env.NODE_ENV === 'production';\n logger.debug(`[SuperExpress] is started with version ${version || 'unknown'}`);\n logger.debug(`[SuperExpress] will listen on port ${port}`);\n logger.debug(`[SuperExpress] production mode: ${isProd}`);\n\n const server = nativeListen(port, callback);\n\n // Attach server to HealthManager for graceful shutdown (if provided)\n if (healthManager) {\n healthManager.attachServer({ connection: server });\n logger.debug('[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅');\n }\n\n return server;\n } as typeof app['listen'];\n\n return Object.assign(app, { nativeListen }) as SuperExpressApp;\n}\n\nexport default superExpress;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["defaultOptions: Omit<Options, 'logger'>","healthManager: HealthManager","error: any","nativeListen: typeof app['listen']"],"sources":["../config/default-options.ts","../package.json","../src/index.ts"],"sourcesContent":["import type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { HealthManagerOptions } from '@autofleet/nitur';\n\n/** Options to customize the behavior of the SuperExpress application. */\nexport interface Options {\n /** The name of the application. @default 'default-name' */\n name?: string;\n /** The version of the application. @default 'default-version' */\n version?: string;\n /** Enables or disables body parser middleware. if given a string, will be used as the limit for body size @default '1000mb' */\n bodyParser?: boolean | string;\n /** Enables or disables security headers middleware. @default true */\n helmet?: boolean;\n /** Enables or disables HTTP request logging middleware. @default true */\n morgan?: boolean;\n /** Enables or disables the stats endpoint middleware. @default true */\n stats?: boolean;\n /** Enables or disables request tracing middleware. @default true */\n tracing?: boolean;\n /** Enables or disables eager loading of user permissions for tracing middleware. @default true */\n eagerLoadUserPermissions?: boolean;\n /** The servers logger instance. */\n logger: LoggerInstanceManager;\n /** HealthManager options to create a HealthManager instance for application health and graceful shutdown */\n healthManagerOptions?: Omit<HealthManagerOptions, 'logger'>;\n}\n\nexport const defaultOptions: Omit<Options, 'logger'> = {\n bodyParser: '1000mb',\n helmet: true,\n morgan: true,\n stats: true,\n tracing: true,\n eagerLoadUserPermissions: true,\n} satisfies Omit<Options, 'logger'>;\n","","import type { Server } from 'node:http';\nimport crypto from 'node:crypto';\nimport express from 'express';\nimport { HealthManager } from '@autofleet/nitur';\nimport { defaultOptions, type Options } from '../config/default-options.js';\nimport { version } from '../package.json' with { type: 'json' };\n\n/** Extended express.Application interface which includes nativeListen and the overridden listen method. */\ninterface SuperExpressApp extends Omit<express.Application, 'listen'> {\n /** Original express listen method. */\n nativeListen: express.Application['listen'];\n\n /**\n * Overridden listen method to add custom behavior.\n * @param port - The port number to listen on.\n * @param cb - Optional callback function to execute after the server starts listening.\n */\n listen(port: number, cb?: () => void): Server;\n}\n\n/**\n * Creates a new SuperExpress application with the given options.\n * @param options Optional settings to customize the application.\n * @returns A SuperExpress application instance.\n */\nexport function superExpress({ logger, ...options }: Options): SuperExpressApp {\n const app = express();\n // REMOVE query parameter limit, as it can cause issues with large payloads: https://github.com/expressjs/express/issues/5878\n // Additionally, remove the `arrayLimit` behavior, which changed in `qs@6.14.1` to 20, to solve a CVE, while being a breaking change. See https://github.com/ljharb/qs/issues/537\n app.set('query parser', false);\n app.use((req, _res, next) => (req.query = undefined!, next()), express.query({ parameterLimit: Infinity, arrayLimit: Infinity }));\n const mergedOptions = { ...defaultOptions, ...options };\n\n // Create HealthManager instance if options are provided\n let healthManager: HealthManager;\n\n /** Formatting */\n if (mergedOptions.morgan) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const morgan = require('morgan') as typeof import('morgan');\n logger.debug('[SuperExpress] formatting is enabled ✅');\n app.use(morgan((tokens, req, res) => {\n const values = {\n method: tokens.method(req, res),\n url: tokens.url(req, res) ?? 'unknown URL',\n status: tokens.status(req, res),\n contentLength: tokens.res(req, res, 'content-length'),\n responseTime: tokens['response-time'](req, res) ?? '0',\n userAgent: tokens['user-agent'](req, res),\n };\n logger.info(values.url, {\n httpRequest: {\n status: values.status,\n requestUrl: values.url,\n requestMethod: values.method,\n responseSize: values.contentLength,\n latency: {\n seconds: Number.parseInt(values.responseTime, 10) / 1_000,\n nanos: Number.parseInt(values.responseTime, 10) * 1_000_000,\n },\n userAgent: values.userAgent,\n },\n });\n return undefined;\n }));\n }\n /** Security */\n if (mergedOptions.helmet) {\n logger.debug('[SuperExpress] security is enabled ✅');\n // this is what helmet does by default. https://helmetjs.github.io/faq/you-might-not-need-helmet/\n\n // Middleware to generate nonce per request and set security headers\n app.use((_req, res, next) => {\n // Generate a random nonce for this request\n const nonce = crypto.randomBytes(16).toString('base64');\n\n // Store nonce in res.locals so it can be accessed in templates\n res.locals.cspNonce = nonce;\n\n const HEADERS = {\n 'Content-Security-Policy':\n // eslint-disable-next-line @stylistic/max-len\n `default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' 'nonce-${nonce}';script-src-attr 'none';style-src 'self' https: 'nonce-${nonce}';upgrade-insecure-requests`,\n 'Cross-Origin-Opener-Policy': 'same-origin',\n 'Cross-Origin-Resource-Policy': 'same-origin',\n 'Origin-Agent-Cluster': '?1',\n 'Referrer-Policy': 'no-referrer',\n 'Strict-Transport-Security': 'max-age=15552000; includeSubDomains',\n 'X-Content-Type-Options': 'nosniff',\n 'X-DNS-Prefetch-Control': 'off',\n 'X-Download-Options': 'noopen',\n 'X-Frame-Options': 'SAMEORIGIN',\n 'X-Permitted-Cross-Domain-Policies': 'none',\n 'X-XSS-Protection': '0',\n };\n\n res.set(HEADERS);\n next();\n });\n app.disable('x-powered-by');\n } else {\n logger.warn('[SuperExpress] security headers are disabled 😨');\n }\n /** Body Parser */\n if (mergedOptions.bodyParser) {\n logger.debug('[SuperExpress] body-parser is enabled ✅');\n const limit = typeof mergedOptions.bodyParser === 'string' ? mergedOptions.bodyParser : '1000mb';\n app.use(express.json({ limit }));\n } else {\n logger.debug('[SuperExpress] body-parser is disabled ❌');\n }\n /** Alive/Ready Endpoints */\n if (mergedOptions.healthManagerOptions) {\n healthManager = new HealthManager({\n ...mergedOptions.healthManagerOptions,\n logger,\n });\n\n app.get('/alive', async (_req, res) => {\n try {\n const result = await healthManager.aliveCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n app.get('/ready', async (_req, res) => {\n try {\n const result = await healthManager.readyCheck();\n res.status(result.statusCode).json({ status: result.status });\n } catch (error: any) {\n const body = error.body?.() || { status: 'ERROR', errors: [error.message] };\n res.status(error.statusCode || 503).json(body);\n }\n });\n\n logger.debug('[SuperExpress] added /alive and /ready endpoints with HealthManager ✅');\n }\n /** Stats Endpoint */\n if (mergedOptions.stats) {\n const serverRunningSince = new Date();\n app.get('/stats', (_req, res) => {\n res.json({\n name: mergedOptions.name || 'default-name',\n version: mergedOptions.version || 'default-version',\n serverRunningSince,\n });\n });\n logger.debug('[SuperExpress] added /stats endpoint ✅');\n }\n /** Tracing */\n if (mergedOptions.tracing) {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { enableTracing, middleware } = require('@autofleet/zehut') as typeof import('@autofleet/zehut');\n enableTracing({ logger });\n\n app.use(middleware({\n eagerLoadUserPermissions: mergedOptions.eagerLoadUserPermissions,\n }));\n logger.debug('[SuperExpress] tracing is enabled ✅');\n }\n\n const nativeListen: typeof app['listen'] = app.listen.bind(app);\n app.listen = function (port: number, callback?: () => void) {\n const isProd = process.env.NODE_ENV === 'production';\n logger.debug(`[SuperExpress] is started with version ${version || 'unknown'}`);\n logger.debug(`[SuperExpress] will listen on port ${port}`);\n logger.debug(`[SuperExpress] production mode: ${isProd}`);\n\n const server = nativeListen(port, callback);\n\n // Attach server to HealthManager for graceful shutdown (if provided)\n if (healthManager) {\n healthManager.attachServer({ connection: server });\n logger.debug('[SuperExpress] HTTP server attached to HealthManager for graceful shutdown ✅');\n }\n\n return server;\n } as typeof app['listen'];\n\n return Object.assign(app, { nativeListen }) as SuperExpressApp;\n}\n\nexport default superExpress;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/super-express",
3
- "version": "8.3.10-beta-859c5e8b.0",
3
+ "version": "8.4.0",
4
4
  "description": "AF Express with built in boilerplate",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,9 +43,9 @@
43
43
  "@types/supertest": "^6.0.2",
44
44
  "morgan": "^1.10.0",
45
45
  "supertest": "^7.0.0",
46
- "@autofleet/logger": "^4.2.51",
47
- "@autofleet/zehut": "^4.13.0-beta-72227c92.0",
48
- "@autofleet/nitur": "^2.5.4"
46
+ "@autofleet/nitur": "^2.6.0",
47
+ "@autofleet/zehut": "^4.12.0",
48
+ "@autofleet/logger": "^4.2.51"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@autofleet/logger": ">=4.0.0",