@merkaly/nest 0.1.6 → 0.1.8

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 (102) hide show
  1. package/README.md +159 -0
  2. package/dist/config/env.d.ts +17 -0
  3. package/dist/config/env.d.ts.map +1 -0
  4. package/dist/config/env.js +67 -0
  5. package/dist/config/env.js.map +1 -0
  6. package/dist/config/index.d.ts +2 -0
  7. package/dist/config/index.d.ts.map +1 -0
  8. package/dist/config/index.js +18 -0
  9. package/dist/config/index.js.map +1 -0
  10. package/dist/events/index.d.ts +3 -0
  11. package/dist/events/index.d.ts.map +1 -0
  12. package/dist/events/index.js +19 -0
  13. package/dist/events/index.js.map +1 -0
  14. package/dist/events/webhook-event.d.ts +12 -0
  15. package/dist/events/webhook-event.d.ts.map +1 -0
  16. package/dist/events/webhook-event.js +11 -0
  17. package/dist/events/webhook-event.js.map +1 -0
  18. package/dist/events/webhook-patterns.d.ts +52 -0
  19. package/dist/events/webhook-patterns.d.ts.map +1 -0
  20. package/dist/events/webhook-patterns.js +49 -0
  21. package/dist/events/webhook-patterns.js.map +1 -0
  22. package/dist/filters/abstract.filter.d.ts +12 -0
  23. package/dist/filters/abstract.filter.d.ts.map +1 -0
  24. package/dist/filters/abstract.filter.js +55 -0
  25. package/dist/filters/abstract.filter.js.map +1 -0
  26. package/dist/filters/exceptions.filter.d.ts +5 -0
  27. package/dist/filters/exceptions.filter.d.ts.map +1 -0
  28. package/dist/filters/exceptions.filter.js +37 -0
  29. package/dist/filters/exceptions.filter.js.map +1 -0
  30. package/dist/filters/index.d.ts +3 -0
  31. package/dist/filters/index.d.ts.map +1 -0
  32. package/dist/filters/index.js +19 -0
  33. package/dist/filters/index.js.map +1 -0
  34. package/dist/http/body-parsers.d.ts +9 -0
  35. package/dist/http/body-parsers.d.ts.map +1 -0
  36. package/dist/http/body-parsers.js +26 -0
  37. package/dist/http/body-parsers.js.map +1 -0
  38. package/dist/http/index.d.ts +3 -0
  39. package/dist/http/index.d.ts.map +1 -0
  40. package/dist/http/index.js +19 -0
  41. package/dist/http/index.js.map +1 -0
  42. package/dist/http/request-logger.d.ts +11 -0
  43. package/dist/http/request-logger.d.ts.map +1 -0
  44. package/dist/http/request-logger.js +30 -0
  45. package/dist/http/request-logger.js.map +1 -0
  46. package/dist/index.d.ts +7 -1
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +21 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/logger/index.d.ts +5 -0
  51. package/dist/logger/index.d.ts.map +1 -0
  52. package/dist/logger/index.js +21 -0
  53. package/dist/logger/index.js.map +1 -0
  54. package/dist/logger/logger.module.d.ts +8 -0
  55. package/dist/logger/logger.module.d.ts.map +1 -0
  56. package/dist/logger/logger.module.js +43 -0
  57. package/dist/logger/logger.module.js.map +1 -0
  58. package/dist/logger/logger.options.d.ts +22 -0
  59. package/dist/logger/logger.options.d.ts.map +1 -0
  60. package/dist/logger/logger.options.js +5 -0
  61. package/dist/logger/logger.options.js.map +1 -0
  62. package/dist/logger/logger.service.d.ts +18 -0
  63. package/dist/logger/logger.service.d.ts.map +1 -0
  64. package/dist/logger/logger.service.js +90 -0
  65. package/dist/logger/logger.service.js.map +1 -0
  66. package/dist/logger/request-context.d.ts +14 -0
  67. package/dist/logger/request-context.d.ts.map +1 -0
  68. package/dist/logger/request-context.js +38 -0
  69. package/dist/logger/request-context.js.map +1 -0
  70. package/dist/rabbit/events.publisher.d.ts +18 -0
  71. package/dist/rabbit/events.publisher.d.ts.map +1 -0
  72. package/dist/rabbit/events.publisher.js +95 -0
  73. package/dist/rabbit/events.publisher.js.map +1 -0
  74. package/dist/rabbit/index.d.ts +5 -0
  75. package/dist/rabbit/index.d.ts.map +1 -0
  76. package/dist/rabbit/index.js +21 -0
  77. package/dist/rabbit/index.js.map +1 -0
  78. package/dist/rabbit/rabbit.consumer.d.ts +12 -0
  79. package/dist/rabbit/rabbit.consumer.d.ts.map +1 -0
  80. package/dist/rabbit/rabbit.consumer.js +30 -0
  81. package/dist/rabbit/rabbit.consumer.js.map +1 -0
  82. package/dist/rabbit/rabbit.module.d.ts +8 -0
  83. package/dist/rabbit/rabbit.module.d.ts.map +1 -0
  84. package/dist/rabbit/rabbit.module.js +63 -0
  85. package/dist/rabbit/rabbit.module.js.map +1 -0
  86. package/dist/rabbit/rabbit.options.d.ts +19 -0
  87. package/dist/rabbit/rabbit.options.d.ts.map +1 -0
  88. package/dist/rabbit/rabbit.options.js +7 -0
  89. package/dist/rabbit/rabbit.options.js.map +1 -0
  90. package/dist/signature/index.d.ts +3 -0
  91. package/dist/signature/index.d.ts.map +1 -0
  92. package/dist/signature/index.js +19 -0
  93. package/dist/signature/index.js.map +1 -0
  94. package/dist/signature/signature.guard.d.ts +11 -0
  95. package/dist/signature/signature.guard.d.ts.map +1 -0
  96. package/dist/signature/signature.guard.js +23 -0
  97. package/dist/signature/signature.guard.js.map +1 -0
  98. package/dist/signature/signature.util.d.ts +9 -0
  99. package/dist/signature/signature.util.d.ts.map +1 -0
  100. package/dist/signature/signature.util.js +21 -0
  101. package/dist/signature/signature.util.js.map +1 -0
  102. package/package.json +21 -39
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.publisher.js","sourceRoot":"","sources":["../../src/rabbit/events.publisher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAOwB;AAExB,+BAA8C;AAE9C,sCAA0C;AAC1C,qDAO0B;AAE1B,MAAM,QAAQ,GAAG,CAAC,KAAU,EAAU,EAAE,CACtC,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,GAAG,EAAE,OAAO;IACnB,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAGvD,IAAM,eAAe,uBAArB,MAAM,eAAe;IAMiB;IACO;IANjC,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IACzC,MAAM,CAAgB;IAC/B,YAAY,CAAe;IAEnC,YAC2C,OAA4B,EACrB,OAAmC,EACvE,MAAsB;QAFO,YAAO,GAAP,OAAO,CAAqB;QACrB,YAAO,GAAP,OAAO,CAA4B;QAGnF,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,IAAI,sBAAa,EAAE,CAAC;QAC5C,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC;IAC1D,CAAC;IAED,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAEM,sBAAsB;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBACtB,KAAK,EAAE,iBAAe,CAAC,IAAI;gBAC3B,OAAO,EAAE,uEAAuE;gBAChF,IAAI,EAAE,OAAO;aACd,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE/C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;YAClC,IAAI,CAAC,YAAY,GAAG,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACtC,IAAI,CAAC,YAAY,GAAG,cAAc,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;gBAChB,KAAK,EAAE,iBAAe,CAAC,IAAI;gBAC3B,OAAO,EAAE,uBAAuB,QAAQ,CAAC,KAAK,CAAC,EAAE;gBACjD,IAAI,EAAE,OAAO;aACd,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,qBAAqB;QAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACjF,CAAC;IAEM,OAAO,CACZ,OAAuC,EACvC,KAAsB;QAEtB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,oCAA2B,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC3F,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QACnE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,wCAAuB,CAAC;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAA,cAAO,EAAC,EAAE,CAAC,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,iBAAe,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAE3D,OAAO,IAAA,oBAAa,EAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;aACxD,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,KAAK,CAAC,EAAE,QAAQ,KAAK,EAAE,EAAE,CAAC,CAAC;aACxF,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;gBAChB,GAAG,GAAG;gBACN,OAAO,EAAE,GAAG,OAAO,KAAK,KAAK,CAAC,EAAE,QAAQ,KAAK,YAAY,QAAQ,CAAC,KAAK,CAAC,EAAE;aAC3E,CAAC,CAAC;YAEH,MAAM,IAAI,oCAA2B,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,OAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAE5E,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;IAClC,CAAC;CACF,CAAA;AA7EY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;IAOR,WAAA,IAAA,eAAM,EAAC,+BAAc,CAAC,CAAA;IACtB,WAAA,IAAA,eAAM,EAAC,sCAAqB,CAAC,CAAA;IAC7B,WAAA,IAAA,iBAAQ,GAAE,CAAA;qDAAU,sBAAa;GARzB,eAAe,CA6E3B"}
@@ -0,0 +1,5 @@
1
+ export * from './events.publisher';
2
+ export * from './rabbit.consumer';
3
+ export * from './rabbit.module';
4
+ export * from './rabbit.options';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rabbit/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./events.publisher"), exports);
18
+ __exportStar(require("./rabbit.consumer"), exports);
19
+ __exportStar(require("./rabbit.module"), exports);
20
+ __exportStar(require("./rabbit.options"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rabbit/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,oDAAkC;AAClC,kDAAgC;AAChC,mDAAiC"}
@@ -0,0 +1,12 @@
1
+ import { RmqContext, RmqOptions } from '@nestjs/microservices';
2
+ import { WebhookPattern } from '../events';
3
+ export interface RabbitConsumerOptions {
4
+ url: string;
5
+ queue: string;
6
+ prefetchCount?: number;
7
+ }
8
+ export declare function rabbitConsumerOptions(options: RabbitConsumerOptions): RmqOptions;
9
+ export declare const OnRabbitEvent: (pattern: WebhookPattern | (string & {})) => MethodDecorator;
10
+ export declare function ackMessage(context: RmqContext): void;
11
+ export declare function nackMessage(context: RmqContext, requeue?: boolean): void;
12
+ //# sourceMappingURL=rabbit.consumer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbit.consumer.d.ts","sourceRoot":"","sources":["../../src/rabbit/rabbit.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,UAAU,EAAE,UAAU,EAAa,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAWhF;AAED,eAAO,MAAM,aAAa,GAAI,SAAS,cAAc,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,oBAC/B,CAAC;AAEvC,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,QAI7C;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,UAAQ,QAI/D"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OnRabbitEvent = void 0;
4
+ exports.rabbitConsumerOptions = rabbitConsumerOptions;
5
+ exports.ackMessage = ackMessage;
6
+ exports.nackMessage = nackMessage;
7
+ const microservices_1 = require("@nestjs/microservices");
8
+ function rabbitConsumerOptions(options) {
9
+ return {
10
+ transport: microservices_1.Transport.RMQ,
11
+ options: {
12
+ urls: [options.url],
13
+ queue: options.queue,
14
+ queueOptions: { durable: true },
15
+ noAck: false,
16
+ prefetchCount: options.prefetchCount ?? 10,
17
+ },
18
+ };
19
+ }
20
+ const OnRabbitEvent = (pattern) => (0, microservices_1.EventPattern)(pattern, microservices_1.Transport.RMQ);
21
+ exports.OnRabbitEvent = OnRabbitEvent;
22
+ function ackMessage(context) {
23
+ const channel = context.getChannelRef();
24
+ channel.ack(context.getMessage());
25
+ }
26
+ function nackMessage(context, requeue = false) {
27
+ const channel = context.getChannelRef();
28
+ channel.nack(context.getMessage(), false, requeue);
29
+ }
30
+ //# sourceMappingURL=rabbit.consumer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbit.consumer.js","sourceRoot":"","sources":["../../src/rabbit/rabbit.consumer.ts"],"names":[],"mappings":";;;AASA,sDAWC;AAKD,gCAIC;AAED,kCAIC;AAnCD,yDAAwF;AASxF,SAAgB,qBAAqB,CAAC,OAA8B;IAClE,OAAO;QACL,SAAS,EAAE,yBAAS,CAAC,GAAG;QACxB,OAAO,EAAE;YACP,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YACnB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YAC/B,KAAK,EAAE,KAAK;YACZ,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,EAAE;SAC3C;KACF,CAAC;AACJ,CAAC;AAEM,MAAM,aAAa,GAAG,CAAC,OAAuC,EAAE,EAAE,CACvE,IAAA,4BAAY,EAAC,OAAO,EAAE,yBAAS,CAAC,GAAG,CAAC,CAAC;AAD1B,QAAA,aAAa,iBACa;AAEvC,SAAgB,UAAU,CAAC,OAAmB;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,SAAgB,WAAW,CAAC,OAAmB,EAAE,OAAO,GAAG,KAAK;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAExC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { RabbitClientFactory, RabbitModuleAsyncOptions, RabbitModuleOptions } from './rabbit.options';
3
+ export declare function createRabbitClientFactory(options: RabbitModuleOptions): RabbitClientFactory | null;
4
+ export declare class RabbitModule {
5
+ static forRoot(options: RabbitModuleOptions): DynamicModule;
6
+ static forRootAsync(options: RabbitModuleAsyncOptions): DynamicModule;
7
+ }
8
+ //# sourceMappingURL=rabbit.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbit.module.d.ts","sourceRoot":"","sources":["../../src/rabbit/rabbit.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EAGL,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAE1B,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,GAAG,IAAI,CAc5B;AAQD,qBAEa,YAAY;IACvB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa;IAY3D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,wBAAwB,GAAG,aAAa;CAYtE"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var RabbitModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.RabbitModule = void 0;
11
+ exports.createRabbitClientFactory = createRabbitClientFactory;
12
+ const common_1 = require("@nestjs/common");
13
+ const microservices_1 = require("@nestjs/microservices");
14
+ const events_publisher_1 = require("./events.publisher");
15
+ const rabbit_options_1 = require("./rabbit.options");
16
+ function createRabbitClientFactory(options) {
17
+ const { url } = options;
18
+ if (!url) {
19
+ if (options.required)
20
+ throw new Error('RabbitMQ url is required');
21
+ return null;
22
+ }
23
+ return (queue) => microservices_1.ClientProxyFactory.create({
24
+ transport: microservices_1.Transport.RMQ,
25
+ options: { urls: [url], queue, queueOptions: { durable: true }, persistent: true },
26
+ });
27
+ }
28
+ const clientFactoryProvider = {
29
+ provide: rabbit_options_1.RABBIT_CLIENT_FACTORY,
30
+ useFactory: createRabbitClientFactory,
31
+ inject: [rabbit_options_1.RABBIT_OPTIONS],
32
+ };
33
+ let RabbitModule = RabbitModule_1 = class RabbitModule {
34
+ static forRoot(options) {
35
+ return {
36
+ module: RabbitModule_1,
37
+ providers: [
38
+ { provide: rabbit_options_1.RABBIT_OPTIONS, useValue: options },
39
+ clientFactoryProvider,
40
+ events_publisher_1.EventsPublisher,
41
+ ],
42
+ exports: [events_publisher_1.EventsPublisher],
43
+ };
44
+ }
45
+ static forRootAsync(options) {
46
+ return {
47
+ module: RabbitModule_1,
48
+ imports: options.imports ?? [],
49
+ providers: [
50
+ { provide: rabbit_options_1.RABBIT_OPTIONS, useFactory: options.useFactory, inject: options.inject ?? [] },
51
+ clientFactoryProvider,
52
+ events_publisher_1.EventsPublisher,
53
+ ],
54
+ exports: [events_publisher_1.EventsPublisher],
55
+ };
56
+ }
57
+ };
58
+ exports.RabbitModule = RabbitModule;
59
+ exports.RabbitModule = RabbitModule = RabbitModule_1 = __decorate([
60
+ (0, common_1.Global)(),
61
+ (0, common_1.Module)({})
62
+ ], RabbitModule);
63
+ //# sourceMappingURL=rabbit.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbit.module.js","sourceRoot":"","sources":["../../src/rabbit/rabbit.module.ts"],"names":[],"mappings":";;;;;;;;;;AAWA,8DAgBC;AA3BD,2CAAyE;AACzE,yDAAsE;AACtE,yDAAqD;AACrD,qDAM0B;AAE1B,SAAgB,yBAAyB,CACvC,OAA4B;IAE5B,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAExB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,IAAI,OAAO,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAElE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,EAAE,CACf,kCAAkB,CAAC,MAAM,CAAC;QACxB,SAAS,EAAE,yBAAS,CAAC,GAAG;QACxB,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;KACnF,CAAC,CAAC;AACP,CAAC;AAED,MAAM,qBAAqB,GAAa;IACtC,OAAO,EAAE,sCAAqB;IAC9B,UAAU,EAAE,yBAAyB;IACrC,MAAM,EAAE,CAAC,+BAAc,CAAC;CACzB,CAAC;AAIK,IAAM,YAAY,oBAAlB,MAAM,YAAY;IACvB,MAAM,CAAC,OAAO,CAAC,OAA4B;QACzC,OAAO;YACL,MAAM,EAAE,cAAY;YACpB,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,+BAAc,EAAE,QAAQ,EAAE,OAAO,EAAE;gBAC9C,qBAAqB;gBACrB,kCAAe;aAChB;YACD,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAiC;QACnD,OAAO;YACL,MAAM,EAAE,cAAY;YACpB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,+BAAc,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE;gBACzF,qBAAqB;gBACrB,kCAAe;aAChB;YACD,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;CACF,CAAA;AAzBY,oCAAY;uBAAZ,YAAY;IAFxB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,YAAY,CAyBxB"}
@@ -0,0 +1,19 @@
1
+ import { ModuleMetadata } from '@nestjs/common';
2
+ import { ClientProxy } from '@nestjs/microservices';
3
+ export declare const RABBIT_OPTIONS: unique symbol;
4
+ export declare const RABBIT_CLIENT_FACTORY: unique symbol;
5
+ export interface RabbitModuleOptions {
6
+ url?: string;
7
+ queue: string;
8
+ routes?: Record<string, string>;
9
+ timeout?: number;
10
+ required?: boolean;
11
+ }
12
+ export interface RabbitModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
13
+ useFactory: (...args: any[]) => RabbitModuleOptions | Promise<RabbitModuleOptions>;
14
+ inject?: any[];
15
+ }
16
+ export type RabbitClientFactory = (queue: string) => ClientProxy;
17
+ export type BrokerStatus = 'disabled' | 'connecting' | 'connected' | 'disconnected';
18
+ export declare const DEFAULT_PUBLISH_TIMEOUT = 5000;
19
+ //# sourceMappingURL=rabbit.options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbit.options.d.ts","sourceRoot":"","sources":["../../src/rabbit/rabbit.options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,eAAO,MAAM,cAAc,eAA2B,CAAC;AACvD,eAAO,MAAM,qBAAqB,eAAkC,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;IAC/E,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnF,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;CAChB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,CAAC;AAEjE,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;AAEpF,eAAO,MAAM,uBAAuB,OAAO,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_PUBLISH_TIMEOUT = exports.RABBIT_CLIENT_FACTORY = exports.RABBIT_OPTIONS = void 0;
4
+ exports.RABBIT_OPTIONS = Symbol('RABBIT_OPTIONS');
5
+ exports.RABBIT_CLIENT_FACTORY = Symbol('RABBIT_CLIENT_FACTORY');
6
+ exports.DEFAULT_PUBLISH_TIMEOUT = 5000;
7
+ //# sourceMappingURL=rabbit.options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbit.options.js","sourceRoot":"","sources":["../../src/rabbit/rabbit.options.ts"],"names":[],"mappings":";;;AAGa,QAAA,cAAc,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAC1C,QAAA,qBAAqB,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;AAmBxD,QAAA,uBAAuB,GAAG,IAAI,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './signature.guard';
2
+ export * from './signature.util';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/signature/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./signature.guard"), exports);
18
+ __exportStar(require("./signature.util"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/signature/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,mDAAiC"}
@@ -0,0 +1,11 @@
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ export interface WebhookRequest {
3
+ rawBody: Buffer;
4
+ headers: Record<string, string | string[] | undefined>;
5
+ }
6
+ export declare abstract class SignatureGuard implements CanActivate {
7
+ protected abstract verify(request: WebhookRequest): boolean | Promise<boolean>;
8
+ canActivate(context: ExecutionContext): Promise<boolean>;
9
+ protected header(request: Pick<WebhookRequest, 'headers'>, name: string): string | undefined;
10
+ }
11
+ //# sourceMappingURL=signature.guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.guard.d.ts","sourceRoot":"","sources":["../../src/signature/signature.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;CACxD;AAED,8BAAsB,cAAe,YAAW,WAAW;IACzD,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAE9E,WAAW,CAAC,OAAO,EAAE,gBAAgB;IAcrC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM;CAKxE"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SignatureGuard = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ class SignatureGuard {
6
+ canActivate(context) {
7
+ const request = context.switchToHttp().getRequest();
8
+ if (!Buffer.isBuffer(request.rawBody)) {
9
+ throw new common_1.BadRequestException('Raw body unavailable (unsupported content type?)');
10
+ }
11
+ return Promise.resolve(this.verify(request)).then((valid) => {
12
+ if (!valid)
13
+ throw new common_1.UnauthorizedException('Invalid webhook signature');
14
+ return true;
15
+ });
16
+ }
17
+ header(request, name) {
18
+ const value = request.headers[name.toLowerCase()];
19
+ return Array.isArray(value) ? value[0] : value;
20
+ }
21
+ }
22
+ exports.SignatureGuard = SignatureGuard;
23
+ //# sourceMappingURL=signature.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.guard.js","sourceRoot":"","sources":["../../src/signature/signature.guard.ts"],"names":[],"mappings":";;;AAAA,2CAKwB;AAOxB,MAAsB,cAAc;IAGlC,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAA2B,CAAC;QAE7E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,4BAAmB,CAAC,kDAAkD,CAAC,CAAC;QACpF,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAyB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YAC5E,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,8BAAqB,CAAC,2BAA2B,CAAC,CAAC;YAEzE,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAES,MAAM,CAAC,OAAwC,EAAE,IAAY;QACrE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAElD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACjD,CAAC;CACF;AAtBD,wCAsBC"}
@@ -0,0 +1,9 @@
1
+ export type SignatureInput = string | Buffer;
2
+ export interface HmacOptions {
3
+ algorithm?: string;
4
+ encoding?: 'hex' | 'base64' | 'base64url';
5
+ }
6
+ export declare function safeCompare(received: SignatureInput | null | undefined, expected: SignatureInput): boolean;
7
+ export declare function hmacDigest(payload: SignatureInput, secret: SignatureInput, options?: HmacOptions): string;
8
+ export declare function verifyHmac(payload: SignatureInput, signature: SignatureInput | null | undefined, secret: SignatureInput, options?: HmacOptions): boolean;
9
+ //# sourceMappingURL=signature.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.util.d.ts","sourceRoot":"","sources":["../../src/signature/signature.util.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,CAAC;CAC3C;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,cAAc,WAOhG;AAED,wBAAgB,UAAU,CACxB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,WAAgB,UAK1B;AAED,wBAAgB,UAAU,CACxB,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC5C,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,WAAgB,WAG1B"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.safeCompare = safeCompare;
4
+ exports.hmacDigest = hmacDigest;
5
+ exports.verifyHmac = verifyHmac;
6
+ const node_crypto_1 = require("node:crypto");
7
+ function safeCompare(received, expected) {
8
+ if (received == null || !expected?.length)
9
+ return false;
10
+ const a = Buffer.from(received);
11
+ const b = Buffer.from(expected);
12
+ return a.length === b.length && (0, node_crypto_1.timingSafeEqual)(a, b);
13
+ }
14
+ function hmacDigest(payload, secret, options = {}) {
15
+ const { algorithm = 'sha256', encoding = 'hex' } = options;
16
+ return (0, node_crypto_1.createHmac)(algorithm, secret).update(payload).digest(encoding);
17
+ }
18
+ function verifyHmac(payload, signature, secret, options = {}) {
19
+ return safeCompare(signature, hmacDigest(payload, secret, options));
20
+ }
21
+ //# sourceMappingURL=signature.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.util.js","sourceRoot":"","sources":["../../src/signature/signature.util.ts"],"names":[],"mappings":";;AASA,kCAOC;AAED,gCAQC;AAED,gCAOC;AAnCD,6CAA0D;AAS1D,SAAgB,WAAW,CAAC,QAA2C,EAAE,QAAwB;IAC/F,IAAI,QAAQ,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,OAAO,KAAK,CAAC;IAExD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEhC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,IAAA,6BAAe,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAgB,UAAU,CACxB,OAAuB,EACvB,MAAsB,EACtB,UAAuB,EAAE;IAEzB,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAE3D,OAAO,IAAA,wBAAU,EAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACxE,CAAC;AAED,SAAgB,UAAU,CACxB,OAAuB,EACvB,SAA4C,EAC5C,MAAsB,EACtB,UAAuB,EAAE;IAEzB,OAAO,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACtE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@merkaly/nest",
3
- "version": "0.1.6",
4
- "description": "Shared NestJS infrastructure for Merkaly backend apps",
3
+ "version": "0.1.8",
4
+ "description": "Shared NestJS runtime and tooling for Merkaly backend apps: pinned versions plus RabbitMQ events, logger, filters, config and signatures",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/merkaly-io/nest.git"
@@ -24,53 +24,38 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "@eslint/js": "^9.39.0",
27
- "@nestjs/cli": "^11.0.10",
28
- "@nestjs/common": "^11.1.18",
29
- "@nestjs/core": "^11.1.18",
30
- "@nestjs/event-emitter": "^3.1.0",
31
- "@nestjs/mapped-types": "^2.1.1",
32
- "@nestjs/microservices": "^11.1.18",
33
- "@nestjs/schematics": "^11.1.0",
34
- "@nestjs/testing": "^11.1.6",
35
- "@types/jest": "^30.0.0",
36
- "@types/node": "^26.0.0",
27
+ "@nestjs/cli": "^12.0.0",
28
+ "@nestjs/common": "^11.2.8",
29
+ "@nestjs/core": "^11.2.8",
30
+ "@nestjs/event-emitter": "^12.0.0",
31
+ "@nestjs/mapped-types": "^12.0.0",
32
+ "@nestjs/microservices": "^11.2.8",
33
+ "@nestjs/platform-express": "^11.2.8",
34
+ "@nestjs/schematics": "^12.0.0",
35
+ "@nestjs/swagger": "^11.4.7",
36
+ "@types/express": "^5.0.6",
37
+ "@types/node": "^26.6.1",
37
38
  "amqp-connection-manager": "^5.0.0",
38
- "amqplib": "^2.0.1",
39
+ "amqplib": "^2.2.0",
40
+ "chalk": "^4.1.2",
39
41
  "class-transformer": "^0.5.1",
40
42
  "class-validator": "^0.15.1",
43
+ "dotenv": "^18.0.9",
41
44
  "eslint": "^9.39.0",
42
45
  "eslint-config-prettier": "^10.1.8",
43
46
  "eslint-plugin-import": "^2.32.0",
44
47
  "eslint-plugin-prettier": "^5.5.4",
45
- "globals": "^17.6.0",
46
- "jest": "^30.4.1",
48
+ "express": "^5.2.1",
49
+ "globals": "^17.13.0",
47
50
  "nestjs-console": "^10.0.0",
48
- "prettier": "^3.8.0",
51
+ "prettier": "^3.9.3",
49
52
  "reflect-metadata": "^0.2.2",
50
53
  "rxjs": "^7.8.1",
51
54
  "source-map-support": "^0.5.21",
52
- "ts-jest": "^29.4.1",
53
55
  "ts-node": "^10.9.2",
54
56
  "tsconfig-paths": "^4.2.0",
55
57
  "typescript": "^6.0.3",
56
- "typescript-eslint": "^8.61.0"
57
- },
58
- "jest": {
59
- "moduleFileExtensions": [
60
- "js",
61
- "json",
62
- "ts"
63
- ],
64
- "rootDir": "src",
65
- "testRegex": ".*\\.spec\\.ts$",
66
- "transform": {
67
- "^.+\\.(t|j)s$": "ts-jest"
68
- },
69
- "collectCoverageFrom": [
70
- "**/*.(t|j)s"
71
- ],
72
- "coverageDirectory": "../coverage",
73
- "testEnvironment": "node"
58
+ "typescript-eslint": "^8.72.0"
74
59
  },
75
60
  "engines": {
76
61
  "node": ">=24"
@@ -83,9 +68,6 @@
83
68
  "clean": "tsc -b --clean",
84
69
  "dev": "tsc -p tsconfig.build.json --watch",
85
70
  "format": "prettier --write \"src/**/*.ts\"",
86
- "lint": "eslint .",
87
- "test": "jest",
88
- "test:cov": "jest --coverage",
89
- "test:watch": "jest --watch"
71
+ "lint": "eslint ."
90
72
  }
91
73
  }