Skip to content

Commit f079b3e

Browse files
committed
resolve comments
1 parent 0c777d8 commit f079b3e

3 files changed

Lines changed: 95 additions & 32 deletions

File tree

src/appConfigurationImpl.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,10 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
841841
}
842842
i++;
843843
}
844+
845+
if (i < pageWatchers.length) {
846+
return true;
847+
}
844848
}
845849
return false;
846850
};
@@ -887,7 +891,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
887891
const lastServerResponseTime = pageWatchers[i].lastServerResponseTime;
888892
let isResponseFresh = false;
889893
if (lastServerResponseTime !== undefined) {
890-
isResponseFresh = serverResponseTime > lastServerResponseTime;
894+
isResponseFresh = serverResponseTime >= lastServerResponseTime;
891895
}
892896
if (isResponseFresh &&
893897
getStatusCode(page._response.status) === 200 && // conditional request returns 304 if not changed
@@ -1370,14 +1374,14 @@ function getFeatureFlagPageWatchers(selectors?: SettingSelector[]): PagedSetting
13701374
// Default selector: key/name: *, label: \0
13711375
return [{ keyFilter: `${featureFlagPrefix}${KeyFilter.Any}`, labelFilter: LabelFilter.Null }];
13721376
}
1373-
// Deep clone so the caller's option objects are never mutated.
1374-
const clonedSelectors = structuredClone(selectors);
1375-
clonedSelectors.forEach(selector => {
1376-
if (selector.keyFilter) {
1377-
selector.keyFilter = `${featureFlagPrefix}${selector.keyFilter}`;
1378-
}
1379-
});
1380-
return getValidSettingSelectors(clonedSelectors);
1377+
// Create prefixed copies because the original selectors are also used as unprefixed selectors for enhanced feature flags.
1378+
const prefixedSelectors = selectors.map(selector => ({
1379+
...selector,
1380+
keyFilter: selector.keyFilter
1381+
? `${featureFlagPrefix}${selector.keyFilter}`
1382+
: selector.keyFilter
1383+
}));
1384+
return getValidSettingSelectors(prefixedSelectors);
13811385
}
13821386

13831387
function validateTagFilters(tagFilters: string[]): void {

src/featureManagement/featureFlagConverter.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,62 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4-
import { FeatureFlag } from "@azure/app-configuration";
4+
import type { FeatureFlag as AzAppConfigFeatureFlag } from "@azure/app-configuration";
5+
import type {
6+
FeatureFilter,
7+
FeatureFlag,
8+
FeatureFlagAllocation,
9+
FeatureFlagTelemetry,
10+
FeatureFlagVariant
11+
} from "./featureFlags.js";
512

613
/**
714
* Converts @see FeatureFlag into the
815
* Microsoft Feature Flag schema object used within the `feature_management.feature_flags`
916
* array. This mirrors the shape produced by parsing a classic feature flag key-value, so that downstream
1017
* feature management parsing and the provider's telemetry/tracing logic are unchanged.
1118
*/
12-
export function convert(featureFlag: FeatureFlag): any {
13-
const result: any = {
19+
export function convert(featureFlag: AzAppConfigFeatureFlag): FeatureFlag {
20+
const result: FeatureFlag = {
1421
id: featureFlag.name,
15-
enabled: featureFlag.enabled
22+
enabled: featureFlag.enabled,
23+
conditions: {
24+
client_filters: (featureFlag.conditions?.filters ?? []).map(filter => {
25+
const clientFilter: FeatureFilter = { name: filter.name };
26+
if (filter.parameters != null) {
27+
clientFilter.parameters = Object.fromEntries(
28+
Object.entries(filter.parameters).map(([name, value]): [string, unknown] => [name, JSON.parse(value) as unknown]));
29+
}
30+
return clientFilter;
31+
})
32+
}
1633
};
1734

1835
if (featureFlag.description != null) {
1936
result.description = featureFlag.description;
2037
}
2138

22-
// conditions: filters -> client_filters, requirementType -> requirement_type
23-
const conditions: any = {
24-
client_filters: (featureFlag.conditions?.filters ?? []).map(filter => {
25-
const clientFilter: any = { name: filter.name };
26-
if (filter.parameters != null) {
27-
clientFilter.parameters = Object.fromEntries(
28-
Object.entries(filter.parameters).map(([name, value]) => [name, JSON.parse(value)]));
29-
}
30-
return clientFilter;
31-
})
32-
};
3339
if (featureFlag.conditions?.requirementType != null) {
34-
conditions.requirement_type = featureFlag.conditions.requirementType;
40+
result.conditions.requirement_type = featureFlag.conditions.requirementType;
3541
}
36-
result.conditions = conditions;
3742

3843
// variants: value -> configuration_value, statusOverride -> status_override
3944
if (featureFlag.variants != null) {
4045
result.variants = featureFlag.variants.map(variant => {
41-
const result_variant: any = { name: variant.name };
46+
const resultVariant: FeatureFlagVariant = { name: variant.name };
4247
if (variant.value !== undefined) {
43-
result_variant.configuration_value = variant.value;
48+
resultVariant.configuration_value = variant.value;
4449
}
4550
if (variant.statusOverride != null) {
46-
result_variant.status_override = variant.statusOverride;
51+
resultVariant.status_override = variant.statusOverride;
4752
}
48-
return result_variant;
53+
return resultVariant;
4954
});
5055
}
5156

5257
// allocation: camelCase -> snake_case
5358
if (featureFlag.allocation != null) {
54-
const allocation: any = {};
59+
const allocation: FeatureFlagAllocation = {};
5560
const sourceAllocation = featureFlag.allocation;
5661
if (sourceAllocation.defaultWhenDisabled != null) {
5762
allocation.default_when_disabled = sourceAllocation.defaultWhenDisabled;
@@ -76,7 +81,7 @@ export function convert(featureFlag: FeatureFlag): any {
7681

7782
// telemetry: metadata is (re)populated later by the provider with ETag/FeatureFlagReference/AllocationId
7883
if (featureFlag.telemetry != null) {
79-
const telemetry: any = { enabled: featureFlag.telemetry.enabled };
84+
const telemetry: FeatureFlagTelemetry = { enabled: featureFlag.telemetry.enabled };
8085
if (featureFlag.telemetry.metadata != null) {
8186
telemetry.metadata = featureFlag.telemetry.metadata;
8287
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import type {
5+
FeatureFlag as AzAppConfigFeatureFlag,
6+
FeatureFlagAllocation as AzAppConfigFeatureFlagAllocation,
7+
FeatureFlagConditions as AzAppConfigFeatureFlagConditions,
8+
FeatureFilter as AzAppConfigFeatureFilter,
9+
FeatureFlagTelemetryConfiguration as AzAppConfigFeatureFlagTelemetryConfiguration,
10+
FeatureFlagVariantDefinition as AzAppConfigFeatureFlagVariantDefinition,
11+
GroupAllocation as AzAppConfigGroupAllocation,
12+
PercentileAllocation as AzAppConfigPercentileAllocation,
13+
UserAllocation as AzAppConfigUserAllocation
14+
} from "@azure/app-configuration";
15+
16+
export interface FeatureFilter {
17+
name: AzAppConfigFeatureFilter["name"];
18+
parameters?: Record<string, unknown>;
19+
}
20+
21+
export interface FeatureFlagConditions {
22+
client_filters: FeatureFilter[];
23+
requirement_type?: AzAppConfigFeatureFlagConditions["requirementType"];
24+
}
25+
26+
export interface FeatureFlagVariant {
27+
name: AzAppConfigFeatureFlagVariantDefinition["name"];
28+
configuration_value?: AzAppConfigFeatureFlagVariantDefinition["value"];
29+
status_override?: AzAppConfigFeatureFlagVariantDefinition["statusOverride"];
30+
}
31+
32+
export interface FeatureFlagAllocation {
33+
default_when_disabled?: AzAppConfigFeatureFlagAllocation["defaultWhenDisabled"];
34+
default_when_enabled?: AzAppConfigFeatureFlagAllocation["defaultWhenEnabled"];
35+
percentile?: AzAppConfigPercentileAllocation[];
36+
user?: AzAppConfigUserAllocation[];
37+
group?: AzAppConfigGroupAllocation[];
38+
seed?: AzAppConfigFeatureFlagAllocation["seed"];
39+
}
40+
41+
export interface FeatureFlagTelemetry {
42+
enabled: AzAppConfigFeatureFlagTelemetryConfiguration["enabled"];
43+
metadata?: AzAppConfigFeatureFlagTelemetryConfiguration["metadata"];
44+
}
45+
46+
export interface FeatureFlag {
47+
id: AzAppConfigFeatureFlag["name"];
48+
enabled: AzAppConfigFeatureFlag["enabled"];
49+
description?: AzAppConfigFeatureFlag["description"];
50+
conditions: FeatureFlagConditions;
51+
variants?: FeatureFlagVariant[];
52+
allocation?: FeatureFlagAllocation;
53+
telemetry?: FeatureFlagTelemetry;
54+
}

0 commit comments

Comments
 (0)