@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,87 @@
|
|
|
1
|
+
import { DynamicModule, Global, Module } from '@nestjs/common';
|
|
2
|
+
import { CqrsModule } from '@nestjs/cqrs';
|
|
3
|
+
import { QuanticCommandBus } from './cqrs/pipeline/QuanticCommandBus';
|
|
4
|
+
import { QuanticQueryBus } from './cqrs/pipeline/QuanticQueryBus';
|
|
5
|
+
import { LogBehavior } from './cqrs/behaviors/LogBehavior';
|
|
6
|
+
import { ValidationBehavior } from './cqrs/behaviors/ValidationBehavior';
|
|
7
|
+
import { CacheBehavior } from './cqrs/behaviors/CacheBehavior';
|
|
8
|
+
import { DistributedLockBehavior } from './cqrs/behaviors/DistributedLockBehavior';
|
|
9
|
+
import { TransactionalBehavior } from './cqrs/behaviors/TransactionalBehavior';
|
|
10
|
+
import { PerformanceBehavior } from './cqrs/behaviors/PerformanceBehavior';
|
|
11
|
+
import { WorkflowBehavior } from './cqrs/behaviors/WorkflowBehavior';
|
|
12
|
+
import { InvalidateCacheBehavior } from './cqrs/behaviors/InvalidateCacheBehavior';
|
|
13
|
+
import { MetricsService } from './metrics/MetricsService';
|
|
14
|
+
import { MetricsController } from './metrics/MetricsController';
|
|
15
|
+
import { GracefulShutdownService } from './lifecycle/GracefulShutdownService';
|
|
16
|
+
import { RedisStreamPublisher } from './events/RedisStreamPublisher';
|
|
17
|
+
import { RedisModule, type RedisModuleOptions } from './redis/redis.module';
|
|
18
|
+
import { UnleashModule, type UnleashModuleOptions } from './unleash/unleash.module';
|
|
19
|
+
|
|
20
|
+
export type SharedKernelModuleOptions = QuanticModuleOptions;
|
|
21
|
+
|
|
22
|
+
export interface QuanticModuleOptions {
|
|
23
|
+
redis?: RedisModuleOptions;
|
|
24
|
+
unleash?: UnleashModuleOptions | false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Global()
|
|
28
|
+
@Module({})
|
|
29
|
+
export class QuanticModule {
|
|
30
|
+
static forRoot(options: QuanticModuleOptions = {}): DynamicModule {
|
|
31
|
+
const imports: Array<DynamicModule> = [
|
|
32
|
+
CqrsModule.forRoot(),
|
|
33
|
+
RedisModule.forRoot(options.redis),
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
if (options.unleash !== false) {
|
|
37
|
+
imports.push(UnleashModule.forRoot(options.unleash));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const exports: any[] = [
|
|
41
|
+
CqrsModule,
|
|
42
|
+
RedisModule,
|
|
43
|
+
RedisStreamPublisher,
|
|
44
|
+
LogBehavior,
|
|
45
|
+
ValidationBehavior,
|
|
46
|
+
CacheBehavior,
|
|
47
|
+
InvalidateCacheBehavior,
|
|
48
|
+
DistributedLockBehavior,
|
|
49
|
+
TransactionalBehavior,
|
|
50
|
+
PerformanceBehavior,
|
|
51
|
+
WorkflowBehavior,
|
|
52
|
+
MetricsService,
|
|
53
|
+
GracefulShutdownService,
|
|
54
|
+
QuanticCommandBus,
|
|
55
|
+
QuanticQueryBus,
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
if (options.unleash !== false) {
|
|
59
|
+
exports.push(UnleashModule);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
module: QuanticModule,
|
|
64
|
+
imports,
|
|
65
|
+
controllers: [MetricsController],
|
|
66
|
+
providers: [
|
|
67
|
+
LogBehavior,
|
|
68
|
+
ValidationBehavior,
|
|
69
|
+
CacheBehavior,
|
|
70
|
+
InvalidateCacheBehavior,
|
|
71
|
+
DistributedLockBehavior,
|
|
72
|
+
TransactionalBehavior,
|
|
73
|
+
PerformanceBehavior,
|
|
74
|
+
WorkflowBehavior,
|
|
75
|
+
MetricsService,
|
|
76
|
+
GracefulShutdownService,
|
|
77
|
+
RedisStreamPublisher,
|
|
78
|
+
QuanticCommandBus,
|
|
79
|
+
QuanticQueryBus,
|
|
80
|
+
],
|
|
81
|
+
exports,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** @deprecated Use QuanticModule instead */
|
|
87
|
+
export const SharedKernelModule = QuanticModule;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm';
|
|
2
|
+
import { TenantBaseEntity } from '../entities/TenantBaseEntity';
|
|
3
|
+
import { tenantStore } from '../middleware/TenantStore';
|
|
4
|
+
|
|
5
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TypeORM subscriber that sets PostgreSQL session variable `app.current_org_id`
|
|
9
|
+
* before write operations on tenant-scoped entities. This enables RLS policies.
|
|
10
|
+
*
|
|
11
|
+
* For SELECT queries, RLS is enforced via the session variable set by the
|
|
12
|
+
* TransactionalBehavior or manually via `SET LOCAL app.current_org_id`.
|
|
13
|
+
*
|
|
14
|
+
* Register this subscriber in each service's TypeORM DataSource config:
|
|
15
|
+
* subscribers: [TenantSubscriber]
|
|
16
|
+
*/
|
|
17
|
+
@EventSubscriber()
|
|
18
|
+
export class TenantSubscriber implements EntitySubscriberInterface<TenantBaseEntity> {
|
|
19
|
+
listenTo() {
|
|
20
|
+
return TenantBaseEntity;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async beforeInsert(event: InsertEvent<TenantBaseEntity>): Promise<void> {
|
|
24
|
+
const orgId = event.entity?.organizationId ?? this.getOrgIdFromStore();
|
|
25
|
+
await this.setTenantId(event.queryRunner, orgId);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async beforeUpdate(event: UpdateEvent<TenantBaseEntity>): Promise<void> {
|
|
29
|
+
const orgId = event.entity?.organizationId ?? this.getOrgIdFromStore();
|
|
30
|
+
await this.setTenantId(event.queryRunner, orgId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async beforeRemove(event: RemoveEvent<TenantBaseEntity>): Promise<void> {
|
|
34
|
+
const orgId = event.entity?.organizationId ?? this.getOrgIdFromStore();
|
|
35
|
+
await this.setTenantId(event.queryRunner, orgId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private getOrgIdFromStore(): string | null {
|
|
39
|
+
return tenantStore.getStore()?.organizationId ?? null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private async setTenantId(queryRunner: any, organizationId?: string | null): Promise<void> {
|
|
43
|
+
if (organizationId && UUID_REGEX.test(organizationId)) {
|
|
44
|
+
await queryRunner.query(`SET LOCAL app.current_org_id = '${organizationId}'`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Test, TestingModuleBuilder } from '@nestjs/testing';
|
|
2
|
+
import { CqrsModule } from '@nestjs/cqrs';
|
|
3
|
+
import { getRepositoryToken } from '@nestjs/typeorm';
|
|
4
|
+
import { Logger } from '@nestjs/common';
|
|
5
|
+
import { QuanticCommandBus } from '../cqrs/pipeline/QuanticCommandBus';
|
|
6
|
+
import { QuanticQueryBus } from '../cqrs/pipeline/QuanticQueryBus';
|
|
7
|
+
import { LogBehavior } from '../cqrs/behaviors/LogBehavior';
|
|
8
|
+
import { ValidationBehavior } from '../cqrs/behaviors/ValidationBehavior';
|
|
9
|
+
import { CacheBehavior } from '../cqrs/behaviors/CacheBehavior';
|
|
10
|
+
import { DistributedLockBehavior } from '../cqrs/behaviors/DistributedLockBehavior';
|
|
11
|
+
import { TransactionalBehavior } from '../cqrs/behaviors/TransactionalBehavior';
|
|
12
|
+
import { PerformanceBehavior } from '../cqrs/behaviors/PerformanceBehavior';
|
|
13
|
+
import { MetricsService } from '../metrics/MetricsService';
|
|
14
|
+
import { REDIS_CLIENT } from '../cqrs/constants';
|
|
15
|
+
import { createMockRepository, createMockRedisClient } from './mocks';
|
|
16
|
+
|
|
17
|
+
export { createMockRepository, createMockRedisClient };
|
|
18
|
+
|
|
19
|
+
export interface TestingModuleOptions {
|
|
20
|
+
/** Providers to register (handlers, services, etc.) */
|
|
21
|
+
providers?: any[];
|
|
22
|
+
/** Entity classes to auto-mock their repositories */
|
|
23
|
+
entities?: any[];
|
|
24
|
+
/** Additional overrides to apply to the TestingModule builder */
|
|
25
|
+
overrides?: Array<{ provide: any; useValue: any }>;
|
|
26
|
+
/** Whether to include the full CQRS pipeline behaviors (default: false) */
|
|
27
|
+
withPipeline?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Factory for bootstrapping a NestJS TestingModule preconfigured
|
|
32
|
+
* with mocked repositories, Redis, and optionally the CQRS pipeline.
|
|
33
|
+
*/
|
|
34
|
+
export class TestingModuleFactory {
|
|
35
|
+
static create(options: TestingModuleOptions = {}): TestingModuleBuilder {
|
|
36
|
+
const { providers = [], entities = [], overrides = [], withPipeline = false } = options;
|
|
37
|
+
|
|
38
|
+
const mockRepos = entities.map((entity) => ({
|
|
39
|
+
provide: getRepositoryToken(entity),
|
|
40
|
+
useValue: createMockRepository(),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
const mockRedis = { provide: REDIS_CLIENT, useValue: createMockRedisClient() };
|
|
44
|
+
|
|
45
|
+
const pipelineProviders = withPipeline
|
|
46
|
+
? [
|
|
47
|
+
LogBehavior,
|
|
48
|
+
ValidationBehavior,
|
|
49
|
+
CacheBehavior,
|
|
50
|
+
DistributedLockBehavior,
|
|
51
|
+
TransactionalBehavior,
|
|
52
|
+
PerformanceBehavior,
|
|
53
|
+
MetricsService,
|
|
54
|
+
QuanticCommandBus,
|
|
55
|
+
QuanticQueryBus,
|
|
56
|
+
]
|
|
57
|
+
: [];
|
|
58
|
+
|
|
59
|
+
let builder = Test.createTestingModule({
|
|
60
|
+
imports: [CqrsModule.forRoot()],
|
|
61
|
+
providers: [
|
|
62
|
+
...mockRepos,
|
|
63
|
+
mockRedis,
|
|
64
|
+
...pipelineProviders,
|
|
65
|
+
...providers,
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
for (const override of overrides) {
|
|
70
|
+
builder = builder.overrideProvider(override.provide).useValue(override.useValue);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Silence NestJS logs during tests
|
|
74
|
+
Logger.overrideLogger(['error']);
|
|
75
|
+
|
|
76
|
+
return builder;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a mock repository with common TypeORM repository methods stubbed.
|
|
3
|
+
*/
|
|
4
|
+
export function createMockRepository<T = any>() {
|
|
5
|
+
return {
|
|
6
|
+
find: jest.fn(),
|
|
7
|
+
findOne: jest.fn(),
|
|
8
|
+
findOneBy: jest.fn(),
|
|
9
|
+
findAndCount: jest.fn(),
|
|
10
|
+
save: jest.fn().mockImplementation((entity: T) => Promise.resolve(entity)),
|
|
11
|
+
create: jest.fn().mockImplementation((dto: any) => dto),
|
|
12
|
+
update: jest.fn(),
|
|
13
|
+
delete: jest.fn(),
|
|
14
|
+
remove: jest.fn(),
|
|
15
|
+
count: jest.fn(),
|
|
16
|
+
createQueryBuilder: jest.fn(() => ({
|
|
17
|
+
where: jest.fn().mockReturnThis(),
|
|
18
|
+
andWhere: jest.fn().mockReturnThis(),
|
|
19
|
+
orderBy: jest.fn().mockReturnThis(),
|
|
20
|
+
addOrderBy: jest.fn().mockReturnThis(),
|
|
21
|
+
take: jest.fn().mockReturnThis(),
|
|
22
|
+
skip: jest.fn().mockReturnThis(),
|
|
23
|
+
leftJoinAndSelect: jest.fn().mockReturnThis(),
|
|
24
|
+
getMany: jest.fn().mockResolvedValue([]),
|
|
25
|
+
getOne: jest.fn().mockResolvedValue(null),
|
|
26
|
+
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
|
|
27
|
+
})),
|
|
28
|
+
manager: {
|
|
29
|
+
transaction: jest.fn().mockImplementation((cb: any) => cb({
|
|
30
|
+
save: jest.fn().mockImplementation((entity: any) => Promise.resolve(entity)),
|
|
31
|
+
findOne: jest.fn(),
|
|
32
|
+
})),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a mock Redis client with common ioredis methods stubbed.
|
|
39
|
+
*/
|
|
40
|
+
export function createMockRedisClient() {
|
|
41
|
+
const client: Record<string, jest.Mock> = {
|
|
42
|
+
get: jest.fn().mockResolvedValue(null),
|
|
43
|
+
set: jest.fn().mockResolvedValue('OK'),
|
|
44
|
+
del: jest.fn().mockResolvedValue(1),
|
|
45
|
+
setex: jest.fn().mockResolvedValue('OK'),
|
|
46
|
+
exists: jest.fn().mockResolvedValue(0),
|
|
47
|
+
xadd: jest.fn().mockResolvedValue('1-0'),
|
|
48
|
+
xreadgroup: jest.fn().mockResolvedValue(null),
|
|
49
|
+
xack: jest.fn().mockResolvedValue(1),
|
|
50
|
+
xgroup: jest.fn().mockResolvedValue('OK'),
|
|
51
|
+
quit: jest.fn().mockResolvedValue('OK'),
|
|
52
|
+
disconnect: jest.fn(),
|
|
53
|
+
on: jest.fn().mockReturnThis(),
|
|
54
|
+
duplicate: jest.fn(),
|
|
55
|
+
};
|
|
56
|
+
// duplicate() returns a fresh mock with the same shape
|
|
57
|
+
client.duplicate.mockImplementation(() => createMockRedisClient());
|
|
58
|
+
return client;
|
|
59
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Module, Global, DynamicModule, Logger } from '@nestjs/common';
|
|
2
|
+
import { initialize, Unleash } from 'unleash-client';
|
|
3
|
+
import { FeatureFlagBehavior } from '../cqrs/behaviors/FeatureFlagBehavior';
|
|
4
|
+
|
|
5
|
+
export interface UnleashModuleOptions {
|
|
6
|
+
url?: string;
|
|
7
|
+
appName?: string;
|
|
8
|
+
customHeaders?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@Global()
|
|
12
|
+
@Module({})
|
|
13
|
+
export class UnleashModule {
|
|
14
|
+
static forRoot(options?: UnleashModuleOptions): DynamicModule {
|
|
15
|
+
const unleashProvider = {
|
|
16
|
+
provide: Unleash,
|
|
17
|
+
useFactory: () => {
|
|
18
|
+
const logger = new Logger('UnleashModule');
|
|
19
|
+
const url = options?.url || process.env['UNLEASH_URL'] || 'http://localhost:4242/api';
|
|
20
|
+
const appName = options?.appName || process.env['UNLEASH_APP_NAME'] || 'arex';
|
|
21
|
+
const token =
|
|
22
|
+
options?.customHeaders?.['Authorization'] ||
|
|
23
|
+
process.env['UNLEASH_API_TOKEN'] ||
|
|
24
|
+
'*:*.unleash-insecure-api-token';
|
|
25
|
+
|
|
26
|
+
logger.log(`Connecting to Unleash at ${url}`);
|
|
27
|
+
|
|
28
|
+
return initialize({
|
|
29
|
+
url,
|
|
30
|
+
appName,
|
|
31
|
+
customHeaders: {
|
|
32
|
+
Authorization: token,
|
|
33
|
+
},
|
|
34
|
+
refreshInterval: 10000,
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
module: UnleashModule,
|
|
41
|
+
providers: [unleashProvider, FeatureFlagBehavior],
|
|
42
|
+
exports: [Unleash, FeatureFlagBehavior],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": false,
|
|
14
|
+
"sourceMap": false,
|
|
15
|
+
"moduleResolution": "node",
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"emitDecoratorMetadata": true,
|
|
18
|
+
"experimentalDecorators": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*"],
|
|
21
|
+
"exclude": ["node_modules", "dist", "**/*.spec.ts"]
|
|
22
|
+
}
|