@quanticjs/core 1.1.1
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.
- package/dist/bootstrap/bootstrapService.d.ts +8 -0
- package/dist/bootstrap/bootstrapService.js +58 -0
- package/dist/cqrs/PipelineExecutor.d.ts +31 -0
- package/dist/cqrs/PipelineExecutor.js +81 -0
- package/dist/cqrs/behaviors/CacheBehavior.d.ts +9 -0
- package/dist/cqrs/behaviors/CacheBehavior.js +68 -0
- package/dist/cqrs/behaviors/DistributedLockBehavior.d.ts +12 -0
- package/dist/cqrs/behaviors/DistributedLockBehavior.js +90 -0
- package/dist/cqrs/behaviors/FeatureFlagBehavior.d.ts +8 -0
- package/dist/cqrs/behaviors/FeatureFlagBehavior.js +58 -0
- package/dist/cqrs/behaviors/InvalidateCacheBehavior.d.ts +9 -0
- package/dist/cqrs/behaviors/InvalidateCacheBehavior.js +61 -0
- package/dist/cqrs/behaviors/LogBehavior.d.ts +9 -0
- package/dist/cqrs/behaviors/LogBehavior.js +125 -0
- package/dist/cqrs/behaviors/PerformanceBehavior.d.ts +12 -0
- package/dist/cqrs/behaviors/PerformanceBehavior.js +56 -0
- package/dist/cqrs/behaviors/TransactionalBehavior.d.ts +18 -0
- package/dist/cqrs/behaviors/TransactionalBehavior.js +77 -0
- package/dist/cqrs/behaviors/ValidationBehavior.d.ts +4 -0
- package/dist/cqrs/behaviors/ValidationBehavior.js +33 -0
- package/dist/cqrs/behaviors/WorkflowBehavior.d.ts +8 -0
- package/dist/cqrs/behaviors/WorkflowBehavior.js +61 -0
- package/dist/cqrs/constants.d.ts +2 -0
- package/dist/cqrs/constants.js +5 -0
- package/dist/cqrs/decorators/Cache.decorator.d.ts +13 -0
- package/dist/cqrs/decorators/Cache.decorator.js +18 -0
- package/dist/cqrs/decorators/DistributedLock.decorator.d.ts +15 -0
- package/dist/cqrs/decorators/DistributedLock.decorator.js +23 -0
- package/dist/cqrs/decorators/FeatureFlag.decorator.d.ts +9 -0
- package/dist/cqrs/decorators/FeatureFlag.decorator.js +14 -0
- package/dist/cqrs/decorators/InvalidateCache.decorator.d.ts +6 -0
- package/dist/cqrs/decorators/InvalidateCache.decorator.js +14 -0
- package/dist/cqrs/decorators/IsolatedTransaction.decorator.d.ts +14 -0
- package/dist/cqrs/decorators/IsolatedTransaction.decorator.js +25 -0
- package/dist/cqrs/decorators/Log.decorator.d.ts +11 -0
- package/dist/cqrs/decorators/Log.decorator.js +18 -0
- package/dist/cqrs/decorators/Validate.decorator.d.ts +24 -0
- package/dist/cqrs/decorators/Validate.decorator.js +37 -0
- package/dist/cqrs/decorators/Workflow.decorator.d.ts +8 -0
- package/dist/cqrs/decorators/Workflow.decorator.js +14 -0
- package/dist/cqrs/interfaces/WorkflowEngine.d.ts +14 -0
- package/dist/cqrs/interfaces/WorkflowEngine.js +4 -0
- package/dist/cqrs/pipeline/QuanticCommandBus.d.ts +37 -0
- package/dist/cqrs/pipeline/QuanticCommandBus.js +99 -0
- package/dist/cqrs/pipeline/QuanticQueryBus.d.ts +28 -0
- package/dist/cqrs/pipeline/QuanticQueryBus.js +78 -0
- package/dist/cqrs/pipeline/runPipeline.d.ts +3 -0
- package/dist/cqrs/pipeline/runPipeline.js +12 -0
- package/dist/cqrs/transaction/TransactionContext.d.ts +18 -0
- package/dist/cqrs/transaction/TransactionContext.js +26 -0
- package/dist/cqrs/transaction/getTransactionalRepo.d.ts +16 -0
- package/dist/cqrs/transaction/getTransactionalRepo.js +22 -0
- package/dist/cqrs/validation/ICommandValidator.d.ts +48 -0
- package/dist/cqrs/validation/ICommandValidator.js +21 -0
- package/dist/entities/BaseEntity.d.ts +5 -0
- package/dist/entities/BaseEntity.js +31 -0
- package/dist/entities/TenantBaseEntity.d.ts +4 -0
- package/dist/entities/TenantBaseEntity.js +22 -0
- package/dist/events/DomainEvent.d.ts +14 -0
- package/dist/events/DomainEvent.js +27 -0
- package/dist/events/OutboxEvent.entity.d.ts +18 -0
- package/dist/events/OutboxEvent.entity.js +87 -0
- package/dist/events/OutboxPublisherService.d.ts +14 -0
- package/dist/events/OutboxPublisherService.js +104 -0
- package/dist/events/RedisStreamConsumer.d.ts +43 -0
- package/dist/events/RedisStreamConsumer.js +158 -0
- package/dist/events/RedisStreamPublisher.d.ts +9 -0
- package/dist/events/RedisStreamPublisher.js +60 -0
- package/dist/filters/GlobalExceptionFilter.d.ts +11 -0
- package/dist/filters/GlobalExceptionFilter.js +102 -0
- package/dist/guards/JwtAuthGuard.d.ts +10 -0
- package/dist/guards/JwtAuthGuard.js +46 -0
- package/dist/guards/JwtStrategy.d.ts +22 -0
- package/dist/guards/JwtStrategy.js +47 -0
- package/dist/guards/RolesGuard.d.ts +8 -0
- package/dist/guards/RolesGuard.js +52 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.js +146 -0
- package/dist/interceptors/ResultInterceptor.d.ts +7 -0
- package/dist/interceptors/ResultInterceptor.js +88 -0
- package/dist/lifecycle/GracefulShutdownService.d.ts +24 -0
- package/dist/lifecycle/GracefulShutdownService.js +93 -0
- package/dist/logging/pino-config.d.ts +35 -0
- package/dist/logging/pino-config.js +79 -0
- package/dist/metrics/MetricsController.d.ts +7 -0
- package/dist/metrics/MetricsController.js +42 -0
- package/dist/metrics/MetricsService.d.ts +13 -0
- package/dist/metrics/MetricsService.js +58 -0
- package/dist/middleware/CorrelationIdMiddleware.d.ts +4 -0
- package/dist/middleware/CorrelationIdMiddleware.js +33 -0
- package/dist/middleware/CorrelationStore.d.ts +11 -0
- package/dist/middleware/CorrelationStore.js +9 -0
- package/dist/middleware/TenantContextMiddleware.d.ts +7 -0
- package/dist/middleware/TenantContextMiddleware.js +27 -0
- package/dist/middleware/TenantStore.d.ts +9 -0
- package/dist/middleware/TenantStore.js +9 -0
- package/dist/redis/redis.module.d.ts +8 -0
- package/dist/redis/redis.module.js +49 -0
- package/dist/resilience/CircuitBreakerFactory.d.ts +12 -0
- package/dist/resilience/CircuitBreakerFactory.js +22 -0
- package/dist/result/Result.d.ts +26 -0
- package/dist/result/Result.js +62 -0
- package/dist/shared-kernel.module.d.ts +13 -0
- package/dist/shared-kernel.module.js +87 -0
- package/dist/subscribers/TenantSubscriber.d.ts +20 -0
- package/dist/subscribers/TenantSubscriber.js +52 -0
- package/dist/testing/TestingModuleFactory.d.ts +23 -0
- package/dist/testing/TestingModuleFactory.js +63 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/mocks.d.ts +34 -0
- package/dist/testing/mocks.js +62 -0
- package/dist/unleash/initial-flags.d.ts +7 -0
- package/dist/unleash/initial-flags.js +9 -0
- package/dist/unleash/unleash.module.d.ts +9 -0
- package/dist/unleash/unleash.module.js +47 -0
- package/package.json +140 -0
- package/src/bootstrap/bootstrapService.ts +72 -0
- package/src/cqrs/behaviors/CacheBehavior.spec.ts +63 -0
- package/src/cqrs/behaviors/CacheBehavior.ts +54 -0
- package/src/cqrs/behaviors/DistributedLockBehavior.ts +88 -0
- package/src/cqrs/behaviors/FeatureFlagBehavior.ts +46 -0
- package/src/cqrs/behaviors/InvalidateCacheBehavior.spec.ts +89 -0
- package/src/cqrs/behaviors/InvalidateCacheBehavior.ts +50 -0
- package/src/cqrs/behaviors/LogBehavior.spec.ts +55 -0
- package/src/cqrs/behaviors/LogBehavior.ts +121 -0
- package/src/cqrs/behaviors/PerformanceBehavior.spec.ts +48 -0
- package/src/cqrs/behaviors/PerformanceBehavior.ts +43 -0
- package/src/cqrs/behaviors/TransactionalBehavior.ts +64 -0
- package/src/cqrs/behaviors/ValidationBehavior.spec.ts +114 -0
- package/src/cqrs/behaviors/ValidationBehavior.ts +29 -0
- package/src/cqrs/behaviors/WorkflowBehavior.spec.ts +97 -0
- package/src/cqrs/behaviors/WorkflowBehavior.ts +62 -0
- package/src/cqrs/constants.ts +2 -0
- package/src/cqrs/decorators/Cache.decorator.ts +24 -0
- package/src/cqrs/decorators/DistributedLock.decorator.ts +34 -0
- package/src/cqrs/decorators/FeatureFlag.decorator.ts +23 -0
- package/src/cqrs/decorators/InvalidateCache.decorator.spec.ts +20 -0
- package/src/cqrs/decorators/InvalidateCache.decorator.ts +17 -0
- package/src/cqrs/decorators/IsolatedTransaction.decorator.ts +24 -0
- package/src/cqrs/decorators/Log.decorator.ts +22 -0
- package/src/cqrs/decorators/Validate.decorator.ts +39 -0
- package/src/cqrs/decorators/Workflow.decorator.ts +22 -0
- package/src/cqrs/interfaces/WorkflowEngine.ts +19 -0
- package/src/cqrs/pipeline/QuanticCommandBus.ts +69 -0
- package/src/cqrs/pipeline/QuanticQueryBus.ts +56 -0
- package/src/cqrs/pipeline/runPipeline.ts +22 -0
- package/src/cqrs/transaction/TransactionContext.ts +26 -0
- package/src/cqrs/transaction/getTransactionalRepo.ts +23 -0
- package/src/cqrs/validation/ICommandValidator.ts +55 -0
- package/src/entities/BaseEntity.ts +16 -0
- package/src/entities/TenantBaseEntity.ts +7 -0
- package/src/events/DomainEvent.ts +27 -0
- package/src/events/OutboxEvent.entity.ts +56 -0
- package/src/events/OutboxPublisherService.ts +94 -0
- package/src/events/RedisStreamConsumer.ts +172 -0
- package/src/events/RedisStreamPublisher.ts +54 -0
- package/src/filters/GlobalExceptionFilter.ts +125 -0
- package/src/guards/JwtAuthGuard.ts +29 -0
- package/src/guards/JwtStrategy.ts +41 -0
- package/src/guards/RolesGuard.ts +39 -0
- package/src/index.ts +118 -0
- package/src/interceptors/ResultInterceptor.ts +93 -0
- package/src/lifecycle/GracefulShutdownService.ts +77 -0
- package/src/logging/pino-config.ts +80 -0
- package/src/metrics/MetricsController.ts +17 -0
- package/src/metrics/MetricsService.ts +55 -0
- package/src/middleware/CorrelationIdMiddleware.ts +27 -0
- package/src/middleware/CorrelationStore.ts +13 -0
- package/src/middleware/TenantContextMiddleware.ts +21 -0
- package/src/middleware/TenantStore.ts +11 -0
- package/src/redis/redis.module.ts +41 -0
- package/src/resilience/CircuitBreakerFactory.ts +33 -0
- package/src/result/Result.ts +66 -0
- package/src/shared-kernel.module.ts +87 -0
- package/src/subscribers/TenantSubscriber.ts +47 -0
- package/src/testing/TestingModuleFactory.ts +78 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/mocks.ts +59 -0
- package/src/unleash/unleash.module.ts +45 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,42 @@
|
|
|
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 __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MetricsController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const JwtAuthGuard_1 = require("../guards/JwtAuthGuard");
|
|
18
|
+
const MetricsService_1 = require("./MetricsService");
|
|
19
|
+
let MetricsController = class MetricsController {
|
|
20
|
+
metrics;
|
|
21
|
+
constructor(metrics) {
|
|
22
|
+
this.metrics = metrics;
|
|
23
|
+
}
|
|
24
|
+
async getMetrics(res) {
|
|
25
|
+
const metricsOutput = await this.metrics.getMetrics();
|
|
26
|
+
res.set('Content-Type', this.metrics.getContentType());
|
|
27
|
+
res.end(metricsOutput);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
exports.MetricsController = MetricsController;
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, common_1.Get)('metrics'),
|
|
33
|
+
__param(0, (0, common_1.Res)()),
|
|
34
|
+
__metadata("design:type", Function),
|
|
35
|
+
__metadata("design:paramtypes", [Object]),
|
|
36
|
+
__metadata("design:returntype", Promise)
|
|
37
|
+
], MetricsController.prototype, "getMetrics", null);
|
|
38
|
+
exports.MetricsController = MetricsController = __decorate([
|
|
39
|
+
(0, JwtAuthGuard_1.Public)(),
|
|
40
|
+
(0, common_1.Controller)(),
|
|
41
|
+
__metadata("design:paramtypes", [MetricsService_1.MetricsService])
|
|
42
|
+
], MetricsController);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { Registry, Counter, Histogram, Gauge } from 'prom-client';
|
|
3
|
+
export declare class MetricsService implements OnModuleInit {
|
|
4
|
+
readonly registry: Registry<"text/plain; version=0.0.4; charset=utf-8">;
|
|
5
|
+
readonly buildTotal: Counter<"status" | "tech_stack">;
|
|
6
|
+
readonly stageDuration: Histogram<"status" | "stage_type">;
|
|
7
|
+
readonly promptCacheHits: Counter<string>;
|
|
8
|
+
readonly queueDepth: Gauge<"queue">;
|
|
9
|
+
readonly handlerDuration: Histogram<"handler" | "result">;
|
|
10
|
+
onModuleInit(): void;
|
|
11
|
+
getMetrics(): Promise<string>;
|
|
12
|
+
getContentType(): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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.MetricsService = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const prom_client_1 = require("prom-client");
|
|
12
|
+
let MetricsService = class MetricsService {
|
|
13
|
+
registry = new prom_client_1.Registry();
|
|
14
|
+
buildTotal = new prom_client_1.Counter({
|
|
15
|
+
name: 'arex_build_total',
|
|
16
|
+
help: 'Total number of builds',
|
|
17
|
+
labelNames: ['status', 'tech_stack'],
|
|
18
|
+
registers: [this.registry],
|
|
19
|
+
});
|
|
20
|
+
stageDuration = new prom_client_1.Histogram({
|
|
21
|
+
name: 'arex_stage_duration_seconds',
|
|
22
|
+
help: 'Duration of pipeline stages in seconds',
|
|
23
|
+
labelNames: ['stage_type', 'status'],
|
|
24
|
+
buckets: [0.5, 1, 2, 5, 10, 30, 60, 120, 300],
|
|
25
|
+
registers: [this.registry],
|
|
26
|
+
});
|
|
27
|
+
promptCacheHits = new prom_client_1.Counter({
|
|
28
|
+
name: 'arex_prompt_cache_hits_total',
|
|
29
|
+
help: 'Total prompt cache hits',
|
|
30
|
+
registers: [this.registry],
|
|
31
|
+
});
|
|
32
|
+
queueDepth = new prom_client_1.Gauge({
|
|
33
|
+
name: 'arex_queue_depth',
|
|
34
|
+
help: 'Current depth of Bull job queue',
|
|
35
|
+
labelNames: ['queue'],
|
|
36
|
+
registers: [this.registry],
|
|
37
|
+
});
|
|
38
|
+
handlerDuration = new prom_client_1.Histogram({
|
|
39
|
+
name: 'arex_handler_duration_seconds',
|
|
40
|
+
help: 'Duration of command/query handlers in seconds',
|
|
41
|
+
labelNames: ['handler', 'result'],
|
|
42
|
+
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5],
|
|
43
|
+
registers: [this.registry],
|
|
44
|
+
});
|
|
45
|
+
onModuleInit() {
|
|
46
|
+
(0, prom_client_1.collectDefaultMetrics)({ register: this.registry });
|
|
47
|
+
}
|
|
48
|
+
async getMetrics() {
|
|
49
|
+
return this.registry.metrics();
|
|
50
|
+
}
|
|
51
|
+
getContentType() {
|
|
52
|
+
return this.registry.contentType;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.MetricsService = MetricsService;
|
|
56
|
+
exports.MetricsService = MetricsService = __decorate([
|
|
57
|
+
(0, common_1.Injectable)()
|
|
58
|
+
], MetricsService);
|
|
@@ -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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.CorrelationIdMiddleware = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const uuid_1 = require("uuid");
|
|
12
|
+
const CorrelationStore_1 = require("./CorrelationStore");
|
|
13
|
+
const CORRELATION_ID_HEADER = 'X-Correlation-ID';
|
|
14
|
+
let CorrelationIdMiddleware = class CorrelationIdMiddleware {
|
|
15
|
+
use(req, res, next) {
|
|
16
|
+
const correlationId = req.headers[CORRELATION_ID_HEADER.toLowerCase()] || (0, uuid_1.v4)();
|
|
17
|
+
req.correlationId = correlationId;
|
|
18
|
+
req.headers[CORRELATION_ID_HEADER.toLowerCase()] = correlationId;
|
|
19
|
+
res.setHeader(CORRELATION_ID_HEADER, correlationId);
|
|
20
|
+
const storeData = {
|
|
21
|
+
correlationId,
|
|
22
|
+
userId: req.user?.keycloakId,
|
|
23
|
+
organizationId: req.user?.organizationId,
|
|
24
|
+
};
|
|
25
|
+
CorrelationStore_1.correlationStore.run(storeData, () => {
|
|
26
|
+
next();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
exports.CorrelationIdMiddleware = CorrelationIdMiddleware;
|
|
31
|
+
exports.CorrelationIdMiddleware = CorrelationIdMiddleware = __decorate([
|
|
32
|
+
(0, common_1.Injectable)()
|
|
33
|
+
], CorrelationIdMiddleware);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
+
export interface CorrelationStoreData {
|
|
3
|
+
correlationId: string;
|
|
4
|
+
userId?: string;
|
|
5
|
+
organizationId?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Request-scoped async local storage for correlation context.
|
|
9
|
+
* Set by CorrelationIdMiddleware, read by LogBehavior and error filters.
|
|
10
|
+
*/
|
|
11
|
+
export declare const correlationStore: AsyncLocalStorage<CorrelationStoreData>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.correlationStore = void 0;
|
|
4
|
+
const async_hooks_1 = require("async_hooks");
|
|
5
|
+
/**
|
|
6
|
+
* Request-scoped async local storage for correlation context.
|
|
7
|
+
* Set by CorrelationIdMiddleware, read by LogBehavior and error filters.
|
|
8
|
+
*/
|
|
9
|
+
exports.correlationStore = new async_hooks_1.AsyncLocalStorage();
|
|
@@ -0,0 +1,27 @@
|
|
|
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.TenantContextMiddleware = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const TenantStore_1 = require("./TenantStore");
|
|
12
|
+
let TenantContextMiddleware = class TenantContextMiddleware {
|
|
13
|
+
use(req, _res, next) {
|
|
14
|
+
// Extract org_id from JWT payload (set by JwtAuthGuard)
|
|
15
|
+
const orgId = req.user?.organizationId || req.headers['x-tenant-id'] || null;
|
|
16
|
+
req.tenantId = orgId;
|
|
17
|
+
req.tenantContext = { organizationId: orgId };
|
|
18
|
+
// Store in AsyncLocalStorage so TenantSubscriber can access it
|
|
19
|
+
TenantStore_1.tenantStore.run({ organizationId: orgId }, () => {
|
|
20
|
+
next();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
exports.TenantContextMiddleware = TenantContextMiddleware;
|
|
25
|
+
exports.TenantContextMiddleware = TenantContextMiddleware = __decorate([
|
|
26
|
+
(0, common_1.Injectable)()
|
|
27
|
+
], TenantContextMiddleware);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
+
export interface TenantStoreData {
|
|
3
|
+
organizationId: string | null;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Request-scoped async local storage for tenant context.
|
|
7
|
+
* Set by TenantContextMiddleware, read by TenantSubscriber.
|
|
8
|
+
*/
|
|
9
|
+
export declare const tenantStore: AsyncLocalStorage<TenantStoreData>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tenantStore = void 0;
|
|
4
|
+
const async_hooks_1 = require("async_hooks");
|
|
5
|
+
/**
|
|
6
|
+
* Request-scoped async local storage for tenant context.
|
|
7
|
+
* Set by TenantContextMiddleware, read by TenantSubscriber.
|
|
8
|
+
*/
|
|
9
|
+
exports.tenantStore = new async_hooks_1.AsyncLocalStorage();
|
|
@@ -0,0 +1,49 @@
|
|
|
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 __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
var RedisModule_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.RedisModule = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
16
|
+
const constants_1 = require("../cqrs/constants");
|
|
17
|
+
let RedisModule = class RedisModule {
|
|
18
|
+
static { RedisModule_1 = this; }
|
|
19
|
+
static logger = new common_1.Logger('RedisModule');
|
|
20
|
+
static forRoot(options = {}) {
|
|
21
|
+
const redisProvider = {
|
|
22
|
+
provide: constants_1.REDIS_CLIENT,
|
|
23
|
+
useFactory: () => {
|
|
24
|
+
const url = options.url || process.env.REDIS_URL || 'redis://localhost:6379';
|
|
25
|
+
const client = new ioredis_1.default(url, {
|
|
26
|
+
maxRetriesPerRequest: 3,
|
|
27
|
+
retryStrategy(times) {
|
|
28
|
+
const delay = Math.min(times * 200, 5000);
|
|
29
|
+
RedisModule_1.logger.warn(`Redis reconnecting (attempt ${times}, delay ${delay}ms)`);
|
|
30
|
+
return delay;
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
client.on('connect', () => RedisModule_1.logger.log('Redis connected'));
|
|
34
|
+
client.on('error', (err) => RedisModule_1.logger.error('Redis error', err.message));
|
|
35
|
+
return client;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
module: RedisModule_1,
|
|
40
|
+
providers: [redisProvider],
|
|
41
|
+
exports: [constants_1.REDIS_CLIENT],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
exports.RedisModule = RedisModule;
|
|
46
|
+
exports.RedisModule = RedisModule = RedisModule_1 = __decorate([
|
|
47
|
+
(0, common_1.Global)(),
|
|
48
|
+
(0, common_1.Module)({})
|
|
49
|
+
], RedisModule);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CircuitBreakerOptions {
|
|
2
|
+
halfOpenAfterMs?: number;
|
|
3
|
+
consecutiveFailures?: number;
|
|
4
|
+
maxRetries?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Creates a resilience policy combining retry + circuit breaker.
|
|
8
|
+
* Usage:
|
|
9
|
+
* const policy = createCircuitBreaker({ consecutiveFailures: 5 });
|
|
10
|
+
* const result = await policy.execute(() => httpCall());
|
|
11
|
+
*/
|
|
12
|
+
export declare function createCircuitBreaker(options?: CircuitBreakerOptions): import("cockatiel").IMergedPolicy<import("cockatiel").IRetryContext & import("cockatiel").IDefaultPolicyContext, never, [import("cockatiel").RetryPolicy, import("cockatiel").CircuitBreakerPolicy]>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCircuitBreaker = createCircuitBreaker;
|
|
4
|
+
const cockatiel_1 = require("cockatiel");
|
|
5
|
+
/**
|
|
6
|
+
* Creates a resilience policy combining retry + circuit breaker.
|
|
7
|
+
* Usage:
|
|
8
|
+
* const policy = createCircuitBreaker({ consecutiveFailures: 5 });
|
|
9
|
+
* const result = await policy.execute(() => httpCall());
|
|
10
|
+
*/
|
|
11
|
+
function createCircuitBreaker(options = {}) {
|
|
12
|
+
const { halfOpenAfterMs = 30_000, consecutiveFailures = 5, maxRetries = 2, } = options;
|
|
13
|
+
const retryPolicy = (0, cockatiel_1.retry)(cockatiel_1.handleAll, {
|
|
14
|
+
maxAttempts: maxRetries,
|
|
15
|
+
backoff: new cockatiel_1.ExponentialBackoff(),
|
|
16
|
+
});
|
|
17
|
+
const breaker = (0, cockatiel_1.circuitBreaker)(cockatiel_1.handleAll, {
|
|
18
|
+
halfOpenAfter: halfOpenAfterMs,
|
|
19
|
+
breaker: new cockatiel_1.ConsecutiveBreaker(consecutiveFailures),
|
|
20
|
+
});
|
|
21
|
+
return (0, cockatiel_1.wrap)(retryPolicy, breaker);
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare enum ErrorType {
|
|
2
|
+
NotFound = "NOT_FOUND",
|
|
3
|
+
Forbidden = "FORBIDDEN",
|
|
4
|
+
Conflict = "CONFLICT",
|
|
5
|
+
ValidationError = "VALIDATION_ERROR",
|
|
6
|
+
InternalError = "INTERNAL_ERROR",
|
|
7
|
+
Unauthorized = "UNAUTHORIZED",
|
|
8
|
+
UnprocessableEntity = "UNPROCESSABLE_ENTITY"
|
|
9
|
+
}
|
|
10
|
+
export declare class Result<T> {
|
|
11
|
+
readonly isSuccess: boolean;
|
|
12
|
+
readonly value?: T | undefined;
|
|
13
|
+
readonly errorType?: ErrorType | undefined;
|
|
14
|
+
readonly errorMessage?: string | undefined;
|
|
15
|
+
private constructor();
|
|
16
|
+
static success<T>(value: T): Result<T>;
|
|
17
|
+
static failure<T>(errorType: ErrorType, message: string): Result<T>;
|
|
18
|
+
static notFound<T>(message: string): Result<T>;
|
|
19
|
+
static forbidden<T>(message: string): Result<T>;
|
|
20
|
+
static conflict<T>(message: string): Result<T>;
|
|
21
|
+
static validationError<T>(message: string): Result<T>;
|
|
22
|
+
static unauthorized<T>(message: string): Result<T>;
|
|
23
|
+
static unprocessableEntity<T>(message: string): Result<T>;
|
|
24
|
+
unwrap(): T;
|
|
25
|
+
map<U>(fn: (value: T) => U): Result<U>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Result = exports.ErrorType = void 0;
|
|
4
|
+
var ErrorType;
|
|
5
|
+
(function (ErrorType) {
|
|
6
|
+
ErrorType["NotFound"] = "NOT_FOUND";
|
|
7
|
+
ErrorType["Forbidden"] = "FORBIDDEN";
|
|
8
|
+
ErrorType["Conflict"] = "CONFLICT";
|
|
9
|
+
ErrorType["ValidationError"] = "VALIDATION_ERROR";
|
|
10
|
+
ErrorType["InternalError"] = "INTERNAL_ERROR";
|
|
11
|
+
ErrorType["Unauthorized"] = "UNAUTHORIZED";
|
|
12
|
+
ErrorType["UnprocessableEntity"] = "UNPROCESSABLE_ENTITY";
|
|
13
|
+
})(ErrorType || (exports.ErrorType = ErrorType = {}));
|
|
14
|
+
class Result {
|
|
15
|
+
isSuccess;
|
|
16
|
+
value;
|
|
17
|
+
errorType;
|
|
18
|
+
errorMessage;
|
|
19
|
+
constructor(isSuccess, value, errorType, errorMessage) {
|
|
20
|
+
this.isSuccess = isSuccess;
|
|
21
|
+
this.value = value;
|
|
22
|
+
this.errorType = errorType;
|
|
23
|
+
this.errorMessage = errorMessage;
|
|
24
|
+
}
|
|
25
|
+
static success(value) {
|
|
26
|
+
return new Result(true, value);
|
|
27
|
+
}
|
|
28
|
+
static failure(errorType, message) {
|
|
29
|
+
return new Result(false, undefined, errorType, message);
|
|
30
|
+
}
|
|
31
|
+
static notFound(message) {
|
|
32
|
+
return Result.failure(ErrorType.NotFound, message);
|
|
33
|
+
}
|
|
34
|
+
static forbidden(message) {
|
|
35
|
+
return Result.failure(ErrorType.Forbidden, message);
|
|
36
|
+
}
|
|
37
|
+
static conflict(message) {
|
|
38
|
+
return Result.failure(ErrorType.Conflict, message);
|
|
39
|
+
}
|
|
40
|
+
static validationError(message) {
|
|
41
|
+
return Result.failure(ErrorType.ValidationError, message);
|
|
42
|
+
}
|
|
43
|
+
static unauthorized(message) {
|
|
44
|
+
return Result.failure(ErrorType.Unauthorized, message);
|
|
45
|
+
}
|
|
46
|
+
static unprocessableEntity(message) {
|
|
47
|
+
return Result.failure(ErrorType.UnprocessableEntity, message);
|
|
48
|
+
}
|
|
49
|
+
unwrap() {
|
|
50
|
+
if (!this.isSuccess || this.value === undefined) {
|
|
51
|
+
throw new Error(`Cannot unwrap failed Result: ${this.errorType} - ${this.errorMessage}`);
|
|
52
|
+
}
|
|
53
|
+
return this.value;
|
|
54
|
+
}
|
|
55
|
+
map(fn) {
|
|
56
|
+
if (this.isSuccess && this.value !== undefined) {
|
|
57
|
+
return Result.success(fn(this.value));
|
|
58
|
+
}
|
|
59
|
+
return Result.failure(this.errorType, this.errorMessage);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.Result = Result;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { type RedisModuleOptions } from './redis/redis.module';
|
|
3
|
+
import { type UnleashModuleOptions } from './unleash/unleash.module';
|
|
4
|
+
export type SharedKernelModuleOptions = QuanticModuleOptions;
|
|
5
|
+
export interface QuanticModuleOptions {
|
|
6
|
+
redis?: RedisModuleOptions;
|
|
7
|
+
unleash?: UnleashModuleOptions | false;
|
|
8
|
+
}
|
|
9
|
+
export declare class QuanticModule {
|
|
10
|
+
static forRoot(options?: QuanticModuleOptions): DynamicModule;
|
|
11
|
+
}
|
|
12
|
+
/** @deprecated Use QuanticModule instead */
|
|
13
|
+
export declare const SharedKernelModule: typeof QuanticModule;
|
|
@@ -0,0 +1,87 @@
|
|
|
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 QuanticModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.SharedKernelModule = exports.QuanticModule = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const cqrs_1 = require("@nestjs/cqrs");
|
|
13
|
+
const QuanticCommandBus_1 = require("./cqrs/pipeline/QuanticCommandBus");
|
|
14
|
+
const QuanticQueryBus_1 = require("./cqrs/pipeline/QuanticQueryBus");
|
|
15
|
+
const LogBehavior_1 = require("./cqrs/behaviors/LogBehavior");
|
|
16
|
+
const ValidationBehavior_1 = require("./cqrs/behaviors/ValidationBehavior");
|
|
17
|
+
const CacheBehavior_1 = require("./cqrs/behaviors/CacheBehavior");
|
|
18
|
+
const DistributedLockBehavior_1 = require("./cqrs/behaviors/DistributedLockBehavior");
|
|
19
|
+
const TransactionalBehavior_1 = require("./cqrs/behaviors/TransactionalBehavior");
|
|
20
|
+
const PerformanceBehavior_1 = require("./cqrs/behaviors/PerformanceBehavior");
|
|
21
|
+
const WorkflowBehavior_1 = require("./cqrs/behaviors/WorkflowBehavior");
|
|
22
|
+
const InvalidateCacheBehavior_1 = require("./cqrs/behaviors/InvalidateCacheBehavior");
|
|
23
|
+
const MetricsService_1 = require("./metrics/MetricsService");
|
|
24
|
+
const MetricsController_1 = require("./metrics/MetricsController");
|
|
25
|
+
const GracefulShutdownService_1 = require("./lifecycle/GracefulShutdownService");
|
|
26
|
+
const RedisStreamPublisher_1 = require("./events/RedisStreamPublisher");
|
|
27
|
+
const redis_module_1 = require("./redis/redis.module");
|
|
28
|
+
const unleash_module_1 = require("./unleash/unleash.module");
|
|
29
|
+
let QuanticModule = QuanticModule_1 = class QuanticModule {
|
|
30
|
+
static forRoot(options = {}) {
|
|
31
|
+
const imports = [
|
|
32
|
+
cqrs_1.CqrsModule.forRoot(),
|
|
33
|
+
redis_module_1.RedisModule.forRoot(options.redis),
|
|
34
|
+
];
|
|
35
|
+
if (options.unleash !== false) {
|
|
36
|
+
imports.push(unleash_module_1.UnleashModule.forRoot(options.unleash));
|
|
37
|
+
}
|
|
38
|
+
const exports = [
|
|
39
|
+
cqrs_1.CqrsModule,
|
|
40
|
+
redis_module_1.RedisModule,
|
|
41
|
+
RedisStreamPublisher_1.RedisStreamPublisher,
|
|
42
|
+
LogBehavior_1.LogBehavior,
|
|
43
|
+
ValidationBehavior_1.ValidationBehavior,
|
|
44
|
+
CacheBehavior_1.CacheBehavior,
|
|
45
|
+
InvalidateCacheBehavior_1.InvalidateCacheBehavior,
|
|
46
|
+
DistributedLockBehavior_1.DistributedLockBehavior,
|
|
47
|
+
TransactionalBehavior_1.TransactionalBehavior,
|
|
48
|
+
PerformanceBehavior_1.PerformanceBehavior,
|
|
49
|
+
WorkflowBehavior_1.WorkflowBehavior,
|
|
50
|
+
MetricsService_1.MetricsService,
|
|
51
|
+
GracefulShutdownService_1.GracefulShutdownService,
|
|
52
|
+
QuanticCommandBus_1.QuanticCommandBus,
|
|
53
|
+
QuanticQueryBus_1.QuanticQueryBus,
|
|
54
|
+
];
|
|
55
|
+
if (options.unleash !== false) {
|
|
56
|
+
exports.push(unleash_module_1.UnleashModule);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
module: QuanticModule_1,
|
|
60
|
+
imports,
|
|
61
|
+
controllers: [MetricsController_1.MetricsController],
|
|
62
|
+
providers: [
|
|
63
|
+
LogBehavior_1.LogBehavior,
|
|
64
|
+
ValidationBehavior_1.ValidationBehavior,
|
|
65
|
+
CacheBehavior_1.CacheBehavior,
|
|
66
|
+
InvalidateCacheBehavior_1.InvalidateCacheBehavior,
|
|
67
|
+
DistributedLockBehavior_1.DistributedLockBehavior,
|
|
68
|
+
TransactionalBehavior_1.TransactionalBehavior,
|
|
69
|
+
PerformanceBehavior_1.PerformanceBehavior,
|
|
70
|
+
WorkflowBehavior_1.WorkflowBehavior,
|
|
71
|
+
MetricsService_1.MetricsService,
|
|
72
|
+
GracefulShutdownService_1.GracefulShutdownService,
|
|
73
|
+
RedisStreamPublisher_1.RedisStreamPublisher,
|
|
74
|
+
QuanticCommandBus_1.QuanticCommandBus,
|
|
75
|
+
QuanticQueryBus_1.QuanticQueryBus,
|
|
76
|
+
],
|
|
77
|
+
exports,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
exports.QuanticModule = QuanticModule;
|
|
82
|
+
exports.QuanticModule = QuanticModule = QuanticModule_1 = __decorate([
|
|
83
|
+
(0, common_1.Global)(),
|
|
84
|
+
(0, common_1.Module)({})
|
|
85
|
+
], QuanticModule);
|
|
86
|
+
/** @deprecated Use QuanticModule instead */
|
|
87
|
+
exports.SharedKernelModule = QuanticModule;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm';
|
|
2
|
+
import { TenantBaseEntity } from '../entities/TenantBaseEntity';
|
|
3
|
+
/**
|
|
4
|
+
* TypeORM subscriber that sets PostgreSQL session variable `app.current_org_id`
|
|
5
|
+
* before write operations on tenant-scoped entities. This enables RLS policies.
|
|
6
|
+
*
|
|
7
|
+
* For SELECT queries, RLS is enforced via the session variable set by the
|
|
8
|
+
* TransactionalBehavior or manually via `SET LOCAL app.current_org_id`.
|
|
9
|
+
*
|
|
10
|
+
* Register this subscriber in each service's TypeORM DataSource config:
|
|
11
|
+
* subscribers: [TenantSubscriber]
|
|
12
|
+
*/
|
|
13
|
+
export declare class TenantSubscriber implements EntitySubscriberInterface<TenantBaseEntity> {
|
|
14
|
+
listenTo(): typeof TenantBaseEntity;
|
|
15
|
+
beforeInsert(event: InsertEvent<TenantBaseEntity>): Promise<void>;
|
|
16
|
+
beforeUpdate(event: UpdateEvent<TenantBaseEntity>): Promise<void>;
|
|
17
|
+
beforeRemove(event: RemoveEvent<TenantBaseEntity>): Promise<void>;
|
|
18
|
+
private getOrgIdFromStore;
|
|
19
|
+
private setTenantId;
|
|
20
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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.TenantSubscriber = void 0;
|
|
10
|
+
const typeorm_1 = require("typeorm");
|
|
11
|
+
const TenantBaseEntity_1 = require("../entities/TenantBaseEntity");
|
|
12
|
+
const TenantStore_1 = require("../middleware/TenantStore");
|
|
13
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14
|
+
/**
|
|
15
|
+
* TypeORM subscriber that sets PostgreSQL session variable `app.current_org_id`
|
|
16
|
+
* before write operations on tenant-scoped entities. This enables RLS policies.
|
|
17
|
+
*
|
|
18
|
+
* For SELECT queries, RLS is enforced via the session variable set by the
|
|
19
|
+
* TransactionalBehavior or manually via `SET LOCAL app.current_org_id`.
|
|
20
|
+
*
|
|
21
|
+
* Register this subscriber in each service's TypeORM DataSource config:
|
|
22
|
+
* subscribers: [TenantSubscriber]
|
|
23
|
+
*/
|
|
24
|
+
let TenantSubscriber = class TenantSubscriber {
|
|
25
|
+
listenTo() {
|
|
26
|
+
return TenantBaseEntity_1.TenantBaseEntity;
|
|
27
|
+
}
|
|
28
|
+
async beforeInsert(event) {
|
|
29
|
+
const orgId = event.entity?.organizationId ?? this.getOrgIdFromStore();
|
|
30
|
+
await this.setTenantId(event.queryRunner, orgId);
|
|
31
|
+
}
|
|
32
|
+
async beforeUpdate(event) {
|
|
33
|
+
const orgId = event.entity?.organizationId ?? this.getOrgIdFromStore();
|
|
34
|
+
await this.setTenantId(event.queryRunner, orgId);
|
|
35
|
+
}
|
|
36
|
+
async beforeRemove(event) {
|
|
37
|
+
const orgId = event.entity?.organizationId ?? this.getOrgIdFromStore();
|
|
38
|
+
await this.setTenantId(event.queryRunner, orgId);
|
|
39
|
+
}
|
|
40
|
+
getOrgIdFromStore() {
|
|
41
|
+
return TenantStore_1.tenantStore.getStore()?.organizationId ?? null;
|
|
42
|
+
}
|
|
43
|
+
async setTenantId(queryRunner, organizationId) {
|
|
44
|
+
if (organizationId && UUID_REGEX.test(organizationId)) {
|
|
45
|
+
await queryRunner.query(`SET LOCAL app.current_org_id = '${organizationId}'`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
exports.TenantSubscriber = TenantSubscriber;
|
|
50
|
+
exports.TenantSubscriber = TenantSubscriber = __decorate([
|
|
51
|
+
(0, typeorm_1.EventSubscriber)()
|
|
52
|
+
], TenantSubscriber);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TestingModuleBuilder } from '@nestjs/testing';
|
|
2
|
+
import { createMockRepository, createMockRedisClient } from './mocks';
|
|
3
|
+
export { createMockRepository, createMockRedisClient };
|
|
4
|
+
export interface TestingModuleOptions {
|
|
5
|
+
/** Providers to register (handlers, services, etc.) */
|
|
6
|
+
providers?: any[];
|
|
7
|
+
/** Entity classes to auto-mock their repositories */
|
|
8
|
+
entities?: any[];
|
|
9
|
+
/** Additional overrides to apply to the TestingModule builder */
|
|
10
|
+
overrides?: Array<{
|
|
11
|
+
provide: any;
|
|
12
|
+
useValue: any;
|
|
13
|
+
}>;
|
|
14
|
+
/** Whether to include the full CQRS pipeline behaviors (default: false) */
|
|
15
|
+
withPipeline?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Factory for bootstrapping a NestJS TestingModule preconfigured
|
|
19
|
+
* with mocked repositories, Redis, and optionally the CQRS pipeline.
|
|
20
|
+
*/
|
|
21
|
+
export declare class TestingModuleFactory {
|
|
22
|
+
static create(options?: TestingModuleOptions): TestingModuleBuilder;
|
|
23
|
+
}
|