1 | import * as express from 'express';
|
2 | import * as cors from 'cors';
|
3 | import * as cookieParser from 'cookie-parser';
|
4 | import * as bodyParser from 'body-parser';
|
5 | import { R, log, constants, fsPath } from '../libs';
|
6 |
|
7 | const listEndpoints = require('express-list-endpoints');
|
8 |
|
9 | export const Router = express.Router;
|
10 | export { staticRoutes } from './middleware/staticRoutes';
|
11 |
|
12 | export type Request = express.Request;
|
13 | export type Response = express.Response;
|
14 |
|
15 | const IS_PRODUCTION = process.env.NODE_ENV === 'production';
|
16 |
|
17 | interface IErrorStack {
|
18 | message: string;
|
19 | stack: string[];
|
20 | }
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | function formatErrorStack(stack: string = ''): IErrorStack {
|
26 | const lines = stack.split('\n');
|
27 | const message = lines[0];
|
28 | lines.shift();
|
29 | return {
|
30 | message,
|
31 | stack: lines.map(line => line.trim()),
|
32 | };
|
33 | }
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | export function sendError(code: number, res: express.Response, err: Error) {
|
40 | const error = IS_PRODUCTION ? err.message : formatErrorStack(err.stack);
|
41 | res.status(code).send({
|
42 | status: code,
|
43 | error,
|
44 | });
|
45 | }
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | export function app(
|
51 | options: {
|
52 | cors?: cors.CorsOptions;
|
53 | json?: bodyParser.OptionsJson;
|
54 | static?: string;
|
55 | } = {},
|
56 | ) {
|
57 | const app = express()
|
58 | .use(cors(options.cors))
|
59 | .use(bodyParser.json(options.json) as any)
|
60 | .use(cookieParser());
|
61 |
|
62 | if (options.static) {
|
63 | app.use(express.static(options.static));
|
64 | }
|
65 |
|
66 | return app;
|
67 | }
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | export function router() {
|
78 | const routes = express.Router();
|
79 | return routes as express.Router;
|
80 | }
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | export function routes(router: express.Router): RouteInfo[] {
|
86 | const items = listEndpoints(router) as RouteInfo[];
|
87 | return items.reduce(
|
88 | (acc, next) => {
|
89 | const index = acc.findIndex(r => r.path === next.path);
|
90 | if (index > -1) {
|
91 |
|
92 | const route = items[index];
|
93 | route.methods = R.uniq([...route.methods, ...next.methods]);
|
94 | return acc;
|
95 | }
|
96 | return [...acc, next];
|
97 | },
|
98 | [] as RouteInfo[],
|
99 | );
|
100 | }
|
101 | export type RouteInfo = {
|
102 | path: string;
|
103 | methods: Array<'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'>;
|
104 | };
|
105 |
|
106 |
|
107 |
|
108 |
|
109 | export function logStarted(port: number, args: {} = {}) {
|
110 | const PACKAGE = require(fsPath.resolve('./package.json'));
|
111 | log.info(`\n> Ready on ${log.cyan('localhost')}:${log.magenta(port)}`);
|
112 | log.info();
|
113 | log.info.gray(` name: ${log.white(PACKAGE.name)}@${PACKAGE.version}`);
|
114 | log.info.gray(` dev: ${constants.IS_DEV}`);
|
115 | log.info();
|
116 | }
|