Skip to content

Commit c61b4a5

Browse files
committed
update
1 parent 920c12f commit c61b4a5

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

src/featureManager.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { IFeatureFilter } from "./filter/FeatureFilter.js";
66
import { RequirementType } from "./schema/model.js";
77
import { IFeatureFlagProvider } from "./featureProvider.js";
88
import { TargetingFilter } from "./filter/TargetingFilter.js";
9-
import { validateFeatureFlag } from "./schema/validator.js";
109

1110
export class FeatureManager {
1211
#provider: IFeatureFlagProvider;
@@ -75,7 +74,6 @@ export class FeatureManager {
7574

7675
async #getFeatureFlag(featureName: string): Promise<any> {
7776
const featureFlag = await this.#provider.getFeatureFlag(featureName);
78-
validateFeatureFlag(featureFlag);
7977
return featureFlag;
8078
}
8179

src/featureProvider.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import { IGettable } from "./gettable.js";
55
import { FeatureFlag, FeatureManagementConfiguration, FEATURE_MANAGEMENT_KEY, FEATURE_FLAGS_KEY } from "./schema/model.js";
6+
import { validateFeatureFlag } from "./schema/validator.js";
67

78
export interface IFeatureFlagProvider {
89
/**
@@ -28,12 +29,16 @@ export class ConfigurationMapFeatureFlagProvider implements IFeatureFlagProvider
2829
}
2930
async getFeatureFlag(featureName: string): Promise<FeatureFlag | undefined> {
3031
const featureConfig = this.#configuration.get<FeatureManagementConfiguration>(FEATURE_MANAGEMENT_KEY);
31-
return featureConfig?.[FEATURE_FLAGS_KEY]?.findLast((feature) => feature.id === featureName);
32+
const featureFlag = featureConfig?.[FEATURE_FLAGS_KEY]?.findLast((feature) => feature.id === featureName);
33+
validateFeatureFlag(featureFlag);
34+
return featureFlag;
3235
}
3336

3437
async getFeatureFlags(): Promise<FeatureFlag[]> {
3538
const featureConfig = this.#configuration.get<FeatureManagementConfiguration>(FEATURE_MANAGEMENT_KEY);
36-
return featureConfig?.[FEATURE_FLAGS_KEY] ?? [];
39+
const featureFlag = featureConfig?.[FEATURE_FLAGS_KEY] ?? [];
40+
validateFeatureFlag(featureFlag);
41+
return featureFlag;
3742
}
3843
}
3944

@@ -49,10 +54,14 @@ export class ConfigurationObjectFeatureFlagProvider implements IFeatureFlagProvi
4954

5055
async getFeatureFlag(featureName: string): Promise<FeatureFlag | undefined> {
5156
const featureFlags = this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY];
52-
return featureFlags?.findLast((feature: FeatureFlag) => feature.id === featureName);
57+
const featureFlag = featureFlags?.findLast((feature: FeatureFlag) => feature.id === featureName);
58+
validateFeatureFlag(featureFlag);
59+
return featureFlag;
5360
}
5461

5562
async getFeatureFlags(): Promise<FeatureFlag[]> {
56-
return this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY] ?? [];
63+
const featureFlag = this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY] ?? [];
64+
validateFeatureFlag(featureFlag);
65+
return featureFlag;
5766
}
5867
}

src/schema/validator.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export function validateFeatureFlag(featureFlag: any): void {
3333
}
3434

3535
function validateFeatureEnablementConditions(conditions: any) {
36+
if (typeof conditions !== "object") {
37+
throw new TypeError("Feature flag 'conditions' must be an object.");
38+
}
3639
if (conditions.requirement_type !== undefined && conditions.requirement_type !== "Any" && conditions.requirement_type !== "All") {
3740
throw new TypeError("'requirement_type' must be 'Any' or 'All'.");
3841
}
@@ -43,7 +46,7 @@ function validateFeatureEnablementConditions(conditions: any) {
4346

4447
function validateClientFilters(client_filters: any) {
4548
if (!Array.isArray(client_filters)) {
46-
throw new TypeError("'client_filters' must be an array.");
49+
throw new TypeError("Feature flag conditions 'client_filters' must be an array.");
4750
}
4851

4952
for (const filter of client_filters) {
@@ -58,7 +61,7 @@ function validateClientFilters(client_filters: any) {
5861

5962
function validateVariants(variants: any) {
6063
if (!Array.isArray(variants)) {
61-
throw new TypeError("'variants' must be an array.");
64+
throw new TypeError("Feature flag 'variants' must be an array.");
6265
}
6366

6467
for (const variant of variants) {
@@ -102,10 +105,13 @@ function validateVariantAllocation(allocation: any) {
102105

103106
function validateUserVariantAllocation(UserAllocations: any) {
104107
if (!Array.isArray(UserAllocations)) {
105-
throw new TypeError("User allocation 'user' must be an array.");
108+
throw new TypeError("Variant 'user' allocation must be an array.");
106109
}
107110

108111
for (const allocation of UserAllocations) {
112+
if (typeof allocation !== "object") {
113+
throw new TypeError("Elements in 'user' allocation must be an object.");
114+
}
109115
if (typeof allocation.variant !== "string") {
110116
throw new TypeError("User allocation 'variant' must be a string.");
111117
}
@@ -114,18 +120,21 @@ function validateUserVariantAllocation(UserAllocations: any) {
114120
}
115121
for (const user of allocation.users) {
116122
if (typeof user !== "string") {
117-
throw new TypeError("Elements in User allocation 'users' must be strings.");
123+
throw new TypeError("Elements in user allocation 'users' must be strings.");
118124
}
119125
}
120126
}
121127
}
122128

123129
function validateGroupVariantAllocation(groupAllocations: any) {
124130
if (!Array.isArray(groupAllocations)) {
125-
throw new TypeError("Group allocation 'group' must be an array.");
131+
throw new TypeError("Variant 'group' allocation must be an array.");
126132
}
127133

128134
for (const allocation of groupAllocations) {
135+
if (typeof allocation !== "object") {
136+
throw new TypeError("Elements in 'group' allocation must be an object.");
137+
}
129138
if (typeof allocation.variant !== "string") {
130139
throw new TypeError("Group allocation 'variant' must be a string.");
131140
}
@@ -134,18 +143,21 @@ function validateGroupVariantAllocation(groupAllocations: any) {
134143
}
135144
for (const group of allocation.groups) {
136145
if (typeof group !== "string") {
137-
throw new TypeError("Elements in Group allocation 'groups' must be strings.");
146+
throw new TypeError("Elements in group allocation 'groups' must be strings.");
138147
}
139148
}
140149
}
141150
}
142151

143152
function validatePercentileVariantAllocation(percentileAllocations: any) {
144153
if (!Array.isArray(percentileAllocations)) {
145-
throw new TypeError("Percentile allocation 'percentile' must be an array.");
154+
throw new TypeError("Variant 'percentile' allocation must be an array.");
146155
}
147156

148157
for (const allocation of percentileAllocations) {
158+
if (typeof allocation !== "object") {
159+
throw new TypeError("Elements in 'percentile' allocation must be an object.");
160+
}
149161
if (typeof allocation.variant !== "string") {
150162
throw new TypeError("Percentile allocation 'variant' must be a string.");
151163
}
@@ -162,7 +174,7 @@ function validatePercentileVariantAllocation(percentileAllocations: any) {
162174
// #region Telemetry
163175
function validateTelemetryOptions(telemetry: any) {
164176
if (typeof telemetry !== "object") {
165-
throw new TypeError("Telemetry option 'telemetry' must be an object.");
177+
throw new TypeError("Feature flag 'telemetry' must be an object.");
166178
}
167179
if (telemetry.enabled !== undefined && typeof telemetry.enabled !== "boolean") {
168180
throw new TypeError("Telemetry 'enabled' must be a boolean.");

0 commit comments

Comments
 (0)