Skip to content

Commit 3052c0b

Browse files
WIP
1 parent ce1edd3 commit 3052c0b

File tree

3 files changed

+71
-10
lines changed

3 files changed

+71
-10
lines changed

src/AzureAppConfigurationImpl.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { IKeyValueAdapter } from "./IKeyValueAdapter";
99
import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter";
1010
import { DEFAULT_REFRESH_INTERVAL_IN_MS, MIN_REFRESH_INTERVAL_IN_MS } from "./RefreshOptions";
1111
import { Disposable } from "./common/disposable";
12-
import { FEATURE_FLAGS_KEY_NAME, FEATURE_MANAGEMENT_KEY_NAME } from "./featureManagement/constants";
12+
import { FEATURE_FLAGS_KEY_NAME, FEATURE_MANAGEMENT_KEY_NAME, TELEMETRY_KEY_NAME, METADATA_KEY_NAME, ETAG_KEY_NAME, FEATURE_FLAG_ID_KEY_NAME, FEATURE_FLAG_REFERENCE_KEY_NAME } from "./featureManagement/constants";
1313
import { AzureKeyVaultKeyValueAdapter } from "./keyvault/AzureKeyVaultKeyValueAdapter";
1414
import { RefreshTimer } from "./refresh/RefreshTimer";
1515
import { getConfigurationSettingWithTrace, listConfigurationSettingsWithTrace, requestTracingEnabled } from "./requestTracing/utils";
@@ -36,6 +36,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
3636
#sortedTrimKeyPrefixes: string[] | undefined;
3737
readonly #requestTracingEnabled: boolean;
3838
#client: AppConfigurationClient;
39+
#clientEndpoint: string | undefined;
3940
#options: AzureAppConfigurationOptions | undefined;
4041
#isInitialLoadCompleted: boolean = false;
4142

@@ -57,9 +58,11 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
5758

5859
constructor(
5960
client: AppConfigurationClient,
61+
clientEndpoint: string | undefined,
6062
options: AzureAppConfigurationOptions | undefined
6163
) {
6264
this.#client = client;
65+
this.#clientEndpoint = clientEndpoint;
6366
this.#options = options;
6467

6568
// Enable request tracing if not opt-out
@@ -273,15 +276,15 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
273276
pageEtags.push(page.etag ?? "");
274277
for (const setting of page.items) {
275278
if (isFeatureFlag(setting)) {
276-
featureFlagsMap.set(setting.key, setting.value);
279+
featureFlagsMap.set(setting.key, setting);
277280
}
278281
}
279282
}
280283
selector.pageEtags = pageEtags;
281284
}
282285

283286
// parse feature flags
284-
const featureFlags = Array.from(featureFlagsMap.values()).map(rawFlag => JSON.parse(rawFlag));
287+
const featureFlags = Array.from(featureFlagsMap.values()).map(setting => this.#parseFeatureflag(setting));
285288

286289
// feature_management is a reserved key, and feature_flags is an array of feature flags
287290
this.#configMap.set(FEATURE_MANAGEMENT_KEY_NAME, { [FEATURE_FLAGS_KEY_NAME]: featureFlags });
@@ -532,6 +535,40 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
532535
}
533536
return response;
534537
}
538+
539+
#parseFeatureflag(setting: ConfigurationSetting<string>): any{
540+
const rawFlag = setting.value;
541+
if (rawFlag === undefined) {
542+
throw new Error("The value of configuration setting cannot be undefined.");
543+
}
544+
const featureFlag = JSON.parse(rawFlag);
545+
546+
if (featureFlag[TELEMETRY_KEY_NAME]) {
547+
const metadata = featureFlag[TELEMETRY_KEY_NAME][METADATA_KEY_NAME];
548+
featureFlag[TELEMETRY_KEY_NAME][METADATA_KEY_NAME] = {
549+
ETAG_KEY_NAME: setting.etag,
550+
FEATURE_FLAG_ID_KEY_NAME: "1",
551+
FEATURE_FLAG_REFERENCE_KEY_NAME: this.#createFeatureFlagReference(setting),
552+
...(metadata || {})
553+
};
554+
}
555+
556+
console.log(featureFlag);
557+
558+
return featureFlag;
559+
}
560+
561+
#calculateFeatureFlagId(setting: ConfigurationSetting<string>): string {
562+
return ""
563+
}
564+
565+
#createFeatureFlagReference(setting: ConfigurationSetting<string>): string {
566+
let featureFlagReference = `${this.#clientEndpoint}kv/${setting.key}`;
567+
if (setting.label && setting.label.trim().length !== 0) {
568+
featureFlagReference += `?label=${setting.label}`;
569+
}
570+
return featureFlagReference;
571+
}
535572
}
536573

537574
function getValidSelectors(selectors: SettingSelector[]): SettingSelector[] {
@@ -575,4 +612,4 @@ function getValidFeatureFlagSelectors(selectors?: SettingSelector[]): SettingSel
575612
} else {
576613
return getValidSelectors(selectors);
577614
}
578-
}
615+
}

src/featureManagement/constants.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@
22
// Licensed under the MIT license.
33

44
export const FEATURE_MANAGEMENT_KEY_NAME = "feature_management";
5-
export const FEATURE_FLAGS_KEY_NAME = "feature_flags";
5+
export const FEATURE_FLAGS_KEY_NAME = "feature_flags";
6+
export const TELEMETRY_KEY_NAME = "telemetry"
7+
export const METADATA_KEY_NAME = "metadata"
8+
export const ETAG_KEY_NAME = "Etag"
9+
export const FEATURE_FLAG_ID_KEY_NAME = "FeatureFlagId"
10+
export const FEATURE_FLAG_REFERENCE_KEY_NAME = "FeatureFlagReference"

src/load.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export async function load(
3232
): Promise<AzureAppConfiguration> {
3333
const startTimestamp = Date.now();
3434
let client: AppConfigurationClient;
35+
let clientEndpoint: string | undefined;
3536
let options: AzureAppConfigurationOptions | undefined;
3637

3738
// input validation
@@ -40,30 +41,33 @@ export async function load(
4041
options = credentialOrOptions as AzureAppConfigurationOptions;
4142
const clientOptions = getClientOptions(options);
4243
client = new AppConfigurationClient(connectionString, clientOptions);
44+
clientEndpoint = parseEndpoint(connectionStringOrEndpoint);
4345
} else if ((connectionStringOrEndpoint instanceof URL || typeof connectionStringOrEndpoint === "string") && instanceOfTokenCredential(credentialOrOptions)) {
44-
let endpoint = connectionStringOrEndpoint;
4546
// ensure string is a valid URL.
46-
if (typeof endpoint === "string") {
47+
if (typeof connectionStringOrEndpoint === "string") {
4748
try {
48-
endpoint = new URL(endpoint);
49+
let endpoint = new URL(connectionStringOrEndpoint);
50+
clientEndpoint = endpoint.toString();
4951
} catch (error) {
5052
if (error.code === "ERR_INVALID_URL") {
5153
throw new Error("Invalid endpoint URL.", { cause: error });
5254
} else {
5355
throw error;
5456
}
5557
}
58+
} else {
59+
clientEndpoint = connectionStringOrEndpoint.toString();
5660
}
5761
const credential = credentialOrOptions as TokenCredential;
5862
options = appConfigOptions;
5963
const clientOptions = getClientOptions(options);
60-
client = new AppConfigurationClient(endpoint.toString(), credential, clientOptions);
64+
client = new AppConfigurationClient(clientEndpoint, credential, clientOptions);
6165
} else {
6266
throw new Error("A connection string or an endpoint with credential must be specified to create a client.");
6367
}
6468

6569
try {
66-
const appConfiguration = new AzureAppConfigurationImpl(client, options);
70+
const appConfiguration = new AzureAppConfigurationImpl(client, clientEndpoint, options);
6771
await appConfiguration.load();
6872
return appConfiguration;
6973
} catch (error) {
@@ -104,3 +108,18 @@ function getClientOptions(options?: AzureAppConfigurationOptions): AppConfigurat
104108
}
105109
});
106110
}
111+
112+
function parseEndpoint(connectionString: string): string | undefined {
113+
const parts = connectionString.split(";");
114+
const endpointPart = parts.find(part => part.startsWith("Endpoint="));
115+
116+
if (endpointPart) {
117+
let endpoint = endpointPart.split("=")[1];
118+
if (!endpoint.endsWith("/")) {
119+
endpoint += "/";
120+
}
121+
return endpoint;
122+
}
123+
124+
return undefined;
125+
}

0 commit comments

Comments
 (0)