@nestarc/feature-flag 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +150 -2
  2. package/dist/admin/admin-options.interface.d.ts +5 -0
  3. package/dist/admin/admin-options.interface.js +3 -0
  4. package/dist/admin/admin-options.interface.js.map +1 -0
  5. package/dist/admin/feature-flag-admin.controller.d.ts +14 -0
  6. package/dist/admin/feature-flag-admin.controller.js +100 -0
  7. package/dist/admin/feature-flag-admin.controller.js.map +1 -0
  8. package/dist/admin/feature-flag-admin.module.d.ts +5 -0
  9. package/dist/admin/feature-flag-admin.module.js +33 -0
  10. package/dist/admin/feature-flag-admin.module.js.map +1 -0
  11. package/dist/cache/memory-cache.adapter.d.ts +11 -0
  12. package/dist/{services/flag-cache.service.js → cache/memory-cache.adapter.js} +18 -31
  13. package/dist/cache/memory-cache.adapter.js.map +1 -0
  14. package/dist/cache/redis-cache.adapter.d.ts +26 -0
  15. package/dist/cache/redis-cache.adapter.js +102 -0
  16. package/dist/cache/redis-cache.adapter.js.map +1 -0
  17. package/dist/feature-flag.constants.d.ts +3 -0
  18. package/dist/feature-flag.constants.js +4 -1
  19. package/dist/feature-flag.constants.js.map +1 -1
  20. package/dist/feature-flag.module.js +49 -10
  21. package/dist/feature-flag.module.js.map +1 -1
  22. package/dist/index.d.ts +10 -2
  23. package/dist/index.js +13 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/interfaces/cache-adapter.interface.d.ts +9 -0
  26. package/dist/interfaces/cache-adapter.interface.js +3 -0
  27. package/dist/interfaces/cache-adapter.interface.js.map +1 -0
  28. package/dist/interfaces/feature-flag-options.interface.d.ts +3 -0
  29. package/dist/interfaces/feature-flag-repository.interface.d.ts +20 -0
  30. package/dist/interfaces/feature-flag-repository.interface.js +3 -0
  31. package/dist/interfaces/feature-flag-repository.interface.js.map +1 -0
  32. package/dist/interfaces/feature-flag.interface.d.ts +5 -0
  33. package/dist/interfaces/tenant-context-provider.interface.d.ts +3 -0
  34. package/dist/interfaces/tenant-context-provider.interface.js +3 -0
  35. package/dist/interfaces/tenant-context-provider.interface.js.map +1 -0
  36. package/dist/repositories/prisma-feature-flag.repository.d.ts +18 -0
  37. package/dist/repositories/prisma-feature-flag.repository.js +157 -0
  38. package/dist/repositories/prisma-feature-flag.repository.js.map +1 -0
  39. package/dist/services/default-tenant-context-provider.d.ts +7 -0
  40. package/dist/services/default-tenant-context-provider.js +35 -0
  41. package/dist/services/default-tenant-context-provider.js.map +1 -0
  42. package/dist/services/feature-flag.service.d.ts +20 -13
  43. package/dist/services/feature-flag.service.js +99 -123
  44. package/dist/services/feature-flag.service.js.map +1 -1
  45. package/dist/services/flag-context-resolver.d.ts +11 -0
  46. package/dist/services/flag-context-resolver.js +40 -0
  47. package/dist/services/flag-context-resolver.js.map +1 -0
  48. package/dist/services/flag-event-publisher.d.ts +7 -0
  49. package/dist/services/flag-event-publisher.js +37 -0
  50. package/dist/services/flag-event-publisher.js.map +1 -0
  51. package/dist/testing/test-feature-flag.module.js +26 -5
  52. package/dist/testing/test-feature-flag.module.js.map +1 -1
  53. package/package.json +15 -2
  54. package/dist/services/flag-cache.service.d.ts +0 -13
  55. package/dist/services/flag-cache.service.js.map +0 -1
package/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @nestarc/feature-flag
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@nestarc/feature-flag.svg)](https://www.npmjs.com/package/@nestarc/feature-flag)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@nestarc/feature-flag.svg)](https://www.npmjs.com/package/@nestarc/feature-flag)
5
+ [![CI](https://github.com/nestarc/nestjs-feature-flag/actions/workflows/ci.yml/badge.svg)](https://github.com/nestarc/nestjs-feature-flag/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![Docs](https://img.shields.io/badge/docs-nestarc.dev-blue.svg)](https://nestarc.dev/packages/feature-flag/)
8
+
3
9
  DB-backed feature flags for NestJS + Prisma + PostgreSQL -- tenant-aware overrides, percentage rollouts, and zero external dependencies.
4
10
 
5
11
  ## Features
@@ -10,7 +16,10 @@ DB-backed feature flags for NestJS + Prisma + PostgreSQL -- tenant-aware overrid
10
16
  - **Guard decorator** -- `@FeatureFlag()` automatically gates routes and controllers
11
17
  - **Bypass decorator** -- `@BypassFeatureFlag()` exempts health checks and public endpoints
12
18
  - **Programmatic evaluation** -- `isEnabled()` and `evaluateAll()` for service-layer logic
13
- - **Built-in caching** -- configurable TTL with manual invalidation
19
+ - **Built-in caching** -- configurable TTL with manual invalidation; Redis Pub/Sub for multi-instance
20
+ - **Pluggable persistence** -- `FeatureFlagRepository` interface for custom backends (Prisma default)
21
+ - **Pluggable tenancy** -- `TenantContextProvider` interface for custom tenant resolution
22
+ - **Admin REST API** -- opt-in `FeatureFlagAdminModule` with guard injection and proper error responses
14
23
  - **Event system** -- optional integration with `@nestjs/event-emitter` for audit and observability
15
24
  - **Testing utilities** -- drop-in `TestFeatureFlagModule` for unit and integration tests
16
25
 
@@ -31,8 +40,35 @@ npm install @nestjs/common @nestjs/core @prisma/client rxjs reflect-metadata
31
40
  ```bash
32
41
  # Required only if you enable emitEvents
33
42
  npm install @nestjs/event-emitter
43
+
44
+ # Required only if you use RedisCacheAdapter
45
+ npm install ioredis
46
+ ```
47
+
48
+ ## Redis Cache (Multi-Instance)
49
+
50
+ For production deployments with multiple instances, use `RedisCacheAdapter` for shared caching and real-time invalidation via Redis Pub/Sub:
51
+
52
+ ```typescript
53
+ import { FeatureFlagModule, RedisCacheAdapter } from '@nestarc/feature-flag';
54
+ import { Redis } from 'ioredis';
55
+
56
+ const redisClient = new Redis({ host: 'localhost', port: 6379 });
57
+
58
+ FeatureFlagModule.forRoot({
59
+ environment: 'production',
60
+ prisma,
61
+ cacheAdapter: new RedisCacheAdapter({
62
+ client: redisClient,
63
+ // subscriber is auto-created via client.duplicate()
64
+ // keyPrefix: 'feature-flag:', // default
65
+ // channel: 'feature-flag:invalidate', // default
66
+ }),
67
+ })
34
68
  ```
35
69
 
70
+ When a flag is updated on any instance, all other instances are notified via Pub/Sub and invalidate their cache immediately — eliminating the stale-cache window.
71
+
36
72
  ## Prisma Schema
37
73
 
38
74
  Add the following models to your `schema.prisma`:
@@ -438,7 +474,13 @@ describe('DashboardController', () => {
438
474
  });
439
475
  ```
440
476
 
441
- `TestFeatureFlagModule.register()` provides a global mock of `FeatureFlagService` where `isEnabled(key)` returns the boolean you specified (defaulting to `false` for unregistered keys) and `evaluateAll()` returns the full map.
477
+ `TestFeatureFlagModule.register()` provides a global mock of `FeatureFlagService`:
478
+ - `isEnabled(key)` returns the boolean you specified (defaulting to `false` for unregistered keys)
479
+ - `evaluateAll()` returns the full flag map
480
+ - `create()`, `update()`, `archive()`, `findByKey()`, `findAll()` return full `FeatureFlagWithOverrides` stub objects
481
+ - `findByKey()` throws `NotFoundException` for unknown keys
482
+
483
+ This is a **stateless boolean stub** -- write operations do not persist state across calls. For stateful test doubles, use your own mock implementation.
442
484
 
443
485
  ## Evaluation Priority
444
486
 
@@ -466,6 +508,7 @@ Percentage rollout uses murmurhash3 for deterministic bucketing: the same user a
466
508
  | `userIdExtractor` | `(req: Request) => string \| null`| `undefined`| Extracts user ID from the incoming request |
467
509
  | `defaultOnMissing` | `boolean` | `false` | Value returned when a flag key does not exist in the database |
468
510
  | `emitEvents` | `boolean` | `false` | Emit lifecycle events via `@nestjs/event-emitter` |
511
+ | `cacheAdapter` | `CacheAdapter` | `MemoryCacheAdapter` | Pluggable cache backend (e.g. `RedisCacheAdapter`) |
469
512
 
470
513
  ### FeatureFlagModuleRootOptions
471
514
 
@@ -504,6 +547,111 @@ const allFlags = await this.flags.findAll();
504
547
  this.flags.invalidateCache();
505
548
  ```
506
549
 
550
+ ## Admin REST API
551
+
552
+ `FeatureFlagAdminModule` provides a REST API for managing flags. It requires a guard — the module won't register without one:
553
+
554
+ ```typescript
555
+ import { FeatureFlagAdminModule } from '@nestarc/feature-flag';
556
+ import { AdminAuthGuard } from './guards/admin-auth.guard';
557
+
558
+ @Module({
559
+ imports: [
560
+ FeatureFlagModule.forRoot({ ... }),
561
+ FeatureFlagAdminModule.register({
562
+ guard: AdminAuthGuard,
563
+ // path: 'feature-flags', // default
564
+ }),
565
+ ],
566
+ })
567
+ export class AppModule {}
568
+ ```
569
+
570
+ ### Endpoints
571
+
572
+ | Method | Route | Description | Error Responses |
573
+ |--------|-------|-------------|-----------------|
574
+ | POST | `/feature-flags` | Create a flag | 409 duplicate key, 400 invalid percentage |
575
+ | GET | `/feature-flags` | List all flags | |
576
+ | GET | `/feature-flags/:key` | Get a single flag | 404 not found |
577
+ | PATCH | `/feature-flags/:key` | Update a flag | 404 not found, 400 invalid percentage |
578
+ | DELETE | `/feature-flags/:key` | Archive a flag | 404 not found |
579
+ | POST | `/feature-flags/:key/overrides` | Set an override | 404 flag not found |
580
+ | DELETE | `/feature-flags/:key/overrides` | Remove an override | 404 flag not found |
581
+
582
+ Percentage values must be between 0 and 100 (inclusive). Invalid values return 400 Bad Request.
583
+
584
+ ## Custom Persistence (Advanced)
585
+
586
+ The default `PrismaFeatureFlagRepository` can be replaced with any implementation of `FeatureFlagRepository`:
587
+
588
+ ```typescript
589
+ import {
590
+ FeatureFlagModule,
591
+ FEATURE_FLAG_REPOSITORY,
592
+ FeatureFlagRepository,
593
+ } from '@nestarc/feature-flag';
594
+
595
+ @Module({
596
+ imports: [
597
+ FeatureFlagModule.forRoot({
598
+ environment: 'production',
599
+ prisma, // still required for module init, but unused if you override the repository
600
+ }),
601
+ ],
602
+ providers: [
603
+ {
604
+ provide: FEATURE_FLAG_REPOSITORY,
605
+ useClass: MyCustomRepository, // implements FeatureFlagRepository
606
+ },
607
+ ],
608
+ })
609
+ export class AppModule {}
610
+ ```
611
+
612
+ ## Custom Tenant Resolution (Advanced)
613
+
614
+ Override the default `@nestarc/tenancy` integration with your own `TenantContextProvider`:
615
+
616
+ ```typescript
617
+ import {
618
+ FeatureFlagModule,
619
+ TENANT_CONTEXT_PROVIDER,
620
+ TenantContextProvider,
621
+ } from '@nestarc/feature-flag';
622
+
623
+ @Injectable()
624
+ class MyTenantProvider implements TenantContextProvider {
625
+ getCurrentTenantId(): string | null {
626
+ // your custom tenant resolution logic
627
+ return 'tenant-from-custom-source';
628
+ }
629
+ }
630
+
631
+ @Module({
632
+ imports: [FeatureFlagModule.forRoot({ ... })],
633
+ providers: [
634
+ { provide: TENANT_CONTEXT_PROVIDER, useClass: MyTenantProvider },
635
+ ],
636
+ })
637
+ export class AppModule {}
638
+ ```
639
+
640
+ ## Performance
641
+
642
+ Measured with PostgreSQL 16, Prisma 6, 500 iterations on Apple Silicon:
643
+
644
+ | Scenario | Avg | P50 | P95 | P99 |
645
+ |----------|-----|-----|-----|-----|
646
+ | **isEnabled() — cache hit** | **0.04ms** | **0.03ms** | **0.05ms** | **0.07ms** |
647
+ | isEnabled() — cache miss (DB lookup) | 1.30ms | 1.14ms | 2.54ms | 3.69ms |
648
+ | isEnabled() — override cascade (cold) | 1.07ms | 1.02ms | 1.43ms | 2.11ms |
649
+ | **evaluateAll() — 50 flags (mixed)** | **0.19ms** | **0.04ms** | **1.55ms** | **1.71ms** |
650
+
651
+ Cache speedup: **32.5x** (hit vs miss). Keep the default 30s cache TTL for optimal performance.
652
+
653
+ > Reproduce: `docker compose up -d && dotenv -e .env.test -- npx ts-node benchmarks/evaluation-overhead.ts`
654
+
507
655
  ## License
508
656
 
509
657
  MIT
@@ -0,0 +1,5 @@
1
+ import { CanActivate, Type } from '@nestjs/common';
2
+ export interface FeatureFlagAdminOptions {
3
+ guard: Type<CanActivate>;
4
+ path?: string;
5
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=admin-options.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-options.interface.js","sourceRoot":"","sources":["../../src/admin/admin-options.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import { FeatureFlagService } from '../services/feature-flag.service';
2
+ import { CreateFeatureFlagInput, UpdateFeatureFlagInput, SetOverrideInput, FeatureFlagWithOverrides } from '../interfaces/feature-flag.interface';
3
+ import { RemoveOverrideInput } from '../interfaces/feature-flag.interface';
4
+ export declare class FeatureFlagAdminController {
5
+ private readonly service;
6
+ constructor(service: FeatureFlagService);
7
+ create(input: CreateFeatureFlagInput): Promise<FeatureFlagWithOverrides>;
8
+ findAll(): Promise<FeatureFlagWithOverrides[]>;
9
+ findByKey(key: string): Promise<FeatureFlagWithOverrides>;
10
+ update(key: string, input: UpdateFeatureFlagInput): Promise<FeatureFlagWithOverrides>;
11
+ archive(key: string): Promise<FeatureFlagWithOverrides>;
12
+ setOverride(key: string, input: SetOverrideInput): Promise<void>;
13
+ removeOverride(key: string, input: RemoveOverrideInput): Promise<void>;
14
+ }
@@ -0,0 +1,100 @@
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.FeatureFlagAdminController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const feature_flag_service_1 = require("../services/feature-flag.service");
18
+ let FeatureFlagAdminController = class FeatureFlagAdminController {
19
+ constructor(service) {
20
+ this.service = service;
21
+ }
22
+ create(input) {
23
+ return this.service.create(input);
24
+ }
25
+ findAll() {
26
+ return this.service.findAll();
27
+ }
28
+ findByKey(key) {
29
+ return this.service.findByKey(key);
30
+ }
31
+ update(key, input) {
32
+ return this.service.update(key, input);
33
+ }
34
+ archive(key) {
35
+ return this.service.archive(key);
36
+ }
37
+ setOverride(key, input) {
38
+ return this.service.setOverride(key, input);
39
+ }
40
+ removeOverride(key, input) {
41
+ return this.service.removeOverride(key, input);
42
+ }
43
+ };
44
+ exports.FeatureFlagAdminController = FeatureFlagAdminController;
45
+ __decorate([
46
+ (0, common_1.Post)(),
47
+ __param(0, (0, common_1.Body)()),
48
+ __metadata("design:type", Function),
49
+ __metadata("design:paramtypes", [Object]),
50
+ __metadata("design:returntype", Promise)
51
+ ], FeatureFlagAdminController.prototype, "create", null);
52
+ __decorate([
53
+ (0, common_1.Get)(),
54
+ __metadata("design:type", Function),
55
+ __metadata("design:paramtypes", []),
56
+ __metadata("design:returntype", Promise)
57
+ ], FeatureFlagAdminController.prototype, "findAll", null);
58
+ __decorate([
59
+ (0, common_1.Get)(':key'),
60
+ __param(0, (0, common_1.Param)('key')),
61
+ __metadata("design:type", Function),
62
+ __metadata("design:paramtypes", [String]),
63
+ __metadata("design:returntype", Promise)
64
+ ], FeatureFlagAdminController.prototype, "findByKey", null);
65
+ __decorate([
66
+ (0, common_1.Patch)(':key'),
67
+ __param(0, (0, common_1.Param)('key')),
68
+ __param(1, (0, common_1.Body)()),
69
+ __metadata("design:type", Function),
70
+ __metadata("design:paramtypes", [String, Object]),
71
+ __metadata("design:returntype", Promise)
72
+ ], FeatureFlagAdminController.prototype, "update", null);
73
+ __decorate([
74
+ (0, common_1.Delete)(':key'),
75
+ __param(0, (0, common_1.Param)('key')),
76
+ __metadata("design:type", Function),
77
+ __metadata("design:paramtypes", [String]),
78
+ __metadata("design:returntype", Promise)
79
+ ], FeatureFlagAdminController.prototype, "archive", null);
80
+ __decorate([
81
+ (0, common_1.Post)(':key/overrides'),
82
+ __param(0, (0, common_1.Param)('key')),
83
+ __param(1, (0, common_1.Body)()),
84
+ __metadata("design:type", Function),
85
+ __metadata("design:paramtypes", [String, Object]),
86
+ __metadata("design:returntype", Promise)
87
+ ], FeatureFlagAdminController.prototype, "setOverride", null);
88
+ __decorate([
89
+ (0, common_1.Delete)(':key/overrides'),
90
+ __param(0, (0, common_1.Param)('key')),
91
+ __param(1, (0, common_1.Body)()),
92
+ __metadata("design:type", Function),
93
+ __metadata("design:paramtypes", [String, Object]),
94
+ __metadata("design:returntype", Promise)
95
+ ], FeatureFlagAdminController.prototype, "removeOverride", null);
96
+ exports.FeatureFlagAdminController = FeatureFlagAdminController = __decorate([
97
+ (0, common_1.Controller)(),
98
+ __metadata("design:paramtypes", [feature_flag_service_1.FeatureFlagService])
99
+ ], FeatureFlagAdminController);
100
+ //# sourceMappingURL=feature-flag-admin.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag-admin.controller.js","sourceRoot":"","sources":["../../src/admin/feature-flag-admin.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AACxB,2EAAsE;AAU/D,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,YAA6B,OAA2B;QAA3B,YAAO,GAAP,OAAO,CAAoB;IAAG,CAAC;IAG5D,MAAM,CAAS,KAA6B;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAGD,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;IAGD,SAAS,CAAe,GAAW;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;IAGD,MAAM,CACU,GAAW,EACjB,KAA6B;QAErC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAGD,OAAO,CAAe,GAAW;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAGD,WAAW,CACK,GAAW,EACjB,KAAuB;QAE/B,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAGD,cAAc,CACE,GAAW,EACjB,KAA0B;QAElC,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;CACF,CAAA;AA9CY,gEAA0B;AAIrC;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;;;wDAEb;AAGD;IADC,IAAA,YAAG,GAAE;;;;yDAGL;AAGD;IADC,IAAA,YAAG,EAAC,MAAM,CAAC;IACD,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;;;;2DAEtB;AAGD;IADC,IAAA,cAAK,EAAC,MAAM,CAAC;IAEX,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;IACZ,WAAA,IAAA,aAAI,GAAE,CAAA;;;;wDAGR;AAGD;IADC,IAAA,eAAM,EAAC,MAAM,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;;;;yDAEpB;AAGD;IADC,IAAA,aAAI,EAAC,gBAAgB,CAAC;IAEpB,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;IACZ,WAAA,IAAA,aAAI,GAAE,CAAA;;;;6DAGR;AAGD;IADC,IAAA,eAAM,EAAC,gBAAgB,CAAC;IAEtB,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;IACZ,WAAA,IAAA,aAAI,GAAE,CAAA;;;;gEAGR;qCA7CU,0BAA0B;IADtC,IAAA,mBAAU,GAAE;qCAE2B,yCAAkB;GAD7C,0BAA0B,CA8CtC"}
@@ -0,0 +1,5 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { FeatureFlagAdminOptions } from './admin-options.interface';
3
+ export declare class FeatureFlagAdminModule {
4
+ static register(options: FeatureFlagAdminOptions): DynamicModule;
5
+ }
@@ -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 FeatureFlagAdminModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.FeatureFlagAdminModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const feature_flag_admin_controller_1 = require("./feature-flag-admin.controller");
13
+ let FeatureFlagAdminModule = FeatureFlagAdminModule_1 = class FeatureFlagAdminModule {
14
+ static register(options) {
15
+ if (!options.guard) {
16
+ throw new Error('FeatureFlagAdminModule requires a guard. ' +
17
+ 'Pass your auth guard via register({ guard: MyGuard }).');
18
+ }
19
+ const path = options.path ?? 'feature-flags';
20
+ Reflect.defineMetadata('path', path, feature_flag_admin_controller_1.FeatureFlagAdminController);
21
+ Reflect.defineMetadata('__guards__', [options.guard], feature_flag_admin_controller_1.FeatureFlagAdminController);
22
+ return {
23
+ module: FeatureFlagAdminModule_1,
24
+ controllers: [feature_flag_admin_controller_1.FeatureFlagAdminController],
25
+ providers: [options.guard],
26
+ };
27
+ }
28
+ };
29
+ exports.FeatureFlagAdminModule = FeatureFlagAdminModule;
30
+ exports.FeatureFlagAdminModule = FeatureFlagAdminModule = FeatureFlagAdminModule_1 = __decorate([
31
+ (0, common_1.Module)({})
32
+ ], FeatureFlagAdminModule);
33
+ //# sourceMappingURL=feature-flag-admin.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag-admin.module.js","sourceRoot":"","sources":["../../src/admin/feature-flag-admin.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAuD;AACvD,mFAA6E;AAItE,IAAM,sBAAsB,8BAA5B,MAAM,sBAAsB;IACjC,MAAM,CAAC,QAAQ,CAAC,OAAgC;QAC9C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,2CAA2C;gBAC3C,wDAAwD,CACzD,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC;QAE7C,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,0DAA0B,CAAC,CAAC;QACjE,OAAO,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,0DAA0B,CAAC,CAAC;QAElF,OAAO;YACL,MAAM,EAAE,wBAAsB;YAC9B,WAAW,EAAE,CAAC,0DAA0B,CAAC;YACzC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;SAC3B,CAAC;IACJ,CAAC;CACF,CAAA;AApBY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,sBAAsB,CAoBlC"}
@@ -0,0 +1,11 @@
1
+ import { CacheAdapter } from '../interfaces/cache-adapter.interface';
2
+ import { FeatureFlagWithOverrides } from '../interfaces/feature-flag.interface';
3
+ export declare class MemoryCacheAdapter implements CacheAdapter {
4
+ private cache;
5
+ private allFlagsCache;
6
+ get(key: string): Promise<FeatureFlagWithOverrides | null>;
7
+ set(key: string, data: FeatureFlagWithOverrides, ttlMs: number): Promise<void>;
8
+ getAll(): Promise<FeatureFlagWithOverrides[] | null>;
9
+ setAll(data: FeatureFlagWithOverrides[], ttlMs: number): Promise<void>;
10
+ invalidate(key?: string): Promise<void>;
11
+ }
@@ -5,23 +5,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
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
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
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
8
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.FlagCacheService = void 0;
9
+ exports.MemoryCacheAdapter = void 0;
16
10
  const common_1 = require("@nestjs/common");
17
- const feature_flag_constants_1 = require("../feature-flag.constants");
18
- let FlagCacheService = class FlagCacheService {
19
- constructor(options) {
20
- this.options = options;
11
+ let MemoryCacheAdapter = class MemoryCacheAdapter {
12
+ constructor() {
21
13
  this.cache = new Map();
22
14
  this.allFlagsCache = null;
23
15
  }
24
- get(key) {
16
+ async get(key) {
25
17
  const entry = this.cache.get(key);
26
18
  if (!entry)
27
19
  return null;
@@ -31,13 +23,12 @@ let FlagCacheService = class FlagCacheService {
31
23
  }
32
24
  return entry.data;
33
25
  }
34
- set(key, data) {
35
- const ttl = this.options.cacheTtlMs ?? 30_000;
36
- if (ttl === 0)
26
+ async set(key, data, ttlMs) {
27
+ if (ttlMs === 0)
37
28
  return;
38
- this.cache.set(key, { data, expiresAt: Date.now() + ttl });
29
+ this.cache.set(key, { data, expiresAt: Date.now() + ttlMs });
39
30
  }
40
- getAll() {
31
+ async getAll() {
41
32
  if (!this.allFlagsCache)
42
33
  return null;
43
34
  if (Date.now() > this.allFlagsCache.expiresAt) {
@@ -46,27 +37,23 @@ let FlagCacheService = class FlagCacheService {
46
37
  }
47
38
  return this.allFlagsCache.data;
48
39
  }
49
- setAll(data) {
50
- const ttl = this.options.cacheTtlMs ?? 30_000;
51
- if (ttl === 0)
40
+ async setAll(data, ttlMs) {
41
+ if (ttlMs === 0)
52
42
  return;
53
- this.allFlagsCache = { data, expiresAt: Date.now() + ttl };
43
+ this.allFlagsCache = { data, expiresAt: Date.now() + ttlMs };
54
44
  }
55
- invalidate(key) {
45
+ async invalidate(key) {
56
46
  if (key) {
57
47
  this.cache.delete(key);
58
- this.allFlagsCache = null;
59
48
  }
60
49
  else {
61
50
  this.cache.clear();
62
- this.allFlagsCache = null;
63
51
  }
52
+ this.allFlagsCache = null;
64
53
  }
65
54
  };
66
- exports.FlagCacheService = FlagCacheService;
67
- exports.FlagCacheService = FlagCacheService = __decorate([
68
- (0, common_1.Injectable)(),
69
- __param(0, (0, common_1.Inject)(feature_flag_constants_1.FEATURE_FLAG_MODULE_OPTIONS)),
70
- __metadata("design:paramtypes", [Object])
71
- ], FlagCacheService);
72
- //# sourceMappingURL=flag-cache.service.js.map
55
+ exports.MemoryCacheAdapter = MemoryCacheAdapter;
56
+ exports.MemoryCacheAdapter = MemoryCacheAdapter = __decorate([
57
+ (0, common_1.Injectable)()
58
+ ], MemoryCacheAdapter);
59
+ //# sourceMappingURL=memory-cache.adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-cache.adapter.js","sourceRoot":"","sources":["../../src/cache/memory-cache.adapter.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAUrC,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAAxB;QACG,UAAK,GAAG,IAAI,GAAG,EAAgD,CAAC;QAChE,kBAAa,GAAkD,IAAI,CAAC;IAuC9E,CAAC;IArCC,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,IAA8B,EAAE,KAAa;QAClE,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO;QACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,MAAM;QACV,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO,IAAI,CAAC;QACrC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;YAC9C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAgC,EAAE,KAAa;QAC1D,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO;QACxB,IAAI,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAY;QAC3B,IAAI,GAAG,EAAE,CAAC;YACR,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;CACF,CAAA;AAzCY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,mBAAU,GAAE;GACA,kBAAkB,CAyC9B"}
@@ -0,0 +1,26 @@
1
+ import type { Redis } from 'ioredis';
2
+ import { CacheAdapter } from '../interfaces/cache-adapter.interface';
3
+ import { FeatureFlagWithOverrides } from '../interfaces/feature-flag.interface';
4
+ export interface RedisCacheAdapterOptions {
5
+ client: Redis;
6
+ subscriber?: Redis;
7
+ keyPrefix?: string;
8
+ channel?: string;
9
+ }
10
+ export declare class RedisCacheAdapter implements CacheAdapter {
11
+ private readonly client;
12
+ private readonly subscriber;
13
+ private readonly keyPrefix;
14
+ private readonly channel;
15
+ private readonly ownsSubscriber;
16
+ constructor(options: RedisCacheAdapterOptions);
17
+ private setupSubscription;
18
+ get(key: string): Promise<FeatureFlagWithOverrides | null>;
19
+ set(key: string, data: FeatureFlagWithOverrides, ttlMs: number): Promise<void>;
20
+ getAll(): Promise<FeatureFlagWithOverrides[] | null>;
21
+ setAll(data: FeatureFlagWithOverrides[], ttlMs: number): Promise<void>;
22
+ invalidate(key?: string): Promise<void>;
23
+ onModuleDestroy(): Promise<void>;
24
+ private prefixedKey;
25
+ private flushLocal;
26
+ }
@@ -0,0 +1,102 @@
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.RedisCacheAdapter = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ let RedisCacheAdapter = class RedisCacheAdapter {
15
+ constructor(options) {
16
+ this.client = options.client;
17
+ this.keyPrefix = options.keyPrefix ?? 'feature-flag:';
18
+ this.channel = options.channel ?? 'feature-flag:invalidate';
19
+ if (options.subscriber) {
20
+ this.subscriber = options.subscriber;
21
+ this.ownsSubscriber = false;
22
+ }
23
+ else {
24
+ this.subscriber = this.client.duplicate();
25
+ this.ownsSubscriber = true;
26
+ }
27
+ this.setupSubscription();
28
+ }
29
+ setupSubscription() {
30
+ this.subscriber.subscribe(this.channel);
31
+ this.subscriber.on('message', (ch, message) => {
32
+ if (ch !== this.channel)
33
+ return;
34
+ if (message === '__all__') {
35
+ this.flushLocal();
36
+ }
37
+ else {
38
+ this.client.del(this.prefixedKey(message));
39
+ this.client.del(this.prefixedKey('__all__'));
40
+ }
41
+ });
42
+ }
43
+ async get(key) {
44
+ const raw = await this.client.get(this.prefixedKey(key));
45
+ if (!raw)
46
+ return null;
47
+ return JSON.parse(raw);
48
+ }
49
+ async set(key, data, ttlMs) {
50
+ if (ttlMs === 0)
51
+ return;
52
+ await this.client.set(this.prefixedKey(key), JSON.stringify(data), 'PX', ttlMs);
53
+ }
54
+ async getAll() {
55
+ const raw = await this.client.get(this.prefixedKey('__all__'));
56
+ if (!raw)
57
+ return null;
58
+ return JSON.parse(raw);
59
+ }
60
+ async setAll(data, ttlMs) {
61
+ if (ttlMs === 0)
62
+ return;
63
+ await this.client.set(this.prefixedKey('__all__'), JSON.stringify(data), 'PX', ttlMs);
64
+ }
65
+ async invalidate(key) {
66
+ if (key) {
67
+ await this.client.del(this.prefixedKey(key));
68
+ await this.client.del(this.prefixedKey('__all__'));
69
+ await this.client.publish(this.channel, key);
70
+ }
71
+ else {
72
+ await this.flushLocal();
73
+ await this.client.publish(this.channel, '__all__');
74
+ }
75
+ }
76
+ async onModuleDestroy() {
77
+ await this.subscriber.unsubscribe(this.channel);
78
+ if (this.ownsSubscriber) {
79
+ await this.subscriber.quit();
80
+ }
81
+ }
82
+ prefixedKey(key) {
83
+ return `${this.keyPrefix}${key}`;
84
+ }
85
+ async flushLocal() {
86
+ const pattern = `${this.keyPrefix}*`;
87
+ let cursor = '0';
88
+ do {
89
+ const [nextCursor, keys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
90
+ cursor = nextCursor;
91
+ if (keys.length > 0) {
92
+ await this.client.del(...keys);
93
+ }
94
+ } while (cursor !== '0');
95
+ }
96
+ };
97
+ exports.RedisCacheAdapter = RedisCacheAdapter;
98
+ exports.RedisCacheAdapter = RedisCacheAdapter = __decorate([
99
+ (0, common_1.Injectable)(),
100
+ __metadata("design:paramtypes", [Object])
101
+ ], RedisCacheAdapter);
102
+ //# sourceMappingURL=redis-cache.adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-cache.adapter.js","sourceRoot":"","sources":["../../src/cache/redis-cache.adapter.ts"],"names":[],"mappings":"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"}
@@ -3,3 +3,6 @@ export declare const DEFAULT_CACHE_TTL_MS = 30000;
3
3
  export declare const FEATURE_FLAG_KEY = "FEATURE_FLAG_KEY";
4
4
  export declare const FEATURE_FLAG_OPTIONS_KEY = "FEATURE_FLAG_OPTIONS_KEY";
5
5
  export declare const BYPASS_FEATURE_FLAG_KEY = "BYPASS_FEATURE_FLAG_KEY";
6
+ export declare const CACHE_ADAPTER: unique symbol;
7
+ export declare const FEATURE_FLAG_REPOSITORY: unique symbol;
8
+ export declare const TENANT_CONTEXT_PROVIDER: unique symbol;
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BYPASS_FEATURE_FLAG_KEY = exports.FEATURE_FLAG_OPTIONS_KEY = exports.FEATURE_FLAG_KEY = exports.DEFAULT_CACHE_TTL_MS = exports.FEATURE_FLAG_MODULE_OPTIONS = void 0;
3
+ exports.TENANT_CONTEXT_PROVIDER = exports.FEATURE_FLAG_REPOSITORY = exports.CACHE_ADAPTER = exports.BYPASS_FEATURE_FLAG_KEY = exports.FEATURE_FLAG_OPTIONS_KEY = exports.FEATURE_FLAG_KEY = exports.DEFAULT_CACHE_TTL_MS = exports.FEATURE_FLAG_MODULE_OPTIONS = void 0;
4
4
  exports.FEATURE_FLAG_MODULE_OPTIONS = Symbol('FEATURE_FLAG_MODULE_OPTIONS');
5
5
  exports.DEFAULT_CACHE_TTL_MS = 30_000;
6
6
  exports.FEATURE_FLAG_KEY = 'FEATURE_FLAG_KEY';
7
7
  exports.FEATURE_FLAG_OPTIONS_KEY = 'FEATURE_FLAG_OPTIONS_KEY';
8
8
  exports.BYPASS_FEATURE_FLAG_KEY = 'BYPASS_FEATURE_FLAG_KEY';
9
+ exports.CACHE_ADAPTER = Symbol('CACHE_ADAPTER');
10
+ exports.FEATURE_FLAG_REPOSITORY = Symbol('FEATURE_FLAG_REPOSITORY');
11
+ exports.TENANT_CONTEXT_PROVIDER = Symbol('TENANT_CONTEXT_PROVIDER');
9
12
  //# sourceMappingURL=feature-flag.constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-flag.constants.js","sourceRoot":"","sources":["../src/feature-flag.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,2BAA2B,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;AAEpE,QAAA,oBAAoB,GAAG,MAAM,CAAC;AAE9B,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACtC,QAAA,wBAAwB,GAAG,0BAA0B,CAAC;AACtD,QAAA,uBAAuB,GAAG,yBAAyB,CAAC"}
1
+ {"version":3,"file":"feature-flag.constants.js","sourceRoot":"","sources":["../src/feature-flag.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,2BAA2B,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;AAEpE,QAAA,oBAAoB,GAAG,MAAM,CAAC;AAE9B,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACtC,QAAA,wBAAwB,GAAG,0BAA0B,CAAC;AACtD,QAAA,uBAAuB,GAAG,yBAAyB,CAAC;AAEpD,QAAA,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AACxC,QAAA,uBAAuB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAC5D,QAAA,uBAAuB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC"}