huxy-node-server 1.0.0-beta.1 → 1.0.0-beta.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +185 -157
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "huxy-node-server",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.3",
4
4
  "description": "一个精炼、高性能的 Express.js 服务器模板,为现代 Node.js 应用程序设计,提供灵活的功能和最佳实践。",
5
5
  "type": "module",
6
6
  "module": "./src/index.js",
package/src/index.js CHANGED
@@ -1,32 +1,32 @@
1
- import T from 'express';
2
- import V from 'helmet';
3
- import F from 'cors';
4
- import {rateLimit as K, ipKeyGenerator as W} from 'express-rate-limit';
5
- import z from 'compression';
6
- import X from 'pino-http';
7
- import {createServer as B} from 'node:http';
8
- import U from 'pino';
9
- import w from 'node:os';
10
- import D from 'node:net';
11
- var m = (t = new Date()) => t.toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai', hour12: !1}),
12
- l = t => {
13
- let o = t ? 'https' : 'http',
14
- e = w.networkInterfaces(),
1
+ import E from 'express';
2
+ import K from 'helmet';
3
+ import W from 'cors';
4
+ import {rateLimit as z, ipKeyGenerator as X} from 'express-rate-limit';
5
+ import B from 'compression';
6
+ import Q from 'pino-http';
7
+ import {createServer as J} from 'node:http';
8
+ import w from 'pino';
9
+ import M from 'node:os';
10
+ import k from 'node:net';
11
+ var m = (e = new Date()) => e.toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai', hour12: !1}),
12
+ u = e => {
13
+ let o = e ? 'https' : 'http',
14
+ t = M.networkInterfaces(),
15
15
  r = [];
16
- return (Object.keys(e).map(i => r.push(...e[i])), r.filter(i => i.family === 'IPv4').map(i => `${o}://${i.address}`));
16
+ return (Object.keys(t).map(n => r.push(...t[n])), r.filter(n => n.family === 'IPv4').map(n => `${o}://${n.address}`));
17
17
  },
18
- x = t => {
19
- let o = t ?? process.argv.slice(2) ?? [],
20
- e = {};
18
+ x = e => {
19
+ let o = e ?? process.argv.slice(2) ?? [],
20
+ t = {};
21
21
  return (
22
22
  o.map(r => {
23
- let [n, s] = r.split('=');
24
- e[n] = s;
23
+ let [s, i] = r.split('=');
24
+ t[s] = i;
25
25
  }),
26
- e
26
+ t
27
27
  );
28
28
  },
29
- H = {
29
+ U = {
30
30
  NODE_ENV: 'nodeEnv',
31
31
  PORT: 'port',
32
32
  STATIC_PORT: 'staticPort',
@@ -40,34 +40,66 @@ var m = (t = new Date()) => t.toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai'
40
40
  JWT_SECRET: 'secret',
41
41
  AUTH_TOKEN: 'authToken',
42
42
  },
43
- M = (t, o, e) => {
44
- let [r, n] = t.split('.');
45
- r && n ? (e[r] || (e[r] = {}), (e[r][n] = o)) : (e[r] = o);
43
+ j = (e, o, t) => {
44
+ let [r, s] = e.split('.');
45
+ r && s ? (t[r] || (t[r] = {}), (t[r][s] = o)) : (t[r] = o);
46
46
  },
47
- u = (t = {}, o = H) => {
48
- let {env: e} = process;
49
- Object.keys(o).map(n => {
50
- let s = e[n];
51
- s && M(o[n], s, t);
47
+ d = (e = {}, o = U) => {
48
+ let {env: t} = process;
49
+ Object.keys(o).map(s => {
50
+ let i = t[s] ?? e[s];
51
+ i && j(o[s], i, e);
52
52
  });
53
- let r = {...t, ...x()};
53
+ let r = {...e, ...x()};
54
54
  return ((r.port = r.staticPort || r.port), (r.isDev = r.NODE_ENV === 'development'), r);
55
55
  },
56
- d = (t, o = '127.0.0.1') =>
57
- new Promise(e => {
58
- let r = D.createServer();
59
- (r.once('error', n => {
60
- (r.close(), e((n.code === 'EADDRINUSE', !1)));
56
+ f = (e, o = '127.0.0.1') =>
57
+ new Promise(t => {
58
+ let r = k.createServer();
59
+ (r.once('error', s => {
60
+ (r.close(), t((s.code === 'EADDRINUSE', !1)));
61
61
  }),
62
62
  r.once('listening', () => {
63
- (r.close(), e(!0));
63
+ (r.close(), t(!0));
64
64
  }),
65
- r.listen(Number(t), o));
65
+ r.listen(Number(e), o));
66
+ }),
67
+ I = (e, o = {}) => {
68
+ let t = r => {
69
+ (a.warn(`\u6536\u5230 ${r} \u4FE1\u53F7, \u{1F6D1} \u6B63\u5728\u5173\u95ED\u670D\u52A1\u5668...`),
70
+ e.close(async () => {
71
+ (a.info('\u{1F44B} \u670D\u52A1\u5668\u5DF2\u5173\u95ED'), await o.shutdown?.(), process.exit(0));
72
+ }),
73
+ setTimeout(() => {
74
+ (a.error('\u274C \u5F3A\u5236\u5173\u95ED\u670D\u52A1\u5668'), process.exit(1));
75
+ }, 5e3));
76
+ };
77
+ (process.on('SIGTERM', () => t('SIGTERM')),
78
+ process.on('SIGINT', () => t('SIGINT')),
79
+ process.on('uncaughtException', r => {
80
+ (a.fatal(r, `\u{1F4A5} \u672A\u6355\u83B7\u7684\u5F02\u5E38: ${r.message}`), process.exit(1));
81
+ }),
82
+ process.on('unhandledRejection', (r, s) => {
83
+ (a.fatal({reason: r, promise: s}, '\u26A0\uFE0F \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD'), process.exit(1));
84
+ }));
85
+ },
86
+ P = (e, {port: o, host: t = '0.0.0.0'} = {}) =>
87
+ new Promise((r, s) => {
88
+ let i = l => {
89
+ (c(), s(l));
90
+ },
91
+ n = () => {
92
+ (c(), r(e));
93
+ },
94
+ c = () => {
95
+ (e.off('error', i), e.off('listening', n));
96
+ };
97
+ (e.once('error', i), e.once('listening', n), e.listen(o, t));
66
98
  });
67
99
  import 'dotenv';
68
- var k = {
69
- nodeEnv: 'production',
70
- isDev: !1,
100
+ var G = {
101
+ nodeEnv: process.env.NODE_ENV || 'development',
102
+ isDev: process.env.NODE_ENV === 'development',
71
103
  port: parseInt(process.env.PORT || '3000', 10),
72
104
  host: process.env.HOST || '0.0.0.0',
73
105
  basepath: process.env.BASEPATH || '/',
@@ -78,149 +110,145 @@ var k = {
78
110
  message: {error: '\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5'},
79
111
  },
80
112
  helmet: {
81
- contentSecurityPolicy: {directives: {defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], scriptSrc: ["'self'"], imgSrc: ["'self'", 'data:', 'https:']}},
113
+ contentSecurityPolicy: {directives: {defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], scriptSrc: ["'self'", "'unsafe-eval'"], imgSrc: ["'self'", 'data:', 'https:']}},
82
114
  crossOriginEmbedderPolicy: !1,
83
115
  },
84
116
  logLevel: process.env.LOG_LEVEL || 30,
85
117
  },
86
- f = k;
87
- var c = (t, o) =>
88
- U({
89
- name: t,
90
- level: f.logLevel,
91
- transport: {target: 'pino-pretty', options: {colorize: !0, sync: !0}, ignore: 'pid,hostname,level,time', translateTime: 'UTC:yyyy-mm-dd HH:MM:ss', customColors: 'err:red,info:blue'},
118
+ g = G;
119
+ var p = (e, o) =>
120
+ w({
121
+ name: e,
122
+ level: g.logLevel,
123
+ formatters: {level: t => ({level: t})},
124
+ timestamp: w.stdTimeFunctions.isoTime,
125
+ base: null,
126
+ transport: {target: 'pino-pretty', options: {colorize: !0, sync: !0, levelFirst: !0}, ignore: 'pid,hostname,level,time', translateTime: 'SYS:yyyy-mm-dd HH:MM:ss'},
92
127
  ...o,
93
128
  }),
94
- P = () => {
95
- let t = c('http-request');
96
- return (o, e, r) => {
97
- let n = Date.now();
98
- (e.on('finish', () => {
99
- let s = Date.now() - n,
100
- i = {method: o.method, url: o.originalUrl, status: e.statusCode, duration: `${s}ms`, ip: o.ip, userAgent: o.get('User-Agent'), timestamp: m()};
101
- e.statusCode >= 500 ? t.error(i, 'HTTP\u8BF7\u6C42\u9519\u8BEF') : e.statusCode >= 400 ? t.warn(i, 'HTTP\u5BA2\u6237\u7AEF\u9519\u8BEF') : t.info(i, 'HTTP\u8BF7\u6C42');
129
+ L = () => {
130
+ let e = p('http-request');
131
+ return (o, t, r) => {
132
+ let s = Date.now();
133
+ (t.on('finish', () => {
134
+ let i = Date.now() - s,
135
+ n = {method: o.method, url: o.originalUrl, status: t.statusCode, duration: `${i}ms`, ip: o.ip, userAgent: o.get('User-Agent'), timestamp: m()};
136
+ t.statusCode >= 500 ? e.error(n, 'HTTP\u8BF7\u6C42\u9519\u8BEF') : t.statusCode >= 400 && e.warn(n, 'HTTP\u5BA2\u6237\u7AEF\u9519\u8BEF');
102
137
  }),
103
138
  r());
104
139
  };
105
140
  },
106
- a = c('huxy');
107
- var y = c('error-handler'),
108
- b = t => (o, e, r) => {
109
- (y.error({message: 'Not Found', timestamp: m(), url: o.originalUrl, method: o.method, ip: o.ip, userAgent: o.get('User-Agent')}, '\u627E\u4E0D\u5230\u8DEF\u5F84'),
110
- e.status(404).json({success: !1, timestamp: m(), status: 404, message: `\u8DEF\u7531 ${o.method} ${o.originalUrl} \u4E0D\u5B58\u5728`, url: o.originalUrl}));
141
+ a = p('huxy');
142
+ var b = p('error-handler'),
143
+ A = e => (o, t, r) => {
144
+ (b.error({message: 'Not Found', timestamp: m(), url: o.originalUrl, method: o.method, ip: o.ip, userAgent: o.get('User-Agent')}, '\u627E\u4E0D\u5230\u8DEF\u5F84'),
145
+ t.status(404).json({success: !1, timestamp: m(), status: 404, message: `\u8DEF\u7531 ${o.method} ${o.originalUrl} \u4E0D\u5B58\u5728`, url: o.originalUrl}));
111
146
  },
112
- A = t => (o, e, r, n) => {
113
- let s = o.status || 500,
114
- i = o.message;
115
- (y.error({message: i, timestamp: m(), stack: o.stack, url: e.originalUrl, method: e.method, ip: e.ip, userAgent: e.get('User-Agent')}, '\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF'),
116
- r.status(s).json({success: !1, timestamp: m(), message: t.isDev ? i : '\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF', stack: t.isDev ? o.stack : void 0}));
147
+ N = e => (o, t, r, s) => {
148
+ let i = o.status || 500,
149
+ n = o.message;
150
+ (b.error({message: n, timestamp: m(), stack: o.stack, url: t.originalUrl, method: t.method, ip: t.ip, userAgent: t.get('User-Agent')}, '\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF'),
151
+ r.status(i).json({success: !1, timestamp: m(), message: e.isDev ? n : '\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF', stack: e.isDev ? o.stack : void 0}));
117
152
  };
118
- var L = t => (o, e, r) => {
119
- (o.path.match(/\.(js|css|png|jpe?g|ico|webp|svg|mpeg|webm|m4a)$/) ? e.set('Cache-Control', 'public, max-age=31536000, immutable') : e.set('Cache-Control', 'no-cache'), r());
153
+ var R = e => (o, t, r) => {
154
+ (o.path.match(/\.(js|css|png|jpe?g|ico|webp|svg|mpeg|webm|m4a)$/) ? t.set('Cache-Control', 'public, max-age=31536000, immutable') : t.set('Cache-Control', 'no-cache'), r());
120
155
  };
121
- import {Router as j} from 'express';
122
- var G = t => {
123
- let o = j();
156
+ import {Router as F} from 'express';
157
+ var V = e => {
158
+ let o = F();
124
159
  return (
125
- o.use('/health', (e, r) => {
126
- r.status(200).json({status: 'OK', timestamp: m(), uptime: process.uptime(), environment: t.nodeEnv, memoryUsage: process.memoryUsage(), pid: process.pid});
160
+ o.use('/health', (t, r) => {
161
+ r.status(200).json({status: 'OK', timestamp: m(), environment: e.nodeEnv, uptime: process.uptime(), memoryUsage: process.memoryUsage(), pid: process.pid});
127
162
  }),
128
- o.get('/', (e, r) => {
129
- r.status(200).json({message: 'Node.js \u670D\u52A1\u5668\u8FD0\u884C\u4E2D', timestamp: m(), environment: t.nodeEnv});
163
+ o.get('/status', (t, r) => {
164
+ r.status(200).json({message: 'Node.js \u670D\u52A1\u5668\u8FD0\u884C\u4E2D', timestamp: m(), environment: e.nodeEnv});
130
165
  }),
131
166
  o
132
167
  );
133
168
  },
134
- N = G;
135
- var Q = (t, o = {}) => (
136
- t.disable('x-powered-by'),
137
- t.set('trust proxy', 1),
138
- t.use(V(o.helmet)),
139
- t.use(F(o.cors)),
140
- t.use(K({keyGenerator: e => W(e.ip) || e.headers['x-huxy-auth'] || e.headers['x-api-key'] || e.headers.authorization, ...o.rateLimit})),
141
- t.use(z()),
142
- t.use(T.json({limit: '20mb'})),
143
- t.use(T.urlencoded({extended: !0, limit: '20mb'})),
144
- t.use(X({logger: a, quietReqLogger: !0, autoLogging: !1})),
145
- t.use(P()),
146
- t.use(L(o)),
147
- t
148
- ),
149
- J = t => {
150
- let o = e => {
151
- (a.info(`\u6536\u5230 ${e} \u4FE1\u53F7, \u{1F6D1} \u6B63\u5728\u5173\u95ED\u670D\u52A1\u5668...`),
152
- t.close(() => {
153
- (a.info('\u{1F44B} \u670D\u52A1\u5668\u5DF2\u5173\u95ED'), process.exit(0));
154
- }),
155
- setTimeout(() => {
156
- (a.error('\u274C \u5F3A\u5236\u5173\u95ED\u670D\u52A1\u5668'), process.exit(1));
157
- }, 5e3));
158
- };
159
- (process.on('SIGTERM', () => o('SIGTERM')),
160
- process.on('SIGINT', () => o('SIGINT')),
161
- process.on('uncaughtException', e => {
162
- (a.error(e, `\u672A\u6355\u83B7\u7684\u5F02\u5E38: ${e.message}`), process.exit(1));
163
- }),
164
- process.on('unhandledRejection', (e, r) => {
165
- (a.error({reason: e, promise: r}, '\u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD'), process.exit(1));
166
- }));
169
+ _ = V;
170
+ var Y = (e, o = {}) => {
171
+ (e.disable('x-powered-by'),
172
+ e.set('trust proxy', 1),
173
+ e.use(K(o.helmet)),
174
+ e.use(W(o.cors)),
175
+ e.use(z({keyGenerator: t => X(t.ip) || t.headers['x-huxy-auth'] || t.headers['x-api-key'] || t.headers.authorization, ...o.rateLimit})),
176
+ e.use(B()),
177
+ e.use(E.json({limit: '20mb'})),
178
+ e.use(E.urlencoded({extended: !0, limit: '20mb'})),
179
+ e.use(Q({logger: a, quietReqLogger: !0, autoLogging: !1})),
180
+ o.isDev && e.use(L()),
181
+ e.use(R(o)));
182
+ },
183
+ Z = (e, o = {}) => {
184
+ (e.use(_(o)), e.use(A(o)), e.use(N(o)));
185
+ },
186
+ q = async (e, o) => {
187
+ let t = d(e),
188
+ {port: r} = t;
189
+ (await f(r, t.host)) || ((t.port = Number(r) + 1), a.warn(`\u7AEF\u53E3 ${r} \u5DF2\u88AB\u5360\u7528\uFF0C\u73B0\u5728\u4F7F\u7528\u7AEF\u53E3 ${t.port}`));
190
+ let i = E();
191
+ Y(i, t);
192
+ let n = J(i);
193
+ I(n, t);
194
+ try {
195
+ await P(n, t);
196
+ } catch {
197
+ (a.error('\u26A0\uFE0F \u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25'), process.exit(1));
198
+ }
199
+ return (await o?.(t, i, n), Z(i, t), {app: i, httpServer: n, config: t});
167
200
  },
168
- Z = async (t, o) => {
169
- let e = u(t),
170
- {port: r} = e;
171
- (await d(r, e.host)) || ((e.port = Number(r) + 1), a.warn(`\u7AEF\u53E3 ${r} \u5DF2\u88AB\u5360\u7528\uFF0C\u73B0\u5728\u4F7F\u7528\u7AEF\u53E3 ${e.port}`));
172
- let s = T();
173
- Q(s, e);
174
- let i = B(s);
175
- return (o?.(i, s, e), s.use(N(e)), s.use(b(e)), s.use(A(e)), J(i), {app: s, httpServer: i, config: e});
201
+ $ = q;
202
+ var ee = (e, o = 56) => {
203
+ let t = e.length,
204
+ r = o - t,
205
+ s = ~~(r / 2);
206
+ return `${'-'.repeat(s)}${e}${'-'.repeat(r - s)}`;
176
207
  },
177
- R = Z;
178
- var Y = (t, o, e) =>
179
- R({...f, ...t}, (r, n, s) => {
180
- let {port: i, host: p, nodeEnv: h, basepath: I, appName: C = 'HuxyServer'} = s;
181
- r.listen(i, p, () => {
182
- if (!e) {
183
- let $ = l()
184
- .filter(v => v !== `http://${p}`)
185
- .map(v => `http://${v}:${i}${I}`);
186
- (a.info(`-----------------------${C}-----------------------`),
187
- a.info(`\u{1F680} \u670D\u52A1\u8FD0\u884C\u5728\u3010${h}\u3011\u73AF\u5883: http://${p}:${i}${I}`),
188
- a.info(`-----------------[${m()}]------------------`),
189
- a.info({ips: $}, '\u672C\u5730\u5730\u5740\uFF1A'));
190
- }
191
- o?.(s, n, r);
192
- });
208
+ te = (e, o, t) =>
209
+ $({...g, ...e}, async (r, s, i) => {
210
+ let {port: n, host: c, nodeEnv: l, basepath: y, appName: C = 'HuxyServer'} = r;
211
+ if (!t) {
212
+ let H = u()
213
+ .filter(v => v !== `http://${c}`)
214
+ .map(v => `http://${v}:${n}${y}`);
215
+ (a.info(ee(C)),
216
+ a.info(`\u{1F680} \u670D\u52A1\u8FD0\u884C\u5728\u3010${l}\u3011\u73AF\u5883: http://${c}:${n}${y}`),
217
+ a.info(`-----------------[${m()}]------------------`),
218
+ a.info({ips: H}, '\u672C\u5730\u5730\u5740\uFF1A'));
219
+ }
220
+ await o?.(r, s, i);
193
221
  }),
194
- g = Y;
195
- import oe from 'express';
196
- import {fileURLToPath as q} from 'node:url';
197
- import {dirname as ee, resolve as te} from 'node:path';
198
- var E = (t = import.meta.url) => ee(q(t)),
199
- S = t => te(E(), t),
200
- _ = S;
201
- var re = {port: 9e3, host: 'localhost', basepath: '/', buildPath: './build'},
202
- se = (t, o) =>
203
- g({...re, ...t}, (e, r, n) => {
204
- let {basepath: s, buildPath: i} = e;
205
- (r.use(s, oe.static(i, {maxAge: '1y', immutable: !0})),
206
- r.get(`${s}/{*splat}`.replace('//', '/'), (p, h) => {
207
- h.sendFile(_(i, 'index.html'));
222
+ h = te;
223
+ import ne from 'express';
224
+ import {fileURLToPath as oe} from 'node:url';
225
+ import {dirname as re, resolve as se} from 'node:path';
226
+ var T = (e = import.meta.url) => re(oe(e)),
227
+ S = e => se(T(), e),
228
+ O = S;
229
+ var ie = {port: 9e3, host: 'localhost', basepath: '/', buildPath: './build'},
230
+ ae = (e, o) =>
231
+ h({...ie, ...e}, async (t, r, s) => {
232
+ let {basepath: i, buildPath: n} = t;
233
+ (r.use(i, ne.static(n, {maxAge: '1y', immutable: !0})),
234
+ r.get(`${i}/{*splat}`.replace('//', '/'), (c, l) => {
235
+ l.sendFile(O(n, 'index.html'));
208
236
  }),
209
- o?.(e, r, n));
237
+ await o?.(t, r, s));
210
238
  }),
211
- O = se;
212
- var Ye = {startServer: g, startStatic: O, logger: a, createLogger: c, dateTime: m, localIPs: l, nodeArgs: x, getEnvConfig: u, checkPort: d, getDirName: E, resolvePath: S};
239
+ D = ae;
240
+ var ot = {startServer: h, startStatic: D, logger: a, createLogger: p, dateTime: m, localIPs: u, nodeArgs: x, getEnvConfig: d, checkPort: f, getDirName: T, resolvePath: S};
213
241
  export {
214
- d as checkPort,
215
- c as createLogger,
242
+ f as checkPort,
243
+ p as createLogger,
216
244
  m as dateTime,
217
- Ye as default,
218
- E as getDirName,
219
- u as getEnvConfig,
220
- l as localIPs,
245
+ ot as default,
246
+ T as getDirName,
247
+ d as getEnvConfig,
248
+ u as localIPs,
221
249
  a as logger,
222
250
  x as nodeArgs,
223
251
  S as resolvePath,
224
- g as startServer,
225
- O as startStatic,
252
+ h as startServer,
253
+ D as startStatic,
226
254
  };