@owox/backend 0.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.
Files changed (107) hide show
  1. package/README.md +144 -0
  2. package/dist/app.module.js +39 -0
  3. package/dist/common/authorization-context/authorization.context.js +21 -0
  4. package/dist/common/common.module.js +21 -0
  5. package/dist/common/exceptions/access-validation.exception.js +15 -0
  6. package/dist/common/exceptions/base-exception.filter.js +30 -0
  7. package/dist/common/exceptions/base.exception.js +3 -0
  8. package/dist/common/exceptions/business-violation.exception.js +14 -0
  9. package/dist/common/resolver/type-resolver.js +33 -0
  10. package/dist/common/resolver/typed-component.resolver.js +3 -0
  11. package/dist/common/scheduler/facades/scheduler-facade.impl.js +55 -0
  12. package/dist/common/scheduler/scheduler.module.js +32 -0
  13. package/dist/common/scheduler/services/fetchers/time-based-trigger-fetcher.factory.js +24 -0
  14. package/dist/common/scheduler/services/fetchers/time-based-trigger-fetcher.service.js +82 -0
  15. package/dist/common/scheduler/services/graceful-shutdown.service.js +96 -0
  16. package/dist/common/scheduler/services/runners/abstract-trigger-runner.service.js +82 -0
  17. package/dist/common/scheduler/services/runners/direct-trigger-runner.service.js +14 -0
  18. package/dist/common/scheduler/services/runners/pubsub-trigger-runner.service.js +145 -0
  19. package/dist/common/scheduler/services/runners/trigger-runner.factory.js +87 -0
  20. package/dist/common/scheduler/services/runners/trigger-runner.interface.js +3 -0
  21. package/dist/common/scheduler/services/system-time.service.js +20 -0
  22. package/dist/common/scheduler/shared/entities/scheduled-trigger.entity.js +47 -0
  23. package/dist/common/scheduler/shared/entities/time-based-trigger.entity.js +72 -0
  24. package/dist/common/scheduler/shared/scheduler.facade.js +5 -0
  25. package/dist/common/scheduler/shared/time-based-trigger-handler.interface.js +3 -0
  26. package/dist/config/database.config.js +31 -0
  27. package/dist/config/express-static.config.js +33 -0
  28. package/dist/config/global-pipes.config.js +12 -0
  29. package/dist/config/swagger.config.js +16 -0
  30. package/dist/data-marts/controllers/data-mart.controller.js +182 -0
  31. package/dist/data-marts/controllers/data-storage.controller.js +124 -0
  32. package/dist/data-marts/controllers/spec/data-mart.api.js +43 -0
  33. package/dist/data-marts/controllers/spec/data-storage.api.js +29 -0
  34. package/dist/data-marts/data-marts.module.js +65 -0
  35. package/dist/data-marts/data-storage-types/athena/schemas/athena-config.schema.js +10 -0
  36. package/dist/data-marts/data-storage-types/athena/schemas/athena-credentials.schema.js +12 -0
  37. package/dist/data-marts/data-storage-types/athena/services/athena-access.validator.js +39 -0
  38. package/dist/data-marts/data-storage-types/athena/services/athena-title.generator.js +24 -0
  39. package/dist/data-marts/data-storage-types/bigquery/schemas/bigquery-config.schema.js +9 -0
  40. package/dist/data-marts/data-storage-types/bigquery/schemas/bigquery-credentials.schema.js +11 -0
  41. package/dist/data-marts/data-storage-types/bigquery/services/bigquery-access.validator.js +39 -0
  42. package/dist/data-marts/data-storage-types/bigquery/services/bigquery-title.generator.js +24 -0
  43. package/dist/data-marts/data-storage-types/data-storage-config.type.js +3 -0
  44. package/dist/data-marts/data-storage-types/data-storage-facades.js +7 -0
  45. package/dist/data-marts/data-storage-types/data-storage-providers.js +27 -0
  46. package/dist/data-marts/data-storage-types/enums/data-storage-type.enum.js +20 -0
  47. package/dist/data-marts/data-storage-types/facades/data-storage-access.facade.js +38 -0
  48. package/dist/data-marts/data-storage-types/facades/data-storage-title.facade.js +38 -0
  49. package/dist/data-marts/data-storage-types/interfaces/data-storage-access-validator.interface.js +15 -0
  50. package/dist/data-marts/data-storage-types/interfaces/data-storage-title-generator.interface.js +3 -0
  51. package/dist/data-marts/dto/domain/create-data-mart.command.js +17 -0
  52. package/dist/data-marts/dto/domain/create-data-storage.command.js +13 -0
  53. package/dist/data-marts/dto/domain/data-mart.dto.js +27 -0
  54. package/dist/data-marts/dto/domain/data-storage.dto.js +25 -0
  55. package/dist/data-marts/dto/domain/delete-data-mart.command.js +15 -0
  56. package/dist/data-marts/dto/domain/delete-data-storage.command.js +13 -0
  57. package/dist/data-marts/dto/domain/get-data-mart.command.js +15 -0
  58. package/dist/data-marts/dto/domain/get-data-storage.command.js +13 -0
  59. package/dist/data-marts/dto/domain/list-data-marts.command.js +13 -0
  60. package/dist/data-marts/dto/domain/list-data-storages.command.js +11 -0
  61. package/dist/data-marts/dto/domain/publish-data-mart.command.js +15 -0
  62. package/dist/data-marts/dto/domain/update-data-mart-definition.command.js +19 -0
  63. package/dist/data-marts/dto/domain/update-data-mart-description.command.js +17 -0
  64. package/dist/data-marts/dto/domain/update-data-mart-title.command.js +17 -0
  65. package/dist/data-marts/dto/domain/update-data-storage.command.js +19 -0
  66. package/dist/data-marts/dto/presentation/create-data-mart-request-api.dto.js +32 -0
  67. package/dist/data-marts/dto/presentation/create-data-mart-response-api.dto.js +27 -0
  68. package/dist/data-marts/dto/presentation/create-data-storage-api.dto.js +25 -0
  69. package/dist/data-marts/dto/presentation/data-mart-response-api.dto.js +65 -0
  70. package/dist/data-marts/dto/presentation/data-storage-list-response-api.dto.js +43 -0
  71. package/dist/data-marts/dto/presentation/data-storage-response-api.dto.js +64 -0
  72. package/dist/data-marts/dto/presentation/update-data-mart-definition-api.dto.js +31 -0
  73. package/dist/data-marts/dto/presentation/update-data-mart-description-api.dto.js +27 -0
  74. package/dist/data-marts/dto/presentation/update-data-mart-title-api.dto.js +25 -0
  75. package/dist/data-marts/dto/presentation/update-data-storage-api.dto.js +50 -0
  76. package/dist/data-marts/dto/schemas/data-mart-table-definitions/data-mart-definition.js +3 -0
  77. package/dist/data-marts/dto/schemas/data-mart-table-definitions/sql-definition.schema.js +8 -0
  78. package/dist/data-marts/dto/schemas/data-mart-table-definitions/table-definition.schema.js +8 -0
  79. package/dist/data-marts/dto/schemas/data-mart-table-definitions/table-pattern-definition.schema.js +8 -0
  80. package/dist/data-marts/dto/schemas/data-mart-table-definitions/view-definition.schema.js +8 -0
  81. package/dist/data-marts/entities/data-mart.entity.js +84 -0
  82. package/dist/data-marts/entities/data-storage.entity.js +66 -0
  83. package/dist/data-marts/enums/data-mart-definition-type.enum.js +11 -0
  84. package/dist/data-marts/enums/data-mart-status.enum.js +9 -0
  85. package/dist/data-marts/mappers/data-mart.mapper.js +87 -0
  86. package/dist/data-marts/mappers/data-storage.mapper.js +75 -0
  87. package/dist/data-marts/services/data-mart.service.js +44 -0
  88. package/dist/data-marts/services/data-storage.service.js +39 -0
  89. package/dist/data-marts/use-cases/create-data-mart.service.js +51 -0
  90. package/dist/data-marts/use-cases/create-data-storage.service.js +44 -0
  91. package/dist/data-marts/use-cases/delete-data-mart.service.js +39 -0
  92. package/dist/data-marts/use-cases/delete-data-storage.service.js +52 -0
  93. package/dist/data-marts/use-cases/get-data-mart.service.js +34 -0
  94. package/dist/data-marts/use-cases/get-data-storage.service.js +34 -0
  95. package/dist/data-marts/use-cases/list-data-marts.service.js +42 -0
  96. package/dist/data-marts/use-cases/list-data-storages.service.js +42 -0
  97. package/dist/data-marts/use-cases/publish-data-mart.service.js +54 -0
  98. package/dist/data-marts/use-cases/update-data-mart-definition.service.js +51 -0
  99. package/dist/data-marts/use-cases/update-data-mart-description.service.js +46 -0
  100. package/dist/data-marts/use-cases/update-data-mart-title.service.js +46 -0
  101. package/dist/data-marts/use-cases/update-data-storage.service.js +53 -0
  102. package/dist/main.js +33 -0
  103. package/dist/public/assets/index-BZJIHZWS.js +502 -0
  104. package/dist/public/assets/index-BpZgB8Pl.css +1 -0
  105. package/dist/public/favicon.png +0 -0
  106. package/dist/public/index.html +14 -0
  107. package/package.json +106 -0
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # 🧭 Architecture Guidelines for Backend Application
2
+
3
+ These guidelines define how to structure and organize the backend architecture for the project using NestJS, TypeORM, and clean layering principles.
4
+
5
+ ---
6
+
7
+ This document also includes the conventions for organizing the application structure, including module layout, naming rules, and folder hierarchy.
8
+
9
+ [modular monolith conventions](./MODULAR_CONVENTIONS.md).
10
+
11
+ ---
12
+
13
+ ## 🧱 Project Layers
14
+
15
+ ### 1. **Entity Layer**
16
+
17
+ * Contains ORM entities (TypeORM `@Entity()` classes).
18
+ * Entities model the database structure.
19
+ * Only internal logic; **no external dependencies** like DTOs.
20
+
21
+ ### 2. **DTO Layer**
22
+
23
+ #### a) **Domain DTOs**
24
+
25
+ * Used within use-cases and services.
26
+ * Belong to application/domain layer.
27
+ * **Must not depend on API/CLI DTOs**.
28
+ * **May depend on Entities**, but not on presentation-level DTOs.
29
+ * Mapping into Domain DTOs is done via **non-static mappers**, not `fromEntity()` inside DTO.
30
+
31
+ #### b) **API/CLI DTOs (Presentation DTOs)**
32
+
33
+ * Presentation-specific output format (API, CLI, etc).
34
+ * Belong to the presentation layer.
35
+ * Can be mapped via **presentation mappers** (non-static).
36
+ * Lower layers **may depend on upper layers**, but the domain layer must never depend on higher-level concerns.
37
+
38
+ ### 3. **Entity Service Layer**
39
+
40
+ * Contains logic for a single entity (e.g., `UserService`).
41
+ * Should interact only with the **corresponding repository**.
42
+ * Can return both:
43
+
44
+ * `Entity` — for use-case services
45
+ * `Domain DTO` — for API/CLI usage (only if simple)
46
+ * **Must not depend on other services or use-cases**.
47
+
48
+ ### 4. **Use-Case Service Layer**
49
+
50
+ * Represents a single business scenario (e.g., `CreateUserService`, `GetUserWithPostsService`).
51
+ * Should typically expose only one public method — usually named `run(...)`.
52
+ * In more complex cases where multiple related operations are needed, it is acceptable to define several clearly named public methods instead of using `run(...)`.
53
+ * Can depend on multiple entity services, repositories, or infrastructure services.
54
+ * Returns a **Domain DTO**.
55
+ * Does **not** return Entity directly.
56
+
57
+ ### 5. **Presentation Layer (Controller, CLI)**
58
+
59
+ * Depends only on **use-case services** or entity services (for simple reads).
60
+ * Receives or returns **presentation-specific DTOs**.
61
+ * Must never operate on Entity directly.
62
+ * Performs mapping to and from presentation DTOs using **non-static mappers**.
63
+
64
+ ### 6. **Infrastructure Layer**
65
+
66
+ * Services to interact with email, queues, external APIs, files, etc.
67
+ * Can be injected into use-case services.
68
+
69
+ ---
70
+
71
+ ## 📦 Mapping Conventions
72
+
73
+ | Source | Target | How |
74
+ | ---------- | ----------- | -------------------- |
75
+ | Entity | Domain DTO | via dedicated mapper |
76
+ | Domain DTO | API/CLI DTO | via dedicated mapper |
77
+
78
+ > 📌 **Do not place `fromEntity()` or `fromDomain()` inside DTOs**, and avoid doing mapping inside services as well.
79
+ > Use dedicated **mapper classes** to convert between layers.
80
+
81
+ > 🧩 Naming and grouping of mappers (e.g., one vs many) — left to the team's discretion.
82
+
83
+ ---
84
+
85
+ ## ✅ Best Practices
86
+
87
+ * Keep **Entity Services** focused per entity.
88
+ * Use **Use-Case Services** for all orchestrations across domains.
89
+ * Structure code to allow **reuse across API, CLI, cron, etc.**
90
+ * Prefer **explicit DTOs** at every boundary.
91
+ * Maintain **one scenario = one use-case service** with a single `.run()` method.
92
+ * Avoid returning Entity from any service that crosses layers.
93
+ * Domain DTOs may depend on Entity, but never on presentation DTOs.
94
+ * API/CLI DTOs may depend on Domain DTOs, but never the other way around.
95
+ * Entity Services **must not depend** on Use-Case Services or other Entity Services.
96
+ * Use-case services **can depend** on multiple Entity Services and Repositories.
97
+ * Controllers and CLI commands must **never see Entities**.
98
+ * Use **dedicated mapper classes** instead of placing logic inside DTOs.
99
+
100
+ ---
101
+
102
+ ## 📁 Suggested Folder Structure
103
+
104
+ ```
105
+ src/
106
+ users/
107
+ entities/
108
+ user.entity.ts
109
+ services/
110
+ user.service.ts
111
+ use-cases/
112
+ get-user.service.ts
113
+ dto/
114
+ domain/ # Domain DTOs (used in use-cases)
115
+ user-domain.dto.ts
116
+ presentation/ # API/CLI DTOs
117
+ user-api-response.dto.ts
118
+ user-cli-response.dto.ts
119
+ mappers/
120
+ user.mapper.ts # Contains conversion logic between layers
121
+ enums/
122
+ user-role.enum.ts
123
+ controllers/
124
+ user.controller.ts
125
+ ```
126
+
127
+ ### 📌 Notes:
128
+
129
+ * Domain DTOs are stored under `dto/domain/` — they are part of the application layer.
130
+ * Presentation-layer DTOs are stored under `dto/presentation/` — used in API/CLI.
131
+ * Each module (e.g., `users/`) is a self-contained feature with clearly organized responsibilities.
132
+ * Mapping logic is implemented in `mappers/` folder per feature.
133
+
134
+ ---
135
+
136
+ ## 🔚 Summary
137
+
138
+ This architecture encourages:
139
+
140
+ * Separation of concerns
141
+ * Clear ownership of logic
142
+ * Readable, testable, and maintainable code
143
+
144
+ Following these guidelines will help create a codebase that is easy to extend, open to the community, and maintainable in the long term.
@@ -0,0 +1,39 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AppModule = void 0;
10
+ const path = require("path");
11
+ const common_1 = require("@nestjs/common");
12
+ const typeorm_1 = require("@nestjs/typeorm");
13
+ const config_1 = require("@nestjs/config");
14
+ const schedule_1 = require("@nestjs/schedule");
15
+ const database_config_1 = require("./config/database.config");
16
+ const data_marts_module_1 = require("./data-marts/data-marts.module");
17
+ const common_module_1 = require("./common/common.module");
18
+ let AppModule = class AppModule {
19
+ };
20
+ exports.AppModule = AppModule;
21
+ exports.AppModule = AppModule = __decorate([
22
+ (0, common_1.Module)({
23
+ imports: [
24
+ config_1.ConfigModule.forRoot({
25
+ isGlobal: true,
26
+ envFilePath: path.resolve(__dirname, '../../../.env'),
27
+ }),
28
+ typeorm_1.TypeOrmModule.forRootAsync({
29
+ imports: [config_1.ConfigModule],
30
+ inject: [config_1.ConfigService],
31
+ useFactory: database_config_1.getDatabaseConfig,
32
+ }),
33
+ schedule_1.ScheduleModule.forRoot(),
34
+ data_marts_module_1.DataMartsModule,
35
+ common_module_1.CommonModule,
36
+ ],
37
+ })
38
+ ], AppModule);
39
+ //# sourceMappingURL=app.module.js.map
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthContext = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ exports.AuthContext = (0, common_1.createParamDecorator)((data, ctx) => {
6
+ const fillStub = process.env.FILL_AUTH_CONTEXT === undefined || process.env.FILL_AUTH_CONTEXT === '1';
7
+ if (fillStub) {
8
+ return { projectId: '0', userId: '0' };
9
+ }
10
+ const request = ctx.switchToHttp().getRequest();
11
+ const projectId = request.headers['x-project'];
12
+ const userId = request.headers['x-user'];
13
+ if (!userId) {
14
+ throw new common_1.BadRequestException('Missing X-User header');
15
+ }
16
+ if (!projectId) {
17
+ throw new common_1.BadRequestException('Missing X-Project header');
18
+ }
19
+ return { projectId, userId };
20
+ });
21
+ //# sourceMappingURL=authorization.context.js.map
@@ -0,0 +1,21 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.CommonModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const scheduler_module_1 = require("./scheduler/scheduler.module");
12
+ let CommonModule = class CommonModule {
13
+ };
14
+ exports.CommonModule = CommonModule;
15
+ exports.CommonModule = CommonModule = __decorate([
16
+ (0, common_1.Module)({
17
+ imports: [scheduler_module_1.SchedulerModule],
18
+ exports: [scheduler_module_1.SchedulerModule],
19
+ })
20
+ ], CommonModule);
21
+ //# sourceMappingURL=common.module.js.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccessValidationException = void 0;
4
+ const business_violation_exception_1 = require("./business-violation.exception");
5
+ class AccessValidationException extends business_violation_exception_1.BusinessViolationException {
6
+ message;
7
+ errorDetails;
8
+ constructor(message, errorDetails) {
9
+ super(message, errorDetails);
10
+ this.message = message;
11
+ this.errorDetails = errorDetails;
12
+ }
13
+ }
14
+ exports.AccessValidationException = AccessValidationException;
15
+ //# sourceMappingURL=access-validation.exception.js.map
@@ -0,0 +1,30 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.BaseExceptionFilter = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const business_violation_exception_1 = require("./business-violation.exception");
12
+ let BaseExceptionFilter = class BaseExceptionFilter {
13
+ catch(exception, host) {
14
+ const ctx = host.switchToHttp();
15
+ const response = ctx.getResponse();
16
+ const request = ctx.getRequest();
17
+ response.status(common_1.HttpStatus.BAD_REQUEST).json({
18
+ statusCode: common_1.HttpStatus.BAD_REQUEST,
19
+ timestamp: new Date().toISOString(),
20
+ path: request.url,
21
+ message: exception.message,
22
+ errorDetails: exception.errorDetails,
23
+ });
24
+ }
25
+ };
26
+ exports.BaseExceptionFilter = BaseExceptionFilter;
27
+ exports.BaseExceptionFilter = BaseExceptionFilter = __decorate([
28
+ (0, common_1.Catch)(business_violation_exception_1.BusinessViolationException)
29
+ ], BaseExceptionFilter);
30
+ //# sourceMappingURL=base-exception.filter.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=base.exception.js.map
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BusinessViolationException = void 0;
4
+ class BusinessViolationException extends Error {
5
+ message;
6
+ errorDetails;
7
+ constructor(message, errorDetails) {
8
+ super(message);
9
+ this.message = message;
10
+ this.errorDetails = errorDetails;
11
+ }
12
+ }
13
+ exports.BusinessViolationException = BusinessViolationException;
14
+ //# sourceMappingURL=business-violation.exception.js.map
@@ -0,0 +1,33 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TypeResolver = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ let TypeResolver = class TypeResolver {
15
+ map = new Map();
16
+ constructor(components) {
17
+ for (const c of components) {
18
+ this.map.set(c.type, c);
19
+ }
20
+ }
21
+ resolve(type) {
22
+ const component = this.map.get(type);
23
+ if (!component)
24
+ throw new Error(`No component found for type: ${type}`);
25
+ return component;
26
+ }
27
+ };
28
+ exports.TypeResolver = TypeResolver;
29
+ exports.TypeResolver = TypeResolver = __decorate([
30
+ (0, common_1.Injectable)(),
31
+ __metadata("design:paramtypes", [Array])
32
+ ], TypeResolver);
33
+ //# sourceMappingURL=type-resolver.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=typed-component.resolver.js.map
@@ -0,0 +1,55 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var SchedulerFacadeImpl_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.SchedulerFacadeImpl = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const schedule_1 = require("@nestjs/schedule");
16
+ const cron_1 = require("cron");
17
+ const system_time_service_1 = require("../services/system-time.service");
18
+ const config_1 = require("@nestjs/config");
19
+ const trigger_runner_factory_1 = require("../services/runners/trigger-runner.factory");
20
+ const time_based_trigger_fetcher_factory_1 = require("../services/fetchers/time-based-trigger-fetcher.factory");
21
+ let SchedulerFacadeImpl = SchedulerFacadeImpl_1 = class SchedulerFacadeImpl {
22
+ schedulerRegistry;
23
+ configService;
24
+ triggerFetcherFactory;
25
+ triggerRunnerFactory;
26
+ systemTimeService;
27
+ logger = new common_1.Logger(SchedulerFacadeImpl_1.name);
28
+ defaultTimezone = 'UTC';
29
+ constructor(schedulerRegistry, configService, triggerFetcherFactory, triggerRunnerFactory, systemTimeService) {
30
+ this.schedulerRegistry = schedulerRegistry;
31
+ this.configService = configService;
32
+ this.triggerFetcherFactory = triggerFetcherFactory;
33
+ this.triggerRunnerFactory = triggerRunnerFactory;
34
+ this.systemTimeService = systemTimeService;
35
+ }
36
+ async registerTimeBasedTriggerHandler(triggerHandler) {
37
+ const runner = await this.triggerRunnerFactory.createRunner(triggerHandler, this.systemTimeService);
38
+ const fetcher = this.triggerFetcherFactory.createFetcher(triggerHandler.getTriggerRepository(), this.systemTimeService);
39
+ const timezone = this.configService.get('SCHEDULER_TIMEZONE', this.defaultTimezone);
40
+ const job = new cron_1.CronJob(triggerHandler.processingCronExpression(), () => fetcher.fetchTriggersReadyForProcessing().then(triggers => runner.runTriggers(triggers)), null, false, timezone);
41
+ this.schedulerRegistry.addCronJob(triggerHandler.constructor.name, job);
42
+ job.start();
43
+ this.logger.log(`Time-based trigger handler '${triggerHandler.constructor.name}' initialized '${triggerHandler.processingCronExpression()}' ${timezone}`);
44
+ }
45
+ };
46
+ exports.SchedulerFacadeImpl = SchedulerFacadeImpl;
47
+ exports.SchedulerFacadeImpl = SchedulerFacadeImpl = SchedulerFacadeImpl_1 = __decorate([
48
+ (0, common_1.Injectable)(),
49
+ __metadata("design:paramtypes", [schedule_1.SchedulerRegistry,
50
+ config_1.ConfigService,
51
+ time_based_trigger_fetcher_factory_1.TimeBasedTriggerFetcherFactory,
52
+ trigger_runner_factory_1.TriggerRunnerFactory,
53
+ system_time_service_1.SystemTimeService])
54
+ ], SchedulerFacadeImpl);
55
+ //# sourceMappingURL=scheduler-facade.impl.js.map
@@ -0,0 +1,32 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SchedulerModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const scheduler_facade_impl_1 = require("./facades/scheduler-facade.impl");
12
+ const scheduler_facade_1 = require("./shared/scheduler.facade");
13
+ const trigger_runner_factory_1 = require("./services/runners/trigger-runner.factory");
14
+ const system_time_service_1 = require("./services/system-time.service");
15
+ const time_based_trigger_fetcher_factory_1 = require("./services/fetchers/time-based-trigger-fetcher.factory");
16
+ const graceful_shutdown_service_1 = require("./services/graceful-shutdown.service");
17
+ let SchedulerModule = class SchedulerModule {
18
+ };
19
+ exports.SchedulerModule = SchedulerModule;
20
+ exports.SchedulerModule = SchedulerModule = __decorate([
21
+ (0, common_1.Module)({
22
+ providers: [
23
+ { provide: scheduler_facade_1.SCHEDULER_FACADE, useClass: scheduler_facade_impl_1.SchedulerFacadeImpl },
24
+ time_based_trigger_fetcher_factory_1.TimeBasedTriggerFetcherFactory,
25
+ trigger_runner_factory_1.TriggerRunnerFactory,
26
+ system_time_service_1.SystemTimeService,
27
+ graceful_shutdown_service_1.GracefulShutdownService,
28
+ ],
29
+ exports: [scheduler_facade_1.SCHEDULER_FACADE],
30
+ })
31
+ ], SchedulerModule);
32
+ //# sourceMappingURL=scheduler.module.js.map
@@ -0,0 +1,24 @@
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 TimeBasedTriggerFetcherFactory_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.TimeBasedTriggerFetcherFactory = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const time_based_trigger_fetcher_service_1 = require("./time-based-trigger-fetcher.service");
13
+ let TimeBasedTriggerFetcherFactory = TimeBasedTriggerFetcherFactory_1 = class TimeBasedTriggerFetcherFactory {
14
+ logger = new common_1.Logger(TimeBasedTriggerFetcherFactory_1.name);
15
+ createFetcher(repository, systemTimeService) {
16
+ this.logger.log(`[${repository.metadata.name}] Creating TimeBasedTriggerFetcherService`);
17
+ return new time_based_trigger_fetcher_service_1.TimeBasedTriggerFetcherService(repository, systemTimeService);
18
+ }
19
+ };
20
+ exports.TimeBasedTriggerFetcherFactory = TimeBasedTriggerFetcherFactory;
21
+ exports.TimeBasedTriggerFetcherFactory = TimeBasedTriggerFetcherFactory = TimeBasedTriggerFetcherFactory_1 = __decorate([
22
+ (0, common_1.Injectable)()
23
+ ], TimeBasedTriggerFetcherFactory);
24
+ //# sourceMappingURL=time-based-trigger-fetcher.factory.js.map
@@ -0,0 +1,82 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var TimeBasedTriggerFetcherService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.TimeBasedTriggerFetcherService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const time_based_trigger_entity_1 = require("../../shared/entities/time-based-trigger.entity");
16
+ const system_time_service_1 = require("../system-time.service");
17
+ const typeorm_1 = require("typeorm");
18
+ let TimeBasedTriggerFetcherService = TimeBasedTriggerFetcherService_1 = class TimeBasedTriggerFetcherService {
19
+ repository;
20
+ systemClock;
21
+ logger = new common_1.Logger(TimeBasedTriggerFetcherService_1.name);
22
+ entityName;
23
+ constructor(repository, systemClock) {
24
+ this.repository = repository;
25
+ this.systemClock = systemClock;
26
+ this.entityName = this.repository.metadata.name;
27
+ }
28
+ async fetchTriggersReadyForProcessing() {
29
+ this.logger.debug(`[${this.entityName}] Fetching triggers ready for processing.`);
30
+ const startTime = this.systemClock.now();
31
+ try {
32
+ const triggers = await this.findTriggersReadyForProcessing(startTime);
33
+ return await this.markTriggersAsReady(triggers);
34
+ }
35
+ catch (error) {
36
+ this.logCriticalFailure(error);
37
+ }
38
+ return [];
39
+ }
40
+ async markTriggersAsReady(triggers) {
41
+ const triggersToProcess = [];
42
+ for (let i = 0; i < triggers.length; i++) {
43
+ const trigger = triggers[i];
44
+ try {
45
+ trigger.status = time_based_trigger_entity_1.TriggerStatus.READY;
46
+ await this.repository.save(trigger);
47
+ triggersToProcess.push(trigger);
48
+ }
49
+ catch (error) {
50
+ if (error instanceof typeorm_1.OptimisticLockVersionMismatchError) {
51
+ this.logger.log(`[${this.entityName}] Optimistic lock conflict for trigger ${trigger.id}. Skipping as likely processed by another instance.`);
52
+ }
53
+ else {
54
+ throw error;
55
+ }
56
+ }
57
+ }
58
+ return triggersToProcess;
59
+ }
60
+ async findTriggersReadyForProcessing(currentTime) {
61
+ return this.repository
62
+ .createQueryBuilder('t')
63
+ .where('t.nextRunTimestamp IS NOT NULL')
64
+ .andWhere('t.nextRunTimestamp <= :currentTime', { currentTime })
65
+ .andWhere('t.isActive = true')
66
+ .andWhere('t.status = :status', { status: time_based_trigger_entity_1.TriggerStatus.IDLE })
67
+ .orderBy('t.nextRunTimestamp', 'ASC')
68
+ .getMany();
69
+ }
70
+ logCriticalFailure(error) {
71
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
72
+ const errorStack = error instanceof Error ? error.stack : undefined;
73
+ this.logger.error(`[${this.entityName}] Critical failure in dispatcher: ${errorMessage}`, errorStack);
74
+ }
75
+ };
76
+ exports.TimeBasedTriggerFetcherService = TimeBasedTriggerFetcherService;
77
+ exports.TimeBasedTriggerFetcherService = TimeBasedTriggerFetcherService = TimeBasedTriggerFetcherService_1 = __decorate([
78
+ (0, common_1.Injectable)(),
79
+ __metadata("design:paramtypes", [typeorm_1.Repository,
80
+ system_time_service_1.SystemTimeService])
81
+ ], TimeBasedTriggerFetcherService);
82
+ //# sourceMappingURL=time-based-trigger-fetcher.service.js.map
@@ -0,0 +1,96 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var GracefulShutdownService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.GracefulShutdownService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const config_1 = require("@nestjs/config");
16
+ let GracefulShutdownService = GracefulShutdownService_1 = class GracefulShutdownService {
17
+ configService;
18
+ logger = new common_1.Logger(GracefulShutdownService_1.name);
19
+ isShuttingDown = false;
20
+ shutdownPromise = null;
21
+ shutdownResolve = null;
22
+ activeProcesses = new Map();
23
+ shutdownTimeoutMinutes;
24
+ constructor(configService) {
25
+ this.configService = configService;
26
+ this.shutdownTimeoutMinutes = this.configService.get('SCHEDULER_GRACEFUL_SHUTDOWN_TIMEOUT_MINUTES', 15);
27
+ this.logger.log(`Graceful shutdown timeout set to ${this.shutdownTimeoutMinutes}m`);
28
+ }
29
+ isInShutdownMode() {
30
+ return this.isShuttingDown;
31
+ }
32
+ registerActiveProcess(processId) {
33
+ this.activeProcesses.set(processId, {
34
+ id: processId,
35
+ startTime: new Date(),
36
+ });
37
+ this.logger.debug(`Registered active process: ${processId}. Total active: ${this.activeProcesses.size}`);
38
+ return processId;
39
+ }
40
+ unregisterActiveProcess(processId) {
41
+ if (this.activeProcesses.has(processId)) {
42
+ this.activeProcesses.delete(processId);
43
+ this.logger.debug(`Unregistered process: ${processId}. Remaining active: ${this.activeProcesses.size}`);
44
+ if (this.isShuttingDown && this.activeProcesses.size === 0) {
45
+ this.logger.log('All active processes completed, finalizing shutdown');
46
+ this.completeShutdown();
47
+ }
48
+ }
49
+ }
50
+ async initiateShutdown() {
51
+ if (this.isShuttingDown) {
52
+ return this.shutdownPromise;
53
+ }
54
+ this.isShuttingDown = true;
55
+ this.logger.log(`Graceful shutdown initiated. Active processes: ${this.activeProcesses.size}`);
56
+ if (this.activeProcesses.size === 0) {
57
+ this.logger.log('No active processes, completing shutdown immediately');
58
+ this.shutdownPromise = Promise.resolve();
59
+ return this.shutdownPromise;
60
+ }
61
+ this.shutdownPromise = new Promise(resolve => {
62
+ this.shutdownResolve = resolve;
63
+ setTimeout(() => {
64
+ if (this.isShuttingDown && this.shutdownResolve) {
65
+ const remainingProcesses = this.activeProcesses.size;
66
+ if (remainingProcesses > 0) {
67
+ this.logger.warn(`Forcing shutdown after timeout of ${this.shutdownTimeoutMinutes}m. ${remainingProcesses} processes still active.`);
68
+ this.activeProcesses.forEach((process, id) => {
69
+ const durationMs = new Date().getTime() - process.startTime.getTime();
70
+ const durationMinutes = Math.round((durationMs / 60000) * 10) / 10;
71
+ this.logger.warn(`Process ${id} has been running for ${durationMinutes}m`);
72
+ });
73
+ }
74
+ this.shutdownResolve();
75
+ }
76
+ }, this.shutdownTimeoutMinutes * 60 * 1000);
77
+ });
78
+ return this.shutdownPromise;
79
+ }
80
+ completeShutdown() {
81
+ if (this.isShuttingDown && this.shutdownResolve) {
82
+ this.logger.log('Graceful shutdown completed');
83
+ this.shutdownResolve();
84
+ this.shutdownResolve = null;
85
+ }
86
+ }
87
+ async onModuleDestroy() {
88
+ await this.initiateShutdown();
89
+ }
90
+ };
91
+ exports.GracefulShutdownService = GracefulShutdownService;
92
+ exports.GracefulShutdownService = GracefulShutdownService = GracefulShutdownService_1 = __decorate([
93
+ (0, common_1.Injectable)(),
94
+ __metadata("design:paramtypes", [config_1.ConfigService])
95
+ ], GracefulShutdownService);
96
+ //# sourceMappingURL=graceful-shutdown.service.js.map