@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,231 @@
1
+ "use strict";
2
+ // #region Imports
3
+ var AzureFeatureFlagWriter_1;
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.AzureFeatureFlagWriter = void 0;
6
+ const tslib_1 = require("tslib");
7
+ const app_configuration_1 = require("@azure/app-configuration");
8
+ const identity_1 = require("@azure/identity");
9
+ const archipel_platform_configuration_1 = require("@breadstone/archipel-platform-configuration");
10
+ const common_1 = require("@nestjs/common");
11
+ const FeatureFlagWriterPort_1 = require("../contracts/FeatureFlagWriterPort");
12
+ const FeatureFlagError_1 = require("../errors/FeatureFlagError");
13
+ const env_1 = require("./env");
14
+ // #endregion
15
+ /**
16
+ * Azure App Configuration implementation of the {@link FeatureFlagWriterPort}.
17
+ * Uses `@azure/app-configuration` (`AppConfigurationClient`) for CRUD operations
18
+ * on feature flags stored in Azure App Configuration.
19
+ *
20
+ * @public
21
+ */
22
+ let AzureFeatureFlagWriter = AzureFeatureFlagWriter_1 = class AzureFeatureFlagWriter extends FeatureFlagWriterPort_1.FeatureFlagWriterPort {
23
+ // #endregion
24
+ // #region Ctor
25
+ constructor(configService) {
26
+ super();
27
+ this._logger = new common_1.Logger(AzureFeatureFlagWriter_1.name);
28
+ this._configService = configService;
29
+ }
30
+ // #endregion
31
+ // #region Methods
32
+ /**
33
+ * Initializes the Azure App Configuration management client.
34
+ *
35
+ * @public
36
+ */
37
+ async onModuleInit() {
38
+ try {
39
+ const endpoint = this._configService.get(env_1.AZURE_APPCONFIG_ENDPOINT.key);
40
+ const connectionString = this._configService.get(env_1.AZURE_APPCONFIG_CONNECTION_STRING.key);
41
+ if (!endpoint && !connectionString) {
42
+ throw new FeatureFlagError_1.FeatureFlagError('azure', 'Either AZURE_APPCONFIG_ENDPOINT or AZURE_APPCONFIG_CONNECTION_STRING must be configured.');
43
+ }
44
+ if (endpoint) {
45
+ this._client = new app_configuration_1.AppConfigurationClient(endpoint, new identity_1.DefaultAzureCredential());
46
+ }
47
+ else {
48
+ this._client = new app_configuration_1.AppConfigurationClient(connectionString);
49
+ }
50
+ this._logger.log('[AzureFeatureFlagWriter] Initialized successfully');
51
+ }
52
+ catch (error) {
53
+ if (error instanceof FeatureFlagError_1.FeatureFlagError) {
54
+ throw error;
55
+ }
56
+ throw new FeatureFlagError_1.FeatureFlagError('azure', 'Failed to initialize Azure App Configuration admin client', error);
57
+ }
58
+ }
59
+ /** @inheritdoc */
60
+ async getFlag(key) {
61
+ this.ensureInitialized();
62
+ try {
63
+ const setting = await this._client.getConfigurationSetting({
64
+ key: `${app_configuration_1.featureFlagPrefix}${key}`,
65
+ });
66
+ if (!(0, app_configuration_1.isFeatureFlag)(setting)) {
67
+ return undefined;
68
+ }
69
+ const parsed = (0, app_configuration_1.parseFeatureFlag)(setting);
70
+ return {
71
+ key,
72
+ enabled: parsed.value.enabled,
73
+ description: parsed.value.description,
74
+ label: parsed.label,
75
+ };
76
+ }
77
+ catch (error) {
78
+ if (this.isNotFoundError(error)) {
79
+ return undefined;
80
+ }
81
+ this._logger.error(`[AzureFeatureFlagWriter] getFlag failed for "${key}"`, {
82
+ key,
83
+ error: error.message,
84
+ });
85
+ throw new FeatureFlagError_1.FeatureFlagError('azure', `Failed to get feature flag "${key}"`, error);
86
+ }
87
+ }
88
+ /** @inheritdoc */
89
+ async listFlags() {
90
+ this.ensureInitialized();
91
+ try {
92
+ const flags = [];
93
+ const settings = this._client.listConfigurationSettings({
94
+ keyFilter: `${app_configuration_1.featureFlagPrefix}*`,
95
+ });
96
+ for await (const setting of settings) {
97
+ if (!(0, app_configuration_1.isFeatureFlag)(setting)) {
98
+ continue;
99
+ }
100
+ const parsed = (0, app_configuration_1.parseFeatureFlag)(setting);
101
+ const key = setting.key.replace(app_configuration_1.featureFlagPrefix, '');
102
+ flags.push({
103
+ key,
104
+ enabled: parsed.value.enabled,
105
+ description: parsed.value.description,
106
+ label: parsed.label,
107
+ });
108
+ }
109
+ return flags;
110
+ }
111
+ catch (error) {
112
+ this._logger.error('[AzureFeatureFlagWriter] listFlags failed', {
113
+ error: error.message,
114
+ });
115
+ throw new FeatureFlagError_1.FeatureFlagError('azure', 'Failed to list feature flags', error);
116
+ }
117
+ }
118
+ /** @inheritdoc */
119
+ async createFlag(definition) {
120
+ this.ensureInitialized();
121
+ try {
122
+ await this._client.addConfigurationSetting({
123
+ key: `${app_configuration_1.featureFlagPrefix}${definition.key}`,
124
+ contentType: app_configuration_1.featureFlagContentType,
125
+ label: definition.label,
126
+ value: JSON.stringify({
127
+ id: definition.key,
128
+ enabled: definition.enabled,
129
+ description: definition.description ?? '',
130
+ conditions: { client_filters: [] },
131
+ }),
132
+ });
133
+ this._logger.log(`[AzureFeatureFlagWriter] Created flag "${definition.key}"`);
134
+ }
135
+ catch (error) {
136
+ this._logger.error(`[AzureFeatureFlagWriter] createFlag failed for "${definition.key}"`, {
137
+ key: definition.key,
138
+ error: error.message,
139
+ });
140
+ throw new FeatureFlagError_1.FeatureFlagError('azure', `Failed to create feature flag "${definition.key}"`, error);
141
+ }
142
+ }
143
+ /** @inheritdoc */
144
+ async updateFlag(key, updates) {
145
+ this.ensureInitialized();
146
+ try {
147
+ const settingKey = `${app_configuration_1.featureFlagPrefix}${key}`;
148
+ const existing = await this._client.getConfigurationSetting({ key: settingKey });
149
+ if (!(0, app_configuration_1.isFeatureFlag)(existing)) {
150
+ throw new FeatureFlagError_1.FeatureFlagError('azure', `Configuration setting "${key}" is not a feature flag.`);
151
+ }
152
+ const parsed = (0, app_configuration_1.parseFeatureFlag)(existing);
153
+ const updatedValue = {
154
+ id: key,
155
+ enabled: updates.enabled ?? parsed.value.enabled,
156
+ description: updates.description ?? parsed.value.description ?? '',
157
+ conditions: parsed.value.conditions ?? { client_filters: [] },
158
+ };
159
+ await this._client.setConfigurationSetting({
160
+ key: settingKey,
161
+ contentType: app_configuration_1.featureFlagContentType,
162
+ label: updates.label ?? existing.label,
163
+ value: JSON.stringify(updatedValue),
164
+ });
165
+ this._logger.log(`[AzureFeatureFlagWriter] Updated flag "${key}"`);
166
+ }
167
+ catch (error) {
168
+ if (error instanceof FeatureFlagError_1.FeatureFlagError) {
169
+ throw error;
170
+ }
171
+ this._logger.error(`[AzureFeatureFlagWriter] updateFlag failed for "${key}"`, {
172
+ key,
173
+ error: error.message,
174
+ });
175
+ throw new FeatureFlagError_1.FeatureFlagError('azure', `Failed to update feature flag "${key}"`, error);
176
+ }
177
+ }
178
+ /** @inheritdoc */
179
+ async deleteFlag(key) {
180
+ this.ensureInitialized();
181
+ try {
182
+ await this._client.deleteConfigurationSetting({
183
+ key: `${app_configuration_1.featureFlagPrefix}${key}`,
184
+ });
185
+ this._logger.log(`[AzureFeatureFlagWriter] Deleted flag "${key}"`);
186
+ }
187
+ catch (error) {
188
+ this._logger.error(`[AzureFeatureFlagWriter] deleteFlag failed for "${key}"`, {
189
+ key,
190
+ error: error.message,
191
+ });
192
+ throw new FeatureFlagError_1.FeatureFlagError('azure', `Failed to delete feature flag "${key}"`, error);
193
+ }
194
+ }
195
+ /** @inheritdoc */
196
+ async ping() {
197
+ try {
198
+ this.ensureInitialized();
199
+ const iterator = this._client.listConfigurationSettings({ keyFilter: `${app_configuration_1.featureFlagPrefix}*` });
200
+ // Perform a minimal read to verify connectivity.
201
+ await iterator.next();
202
+ return true;
203
+ }
204
+ catch {
205
+ return false;
206
+ }
207
+ }
208
+ /**
209
+ * Checks whether the error is a 404 (resource not found).
210
+ */
211
+ isNotFoundError(error) {
212
+ return (typeof error === 'object' &&
213
+ error !== null &&
214
+ 'statusCode' in error &&
215
+ error.statusCode === 404);
216
+ }
217
+ /**
218
+ * Ensures the management client has been initialized.
219
+ */
220
+ ensureInitialized() {
221
+ if (!this._client) {
222
+ throw new FeatureFlagError_1.FeatureFlagError('azure', 'AzureFeatureFlagWriter has not been initialized. Ensure onModuleInit() ran.');
223
+ }
224
+ }
225
+ };
226
+ exports.AzureFeatureFlagWriter = AzureFeatureFlagWriter;
227
+ exports.AzureFeatureFlagWriter = AzureFeatureFlagWriter = AzureFeatureFlagWriter_1 = tslib_1.__decorate([
228
+ (0, common_1.Injectable)(),
229
+ tslib_1.__metadata("design:paramtypes", [archipel_platform_configuration_1.ConfigService])
230
+ ], AzureFeatureFlagWriter);
231
+ //# sourceMappingURL=AzureFeatureFlagWriter.js.map
@@ -0,0 +1,11 @@
1
+ import { type IConfigRegistryEntry } from '@breadstone/archipel-platform-configuration';
2
+ /** Azure App Configuration endpoint URL. Required when using Entra ID authentication. */
3
+ export declare const AZURE_APPCONFIG_ENDPOINT: import("@breadstone/archipel-platform-configuration").IConfigKey<string>;
4
+ /** Azure App Configuration connection string. Alternative to endpoint + Entra ID. */
5
+ export declare const AZURE_APPCONFIG_CONNECTION_STRING: import("@breadstone/archipel-platform-configuration").IConfigKey<string>;
6
+ /** Refresh interval in milliseconds for feature flag state. Defaults to 30000. */
7
+ export declare const AZURE_FEATURE_FLAG_REFRESH_INTERVAL: import("@breadstone/archipel-platform-configuration").IConfigKey<number>;
8
+ /** Key filter for selecting feature flags. Defaults to `*` (all). */
9
+ export declare const AZURE_FEATURE_FLAG_KEY_FILTER: import("@breadstone/archipel-platform-configuration").IConfigKey<string>;
10
+ /** Configuration entries required by the Azure feature flag provider. */
11
+ export declare const AZURE_FEATURE_FLAG_CONFIG_ENTRIES: ReadonlyArray<Omit<IConfigRegistryEntry, 'module'>>;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ // #region Imports
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.AZURE_FEATURE_FLAG_CONFIG_ENTRIES = exports.AZURE_FEATURE_FLAG_KEY_FILTER = exports.AZURE_FEATURE_FLAG_REFRESH_INTERVAL = exports.AZURE_APPCONFIG_CONNECTION_STRING = exports.AZURE_APPCONFIG_ENDPOINT = void 0;
5
+ const archipel_platform_configuration_1 = require("@breadstone/archipel-platform-configuration");
6
+ // #endregion
7
+ // ──────────────────────────────────────────────────────────────
8
+ // Azure App Configuration
9
+ // ──────────────────────────────────────────────────────────────
10
+ /** Azure App Configuration endpoint URL. Required when using Entra ID authentication. */
11
+ exports.AZURE_APPCONFIG_ENDPOINT = (0, archipel_platform_configuration_1.createConfigKey)('AZURE_APPCONFIG_ENDPOINT');
12
+ /** Azure App Configuration connection string. Alternative to endpoint + Entra ID. */
13
+ exports.AZURE_APPCONFIG_CONNECTION_STRING = (0, archipel_platform_configuration_1.createConfigKey)('AZURE_APPCONFIG_CONNECTION_STRING');
14
+ /** Refresh interval in milliseconds for feature flag state. Defaults to 30000. */
15
+ exports.AZURE_FEATURE_FLAG_REFRESH_INTERVAL = (0, archipel_platform_configuration_1.createConfigKey)('AZURE_FEATURE_FLAG_REFRESH_INTERVAL');
16
+ /** Key filter for selecting feature flags. Defaults to `*` (all). */
17
+ exports.AZURE_FEATURE_FLAG_KEY_FILTER = (0, archipel_platform_configuration_1.createConfigKey)('AZURE_FEATURE_FLAG_KEY_FILTER');
18
+ // ──────────────────────────────────────────────────────────────
19
+ // Registry entries
20
+ // ──────────────────────────────────────────────────────────────
21
+ /** Configuration entries required by the Azure feature flag provider. */
22
+ exports.AZURE_FEATURE_FLAG_CONFIG_ENTRIES = [
23
+ {
24
+ key: exports.AZURE_APPCONFIG_ENDPOINT,
25
+ required: false,
26
+ description: 'Azure App Configuration endpoint URL. Required when using Entra ID authentication.',
27
+ },
28
+ {
29
+ key: exports.AZURE_APPCONFIG_CONNECTION_STRING,
30
+ required: false,
31
+ description: 'Azure App Configuration connection string. Alternative to endpoint + Entra ID.',
32
+ },
33
+ {
34
+ key: exports.AZURE_FEATURE_FLAG_REFRESH_INTERVAL,
35
+ required: false,
36
+ description: 'Refresh interval in milliseconds for feature flag state. Defaults to 30000.',
37
+ },
38
+ {
39
+ key: exports.AZURE_FEATURE_FLAG_KEY_FILTER,
40
+ required: false,
41
+ description: 'Key filter for selecting feature flags. Defaults to * (all).',
42
+ },
43
+ ];
44
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1,3 @@
1
+ export { AzureFeatureFlagReader } from './AzureFeatureFlagReader';
2
+ export { AzureFeatureFlagWriter } from './AzureFeatureFlagWriter';
3
+ export { AZURE_APPCONFIG_CONNECTION_STRING, AZURE_APPCONFIG_ENDPOINT, AZURE_FEATURE_FLAG_CONFIG_ENTRIES, AZURE_FEATURE_FLAG_KEY_FILTER, AZURE_FEATURE_FLAG_REFRESH_INTERVAL, } from './env';
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AZURE_FEATURE_FLAG_REFRESH_INTERVAL = exports.AZURE_FEATURE_FLAG_KEY_FILTER = exports.AZURE_FEATURE_FLAG_CONFIG_ENTRIES = exports.AZURE_APPCONFIG_ENDPOINT = exports.AZURE_APPCONFIG_CONNECTION_STRING = exports.AzureFeatureFlagWriter = exports.AzureFeatureFlagReader = void 0;
4
+ var AzureFeatureFlagReader_1 = require("./AzureFeatureFlagReader");
5
+ Object.defineProperty(exports, "AzureFeatureFlagReader", { enumerable: true, get: function () { return AzureFeatureFlagReader_1.AzureFeatureFlagReader; } });
6
+ var AzureFeatureFlagWriter_1 = require("./AzureFeatureFlagWriter");
7
+ Object.defineProperty(exports, "AzureFeatureFlagWriter", { enumerable: true, get: function () { return AzureFeatureFlagWriter_1.AzureFeatureFlagWriter; } });
8
+ var env_1 = require("./env");
9
+ Object.defineProperty(exports, "AZURE_APPCONFIG_CONNECTION_STRING", { enumerable: true, get: function () { return env_1.AZURE_APPCONFIG_CONNECTION_STRING; } });
10
+ Object.defineProperty(exports, "AZURE_APPCONFIG_ENDPOINT", { enumerable: true, get: function () { return env_1.AZURE_APPCONFIG_ENDPOINT; } });
11
+ Object.defineProperty(exports, "AZURE_FEATURE_FLAG_CONFIG_ENTRIES", { enumerable: true, get: function () { return env_1.AZURE_FEATURE_FLAG_CONFIG_ENTRIES; } });
12
+ Object.defineProperty(exports, "AZURE_FEATURE_FLAG_KEY_FILTER", { enumerable: true, get: function () { return env_1.AZURE_FEATURE_FLAG_KEY_FILTER; } });
13
+ Object.defineProperty(exports, "AZURE_FEATURE_FLAG_REFRESH_INTERVAL", { enumerable: true, get: function () { return env_1.AZURE_FEATURE_FLAG_REFRESH_INTERVAL; } });
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,54 @@
1
+ import type { IFeatureFlagContext } from '../models/IFeatureFlagContext';
2
+ import type { IFeatureFlagEvaluation } from '../models/IFeatureFlagEvaluation';
3
+ /**
4
+ * Abstract port for feature flag reader operations.
5
+ * Each provider (Azure App Configuration, Vercel Edge Config) must implement this contract
6
+ * so that the consuming application can switch providers without changing business logic.
7
+ *
8
+ * @public
9
+ */
10
+ export declare abstract class FeatureFlagReaderPort {
11
+ /**
12
+ * Evaluates whether a feature flag is enabled.
13
+ *
14
+ * @public
15
+ * @param key - The unique key identifying the feature flag.
16
+ * @param context - Optional evaluation context for targeting and segmentation.
17
+ * @returns `true` if the feature flag is enabled.
18
+ */
19
+ abstract isEnabled(key: string, context?: IFeatureFlagContext): Promise<boolean>;
20
+ /**
21
+ * Returns the variant value of a feature flag for multivariate flags and A/B testing.
22
+ *
23
+ * @public
24
+ * @param key - The unique key identifying the feature flag.
25
+ * @param defaultValue - The default value to return if the flag is not found.
26
+ * @param context - Optional evaluation context for targeting and segmentation.
27
+ * @returns The variant value of the feature flag.
28
+ */
29
+ abstract getVariant<T = unknown>(key: string, defaultValue: T, context?: IFeatureFlagContext): Promise<T>;
30
+ /**
31
+ * Returns all known feature flags with their current evaluation.
32
+ *
33
+ * @public
34
+ * @param context - Optional evaluation context for targeting and segmentation.
35
+ * @returns Array of evaluated feature flags.
36
+ */
37
+ abstract getAllFlags(context?: IFeatureFlagContext): Promise<ReadonlyArray<IFeatureFlagEvaluation>>;
38
+ /**
39
+ * Refreshes the flag state from the remote provider.
40
+ * Implementations should reload configuration from the upstream source.
41
+ *
42
+ * @public
43
+ */
44
+ abstract refresh(): Promise<void>;
45
+ /**
46
+ * Lightweight connectivity check for the feature flag provider.
47
+ * Override in adapters to perform a real API call.
48
+ * Defaults to `true` if not overridden.
49
+ *
50
+ * @public
51
+ * @returns `true` if the provider is reachable.
52
+ */
53
+ ping(): Promise<boolean>;
54
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ // #region Imports
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.FeatureFlagReaderPort = void 0;
5
+ // #endregion
6
+ /**
7
+ * Abstract port for feature flag reader operations.
8
+ * Each provider (Azure App Configuration, Vercel Edge Config) must implement this contract
9
+ * so that the consuming application can switch providers without changing business logic.
10
+ *
11
+ * @public
12
+ */
13
+ class FeatureFlagReaderPort {
14
+ /**
15
+ * Lightweight connectivity check for the feature flag provider.
16
+ * Override in adapters to perform a real API call.
17
+ * Defaults to `true` if not overridden.
18
+ *
19
+ * @public
20
+ * @returns `true` if the provider is reachable.
21
+ */
22
+ async ping() {
23
+ return true;
24
+ }
25
+ }
26
+ exports.FeatureFlagReaderPort = FeatureFlagReaderPort;
27
+ //# sourceMappingURL=FeatureFlagReaderPort.js.map
@@ -0,0 +1,64 @@
1
+ import type { IFeatureFlagDefinition } from '../models/IFeatureFlagDefinition';
2
+ /**
3
+ * Abstract port for feature flag writer operations (CRUD).
4
+ * Each provider (Azure App Configuration, Vercel Edge Config) must implement this contract
5
+ * so that the admin UI backend can manage flags without being coupled to a specific provider.
6
+ *
7
+ * @remarks
8
+ * This port is intentionally separated from {@link FeatureFlagReaderPort} because
9
+ * the read path (consumed by application code) and the write path (consumed by admin tooling)
10
+ * have different deployment contexts, security requirements, and SDK dependencies.
11
+ *
12
+ * @public
13
+ */
14
+ export declare abstract class FeatureFlagWriterPort {
15
+ /**
16
+ * Returns a single feature flag definition by key.
17
+ *
18
+ * @public
19
+ * @param key - The unique key identifying the feature flag.
20
+ * @returns The flag definition, or `undefined` if not found.
21
+ */
22
+ abstract getFlag(key: string): Promise<IFeatureFlagDefinition | undefined>;
23
+ /**
24
+ * Returns all feature flag definitions managed by the provider.
25
+ *
26
+ * @public
27
+ * @returns Array of flag definitions.
28
+ */
29
+ abstract listFlags(): Promise<ReadonlyArray<IFeatureFlagDefinition>>;
30
+ /**
31
+ * Creates a new feature flag.
32
+ *
33
+ * @public
34
+ * @param definition - The flag definition to create.
35
+ * @throws {FeatureFlagError} If the flag already exists or creation fails.
36
+ */
37
+ abstract createFlag(definition: IFeatureFlagDefinition): Promise<void>;
38
+ /**
39
+ * Updates an existing feature flag.
40
+ * Only the fields present in the partial definition are updated.
41
+ *
42
+ * @public
43
+ * @param key - The unique key of the flag to update.
44
+ * @param updates - Partial definition with the fields to update.
45
+ * @throws {FeatureFlagError} If the flag does not exist or the update fails.
46
+ */
47
+ abstract updateFlag(key: string, updates: Partial<Omit<IFeatureFlagDefinition, 'key'>>): Promise<void>;
48
+ /**
49
+ * Deletes a feature flag.
50
+ *
51
+ * @public
52
+ * @param key - The unique key of the flag to delete.
53
+ * @throws {FeatureFlagError} If the deletion fails.
54
+ */
55
+ abstract deleteFlag(key: string): Promise<void>;
56
+ /**
57
+ * Lightweight connectivity check for the writer provider.
58
+ * Defaults to `true` if not overridden.
59
+ *
60
+ * @public
61
+ * @returns `true` if the provider is reachable.
62
+ */
63
+ ping(): Promise<boolean>;
64
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ // #region Imports
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.FeatureFlagWriterPort = void 0;
5
+ // #endregion
6
+ /**
7
+ * Abstract port for feature flag writer operations (CRUD).
8
+ * Each provider (Azure App Configuration, Vercel Edge Config) must implement this contract
9
+ * so that the admin UI backend can manage flags without being coupled to a specific provider.
10
+ *
11
+ * @remarks
12
+ * This port is intentionally separated from {@link FeatureFlagReaderPort} because
13
+ * the read path (consumed by application code) and the write path (consumed by admin tooling)
14
+ * have different deployment contexts, security requirements, and SDK dependencies.
15
+ *
16
+ * @public
17
+ */
18
+ class FeatureFlagWriterPort {
19
+ /**
20
+ * Lightweight connectivity check for the writer provider.
21
+ * Defaults to `true` if not overridden.
22
+ *
23
+ * @public
24
+ * @returns `true` if the provider is reachable.
25
+ */
26
+ async ping() {
27
+ return true;
28
+ }
29
+ }
30
+ exports.FeatureFlagWriterPort = FeatureFlagWriterPort;
31
+ //# sourceMappingURL=FeatureFlagWriterPort.js.map
@@ -0,0 +1,2 @@
1
+ export { FeatureFlagReaderPort } from './FeatureFlagReaderPort';
2
+ export { FeatureFlagWriterPort } from './FeatureFlagWriterPort';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeatureFlagWriterPort = exports.FeatureFlagReaderPort = void 0;
4
+ var FeatureFlagReaderPort_1 = require("./FeatureFlagReaderPort");
5
+ Object.defineProperty(exports, "FeatureFlagReaderPort", { enumerable: true, get: function () { return FeatureFlagReaderPort_1.FeatureFlagReaderPort; } });
6
+ var FeatureFlagWriterPort_1 = require("./FeatureFlagWriterPort");
7
+ Object.defineProperty(exports, "FeatureFlagWriterPort", { enumerable: true, get: function () { return FeatureFlagWriterPort_1.FeatureFlagWriterPort; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,11 @@
1
+ import { SetMetadata } from '@nestjs/common';
2
+ /** Metadata key used to store the feature flag key on route handlers. */
3
+ export declare const FEATURE_FLAG_KEY_METADATA = "feature_flag_key";
4
+ /**
5
+ * Decorator to mark endpoints that require a specific feature flag to be enabled.
6
+ * The guard reads this metadata to evaluate the flag before allowing access.
7
+ *
8
+ * @public
9
+ * @param flagKey - The unique key of the feature flag to check.
10
+ */
11
+ export declare const FeatureFlag: (flagKey: string) => ReturnType<typeof SetMetadata>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ // #region Imports
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.FeatureFlag = exports.FEATURE_FLAG_KEY_METADATA = void 0;
5
+ const common_1 = require("@nestjs/common");
6
+ // #endregion
7
+ /** Metadata key used to store the feature flag key on route handlers. */
8
+ exports.FEATURE_FLAG_KEY_METADATA = 'feature_flag_key';
9
+ /**
10
+ * Decorator to mark endpoints that require a specific feature flag to be enabled.
11
+ * The guard reads this metadata to evaluate the flag before allowing access.
12
+ *
13
+ * @public
14
+ * @param flagKey - The unique key of the feature flag to check.
15
+ */
16
+ const FeatureFlag = (flagKey) => (0, common_1.SetMetadata)(exports.FEATURE_FLAG_KEY_METADATA, flagKey);
17
+ exports.FeatureFlag = FeatureFlag;
18
+ //# sourceMappingURL=FeatureFlag.js.map
@@ -0,0 +1 @@
1
+ export { FEATURE_FLAG_KEY_METADATA, FeatureFlag } from './FeatureFlag';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeatureFlag = exports.FEATURE_FLAG_KEY_METADATA = void 0;
4
+ var FeatureFlag_1 = require("./FeatureFlag");
5
+ Object.defineProperty(exports, "FEATURE_FLAG_KEY_METADATA", { enumerable: true, get: function () { return FeatureFlag_1.FEATURE_FLAG_KEY_METADATA; } });
6
+ Object.defineProperty(exports, "FeatureFlag", { enumerable: true, get: function () { return FeatureFlag_1.FeatureFlag; } });
7
+ //# sourceMappingURL=index.js.map
package/src/env.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { IConfigRegistryEntry } from '@breadstone/archipel-platform-configuration';
2
+ export { AZURE_APPCONFIG_CONNECTION_STRING, AZURE_APPCONFIG_ENDPOINT, AZURE_FEATURE_FLAG_CONFIG_ENTRIES, AZURE_FEATURE_FLAG_KEY_FILTER, AZURE_FEATURE_FLAG_REFRESH_INTERVAL, } from './azure/env';
3
+ export { VERCEL_API_TOKEN, VERCEL_EDGE_CONFIG, VERCEL_EDGE_CONFIG_ID, VERCEL_EDGE_CONFIG_TOKEN, VERCEL_FEATURE_FLAG_CONFIG_ENTRIES, VERCEL_FEATURE_FLAG_PREFIX, VERCEL_FEATURE_FLAG_WRITER_CONFIG_ENTRIES, VERCEL_TEAM_ID, } from './vercel/env';
4
+ /** All configuration entries required by the platform-feature-flags library across all providers. */
5
+ export declare const PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES: ReadonlyArray<Omit<IConfigRegistryEntry, 'module'>>;
package/src/env.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ // #region Imports
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES = exports.VERCEL_TEAM_ID = exports.VERCEL_FEATURE_FLAG_WRITER_CONFIG_ENTRIES = exports.VERCEL_FEATURE_FLAG_PREFIX = exports.VERCEL_FEATURE_FLAG_CONFIG_ENTRIES = exports.VERCEL_EDGE_CONFIG_TOKEN = exports.VERCEL_EDGE_CONFIG_ID = exports.VERCEL_EDGE_CONFIG = exports.VERCEL_API_TOKEN = exports.AZURE_FEATURE_FLAG_REFRESH_INTERVAL = exports.AZURE_FEATURE_FLAG_KEY_FILTER = exports.AZURE_FEATURE_FLAG_CONFIG_ENTRIES = exports.AZURE_APPCONFIG_ENDPOINT = exports.AZURE_APPCONFIG_CONNECTION_STRING = void 0;
5
+ const env_1 = require("./azure/env");
6
+ const env_2 = require("./vercel/env");
7
+ // #endregion
8
+ // ──────────────────────────────────────────────────────────────
9
+ // Re-exports
10
+ // ──────────────────────────────────────────────────────────────
11
+ var env_3 = require("./azure/env");
12
+ Object.defineProperty(exports, "AZURE_APPCONFIG_CONNECTION_STRING", { enumerable: true, get: function () { return env_3.AZURE_APPCONFIG_CONNECTION_STRING; } });
13
+ Object.defineProperty(exports, "AZURE_APPCONFIG_ENDPOINT", { enumerable: true, get: function () { return env_3.AZURE_APPCONFIG_ENDPOINT; } });
14
+ Object.defineProperty(exports, "AZURE_FEATURE_FLAG_CONFIG_ENTRIES", { enumerable: true, get: function () { return env_3.AZURE_FEATURE_FLAG_CONFIG_ENTRIES; } });
15
+ Object.defineProperty(exports, "AZURE_FEATURE_FLAG_KEY_FILTER", { enumerable: true, get: function () { return env_3.AZURE_FEATURE_FLAG_KEY_FILTER; } });
16
+ Object.defineProperty(exports, "AZURE_FEATURE_FLAG_REFRESH_INTERVAL", { enumerable: true, get: function () { return env_3.AZURE_FEATURE_FLAG_REFRESH_INTERVAL; } });
17
+ var env_4 = require("./vercel/env");
18
+ Object.defineProperty(exports, "VERCEL_API_TOKEN", { enumerable: true, get: function () { return env_4.VERCEL_API_TOKEN; } });
19
+ Object.defineProperty(exports, "VERCEL_EDGE_CONFIG", { enumerable: true, get: function () { return env_4.VERCEL_EDGE_CONFIG; } });
20
+ Object.defineProperty(exports, "VERCEL_EDGE_CONFIG_ID", { enumerable: true, get: function () { return env_4.VERCEL_EDGE_CONFIG_ID; } });
21
+ Object.defineProperty(exports, "VERCEL_EDGE_CONFIG_TOKEN", { enumerable: true, get: function () { return env_4.VERCEL_EDGE_CONFIG_TOKEN; } });
22
+ Object.defineProperty(exports, "VERCEL_FEATURE_FLAG_CONFIG_ENTRIES", { enumerable: true, get: function () { return env_4.VERCEL_FEATURE_FLAG_CONFIG_ENTRIES; } });
23
+ Object.defineProperty(exports, "VERCEL_FEATURE_FLAG_PREFIX", { enumerable: true, get: function () { return env_4.VERCEL_FEATURE_FLAG_PREFIX; } });
24
+ Object.defineProperty(exports, "VERCEL_FEATURE_FLAG_WRITER_CONFIG_ENTRIES", { enumerable: true, get: function () { return env_4.VERCEL_FEATURE_FLAG_WRITER_CONFIG_ENTRIES; } });
25
+ Object.defineProperty(exports, "VERCEL_TEAM_ID", { enumerable: true, get: function () { return env_4.VERCEL_TEAM_ID; } });
26
+ // ──────────────────────────────────────────────────────────────
27
+ // Aggregated registry entries
28
+ // ──────────────────────────────────────────────────────────────
29
+ /** All configuration entries required by the platform-feature-flags library across all providers. */
30
+ exports.PLATFORM_FEATURE_FLAGS_CONFIG_ENTRIES = [
31
+ ...env_1.AZURE_FEATURE_FLAG_CONFIG_ENTRIES,
32
+ ...env_2.VERCEL_FEATURE_FLAG_CONFIG_ENTRIES,
33
+ ...env_2.VERCEL_FEATURE_FLAG_WRITER_CONFIG_ENTRIES,
34
+ ];
35
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Domain error thrown when a feature flag operation fails.
3
+ *
4
+ * @public
5
+ */
6
+ export declare class FeatureFlagError extends Error {
7
+ readonly code = "FEATURE_FLAG";
8
+ readonly provider: string;
9
+ constructor(provider: string, message: string, cause?: unknown);
10
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeatureFlagError = void 0;
4
+ /**
5
+ * Domain error thrown when a feature flag operation fails.
6
+ *
7
+ * @public
8
+ */
9
+ class FeatureFlagError extends Error {
10
+ // #endregion
11
+ // #region Ctor
12
+ constructor(provider, message, cause) {
13
+ super(message, { cause });
14
+ // #region Fields
15
+ this.code = 'FEATURE_FLAG';
16
+ this.name = 'FeatureFlagError';
17
+ this.provider = provider;
18
+ }
19
+ }
20
+ exports.FeatureFlagError = FeatureFlagError;
21
+ //# sourceMappingURL=FeatureFlagError.js.map
@@ -0,0 +1 @@
1
+ export { FeatureFlagError } from './FeatureFlagError';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeatureFlagError = void 0;
4
+ var FeatureFlagError_1 = require("./FeatureFlagError");
5
+ Object.defineProperty(exports, "FeatureFlagError", { enumerable: true, get: function () { return FeatureFlagError_1.FeatureFlagError; } });
6
+ //# sourceMappingURL=index.js.map