mongodb-dynamic-api 3.0.1 → 3.2.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.
Files changed (164) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +1 -1
  3. package/src/dynamic-api.module.d.ts +1 -1
  4. package/src/dynamic-api.module.js +11 -3
  5. package/src/dynamic-api.module.js.map +1 -1
  6. package/src/gateways/base.gateway.d.ts +2 -1
  7. package/src/gateways/base.gateway.js +17 -0
  8. package/src/gateways/base.gateway.js.map +1 -1
  9. package/src/gateways/dynamic-api-broadcast.gateway.d.ts +11 -0
  10. package/src/gateways/dynamic-api-broadcast.gateway.js +41 -0
  11. package/src/gateways/dynamic-api-broadcast.gateway.js.map +1 -0
  12. package/src/gateways/index.d.ts +1 -0
  13. package/src/gateways/index.js +1 -0
  14. package/src/gateways/index.js.map +1 -1
  15. package/src/helpers/mixin-data.helper.d.ts +1 -1
  16. package/src/helpers/mixin-data.helper.js +2 -1
  17. package/src/helpers/mixin-data.helper.js.map +1 -1
  18. package/src/interfaces/dynamic-api-ability.interface.d.ts +2 -1
  19. package/src/interfaces/dynamic-api-broadcast-config.interface.d.ts +6 -0
  20. package/src/interfaces/dynamic-api-broadcast-config.interface.js +3 -0
  21. package/src/interfaces/dynamic-api-broadcast-config.interface.js.map +1 -0
  22. package/src/interfaces/dynamic-api-global-state.interface.d.ts +1 -0
  23. package/src/interfaces/dynamic-api-options.interface.d.ts +2 -0
  24. package/src/interfaces/dynamic-api-options.interface.js.map +1 -1
  25. package/src/interfaces/dynamic-api-route-config.interface.d.ts +2 -0
  26. package/src/interfaces/index.d.ts +1 -0
  27. package/src/interfaces/index.js +1 -0
  28. package/src/interfaces/index.js.map +1 -1
  29. package/src/modules/auth/auth.helper.d.ts +7 -5
  30. package/src/modules/auth/auth.helper.js +10 -9
  31. package/src/modules/auth/auth.helper.js.map +1 -1
  32. package/src/modules/auth/auth.module.js +9 -5
  33. package/src/modules/auth/auth.module.js.map +1 -1
  34. package/src/modules/auth/interfaces/auth-options.interface.d.ts +6 -1
  35. package/src/modules/auth/mixins/auth-controller.mixin.d.ts +2 -2
  36. package/src/modules/auth/mixins/auth-controller.mixin.js +2 -1
  37. package/src/modules/auth/mixins/auth-controller.mixin.js.map +1 -1
  38. package/src/modules/auth/mixins/auth-gateway.mixin.d.ts +2 -2
  39. package/src/modules/auth/mixins/auth-gateway.mixin.js +2 -1
  40. package/src/modules/auth/mixins/auth-gateway.mixin.js.map +1 -1
  41. package/src/modules/auth/services/base-auth.service.d.ts +1 -0
  42. package/src/modules/auth/services/base-auth.service.js +4 -0
  43. package/src/modules/auth/services/base-auth.service.js.map +1 -1
  44. package/src/routes/aggregate/aggregate.module.js +1 -1
  45. package/src/routes/aggregate/aggregate.module.js.map +1 -1
  46. package/src/routes/create-many/create-many-controller.interface.d.ts +2 -1
  47. package/src/routes/create-many/create-many-controller.mixin.d.ts +1 -1
  48. package/src/routes/create-many/create-many-controller.mixin.js +14 -6
  49. package/src/routes/create-many/create-many-controller.mixin.js.map +1 -1
  50. package/src/routes/create-many/create-many-gateway.mixin.d.ts +1 -1
  51. package/src/routes/create-many/create-many-gateway.mixin.js +5 -3
  52. package/src/routes/create-many/create-many-gateway.mixin.js.map +1 -1
  53. package/src/routes/create-many/create-many.helper.js +7 -3
  54. package/src/routes/create-many/create-many.helper.js.map +1 -1
  55. package/src/routes/create-many/create-many.module.js +4 -1
  56. package/src/routes/create-many/create-many.module.js.map +1 -1
  57. package/src/routes/create-one/create-one-controller.interface.d.ts +2 -1
  58. package/src/routes/create-one/create-one-controller.mixin.d.ts +1 -1
  59. package/src/routes/create-one/create-one-controller.mixin.js +14 -6
  60. package/src/routes/create-one/create-one-controller.mixin.js.map +1 -1
  61. package/src/routes/create-one/create-one-gateway.mixin.d.ts +1 -1
  62. package/src/routes/create-one/create-one-gateway.mixin.js +5 -3
  63. package/src/routes/create-one/create-one-gateway.mixin.js.map +1 -1
  64. package/src/routes/create-one/create-one.helper.js +7 -3
  65. package/src/routes/create-one/create-one.helper.js.map +1 -1
  66. package/src/routes/create-one/create-one.module.js +4 -1
  67. package/src/routes/create-one/create-one.module.js.map +1 -1
  68. package/src/routes/delete-many/delete-many-controller.interface.d.ts +2 -1
  69. package/src/routes/delete-many/delete-many-controller.mixin.d.ts +1 -1
  70. package/src/routes/delete-many/delete-many-controller.mixin.js +14 -6
  71. package/src/routes/delete-many/delete-many-controller.mixin.js.map +1 -1
  72. package/src/routes/delete-many/delete-many-gateway.mixin.d.ts +1 -1
  73. package/src/routes/delete-many/delete-many-gateway.mixin.js +5 -3
  74. package/src/routes/delete-many/delete-many-gateway.mixin.js.map +1 -1
  75. package/src/routes/delete-many/delete-many.helper.js +7 -3
  76. package/src/routes/delete-many/delete-many.helper.js.map +1 -1
  77. package/src/routes/delete-many/delete-many.module.js +4 -1
  78. package/src/routes/delete-many/delete-many.module.js.map +1 -1
  79. package/src/routes/delete-one/delete-one-controller.interface.d.ts +2 -1
  80. package/src/routes/delete-one/delete-one-controller.mixin.d.ts +1 -1
  81. package/src/routes/delete-one/delete-one-controller.mixin.js +14 -6
  82. package/src/routes/delete-one/delete-one-controller.mixin.js.map +1 -1
  83. package/src/routes/delete-one/delete-one-gateway.mixin.d.ts +1 -1
  84. package/src/routes/delete-one/delete-one-gateway.mixin.js +5 -3
  85. package/src/routes/delete-one/delete-one-gateway.mixin.js.map +1 -1
  86. package/src/routes/delete-one/delete-one.helper.js +7 -3
  87. package/src/routes/delete-one/delete-one.helper.js.map +1 -1
  88. package/src/routes/delete-one/delete-one.module.js +4 -1
  89. package/src/routes/delete-one/delete-one.module.js.map +1 -1
  90. package/src/routes/duplicate-many/duplicate-many-controller.interface.d.ts +2 -1
  91. package/src/routes/duplicate-many/duplicate-many-controller.mixin.d.ts +1 -1
  92. package/src/routes/duplicate-many/duplicate-many-controller.mixin.js +14 -6
  93. package/src/routes/duplicate-many/duplicate-many-controller.mixin.js.map +1 -1
  94. package/src/routes/duplicate-many/duplicate-many-gateway.mixin.d.ts +1 -1
  95. package/src/routes/duplicate-many/duplicate-many-gateway.mixin.js +5 -3
  96. package/src/routes/duplicate-many/duplicate-many-gateway.mixin.js.map +1 -1
  97. package/src/routes/duplicate-many/duplicate-many.helper.js +7 -3
  98. package/src/routes/duplicate-many/duplicate-many.helper.js.map +1 -1
  99. package/src/routes/duplicate-many/duplicate-many.module.js +4 -1
  100. package/src/routes/duplicate-many/duplicate-many.module.js.map +1 -1
  101. package/src/routes/duplicate-one/duplicate-one-controller.interface.d.ts +2 -1
  102. package/src/routes/duplicate-one/duplicate-one-controller.mixin.d.ts +1 -1
  103. package/src/routes/duplicate-one/duplicate-one-controller.mixin.js +14 -6
  104. package/src/routes/duplicate-one/duplicate-one-controller.mixin.js.map +1 -1
  105. package/src/routes/duplicate-one/duplicate-one-gateway.mixin.d.ts +1 -1
  106. package/src/routes/duplicate-one/duplicate-one-gateway.mixin.js +5 -3
  107. package/src/routes/duplicate-one/duplicate-one-gateway.mixin.js.map +1 -1
  108. package/src/routes/duplicate-one/duplicate-one.helper.js +7 -3
  109. package/src/routes/duplicate-one/duplicate-one.helper.js.map +1 -1
  110. package/src/routes/duplicate-one/duplicate-one.module.js +4 -1
  111. package/src/routes/duplicate-one/duplicate-one.module.js.map +1 -1
  112. package/src/routes/get-many/get-many.module.js +1 -1
  113. package/src/routes/get-many/get-many.module.js.map +1 -1
  114. package/src/routes/get-one/get-one.module.js +1 -1
  115. package/src/routes/get-one/get-one.module.js.map +1 -1
  116. package/src/routes/replace-one/replace-one-controller.interface.d.ts +2 -1
  117. package/src/routes/replace-one/replace-one-controller.mixin.d.ts +1 -1
  118. package/src/routes/replace-one/replace-one-controller.mixin.js +14 -6
  119. package/src/routes/replace-one/replace-one-controller.mixin.js.map +1 -1
  120. package/src/routes/replace-one/replace-one-gateway.mixin.d.ts +1 -1
  121. package/src/routes/replace-one/replace-one-gateway.mixin.js +5 -3
  122. package/src/routes/replace-one/replace-one-gateway.mixin.js.map +1 -1
  123. package/src/routes/replace-one/replace-one.helper.js +7 -3
  124. package/src/routes/replace-one/replace-one.helper.js.map +1 -1
  125. package/src/routes/replace-one/replace-one.module.js +4 -1
  126. package/src/routes/replace-one/replace-one.module.js.map +1 -1
  127. package/src/routes/update-many/update-many-controller.interface.d.ts +2 -1
  128. package/src/routes/update-many/update-many-controller.mixin.d.ts +1 -1
  129. package/src/routes/update-many/update-many-controller.mixin.js +14 -6
  130. package/src/routes/update-many/update-many-controller.mixin.js.map +1 -1
  131. package/src/routes/update-many/update-many-gateway.mixin.d.ts +1 -1
  132. package/src/routes/update-many/update-many-gateway.mixin.js +5 -3
  133. package/src/routes/update-many/update-many-gateway.mixin.js.map +1 -1
  134. package/src/routes/update-many/update-many.helper.js +7 -3
  135. package/src/routes/update-many/update-many.helper.js.map +1 -1
  136. package/src/routes/update-many/update-many.module.js +4 -1
  137. package/src/routes/update-many/update-many.module.js.map +1 -1
  138. package/src/routes/update-one/update-one-controller.interface.d.ts +2 -1
  139. package/src/routes/update-one/update-one-controller.mixin.d.ts +1 -1
  140. package/src/routes/update-one/update-one-controller.mixin.js +14 -6
  141. package/src/routes/update-one/update-one-controller.mixin.js.map +1 -1
  142. package/src/routes/update-one/update-one-gateway.mixin.d.ts +1 -1
  143. package/src/routes/update-one/update-one-gateway.mixin.js +5 -3
  144. package/src/routes/update-one/update-one-gateway.mixin.js.map +1 -1
  145. package/src/routes/update-one/update-one.helper.js +7 -3
  146. package/src/routes/update-one/update-one.helper.js.map +1 -1
  147. package/src/routes/update-one/update-one.module.js +4 -1
  148. package/src/routes/update-one/update-one.module.js.map +1 -1
  149. package/src/services/dynamic-api-broadcast/dynamic-api-broadcast.service.d.ts +7 -0
  150. package/src/services/dynamic-api-broadcast/dynamic-api-broadcast.service.js +38 -0
  151. package/src/services/dynamic-api-broadcast/dynamic-api-broadcast.service.js.map +1 -0
  152. package/src/services/index.d.ts +1 -0
  153. package/src/services/index.js +1 -0
  154. package/src/services/index.js.map +1 -1
  155. package/src/version.json +1 -1
  156. package/test/dynamic-api-for-feature.e2e-spec.js +463 -1
  157. package/test/dynamic-api-for-feature.e2e-spec.js.map +1 -1
  158. package/test/e2e.setup.d.ts +24 -2
  159. package/test/e2e.setup.js +173 -18
  160. package/test/e2e.setup.js.map +1 -1
  161. package/test/test-socket-adapter.d.ts +8 -0
  162. package/test/test-socket-adapter.js +23 -0
  163. package/test/test-socket-adapter.js.map +1 -0
  164. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,7 @@
1
+ import { Server } from 'socket.io';
2
+ import { DynamicApiBroadcastConfig } from '../../interfaces';
3
+ export declare class DynamicApiBroadcastService {
4
+ private static wsServer;
5
+ setWsServer(server: Server): void;
6
+ broadcastFromHttp<T extends object>(event: string, data: T[], broadcastConfig: DynamicApiBroadcastConfig<T>): void;
7
+ }
@@ -0,0 +1,38 @@
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 DynamicApiBroadcastService_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.DynamicApiBroadcastService = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ let DynamicApiBroadcastService = DynamicApiBroadcastService_1 = class DynamicApiBroadcastService {
13
+ setWsServer(server) {
14
+ DynamicApiBroadcastService_1.wsServer = server;
15
+ }
16
+ broadcastFromHttp(event, data, broadcastConfig) {
17
+ if (!DynamicApiBroadcastService_1.wsServer || !broadcastConfig || !data?.length) {
18
+ return;
19
+ }
20
+ const { enabled, eventName } = broadcastConfig;
21
+ if (typeof enabled === 'boolean' && !enabled) {
22
+ return;
23
+ }
24
+ const broadcastData = typeof enabled === 'function'
25
+ ? data.filter((item) => enabled(item, undefined))
26
+ : data;
27
+ if (!broadcastData.length) {
28
+ return;
29
+ }
30
+ DynamicApiBroadcastService_1.wsServer.emit(eventName || event, broadcastData);
31
+ }
32
+ };
33
+ exports.DynamicApiBroadcastService = DynamicApiBroadcastService;
34
+ DynamicApiBroadcastService.wsServer = null;
35
+ exports.DynamicApiBroadcastService = DynamicApiBroadcastService = DynamicApiBroadcastService_1 = __decorate([
36
+ (0, common_1.Injectable)()
37
+ ], DynamicApiBroadcastService);
38
+ //# sourceMappingURL=dynamic-api-broadcast.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamic-api-broadcast.service.js","sourceRoot":"","sources":["../../../../libs/dynamic-api/src/services/dynamic-api-broadcast/dynamic-api-broadcast.service.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAA4C;AAKrC,IAAM,0BAA0B,kCAAhC,MAAM,0BAA0B;IAGrC,WAAW,CAAC,MAAc;QACxB,4BAA0B,CAAC,QAAQ,GAAG,MAAM,CAAC;IAC/C,CAAC;IAED,iBAAiB,CACf,KAAa,EACb,IAAS,EACT,eAA6C;QAE7C,IAAI,CAAC,4BAA0B,CAAC,QAAQ,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC;QAE/C,IAAI,OAAO,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,OAAO,KAAK,UAAU;YACjD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAE,OAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/D,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,4BAA0B,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,EAAE,aAAa,CAAC,CAAC;IAC9E,CAAC;;AA/BU,gEAA0B;AACtB,mCAAQ,GAAkB,IAAI,AAAtB,CAAuB;qCADnC,0BAA0B;IADtC,IAAA,mBAAU,GAAE;GACA,0BAA0B,CAgCtC"}
@@ -1,3 +1,4 @@
1
1
  export * from './base/base.service';
2
2
  export * from './bcrypt/bcrypt.service';
3
+ export * from './dynamic-api-broadcast/dynamic-api-broadcast.service';
3
4
  export * from './dynamic-api-global-state/dynamic-api-global-state.service';
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./base/base.service"), exports);
18
18
  __exportStar(require("./bcrypt/bcrypt.service"), exports);
19
+ __exportStar(require("./dynamic-api-broadcast/dynamic-api-broadcast.service"), exports);
19
20
  __exportStar(require("./dynamic-api-global-state/dynamic-api-global-state.service"), exports);
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../libs/dynamic-api/src/services/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,0DAAwC;AACxC,8FAA4E"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../libs/dynamic-api/src/services/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,0DAAwC;AACxC,wFAAsE;AACtE,8FAA4E"}
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "3.0.1"
2
+ "version": "3.2.0"
3
3
  }
@@ -18,12 +18,13 @@ require("dotenv/config");
18
18
  const utils_1 = require("./utils");
19
19
  describe('DynamicApiModule forFeature (e2e)', () => {
20
20
  const uri = process.env.MONGO_DB_URL;
21
- const initApp = async (forFeatureOptions, forRootOptions = {}, initFixtures, initMainCb) => {
21
+ const initApp = async (forFeatureOptions, forRootOptions = {}, initFixtures, initMainCb, testGateway) => {
22
22
  const moduleRef = await testing_1.Test.createTestingModule({
23
23
  imports: [
24
24
  src_1.DynamicApiModule.forRoot(uri, forRootOptions),
25
25
  src_1.DynamicApiModule.forFeature(forFeatureOptions),
26
26
  ],
27
+ providers: testGateway ? [e2e_setup_1.TestGateway] : [],
27
28
  }).compile();
28
29
  await (0, e2e_setup_1.createTestingApp)(moduleRef, initFixtures, initMainCb);
29
30
  };
@@ -634,5 +635,466 @@ describe('DynamicApiModule forFeature (e2e)', () => {
634
635
  });
635
636
  });
636
637
  });
638
+ describe('Websockets', () => {
639
+ let UserEntity = class UserEntity extends src_1.BaseEntity {
640
+ };
641
+ __decorate([
642
+ (0, mongoose_1.Prop)({ type: String, required: true }),
643
+ __metadata("design:type", String)
644
+ ], UserEntity.prototype, "email", void 0);
645
+ __decorate([
646
+ (0, mongoose_1.Prop)({ type: String, required: true }),
647
+ __metadata("design:type", String)
648
+ ], UserEntity.prototype, "password", void 0);
649
+ __decorate([
650
+ (0, mongoose_1.Prop)({ type: Boolean, default: false }),
651
+ __metadata("design:type", Boolean)
652
+ ], UserEntity.prototype, "isAdmin", void 0);
653
+ UserEntity = __decorate([
654
+ (0, mongoose_1.Schema)({ collection: 'users' })
655
+ ], UserEntity);
656
+ let ProductEntity = class ProductEntity extends src_1.BaseEntity {
657
+ };
658
+ __decorate([
659
+ (0, mongoose_1.Prop)({ type: String, required: true }),
660
+ __metadata("design:type", String)
661
+ ], ProductEntity.prototype, "name", void 0);
662
+ __decorate([
663
+ (0, mongoose_1.Prop)({ type: Boolean, default: false }),
664
+ __metadata("design:type", Boolean)
665
+ ], ProductEntity.prototype, "inStock", void 0);
666
+ __decorate([
667
+ (0, mongoose_1.Prop)({ type: String }),
668
+ __metadata("design:type", String)
669
+ ], ProductEntity.prototype, "status", void 0);
670
+ ProductEntity = __decorate([
671
+ (0, mongoose_1.Schema)({ collection: 'products' })
672
+ ], ProductEntity);
673
+ const customEvent = 'product-custom-event';
674
+ let adminAccessToken;
675
+ let userAccessToken;
676
+ let firstProduct;
677
+ let secondProduct;
678
+ beforeEach(async () => {
679
+ const fixtures = async (_) => {
680
+ const model = await (0, utils_1.getModelFromEntity)(ProductEntity);
681
+ await model.insertMany([
682
+ { name: 'mayo', inStock: true },
683
+ { name: 'ketchup' },
684
+ ]).then(([mayoProduct, ketchupProduct]) => {
685
+ firstProduct = mayoProduct;
686
+ secondProduct = ketchupProduct;
687
+ });
688
+ };
689
+ await initApp({
690
+ entity: ProductEntity,
691
+ controllerOptions: {
692
+ apiTag: 'Product',
693
+ path: 'products',
694
+ },
695
+ routes: [
696
+ { type: 'GetMany', isPublic: true },
697
+ {
698
+ type: 'CreateMany',
699
+ webSocket: true,
700
+ broadcast: {
701
+ enabled: (_, user) => user.isAdmin === true,
702
+ },
703
+ },
704
+ {
705
+ type: 'CreateOne',
706
+ webSocket: true,
707
+ broadcast: { enabled: true },
708
+ },
709
+ {
710
+ type: 'UpdateMany',
711
+ webSocket: true,
712
+ broadcast: {
713
+ enabled: false,
714
+ eventName: customEvent,
715
+ },
716
+ },
717
+ {
718
+ type: 'UpdateOne',
719
+ webSocket: true,
720
+ broadcast: {
721
+ enabled: true,
722
+ eventName: customEvent,
723
+ },
724
+ },
725
+ {
726
+ type: 'ReplaceOne',
727
+ webSocket: true,
728
+ broadcast: {
729
+ enabled: true,
730
+ },
731
+ },
732
+ {
733
+ type: 'DuplicateOne',
734
+ webSocket: true,
735
+ broadcast: {
736
+ enabled: (_, user) => user.isAdmin === true,
737
+ eventName: customEvent,
738
+ },
739
+ },
740
+ {
741
+ type: 'DuplicateMany',
742
+ webSocket: true,
743
+ broadcast: {
744
+ enabled: true,
745
+ },
746
+ },
747
+ {
748
+ type: 'DeleteOne',
749
+ webSocket: true,
750
+ broadcast: {
751
+ enabled: true,
752
+ },
753
+ },
754
+ {
755
+ type: 'DeleteMany',
756
+ webSocket: true,
757
+ broadcast: {
758
+ enabled: true,
759
+ },
760
+ },
761
+ ],
762
+ }, {
763
+ useAuth: {
764
+ userEntity: UserEntity,
765
+ login: {
766
+ additionalFields: ['isAdmin'],
767
+ },
768
+ webSocket: true,
769
+ },
770
+ }, fixtures, async (app) => {
771
+ app.useWebSocketAdapter(new e2e_setup_1.TestSocketAdapter(app));
772
+ }, true);
773
+ adminAccessToken = (await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'test', isAdmin: true })).accessToken;
774
+ userAccessToken = (await e2e_setup_1.server.emit('auth-register', { email: 'toto@test.co', password: 'test' })).accessToken;
775
+ });
776
+ it('[CreateOne] should broadcast created product to all clients', async () => {
777
+ await e2e_setup_1.server.emit('create-one-product', { name: 'mustard', inStock: true }, { accessToken: adminAccessToken, expectBroadcast: true });
778
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
779
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
780
+ event: 'create-one-product',
781
+ data: expect.arrayContaining([
782
+ expect.objectContaining({
783
+ name: 'mustard',
784
+ inStock: true,
785
+ }),
786
+ ]),
787
+ });
788
+ });
789
+ it('[CreateMany] should broadcast created products to all clients when admin', async () => {
790
+ await e2e_setup_1.server.emit('create-many-product', {
791
+ list: [
792
+ { name: 'mustard', inStock: true },
793
+ { name: 'relish', inStock: false },
794
+ ],
795
+ }, { accessToken: adminAccessToken, expectBroadcast: true });
796
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
797
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
798
+ event: 'create-many-product',
799
+ data: expect.arrayContaining([
800
+ expect.objectContaining({
801
+ name: 'mustard',
802
+ inStock: true,
803
+ }),
804
+ expect.objectContaining({
805
+ name: 'relish',
806
+ inStock: false,
807
+ }),
808
+ ]),
809
+ });
810
+ });
811
+ it('[CreateMany] should NOT broadcast created products when user is not admin', async () => {
812
+ await e2e_setup_1.server.emit('create-many-product', {
813
+ list: [
814
+ { name: 'pickles', inStock: true },
815
+ { name: 'onions', inStock: false },
816
+ ],
817
+ }, { accessToken: userAccessToken });
818
+ expect(e2e_setup_1.handleSocketBroadcast).not.toHaveBeenCalled();
819
+ });
820
+ it('[UpdateOne] should broadcast updated product to all clients with custom event name', async () => {
821
+ await e2e_setup_1.server.emit('update-one-product', {
822
+ id: firstProduct.id,
823
+ name: 'updated mayo',
824
+ inStock: false,
825
+ }, { accessToken: adminAccessToken, broadcastEvent: customEvent, expectBroadcast: true });
826
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
827
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
828
+ event: customEvent,
829
+ data: expect.arrayContaining([
830
+ expect.objectContaining({
831
+ id: firstProduct.id,
832
+ name: 'updated mayo',
833
+ inStock: false,
834
+ }),
835
+ ]),
836
+ });
837
+ });
838
+ it('[UpdateMany] should NOT broadcast updated products when broadcast is disabled', async () => {
839
+ const { body: products } = await e2e_setup_1.server.get('/products');
840
+ await e2e_setup_1.server.emit('update-many-product', {
841
+ ids: products.map(p => p.id),
842
+ status: 'updated',
843
+ }, { accessToken: adminAccessToken });
844
+ expect(e2e_setup_1.handleSocketBroadcast).not.toHaveBeenCalled();
845
+ });
846
+ it('[DeleteOne] should broadcast deleted product id to all clients', async () => {
847
+ await e2e_setup_1.server.emit('delete-one-product', {
848
+ id: firstProduct.id,
849
+ }, { accessToken: adminAccessToken, expectBroadcast: true });
850
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
851
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
852
+ event: 'delete-one-product',
853
+ data: expect.arrayContaining([
854
+ expect.objectContaining({
855
+ id: firstProduct.id,
856
+ }),
857
+ ]),
858
+ });
859
+ });
860
+ it('[ReplaceOne] should broadcast replaced product to all clients', async () => {
861
+ await e2e_setup_1.server.emit('replace-one-product', {
862
+ id: firstProduct.id,
863
+ name: 'replaced mayo',
864
+ inStock: false,
865
+ }, { accessToken: adminAccessToken, expectBroadcast: true });
866
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
867
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
868
+ event: 'replace-one-product',
869
+ data: expect.arrayContaining([
870
+ expect.objectContaining({
871
+ id: firstProduct.id,
872
+ name: 'replaced mayo',
873
+ inStock: false,
874
+ }),
875
+ ]),
876
+ });
877
+ });
878
+ it('[DuplicateOne] should broadcast duplicated product to all clients with custom event name when admin', async () => {
879
+ await e2e_setup_1.server.emit('duplicate-one-product', {
880
+ id: firstProduct.id,
881
+ name: 'duplicated mayo',
882
+ }, { accessToken: adminAccessToken, broadcastEvent: customEvent, expectBroadcast: true });
883
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
884
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
885
+ event: customEvent,
886
+ data: expect.arrayContaining([
887
+ expect.objectContaining({
888
+ name: 'duplicated mayo',
889
+ inStock: firstProduct.inStock,
890
+ }),
891
+ ]),
892
+ });
893
+ });
894
+ it('[DuplicateOne] should NOT broadcast duplicated product when user is not admin', async () => {
895
+ await e2e_setup_1.server.emit('duplicate-one-product', {
896
+ id: firstProduct.id,
897
+ name: 'duplicated mayo user',
898
+ }, { accessToken: userAccessToken });
899
+ expect(e2e_setup_1.handleSocketBroadcast).not.toHaveBeenCalled();
900
+ });
901
+ it('[DuplicateMany] should broadcast duplicated products to all clients', async () => {
902
+ await e2e_setup_1.server.emit('duplicate-many-product', {
903
+ ids: [secondProduct.id, firstProduct.id],
904
+ status: 'duplicated',
905
+ }, { accessToken: adminAccessToken, expectBroadcast: true });
906
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
907
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
908
+ event: 'duplicate-many-product',
909
+ data: expect.arrayContaining([
910
+ expect.objectContaining({
911
+ id: expect.any(String),
912
+ name: secondProduct.name,
913
+ inStock: secondProduct.inStock,
914
+ status: 'duplicated',
915
+ }),
916
+ expect.objectContaining({
917
+ id: expect.any(String),
918
+ name: firstProduct.name,
919
+ inStock: firstProduct.inStock,
920
+ status: 'duplicated',
921
+ }),
922
+ ]),
923
+ });
924
+ });
925
+ it('[DeleteMany] should broadcast deleted product ids to all clients', async () => {
926
+ const products = [firstProduct, secondProduct];
927
+ await e2e_setup_1.server.emit('delete-many-product', {
928
+ ids: products.map(p => p.id),
929
+ }, { accessToken: adminAccessToken, expectBroadcast: true });
930
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
931
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
932
+ event: 'delete-many-product',
933
+ data: expect.arrayContaining(products.map(p => ({ id: p.id }))),
934
+ });
935
+ });
936
+ });
937
+ describe('HTTP Broadcast', () => {
938
+ let HbProductEntity = class HbProductEntity extends src_1.BaseEntity {
939
+ };
940
+ __decorate([
941
+ (0, mongoose_1.Prop)({ type: String, required: true }),
942
+ __metadata("design:type", String)
943
+ ], HbProductEntity.prototype, "name", void 0);
944
+ __decorate([
945
+ (0, mongoose_1.Prop)({ type: Boolean, default: false }),
946
+ __metadata("design:type", Boolean)
947
+ ], HbProductEntity.prototype, "inStock", void 0);
948
+ __decorate([
949
+ (0, mongoose_1.Prop)({ type: String }),
950
+ __metadata("design:type", String)
951
+ ], HbProductEntity.prototype, "status", void 0);
952
+ HbProductEntity = __decorate([
953
+ (0, mongoose_1.Schema)({ collection: 'hb_products' })
954
+ ], HbProductEntity);
955
+ const customEvent = 'hb-product-custom-event';
956
+ let firstProduct;
957
+ let secondProduct;
958
+ beforeEach(async () => {
959
+ const fixtures = async (_) => {
960
+ const model = await (0, utils_1.getModelFromEntity)(HbProductEntity);
961
+ await model.insertMany([
962
+ { name: 'mayo', inStock: true },
963
+ { name: 'ketchup', inStock: false },
964
+ ]).then(([mayoProduct, ketchupProduct]) => {
965
+ firstProduct = mayoProduct;
966
+ secondProduct = ketchupProduct;
967
+ });
968
+ };
969
+ await initApp({
970
+ entity: HbProductEntity,
971
+ controllerOptions: {
972
+ apiTag: 'HbProduct',
973
+ path: 'hb-products',
974
+ isPublic: true,
975
+ },
976
+ routes: [
977
+ { type: 'GetMany', isPublic: true },
978
+ {
979
+ type: 'CreateOne',
980
+ broadcast: { enabled: true },
981
+ },
982
+ {
983
+ type: 'CreateMany',
984
+ broadcast: { enabled: (data) => data.inStock === true },
985
+ },
986
+ {
987
+ type: 'UpdateOne',
988
+ broadcast: { enabled: true, eventName: customEvent },
989
+ },
990
+ {
991
+ type: 'UpdateMany',
992
+ broadcast: { enabled: false },
993
+ },
994
+ {
995
+ type: 'ReplaceOne',
996
+ broadcast: { enabled: true },
997
+ },
998
+ {
999
+ type: 'DuplicateOne',
1000
+ broadcast: { enabled: true },
1001
+ },
1002
+ {
1003
+ type: 'DuplicateMany',
1004
+ broadcast: { enabled: true },
1005
+ },
1006
+ {
1007
+ type: 'DeleteOne',
1008
+ broadcast: { enabled: true },
1009
+ },
1010
+ {
1011
+ type: 'DeleteMany',
1012
+ broadcast: { enabled: true },
1013
+ },
1014
+ ],
1015
+ }, undefined, fixtures, async (app) => {
1016
+ app.useWebSocketAdapter(new e2e_setup_1.TestSocketAdapter(app));
1017
+ }, true);
1018
+ });
1019
+ it('[CreateOne] should broadcast created product to all WS clients after HTTP call', async () => {
1020
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('post', '/hb-products', { name: 'mustard', inStock: true }, { broadcastEvent: 'create-one-hb-product' });
1021
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1022
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
1023
+ event: 'create-one-hb-product',
1024
+ data: expect.arrayContaining([
1025
+ expect.objectContaining({ name: 'mustard', inStock: true }),
1026
+ ]),
1027
+ });
1028
+ expect(broadcastData).toEqual(expect.arrayContaining([
1029
+ expect.objectContaining({ name: 'mustard', inStock: true }),
1030
+ ]));
1031
+ });
1032
+ it('[CreateMany] should broadcast only inStock products after HTTP call', async () => {
1033
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('post', '/hb-products/many', { list: [{ name: 'pickles', inStock: true }, { name: 'onions', inStock: false }] }, { broadcastEvent: 'create-many-hb-product' });
1034
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1035
+ expect(broadcastData).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'pickles', inStock: true })]));
1036
+ expect(broadcastData).not.toEqual(expect.arrayContaining([expect.objectContaining({ name: 'onions' })]));
1037
+ });
1038
+ it('[UpdateOne] should broadcast updated product with custom event name after HTTP call', async () => {
1039
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('patch', `/hb-products/${firstProduct.id}`, { name: 'updated mayo', inStock: false }, { broadcastEvent: customEvent });
1040
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1041
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
1042
+ event: customEvent,
1043
+ data: expect.arrayContaining([
1044
+ expect.objectContaining({ id: firstProduct.id, name: 'updated mayo', inStock: false }),
1045
+ ]),
1046
+ });
1047
+ expect(broadcastData).toEqual(expect.arrayContaining([
1048
+ expect.objectContaining({ name: 'updated mayo' }),
1049
+ ]));
1050
+ });
1051
+ it('[ReplaceOne] should broadcast replaced product after HTTP call', async () => {
1052
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('put', `/hb-products/${firstProduct.id}`, { name: 'replaced mayo', inStock: false }, { broadcastEvent: 'replace-one-hb-product' });
1053
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1054
+ expect(broadcastData).toEqual(expect.arrayContaining([
1055
+ expect.objectContaining({ id: firstProduct.id, name: 'replaced mayo', inStock: false }),
1056
+ ]));
1057
+ });
1058
+ it('[DuplicateOne] should broadcast duplicated product after HTTP call', async () => {
1059
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('post', `/hb-products/duplicate/${firstProduct.id}`, { name: 'duplicated mayo' }, { broadcastEvent: 'duplicate-one-hb-product' });
1060
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1061
+ expect(broadcastData).toEqual(expect.arrayContaining([
1062
+ expect.objectContaining({ name: 'duplicated mayo', inStock: firstProduct.inStock }),
1063
+ ]));
1064
+ });
1065
+ it('[DuplicateMany] should broadcast duplicated products after HTTP call', async () => {
1066
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('post', '/hb-products/duplicate', { status: 'dup' }, {
1067
+ broadcastEvent: 'duplicate-many-hb-product',
1068
+ query: { ids: [firstProduct.id, secondProduct.id] },
1069
+ });
1070
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1071
+ expect(broadcastData.length).toBeGreaterThanOrEqual(2);
1072
+ });
1073
+ it('[DeleteOne] should broadcast deleted product id to all WS clients after HTTP call', async () => {
1074
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('delete', `/hb-products/${firstProduct.id}`, {}, { broadcastEvent: 'delete-one-hb-product' });
1075
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1076
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledWith({
1077
+ event: 'delete-one-hb-product',
1078
+ data: expect.arrayContaining([expect.objectContaining({ id: firstProduct.id })]),
1079
+ });
1080
+ expect(broadcastData).toEqual(expect.arrayContaining([{ id: firstProduct.id }]));
1081
+ });
1082
+ it('[DeleteMany] should broadcast deleted product ids to all WS clients after HTTP call', async () => {
1083
+ const ids = [firstProduct.id, secondProduct.id];
1084
+ const { broadcastData } = await e2e_setup_1.server.httpWithBroadcast('delete', '/hb-products', {}, {
1085
+ broadcastEvent: 'delete-many-hb-product',
1086
+ query: { ids },
1087
+ });
1088
+ expect(e2e_setup_1.handleSocketBroadcast).toHaveBeenCalledTimes(1);
1089
+ expect(broadcastData).toEqual(expect.arrayContaining(ids.map(id => ({ id }))));
1090
+ });
1091
+ it('[UpdateMany] should NOT broadcast when enabled is false', async () => {
1092
+ const { body: products } = await e2e_setup_1.server.get('/hb-products');
1093
+ const ids = products.map((p) => p.id);
1094
+ const response = await e2e_setup_1.server.patch(`/hb-products/many?ids=${ids.join('&ids=')}`, { status: 'updated' });
1095
+ expect(response).toBeDefined();
1096
+ expect(e2e_setup_1.handleSocketBroadcast).not.toHaveBeenCalled();
1097
+ });
1098
+ });
637
1099
  });
638
1100
  //# sourceMappingURL=dynamic-api-for-feature.e2e-spec.js.map