Skip to content
Merged
2,639 changes: 25 additions & 2,614 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@azure/app-configuration-provider",
"version": "1.1.0",
"version": "1.1.1",
"description": "The JavaScript configuration provider for Azure App Configuration",
"main": "dist/index.js",
"module": "./dist-esm/index.js",
Expand Down Expand Up @@ -35,7 +35,7 @@
"devDependencies": {
"@rollup/plugin-typescript": "^11.1.2",
"@types/mocha": "^10.0.4",
"@types/node": "^20.5.7",
"@types/node": "^22.7.7",
"@types/sinon": "^17.0.1",
"@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.6.0",
Expand All @@ -47,11 +47,11 @@
"mocha": "^10.2.0",
"nock": "^13.3.3",
"rimraf": "^5.0.1",
"rollup": "^3.26.3",
"rollup": "^3.29.5",
"rollup-plugin-dts": "^5.3.0",
"sinon": "^15.2.0",
"tslib": "^2.6.0",
"typescript": "^5.1.6",
"typescript": "^5.6.3",
"uuid": "^9.0.1"
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/AzureAppConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { Disposable } from "./common/disposable";
import { Disposable } from "./common/disposable.js";

export type AzureAppConfiguration = {
/**
Expand Down
32 changes: 16 additions & 16 deletions src/AzureAppConfigurationImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@

import { AppConfigurationClient, ConfigurationSetting, ConfigurationSettingId, GetConfigurationSettingOptions, GetConfigurationSettingResponse, ListConfigurationSettingsOptions, featureFlagPrefix, isFeatureFlag } from "@azure/app-configuration";
import { isRestError } from "@azure/core-rest-pipeline";
import { AzureAppConfiguration, ConfigurationObjectConstructionOptions } from "./AzureAppConfiguration";
import { AzureAppConfigurationOptions } from "./AzureAppConfigurationOptions";
import { IKeyValueAdapter } from "./IKeyValueAdapter";
import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter";
import { DEFAULT_REFRESH_INTERVAL_IN_MS, MIN_REFRESH_INTERVAL_IN_MS } from "./RefreshOptions";
import { Disposable } from "./common/disposable";
import { FEATURE_FLAGS_KEY_NAME, FEATURE_MANAGEMENT_KEY_NAME, TELEMETRY_KEY_NAME, ENABLED_KEY_NAME, METADATA_KEY_NAME, ETAG_KEY_NAME, FEATURE_FLAG_ID_KEY_NAME, FEATURE_FLAG_REFERENCE_KEY_NAME } from "./featureManagement/constants";
import { AzureKeyVaultKeyValueAdapter } from "./keyvault/AzureKeyVaultKeyValueAdapter";
import { RefreshTimer } from "./refresh/RefreshTimer";
import { getConfigurationSettingWithTrace, listConfigurationSettingsWithTrace, requestTracingEnabled } from "./requestTracing/utils";
import { KeyFilter, LabelFilter, SettingSelector } from "./types";
import { AzureAppConfiguration, ConfigurationObjectConstructionOptions } from "./AzureAppConfiguration.js";
import { AzureAppConfigurationOptions } from "./AzureAppConfigurationOptions.js";
import { IKeyValueAdapter } from "./IKeyValueAdapter.js";
import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter.js";
import { DEFAULT_REFRESH_INTERVAL_IN_MS, MIN_REFRESH_INTERVAL_IN_MS } from "./RefreshOptions.js";
import { Disposable } from "./common/disposable.js";
import { FEATURE_FLAGS_KEY_NAME, FEATURE_MANAGEMENT_KEY_NAME, TELEMETRY_KEY_NAME, ENABLED_KEY_NAME, METADATA_KEY_NAME, ETAG_KEY_NAME, FEATURE_FLAG_ID_KEY_NAME, FEATURE_FLAG_REFERENCE_KEY_NAME } from "./featureManagement/constants.js";
import { AzureKeyVaultKeyValueAdapter } from "./keyvault/AzureKeyVaultKeyValueAdapter.js";
import { RefreshTimer } from "./refresh/RefreshTimer.js";
import { getConfigurationSettingWithTrace, listConfigurationSettingsWithTrace, requestTracingEnabled } from "./requestTracing/utils.js";
import { KeyFilter, LabelFilter, SettingSelector } from "./types.js";

type PagedSettingSelector = SettingSelector & {
/**
Expand Down Expand Up @@ -66,7 +66,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
this.#options = options;

// Enable request tracing if not opt-out
this.#requestTracingEnabled = requestTracingEnabled();
this.#requestTracingEnabled = options?.requestTracingOptions?.enabled ?? requestTracingEnabled();

if (options?.trimKeyPrefixes) {
this.#sortedTrimKeyPrefixes = [...options.trimKeyPrefixes].sort((a, b) => b.localeCompare(a));
Expand Down Expand Up @@ -143,19 +143,19 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
return this.#configMap.size;
}

entries(): IterableIterator<[string, any]> {
entries(): MapIterator<[string, any]> {
return this.#configMap.entries();
}

keys(): IterableIterator<string> {
keys(): MapIterator<string> {
return this.#configMap.keys();
}

values(): IterableIterator<any> {
values(): MapIterator<any> {
return this.#configMap.values();
}

[Symbol.iterator](): IterableIterator<[string, any]> {
[Symbol.iterator](): MapIterator<[string, any]> {
return this.#configMap[Symbol.iterator]();
}
// #endregion
Expand Down
16 changes: 11 additions & 5 deletions src/AzureAppConfigurationOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
// Licensed under the MIT license.

import { AppConfigurationClientOptions } from "@azure/app-configuration";
import { KeyVaultOptions } from "./keyvault/KeyVaultOptions";
import { RefreshOptions } from "./RefreshOptions";
import { SettingSelector } from "./types";
import { FeatureFlagOptions } from "./featureManagement/FeatureFlagOptions";
import { KeyVaultOptions } from "./keyvault/KeyVaultOptions.js";
import { RefreshOptions } from "./RefreshOptions.js";
import { SettingSelector } from "./types.js";
import { FeatureFlagOptions } from "./featureManagement/FeatureFlagOptions.js";
import { RequestTracingOptions } from "./requestTracing/RequestTracingOptions.js";

export const MaxRetries = 2;
export const MaxRetryDelayInMs = 60000;
Expand Down Expand Up @@ -47,4 +48,9 @@ export interface AzureAppConfigurationOptions {
* Specifies options used to configure feature flags.
*/
featureFlagOptions?: FeatureFlagOptions;
}

/**
* Specifies options used to configure request tracing.
*/
requestTracingOptions?: RequestTracingOptions;
}
2 changes: 1 addition & 1 deletion src/JsonKeyValueAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

import { ConfigurationSetting, featureFlagContentType, secretReferenceContentType } from "@azure/app-configuration";
import { IKeyValueAdapter } from "./IKeyValueAdapter";
import { IKeyValueAdapter } from "./IKeyValueAdapter.js";

export class JsonKeyValueAdapter implements IKeyValueAdapter {
static readonly #ExcludedJsonContentTypes: string[] = [
Expand Down
2 changes: 1 addition & 1 deletion src/RefreshOptions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { WatchedSetting } from "./WatchedSetting";
import { WatchedSetting } from "./WatchedSetting.js";

export const DEFAULT_REFRESH_INTERVAL_IN_MS = 30 * 1000;
export const MIN_REFRESH_INTERVAL_IN_MS = 1 * 1000;
Expand Down
6 changes: 3 additions & 3 deletions src/featureManagement/FeatureFlagOptions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { FeatureFlagRefreshOptions } from "../RefreshOptions";
import { SettingSelector } from "../types";
import { FeatureFlagRefreshOptions } from "../RefreshOptions.js";
import { SettingSelector } from "../types.js";

/**
* Options used to configure feature flags.
Expand All @@ -27,4 +27,4 @@ export interface FeatureFlagOptions {
* Specifies how feature flag refresh is configured. All selected feature flags will be watched for changes.
*/
refresh?: FeatureFlagRefreshOptions;
}
}
9 changes: 5 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

export { AzureAppConfiguration } from "./AzureAppConfiguration";
export { Disposable } from "./common/disposable";
export { load } from "./load";
export { KeyFilter, LabelFilter } from "./types";
export { AzureAppConfiguration } from "./AzureAppConfiguration.js";
export { Disposable } from "./common/disposable.js";
export { load } from "./load.js";
export { KeyFilter, LabelFilter } from "./types.js";
export { VERSION } from "./version.js";
6 changes: 3 additions & 3 deletions src/keyvault/AzureKeyVaultKeyValueAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Licensed under the MIT license.

import { ConfigurationSetting, isSecretReference, parseSecretReference } from "@azure/app-configuration";
import { IKeyValueAdapter } from "../IKeyValueAdapter";
import { KeyVaultOptions } from "./KeyVaultOptions";
import { IKeyValueAdapter } from "../IKeyValueAdapter.js";
import { KeyVaultOptions } from "./KeyVaultOptions.js";
import { SecretClient, parseKeyVaultSecretIdentifier } from "@azure/keyvault-secrets";

export class AzureKeyVaultKeyValueAdapter implements IKeyValueAdapter {
Expand Down Expand Up @@ -72,4 +72,4 @@ export class AzureKeyVaultKeyValueAdapter implements IKeyValueAdapter {

function getHost(url: string) {
return new URL(url).host;
}
}
25 changes: 21 additions & 4 deletions src/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

import { AppConfigurationClient, AppConfigurationClientOptions } from "@azure/app-configuration";
import { TokenCredential } from "@azure/identity";
import { AzureAppConfiguration } from "./AzureAppConfiguration";
import { AzureAppConfigurationImpl } from "./AzureAppConfigurationImpl";
import { AzureAppConfigurationOptions, MaxRetries, MaxRetryDelayInMs } from "./AzureAppConfigurationOptions";
import * as RequestTracing from "./requestTracing/constants";
import { AzureAppConfiguration } from "./AzureAppConfiguration.js";
import { AzureAppConfigurationImpl } from "./AzureAppConfigurationImpl.js";
import { AzureAppConfigurationOptions, MaxRetries, MaxRetryDelayInMs } from "./AzureAppConfigurationOptions.js";
import * as RequestTracing from "./requestTracing/constants.js";

const MIN_DELAY_FOR_UNHANDLED_ERROR: number = 5000; // 5 seconds

Expand Down Expand Up @@ -82,6 +82,23 @@ export async function load(
}
}

/**
* Loads the data from a CDN and returns an instance of AzureAppConfiguration.
* @param cdnEndpoint The URL to the CDN.
* @param appConfigOptions Optional parameters.
*/
export async function loadFromCdn(cdnEndpoint: URL | string, options?: AzureAppConfigurationOptions): Promise<AzureAppConfiguration>;

export async function loadFromCdn(
cdnEndpoint: string | URL,
appConfigOptions?: AzureAppConfigurationOptions
): Promise<AzureAppConfiguration> {
const emptyTokenCredential: TokenCredential = {
getToken: async () => ({ token: "", expiresOnTimestamp: 0 })
};
return await load(cdnEndpoint, emptyTokenCredential, appConfigOptions);
}

function instanceOfTokenCredential(obj: unknown) {
return obj && typeof obj === "object" && "getToken" in obj && typeof obj.getToken === "function";
}
Expand Down
12 changes: 12 additions & 0 deletions src/requestTracing/RequestTracingOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

/**
* Options used to configure request tracing.
*/
export interface RequestTracingOptions {
/**
* Specifies whether request tracing is enabled.
*/
enabled: boolean;
}
2 changes: 1 addition & 1 deletion src/requestTracing/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { VERSION } from "../version";
import { VERSION } from "../version.js";

export const ENV_AZURE_APP_CONFIGURATION_TRACING_DISABLED = "AZURE_APP_CONFIGURATION_TRACING_DISABLED";

Expand Down
4 changes: 2 additions & 2 deletions src/requestTracing/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

import { AppConfigurationClient, ConfigurationSettingId, GetConfigurationSettingOptions, ListConfigurationSettingsOptions } from "@azure/app-configuration";
import { AzureAppConfigurationOptions } from "../AzureAppConfigurationOptions";
import { AzureAppConfigurationOptions } from "../AzureAppConfigurationOptions.js";
import {
AZURE_FUNCTION_ENV_VAR,
AZURE_WEB_APP_ENV_VAR,
Expand Down Expand Up @@ -111,7 +111,7 @@ export function requestTracingEnabled(): boolean {

function getEnvironmentVariable(name: string) {
// Make it compatible with non-Node.js runtime
if (typeof process?.env === "object") {
if (typeof process !== "undefined" && typeof process?.env === "object") {
return process.env[name];
} else {
return undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

export const VERSION = "1.1.0";
export const VERSION = "1.1.1";
4 changes: 2 additions & 2 deletions test/clientOptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { load } from "./exportedApi";
import { createMockedConnectionString } from "./utils/testHelper";
import { load } from "./exportedApi.js";
import { createMockedConnectionString } from "./utils/testHelper.js";
import * as nock from "nock";

class HttpRequestCountPolicy {
Expand Down
4 changes: 2 additions & 2 deletions test/featureFlag.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { load } from "./exportedApi";
import { createMockedConnectionString, createMockedEndpoint, createMockedFeatureFlag, createMockedKeyValue, mockAppConfigurationClientListConfigurationSettings, restoreMocks } from "./utils/testHelper";
import { load } from "./exportedApi.js";
import { createMockedConnectionString, createMockedEndpoint, createMockedFeatureFlag, createMockedKeyValue, mockAppConfigurationClientListConfigurationSettings, restoreMocks } from "./utils/testHelper.js";
chai.use(chaiAsPromised);
const expect = chai.expect;

Expand Down
4 changes: 2 additions & 2 deletions test/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { load } from "./exportedApi";
import { mockAppConfigurationClientListConfigurationSettings, restoreMocks, createMockedConnectionString, createMockedKeyVaultReference, createMockedJsonKeyValue } from "./utils/testHelper";
import { load } from "./exportedApi.js";
import { mockAppConfigurationClientListConfigurationSettings, restoreMocks, createMockedConnectionString, createMockedKeyVaultReference, createMockedJsonKeyValue } from "./utils/testHelper.js";

const jsonKeyValue = createMockedJsonKeyValue("json.settings.logging", '{"Test":{"Level":"Debug"},"Prod":{"Level":"Warning"}}');
const keyVaultKeyValue = createMockedKeyVaultReference("TestKey", "https://fake-vault-name.vault.azure.net/secrets/fakeSecretName");
Expand Down
6 changes: 3 additions & 3 deletions test/keyvault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { load } from "./exportedApi";
import { sinon, createMockedConnectionString, createMockedTokenCredential, mockAppConfigurationClientListConfigurationSettings, mockSecretClientGetSecret, restoreMocks, createMockedKeyVaultReference } from "./utils/testHelper";
import { load } from "./exportedApi.js";
import { sinon, createMockedConnectionString, createMockedTokenCredential, mockAppConfigurationClientListConfigurationSettings, mockSecretClientGetSecret, restoreMocks, createMockedKeyVaultReference } from "./utils/testHelper.js";
import { KeyVaultSecret, SecretClient } from "@azure/keyvault-secrets";

const mockedData = [
Expand Down Expand Up @@ -111,4 +111,4 @@ describe("key vault reference", function () {
expect(settings.get("TestKey")).eq("SecretValue");
expect(settings.get("TestKey2")).eq("SecretValue2");
});
});
});
4 changes: 2 additions & 2 deletions test/load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { load } from "./exportedApi";
import { mockAppConfigurationClientListConfigurationSettings, restoreMocks, createMockedConnectionString, createMockedEndpoint, createMockedTokenCredential, createMockedKeyValue } from "./utils/testHelper";
import { load } from "./exportedApi.js";
import { mockAppConfigurationClientListConfigurationSettings, restoreMocks, createMockedConnectionString, createMockedEndpoint, createMockedTokenCredential, createMockedKeyValue } from "./utils/testHelper.js";

const mockedKVs = [{
key: "app.settings.fontColor",
Expand Down
6 changes: 3 additions & 3 deletions test/refresh.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { load } from "./exportedApi";
import { mockAppConfigurationClientListConfigurationSettings, mockAppConfigurationClientGetConfigurationSetting, restoreMocks, createMockedConnectionString, createMockedKeyValue, sleepInMs, createMockedFeatureFlag } from "./utils/testHelper";
import { load } from "./exportedApi.js";
import { mockAppConfigurationClientListConfigurationSettings, mockAppConfigurationClientGetConfigurationSetting, restoreMocks, createMockedConnectionString, createMockedKeyValue, sleepInMs, createMockedFeatureFlag } from "./utils/testHelper.js";
import * as uuid from "uuid";

let mockedKVs: any[] = [];
Expand Down Expand Up @@ -423,4 +423,4 @@ describe("dynamic refresh feature flags", function () {
await settings.refresh();
expect(refreshSuccessfulCount).eq(1); // change in feature flags, because page etags are different.
});
});
});
18 changes: 16 additions & 2 deletions test/requestTracing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);
const expect = chai.expect;
import { createMockedConnectionString, createMockedKeyValue, createMockedTokenCredential, mockAppConfigurationClientListConfigurationSettings, restoreMocks, sleepInMs } from "./utils/testHelper";
import { load } from "./exportedApi";
import { createMockedConnectionString, createMockedKeyValue, createMockedTokenCredential, mockAppConfigurationClientListConfigurationSettings, restoreMocks, sleepInMs } from "./utils/testHelper.js";
import { load } from "./exportedApi.js";

class HttpRequestHeadersPolicy {
headers: any;
Expand Down Expand Up @@ -122,6 +122,20 @@ describe("request tracing", function () {
delete process.env.AZURE_APP_CONFIGURATION_TRACING_DISABLED;
});

it("should disable request tracing by RequestTracingOptions", async () => {
try {
await load(createMockedConnectionString(fakeEndpoint), {
clientOptions,
requestTracingOptions: {
enabled: false
}
});
} catch (e) { /* empty */ }
expect(headerPolicy.headers).not.undefined;
const correlationContext = headerPolicy.headers.get("Correlation-Context");
expect(correlationContext).undefined;
});

it("should have request type in correlation-context header when refresh is enabled", async () => {
mockAppConfigurationClientListConfigurationSettings([{
key: "app.settings.fontColor",
Expand Down
Loading