@autofleet/super-express 5.0.0 → 6.0.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/README.md +5 -8
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -11
- package/.nvmrc +0 -1
- package/config/default-options.json +0 -10
- package/src/index.d.ts +0 -86
- package/src/index.js +0 -94
- package/test/index.test.js +0 -80
- package/test/mock-package.json +0 -1
package/README.md
CHANGED
@@ -35,10 +35,9 @@ const options = {
|
|
35
35
|
morgan: true,
|
36
36
|
nitur: true,
|
37
37
|
stats: true,
|
38
|
-
packageJsonPath: './package.json',
|
39
38
|
tracing: true,
|
40
39
|
eagerLoadUserPermissions: true,
|
41
|
-
aliveEndpointOptions: {
|
40
|
+
aliveEndpointOptions: { sequelize },
|
42
41
|
};
|
43
42
|
|
44
43
|
const app = await createSuperExpressApp(options);
|
@@ -52,12 +51,11 @@ app.listen(3000, () => {
|
|
52
51
|
|
53
52
|
You can customize the behavior of SuperExpress by passing an options object:
|
54
53
|
|
55
|
-
- `bodyParser` (boolean): Enables or disables the body parser middleware.
|
54
|
+
- `bodyParser` (boolean|string): Enables or disables the body parser middleware.
|
56
55
|
- `helmet` (boolean): Enables or disables security headers.
|
57
56
|
- `morgan` (boolean): Enables or disables HTTP request logging.
|
58
57
|
- `nitur` (boolean): Enables or disables the alive endpoint.
|
59
58
|
- `stats` (boolean): Enables or disables the stats endpoint.
|
60
|
-
- `packageJsonPath` (string): Path to the `package.json` file for the stats endpoint.
|
61
59
|
- `tracing` (boolean): Enables or disables request tracing.
|
62
60
|
- `eagerLoadUserPermissions` (boolean): Enables or disables eager loading of user permissions for tracing middleware.
|
63
61
|
- `aliveEndpointOptions` (object): Options to customize the alive endpoint.
|
@@ -72,7 +70,7 @@ You can customize the behavior of SuperExpress by passing an options object:
|
|
72
70
|
|
73
71
|
### Stats Endpoint
|
74
72
|
|
75
|
-
- **Path**:
|
73
|
+
- **Path**: `/stats`
|
76
74
|
- **Method**: `GET`
|
77
75
|
- **Description**: Provides server and application statistics.
|
78
76
|
|
@@ -81,7 +79,7 @@ You can customize the behavior of SuperExpress by passing an options object:
|
|
81
79
|
This project uses Node.js's built-in test runner for testing. To run the tests, execute:
|
82
80
|
|
83
81
|
```bash
|
84
|
-
node --
|
82
|
+
node --run test
|
85
83
|
```
|
86
84
|
|
87
85
|
## Example
|
@@ -97,10 +95,9 @@ const options = {
|
|
97
95
|
morgan: true,
|
98
96
|
nitur: true,
|
99
97
|
stats: true,
|
100
|
-
packageJsonPath: './package.json',
|
101
98
|
tracing: true,
|
102
99
|
eagerLoadUserPermissions: true,
|
103
|
-
aliveEndpointOptions: {
|
100
|
+
aliveEndpointOptions: { sequelize },
|
104
101
|
};
|
105
102
|
|
106
103
|
const app = await createSuperExpressApp(options);
|
package/dist/index.cjs
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
'use strict';var l=require('node:fs'),f=require('node:path'),node_module=require('node:module'),c=require('express');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var l__default=/*#__PURE__*/_interopDefault(l);var f__default=/*#__PURE__*/_interopDefault(f);var c__default=/*#__PURE__*/_interopDefault(c);var d={bodyParser:"1000mb",helmet:true,morgan:true,nitur:true,stats:true,tracing:true,eagerLoadUserPermissions:true};var p=node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))),g=JSON.parse(l__default.default.readFileSync(f__default.default.resolve(undefined,"../package.json"),"utf8"));function S({logger:e,...m}){let o=c__default.default(),r={...d,...m};if(r.morgan){let t=p("morgan");e.debug("[SuperExpress] formatting is enabled \u2705"),o.use(t((n,s,i)=>{let a={method:n.method(s,i),url:n.url(s,i)??"unknown URL",status:n.status(s,i),contentLength:n.res(s,i,"content-length"),responseTime:n["response-time"](s,i)??"0",userAgent:n["user-agent"](s,i)};e.info(a.url,{httpRequest:{status:a.status,requestUrl:a.url,requestMethod:a.method,responseSize:a.contentLength,latency:{seconds:Number.parseInt(a.responseTime,10)/1e3,nanos:Number.parseInt(a.responseTime,10)*1e6},userAgent:a.userAgent}});}));}if(r.helmet){e.debug("[SuperExpress] security is enabled \u2705");let t={"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';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';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"};o.use((n,s,i)=>{s.set(t),i();}),o.disable("x-powered-by");}else e.warn("[SuperExpress] security headers are disabled \u{1F628}");if(r.bodyParser){e.debug("[SuperExpress] body-parser is enabled \u2705");let t=typeof r.bodyParser=="string"?r.bodyParser:"1000mb";o.use(c__default.default.json({limit:t}));}else e.debug("[SuperExpress] body-parser is disabled \u274C");if(r.nitur){let{aliveEndpoint:t}=p("@autofleet/nitur");o.get("/alive",t({logger:e,...r.aliveEndpointOptions})),e.debug("[SuperExpress] added /alive endpoint \u2705");}if(r.stats){let t=new Date;o.get("/stats",(n,s)=>{s.json({name:r.name||"default-name",version:r.version||"default-version",serverRunningSince:t});}),e.debug("[SuperExpress] added /stats endpoint \u2705");}if(r.tracing){let{enableTracing:t,middleware:n,outbreak:s}=p("@autofleet/zehut");t(),e.addContextMiddleware(()=>({traceId:s.getCurrentContext()?.context?.get("x-trace-id")})),o.use(n({eagerLoadUserPermissions:r.eagerLoadUserPermissions})),e.debug("[SuperExpress] tracing is enabled \u2705");}let u=o.listen.bind(o);return o.listen=function(t,n){let s=process.env.NODE_ENV==="production",i=g?.version||"unknown";return e.debug(`[SuperExpress] is started with version ${i}`),e.debug(`[SuperExpress] will listen on port ${t}`),e.debug(`[SuperExpress] production mode: ${s}`),u(t,n)},Object.assign(o,{nativeListen:u})}module.exports=S;//# sourceMappingURL=index.cjs.map
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../config/default-options.ts","../src/index.ts"],"names":["defaultOptions","safeRequire","createRequire","packageJson","fs","path","superExpress","logger","options","app","express","mergedOptions","morgan","tokens","req","res","values","HEADERS","_req","next","limit","aliveEndpoint","serverRunningSince","enableTracing","middleware","outbreak","nativeListen","port","callback","isProd","version"],"mappings":"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","file":"index.cjs","sourcesContent":["import { LoggerInstanceManager } from '@autofleet/logger';\nimport { aliveEndpoint } 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 alive endpoint middleware. @default true */\n nitur?: 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 /** Options to customize the alive endpoint middleware. */\n aliveEndpointOptions?: Omit<Parameters<typeof aliveEndpoint>[0], 'logger'>;\n /** The servers logger instance. */\n logger: LoggerInstanceManager;\n}\n\nexport const defaultOptions = {\n bodyParser: '1000mb',\n helmet: true,\n morgan: true,\n nitur: true,\n stats: true,\n tracing: true,\n eagerLoadUserPermissions: true,\n} satisfies Omit<Options, 'logger'>;","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Server } from 'node:http';\nimport { createRequire } from 'node:module';\nimport express from 'express';\nimport { defaultOptions, Options } from '../config/default-options.js';\n\nconst safeRequire = createRequire(import.meta.url);\n\nconst packageJson = JSON.parse(fs.readFileSync(path.resolve(import.meta.dirname, '../package.json'), 'utf8'));\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 * @param expressOptions - Optional settings to customize express.\n * @returns A SuperExpress application instance.\n */\nexport default function superExpress({ logger, ...options }: Options): SuperExpressApp {\n const app = express();\n const mergedOptions = { ...defaultOptions, ...options };\n /** Formatting */\n if (mergedOptions.morgan) {\n const morgan = safeRequire('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 const HEADERS = {\n \"Content-Security-Policy\":\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';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';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 app.use((_req, res, next) => {\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 Endpoint */\n if (mergedOptions.nitur) {\n const { aliveEndpoint } = safeRequire('@autofleet/nitur') as typeof import('@autofleet/nitur');\n app.get('/alive', aliveEndpoint({ logger, ...mergedOptions.aliveEndpointOptions }));\n logger.debug('[SuperExpress] added /alive endpoint ✅');\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 const { enableTracing, middleware, outbreak } = safeRequire('@autofleet/zehut') as typeof import('@autofleet/zehut');\n enableTracing();\n logger.addContextMiddleware(() => ({\n traceId: outbreak.getCurrentContext()?.context?.get('x-trace-id'),\n }));\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 const version = packageJson?.version || 'unknown';\n logger.debug(`[SuperExpress] is started with version ${version}`);\n logger.debug(`[SuperExpress] will listen on port ${port}`);\n logger.debug(`[SuperExpress] production mode: ${isProd}`);\n return nativeListen(port, callback)\n } as typeof app['listen'];\n\n return Object.assign(app, { nativeListen }) as SuperExpressApp;\n};"]}
|
package/dist/index.d.cts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
import { Server } from 'node:http';
|
2
|
+
import express from 'express';
|
3
|
+
import { LoggerInstanceManager } from '@autofleet/logger';
|
4
|
+
import { aliveEndpoint } from '@autofleet/nitur';
|
5
|
+
|
6
|
+
/** Options to customize the behavior of the SuperExpress application. */
|
7
|
+
interface Options {
|
8
|
+
/** The name of the application. @default 'default-name' */
|
9
|
+
name?: string;
|
10
|
+
/** The version of the application. @default 'default-version' */
|
11
|
+
version?: string;
|
12
|
+
/** Enables or disables body parser middleware. if given a string, will be used as the limit for body size @default '1000mb' */
|
13
|
+
bodyParser?: boolean | string;
|
14
|
+
/** Enables or disables security headers middleware. @default true */
|
15
|
+
helmet?: boolean;
|
16
|
+
/** Enables or disables HTTP request logging middleware. @default true */
|
17
|
+
morgan?: boolean;
|
18
|
+
/** Enables or disables the alive endpoint middleware. @default true */
|
19
|
+
nitur?: boolean;
|
20
|
+
/** Enables or disables the stats endpoint middleware. @default true */
|
21
|
+
stats?: boolean;
|
22
|
+
/** Enables or disables request tracing middleware. @default true */
|
23
|
+
tracing?: boolean;
|
24
|
+
/** Enables or disables eager loading of user permissions for tracing middleware. @default true */
|
25
|
+
eagerLoadUserPermissions?: boolean;
|
26
|
+
/** Options to customize the alive endpoint middleware. */
|
27
|
+
aliveEndpointOptions?: Omit<Parameters<typeof aliveEndpoint>[0], 'logger'>;
|
28
|
+
/** The servers logger instance. */
|
29
|
+
logger: LoggerInstanceManager;
|
30
|
+
}
|
31
|
+
|
32
|
+
/** Extended express.Application interface which includes nativeListen and the overridden listen method. */
|
33
|
+
interface SuperExpressApp extends Omit<express.Application, 'listen'> {
|
34
|
+
/** Original express listen method. */
|
35
|
+
nativeListen: express.Application['listen'];
|
36
|
+
/**
|
37
|
+
* Overridden listen method to add custom behavior.
|
38
|
+
* @param port - The port number to listen on.
|
39
|
+
* @param cb - Optional callback function to execute after the server starts listening.
|
40
|
+
*/
|
41
|
+
listen(port: number, cb?: () => void): Server;
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Creates a new SuperExpress application with the given options.
|
45
|
+
* @param options - Optional settings to customize the application.
|
46
|
+
* @param expressOptions - Optional settings to customize express.
|
47
|
+
* @returns A SuperExpress application instance.
|
48
|
+
*/
|
49
|
+
declare function superExpress({ logger, ...options }: Options): SuperExpressApp;
|
50
|
+
|
51
|
+
export { superExpress as default };
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
import { Server } from 'node:http';
|
2
|
+
import express from 'express';
|
3
|
+
import { LoggerInstanceManager } from '@autofleet/logger';
|
4
|
+
import { aliveEndpoint } from '@autofleet/nitur';
|
5
|
+
|
6
|
+
/** Options to customize the behavior of the SuperExpress application. */
|
7
|
+
interface Options {
|
8
|
+
/** The name of the application. @default 'default-name' */
|
9
|
+
name?: string;
|
10
|
+
/** The version of the application. @default 'default-version' */
|
11
|
+
version?: string;
|
12
|
+
/** Enables or disables body parser middleware. if given a string, will be used as the limit for body size @default '1000mb' */
|
13
|
+
bodyParser?: boolean | string;
|
14
|
+
/** Enables or disables security headers middleware. @default true */
|
15
|
+
helmet?: boolean;
|
16
|
+
/** Enables or disables HTTP request logging middleware. @default true */
|
17
|
+
morgan?: boolean;
|
18
|
+
/** Enables or disables the alive endpoint middleware. @default true */
|
19
|
+
nitur?: boolean;
|
20
|
+
/** Enables or disables the stats endpoint middleware. @default true */
|
21
|
+
stats?: boolean;
|
22
|
+
/** Enables or disables request tracing middleware. @default true */
|
23
|
+
tracing?: boolean;
|
24
|
+
/** Enables or disables eager loading of user permissions for tracing middleware. @default true */
|
25
|
+
eagerLoadUserPermissions?: boolean;
|
26
|
+
/** Options to customize the alive endpoint middleware. */
|
27
|
+
aliveEndpointOptions?: Omit<Parameters<typeof aliveEndpoint>[0], 'logger'>;
|
28
|
+
/** The servers logger instance. */
|
29
|
+
logger: LoggerInstanceManager;
|
30
|
+
}
|
31
|
+
|
32
|
+
/** Extended express.Application interface which includes nativeListen and the overridden listen method. */
|
33
|
+
interface SuperExpressApp extends Omit<express.Application, 'listen'> {
|
34
|
+
/** Original express listen method. */
|
35
|
+
nativeListen: express.Application['listen'];
|
36
|
+
/**
|
37
|
+
* Overridden listen method to add custom behavior.
|
38
|
+
* @param port - The port number to listen on.
|
39
|
+
* @param cb - Optional callback function to execute after the server starts listening.
|
40
|
+
*/
|
41
|
+
listen(port: number, cb?: () => void): Server;
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Creates a new SuperExpress application with the given options.
|
45
|
+
* @param options - Optional settings to customize the application.
|
46
|
+
* @param expressOptions - Optional settings to customize express.
|
47
|
+
* @returns A SuperExpress application instance.
|
48
|
+
*/
|
49
|
+
declare function superExpress({ logger, ...options }: Options): SuperExpressApp;
|
50
|
+
|
51
|
+
export { superExpress as default };
|
package/dist/index.js
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
import l from'node:fs';import f from'node:path';import {createRequire}from'node:module';import c from'express';var d={bodyParser:"1000mb",helmet:true,morgan:true,nitur:true,stats:true,tracing:true,eagerLoadUserPermissions:true};var p=createRequire(import.meta.url),g=JSON.parse(l.readFileSync(f.resolve(import.meta.dirname,"../package.json"),"utf8"));function S({logger:e,...m}){let o=c(),r={...d,...m};if(r.morgan){let t=p("morgan");e.debug("[SuperExpress] formatting is enabled \u2705"),o.use(t((n,s,i)=>{let a={method:n.method(s,i),url:n.url(s,i)??"unknown URL",status:n.status(s,i),contentLength:n.res(s,i,"content-length"),responseTime:n["response-time"](s,i)??"0",userAgent:n["user-agent"](s,i)};e.info(a.url,{httpRequest:{status:a.status,requestUrl:a.url,requestMethod:a.method,responseSize:a.contentLength,latency:{seconds:Number.parseInt(a.responseTime,10)/1e3,nanos:Number.parseInt(a.responseTime,10)*1e6},userAgent:a.userAgent}});}));}if(r.helmet){e.debug("[SuperExpress] security is enabled \u2705");let t={"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';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';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"};o.use((n,s,i)=>{s.set(t),i();}),o.disable("x-powered-by");}else e.warn("[SuperExpress] security headers are disabled \u{1F628}");if(r.bodyParser){e.debug("[SuperExpress] body-parser is enabled \u2705");let t=typeof r.bodyParser=="string"?r.bodyParser:"1000mb";o.use(c.json({limit:t}));}else e.debug("[SuperExpress] body-parser is disabled \u274C");if(r.nitur){let{aliveEndpoint:t}=p("@autofleet/nitur");o.get("/alive",t({logger:e,...r.aliveEndpointOptions})),e.debug("[SuperExpress] added /alive endpoint \u2705");}if(r.stats){let t=new Date;o.get("/stats",(n,s)=>{s.json({name:r.name||"default-name",version:r.version||"default-version",serverRunningSince:t});}),e.debug("[SuperExpress] added /stats endpoint \u2705");}if(r.tracing){let{enableTracing:t,middleware:n,outbreak:s}=p("@autofleet/zehut");t(),e.addContextMiddleware(()=>({traceId:s.getCurrentContext()?.context?.get("x-trace-id")})),o.use(n({eagerLoadUserPermissions:r.eagerLoadUserPermissions})),e.debug("[SuperExpress] tracing is enabled \u2705");}let u=o.listen.bind(o);return o.listen=function(t,n){let s=process.env.NODE_ENV==="production",i=g?.version||"unknown";return e.debug(`[SuperExpress] is started with version ${i}`),e.debug(`[SuperExpress] will listen on port ${t}`),e.debug(`[SuperExpress] production mode: ${s}`),u(t,n)},Object.assign(o,{nativeListen:u})}export{S as default};//# sourceMappingURL=index.js.map
|
2
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../config/default-options.ts","../src/index.ts"],"names":["defaultOptions","safeRequire","createRequire","packageJson","fs","path","superExpress","logger","options","app","express","mergedOptions","morgan","tokens","req","res","values","HEADERS","_req","next","limit","aliveEndpoint","serverRunningSince","enableTracing","middleware","outbreak","nativeListen","port","callback","isProd","version"],"mappings":"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","file":"index.js","sourcesContent":["import { LoggerInstanceManager } from '@autofleet/logger';\nimport { aliveEndpoint } 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 alive endpoint middleware. @default true */\n nitur?: 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 /** Options to customize the alive endpoint middleware. */\n aliveEndpointOptions?: Omit<Parameters<typeof aliveEndpoint>[0], 'logger'>;\n /** The servers logger instance. */\n logger: LoggerInstanceManager;\n}\n\nexport const defaultOptions = {\n bodyParser: '1000mb',\n helmet: true,\n morgan: true,\n nitur: true,\n stats: true,\n tracing: true,\n eagerLoadUserPermissions: true,\n} satisfies Omit<Options, 'logger'>;","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Server } from 'node:http';\nimport { createRequire } from 'node:module';\nimport express from 'express';\nimport { defaultOptions, Options } from '../config/default-options.js';\n\nconst safeRequire = createRequire(import.meta.url);\n\nconst packageJson = JSON.parse(fs.readFileSync(path.resolve(import.meta.dirname, '../package.json'), 'utf8'));\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 * @param expressOptions - Optional settings to customize express.\n * @returns A SuperExpress application instance.\n */\nexport default function superExpress({ logger, ...options }: Options): SuperExpressApp {\n const app = express();\n const mergedOptions = { ...defaultOptions, ...options };\n /** Formatting */\n if (mergedOptions.morgan) {\n const morgan = safeRequire('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 const HEADERS = {\n \"Content-Security-Policy\":\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';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';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 app.use((_req, res, next) => {\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 Endpoint */\n if (mergedOptions.nitur) {\n const { aliveEndpoint } = safeRequire('@autofleet/nitur') as typeof import('@autofleet/nitur');\n app.get('/alive', aliveEndpoint({ logger, ...mergedOptions.aliveEndpointOptions }));\n logger.debug('[SuperExpress] added /alive endpoint ✅');\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 const { enableTracing, middleware, outbreak } = safeRequire('@autofleet/zehut') as typeof import('@autofleet/zehut');\n enableTracing();\n logger.addContextMiddleware(() => ({\n traceId: outbreak.getCurrentContext()?.context?.get('x-trace-id'),\n }));\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 const version = packageJson?.version || 'unknown';\n logger.debug(`[SuperExpress] is started with version ${version}`);\n logger.debug(`[SuperExpress] will listen on port ${port}`);\n logger.debug(`[SuperExpress] production mode: ${isProd}`);\n return nativeListen(port, callback)\n } as typeof app['listen'];\n\n return Object.assign(app, { nativeListen }) as SuperExpressApp;\n};"]}
|
package/package.json
CHANGED
@@ -1,18 +1,53 @@
|
|
1
1
|
{
|
2
2
|
"name": "@autofleet/super-express",
|
3
|
-
"version": "
|
3
|
+
"version": "6.0.0",
|
4
4
|
"description": "AF Express with built in boilerplate",
|
5
|
-
"
|
5
|
+
"type": "module",
|
6
|
+
"main": "./dist/index.js",
|
7
|
+
"module": "./dist/index.js",
|
8
|
+
"types": "./dist/index.d.ts",
|
9
|
+
"exports": {
|
10
|
+
".": {
|
11
|
+
"import": {
|
12
|
+
"types": "./dist/index.d.ts",
|
13
|
+
"default": "./dist/index.js"
|
14
|
+
},
|
15
|
+
"require": {
|
16
|
+
"types": "./dist/index.d.cts",
|
17
|
+
"default": "./dist/index.cjs"
|
18
|
+
}
|
19
|
+
}
|
20
|
+
},
|
21
|
+
"engines": {
|
22
|
+
"node": ">=18"
|
23
|
+
},
|
6
24
|
"author": "Autofleet",
|
7
25
|
"license": "MIT",
|
26
|
+
"files": [
|
27
|
+
"dist/"
|
28
|
+
],
|
8
29
|
"dependencies": {
|
9
|
-
"@autofleet/nitur": "^1.
|
10
|
-
"@autofleet/zehut": "^3.0
|
11
|
-
"express": "^4.
|
30
|
+
"@autofleet/nitur": "^2.1.0",
|
31
|
+
"@autofleet/zehut": "^3.2.0",
|
32
|
+
"express": "^4.21.2",
|
12
33
|
"morgan": "^1.10.0"
|
13
34
|
},
|
35
|
+
"peerDependencies": {
|
36
|
+
"@autofleet/logger": ">=4.0.0"
|
37
|
+
},
|
38
|
+
"devDependencies": {
|
39
|
+
"@autofleet/logger": "^4.2.1",
|
40
|
+
"@types/express": "^4.17.21",
|
41
|
+
"@types/morgan": "^1.9.9",
|
42
|
+
"@types/supertest": "^6.0.2",
|
43
|
+
"supertest": "^7.0.0",
|
44
|
+
"tsup": "^8.4.0",
|
45
|
+
"tsx": "^4.19.3",
|
46
|
+
"typescript": "^5.8.2"
|
47
|
+
},
|
14
48
|
"scripts": {
|
15
|
-
"test": "
|
49
|
+
"test": "tsx --test",
|
50
|
+
"build": "tsup"
|
16
51
|
},
|
17
52
|
"repository": {
|
18
53
|
"type": "git",
|
@@ -21,9 +56,5 @@
|
|
21
56
|
"bugs": {
|
22
57
|
"url": "https://github.com/Autofleet/super-express/issues"
|
23
58
|
},
|
24
|
-
"homepage": "https://github.com/Autofleet/super-express#readme"
|
25
|
-
"devDependencies": {
|
26
|
-
"@types/express": "^4.17.21",
|
27
|
-
"supertest": "^7.0.0"
|
28
|
-
}
|
59
|
+
"homepage": "https://github.com/Autofleet/super-express#readme"
|
29
60
|
}
|
package/.nvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
20.15.0
|
package/src/index.d.ts
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
import * as express from 'express';
|
2
|
-
|
3
|
-
/**
|
4
|
-
* Options to customize the behavior of the SuperExpress application.
|
5
|
-
*/
|
6
|
-
export interface DefaultOptions {
|
7
|
-
/**
|
8
|
-
* The name of the application.
|
9
|
-
*/
|
10
|
-
name?: string;
|
11
|
-
/**
|
12
|
-
* The version of the application.
|
13
|
-
*/
|
14
|
-
version?: string;
|
15
|
-
/**
|
16
|
-
* Enables or disables body parser middleware.
|
17
|
-
*/
|
18
|
-
bodyParser?: boolean;
|
19
|
-
/**
|
20
|
-
* Enables or disables security headers middleware.
|
21
|
-
*/
|
22
|
-
helmet?: boolean;
|
23
|
-
/**
|
24
|
-
* Enables or disables HTTP request logging middleware.
|
25
|
-
*/
|
26
|
-
morgan?: boolean;
|
27
|
-
/**
|
28
|
-
* Enables or disables the alive endpoint middleware.
|
29
|
-
*/
|
30
|
-
nitur?: boolean;
|
31
|
-
/**
|
32
|
-
* Enables or disables the stats endpoint middleware.
|
33
|
-
*/
|
34
|
-
stats?: boolean;
|
35
|
-
/**
|
36
|
-
* Enables or disables request tracing middleware.
|
37
|
-
*/
|
38
|
-
tracing?: boolean;
|
39
|
-
/**
|
40
|
-
* Enables or disables eager loading of user permissions for tracing middleware.
|
41
|
-
*/
|
42
|
-
eagerLoadUserPermissions?: boolean;
|
43
|
-
/**
|
44
|
-
* Options to customize the alive endpoint middleware.
|
45
|
-
*/
|
46
|
-
aliveEndpointOptions?: Record<string, unknown>;
|
47
|
-
// Add other options from config/default-options.json as needed
|
48
|
-
}
|
49
|
-
|
50
|
-
/**
|
51
|
-
* Type for the callback function used in the listen method.
|
52
|
-
*/
|
53
|
-
export type ListenCallback = () => void;
|
54
|
-
|
55
|
-
type Listen = express.Application['listen'];
|
56
|
-
type Server = Listen extends (port: any, cb: any) => infer R ? R : never;
|
57
|
-
|
58
|
-
/**
|
59
|
-
* Extends the express.Application interface to include nativeListen and the overridden listen method.
|
60
|
-
*/
|
61
|
-
export interface SuperExpressApp extends express.Application {
|
62
|
-
/**
|
63
|
-
* Original express listen method.
|
64
|
-
*/
|
65
|
-
nativeListen: Listen;
|
66
|
-
|
67
|
-
/**
|
68
|
-
* Overridden listen method to add custom behavior.
|
69
|
-
* @param port - The port number to listen on.
|
70
|
-
* @param cb - Optional callback function to execute after the server starts listening.
|
71
|
-
*/
|
72
|
-
listen(port: number, cb?: ListenCallback): Server;
|
73
|
-
}
|
74
|
-
|
75
|
-
/**
|
76
|
-
* Creates a new SuperExpress application with the given options.
|
77
|
-
* @param options - Optional settings to customize the application.
|
78
|
-
* @param expressOptions - Optional settings to customize express.
|
79
|
-
* @returns A SuperExpress application instance.
|
80
|
-
*/
|
81
|
-
declare function createSuperExpressApp(
|
82
|
-
options?: Partial<DefaultOptions>,
|
83
|
-
expressOptions?: express.ApplicationOptions,
|
84
|
-
): SuperExpressApp;
|
85
|
-
|
86
|
-
export = createSuperExpressApp;
|
package/src/index.js
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
const express = require('express');
|
2
|
-
const morgan = require('morgan');
|
3
|
-
const { aliveEndpoint } = require('@autofleet/nitur');
|
4
|
-
const zehut = require('@autofleet/zehut');
|
5
|
-
const { enableTracing } = zehut;
|
6
|
-
const fs = require('fs');
|
7
|
-
const path = require('path');
|
8
|
-
|
9
|
-
const defaultOptions = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../config/default-options.json'), 'utf8'));
|
10
|
-
const packageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'));
|
11
|
-
|
12
|
-
module.exports = function (options = {}, expressOptions = {}) {
|
13
|
-
const app = express(expressOptions);
|
14
|
-
const mergedOptions = Object.assign({}, defaultOptions, options);
|
15
|
-
/** Formatting */
|
16
|
-
if (mergedOptions.morgan) {
|
17
|
-
console.log('[SuperExpress] formatting is enabled ✅');
|
18
|
-
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
19
|
-
}
|
20
|
-
/** Security */
|
21
|
-
if (mergedOptions.helmet) {
|
22
|
-
console.log('[SuperExpress] security is enabled ✅');
|
23
|
-
// this is what helmet does by default. https://helmetjs.github.io/faq/you-might-not-need-helmet/
|
24
|
-
const HEADERS = {
|
25
|
-
"Content-Security-Policy":
|
26
|
-
"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';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests",
|
27
|
-
"Cross-Origin-Opener-Policy": "same-origin",
|
28
|
-
"Cross-Origin-Resource-Policy": "same-origin",
|
29
|
-
"Origin-Agent-Cluster": "?1",
|
30
|
-
"Referrer-Policy": "no-referrer",
|
31
|
-
"Strict-Transport-Security": "max-age=15552000; includeSubDomains",
|
32
|
-
"X-Content-Type-Options": "nosniff",
|
33
|
-
"X-DNS-Prefetch-Control": "off",
|
34
|
-
"X-Download-Options": "noopen",
|
35
|
-
"X-Frame-Options": "SAMEORIGIN",
|
36
|
-
"X-Permitted-Cross-Domain-Policies": "none",
|
37
|
-
"X-XSS-Protection": "0",
|
38
|
-
};
|
39
|
-
app.use((req, res, next) => {
|
40
|
-
res.set(HEADERS);
|
41
|
-
next();
|
42
|
-
});
|
43
|
-
app.disable('x-powered-by');
|
44
|
-
}
|
45
|
-
/** Body Parser */
|
46
|
-
if (mergedOptions.bodyParser) {
|
47
|
-
console.log('[SuperExpress] body-parser is enabled ✅');
|
48
|
-
app.use(express.json({ limit: '1000mb' }))
|
49
|
-
} else {
|
50
|
-
console.log('[SuperExpress] body-parser is disabled ❌');
|
51
|
-
}
|
52
|
-
/** Alive Endpoint */
|
53
|
-
if (mergedOptions.nitur) {
|
54
|
-
app.get('/alive', aliveEndpoint(mergedOptions.aliveEndpointOptions || {}));
|
55
|
-
console.log('[SuperExpress] added /alive endpoint ✅');
|
56
|
-
}
|
57
|
-
/** Stats Endpoint */
|
58
|
-
if (mergedOptions.stats) {
|
59
|
-
const serverRunningSince = new Date();
|
60
|
-
app.get('/stats', (req, res) => {
|
61
|
-
res.json({
|
62
|
-
name: mergedOptions.name || 'default-name',
|
63
|
-
version: mergedOptions.version || 'default-version',
|
64
|
-
serverRunningSince,
|
65
|
-
});
|
66
|
-
});
|
67
|
-
console.log('[SuperExpress] added /stats endpoint ✅');
|
68
|
-
}
|
69
|
-
/** Tracing */
|
70
|
-
if (mergedOptions.tracing) {
|
71
|
-
enableTracing({
|
72
|
-
outbreakOptions: {
|
73
|
-
headersPrefix: 'x-af',
|
74
|
-
},
|
75
|
-
});
|
76
|
-
|
77
|
-
app.use(zehut.middleware({
|
78
|
-
eagerLoadUserPermissions: mergedOptions.eagerLoadUserPermissions,
|
79
|
-
}));
|
80
|
-
console.log('[SuperExpress] tracing is enabled ✅');
|
81
|
-
}
|
82
|
-
|
83
|
-
app.nativeListen = app.listen
|
84
|
-
app.listen = function (port, cb) {
|
85
|
-
const isProd = process.env.NODE_ENV === 'production';
|
86
|
-
const version = packageJson?.version || 'unknown';
|
87
|
-
console.log(`[SuperExpress] is started with version ${version}`);
|
88
|
-
console.log(`[SuperExpress] will listen on port ${port}`);
|
89
|
-
console.log(`[SuperExpress] production mode: ${isProd}`);
|
90
|
-
return app.nativeListen(port, cb)
|
91
|
-
}
|
92
|
-
|
93
|
-
return app
|
94
|
-
};
|
package/test/index.test.js
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
const assert = require('assert').strict;
|
2
|
-
const { test } = require('node:test');
|
3
|
-
const supertest = require('supertest');
|
4
|
-
const createSuperExpressApp = require('../src/index.js');
|
5
|
-
|
6
|
-
// Mock the default-options.json file content
|
7
|
-
const defaultOptions = {
|
8
|
-
bodyParser: true,
|
9
|
-
helmet: true,
|
10
|
-
morgan: true,
|
11
|
-
nitur: true,
|
12
|
-
stats: true,
|
13
|
-
tracing: true,
|
14
|
-
eagerLoadUserPermissions: true,
|
15
|
-
};
|
16
|
-
|
17
|
-
// Test for the existence of default middleware
|
18
|
-
test('should create an app with default middleware', async () => {
|
19
|
-
const app = createSuperExpressApp();
|
20
|
-
|
21
|
-
// Test for the existence of bodyParser middleware
|
22
|
-
await supertest(app)
|
23
|
-
.post('/')
|
24
|
-
.send({ key: 'value' })
|
25
|
-
.expect(404); // Expect 404 because no routes are defined
|
26
|
-
|
27
|
-
// Test for the overridden listen method
|
28
|
-
const originalConsoleLog = console.log;
|
29
|
-
let logOutput = [];
|
30
|
-
console.log = (...args) => logOutput.push(...args);
|
31
|
-
const server = app.listen(3000, () => { });
|
32
|
-
assert(logOutput.includes('[SuperExpress] will listen on port 3000'));
|
33
|
-
|
34
|
-
console.log = originalConsoleLog;
|
35
|
-
server.close();
|
36
|
-
});
|
37
|
-
|
38
|
-
// Test for custom options
|
39
|
-
test('should create an app with custom options', async () => {
|
40
|
-
const app = createSuperExpressApp(defaultOptions);
|
41
|
-
const server = app.listen(3000, () => { });
|
42
|
-
|
43
|
-
// Test for the alive endpoint
|
44
|
-
await supertest(app)
|
45
|
-
.get('/alive')
|
46
|
-
.expect(200);
|
47
|
-
|
48
|
-
// Test for the stats endpoint
|
49
|
-
await supertest(app)
|
50
|
-
.get('/stats')
|
51
|
-
.expect(200)
|
52
|
-
.expect((res) => {
|
53
|
-
assert(res.body.name);
|
54
|
-
assert(res.body.version);
|
55
|
-
assert(res.body.serverRunningSince);
|
56
|
-
});
|
57
|
-
server.close();
|
58
|
-
});
|
59
|
-
|
60
|
-
// Test for disabled body parser
|
61
|
-
test('should disable body parser when option is set to false', async () => {
|
62
|
-
const originalConsoleLog = console.log;
|
63
|
-
let logOutput = [];
|
64
|
-
console.log = (...args) => logOutput.push(...args);
|
65
|
-
|
66
|
-
const app = createSuperExpressApp({ bodyParser: false });
|
67
|
-
const server = app.listen(3000, () => { });
|
68
|
-
|
69
|
-
try {
|
70
|
-
assert(logOutput.includes('[SuperExpress] body-parser is disabled ❌'));
|
71
|
-
await supertest(app)
|
72
|
-
.post('/')
|
73
|
-
.send({ key: 'value' })
|
74
|
-
.expect(404);
|
75
|
-
} finally {
|
76
|
-
console.log = originalConsoleLog;
|
77
|
-
server.close();
|
78
|
-
}
|
79
|
-
|
80
|
-
});
|
package/test/mock-package.json
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"name":"test-package","version":"1.0.0"}
|