npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

azure-feature-flags

v1.4.0

Published

Fetch and validate feature flags managed via Azure App Configuration.

Downloads

57

Readme

Azure Feature Flags

Get/set and validate feature flags from Azure App Configuration.

View demo app: Use your own Azure App Configuration to see what Feature Flags are available and how they validate.

GitHub NPM JSR

Install

NPM

npm i azure-feature-flags
yarn add azure-feature-flags
bun add azure-feature-flags

JSR

npx jsr add @gs/azure-feature-flags
deno add @gs/azure-feature-flags

In all the examples below, the imports are done from azure-feature-flags package but for Deno, they need to be replaced with either npm:azure-feature-flags or @gs/azure-feature-flags.

class FeatureFlagService

Create and use a singular instance of service. It is wrapper around individually exported functions from service API and validation API.

For better tree-shaking, you can import individual functions from their respective entry-points.

import { FeatureFlagService } from "azure-feature-flags";

// FeatureFlagService service requires `client` of type
// `AppConfigurationClient` or `AppConfigurationClientLite`
// See Service API section for generating it.
const service = new FeatureFlagService(client);

const created = await service.set({ id: "flag-id", enabled: true });
const featureFlagsRecord = await service.getAllAsRecord();
const featureFlagsList = await service.getAllAsList();
const featureFlag = await service.getByKey("flag-id");
const enabledOrVariant = await service.getByKeyAndValidate("flag-id", {
  groups: ["admin"],
});
const deleted = await service.delete("flag-id");

Service API

The Service API directly interact with Azure App Config. All Service API accepts Azure App Configuration client as first parameter. It can be generated with the @azure/app-configuration package or via the internal tool.

Pros and cons of generating client with @azure/app-configuration package.

Pros:

  • Standard client that can be used with other Azure services
  • Maintained by Azure.
  • Decoupled with this library's maintenance.
  • Need to authenticate with Azure CredentialToken.

Cons:

  • Additional Bundle size of ~30kB (Gzipped) which is quite big for making couple of API calls
  • The internal tool is well suited/optimised for making Feature Flag specific calls to Azure App Config.

Create App configuration client

  • With internal tool (preferred)

    import { AppConfigurationClientLite } from "azure-feature-flags/client";
    
    const connectionString = process.env.AZURE_CONFIG_ACCESS_STRING;
    const client = new AppConfigurationClientLite(connectionString);
  • With "@azure/app-configuration" package

    import { AppConfigurationClient } from "@azure/app-configuration";
    
    const connectionString = process.env.AZURE_CONFIG_ACCESS_STRING;
    const client = new AppConfigurationClient(connectionString);

getFeatureFlagsRecord

Get all feature flags from Azure App Config and return them as a record.

import {
  getFeatureFlagsRecord,
  type FeatureFlagsRecord,
} from "azure-feature-flags/service";

const featureFlags: FeatureFlagsRecord = await getFeatureFlagsRecord(client);

getFeatureFlagsList

Get all feature flags from Azure App Config and return them as a list/array.

import {
  getFeatureFlagsList,
  type FeatureFlag,
} from "azure-feature-flags/service";

const featureFlags: FeatureFlag[] = await getFeatureFlagsList(client);

getFeatureFlagByKey

Get feature flag data for specific key.

import {
  getFeatureFlagByKey,
  type FeatureFlag,
} from "azure-feature-flags/service";

const featureFlagKey = "your-feature-flag-key";

const featureFlag: FeatureFlag | null = await getFeatureFlagByKey(
  client,
  featureFlagKey
);

setFeatureFlag

Set a new feature flag data or update existing one

import { setFeatureFlag, type FeatureFlag } from "azure-feature-flags/service";

const featureFlag: FeatureFlag = {
  id: "your-feature-flag-id",
  enabled: true,
  conditions: { client_filters: [] },
};

const success: boolean = await setFeatureFlag(client, featureFlag);

deleteFeatureFlag

Get feature flag data for specific key.

import { deleteFeatureFlag } from "azure-feature-flags/service";

const featureFlagKey = "your-feature-flag-key";

const deleted: boolean = await deleteFeatureFlag(client, featureFlagKey);

Validation API

validateFeatureFlag

Validate both types of Feature Flags - Filters and Variants. The function calls respective validators under the hood to do the heavy lifting.

Note: If you know which type of Feature Flag you wish to validate, then directly import and use validateFeatureFlagWithFilters for filters and validateFeatureFlagWithVariants for variants.

import { validateFeatureFlag } from "azure-feature-flags/validate";

const enabledOrVariant = await validateFeatureFlag(featureFlag);

validateFeatureFlagWithFilters

Validate a feature-flag object against filters/conditions.

Note: The function will throw if a custom filter is encountered without a validator. Hence, it is recommended to wrap the function call in try-catch for handling unsupported custom filters.

Note, all exports can be imported from root package azure-feature-flags but for sake of tree-shaking, they are made available from azure-feature-flags/validate

Default and TimeWindow filter

If filters are not set on the flag, the validation returns the value set in featureFlag.enabled. Otherwise, the TimeWindow filter is also tested against current time.

import { validateFeatureFlagWithFilters } from "azure-feature-flags/validate";

const isValid: boolean = await validateFeatureFlagWithFilters(featureFlag);

Targeting filter

When a group(s) or user(s) are provided, the value is matched against the targeted audiences (both included and excluded) set in the Azure App Config.

import { validateFeatureFlagWithFilters } from "azure-feature-flags/validate";

const isValid: boolean = await validateFeatureFlagWithFilters(featureFlag, {
  groups: ["editor"],
  users: ["user-id"],
});
Handle rollout

By default, for a given flag-key and groupName, the function generates a static hash. That hash is converted to a percentage and compare with rolloutPercentage. This is standard rollout method used in Azure's DotNet SDK.

Built-in handlers

The package exports some rollout handlers which can be used instead of creating your own.

  • handleRolloutWithIncrement

    Note: This handler is used by default.

    The numbers on incremented on both sides (true and false) according to their ratio until a limit has reached. Then the increments are reset and it begins again.

    For eg. For a 50% rollout, first run will be true, second be false, and then repeat. For a 75% rollout, first 3 runs will be true and then a false, and then repeat.

    import { validateFeatureFlagWithFilters } from "azure-feature-flags/validate";
    import { handleRolloutWithIncrement } from "azure-feature-flags/rollout";
    
    const isValid: boolean = await validateFeatureFlagWithFilters(featureFlag, {
      groups: ["editor"],
      handleRollout: handleRolloutWithIncrement,
    });
Custom handler
import {
  validateFeatureFlagWithFilters,
  type FeatureFlagHandleRollout,
} from "azure-feature-flags/validate";

const handleRollout: FeatureFlagHandleRollout = (
  flagKey,
  rolloutPercentage,
  groupName // groupName is `undefined` for `DefaultRolloutPercentage`.
) => {
  // logic to determine if the feature flag should be enabled or not.
  return groupName === "editor" && rolloutPercentage > Math.random() * 100;
};

const isValid: boolean = await validateFeatureFlagWithFilters(featureFlag, {
  groups: ["editor"],
  handleRollout,
});

Custom filter

Azure allows for custom filters and they need to be manually tested against. The function accepts an object of custom filters to test against.

The validator function received the filter object set in Azure Config as first argument, and groups & users are 2nd param.

import {
  validateFeatureFlagWithFilters,
  type FeatureFlagCustomFilterValidator,
} from "azure-feature-flags/validate";

const myFilterValidator: FeatureFlagCustomFilterValidator = async (
  filter,
  options
) => {
  // logic to determine if the feature flag should be enabled or not.
  return (
    filter.parameters["foo"] === "bar" && filter.parameters["abc"] !== "def"
  );
};

const isValid: boolean = await validateFeatureFlagWithFilters(featureFlag, {
  customFilterValidators: { "my-filter-name": myFilterValidator },
});

validateFeatureFlagWithVariants

This API is experimental and may change as the Variants feature of Azure App Configuration Feature Manager is under Preview.

import { validateFeatureFlagWithVariants } from "azure-feature-flags/validate";

// featureFlag with variants. It will throw if the flag is of other type (filters)
const variant = await validateFeatureFlagWithVariants(featureFlag, {
  groups: [],
  users: [],
});

The options accepts handleAllocate function to override the default allocation function. The default allocation function uses simple increments as per ratio between the allocation percentiles.

License

MIT © 2024 Siddhant Gupta (@GuptaSiddhant)

MIT License for Azure App Configuration SDK for JS