moost 0.0.1-beta.1 → 0.0.1-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.
@@ -16,7 +16,7 @@ function getMoostMate() {
16
16
  return moostMate;
17
17
  }
18
18
 
19
- const prefix = '__moost_';
19
+ const prefix = '__moost__';
20
20
  function useCacheObject(name, def) {
21
21
  const cc = wooks.useCurrentWooksContext().getCtx().customContext;
22
22
  const key = prefix + name;
@@ -37,9 +37,10 @@ function useControllerMeta() {
37
37
  getMethodMeta: () => getMoostMate().read(controller, method),
38
38
  };
39
39
  }
40
- function setComposableControllerContext(controller, method) {
41
- setCacheObject('controller', controller);
42
- setCacheObject('method', method);
40
+ function setComposableControllerContext(data) {
41
+ setCacheObject('controller', data.controller);
42
+ setCacheObject('method', data.method);
43
+ setCacheObject('pathBuilder', data.pathBuilder);
43
44
  }
44
45
 
45
46
  async function runPipes(pipes, meta, restoreCtx) {
@@ -106,7 +107,7 @@ function getNewMoostInfact() {
106
107
  }
107
108
 
108
109
  function bindHandler(getInstance, method, wooksApp, options) {
109
- wooksApp.on(options.httpMethod, options.path, async () => {
110
+ const pathBuilder = wooksApp.on(options.httpMethod, options.path, async () => {
110
111
  const { restoreCtx } = wooks.useCurrentWooksContext();
111
112
  const { reqId, rawRequest } = wooks.useRequest();
112
113
  const infact = getMoostInfact();
@@ -115,7 +116,11 @@ function bindHandler(getInstance, method, wooksApp, options) {
115
116
  rawRequest.on('end', () => infact.unregisterScope(scopeId));
116
117
  const instance = await getInstance();
117
118
  restoreCtx();
118
- setComposableControllerContext(instance, method);
119
+ setComposableControllerContext({
120
+ controller: instance,
121
+ method: method,
122
+ pathBuilder: pathBuilder,
123
+ });
119
124
  let response;
120
125
  let responseOverwritten = false;
121
126
  const before = [];
@@ -125,10 +130,12 @@ function bindHandler(getInstance, method, wooksApp, options) {
125
130
  response = reply;
126
131
  responseOverwritten = true;
127
132
  }
133
+ // init interceptors
128
134
  for (const handler of options.interceptorHandlers) {
129
135
  restoreCtx();
130
136
  await handler((fn) => { before.push(fn); }, (fn) => { after.unshift(fn); }, (fn) => { onError.unshift(fn); });
131
137
  }
138
+ // params
132
139
  let args = [];
133
140
  try {
134
141
  restoreCtx();
@@ -138,12 +145,14 @@ function bindHandler(getInstance, method, wooksApp, options) {
138
145
  response = e;
139
146
  }
140
147
  if (!response) {
148
+ // fire before interceptors
141
149
  for (const handler of before) {
142
150
  restoreCtx();
143
151
  await handler(replyFn);
144
152
  if (responseOverwritten)
145
153
  break;
146
154
  }
155
+ // fire request handler
147
156
  if (!responseOverwritten) {
148
157
  try {
149
158
  restoreCtx();
@@ -154,6 +163,7 @@ function bindHandler(getInstance, method, wooksApp, options) {
154
163
  }
155
164
  }
156
165
  }
166
+ // fire after interceptors
157
167
  if (response instanceof Error) {
158
168
  for (const handler of onError) {
159
169
  restoreCtx();
@@ -180,6 +190,7 @@ async function applyPipesToArgs(argsPipes) {
180
190
  }
181
191
 
182
192
  function getInstanceOwnMethods(instance) {
193
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
183
194
  const proto = Object.getPrototypeOf(instance);
184
195
  return [
185
196
  ...Object.getOwnPropertyNames(proto),
@@ -187,8 +198,10 @@ function getInstanceOwnMethods(instance) {
187
198
  ].filter(m => typeof instance[m] === 'function');
188
199
  }
189
200
 
201
+ /* istanbul ignore file */
190
202
  const banner = () => `[moost][${new Date().toISOString().replace('T', ' ').replace(/\.\d{3}z$/i, '')}] `;
191
203
 
204
+ /* istanbul ignore file */
192
205
  function log(text) {
193
206
  console.log('' + '' + banner() + text + '');
194
207
  }
@@ -199,6 +212,7 @@ function logError(error) {
199
212
  console.error('' + '' + banner() + error + '');
200
213
  }
201
214
 
215
+ /* istanbul ignore file */
202
216
  function panic(error) {
203
217
  logError(error);
204
218
  return new Error(error);
@@ -237,6 +251,7 @@ function bindControllerMethods(getInstance, classConstructor, wooksApp, options)
237
251
  const methodMeta = getMoostMate().read(fakeInstance, method) || {};
238
252
  if (!methodMeta.httpHandler || !methodMeta.httpHandler.length)
239
253
  continue;
254
+ // preparing interceptors
240
255
  const interceptors = [...(opts.interceptors || []), ...(meta.interceptors || []), ...(methodMeta.interceptors || [])].sort((a, b) => a.priority - b.priority);
241
256
  const interceptorHandlers = [];
242
257
  for (const { handler } of interceptors) {
@@ -253,6 +268,7 @@ function bindControllerMethods(getInstance, classConstructor, wooksApp, options)
253
268
  interceptorHandlers.push(handler);
254
269
  }
255
270
  }
271
+ // preparing pipes
256
272
  const pipes = [...(opts.pipes || []), ...(meta.pipes || []), ...(methodMeta.pipes || [])];
257
273
  const argsPipes = [];
258
274
  for (const p of methodMeta.params || []) {
@@ -261,6 +277,7 @@ function bindControllerMethods(getInstance, classConstructor, wooksApp, options)
261
277
  pipes: [...pipes, ...(p.pipes || [])].sort((a, b) => a.priority - b.priority),
262
278
  });
263
279
  }
280
+ // preparing provide
264
281
  const provide = { ...(opts.provide || {}), ...(meta.provide || {}) };
265
282
  for (const { method: httpMethod, path: httpPath } of methodMeta.httpHandler) {
266
283
  const path = typeof httpPath === 'string' ? httpPath : typeof method === 'string' ? method : '';
@@ -296,21 +313,58 @@ function Optional() {
296
313
  }
297
314
  function Required() {
298
315
  const mate = getMoostMate();
299
- return mate.apply(mate.decorate('required', true), mate.decorateClass((meta, key, index) => {
316
+ return mate.apply(mate.decorate('required', true),
317
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
318
+ mate.decorateClass((meta, key, index) => {
300
319
  if (typeof index !== 'number' && meta && ['string', 'symbol'].includes(typeof key)) {
320
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
301
321
  meta.requiredProps = meta.requiredProps || [];
322
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
302
323
  meta.requiredProps.push(key);
303
324
  }
304
325
  return meta;
305
326
  }));
306
327
  }
307
328
 
329
+ /**
330
+ * Hook to the Response Status
331
+ * @decorator
332
+ * @param resolver - resolver function
333
+ * @param label - field label
334
+ * @paramType unknown
335
+ */
308
336
  function Resolve(resolver, label) {
309
337
  return (target, key, index) => {
310
338
  fillLabel(target, key, index, label);
311
339
  getMoostMate().decorate('resolver', resolver)(target, key, index);
312
340
  };
313
341
  }
342
+ /**
343
+ * Hook to the Response Status
344
+ * @decorator
345
+ * @paramType TStatusHook
346
+ */
347
+ const StatusHook = Resolve(() => wooks.useStatus(), 'status');
348
+ /**
349
+ * Hook to the Response Header
350
+ * @decorator
351
+ * @param name - header name
352
+ * @paramType THeaderHook
353
+ */
354
+ const HeaderHook = (name) => Resolve(() => wooks.useRespHeader(name), name);
355
+ /**
356
+ * Hook to the Response Cookie
357
+ * @decorator
358
+ * @param name - header name
359
+ * @paramType TCookieHook
360
+ */
361
+ const CookieHook = (name) => Resolve(() => wooks.useRespCookie(name), name);
362
+ /**
363
+ * Parse Authorisation Header
364
+ * @decorator
365
+ * @param name - define what to take from the Auth header
366
+ * @paramType string
367
+ */
314
368
  function Authorization(name) {
315
369
  return Resolve(() => {
316
370
  var _a, _b;
@@ -329,21 +383,50 @@ function Authorization(name) {
329
383
  }
330
384
  }, 'authorization');
331
385
  }
386
+ /**
387
+ * Get Request Header Value
388
+ * @decorator
389
+ * @param name - header name
390
+ * @paramType string
391
+ */
332
392
  function Header(name) {
333
393
  return Resolve(() => {
334
394
  const headers = wooks.useHeaders();
335
395
  return headers[name];
336
396
  }, 'header: ' + name);
337
397
  }
398
+ /**
399
+ * Get Request Cookie Value
400
+ * @decorator
401
+ * @param name - cookie name
402
+ * @paramType string
403
+ */
338
404
  function Cookie(name) {
339
405
  return Resolve(() => wooks.useCookies().getCookie(name), 'cookie: ' + name);
340
406
  }
407
+ /**
408
+ * Get Param Value from url parh
409
+ * @decorator
410
+ * @param name - param name
411
+ * @paramType string
412
+ */
341
413
  function Param(name) {
342
414
  return Resolve(() => wooks.useRouteParams().getRouteParam(name), name);
343
415
  }
416
+ /**
417
+ * Get Parsed Params from url parh
418
+ * @decorator
419
+ * @paramType object
420
+ */
344
421
  function Params() {
345
422
  return Resolve(() => wooks.useRouteParams().routeParams, 'params');
346
423
  }
424
+ /**
425
+ * Get Query Item value or the whole parsed Query as an object
426
+ * @decorator
427
+ * @param name - query item name (optional)
428
+ * @paramType string | object
429
+ */
347
430
  function Query(name) {
348
431
  return Resolve(() => {
349
432
  const { jsonSearchParams, urlSearchParams } = wooks.useSearchParams();
@@ -357,33 +440,86 @@ function Query(name) {
357
440
  return Object.keys(json).length ? json : undefined;
358
441
  }, name || 'Query');
359
442
  }
443
+ /**
444
+ * Get Requested URL
445
+ * @decorator
446
+ * @paramType string
447
+ */
360
448
  function Url() {
361
449
  return Resolve(() => wooks.useRequest().url, 'url');
362
450
  }
451
+ /**
452
+ * Get Requested HTTP Method
453
+ * @decorator
454
+ * @paramType string
455
+ */
363
456
  function Method() {
364
457
  return Resolve(() => wooks.useRequest().method, 'http_method');
365
458
  }
459
+ /**
460
+ * Get Raw Request Instance
461
+ * @decorator
462
+ * @paramType IncomingMessage
463
+ */
366
464
  function Req() {
367
465
  return Resolve(() => wooks.useRequest().rawRequest, 'request');
368
466
  }
467
+ /**
468
+ * Get Request Unique Identificator (UUID)
469
+ * @decorator
470
+ * @paramType string
471
+ */
369
472
  function ReqId() {
370
473
  return Resolve(() => wooks.useRequest().reqId(), 'reqId');
371
474
  }
475
+ /**
476
+ * Get Request IP Address
477
+ * @decorator
478
+ * @paramType string
479
+ */
372
480
  function Ip(opts) {
373
481
  return Resolve(() => wooks.useRequest().getIp(opts), 'ip');
374
482
  }
483
+ /**
484
+ * Get Request IP Address list
485
+ * @decorator
486
+ * @paramType string[]
487
+ */
375
488
  function IpList() {
376
489
  return Resolve(() => wooks.useRequest().getIpList(), 'ipList');
377
490
  }
491
+ /**
492
+ * Get Raw Response Object
493
+ * @decorator
494
+ * @param options - passthrough options
495
+ * @paramType string
496
+ */
378
497
  function Res(options) {
379
498
  return Resolve(() => wooks.useResponse().rawResponse(options), 'response');
380
499
  }
500
+ /**
501
+ * Provide Const Value
502
+ * @decorator
503
+ * @param value - provided value
504
+ * @param label - label of the field
505
+ * @paramType unknown
506
+ */
381
507
  function Const(value, label) {
382
508
  return Resolve(() => value, label);
383
509
  }
510
+ /**
511
+ * Get Parsed Request Body
512
+ * @decorator
513
+ * @paramType object | string | unknown
514
+ */
384
515
  function Body() {
385
516
  return Resolve(() => wooks.useBody().parseBody(), 'body');
386
517
  }
518
+ /**
519
+ * Get Raw Request Body Buffer
520
+ * @decorator
521
+ * @paramType Promise<Buffer>
522
+ */
387
523
  function RawBody() {
388
524
  return Resolve(() => wooks.useBody().rawBody(), 'body');
389
525
  }
@@ -396,6 +532,14 @@ function fillLabel(target, key, index, name) {
396
532
  }
397
533
  }
398
534
 
535
+ /**
536
+ * Mark the Class as Injectable to enable it to be used in dependency injection
537
+ * @decorator
538
+ * @param scope - Scope for injection ("FOR_REQUEST" | "SINGLETON" | true)
539
+ * FOR_REQUEST - will create a new instance for each incoming request
540
+ * SINGLETON | true - will create a new instance only once
541
+ * @param label - field label
542
+ */
399
543
  function Injectable(scope = true) {
400
544
  return getMoostMate().decorate('injectable', scope);
401
545
  }
@@ -405,6 +549,11 @@ const insureInjectable = getMoostMate().decorate((meta) => {
405
549
  return meta;
406
550
  });
407
551
 
552
+ /**
553
+ * Set Class as a Controller
554
+ * @decorator
555
+ * @param prefix - define the prefix for all the paths of this controller
556
+ */
408
557
  function Controller(prefix) {
409
558
  const mate = getMoostMate();
410
559
  return mate.apply(insureInjectable, mate.decorate('controller', { prefix: prefix || '' }));
@@ -483,17 +632,36 @@ function IsBoolean(...args) {
483
632
  return Validate(valido$1.validoIsBoolean(...args));
484
633
  }
485
634
 
635
+ const valido = new valido$1.Valido({
636
+ getDtoMeta(value, _type) {
637
+ let type = _type;
638
+ if (!type) {
639
+ type = mate.getConstructor(value);
640
+ }
641
+ const mate$1 = getMoostMate();
642
+ return mate$1.read(type);
643
+ },
644
+ getDtoParamMeta(value, type, key) {
645
+ const mate = getMoostMate();
646
+ return mate.read(type, key);
647
+ },
648
+ });
649
+ function getMoostValido() {
650
+ return valido;
651
+ }
652
+
486
653
  class Moost {
487
654
  constructor(options) {
488
655
  this.options = options;
489
656
  this.pipes = [...sharedPipes];
490
657
  this.interceptors = [];
491
- this.provide = {};
658
+ this.provide = infact.createProvideRegistry([infact.Infact, getMoostInfact], [mate.Mate, getMoostMate], [valido$1.Valido, getMoostValido]);
492
659
  this.unregisteredControllers = [];
493
660
  }
494
661
  async listen(port, hostname, cb) {
495
662
  var _a, _b, _c;
496
663
  this.wooksApp = new wooks.Wooks((_a = this.options) === null || _a === void 0 ? void 0 : _a.wooksOptions);
664
+ this.setProvideRegistry(infact.createProvideRegistry([wooks.Wooks, () => this.wooksApp], [Moost, () => this]));
497
665
  const _port = Number(((_b = this.options) === null || _b === void 0 ? void 0 : _b.port) || port);
498
666
  const _hostname = ((_c = this.options) === null || _c === void 0 ? void 0 : _c.hostname) || hostname;
499
667
  if (!_port) {
@@ -541,10 +709,13 @@ class Moost {
541
709
  instance = controller;
542
710
  infact.setProvideRegByInstance(instance, provide);
543
711
  }
712
+ // getInstance - instance factory for resolving SINGLETON and FOR_REQUEST instance
544
713
  const getInstance = instance ? () => Promise.resolve(instance) : async () => {
714
+ // if (!instance) {
545
715
  infact.silent();
546
716
  const instance = await infact.get(controller, provide);
547
717
  infact.silent(false);
718
+ // }
548
719
  return instance;
549
720
  };
550
721
  const classConstructor = mate.isConstructor(controller) ? controller : mate.getConstructor(controller);
@@ -602,10 +773,20 @@ class Moost {
602
773
  }
603
774
  return this;
604
775
  }
776
+ /**
777
+ * Register new entried to provide as dependency injections
778
+ * @param provide - Provide Registry (use createProvideRegistry from '\@prostojs/infact')
779
+ * @returns
780
+ */
605
781
  setProvideRegistry(provide) {
606
782
  this.provide = { ...this.provide, ...provide };
607
783
  return this;
608
784
  }
785
+ /**
786
+ * Register controllers (similar to @ImportController decorator)
787
+ * @param controllers - list of target controllers (instances)
788
+ * @returns
789
+ */
609
790
  registerControllers(...controllers) {
610
791
  this.unregisteredControllers.push(...controllers);
611
792
  return this;
@@ -671,24 +852,6 @@ function typeError(value, targetType, label) {
671
852
  throw new wooks.WooksError(400, `${prefix}${JSON.stringify(value)} is not a ${targetType} type`);
672
853
  }
673
854
 
674
- const valido = new valido$1.Valido({
675
- getDtoMeta(value, _type) {
676
- let type = _type;
677
- if (!type) {
678
- type = mate.getConstructor(value);
679
- }
680
- const mate$1 = getMoostMate();
681
- return mate$1.read(type);
682
- },
683
- getDtoParamMeta(value, type, key) {
684
- const mate = getMoostMate();
685
- return mate.read(type, key);
686
- },
687
- });
688
- function getMoostValido() {
689
- return valido;
690
- }
691
-
692
855
  const DEFAULT_ERROR_LIMIT = 10;
693
856
  function firstString(errors) {
694
857
  const keys = Object.keys(errors);
@@ -725,10 +888,12 @@ exports.Circular = Circular;
725
888
  exports.Const = Const;
726
889
  exports.Controller = Controller;
727
890
  exports.Cookie = Cookie;
891
+ exports.CookieHook = CookieHook;
728
892
  exports.Delete = Delete;
729
893
  exports.Dto = Dto;
730
894
  exports.Get = Get;
731
895
  exports.Header = Header;
896
+ exports.HeaderHook = HeaderHook;
732
897
  exports.HttpMethod = HttpMethod;
733
898
  exports.ImportController = ImportController;
734
899
  exports.Inject = Inject;
@@ -758,6 +923,7 @@ exports.ReqId = ReqId;
758
923
  exports.Required = Required;
759
924
  exports.Res = Res;
760
925
  exports.Resolve = Resolve;
926
+ exports.StatusHook = StatusHook;
761
927
  exports.Url = Url;
762
928
  exports.Validate = Validate;
763
929
  exports.genericTypesCastPipe = genericTypesCastPipe;