@radatek/microserver 2.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.
@@ -0,0 +1,769 @@
1
+ /**
2
+ * MicroServer
3
+ * @version 2.0.0
4
+ * @package @radatek/microserver
5
+ * @copyright Darius Kisonas 2022
6
+ * @license MIT
7
+ */
8
+ import http from 'http';
9
+ import net from 'net';
10
+ import { Readable } from 'stream';
11
+ import { EventEmitter } from 'events';
12
+ export declare class Warning extends Error {
13
+ constructor(text: string);
14
+ }
15
+ export declare class ResponseError extends Error {
16
+ static getStatusCode(text: string | number | undefined): number;
17
+ static getStatusText(text: string | number | undefined): string;
18
+ statusCode: number;
19
+ constructor(text: string | number | undefined, statusCode?: number);
20
+ }
21
+ export declare class AccessDenied extends ResponseError {
22
+ constructor(text?: string);
23
+ }
24
+ export declare class InvalidData extends ResponseError {
25
+ constructor(text?: string, type?: string);
26
+ }
27
+ export declare class NotFound extends ResponseError {
28
+ constructor(text?: string);
29
+ }
30
+ export declare class WebSocketError extends Error {
31
+ statusCode: number;
32
+ constructor(text?: string, code?: number);
33
+ }
34
+ export declare abstract class Plugin {
35
+ priority?: number;
36
+ handler?(req: ServerRequest, res: ServerResponse, next: Function): void;
37
+ constructor(router: Router, ...args: any);
38
+ }
39
+ interface PluginClass {
40
+ new (router: Router, ...args: any): Plugin;
41
+ }
42
+ /** Extended http.IncomingMessage */
43
+ export declare class ServerRequest extends http.IncomingMessage {
44
+ /** Request protocol: http or https */
45
+ protocol: string;
46
+ /** Request client IP */
47
+ ip?: string;
48
+ /** Request from local network */
49
+ localip?: boolean;
50
+ /** Request is secure (https) */
51
+ secure?: boolean;
52
+ /** Request whole path */
53
+ path: string;
54
+ /** Request pathname */
55
+ pathname: string;
56
+ /** Base url */
57
+ baseUrl: string;
58
+ /** Original url */
59
+ originalUrl?: string;
60
+ /** GET parameters */
61
+ get: {
62
+ [key: string]: string;
63
+ };
64
+ /** Router named parameters */
65
+ params: {
66
+ [key: string]: string;
67
+ };
68
+ /** Router named parameters list */
69
+ paramsList: string[];
70
+ /** Router */
71
+ router: Router;
72
+ /** Authentication object */
73
+ auth?: Auth;
74
+ /** Authenticated user info */
75
+ user?: UserInfo;
76
+ /** Model used for request */
77
+ model?: Model;
78
+ /** Authentication token id */
79
+ tokenId?: string;
80
+ /** Request raw body */
81
+ rawBody: Buffer[];
82
+ /** Request raw body size */
83
+ rawBodySize: number;
84
+ private constructor();
85
+ /** Update request url */
86
+ updateUrl(url: string): void;
87
+ /** Rewrite request url */
88
+ rewrite(url: string): void;
89
+ /** Request body: JSON or POST parameters */
90
+ get body(): {
91
+ [key: string]: any;
92
+ };
93
+ /** Alias to body */
94
+ get post(): {
95
+ [key: string]: any;
96
+ };
97
+ /** Get websocket */
98
+ get websocket(): WebSocket;
99
+ /** get files list in request */
100
+ files(): Promise<any[] | undefined>;
101
+ /** Decode request body */
102
+ bodyDecode(res: ServerResponse, options: any, next: () => void): void;
103
+ }
104
+ /** Extends http.ServerResponse */
105
+ export declare class ServerResponse extends http.ServerResponse {
106
+ req: ServerRequest;
107
+ router: Router;
108
+ isJson: boolean;
109
+ headersOnly: boolean;
110
+ private constructor();
111
+ /** Send error reponse */
112
+ error(error: string | number | Error, text?: string): void;
113
+ /** Sets Content-Type acording to data and sends response */
114
+ send(data?: string | Buffer | Error | Readable | object): void;
115
+ /** Send json response */
116
+ json(data: any): void;
117
+ /** Send json response in form { success: false, error: err } */
118
+ jsonError(error: string | number | object | Error, code?: number): void;
119
+ /** Send json response in form { success: true, ... } */
120
+ jsonSuccess(data?: object | string, code?: number): void;
121
+ /** Send redirect response to specified URL with optional status code (default: 302) */
122
+ redirect(code: number | string, url?: string): void;
123
+ }
124
+ /** WebSocket options */
125
+ export interface WebSocketOptions {
126
+ maxPayload?: number;
127
+ autoPong?: boolean;
128
+ permessageDeflate?: boolean;
129
+ maxWindowBits?: number;
130
+ deflate?: boolean;
131
+ }
132
+ /** WebSocket class */
133
+ export declare class WebSocket extends EventEmitter {
134
+ ready: boolean;
135
+ constructor(req: ServerRequest, options?: WebSocketOptions);
136
+ /** Close connection */
137
+ close(reason?: number, data?: Buffer): void;
138
+ /** Generate WebSocket frame from data */
139
+ static getFrame(data: number | string | Buffer | undefined, options?: any): Buffer;
140
+ /** Send data */
141
+ send(data: string | Buffer): void;
142
+ /** Send ping frame */
143
+ ping(buffer?: Buffer): void;
144
+ /** Send pong frame */
145
+ pong(buffer?: Buffer): void;
146
+ protected _sendFrame(opcode: number, data: Buffer, cb?: () => void): void;
147
+ }
148
+ /**
149
+ * Controller for dynamic routes
150
+ *
151
+ * @example
152
+ * ```js
153
+ * class MyController extends Controller {
154
+ * static model = MyModel;
155
+ * static acl = 'auth';
156
+ *
157
+ * static 'acl:index' = '';
158
+ * static 'url:index' = 'GET /index';
159
+ * async index (req, res) {
160
+ * res.send('Hello World')
161
+ * }
162
+ *
163
+ * //function name prefixes translated to HTTP methods:
164
+ * // all => GET, get => GET, insert => POST, post => POST,
165
+ * // update => PUT, put => PUT, delete => DELETE,
166
+ * // modify => PATCH, patch => PATCH,
167
+ * // websocket => internal WebSocket
168
+ * // automatic acl will be: class_name + '/' + function_name_prefix
169
+ * // automatic url will be: method + ' /' + class_name + '/' + function_name_without_prefix
170
+ *
171
+ * //static 'acl:allUsers' = 'MyController/all';
172
+ * //static 'url:allUsers' = 'GET /MyController/Users';
173
+ * async allUsers () {
174
+ * return ['usr1', 'usr2', 'usr3']
175
+ * }
176
+ *
177
+ * //static 'acl:getOrder' = 'MyController/get';
178
+ * //static 'url:getOrder' = 'GET /Users/:id/:id1';
179
+ * static 'group:getOrder' = 'orders';
180
+ * static 'model:getOrder' = OrderModel;
181
+ * async getOrder (id: string, id1: string) {
182
+ * return {id, extras: id1, type: 'order'}
183
+ * }
184
+ *
185
+ * //static 'acl:insertOrder' = 'MyController/insert';
186
+ * //static 'url:insertOrder' = 'POST /Users/:id';
187
+ * static 'model:insertOrder' = OrderModel;
188
+ * async insertOrder (id: string, id1: string) {
189
+ * return {id, extras: id1, type: 'order'}
190
+ * }
191
+ *
192
+ * static 'acl:POST /login' = '';
193
+ * async 'POST /login' () {
194
+ * return {id, extras: id1, type: 'order'}
195
+ * }
196
+ * }
197
+ * ```
198
+ */
199
+ export declare class Controller {
200
+ protected req: ServerRequest;
201
+ protected res: ServerResponse;
202
+ model?: Model;
203
+ constructor(req: ServerRequest, res: ServerResponse);
204
+ /** Generate routes for this controller */
205
+ static routes(): any[];
206
+ }
207
+ /** Middleware */
208
+ export interface Middleware {
209
+ (req: ServerRequest, res: ServerResponse, next: Function): any;
210
+ /** @default 0 */
211
+ priority?: number;
212
+ plugin?: Plugin;
213
+ }
214
+ /** Router */
215
+ export declare class Router extends EventEmitter {
216
+ server: MicroServer;
217
+ auth?: Auth;
218
+ /** @param {MicroServer} server */
219
+ constructor(server: MicroServer);
220
+ /** Handler */
221
+ handler(req: ServerRequest, res: ServerResponse, next: Function, method?: string): any;
222
+ /** Clear routes and middlewares */
223
+ clear(): this;
224
+ /**
225
+ * Add middleware route.
226
+ * Middlewares may return promises for res.jsonSuccess(...), throw errors for res.error(...), return string or {} for res.send(...)
227
+ *
228
+ * @signature add(plugin: Plugin)
229
+ * @param {Plugin} plugin plugin module instance
230
+ * @return {Router} current router
231
+ *
232
+ * @signature add(pluginid: string, ...args: any)
233
+ * @param {string} pluginid pluginid module
234
+ * @param {...any} args arguments passed to constructor
235
+ * @return {Router} current router
236
+ *
237
+ * @signature add(pluginClass: typeof Plugin, ...args: any)
238
+ * @param {typeof Plugin} pluginClass plugin class
239
+ * @param {...any} args arguments passed to constructor
240
+ * @return {Router} current router
241
+ *
242
+ * @signature add(middleware: Middleware)
243
+ * @param {Middleware} middleware
244
+ * @return {Router} current router
245
+ *
246
+ * @signature add(methodUrl: string, ...middlewares: any)
247
+ * @param {string} methodUrl 'METHOD /url' or '/url'
248
+ * @param {...any} middlewares
249
+ * @return {Router} current router
250
+ *
251
+ * @signature add(methodUrl: string, controllerClass: typeof Controller)
252
+ * @param {string} methodUrl 'METHOD /url' or '/url'
253
+ * @param {typeof Controller} controllerClass
254
+ * @return {Router} current router
255
+ *
256
+ * @signature add(methodUrl: string, routes: Array<Array<any>>)
257
+ * @param {string} methodUrl 'METHOD /url' or '/url'
258
+ * @param {Array<Array<any>>} routes list with subroutes: ['METHOD /suburl', ...middlewares]
259
+ * @return {Router} current router
260
+ *
261
+ * @signature add(methodUrl: string, routes: Array<Array<any>>)
262
+ * @param {string} methodUrl 'METHOD /url' or '/url'
263
+ * @param {Array<Array<any>>} routes list with subroutes: ['METHOD /suburl', ...middlewares]
264
+ * @return {Router} current router
265
+ *
266
+ * @signature add(routes: { [key: string]: Array<any> })
267
+ * @param { {[key: string]: Array<any>} } routes list with subroutes: 'METHOD /suburl': [...middlewares]
268
+ * @return {Router} current router
269
+ *
270
+ * @signature add(methodUrl: string, routes: { [key: string]: Array<any> })
271
+ * @param {string} methodUrl 'METHOD /url' or '/url'
272
+ * @param { {[key: string]: Array<any>} } routes list with subroutes: 'METHOD /suburl': [...middlewares]
273
+ * @return {Router} current router
274
+ */
275
+ add(...args: any): Router;
276
+ /** Add hook */
277
+ hook(url: string, ...mid: Middleware[]): Router;
278
+ /** Check if middleware allready added */
279
+ has(mid: Middleware): boolean;
280
+ }
281
+ export interface HttpHandler {
282
+ (req: ServerRequest, res: ServerResponse): void;
283
+ }
284
+ export interface TcpHandler {
285
+ (socket: net.Socket): void;
286
+ }
287
+ export interface ListenConfig {
288
+ /** listen port(s) with optional protocol and host (Ex. 8080 or '0.0.0.0:8080,8180' or 'https://0.0.0.0:8080' or 'tcp://0.0.0.0:8080' or 'tls://0.0.0.0:8080') */
289
+ listen?: string | number;
290
+ /** tls options */
291
+ tls?: {
292
+ cert: string;
293
+ key: string;
294
+ ca?: string;
295
+ };
296
+ /** custom handler */
297
+ handler?: HttpHandler | TcpHandler;
298
+ }
299
+ export interface CorsOptions {
300
+ /** allowed origins (default: '*') */
301
+ origin: string;
302
+ /** allowed headers (default: '*') */
303
+ headers: string;
304
+ /** allow credentials (default: false) */
305
+ credentials: boolean;
306
+ /** Expose headers */
307
+ expose?: string;
308
+ /** Max age */
309
+ maxAge?: number;
310
+ }
311
+ /** MicroServer configuration */
312
+ export interface MicroServerConfig extends ListenConfig {
313
+ /** server instance root path */
314
+ root?: string;
315
+ /** Auth options */
316
+ auth?: AuthOptions;
317
+ /** routes to add */
318
+ routes?: any;
319
+ /** Static file options */
320
+ static?: StaticOptions;
321
+ /** max body size (default: 5MB) */
322
+ maxBodySize?: number;
323
+ /** allowed HTTP methods */
324
+ methods?: string;
325
+ /** trust proxy */
326
+ trustProxy?: string[];
327
+ /** cors options */
328
+ cors?: string | CorsOptions | boolean;
329
+ /** upload dir (default: './upload') */
330
+ uploadDir?: string;
331
+ /** allow websocket deflate compression (default: false) */
332
+ websocketCompress?: boolean;
333
+ /** max websocket payload (default: 1MB) */
334
+ websocketMaxPayload?: number;
335
+ /** websocket max window bits 8-15 for deflate (default: 10) */
336
+ websocketMaxWindowBits?: number;
337
+ /** extra options for plugins */
338
+ [key: string]: any;
339
+ }
340
+ export declare class MicroServer extends EventEmitter {
341
+ /** server configuration */
342
+ config: MicroServerConfig;
343
+ /** main router */
344
+ router: Router;
345
+ /** virtual host routers */
346
+ vhosts?: {
347
+ [key: string]: Router;
348
+ };
349
+ /** all sockets */
350
+ sockets: Set<net.Socket>;
351
+ /** server instances */
352
+ servers: Set<net.Server>;
353
+ static plugins: {
354
+ [key: string]: PluginClass;
355
+ };
356
+ plugins: {
357
+ [key: string]: Plugin;
358
+ };
359
+ constructor(config: MicroServerConfig);
360
+ /** Add one time listener or call immediatelly for 'ready' */
361
+ once(name: string, cb: Function): this;
362
+ /** Add listener and call immediatelly for 'ready' */
363
+ on(name: string, cb: Function): this;
364
+ /** Listen server, should be used only if config.listen is not set */
365
+ listen(config?: ListenConfig): Promise<unknown>;
366
+ /** 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' */
367
+ bind(fn: string | Function | object): Function;
368
+ /** Add middleware, routes, etc.. see {Router.add} */
369
+ use(...args: any): MicroServer;
370
+ /** Default server handler */
371
+ handler(req: ServerRequest, res: ServerResponse): void;
372
+ protected requestInit(req: ServerRequest, res?: ServerResponse): void;
373
+ /** Preprocess request, used by {MicroServer.handler} */
374
+ handlerInit(req: ServerRequest, res: ServerResponse, next: Function): void;
375
+ /** Last request handler */
376
+ handlerLast(req: ServerRequest, res: ServerResponse, next?: Function): any;
377
+ /** Default upgrade handler, used for WebSockets */
378
+ handlerUpgrade(req: ServerRequest, socket: net.Socket, head: any): void;
379
+ /** Close server instance */
380
+ close(): Promise<void>;
381
+ /** Add route, alias to `server.router.add('GET ' + url, ...args)` */
382
+ get(url: string, ...args: any): MicroServer;
383
+ /** Add route, alias to `server.router.add('POST ' + url, ...args)` */
384
+ post(url: string, ...args: any): MicroServer;
385
+ /** Add route, alias to `server.router.add('PUT ' + url, ...args)` */
386
+ put(url: string, ...args: any): MicroServer;
387
+ /** Add route, alias to `server.router.add('PATCH ' + url, ...args)` */
388
+ patch(url: string, ...args: any): MicroServer;
389
+ /** Add route, alias to `server.router.add('DELETE ' + url, ...args)` */
390
+ delete(url: string, ...args: any): MicroServer;
391
+ /** Add websocket handler, alias to `server.router.add('WEBSOCKET ' + url, ...args)` */
392
+ websocket(url: string, ...args: any): MicroServer;
393
+ /** Add router hook, alias to `server.router.hook(url, ...args)` */
394
+ hook(url: string, ...args: any): MicroServer;
395
+ }
396
+ /** Static files options */
397
+ export interface StaticOptions {
398
+ /** files root directory */
399
+ root?: string;
400
+ /** url path */
401
+ path?: string;
402
+ /** additional mime types */
403
+ mimeTypes?: {
404
+ [key: string]: string;
405
+ };
406
+ /** file extension handlers */
407
+ handlers?: {
408
+ [key: string]: Middleware;
409
+ };
410
+ /** ignore prefixes */
411
+ ignore?: string[];
412
+ /** index file. default: 'index.html' */
413
+ index?: string;
414
+ /** Update Last-Modified header. default: true */
415
+ lastModified?: boolean;
416
+ /** Update ETag header. default: true */
417
+ etag?: boolean;
418
+ /** Max file age in seconds */
419
+ maxAge?: number;
420
+ }
421
+ /** Proxy plugin options */
422
+ export interface ProxyPluginOptions {
423
+ /** Base path */
424
+ path?: string;
425
+ /** Remote url */
426
+ remote?: string;
427
+ /** Match regex filter */
428
+ match?: string;
429
+ /** Override/set headers for remote */
430
+ headers?: {
431
+ [key: string]: string;
432
+ };
433
+ /** Valid headers to forward */
434
+ validHeaders?: {
435
+ [key: string]: boolean;
436
+ };
437
+ }
438
+ export declare class ProxyPlugin extends Plugin {
439
+ /** Default valid headers */
440
+ static validHeaders: {
441
+ [key: string]: boolean;
442
+ };
443
+ /** Current valid headers */
444
+ validHeaders: {
445
+ [key: string]: boolean;
446
+ };
447
+ /** Override headers to forward to remote */
448
+ headers: {
449
+ [key: string]: string;
450
+ } | undefined;
451
+ /** Remote url */
452
+ remoteUrl: URL;
453
+ /** Match regex filter */
454
+ regex?: RegExp;
455
+ constructor(router: Router, options?: ProxyPluginOptions | string);
456
+ /** Default proxy handler */
457
+ proxyHandler(req: ServerRequest, res: ServerResponse, next: Function): any;
458
+ /** Proxy plugin handler as middleware */
459
+ handler?(req: ServerRequest, res: ServerResponse, next: Function): void;
460
+ }
461
+ /** User info */
462
+ export interface UserInfo {
463
+ /** User id */
464
+ id: string;
465
+ /** User password plain or hash */
466
+ password?: string;
467
+ /** ACL options */
468
+ acl?: {
469
+ [key: string]: boolean;
470
+ };
471
+ /** User group */
472
+ group?: string;
473
+ /** Custom user data */
474
+ [key: string]: any;
475
+ }
476
+ /** Authentication options */
477
+ export interface AuthOptions {
478
+ /** Authentication token */
479
+ token: string | Buffer;
480
+ /** Users */
481
+ users?: {
482
+ [key: string]: UserInfo;
483
+ } | ((usr: string, psw?: string) => Promise<UserInfo | undefined>);
484
+ /** Default ACL */
485
+ defaultAcl?: {
486
+ [key: string]: boolean;
487
+ };
488
+ /** Expire time in seconds */
489
+ expire?: number;
490
+ /** Authentication mode */
491
+ mode?: 'cookie' | 'token';
492
+ /** Authentication realm for basic authentication */
493
+ realm?: string;
494
+ /** Redirect URL */
495
+ redirect?: string;
496
+ /** Authentication cache */
497
+ cache?: {
498
+ [key: string]: {
499
+ data: UserInfo;
500
+ time: number;
501
+ };
502
+ };
503
+ /** Interal next cache cleanup time */
504
+ cacheCleanup?: number;
505
+ }
506
+ /** Authentication class */
507
+ export declare class Auth {
508
+ /** Server request */
509
+ req: ServerRequest | undefined;
510
+ /** Server response */
511
+ res: ServerResponse | undefined;
512
+ /** Authentication options */
513
+ options: AuthOptions;
514
+ /** Get user function */
515
+ users: ((usr: string, psw?: string, salt?: string) => Promise<UserInfo | undefined>);
516
+ constructor(options?: AuthOptions);
517
+ /** Decode token */
518
+ decode(data: string): {
519
+ data: string;
520
+ expire: number;
521
+ };
522
+ /** Encode token */
523
+ encode(data: string, expire?: number): string;
524
+ /**
525
+ * Check acl over authenticated user with: `id`, `group/*`, `*`
526
+ * @param {string} id - to authenticate: `id`, `group/id`, `model/action`, comma separated best: true => false => def
527
+ * @param {boolean} [def=false] - default access
528
+ */
529
+ acl(id: string, def?: boolean): boolean;
530
+ /**
531
+ * Authenticate user and setup cookie
532
+ * @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}})
533
+ * @param {string} [psw] - user password (if used for user authentication with options.users)
534
+ * @param {number} [expire] - expire time in seconds (default: options.expire)
535
+ */
536
+ token(usr: string | UserInfo | undefined, psw: string | undefined, expire?: number): Promise<string | undefined>;
537
+ /**
538
+ * Authenticate user and setup cookie
539
+ */
540
+ login(usr: string | UserInfo | undefined, psw?: string, options?: {
541
+ expire?: number;
542
+ salt?: string;
543
+ }): Promise<UserInfo | undefined>;
544
+ /** Logout logged in user */
545
+ logout(): void;
546
+ /** Get hashed string from user and password */
547
+ password(usr: string, psw: string, salt?: string): string;
548
+ /** Get hashed string from user and password */
549
+ static password(usr: string, psw: string, salt?: string): string;
550
+ /** Validate user password */
551
+ checkPassword(usr: string, psw: string, storedPsw: string, salt?: string): boolean;
552
+ /** Validate user password */
553
+ static checkPassword(usr: string, psw: string, storedPsw: string, salt?: string): boolean;
554
+ /** Clear user cache if users setting where changed */
555
+ clearCache(): void;
556
+ }
557
+ /** Create microserver */
558
+ export declare function create(config: MicroServerConfig): MicroServer;
559
+ export interface FileStoreOptions {
560
+ /** Base directory */
561
+ dir?: string;
562
+ /** Cache timeout in milliseconds */
563
+ cacheTimeout?: number;
564
+ /** Max number of cached items */
565
+ cacheItems?: number;
566
+ /** Debounce timeout in milliseconds for autosave */
567
+ debounceTimeout?: number;
568
+ }
569
+ /** JSON File store */
570
+ export declare class FileStore {
571
+ constructor(options?: FileStoreOptions);
572
+ /** cleanup cache */
573
+ cleanup(): void;
574
+ close(): Promise<void>;
575
+ sync(): Promise<void>;
576
+ /** load json file data */
577
+ load(name: string, autosave?: boolean): Promise<any>;
578
+ /** save data */
579
+ save(name: string, data: any): Promise<void>;
580
+ /** load all files in directory */
581
+ all(name: string, autosave?: boolean): Promise<{
582
+ [key: string]: any;
583
+ }>;
584
+ /** delete data file */
585
+ delete(name: string): Promise<void>;
586
+ /** Observe data object */
587
+ observe(data: object, cb: (data: object, key: string, value: any) => void): object;
588
+ }
589
+ /** Model validation options */
590
+ interface ModelValidateOptions {
591
+ /** User info */
592
+ user?: UserInfo;
593
+ /** Request params */
594
+ params?: Object;
595
+ /** is insert */
596
+ insert?: boolean;
597
+ /** is read-only */
598
+ readOnly?: boolean;
599
+ /** validate */
600
+ validate?: boolean;
601
+ /** use default */
602
+ default?: boolean;
603
+ /** is required */
604
+ required?: boolean;
605
+ /** projection fields */
606
+ projection?: Document;
607
+ }
608
+ /** Model field validation options */
609
+ interface ModelValidateFieldOptions extends ModelValidateOptions {
610
+ name: string;
611
+ field: FieldDescriptionInternal;
612
+ model: Model;
613
+ }
614
+ export interface ModelCallbackFunc {
615
+ (options: any): any;
616
+ }
617
+ /** Model field description */
618
+ export interface FieldDescriptionObject {
619
+ /** Field type */
620
+ type: string | Function | Model | Array<string | Function | Model>;
621
+ /** Is array */
622
+ array?: boolean;
623
+ /** Is required */
624
+ required?: boolean | string | ModelCallbackFunc;
625
+ /** Can read */
626
+ canRead?: boolean | string | ModelCallbackFunc;
627
+ /** Can write */
628
+ canWrite?: boolean | string | ModelCallbackFunc;
629
+ /** Default value */
630
+ default?: number | string | ModelCallbackFunc;
631
+ /** Validate function */
632
+ validate?: (value: any, options: ModelValidateOptions) => string | number | object | null | Error | typeof Error;
633
+ /** Valid values */
634
+ enum?: Array<string | number>;
635
+ /** Minimum value for string and number */
636
+ minimum?: number | string;
637
+ /** Maximum value for string and number */
638
+ maximum?: number | string;
639
+ /** Regex validation or 'email', 'url', 'date', 'time', 'date-time' */
640
+ format?: string;
641
+ }
642
+ type FieldDescription = FieldDescriptionObject | string | Function | Model | FieldDescription[];
643
+ interface FieldDescriptionInternal {
644
+ type: string;
645
+ model?: Model;
646
+ required?: ModelCallbackFunc;
647
+ canRead: ModelCallbackFunc;
648
+ canWrite: ModelCallbackFunc;
649
+ default: ModelCallbackFunc;
650
+ validate: (value: any, options: ModelValidateFieldOptions) => any;
651
+ }
652
+ export declare interface ModelCollections {
653
+ collection(name: string): Promise<MicroCollection>;
654
+ }
655
+ export declare class Model {
656
+ static collections?: ModelCollections;
657
+ static models: {
658
+ [key: string]: Model;
659
+ };
660
+ /** Define model */
661
+ static define(name: string, fields: {
662
+ [key: string]: FieldDescription;
663
+ }, options?: {
664
+ collection?: MicroCollection | Promise<MicroCollection>;
665
+ class?: typeof Model;
666
+ }): Model;
667
+ /** Model fields description */
668
+ model: {
669
+ [key: string]: FieldDescriptionInternal;
670
+ };
671
+ /** Model name */
672
+ name: string;
673
+ /** Model collection for persistance */
674
+ collection?: MicroCollection | Promise<MicroCollection>;
675
+ /** Create model acording to description */
676
+ constructor(fields: {
677
+ [key: string]: FieldDescription;
678
+ }, options?: {
679
+ collection?: MicroCollection | Promise<MicroCollection>;
680
+ name?: string;
681
+ });
682
+ /** Validate data over model */
683
+ validate(data: Document, options?: ModelValidateOptions): Document;
684
+ /** Generate filter for data queries */
685
+ getFilter(data: Document, options?: ModelValidateOptions): Document;
686
+ /** Find one document */
687
+ findOne(query: Query, options?: ModelValidateOptions): Promise<Document | undefined>;
688
+ /** Find many documents */
689
+ findMany(query: Query, options?: ModelValidateOptions): Promise<Document[]>;
690
+ /** Insert a new document */
691
+ insert(data: Document, options?: ModelValidateOptions): Promise<void>;
692
+ /** Update one matching document */
693
+ update(query: Query, options?: ModelValidateOptions): Promise<void>;
694
+ /** Delete one matching document */
695
+ delete(query: Query, options?: ModelValidateOptions): Promise<void>;
696
+ /** Microserver middleware */
697
+ handler(req: ServerRequest, res: ServerResponse): any;
698
+ }
699
+ export declare interface MicroCollectionOptions {
700
+ /** Collection name */
701
+ name?: string;
702
+ /** Collection persistent store */
703
+ store?: FileStore;
704
+ /** Custom data loader */
705
+ load?: (col: MicroCollection) => Promise<object>;
706
+ /** Custom data saver */
707
+ save?: (id: string, doc: Document | undefined, col: MicroCollection) => Promise<Document>;
708
+ /** Preloaded data object */
709
+ data?: {
710
+ [key: string]: Document;
711
+ };
712
+ }
713
+ export declare interface Query {
714
+ [key: string]: any;
715
+ }
716
+ export declare interface Document {
717
+ [key: string]: any;
718
+ }
719
+ /** Cursor */
720
+ export declare interface Cursor {
721
+ forEach(cb: Function, self?: any): Promise<number>;
722
+ all(): Promise<Document[]>;
723
+ }
724
+ /** Find options */
725
+ export declare interface FindOptions {
726
+ /** Query */
727
+ query?: Query;
728
+ /** is upsert */
729
+ upsert?: boolean;
730
+ /** is new */
731
+ new?: boolean;
732
+ /** update object */
733
+ update?: Query;
734
+ /** maximum number of hits */
735
+ limit?: number;
736
+ }
737
+ /** minimalistic indexed mongo type collection with persistance for usage with Model */
738
+ export declare class MicroCollection {
739
+ /** Collection name */
740
+ name: string;
741
+ /** Collection data */
742
+ data: {
743
+ [key: string]: Document;
744
+ };
745
+ /** Get collections factory */
746
+ static collections(options: MicroCollectionOptions): ModelCollections;
747
+ constructor(options?: MicroCollectionOptions);
748
+ /** check for collection is ready */
749
+ protected checkReady(): Promise<void>;
750
+ /** Query document with query filter */
751
+ protected queryDocument(query?: Query, data?: Document): Document;
752
+ /** Count all documents */
753
+ count(): Promise<number>;
754
+ /** Find one matching document */
755
+ findOne(query: Query): Promise<Document | undefined>;
756
+ /** Find all matching documents */
757
+ find(query: Query): Cursor;
758
+ /** Find and modify one matching document */
759
+ findAndModify(options: FindOptions): Promise<number>;
760
+ /** Insert one document */
761
+ insertOne(doc: Document): Promise<Document>;
762
+ /** Insert multiple documents */
763
+ insert(docs: Document[]): Promise<Document[]>;
764
+ /** Delete one matching document */
765
+ deleteOne(query: Query): Promise<void>;
766
+ /** Delete all matching documents */
767
+ deleteMany(query: Query): Promise<number>;
768
+ }
769
+