@breadstone/archipel-platform-feature-flags 0.0.32

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 (52) hide show
  1. package/README.md +10 -0
  2. package/package.json +100 -0
  3. package/src/FeatureFlagModule.d.ts +20 -0
  4. package/src/FeatureFlagModule.js +59 -0
  5. package/src/azure/AzureFeatureFlagReader.d.ts +46 -0
  6. package/src/azure/AzureFeatureFlagReader.js +190 -0
  7. package/src/azure/AzureFeatureFlagWriter.d.ts +43 -0
  8. package/src/azure/AzureFeatureFlagWriter.js +231 -0
  9. package/src/azure/env.d.ts +11 -0
  10. package/src/azure/env.js +44 -0
  11. package/src/azure/index.d.ts +3 -0
  12. package/src/azure/index.js +14 -0
  13. package/src/contracts/FeatureFlagReaderPort.d.ts +54 -0
  14. package/src/contracts/FeatureFlagReaderPort.js +27 -0
  15. package/src/contracts/FeatureFlagWriterPort.d.ts +64 -0
  16. package/src/contracts/FeatureFlagWriterPort.js +31 -0
  17. package/src/contracts/index.d.ts +2 -0
  18. package/src/contracts/index.js +8 -0
  19. package/src/decorators/FeatureFlag.d.ts +11 -0
  20. package/src/decorators/FeatureFlag.js +18 -0
  21. package/src/decorators/index.d.ts +1 -0
  22. package/src/decorators/index.js +7 -0
  23. package/src/env.d.ts +5 -0
  24. package/src/env.js +35 -0
  25. package/src/errors/FeatureFlagError.d.ts +10 -0
  26. package/src/errors/FeatureFlagError.js +21 -0
  27. package/src/errors/index.d.ts +1 -0
  28. package/src/errors/index.js +6 -0
  29. package/src/guards/FeatureFlagGuard.d.ts +30 -0
  30. package/src/guards/FeatureFlagGuard.js +69 -0
  31. package/src/guards/index.d.ts +1 -0
  32. package/src/guards/index.js +6 -0
  33. package/src/index.d.ts +11 -0
  34. package/src/index.js +19 -0
  35. package/src/models/IFeatureFlagContext.d.ts +13 -0
  36. package/src/models/IFeatureFlagContext.js +3 -0
  37. package/src/models/IFeatureFlagDefinition.d.ts +17 -0
  38. package/src/models/IFeatureFlagDefinition.js +3 -0
  39. package/src/models/IFeatureFlagEvaluation.d.ts +13 -0
  40. package/src/models/IFeatureFlagEvaluation.js +3 -0
  41. package/src/models/IFeatureFlagModuleOptions.d.ts +30 -0
  42. package/src/models/IFeatureFlagModuleOptions.js +4 -0
  43. package/src/models/index.d.ts +4 -0
  44. package/src/models/index.js +3 -0
  45. package/src/vercel/VercelFeatureFlagReader.d.ts +54 -0
  46. package/src/vercel/VercelFeatureFlagReader.js +158 -0
  47. package/src/vercel/VercelFeatureFlagWriter.d.ts +71 -0
  48. package/src/vercel/VercelFeatureFlagWriter.js +308 -0
  49. package/src/vercel/env.d.ts +17 -0
  50. package/src/vercel/env.js +69 -0
  51. package/src/vercel/index.d.ts +3 -0
  52. package/src/vercel/index.js +17 -0
@@ -0,0 +1,30 @@
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ import { Reflector } from '@nestjs/core';
3
+ import { FeatureFlagReaderPort } from '../contracts/FeatureFlagReaderPort';
4
+ /**
5
+ * Guard that checks if a feature flag is enabled before allowing access to a route.
6
+ * Use the {@link FeatureFlag} decorator to specify which flag to check.
7
+ *
8
+ * @public
9
+ */
10
+ export declare class FeatureFlagGuard implements CanActivate {
11
+ private readonly _featureFlagReader;
12
+ private readonly _reflector;
13
+ private readonly _logger;
14
+ /**
15
+ * Constructs a new instance of the `FeatureFlagGuard` class.
16
+ *
17
+ * @public
18
+ * @param featureFlagReader - The feature flag reader port.
19
+ * @param reflector - The NestJS reflector.
20
+ */
21
+ constructor(featureFlagReader: FeatureFlagReaderPort, reflector: Reflector);
22
+ /**
23
+ * Determines whether the guarded feature flag is enabled.
24
+ *
25
+ * @public
26
+ * @param context - The execution context.
27
+ * @returns `true` when the feature flag is enabled and access is allowed.
28
+ */
29
+ canActivate(context: ExecutionContext): Promise<boolean>;
30
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ // #region Imports
3
+ var FeatureFlagGuard_1;
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.FeatureFlagGuard = void 0;
6
+ const tslib_1 = require("tslib");
7
+ const common_1 = require("@nestjs/common");
8
+ const core_1 = require("@nestjs/core");
9
+ const FeatureFlagReaderPort_1 = require("../contracts/FeatureFlagReaderPort");
10
+ const FeatureFlag_1 = require("../decorators/FeatureFlag");
11
+ // #endregion
12
+ /**
13
+ * Guard that checks if a feature flag is enabled before allowing access to a route.
14
+ * Use the {@link FeatureFlag} decorator to specify which flag to check.
15
+ *
16
+ * @public
17
+ */
18
+ let FeatureFlagGuard = FeatureFlagGuard_1 = class FeatureFlagGuard {
19
+ // #endregion
20
+ // #region Ctor
21
+ /**
22
+ * Constructs a new instance of the `FeatureFlagGuard` class.
23
+ *
24
+ * @public
25
+ * @param featureFlagReader - The feature flag reader port.
26
+ * @param reflector - The NestJS reflector.
27
+ */
28
+ constructor(featureFlagReader, reflector) {
29
+ this._logger = new common_1.Logger(FeatureFlagGuard_1.name);
30
+ this._featureFlagReader = featureFlagReader;
31
+ this._reflector = reflector;
32
+ }
33
+ // #endregion
34
+ // #region Methods
35
+ /**
36
+ * Determines whether the guarded feature flag is enabled.
37
+ *
38
+ * @public
39
+ * @param context - The execution context.
40
+ * @returns `true` when the feature flag is enabled and access is allowed.
41
+ */
42
+ async canActivate(context) {
43
+ const flagKey = this._reflector.get(FeatureFlag_1.FEATURE_FLAG_KEY_METADATA, context.getHandler());
44
+ if (!flagKey) {
45
+ return true;
46
+ }
47
+ try {
48
+ const request = context.switchToHttp().getRequest();
49
+ const user = request.user;
50
+ const isEnabled = await this._featureFlagReader.isEnabled(flagKey, {
51
+ userId: user?.id,
52
+ });
53
+ return isEnabled;
54
+ }
55
+ catch (error) {
56
+ this._logger.error(`[FeatureFlagGuard] Failed to evaluate flag "${flagKey}"`, {
57
+ flagKey,
58
+ error: error.message,
59
+ });
60
+ return false;
61
+ }
62
+ }
63
+ };
64
+ exports.FeatureFlagGuard = FeatureFlagGuard;
65
+ exports.FeatureFlagGuard = FeatureFlagGuard = FeatureFlagGuard_1 = tslib_1.__decorate([
66
+ (0, common_1.Injectable)(),
67
+ tslib_1.__metadata("design:paramtypes", [FeatureFlagReaderPort_1.FeatureFlagReaderPort, core_1.Reflector])
68
+ ], FeatureFlagGuard);
69
+ //# sourceMappingURL=FeatureFlagGuard.js.map
@@ -0,0 +1 @@
1
+ export { FeatureFlagGuard } from './FeatureFlagGuard';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeatureFlagGuard = void 0;
4
+ var FeatureFlagGuard_1 = require("./FeatureFlagGuard");
5
+ Object.defineProperty(exports, "FeatureFlagGuard", { enumerable: true, get: function () { return FeatureFlagGuard_1.FeatureFlagGuard; } });
6
+ //# sourceMappingURL=index.js.map
package/src/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export { FeatureFlagReaderPort } from './contracts/FeatureFlagReaderPort';
2
+ export { FeatureFlagWriterPort } from './contracts/FeatureFlagWriterPort';
3
+ export { FEATURE_FLAG_KEY_METADATA, FeatureFlag } from './decorators/FeatureFlag';
4
+ export { PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES } from './env';
5
+ export { FeatureFlagError } from './errors/FeatureFlagError';
6
+ export { FeatureFlagModule } from './FeatureFlagModule';
7
+ export { FeatureFlagGuard } from './guards/FeatureFlagGuard';
8
+ export type { IFeatureFlagContext } from './models/IFeatureFlagContext';
9
+ export type { IFeatureFlagDefinition } from './models/IFeatureFlagDefinition';
10
+ export type { IFeatureFlagEvaluation } from './models/IFeatureFlagEvaluation';
11
+ export type { IFeatureFlagModuleOptions } from './models/IFeatureFlagModuleOptions';
package/src/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeatureFlagGuard = exports.FeatureFlagModule = exports.FeatureFlagError = exports.PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES = exports.FeatureFlag = exports.FEATURE_FLAG_KEY_METADATA = exports.FeatureFlagWriterPort = exports.FeatureFlagReaderPort = void 0;
4
+ var FeatureFlagReaderPort_1 = require("./contracts/FeatureFlagReaderPort");
5
+ Object.defineProperty(exports, "FeatureFlagReaderPort", { enumerable: true, get: function () { return FeatureFlagReaderPort_1.FeatureFlagReaderPort; } });
6
+ var FeatureFlagWriterPort_1 = require("./contracts/FeatureFlagWriterPort");
7
+ Object.defineProperty(exports, "FeatureFlagWriterPort", { enumerable: true, get: function () { return FeatureFlagWriterPort_1.FeatureFlagWriterPort; } });
8
+ var FeatureFlag_1 = require("./decorators/FeatureFlag");
9
+ Object.defineProperty(exports, "FEATURE_FLAG_KEY_METADATA", { enumerable: true, get: function () { return FeatureFlag_1.FEATURE_FLAG_KEY_METADATA; } });
10
+ Object.defineProperty(exports, "FeatureFlag", { enumerable: true, get: function () { return FeatureFlag_1.FeatureFlag; } });
11
+ var env_1 = require("./env");
12
+ Object.defineProperty(exports, "PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES", { enumerable: true, get: function () { return env_1.PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES; } });
13
+ var FeatureFlagError_1 = require("./errors/FeatureFlagError");
14
+ Object.defineProperty(exports, "FeatureFlagError", { enumerable: true, get: function () { return FeatureFlagError_1.FeatureFlagError; } });
15
+ var FeatureFlagModule_1 = require("./FeatureFlagModule");
16
+ Object.defineProperty(exports, "FeatureFlagModule", { enumerable: true, get: function () { return FeatureFlagModule_1.FeatureFlagModule; } });
17
+ var FeatureFlagGuard_1 = require("./guards/FeatureFlagGuard");
18
+ Object.defineProperty(exports, "FeatureFlagGuard", { enumerable: true, get: function () { return FeatureFlagGuard_1.FeatureFlagGuard; } });
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Context passed to feature flag evaluation for targeting and segmentation.
3
+ *
4
+ * @public
5
+ */
6
+ export interface IFeatureFlagContext {
7
+ /** Unique identifier of the current user. */
8
+ readonly userId?: string;
9
+ /** Groups or segments the user belongs to (e.g. beta testers, enterprise). */
10
+ readonly groups?: ReadonlyArray<string>;
11
+ /** Arbitrary attributes for custom targeting rules. */
12
+ readonly attributes?: Readonly<Record<string, unknown>>;
13
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IFeatureFlagContext.js.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Represents a full feature flag definition for admin operations (create / update / read).
3
+ *
4
+ * @public
5
+ */
6
+ export interface IFeatureFlagDefinition {
7
+ /** Unique key identifying the feature flag. */
8
+ readonly key: string;
9
+ /** Whether the feature flag is currently enabled. */
10
+ readonly enabled: boolean;
11
+ /** Optional human-readable description. */
12
+ readonly description?: string;
13
+ /** Optional label / environment tag (e.g. `"production"`, `"staging"`). */
14
+ readonly label?: string;
15
+ /** Optional variant value for multivariate flags. */
16
+ readonly variant?: unknown;
17
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IFeatureFlagDefinition.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Result of evaluating a single feature flag.
3
+ *
4
+ * @public
5
+ */
6
+ export interface IFeatureFlagEvaluation {
7
+ /** The unique key identifying the feature flag. */
8
+ readonly key: string;
9
+ /** Whether the feature flag is currently enabled. */
10
+ readonly enabled: boolean;
11
+ /** Optional variant value for multivariate flags / A/B testing. */
12
+ readonly variant?: unknown;
13
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IFeatureFlagEvaluation.js.map
@@ -0,0 +1,30 @@
1
+ import type { IConfigRegistryEntry } from '@breadstone/archipel-platform-configuration';
2
+ import type { Type } from '@nestjs/common';
3
+ import type { FeatureFlagReaderPort } from '../contracts/FeatureFlagReaderPort';
4
+ import type { FeatureFlagWriterPort } from '../contracts/FeatureFlagWriterPort';
5
+ /**
6
+ * Configuration options for the {@link FeatureFlagModule}.
7
+ *
8
+ * @public
9
+ */
10
+ export interface IFeatureFlagModuleOptions {
11
+ /**
12
+ * Concrete implementation of the {@link FeatureFlagReaderPort}.
13
+ * For example, `AzureFeatureFlagReader` or `VercelFeatureFlagReader`.
14
+ */
15
+ readonly featureFlagReader: Type<FeatureFlagReaderPort>;
16
+ /**
17
+ * Optional concrete implementation of the {@link FeatureFlagWriterPort}.
18
+ * For example, `AzureFeatureFlagWriter` or `VercelFeatureFlagWriter`.
19
+ * When provided the module will also export the writer port for CRUD operations.
20
+ */
21
+ readonly featureFlagWriter?: Type<FeatureFlagWriterPort>;
22
+ /**
23
+ * Provider-specific configuration entries to register with the config module.
24
+ */
25
+ readonly configEntries?: ReadonlyArray<Omit<IConfigRegistryEntry, 'module'>>;
26
+ /**
27
+ * When `true` the module is registered globally.
28
+ */
29
+ readonly isGlobal?: boolean;
30
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // #region Imports
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=IFeatureFlagModuleOptions.js.map
@@ -0,0 +1,4 @@
1
+ export type { IFeatureFlagContext } from './IFeatureFlagContext';
2
+ export type { IFeatureFlagDefinition } from './IFeatureFlagDefinition';
3
+ export type { IFeatureFlagEvaluation } from './IFeatureFlagEvaluation';
4
+ export type { IFeatureFlagModuleOptions } from './IFeatureFlagModuleOptions';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,54 @@
1
+ import { ConfigService } from '@breadstone/archipel-platform-configuration';
2
+ import { type OnModuleInit } from '@nestjs/common';
3
+ import { FeatureFlagReaderPort } from '../contracts/FeatureFlagReaderPort';
4
+ import type { IFeatureFlagContext } from '../models/IFeatureFlagContext';
5
+ import type { IFeatureFlagEvaluation } from '../models/IFeatureFlagEvaluation';
6
+ /**
7
+ * Vercel Edge Config implementation of the {@link FeatureFlagReaderPort}.
8
+ * Uses `@vercel/edge-config` for reading feature flag state from a Vercel Edge Config store.
9
+ *
10
+ * Feature flags are expected to be stored as a single object in Edge Config
11
+ * under the configured prefix key (default: `featureFlags`). The object maps
12
+ * flag keys to their values (boolean for simple on/off, or any value for variants).
13
+ *
14
+ * @example
15
+ * Edge Config structure:
16
+ * ```json
17
+ * {
18
+ * "featureFlags": {
19
+ * "new-checkout-flow": true,
20
+ * "pricing-tier": "enterprise",
21
+ * "max-upload-size": 100
22
+ * }
23
+ * }
24
+ * ```
25
+ *
26
+ * @public
27
+ */
28
+ export declare class VercelFeatureFlagReader extends FeatureFlagReaderPort implements OnModuleInit {
29
+ private readonly _configService;
30
+ private readonly _logger;
31
+ private _edgeConfigClient;
32
+ private _flagPrefix;
33
+ constructor(configService: ConfigService);
34
+ /**
35
+ * Initializes the Vercel Edge Config client.
36
+ *
37
+ * @public
38
+ */
39
+ onModuleInit(): Promise<void>;
40
+ /** @inheritdoc */
41
+ isEnabled(key: string, _context?: IFeatureFlagContext): Promise<boolean>;
42
+ /** @inheritdoc */
43
+ getVariant<T = unknown>(key: string, defaultValue: T, _context?: IFeatureFlagContext): Promise<T>;
44
+ /** @inheritdoc */
45
+ getAllFlags(_context?: IFeatureFlagContext): Promise<ReadonlyArray<IFeatureFlagEvaluation>>;
46
+ /** @inheritdoc */
47
+ refresh(): Promise<void>;
48
+ /** @inheritdoc */
49
+ ping(): Promise<boolean>;
50
+ /**
51
+ * Ensures the Edge Config client has been initialized.
52
+ */
53
+ private ensureInitialized;
54
+ }
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ // #region Imports
3
+ var VercelFeatureFlagReader_1;
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.VercelFeatureFlagReader = void 0;
6
+ const tslib_1 = require("tslib");
7
+ const archipel_platform_configuration_1 = require("@breadstone/archipel-platform-configuration");
8
+ const common_1 = require("@nestjs/common");
9
+ const edge_config_1 = require("@vercel/edge-config");
10
+ const FeatureFlagReaderPort_1 = require("../contracts/FeatureFlagReaderPort");
11
+ const FeatureFlagError_1 = require("../errors/FeatureFlagError");
12
+ const env_1 = require("./env");
13
+ // #endregion
14
+ /** Default prefix for feature flag keys in Edge Config. */
15
+ const DEFAULT_FLAG_PREFIX = 'featureFlags';
16
+ /**
17
+ * Vercel Edge Config implementation of the {@link FeatureFlagReaderPort}.
18
+ * Uses `@vercel/edge-config` for reading feature flag state from a Vercel Edge Config store.
19
+ *
20
+ * Feature flags are expected to be stored as a single object in Edge Config
21
+ * under the configured prefix key (default: `featureFlags`). The object maps
22
+ * flag keys to their values (boolean for simple on/off, or any value for variants).
23
+ *
24
+ * @example
25
+ * Edge Config structure:
26
+ * ```json
27
+ * {
28
+ * "featureFlags": {
29
+ * "new-checkout-flow": true,
30
+ * "pricing-tier": "enterprise",
31
+ * "max-upload-size": 100
32
+ * }
33
+ * }
34
+ * ```
35
+ *
36
+ * @public
37
+ */
38
+ let VercelFeatureFlagReader = VercelFeatureFlagReader_1 = class VercelFeatureFlagReader extends FeatureFlagReaderPort_1.FeatureFlagReaderPort {
39
+ // #endregion
40
+ // #region Ctor
41
+ constructor(configService) {
42
+ super();
43
+ this._logger = new common_1.Logger(VercelFeatureFlagReader_1.name);
44
+ this._flagPrefix = DEFAULT_FLAG_PREFIX;
45
+ this._configService = configService;
46
+ }
47
+ // #endregion
48
+ // #region Methods
49
+ /**
50
+ * Initializes the Vercel Edge Config client.
51
+ *
52
+ * @public
53
+ */
54
+ async onModuleInit() {
55
+ try {
56
+ const connectionString = this._configService.get(env_1.VERCEL_EDGE_CONFIG.key);
57
+ if (!connectionString) {
58
+ throw new FeatureFlagError_1.FeatureFlagError('vercel', 'EDGE_CONFIG must be configured for the Vercel feature flag provider.');
59
+ }
60
+ this._edgeConfigClient = (0, edge_config_1.createClient)(connectionString);
61
+ this._flagPrefix = this._configService.get(env_1.VERCEL_FEATURE_FLAG_PREFIX.key) ?? DEFAULT_FLAG_PREFIX;
62
+ this._logger.log('[VercelFeatureFlagReader] Initialized successfully');
63
+ }
64
+ catch (error) {
65
+ if (error instanceof FeatureFlagError_1.FeatureFlagError) {
66
+ throw error;
67
+ }
68
+ throw new FeatureFlagError_1.FeatureFlagError('vercel', 'Failed to initialize Vercel Edge Config client', error);
69
+ }
70
+ }
71
+ /** @inheritdoc */
72
+ async isEnabled(key, _context) {
73
+ this.ensureInitialized();
74
+ try {
75
+ const flags = await this._edgeConfigClient.get(this._flagPrefix);
76
+ if (!flags || !(key in flags)) {
77
+ return false;
78
+ }
79
+ return Boolean(flags[key]);
80
+ }
81
+ catch (error) {
82
+ this._logger.error(`[VercelFeatureFlagReader] isEnabled failed for flag "${key}"`, {
83
+ key,
84
+ error: error.message,
85
+ });
86
+ throw new FeatureFlagError_1.FeatureFlagError('vercel', `Failed to evaluate feature flag "${key}"`, error);
87
+ }
88
+ }
89
+ /** @inheritdoc */
90
+ async getVariant(key, defaultValue, _context) {
91
+ this.ensureInitialized();
92
+ try {
93
+ const flags = await this._edgeConfigClient.get(this._flagPrefix);
94
+ if (!flags || !(key in flags)) {
95
+ return defaultValue;
96
+ }
97
+ return flags[key] ?? defaultValue;
98
+ }
99
+ catch (error) {
100
+ this._logger.error(`[VercelFeatureFlagReader] getVariant failed for flag "${key}"`, {
101
+ key,
102
+ error: error.message,
103
+ });
104
+ throw new FeatureFlagError_1.FeatureFlagError('vercel', `Failed to get variant for feature flag "${key}"`, error);
105
+ }
106
+ }
107
+ /** @inheritdoc */
108
+ async getAllFlags(_context) {
109
+ this.ensureInitialized();
110
+ try {
111
+ const flags = await this._edgeConfigClient.get(this._flagPrefix);
112
+ if (!flags) {
113
+ return [];
114
+ }
115
+ return Object.entries(flags).map(([key, value]) => ({
116
+ key,
117
+ enabled: Boolean(value),
118
+ variant: typeof value === 'boolean' ? undefined : value,
119
+ }));
120
+ }
121
+ catch (error) {
122
+ this._logger.error('[VercelFeatureFlagReader] getAllFlags failed', {
123
+ error: error.message,
124
+ });
125
+ throw new FeatureFlagError_1.FeatureFlagError('vercel', 'Failed to retrieve all feature flags', error);
126
+ }
127
+ }
128
+ /** @inheritdoc */
129
+ async refresh() {
130
+ // Vercel Edge Config is near-realtime and does not require explicit refresh.
131
+ // This method is a no-op but can be extended in the future if needed.
132
+ }
133
+ /** @inheritdoc */
134
+ async ping() {
135
+ try {
136
+ this.ensureInitialized();
137
+ await this._edgeConfigClient.digest();
138
+ return true;
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ /**
145
+ * Ensures the Edge Config client has been initialized.
146
+ */
147
+ ensureInitialized() {
148
+ if (!this._edgeConfigClient) {
149
+ throw new FeatureFlagError_1.FeatureFlagError('vercel', 'VercelFeatureFlagReader has not been initialized. Ensure onModuleInit() ran.');
150
+ }
151
+ }
152
+ };
153
+ exports.VercelFeatureFlagReader = VercelFeatureFlagReader;
154
+ exports.VercelFeatureFlagReader = VercelFeatureFlagReader = VercelFeatureFlagReader_1 = tslib_1.__decorate([
155
+ (0, common_1.Injectable)(),
156
+ tslib_1.__metadata("design:paramtypes", [archipel_platform_configuration_1.ConfigService])
157
+ ], VercelFeatureFlagReader);
158
+ //# sourceMappingURL=VercelFeatureFlagReader.js.map
@@ -0,0 +1,71 @@
1
+ import { ConfigService } from '@breadstone/archipel-platform-configuration';
2
+ import { type OnModuleInit } from '@nestjs/common';
3
+ import { FeatureFlagWriterPort } from '../contracts/FeatureFlagWriterPort';
4
+ import type { IFeatureFlagDefinition } from '../models/IFeatureFlagDefinition';
5
+ /**
6
+ * Vercel Edge Config implementation of the {@link FeatureFlagWriterPort}.
7
+ * Uses the Vercel REST API to manage feature flags stored in a Vercel Edge Config store.
8
+ *
9
+ * @remarks
10
+ * The Vercel admin client stores feature flags as a single object under the configured
11
+ * prefix key (default: `featureFlags`). Each flag key maps to a {@link IFeatureFlagDefinition}
12
+ * serialized as JSON.
13
+ *
14
+ * @public
15
+ */
16
+ export declare class VercelFeatureFlagWriter extends FeatureFlagWriterPort implements OnModuleInit {
17
+ private readonly _configService;
18
+ private readonly _logger;
19
+ private _apiToken;
20
+ private _edgeConfigId;
21
+ private _teamId;
22
+ private _flagPrefix;
23
+ constructor(configService: ConfigService);
24
+ /**
25
+ * Initializes the Vercel admin client by reading configuration.
26
+ *
27
+ * @public
28
+ */
29
+ onModuleInit(): Promise<void>;
30
+ /** @inheritdoc */
31
+ getFlag(key: string): Promise<IFeatureFlagDefinition | undefined>;
32
+ /** @inheritdoc */
33
+ listFlags(): Promise<ReadonlyArray<IFeatureFlagDefinition>>;
34
+ /** @inheritdoc */
35
+ createFlag(definition: IFeatureFlagDefinition): Promise<void>;
36
+ /** @inheritdoc */
37
+ updateFlag(key: string, updates: Partial<Omit<IFeatureFlagDefinition, 'key'>>): Promise<void>;
38
+ /** @inheritdoc */
39
+ deleteFlag(key: string): Promise<void>;
40
+ /** @inheritdoc */
41
+ ping(): Promise<boolean>;
42
+ /**
43
+ * Reads the current flags object from Edge Config via the Vercel REST API.
44
+ */
45
+ private readFlagsFromEdgeConfig;
46
+ /**
47
+ * Writes the flags object to Edge Config via the Vercel REST API.
48
+ */
49
+ private writeFlagsToEdgeConfig;
50
+ /**
51
+ * Builds a full Vercel API URL, appending the team ID query parameter if configured.
52
+ */
53
+ private buildUrl;
54
+ /**
55
+ * Performs an HTTP request to the Vercel REST API with timeout and authorization.
56
+ */
57
+ private request;
58
+ /**
59
+ * Converts a stored value into an {@link IFeatureFlagDefinition}.
60
+ */
61
+ private toDefinition;
62
+ /**
63
+ * Converts an {@link IFeatureFlagDefinition} into the stored value shape.
64
+ * Simple boolean flags are stored as booleans; flags with metadata are stored as objects.
65
+ */
66
+ private toStoredValue;
67
+ /**
68
+ * Ensures the admin client has been initialized.
69
+ */
70
+ private ensureInitialized;
71
+ }