@radatek/microserver 3.0.4 → 3.0.6
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/microserver.d.ts +6 -22
- package/microserver.js +104 -92
- package/package.json +1 -1
package/microserver.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MicroServer
|
|
3
|
-
* @version 3.0.
|
|
3
|
+
* @version 3.0.6
|
|
4
4
|
* @package @radatek/microserver
|
|
5
5
|
* @copyright Darius Kisonas 2022
|
|
6
6
|
* @license MIT
|
|
@@ -86,7 +86,6 @@ export declare class ServerRequest<T = any> extends http.IncomingMessage {
|
|
|
86
86
|
rawBody: Buffer[];
|
|
87
87
|
/** Request raw body size */
|
|
88
88
|
rawBodySize: number;
|
|
89
|
-
private constructor();
|
|
90
89
|
/** Extend http.IncomingMessage */
|
|
91
90
|
static extend(req: http.IncomingMessage, res: http.ServerResponse, server: MicroServer): ServerRequest;
|
|
92
91
|
/** Check if request is ready */
|
|
@@ -115,7 +114,6 @@ export declare class ServerResponse<T = any> extends http.ServerResponse {
|
|
|
115
114
|
readonly req: ServerRequest<T>;
|
|
116
115
|
/** Should response be json */
|
|
117
116
|
isJson: boolean;
|
|
118
|
-
private constructor();
|
|
119
117
|
/** Extends http.ServerResponse */
|
|
120
118
|
static extend(res: http.ServerResponse): void;
|
|
121
119
|
/** Send error reponse */
|
|
@@ -329,8 +327,6 @@ export declare class WebSocket extends EventEmitter {
|
|
|
329
327
|
constructor(req: ServerRequest, options?: WebSocketOptions);
|
|
330
328
|
/** Close connection */
|
|
331
329
|
close(reason?: number, data?: Buffer): void;
|
|
332
|
-
/** Generate WebSocket frame from data */
|
|
333
|
-
static getFrame(data: number | string | Buffer | undefined, options?: any): Buffer;
|
|
334
330
|
/** Send data */
|
|
335
331
|
send(data: string | Buffer): void;
|
|
336
332
|
/** Send ping frame */
|
|
@@ -346,8 +342,7 @@ export declare class WebSocket extends EventEmitter {
|
|
|
346
342
|
export declare class WebSocketPlugin extends Plugin {
|
|
347
343
|
name: string;
|
|
348
344
|
constructor(options?: any, server?: MicroServer);
|
|
349
|
-
|
|
350
|
-
upgradeHandler(server: MicroServer, req: ServerRequest, socket: net.Socket, head: any): void;
|
|
345
|
+
upgradeHandler(server: MicroServer, req: ServerRequest, socket: net.Socket, head: any): any;
|
|
351
346
|
}
|
|
352
347
|
/** Trust proxy plugin, adds `req.ip` and `req.localip` */
|
|
353
348
|
export declare class TrustProxyPlugin extends Plugin {
|
|
@@ -584,22 +579,11 @@ export declare class Auth {
|
|
|
584
579
|
};
|
|
585
580
|
/** Encode token */
|
|
586
581
|
encode(data: string, expire?: number): string;
|
|
587
|
-
/**
|
|
588
|
-
* Check acl over authenticated user with: `id`, `group/*`, `*`
|
|
589
|
-
* @param {string} id - to authenticate: `id`, `group/id`, `model/action`, comma separated best: true => false => def
|
|
590
|
-
* @param {boolean} [def=false] - default access
|
|
591
|
-
*/
|
|
582
|
+
/** Check acl over authenticated user with: `id`, `group/*`, `*` */
|
|
592
583
|
acl(id: string, def?: boolean): boolean;
|
|
593
|
-
/**
|
|
594
|
-
* Authenticate user and setup cookie
|
|
595
|
-
* @param {string|UserInfo} usr - user id used with options.users to retrieve user object. User object must contain `id` and `acl` object (Ex. usr = {id:'usr', acl:{'users/*':true}})
|
|
596
|
-
* @param {string} [psw] - user password (if used for user authentication with options.users)
|
|
597
|
-
* @param {number} [expire] - expire time in seconds (default: options.expire)
|
|
598
|
-
*/
|
|
584
|
+
/** Generate token from user info */
|
|
599
585
|
token(usr: string | UserInfo | undefined, psw: string | undefined, expire?: number): Promise<string | undefined>;
|
|
600
|
-
/**
|
|
601
|
-
* Authenticate user and setup cookie
|
|
602
|
-
*/
|
|
586
|
+
/** Authenticate user and setup cookie */
|
|
603
587
|
login(usr: string | UserInfo | undefined, psw?: string, options?: {
|
|
604
588
|
expire?: number;
|
|
605
589
|
salt?: string;
|
|
@@ -937,4 +921,4 @@ export declare class MicroCollection<TSchema extends ModelSchema = any> {
|
|
|
937
921
|
modifiedCount: number;
|
|
938
922
|
}>;
|
|
939
923
|
}
|
|
940
|
-
|
|
924
|
+
export {};
|
package/microserver.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MicroServer
|
|
3
|
-
* @version 3.0.
|
|
3
|
+
* @version 3.0.6
|
|
4
4
|
* @package @radatek/microserver
|
|
5
5
|
* @copyright Darius Kisonas 2022
|
|
6
6
|
* @license MIT
|
|
@@ -116,8 +116,11 @@ export class ServerRequest extends http.IncomingMessage {
|
|
|
116
116
|
rawBody;
|
|
117
117
|
/** Request raw body size */
|
|
118
118
|
rawBodySize;
|
|
119
|
+
// @internal
|
|
119
120
|
_body;
|
|
121
|
+
// @internal
|
|
120
122
|
_isReady;
|
|
123
|
+
// @internal
|
|
121
124
|
constructor(res, server) {
|
|
122
125
|
super(new net.Socket());
|
|
123
126
|
ServerRequest.extend(this, res, server);
|
|
@@ -212,6 +215,7 @@ export class ServerRequest extends http.IncomingMessage {
|
|
|
212
215
|
export class ServerResponse extends http.ServerResponse {
|
|
213
216
|
/** Should response be json */
|
|
214
217
|
isJson;
|
|
218
|
+
// @internal
|
|
215
219
|
constructor(server) {
|
|
216
220
|
super(new http.IncomingMessage(new net.Socket()));
|
|
217
221
|
ServerRequest.extend(this.req, this, server);
|
|
@@ -365,9 +369,13 @@ export class MicroServer extends EventEmitter {
|
|
|
365
369
|
config;
|
|
366
370
|
/** Authorization object */
|
|
367
371
|
auth;
|
|
372
|
+
// @internal
|
|
368
373
|
_plugins = {};
|
|
374
|
+
// @internal
|
|
369
375
|
_stack = [];
|
|
376
|
+
// @internal
|
|
370
377
|
_router = new RouterPlugin();
|
|
378
|
+
// @internal
|
|
371
379
|
_worker = new Worker();
|
|
372
380
|
/** All sockets */
|
|
373
381
|
sockets;
|
|
@@ -499,6 +507,7 @@ export class MicroServer extends EventEmitter {
|
|
|
499
507
|
return this._worker.wait('listen');
|
|
500
508
|
}
|
|
501
509
|
/* bind middleware or create one from string like: 'redirect:302,https://redirect.to', 'error:422', 'param:name=value', 'acl:users/get', 'model:User', 'group:Users', 'user:admin' */
|
|
510
|
+
// @internal
|
|
502
511
|
_bind(fn) {
|
|
503
512
|
if (typeof fn === 'string') {
|
|
504
513
|
let name = fn;
|
|
@@ -683,6 +692,7 @@ export class MicroServer extends EventEmitter {
|
|
|
683
692
|
this._router.add(method, url, args.filter(o => o).map((o) => this._bind(o)), true);
|
|
684
693
|
return this._worker.endJob();
|
|
685
694
|
}
|
|
695
|
+
// @internal
|
|
686
696
|
async _plugin(plugin) {
|
|
687
697
|
if (plugin.handler) {
|
|
688
698
|
const middleware = plugin.handler.bind(plugin);
|
|
@@ -695,7 +705,9 @@ export class MicroServer extends EventEmitter {
|
|
|
695
705
|
if (routes)
|
|
696
706
|
await this.use(routes);
|
|
697
707
|
}
|
|
698
|
-
if (plugin.
|
|
708
|
+
if (plugin.name) {
|
|
709
|
+
if (this._plugins[plugin.name])
|
|
710
|
+
throw new Error(`Plugin ${plugin.name} already added`);
|
|
699
711
|
this._plugins[plugin.name] = plugin;
|
|
700
712
|
this.emit('plugin', plugin.name);
|
|
701
713
|
this.emit('plugin:' + plugin.name);
|
|
@@ -791,16 +803,23 @@ export class MicroServer extends EventEmitter {
|
|
|
791
803
|
}
|
|
792
804
|
// #region RouterPlugin
|
|
793
805
|
class RouterItem {
|
|
806
|
+
// @internal
|
|
794
807
|
_stack; // add if middlewares added if not last
|
|
808
|
+
// @internal
|
|
795
809
|
_next; // next middlewares
|
|
810
|
+
// @internal
|
|
796
811
|
_paramName; // param name if param is used
|
|
812
|
+
// @internal
|
|
797
813
|
_paramWild;
|
|
814
|
+
// @internal
|
|
798
815
|
_withParam; // next middlewares if param is used
|
|
816
|
+
// @internal
|
|
799
817
|
_last;
|
|
800
818
|
}
|
|
801
819
|
class RouterPlugin extends Plugin {
|
|
802
820
|
priority = 100;
|
|
803
821
|
name = 'router';
|
|
822
|
+
// @internal
|
|
804
823
|
_tree = {};
|
|
805
824
|
constructor() {
|
|
806
825
|
super();
|
|
@@ -850,6 +869,7 @@ class RouterPlugin extends Plugin {
|
|
|
850
869
|
node._stack.push(...middlewares);
|
|
851
870
|
}
|
|
852
871
|
}
|
|
872
|
+
// @internal
|
|
853
873
|
_getStack(path, treeItems) {
|
|
854
874
|
const out = [];
|
|
855
875
|
const segments = path.split('/').filter(s => s);
|
|
@@ -963,7 +983,9 @@ export class CorsPlugin extends Plugin {
|
|
|
963
983
|
export class MethodsPlugin extends Plugin {
|
|
964
984
|
priority = -90;
|
|
965
985
|
name = 'methods';
|
|
986
|
+
// @internal
|
|
966
987
|
_methods;
|
|
988
|
+
// @internal
|
|
967
989
|
_methodsIdx;
|
|
968
990
|
constructor(methods) {
|
|
969
991
|
super();
|
|
@@ -987,6 +1009,7 @@ export class MethodsPlugin extends Plugin {
|
|
|
987
1009
|
export class BodyPlugin extends Plugin {
|
|
988
1010
|
priority = -80;
|
|
989
1011
|
name = 'body';
|
|
1012
|
+
// @internal
|
|
990
1013
|
_maxBodySize;
|
|
991
1014
|
constructor(options) {
|
|
992
1015
|
super();
|
|
@@ -1041,7 +1064,9 @@ export class BodyPlugin extends Plugin {
|
|
|
1041
1064
|
export class UploadPlugin extends Plugin {
|
|
1042
1065
|
priority = -70;
|
|
1043
1066
|
name = 'upload';
|
|
1067
|
+
// @internal
|
|
1044
1068
|
_maxFileSize;
|
|
1069
|
+
// @internal
|
|
1045
1070
|
_uploadDir;
|
|
1046
1071
|
constructor(options) {
|
|
1047
1072
|
super();
|
|
@@ -1131,6 +1156,10 @@ export class UploadPlugin extends Plugin {
|
|
|
1131
1156
|
const safeWriteLength = buffer.length - lookahead;
|
|
1132
1157
|
if (safeWriteLength > 0) {
|
|
1133
1158
|
lastFile.size += safeWriteLength;
|
|
1159
|
+
if (lastFile.size > this._maxFileSize) {
|
|
1160
|
+
req.setReady(new ResponseError("file too big", 413));
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1134
1163
|
fileStream.write(buffer.subarray(0, safeWriteLength));
|
|
1135
1164
|
buffer = buffer.subarray(safeWriteLength);
|
|
1136
1165
|
}
|
|
@@ -1167,10 +1196,15 @@ const EMPTY_BUFFER = Buffer.alloc(0);
|
|
|
1167
1196
|
const DEFLATE_TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
|
|
1168
1197
|
/** WebSocket class */
|
|
1169
1198
|
export class WebSocket extends EventEmitter {
|
|
1199
|
+
// @internal
|
|
1170
1200
|
_socket;
|
|
1201
|
+
// @internal
|
|
1171
1202
|
_frame;
|
|
1203
|
+
// @internal
|
|
1172
1204
|
_buffers = [EMPTY_BUFFER];
|
|
1205
|
+
// @internal
|
|
1173
1206
|
_buffersLength = 0;
|
|
1207
|
+
// @internal
|
|
1174
1208
|
_options;
|
|
1175
1209
|
ready = false;
|
|
1176
1210
|
constructor(req, options) {
|
|
@@ -1189,7 +1223,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1189
1223
|
const version = +(req.headers['sec-websocket-version'] || 0);
|
|
1190
1224
|
const extensions = req.headers['sec-websocket-extensions'];
|
|
1191
1225
|
const headers = [];
|
|
1192
|
-
if (!key ||
|
|
1226
|
+
if (!key || upgrade?.toLocaleLowerCase() !== 'websocket' || version !== 13) {
|
|
1193
1227
|
this._abort('Invalid WebSocket request', 400);
|
|
1194
1228
|
return;
|
|
1195
1229
|
}
|
|
@@ -1200,12 +1234,12 @@ export class WebSocket extends EventEmitter {
|
|
|
1200
1234
|
headers.push(header);
|
|
1201
1235
|
this._options.deflate = true;
|
|
1202
1236
|
}
|
|
1203
|
-
this.ready = true;
|
|
1204
1237
|
this._upgrade(key, headers, () => {
|
|
1205
|
-
|
|
1238
|
+
this.ready = true;
|
|
1206
1239
|
this.emit('open');
|
|
1207
1240
|
});
|
|
1208
1241
|
}
|
|
1242
|
+
// @internal
|
|
1209
1243
|
_upgrade(key, headers = [], cb) {
|
|
1210
1244
|
const digest = crypto.createHash('sha1')
|
|
1211
1245
|
.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
|
@@ -1236,45 +1270,6 @@ export class WebSocket extends EventEmitter {
|
|
|
1236
1270
|
}
|
|
1237
1271
|
return this._sendFrame(0x88, data || EMPTY_BUFFER, () => this._socket.destroy());
|
|
1238
1272
|
}
|
|
1239
|
-
/** Generate WebSocket frame from data */
|
|
1240
|
-
static getFrame(data, options) {
|
|
1241
|
-
let msgType = 8;
|
|
1242
|
-
let dataLength = 0;
|
|
1243
|
-
if (typeof data === 'string') {
|
|
1244
|
-
msgType = 1;
|
|
1245
|
-
dataLength = Buffer.byteLength(data, 'utf8');
|
|
1246
|
-
}
|
|
1247
|
-
else if (data instanceof Buffer) {
|
|
1248
|
-
msgType = 2;
|
|
1249
|
-
dataLength = data.length;
|
|
1250
|
-
}
|
|
1251
|
-
else if (typeof data === 'number') {
|
|
1252
|
-
msgType = data;
|
|
1253
|
-
}
|
|
1254
|
-
const headerSize = 2 + (dataLength < 126 ? 0 : dataLength < 65536 ? 2 : 8) + (dataLength && options?.mask ? 4 : 0);
|
|
1255
|
-
const frame = Buffer.allocUnsafe(headerSize + dataLength);
|
|
1256
|
-
frame[0] = 0x80 | msgType;
|
|
1257
|
-
frame[1] = dataLength > 65535 ? 127 : dataLength > 125 ? 126 : dataLength;
|
|
1258
|
-
if (dataLength > 65535)
|
|
1259
|
-
frame.writeBigUInt64BE(dataLength, 2);
|
|
1260
|
-
else if (dataLength > 125)
|
|
1261
|
-
frame.writeUInt16BE(dataLength, 2);
|
|
1262
|
-
if (dataLength && frame.length > dataLength) {
|
|
1263
|
-
if (typeof data === 'string')
|
|
1264
|
-
frame.write(data, headerSize, 'utf8');
|
|
1265
|
-
else
|
|
1266
|
-
data.copy(frame, headerSize);
|
|
1267
|
-
}
|
|
1268
|
-
if (dataLength && options?.mask) {
|
|
1269
|
-
let i = headerSize, h = headerSize - 4;
|
|
1270
|
-
for (let i = 0; i < 4; i++)
|
|
1271
|
-
frame[h + i] = Math.floor(Math.random() * 256);
|
|
1272
|
-
for (let j = 0; j < dataLength; j++, i++) {
|
|
1273
|
-
frame[i] ^= frame[h + (j & 3)];
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
return frame;
|
|
1277
|
-
}
|
|
1278
1273
|
/** Send data */
|
|
1279
1274
|
send(data) {
|
|
1280
1275
|
let msgType = typeof data === 'string' ? 1 : 2;
|
|
@@ -1296,6 +1291,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1296
1291
|
else
|
|
1297
1292
|
return this._sendFrame(0x80 | msgType, data);
|
|
1298
1293
|
}
|
|
1294
|
+
// @internal
|
|
1299
1295
|
_errorHandler(error) {
|
|
1300
1296
|
this.emit('error', error);
|
|
1301
1297
|
if (this.ready)
|
|
@@ -1304,6 +1300,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1304
1300
|
this._socket.destroy();
|
|
1305
1301
|
this.ready = false;
|
|
1306
1302
|
}
|
|
1303
|
+
// @internal
|
|
1307
1304
|
_headerLength(buffer) {
|
|
1308
1305
|
if (this._frame)
|
|
1309
1306
|
return 0;
|
|
@@ -1312,6 +1309,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1312
1309
|
let hederInfo = buffer[1];
|
|
1313
1310
|
return 2 + (hederInfo & 0x80 ? 4 : 0) + ((hederInfo & 0x7F) === 126 ? 2 : 0) + ((hederInfo & 0x7F) === 127 ? 8 : 0);
|
|
1314
1311
|
}
|
|
1312
|
+
// @internal
|
|
1315
1313
|
_dataHandler(data) {
|
|
1316
1314
|
while (data.length) {
|
|
1317
1315
|
let frame = this._frame;
|
|
@@ -1418,6 +1416,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1418
1416
|
this._buffers.push(EMPTY_BUFFER);
|
|
1419
1417
|
}
|
|
1420
1418
|
}
|
|
1419
|
+
// @internal
|
|
1421
1420
|
_abort(message, code, headers) {
|
|
1422
1421
|
code = code || 400;
|
|
1423
1422
|
message = message || http.STATUS_CODES[code] || 'Closed';
|
|
@@ -1444,6 +1443,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1444
1443
|
pong(buffer) {
|
|
1445
1444
|
this._sendFrame(0x8A, buffer || EMPTY_BUFFER);
|
|
1446
1445
|
}
|
|
1446
|
+
// @internal
|
|
1447
1447
|
_sendFrame(opcode, data, cb) {
|
|
1448
1448
|
if (!this.ready)
|
|
1449
1449
|
return;
|
|
@@ -1463,24 +1463,21 @@ export class WebSocket extends EventEmitter {
|
|
|
1463
1463
|
else
|
|
1464
1464
|
this._socket.write(frame, () => this._socket.write(data, cb));
|
|
1465
1465
|
}
|
|
1466
|
-
on(event, listener) { return super.on(event, listener); }
|
|
1467
|
-
addListener(event, listener) { return super.addListener(event, listener); }
|
|
1468
|
-
once(event, listener) { return super.once(event, listener); }
|
|
1469
|
-
off(event, listener) { return super.off(event, listener); }
|
|
1470
|
-
removeListener(event, listener) { return super.removeListener(event, listener); }
|
|
1471
1466
|
}
|
|
1472
1467
|
export class WebSocketPlugin extends Plugin {
|
|
1473
1468
|
name = 'websocket';
|
|
1469
|
+
// @internal
|
|
1474
1470
|
_handler;
|
|
1475
1471
|
constructor(options, server) {
|
|
1476
1472
|
super();
|
|
1477
1473
|
if (!server)
|
|
1478
1474
|
throw new Error('Server instance is required');
|
|
1479
1475
|
this._handler = this.upgradeHandler.bind(this, server);
|
|
1480
|
-
server.servers?.forEach(srv => this.
|
|
1481
|
-
server.on('listen', (port, address, srv) => this.
|
|
1476
|
+
server.servers?.forEach(srv => this._addUpgradeHandler(srv));
|
|
1477
|
+
server.on('listen', (port, address, srv) => this._addUpgradeHandler(srv));
|
|
1482
1478
|
}
|
|
1483
|
-
|
|
1479
|
+
// @internal
|
|
1480
|
+
_addUpgradeHandler(srv) {
|
|
1484
1481
|
if (!srv.listeners('upgrade').includes(this._handler))
|
|
1485
1482
|
srv.on('upgrade', this._handler);
|
|
1486
1483
|
}
|
|
@@ -1488,7 +1485,6 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1488
1485
|
const host = req.headers.host || '';
|
|
1489
1486
|
const vhostPlugin = server.getPlugin('vhost');
|
|
1490
1487
|
const vserver = vhostPlugin?.vhosts?.[host] || server;
|
|
1491
|
-
req.method = 'WEBSOCKET';
|
|
1492
1488
|
const res = {
|
|
1493
1489
|
req,
|
|
1494
1490
|
get headersSent() {
|
|
@@ -1519,7 +1515,9 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1519
1515
|
socket.write(headers.join('\r\n'), () => { socket.destroy(); });
|
|
1520
1516
|
},
|
|
1521
1517
|
error(code) {
|
|
1522
|
-
|
|
1518
|
+
if (typeof code !== 'number')
|
|
1519
|
+
code = 405;
|
|
1520
|
+
res.statusCode = code || 405;
|
|
1523
1521
|
res.end();
|
|
1524
1522
|
},
|
|
1525
1523
|
send(data) {
|
|
@@ -1529,15 +1527,18 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1529
1527
|
setHeader() { }
|
|
1530
1528
|
};
|
|
1531
1529
|
ServerRequest.extend(req, res, server);
|
|
1532
|
-
let
|
|
1530
|
+
let ws;
|
|
1533
1531
|
Object.defineProperty(req, 'websocket', {
|
|
1534
1532
|
get: () => {
|
|
1535
|
-
if (!
|
|
1536
|
-
|
|
1537
|
-
return
|
|
1533
|
+
if (!ws)
|
|
1534
|
+
ws = new WebSocket(req, server.config.websocket);
|
|
1535
|
+
return ws;
|
|
1538
1536
|
},
|
|
1539
1537
|
enumerable: true
|
|
1540
1538
|
});
|
|
1539
|
+
if (req.method !== 'GET' || req.headers.upgrade?.toLowerCase() !== 'websocket')
|
|
1540
|
+
return res.error(400);
|
|
1541
|
+
req.method = 'WEBSOCKET';
|
|
1541
1542
|
vserver.handler(req, res);
|
|
1542
1543
|
}
|
|
1543
1544
|
}
|
|
@@ -1547,6 +1548,7 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1547
1548
|
export class TrustProxyPlugin extends Plugin {
|
|
1548
1549
|
priority = -60;
|
|
1549
1550
|
name = 'trustproxy';
|
|
1551
|
+
// @internal
|
|
1550
1552
|
_trustProxy = [];
|
|
1551
1553
|
constructor(options) {
|
|
1552
1554
|
super();
|
|
@@ -1672,9 +1674,6 @@ export class StaticFilesPlugin extends Plugin {
|
|
|
1672
1674
|
options = {};
|
|
1673
1675
|
if (typeof options === 'string')
|
|
1674
1676
|
options = { root: options };
|
|
1675
|
-
// allow multiple instances
|
|
1676
|
-
if (server && !server.getPlugin('static'))
|
|
1677
|
-
this.name = 'static';
|
|
1678
1677
|
this.mimeTypes = options.mimeTypes ? { ...StaticFilesPlugin.mimeTypes, ...options.mimeTypes } : Object.freeze(StaticFilesPlugin.mimeTypes);
|
|
1679
1678
|
this.root = (options.root && path.isAbsolute(options.root) ? options.root : path.resolve(options.root || options?.path || 'public')).replace(/[\/\\]$/, '') + path.sep;
|
|
1680
1679
|
this.ignore = (options.ignore || []).map((p) => path.normalize(path.join(this.root, p)) + path.sep);
|
|
@@ -1686,24 +1685,28 @@ export class StaticFilesPlugin extends Plugin {
|
|
|
1686
1685
|
this.errors = options.errors;
|
|
1687
1686
|
this.prefix = ('/' + (options.path?.replace(/^[.\/]*/, '') || '').replace(/\/$/, '')).replace(/\/$/, '');
|
|
1688
1687
|
const defSend = ServerResponse.prototype.send;
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1688
|
+
if (server && !server.getPlugin('static')) {
|
|
1689
|
+
this.name = 'static'; // only first plugin instance is registered as
|
|
1690
|
+
const defSend = ServerResponse.prototype.send;
|
|
1691
|
+
ServerResponse.prototype.send = function (data) {
|
|
1692
|
+
const plugin = this.req.server.getPlugin('static');
|
|
1693
|
+
if (this.statusCode < 400 || this.isJson || typeof data !== 'string' || !plugin?.errors || this.getHeader('Content-Type'))
|
|
1694
|
+
return defSend.call(this, data);
|
|
1695
|
+
const errFile = plugin.errors[this.statusCode] || plugin.errors['*'];
|
|
1696
|
+
if (errFile)
|
|
1697
|
+
plugin.serveFile(this.req, this, { path: errFile, mimeType: 'text/html' });
|
|
1692
1698
|
return defSend.call(this, data);
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
plugin
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
mimeType: StaticFilesPlugin.mimeTypes[extname(path)] || 'application/octet-stream'
|
|
1705
|
-
});
|
|
1706
|
-
};
|
|
1699
|
+
};
|
|
1700
|
+
ServerResponse.prototype.file = function (path) {
|
|
1701
|
+
const plugin = this.req.server.getPlugin('static');
|
|
1702
|
+
if (!plugin)
|
|
1703
|
+
throw new Error('Server error');
|
|
1704
|
+
plugin.serveFile(this.req, this, typeof path === 'object' ? path : {
|
|
1705
|
+
path,
|
|
1706
|
+
mimeType: StaticFilesPlugin.mimeTypes[extname(path)] || 'application/octet-stream'
|
|
1707
|
+
});
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1707
1710
|
}
|
|
1708
1711
|
/** Default static files handler */
|
|
1709
1712
|
handler(req, res, next) {
|
|
@@ -1962,11 +1965,7 @@ export class Auth {
|
|
|
1962
1965
|
encrypted = iv.toString('base64').slice(0, 22) + cipher.getAuthTag().toString('base64').slice(0, 22) + encrypted;
|
|
1963
1966
|
return encrypted.replace(/==?/, '').replace(/\//g, '.').replace(/\+/g, '-');
|
|
1964
1967
|
}
|
|
1965
|
-
/**
|
|
1966
|
-
* Check acl over authenticated user with: `id`, `group/*`, `*`
|
|
1967
|
-
* @param {string} id - to authenticate: `id`, `group/id`, `model/action`, comma separated best: true => false => def
|
|
1968
|
-
* @param {boolean} [def=false] - default access
|
|
1969
|
-
*/
|
|
1968
|
+
/** Check acl over authenticated user with: `id`, `group/*`, `*` */
|
|
1970
1969
|
acl(id, def = false) {
|
|
1971
1970
|
if (!this.req?.user)
|
|
1972
1971
|
return false;
|
|
@@ -1988,12 +1987,7 @@ export class Auth {
|
|
|
1988
1987
|
access = reqAcl['*'];
|
|
1989
1988
|
return access ?? def;
|
|
1990
1989
|
}
|
|
1991
|
-
/**
|
|
1992
|
-
* Authenticate user and setup cookie
|
|
1993
|
-
* @param {string|UserInfo} usr - user id used with options.users to retrieve user object. User object must contain `id` and `acl` object (Ex. usr = {id:'usr', acl:{'users/*':true}})
|
|
1994
|
-
* @param {string} [psw] - user password (if used for user authentication with options.users)
|
|
1995
|
-
* @param {number} [expire] - expire time in seconds (default: options.expire)
|
|
1996
|
-
*/
|
|
1990
|
+
/** Generate token from user info */
|
|
1997
1991
|
async token(usr, psw, expire) {
|
|
1998
1992
|
let data;
|
|
1999
1993
|
if (typeof usr === 'object' && usr && (usr.id || usr._id))
|
|
@@ -2009,9 +2003,7 @@ export class Auth {
|
|
|
2009
2003
|
if (data)
|
|
2010
2004
|
return this.encode(data, expire);
|
|
2011
2005
|
}
|
|
2012
|
-
/**
|
|
2013
|
-
* Authenticate user and setup cookie
|
|
2014
|
-
*/
|
|
2006
|
+
/** Authenticate user and setup cookie */
|
|
2015
2007
|
async login(usr, psw, options) {
|
|
2016
2008
|
let usrInfo;
|
|
2017
2009
|
if (typeof usr === 'object')
|
|
@@ -2484,7 +2476,9 @@ export class Controller {
|
|
|
2484
2476
|
// #endregion Controller
|
|
2485
2477
|
// #region Worker
|
|
2486
2478
|
class WorkerJob {
|
|
2479
|
+
// @internal
|
|
2487
2480
|
_promises = [];
|
|
2481
|
+
// @internal
|
|
2488
2482
|
_busy = 0;
|
|
2489
2483
|
start() {
|
|
2490
2484
|
this._busy++;
|
|
@@ -2502,7 +2496,9 @@ class WorkerJob {
|
|
|
2502
2496
|
}
|
|
2503
2497
|
}
|
|
2504
2498
|
class Worker {
|
|
2499
|
+
// @internal
|
|
2505
2500
|
_id = 0;
|
|
2501
|
+
// @internal
|
|
2506
2502
|
_jobs = {};
|
|
2507
2503
|
isBusy(id) {
|
|
2508
2504
|
const job = this._jobs[id || 'ready'];
|
|
@@ -2531,11 +2527,17 @@ class Worker {
|
|
|
2531
2527
|
}
|
|
2532
2528
|
/** JSON File store */
|
|
2533
2529
|
export class FileStore {
|
|
2530
|
+
// @internal
|
|
2534
2531
|
_cache;
|
|
2532
|
+
// @internal
|
|
2535
2533
|
_dir;
|
|
2534
|
+
// @internal
|
|
2536
2535
|
_cacheTimeout;
|
|
2536
|
+
// @internal
|
|
2537
2537
|
_cacheItems;
|
|
2538
|
+
// @internal
|
|
2538
2539
|
_debounceTimeout;
|
|
2540
|
+
// @internal
|
|
2539
2541
|
_iter;
|
|
2540
2542
|
constructor(options) {
|
|
2541
2543
|
this._cache = {};
|
|
@@ -2559,7 +2561,9 @@ export class FileStore {
|
|
|
2559
2561
|
}
|
|
2560
2562
|
}
|
|
2561
2563
|
}
|
|
2564
|
+
// @internal
|
|
2562
2565
|
_queue = Promise.resolve();
|
|
2566
|
+
// @internal
|
|
2563
2567
|
async _sync(cb) {
|
|
2564
2568
|
let r;
|
|
2565
2569
|
let p = new Promise(resolve => r = resolve);
|
|
@@ -2738,8 +2742,11 @@ function newObjectId() {
|
|
|
2738
2742
|
return (new Date().getTime() / 1000 | 0).toString(16) + globalObjectId.toString('hex');
|
|
2739
2743
|
}
|
|
2740
2744
|
class ModelCollectionsInternal {
|
|
2745
|
+
// @internal
|
|
2741
2746
|
_ready;
|
|
2747
|
+
// @internal
|
|
2742
2748
|
_wait = new Promise(resolve => this._ready = resolve);
|
|
2749
|
+
// @internal
|
|
2743
2750
|
_db;
|
|
2744
2751
|
set db(db) {
|
|
2745
2752
|
Promise.resolve(db).then(db => this._ready(this._db = db));
|
|
@@ -3042,6 +3049,7 @@ export class Model {
|
|
|
3042
3049
|
}
|
|
3043
3050
|
return res;
|
|
3044
3051
|
}
|
|
3052
|
+
// @internal
|
|
3045
3053
|
_fieldFunction(value, def) {
|
|
3046
3054
|
if (typeof value === 'string' && value.startsWith('${') && value.endsWith('}')) {
|
|
3047
3055
|
const names = value.slice(2, -1).split('.');
|
|
@@ -3059,6 +3067,7 @@ export class Model {
|
|
|
3059
3067
|
return () => def;
|
|
3060
3068
|
return () => value;
|
|
3061
3069
|
}
|
|
3070
|
+
// @internal
|
|
3062
3071
|
_validateField(value, options) {
|
|
3063
3072
|
const field = options.field;
|
|
3064
3073
|
if (value == null) {
|
|
@@ -3186,7 +3195,9 @@ export class Model {
|
|
|
3186
3195
|
}
|
|
3187
3196
|
/** Collection factory */
|
|
3188
3197
|
export class MicroCollectionStore {
|
|
3198
|
+
// @internal
|
|
3189
3199
|
_collections = new Map();
|
|
3200
|
+
// @internal
|
|
3190
3201
|
_store;
|
|
3191
3202
|
constructor(dataPath, storeTimeDelay) {
|
|
3192
3203
|
if (dataPath)
|
|
@@ -3209,6 +3220,7 @@ export class MicroCollection {
|
|
|
3209
3220
|
name;
|
|
3210
3221
|
/** Collection data */
|
|
3211
3222
|
data;
|
|
3223
|
+
// @internal
|
|
3212
3224
|
_save;
|
|
3213
3225
|
constructor(options = {}) {
|
|
3214
3226
|
this.name = options.name || this.constructor.name;
|