diff --git a/.changeset/rename-global-config.md b/.changeset/rename-global-config.md new file mode 100644 index 00000000..93eac5dd --- /dev/null +++ b/.changeset/rename-global-config.md @@ -0,0 +1,14 @@ +--- +'@flags-sdk/global-config': minor +'@flags-sdk/growthbook': major +'@flags-sdk/hypertune': patch +'@flags-sdk/launchdarkly': major +'@flags-sdk/posthog': patch +'@flags-sdk/reflag': patch +'@flags-sdk/statsig': major +'flags': major +--- + +Replace `@vercel/edge-config` with `@vercel/global-config`. + +Rename the Edge Config adapter package to `@flags-sdk/global-config` and rename repository-owned Edge Config files, exports, types, options, variables, and environment variables to Global Config. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f6a9479..722e785e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,7 +81,7 @@ jobs: env: NPM_CONFIG_PROVENANCE: "true" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - EDGE_CONFIG: ${{ secrets.EDGE_CONFIG }} + GLOBAL_CONFIG: ${{ secrets.GLOBAL_CONFIG }} FLAGS_SECRET: ${{ secrets.FLAGS_SECRET }} FLAGS: ${{ secrets.FLAGS }} HAPPYKIT_API_TOKEN: ${{ secrets.HAPPYKIT_API_TOKEN }} @@ -123,7 +123,7 @@ jobs: - name: Build run: pnpm turbo build --filter='./packages/*' env: - EDGE_CONFIG: ${{ secrets.EDGE_CONFIG }} + GLOBAL_CONFIG: ${{ secrets.GLOBAL_CONFIG }} FLAGS_SECRET: ${{ secrets.FLAGS_SECRET }} FLAGS: ${{ secrets.FLAGS }} HAPPYKIT_API_TOKEN: ${{ secrets.HAPPYKIT_API_TOKEN }} diff --git a/apps/docs/components/custom/provider-list.tsx b/apps/docs/components/custom/provider-list.tsx index 8d387ab8..921885ea 100644 --- a/apps/docs/components/custom/provider-list.tsx +++ b/apps/docs/components/custom/provider-list.tsx @@ -44,7 +44,7 @@ const providers: Provider[] = [ name: 'Vercel', href: '/providers/vercel', logo: VercelLogo, - badges: ['Adapter', 'Edge Config', 'Flags Explorer'], + badges: ['Adapter', 'Global Config', 'Flags Explorer'], glowColor: '#000000', skipInvert: true, }, @@ -53,7 +53,7 @@ const providers: Provider[] = [ name: 'Statsig', href: '/providers/statsig', logo: StatsigLogo, - badges: ['Adapter', 'Edge Config', 'Flags Explorer', 'Marketplace'], + badges: ['Adapter', 'Global Config', 'Flags Explorer', 'Marketplace'], glowColor: '#1b63d2', }, { @@ -61,7 +61,7 @@ const providers: Provider[] = [ name: 'Hypertune', href: '/providers/hypertune', logo: HypertuneLogo, - badges: ['Adapter', 'Edge Config', 'Flags Explorer', 'Marketplace'], + badges: ['Adapter', 'Global Config', 'Flags Explorer', 'Marketplace'], glowColor: '#000000', }, { @@ -69,7 +69,7 @@ const providers: Provider[] = [ name: 'LaunchDarkly', href: '/providers/launchdarkly', logo: LaunchDarklyLogo, - badges: ['Adapter', 'Edge Config', 'Flags Explorer'], + badges: ['Adapter', 'Global Config', 'Flags Explorer'], glowColor: '#7084ff', }, { @@ -77,7 +77,7 @@ const providers: Provider[] = [ name: 'GrowthBook', href: '/providers/growthbook', logo: GrowthbookLogo, - badges: ['Adapter', 'Edge Config', 'Flags Explorer', 'Marketplace'], + badges: ['Adapter', 'Global Config', 'Flags Explorer', 'Marketplace'], glowColor: '#7B51FB', }, { @@ -127,7 +127,7 @@ const providers: Provider[] = [ // name: 'Split', // href: '/providers/split', // logo: SplitLogo, - // badges: ['Edge Config', 'Flags Explorer'], + // badges: ['Global Config', 'Flags Explorer'], // glowColor: '#ff00d2', // }, ]; diff --git a/apps/docs/content/docs/frameworks/next/guides/dashboard-pages.mdx b/apps/docs/content/docs/frameworks/next/guides/dashboard-pages.mdx index c11f6db5..b3d40412 100644 --- a/apps/docs/content/docs/frameworks/next/guides/dashboard-pages.mdx +++ b/apps/docs/content/docs/frameworks/next/guides/dashboard-pages.mdx @@ -41,7 +41,7 @@ export const dashboardFlag = flag({ identify, decide({ entities }) { if (!entities?.user) return false; - // Allowed users could be loaded from Edge Config or elsewhere + // Allowed users could be loaded from Global Config or elsewhere const allowedUsers = ['user1']; return allowedUsers.includes(entities.user.id); diff --git a/apps/docs/content/docs/principles/data-locality.mdx b/apps/docs/content/docs/principles/data-locality.mdx index 87f98bcd..e41872c2 100644 --- a/apps/docs/content/docs/principles/data-locality.mdx +++ b/apps/docs/content/docs/principles/data-locality.mdx @@ -51,17 +51,17 @@ applications need to pay the latency cost of bootstrapping feature flags more frequently. Having multiple websocket connections to the same flag provider also increases load on the provider. -## Vercel Edge Config +## Vercel Global Config -Vercel offers a solution called Edge Config to this problem. It is -specifically designed for storing feature flag definitions. Edge Config +Vercel offers a solution called Global Config to this problem. It is +specifically designed for storing feature flag definitions. Global Config can be read in under 1ms at p90 and under 15ms at p95, including the network latency from your Serverless Function or Routing Middleware. To put this into perspective, [according to this benchmark](https://github.com/dvassallo/s3-benchmark), an AWS S3 bucket does not even send the first byte by the time an Edge Config is fully read. -Using Edge Config is optional, but highly recommended, when using the +Using Global Config is optional, but highly recommended, when using the Flags SDK. ## Evaluating on the server @@ -79,7 +79,7 @@ request to establish the evaluation context. To evaluate feature flags at the edge, you need the definition and the evaluation context available at the edge. -Using Edge Config allows storing definitions at the Edge as shown in the +Using Global Config allows storing definitions at the Edge as shown in the previous section. This means you can use feature flags in Routing Functions at ultra low latency. diff --git a/apps/docs/content/docs/providers/custom-adapters.mdx b/apps/docs/content/docs/providers/custom-adapters.mdx index 92967e60..472fe548 100644 --- a/apps/docs/content/docs/providers/custom-adapters.mdx +++ b/apps/docs/content/docs/providers/custom-adapters.mdx @@ -27,7 +27,7 @@ Creating custom adapters is possible by creating an adapter factory: ```ts title="example-adapter.ts" import type { Adapter } from "flags"; -import { createClient, EdgeConfigClient } from "@vercel/edge-config"; +import { createClient, GlobalConfigClient } from "@vercel/global-config"; /** * A factory function for your adapter @@ -108,7 +108,7 @@ return { ## Example -Below is an example of an Flags SDK adapter reading Edge Config. +Below is an example of an Flags SDK adapter reading Global Config. +let defaultGlobalConfigAdapter: + | ReturnType | undefined; /** - * A default Vercel adapter for Edge Config + * A default Vercel adapter for Global Config * */ -export function edgeConfigAdapter(): Adapter< +export function globalConfigAdapter(): Adapter< ValueType, EntitiesType > { // Initialized lazily to avoid warning when it is not actually used and env vars are missing. - if (!defaultEdgeConfigAdapter) { - if (!process.env.EDGE_CONFIG) { - throw new Error("Edge Config Adapter: Missing EDGE_CONFIG env var"); + if (!defaultGlobalConfigAdapter) { + if (!process.env.GLOBAL_CONFIG) { + throw new Error("Global Config Adapter: Missing GLOBAL_CONFIG env var"); } - defaultEdgeConfigAdapter = createEdgeConfigAdapter(process.env.EDGE_CONFIG); + defaultGlobalConfigAdapter = createGlobalConfigAdapter(process.env.GLOBAL_CONFIG); } - return defaultEdgeConfigAdapter(); + return defaultGlobalConfigAdapter(); } ``` diff --git a/apps/docs/content/docs/providers/edge-config.mdx b/apps/docs/content/docs/providers/edge-config.mdx deleted file mode 100644 index ffd28cc4..00000000 --- a/apps/docs/content/docs/providers/edge-config.mdx +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: 'Edge Config' ---- - -The `@flags-sdk/edge-config` package provides a basic adapter for defining feature flags powered by [Vercel Edge Config](https://vercel.com/docs/storage/edge-config) - - - Learn more about Adapters - - -## Installation - -Follow the [Quickstart](/docs/getting-started/next), then add the [Edge Config adapter](https://github.com/vercel/flags/tree/main/packages/adapter-edge-config). - -Install desired dependencies - -```sh -pnpm i @flags-sdk/edge-config -``` - -Set relevant variables - -```sh title=".env.local" -EDGE_CONFIG="edge-config-connection-string" -``` - -## Usage - -```ts title="flags.ts#next" -import { flag } from 'flags/next'; -import { edgeConfigAdapter } from '@flags-sdk/edge-config'; - -export const exampleFlag = flag({ - // Will load the `flags` key from Edge Config - adapter: edgeConfigAdapter, - // Will get the `example-flag` key from the `flags` object - key: 'example-flag', -}); -``` - -Your Edge Config should be [managed on the dashboard](https://vercel.com/docs/storage/edge-config/edge-config-dashboard) as follows: - -```json -{ - // `flags` is the default used by the Edge Config adapter - "flags": { - // Flags using the adapter should have their `key` defined here - "example-flag": true, - "another-example-flag": false, - } -} -``` - -## API reference - -### edgeConfigAdapter - -The adapter assumes that there is an `EDGE_CONFIG` environment variable set with a connection string, -and that it contains a `flags` object with each key corresponding to a flag you define in code. - -```ts title="flags.ts#next" -import { edgeConfigAdapter } from '@flags-sdk/edge-config'; - -export const exampleFlag = flag({ - adapter: edgeConfigAdapter, - key: 'example-flag', -}); -``` - -### createEdgeConfigAdapter - -To customize these options you can import and call `createEdgeConfigAdapter` manually. - -| Option key | Type | Description | -| ----------- | -------- | ----------------------- | -| `connectionString` | `string | EdgeConfigClient` | A [connection string](https://vercel.com/docs/storage/edge-config/using-edge-config#using-a-connection-string) or a [client instance](https://vercel.com/docs/storage/edge-config/edge-config-sdk#use-connection-strings) | -| `options.edgeConfigItemKey` | `string` | Defaults to `flags` | -| `options.teamSlug` | `string` | The team slug used for your team in the Vercel dashboard, used to create links to your Edge Config | - -```ts title="flags.ts#next" -import { createEdgeConfigAdapter } from '@flags-sdk/edge-config'; - -const myEdgeConfigAdapter = createEdgeConfigAdapter({ - connectionString: process.env.OTHER_EDGE_CONFIG_CONNECTION_STRING, - options: { - edgeConfigItemKey: 'other-flags-key', - teamSlug: 'my-vercel-team-slug', - }, -}); - -export const exampleFlag = flag({ - adapter: myEdgeConfigAdapter, - key: 'example-flag', -}); -``` - -## Read more - -Read more about Edge Config, Flags SDK, and the Edge Config adapter. - -- [Concepts: Precompute](/principles/precompute) -- [Edge Config Docs](https://vercel.com/docs/storage/edge-config) -- [Edge Config SDK Reference](https://vercel.com/docs/storage/edge-config/edge-config-sdk) -- [Edge Config Examples](https://vercel.com/templates/edge-config) -- [Edge Config Limits and Pricing](https://vercel.com/docs/storage/edge-config/edge-config-limits) diff --git a/apps/docs/content/docs/providers/global-config.mdx b/apps/docs/content/docs/providers/global-config.mdx new file mode 100644 index 00000000..6fb85255 --- /dev/null +++ b/apps/docs/content/docs/providers/global-config.mdx @@ -0,0 +1,108 @@ +--- +title: 'Global Config' +--- + +The `@flags-sdk/global-config` package provides a basic adapter for defining feature flags powered by [Vercel Global Config](https://vercel.com/docs/storage/global-config) + + + Learn more about Adapters + + +## Installation + +Follow the [Quickstart](/docs/getting-started/next), then add the [Global Config adapter](https://github.com/vercel/flags/tree/main/packages/adapter-global-config). + +Install desired dependencies + +```sh +pnpm i @flags-sdk/global-config +``` + +Set relevant variables + +```sh title=".env.local" +GLOBAL_CONFIG="global-config-connection-string" +``` + +## Usage + +```ts title="flags.ts#next" +import { flag } from 'flags/next'; +import { globalConfigAdapter } from '@flags-sdk/global-config'; + +export const exampleFlag = flag({ + // Will load the `flags` key from Global Config + adapter: globalConfigAdapter, + // Will get the `example-flag` key from the `flags` object + key: 'example-flag', +}); +``` + +Your Global Config should be [managed on the dashboard](https://vercel.com/docs/storage/global-config/global-config-dashboard) as follows: + +```json +{ + // `flags` is the default used by the Global Config adapter + "flags": { + // Flags using the adapter should have their `key` defined here + "example-flag": true, + "another-example-flag": false, + } +} +``` + +## API reference + +### globalConfigAdapter + +The adapter assumes that there is an `GLOBAL_CONFIG` environment variable set with a connection string, +and that it contains a `flags` object with each key corresponding to a flag you define in code. + +```ts title="flags.ts#next" +import { globalConfigAdapter } from '@flags-sdk/global-config'; + +export const exampleFlag = flag({ + adapter: globalConfigAdapter, + key: 'example-flag', +}); +``` + +### createGlobalConfigAdapter + +To customize these options you can import and call `createGlobalConfigAdapter` manually. + +| Option key | Type | Description | +| ----------- | -------- | ----------------------- | +| `connectionString` | `string | GlobalConfigClient` | A [connection string](https://vercel.com/docs/storage/global-config/using-global-config#using-a-connection-string) or a [client instance](https://vercel.com/docs/storage/global-config/global-config-sdk#use-connection-strings) | +| `options.globalConfigItemKey` | `string` | Defaults to `flags` | +| `options.teamSlug` | `string` | The team slug used for your team in the Vercel dashboard, used to create links to your Global Config | + +```ts title="flags.ts#next" +import { createGlobalConfigAdapter } from '@flags-sdk/global-config'; + +const myGlobalConfigAdapter = createGlobalConfigAdapter({ + connectionString: process.env.OTHER_GLOBAL_CONFIG_CONNECTION_STRING, + options: { + globalConfigItemKey: 'other-flags-key', + teamSlug: 'my-vercel-team-slug', + }, +}); + +export const exampleFlag = flag({ + adapter: myGlobalConfigAdapter, + key: 'example-flag', +}); +``` + +## Read more + +Read more about Global Config, Flags SDK, and the Global Config adapter. + +- [Concepts: Precompute](/principles/precompute) +- [Global Config Docs](https://vercel.com/docs/storage/global-config) +- [Global Config SDK Reference](https://vercel.com/docs/storage/global-config/global-config-sdk) +- [Global Config Examples](https://vercel.com/templates/global-config) +- [Global Config Limits and Pricing](https://vercel.com/docs/storage/global-config/global-config-limits) diff --git a/apps/docs/content/docs/providers/growthbook.mdx b/apps/docs/content/docs/providers/growthbook.mdx index 2a495cd8..1afe1bcd 100644 --- a/apps/docs/content/docs/providers/growthbook.mdx +++ b/apps/docs/content/docs/providers/growthbook.mdx @@ -2,7 +2,7 @@ title: 'GrowthBook' --- -The GrowthBook adapter integrates [GrowthBook](https://www.growthbook.io/) with the Flags SDK, enabling feature flagging, experimentation, and configuration management in your application. This adapter lets you evaluate feature flags and experiments, with support for server-side, client-side, and Edge Config bootstrapping. +The GrowthBook adapter integrates [GrowthBook](https://www.growthbook.io/) with the Flags SDK, enabling feature flagging, experimentation, and configuration management in your application. This adapter lets you evaluate feature flags and experiments, with support for server-side, client-side, and Global Config bootstrapping. GrowthBook is an open-source feature flagging and experimentation platform that helps you safely roll out features, run A/B tests, and manage configuration at scale. @@ -41,9 +41,9 @@ The default adapter considers the following environment variables: | `GROWTHBOOK_CLIENT_KEY` | **Required.** GrowthBook SDK key | | `GROWTHBOOK_API_HOST` | Optional. Override the GrowthBook API endpoint | | `GROWTHBOOK_APP_ORIGIN` | Optional. Override the GrowthBook app URL | -| `GROWTHBOOK_EDGE_CONNECTION_STRING` | Optional. Edge Config connection string | -| `GROWTHBOOK_EDGE_CONFIG_ITEM_KEY` | Optional. Edge Config item key (Defaults to your client key) | -| `EXPERIMENTATION_CONFIG` | Optional. Used when installed through Vercel Marketplace (replaces GROWTHBOOK_EDGE_CONNECTION_STRING) | +| `GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING` | Optional. Global Config connection string | +| `GROWTHBOOK_GLOBAL_CONFIG_ITEM_KEY` | Optional. Global Config item key (Defaults to your client key) | +| `EXPERIMENTATION_CONFIG` | Optional. Used when installed through Vercel Marketplace (replaces GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING) | ### Create a custom adapter @@ -56,9 +56,9 @@ const myGrowthBookAdapter = createGrowthbookAdapter({ clientKey: process.env.GROWTHBOOK_CLIENT_KEY!, apiHost: process.env.GROWTHBOOK_API_HOST, // optional appOrigin: process.env.GROWTHBOOK_APP_ORIGIN, // optional - edgeConfig: { - connectionString: process.env.GROWTHBOOK_EDGE_CONNECTION_STRING!, - itemKey: process.env.GROWTHBOOK_EDGE_CONFIG_ITEM_KEY, // optional + globalConfig: { + connectionString: process.env.GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING!, + itemKey: process.env.GROWTHBOOK_GLOBAL_CONFIG_ITEM_KEY, // optional }, trackingCallback: (experiment, result) => { // Custom exposure logging @@ -174,21 +174,21 @@ You may access the underlying GrowthBook instance. Specifically, the GrowthBook If you have set a sticky bucket service, you may retrieve its instance here. -## Edge Config +## Global Config -The adapter can load feature configuration from [Vercel Edge Config](https://vercel.com/docs/storage/edge-config) to lower the latency of feature flag evaluation. +The adapter can load feature configuration from [Vercel Global Config](https://vercel.com/docs/storage/global-config) to lower the latency of feature flag evaluation. -- Set `GROWTHBOOK_EDGE_CONNECTION_STRING` (or `EXPERIMENTATION_CONFIG` if installed through the Vercel Marketplace) in your environment. Optionally set `GROWTHBOOK_EDGE_CONFIG_ITEM_KEY` to override the default key name (defaults to your client key). -- Or pass `edgeConfig` directly to the adapter. +- Set `GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING` (or `EXPERIMENTATION_CONFIG` if installed through the Vercel Marketplace) in your environment. Optionally set `GROWTHBOOK_GLOBAL_CONFIG_ITEM_KEY` to override the default key name (defaults to your client key). +- Or pass `globalConfig` directly to the adapter. -If Edge Config is not set, the adapter will fetch configuration from GrowthBook's API. +If Global Config is not set, the adapter will fetch configuration from GrowthBook's API. ### Configuring a SDK Webhook -1. To automatically populate the Edge Config whenever your feature definitions change, create a GrowthBook [SDK Webhook](https://docs.growthbook.io/app/webhooks/sdk-webhooks) on the same SDK Connection that you are using for the Next.js integration.ts +1. To automatically populate the Global Config whenever your feature definitions change, create a GrowthBook [SDK Webhook](https://docs.growthbook.io/app/webhooks/sdk-webhooks) on the same SDK Connection that you are using for the Next.js integration.ts -2. Select "Vercel Edge Config" as the webhook type and fill out the following fields: -- Vercel Edge Config ID (begins with `ecfg_`) +2. Select "Vercel Global Config" as the webhook type and fill out the following fields: +- Vercel Global Config ID (begins with `ecfg_`) - Team ID (optional) - Vercel API Token (see Vercel → Account Settings → Tokens) @@ -196,11 +196,11 @@ Under the hood, the webhook is being configured with the following properties. I - **Endpoint URL** is being set to ``` - https://api.vercel.com/v1/edge-config/{edge_config_id}/items + https://api.vercel.com/v1/global-config/{global_config_id}/items ``` - **Method** is being set to `PATCH` - An **Authorization: Bearer token** header is being added with your Vercel API Token -- The **Payload format** is being set to `Vercel Edge Config` +- The **Payload format** is being set to `Vercel Global Config` ## Caveats and best practices @@ -233,6 +233,6 @@ export const GET = createFlagsDiscoveryEndpoint(async (request) => { - [GrowthBook Documentation](https://docs.growthbook.io/) - [GrowthBook JS SDK Reference](https://docs.growthbook.io/lib/js) -- [Vercel Edge Config](https://vercel.com/docs/storage/edge-config) +- [Vercel Global Config](https://vercel.com/docs/storage/global-config) - [Flags Explorer](https://vercel.com/docs/flags/flags-explorer) - [Deploy the GrowthBook template](https://vercel.com/templates/next.js/growthbook-flags-sdk-example) diff --git a/apps/docs/content/docs/providers/hypertune.mdx b/apps/docs/content/docs/providers/hypertune.mdx index f00d43fd..c62097de 100644 --- a/apps/docs/content/docs/providers/hypertune.mdx +++ b/apps/docs/content/docs/providers/hypertune.mdx @@ -13,7 +13,7 @@ The `@flags-sdk/hypertune` package provides a managed [Hypertune](https://www.hy Install the required dependencies: ```bash -pnpm i hypertune flags server-only @flags-sdk/hypertune @vercel/edge-config +pnpm i hypertune flags server-only @flags-sdk/hypertune @vercel/global-config ``` Set up Hypertune environment variables based on your framework and app structure: @@ -98,18 +98,18 @@ export const GET = createFlagsDiscoveryEndpoint(() => { Learn more about the Flags Explorer -## How to configure Edge Config +## How to configure Global Config -If Hypertune is syncing to Vercel Edge Config, you can configure that through environment variables or through the adapter. +If Hypertune is syncing to Vercel Global Config, you can configure that through environment variables or through the adapter. ```bash title=".env.local" -EXPERIMENTATION_CONFIG="https://edge-config.vercel.com/ecfg_xyz?token=abc" +EXPERIMENTATION_CONFIG="https://global-config.vercel.com/ecfg_xyz?token=abc" EXPERIMENTATION_CONFIG_ITEM_KEY="hypertune_99999" ``` ```ts title="flags.ts" -import { VercelEdgeConfigInitDataProvider } from 'hypertune' -import { createClient } from "@vercel/edge-config" +import { VercelEdgeConfigInitDataProvider as VercelGlobalConfigInitDataProvider } from 'hypertune' +import { createClient } from "@vercel/global-config" const hypertuneAdapter = createHypertuneAdapter< FlagValues, @@ -117,9 +117,9 @@ const hypertuneAdapter = createHypertuneAdapter< >({ // ... previous initialization code createSourceOptions: { - initDataProvider: new VercelEdgeConfigInitDataProvider({ + initDataProvider: new VercelGlobalConfigInitDataProvider({ edgeConfigClient: createClient( - 'https://edge-config.vercel.com/ecfg_xyz?token=abc' + 'https://global-config.vercel.com/ecfg_xyz?token=abc' ), itemKey: 'hypertune_99999', }), @@ -130,6 +130,6 @@ const hypertuneAdapter = createHypertuneAdapter< ## More resources - [Hypertune Documentation](https://docs.hypertune.com/) -- [Vercel Edge Config](https://vercel.com/docs/edge-config) +- [Vercel Global Config](https://vercel.com/docs/global-config) - [Flags Explorer](https://vercel.com/docs/flags/flags-explorer) - [Hypertune OpenFeature Provider](/providers/openfeature/hypertune) diff --git a/apps/docs/content/docs/providers/index.mdx b/apps/docs/content/docs/providers/index.mdx index 6f988fb1..f3bca0ca 100644 --- a/apps/docs/content/docs/providers/index.mdx +++ b/apps/docs/content/docs/providers/index.mdx @@ -11,14 +11,14 @@ your provider or in case you have an in-house solution for feature flags. ## Featured providers Featured providers offer fast setup using [Vercel Marketplace](https://vercel.com/marketplace/category/experimentation), -and low latency with Edge Config. They also work well outside of Vercel in Next.js and SvelteKit projects. +and low latency with Global Config. They also work well outside of Vercel in Next.js and SvelteKit projects. ## Additional providers Additional providers are published under the `@flags-sdk` npm scope in the [Flags SDK repository](https://github.com/vercel/flags) and offer different levels of -integration with Next.js, SvelteKit, and Edge Config. +integration with Next.js, SvelteKit, and Global Config. @@ -26,4 +26,4 @@ integration with Next.js, SvelteKit, and Edge Config. - **Adapter** - Lets you evaluate feature flags and experiments using the Flags SDK. - **Flags Explorer** - Displays flag metadata like descriptions in the [Flags Explorer](https://vercel.com/docs/flags/flags-explorer). - **Marketplace** - Available in the Vercel Marketplace. -- **Edge Config** - Lets you read feature flags from an Edge Config. +- **Global Config** - Lets you read feature flags from an Global Config. diff --git a/apps/docs/content/docs/providers/launchdarkly.mdx b/apps/docs/content/docs/providers/launchdarkly.mdx index b367d232..adc00e43 100644 --- a/apps/docs/content/docs/providers/launchdarkly.mdx +++ b/apps/docs/content/docs/providers/launchdarkly.mdx @@ -49,10 +49,10 @@ import { createLaunchDarklyAdapter } from '@flags-sdk/launchdarkly'; const customLdAdapter = createLaunchDarklyAdapter({ projectSlug: process.env.LAUNCHDARKLY_PROJECT_SLUG, clientSideId: process.env.LAUNCHDARKLY_CLIENT_SIDE_ID, - // Legacy integrations that provide the connection string as `EDGE_CONFIG` + // Legacy integrations that provide the connection string as `GLOBAL_CONFIG` // can pass it explicitly here. - edgeConfigConnectionString: - process.env.EXPERIMENTATION_CONFIG ?? process.env.EDGE_CONFIG, + globalConfigConnectionString: + process.env.EXPERIMENTATION_CONFIG ?? process.env.GLOBAL_CONFIG, }); ``` @@ -60,17 +60,17 @@ const customLdAdapter = createLaunchDarklyAdapter({ | ---------------------------- | ---------| ------------------------------------------------------------------ | | `projectSlug` | `string` | LaunchDarkly project slug | | `clientSideId` | `string` | LaunchDarkly client-side ID | -| `edgeConfigConnectionString` | `string` | Edge Config connection string | +| `globalConfigConnectionString` | `string` | Global Config connection string | The default LaunchDarkly adapter configures itself based on the following environment variables: - `LAUNCHDARKLY_CLIENT_SIDE_ID` _(required)_ → `clientSideId` - `LAUNCHDARKLY_PROJECT_SLUG` _(required)_ → `projectSlug` -- `EXPERIMENTATION_CONFIG` _(required)_ → `edgeConfigConnectionString` +- `EXPERIMENTATION_CONFIG` _(required)_ → `globalConfigConnectionString` -The native LaunchDarkly [Marketplace integration](https://vercel.com/marketplace/launchdarkly) exposes the Edge Config connection string as `EXPERIMENTATION_CONFIG` when Edge Config is enabled for the collection. +The native LaunchDarkly [Marketplace integration](https://vercel.com/marketplace/launchdarkly) exposes the Global Config connection string as `EXPERIMENTATION_CONFIG` when Global Config is enabled for the collection. -If you use the legacy LaunchDarkly Vercel integration, which provides the connection string as `EDGE_CONFIG`, set `EXPERIMENTATION_CONFIG` to the same value, or use `createLaunchDarklyAdapter` to pass `edgeConfigConnectionString` explicitly. +If you use the legacy LaunchDarkly Vercel integration, which provides the connection string as `GLOBAL_CONFIG`, set `EXPERIMENTATION_CONFIG` to the same value, or use `createLaunchDarklyAdapter` to pass `globalConfigConnectionString` explicitly. --- @@ -144,13 +144,13 @@ ldAdapter.ldClient; --- -## Edge Config +## Global Config -The LaunchDarkly adapter loads the configuration from [Edge Config](https://vercel.com/storage/edge-config). +The LaunchDarkly adapter loads the configuration from [Global Config](https://vercel.com/storage/global-config). -Edge Config is a global, ultra-low latency store which uses active replication and is specifically designed for serving feature flag configuration. +Global Config is a global, ultra-low latency store which uses active replication and is specifically designed for serving feature flag configuration. -The default LaunchDarkly adapter, exported as `ldAdapter`, will automatically connect to Edge Config when the required environment variables are set. It reads the connection string from `EXPERIMENTATION_CONFIG` (provided by the native Marketplace integration). +The default LaunchDarkly adapter, exported as `ldAdapter`, will automatically connect to Global Config when the required environment variables are set. It reads the connection string from `EXPERIMENTATION_CONFIG` (provided by the native Marketplace integration). --- @@ -172,7 +172,7 @@ await ldAdapter.ldClient.waitForInitialization(); ### LaunchDarkly Vercel SDK -The adapter uses the [LaunchDarkly Vercel SDK](https://launchdarkly.com/docs/sdk/edge/vercel) (`@launchdarkly/vercel-server-sdk`) internally, which is designed for usage with Edge Config. +The adapter uses the [LaunchDarkly Vercel SDK](https://launchdarkly.com/docs/sdk/edge/vercel) (`@launchdarkly/vercel-server-sdk`) internally, which is designed for usage with Global Config. --- diff --git a/apps/docs/content/docs/providers/meta.json b/apps/docs/content/docs/providers/meta.json index 14236ac7..15d506d7 100644 --- a/apps/docs/content/docs/providers/meta.json +++ b/apps/docs/content/docs/providers/meta.json @@ -11,7 +11,7 @@ "statsig", "hypertune", "growthbook", - "edge-config", + "global-config", "---Adapters---", "launchdarkly", "reflag", diff --git a/apps/docs/content/docs/providers/openfeature/abtasty.mdx b/apps/docs/content/docs/providers/openfeature/abtasty.mdx index 34ddcc10..bd1daa71 100644 --- a/apps/docs/content/docs/providers/openfeature/abtasty.mdx +++ b/apps/docs/content/docs/providers/openfeature/abtasty.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/cloudbees.mdx b/apps/docs/content/docs/providers/openfeature/cloudbees.mdx index c91c8fe5..bc3f17a7 100644 --- a/apps/docs/content/docs/providers/openfeature/cloudbees.mdx +++ b/apps/docs/content/docs/providers/openfeature/cloudbees.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/confidence-by-spotify.mdx b/apps/docs/content/docs/providers/openfeature/confidence-by-spotify.mdx index 9c24b8de..759dd448 100644 --- a/apps/docs/content/docs/providers/openfeature/confidence-by-spotify.mdx +++ b/apps/docs/content/docs/providers/openfeature/confidence-by-spotify.mdx @@ -84,7 +84,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/configcat.mdx b/apps/docs/content/docs/providers/openfeature/configcat.mdx index c410dd9d..d208a0d9 100644 --- a/apps/docs/content/docs/providers/openfeature/configcat.mdx +++ b/apps/docs/content/docs/providers/openfeature/configcat.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/devcycle.mdx b/apps/docs/content/docs/providers/openfeature/devcycle.mdx index d1acabca..65a3390e 100644 --- a/apps/docs/content/docs/providers/openfeature/devcycle.mdx +++ b/apps/docs/content/docs/providers/openfeature/devcycle.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/featbit.mdx b/apps/docs/content/docs/providers/openfeature/featbit.mdx index e760b57a..64186757 100644 --- a/apps/docs/content/docs/providers/openfeature/featbit.mdx +++ b/apps/docs/content/docs/providers/openfeature/featbit.mdx @@ -85,7 +85,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/flagd.mdx b/apps/docs/content/docs/providers/openfeature/flagd.mdx index c3d7424f..5da99238 100644 --- a/apps/docs/content/docs/providers/openfeature/flagd.mdx +++ b/apps/docs/content/docs/providers/openfeature/flagd.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/flipt.mdx b/apps/docs/content/docs/providers/openfeature/flipt.mdx index e5e52805..1bbef72c 100644 --- a/apps/docs/content/docs/providers/openfeature/flipt.mdx +++ b/apps/docs/content/docs/providers/openfeature/flipt.mdx @@ -84,7 +84,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/go.mdx b/apps/docs/content/docs/providers/openfeature/go.mdx index 7743c160..69d788e2 100644 --- a/apps/docs/content/docs/providers/openfeature/go.mdx +++ b/apps/docs/content/docs/providers/openfeature/go.mdx @@ -82,7 +82,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/growthbook.mdx b/apps/docs/content/docs/providers/openfeature/growthbook.mdx index c6e91e58..aa3be183 100644 --- a/apps/docs/content/docs/providers/openfeature/growthbook.mdx +++ b/apps/docs/content/docs/providers/openfeature/growthbook.mdx @@ -103,7 +103,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/hypertune.mdx b/apps/docs/content/docs/providers/openfeature/hypertune.mdx index 032915f6..13af5bba 100644 --- a/apps/docs/content/docs/providers/openfeature/hypertune.mdx +++ b/apps/docs/content/docs/providers/openfeature/hypertune.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/index.mdx b/apps/docs/content/docs/providers/openfeature/index.mdx index 55858f3e..31d0435a 100644 --- a/apps/docs/content/docs/providers/openfeature/index.mdx +++ b/apps/docs/content/docs/providers/openfeature/index.mdx @@ -9,7 +9,7 @@ title: 'OpenFeature' -_If there is a native Flags SDK adapter for your provider, we recommend using that instead. Native Flags SDK adapters finely tune the SDK for your flag provider, optionally integrate with Edge Config and Flags Explorer, and are configured for Edge Runtime compatibility where possible. See [available adapters](/docs/adapters/supported-providers#adapters)_ +_If there is a native Flags SDK adapter for your provider, we recommend using that instead. Native Flags SDK adapters finely tune the SDK for your flag provider, optionally integrate with Global Config and Flags Explorer, and are configured for Edge Runtime compatibility where possible. See [available adapters](/docs/adapters/supported-providers#adapters)_ The `@flags-sdk/openfeature` package provides an [adapter](#provider-instance) for loading flags from OpenFeature. @@ -199,13 +199,13 @@ await openFeatureAdapter.client(); --- -## Edge Config +## Global Config -The OpenFeature adapter does not integrate with Edge Config directly. +The OpenFeature adapter does not integrate with Global Config directly. -We recommend using a native Flags SDK adapter for your provider instead of using the OpenFeature adapter. Native Flags SDK adapters finely tune the SDK for your flag provider, optionally integrate with Edge Config and Flags Explorer, and are configured for Edge Runtime compatibility where possible. See [available adapters](/docs/adapters/supported-providers#adapters). +We recommend using a native Flags SDK adapter for your provider instead of using the OpenFeature adapter. Native Flags SDK adapters finely tune the SDK for your flag provider, optionally integrate with Global Config and Flags Explorer, and are configured for Edge Runtime compatibility where possible. See [available adapters](/docs/adapters/supported-providers#adapters). -If no native Flags SDK adapter is available, your OpenFeature provider might still allow you to configure Edge Config integration. +If no native Flags SDK adapter is available, your OpenFeature provider might still allow you to configure Global Config integration. --- diff --git a/apps/docs/content/docs/providers/openfeature/kameloon.mdx b/apps/docs/content/docs/providers/openfeature/kameloon.mdx index 7e26a837..04382c18 100644 --- a/apps/docs/content/docs/providers/openfeature/kameloon.mdx +++ b/apps/docs/content/docs/providers/openfeature/kameloon.mdx @@ -84,7 +84,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/posthog.mdx b/apps/docs/content/docs/providers/openfeature/posthog.mdx index 742fc2ee..05e4477c 100644 --- a/apps/docs/content/docs/providers/openfeature/posthog.mdx +++ b/apps/docs/content/docs/providers/openfeature/posthog.mdx @@ -81,7 +81,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/split.mdx b/apps/docs/content/docs/providers/openfeature/split.mdx index ebe1061c..66cda5dd 100644 --- a/apps/docs/content/docs/providers/openfeature/split.mdx +++ b/apps/docs/content/docs/providers/openfeature/split.mdx @@ -86,7 +86,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/openfeature/tggl.mdx b/apps/docs/content/docs/providers/openfeature/tggl.mdx index 9f4ff1fb..3abf5e53 100644 --- a/apps/docs/content/docs/providers/openfeature/tggl.mdx +++ b/apps/docs/content/docs/providers/openfeature/tggl.mdx @@ -82,7 +82,7 @@ export const exampleFlag = flag({ _Note that OpenFeature providers may require additional configuration for optimal performance and compatibility. Setup instructions are provided on a best effort basis. Refer to each provider's own documentation._ _If there is a native Flags SDK adapter for your provider, we recommend using that instead. -Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Edge Config. +Native Flags SDK adapters tune your flag provider's SDK for optimal performance and integrate with Flags Explorer and Global Config. See [available adapters](/docs/adapters/supported-providers#adapters)._ _If you are a feature flag provider interested in developing a native adapter please [open a GitHub issue](https://github.com/vercel/flags) to get in touch._ diff --git a/apps/docs/content/docs/providers/statsig.mdx b/apps/docs/content/docs/providers/statsig.mdx index 738b5163..2646ee13 100644 --- a/apps/docs/content/docs/providers/statsig.mdx +++ b/apps/docs/content/docs/providers/statsig.mdx @@ -66,16 +66,16 @@ const statsigAdapter = createStatsigAdapter({ | `statsigServerApiKey` | `string` | Statsig server secret key | | `statsigOptions` | `StatsigOptions` | Statsig initialization options | | `statsigProjectId` | `string` | Statsig project ID | -| `edgeConfig` | `object` | Edge Config details for use with Statsig's Edge Config integration | -| `edgeConfig.connectionString` | `string` | Edge Config connection string | -| `edgeConfig.itemKey` | `string` | Key under which the Statsig configuration is stored in Edge Config | +| `globalConfig` | `object` | Global Config details for use with Statsig's Global Config integration | +| `globalConfig.connectionString` | `string` | Global Config connection string | +| `globalConfig.itemKey` | `string` | Key under which the Statsig configuration is stored in Global Config | The default statsig adapter configures itself based on the following environment variables: - `STATSIG_SERVER_API_KEY` _(required)_ → `statsigServerApiKey` - `STATSIG_PROJECT_ID` _(optional)_ → `statsigProjectId` -- `EXPERIMENTATION_CONFIG` _(optional)_ → `edgeConfig.connectionString` -- `EXPERIMENTATION_CONFIG_ITEM_KEY` _(optional)_ → `edgeConfig.itemKey` +- `EXPERIMENTATION_CONFIG` _(optional)_ → `globalConfig.connectionString` +- `EXPERIMENTATION_CONFIG_ITEM_KEY` _(optional)_ → `globalConfig.itemKey` --- @@ -354,13 +354,13 @@ Read more about initialization strategies in the [Statsig Docs](https://docs.sta --- -## Edge Config +## Global Config -The Statsig adapter can either load the experiment configuration over the network or bootstrap from [Edge Config](https://vercel.com/storage/edge-config). +The Statsig adapter can either load the experiment configuration over the network or bootstrap from [Global Config](https://vercel.com/storage/global-config). -Using [Edge Config](https://vercel.com/docs/storage/edge-config) is optional but recommended for the best latency. Edge Config is a global, ultra-low latency store which uses active replication and is specifically designed for serving feature flag configuration. +Using [Global Config](https://vercel.com/docs/storage/global-config) is optional but recommended for the best latency. Global Config is a global, ultra-low latency store which uses active replication and is specifically designed for serving feature flag configuration. -The default Statsig adapter, exported as `statsigAdapter`, will automatically connect to Edge Config if the `EXPERIMENTATION_CONFIG` and `EXPERIMENTATION_CONFIG_ITEM_KEY` environment variables are set. If you are using the [Statsig integration on Vercel marketplace](https://vercel.com/marketplace/statsig) these environment variables will be provided automatically, and the default Statsig adapter will read from Edge Config automatically. +The default Statsig adapter, exported as `statsigAdapter`, will automatically connect to Global Config if the `EXPERIMENTATION_CONFIG` and `EXPERIMENTATION_CONFIG_ITEM_KEY` environment variables are set. If you are using the [Statsig integration on Vercel marketplace](https://vercel.com/marketplace/statsig) these environment variables will be provided automatically, and the default Statsig adapter will read from Global Config automatically. --- diff --git a/apps/docs/next.config.ts b/apps/docs/next.config.ts index bb9b667e..07744dff 100644 --- a/apps/docs/next.config.ts +++ b/apps/docs/next.config.ts @@ -33,7 +33,7 @@ const config: NextConfig = { // ----------------------------------------------------------------------- '/docs/adapters/custom-adapters': '/providers/custom-adapters', '/docs/adapters/supported-providers': '/providers', - '/docs/api-reference/adapters/edge-config': '/providers/edge-config', + '/docs/api-reference/adapters/edge-config': '/providers/global-config', '/docs/api-reference/adapters/hypertune': '/providers/hypertune', '/docs/api-reference/adapters/launchdarkly': '/providers/launchdarkly', '/docs/api-reference/adapters/optimizely': '/providers/optimizely', @@ -90,7 +90,7 @@ const config: NextConfig = { '/api-reference/provider/split': '/providers/split', '/api-reference/provider/optimizely': '/providers/optimizely', '/api-reference/provider/hypertune': '/providers/hypertune', - '/api-reference/provider/edge-config': '/providers/edge-config', + '/api-reference/provider/edge-config': '/providers/global-config', '/docs/concepts/flags': '/principles/flags-as-code', '/docs/concepts/flags.ts': '/principles/flags-as-code', '/docs/frameworks/next/overview': '/frameworks/next', diff --git a/examples/shirt-shop/package.json b/examples/shirt-shop/package.json index 660e9f54..dbc62dfe 100644 --- a/examples/shirt-shop/package.json +++ b/examples/shirt-shop/package.json @@ -18,7 +18,7 @@ "@tailwindcss/typography": "0.5.16", "@vercel/analytics": "1.5.0", "@vercel/edge": "1.2.1", - "@vercel/edge-config": "^1.4.3", + "@vercel/global-config": "^1.5.0", "@vercel/toolbar": "0.2.7", "clsx": "2.1.1", "flags": "workspace:*", diff --git a/examples/snippets/.env b/examples/snippets/.env index ccca5b0b..42ce1b7a 100644 --- a/examples/snippets/.env +++ b/examples/snippets/.env @@ -1,3 +1,3 @@ # this is a random secret that can be used for testing FLAGS_SECRET=testing-secret-2pMFwxPkTiHKcrwRfFllrhT1KAc8 -EDGE_CONFIG="https://edge-config.vercel.com/ecfg_fvhsocnj9jbqprcriyscdnre3aix?token=6c514eae-1bf8-45b6-9277-ee6560280140" +GLOBAL_CONFIG="https://global-config.vercel.com/ecfg_fvhsocnj9jbqprcriyscdnre3aix?token=6c514eae-1bf8-45b6-9277-ee6560280140" diff --git a/examples/snippets/app/concepts/adapters/edge-config-adapter.ts b/examples/snippets/app/concepts/adapters/edge-config-adapter.ts deleted file mode 100644 index 41dbbfda..00000000 --- a/examples/snippets/app/concepts/adapters/edge-config-adapter.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { createClient, type EdgeConfigClient } from '@vercel/edge-config'; -import type { Adapter } from 'flags'; - -/** - * An Edge Config adapter for the Flags SDK - */ -export function createEdgeConfigAdapter( - connectionString: string | EdgeConfigClient, - options?: { - edgeConfigItemKey?: string; - teamSlug?: string; - }, -) { - if (!connectionString) { - throw new Error('Edge Config Adapter: Missing connection string'); - } - const edgeConfigClient = - typeof connectionString === 'string' - ? createClient(connectionString) - : connectionString; - - const edgeConfigItemKey = options?.edgeConfigItemKey ?? 'flags'; - - return function edgeConfigAdapter(): Adapter< - ValueType, - EntitiesType - > { - return { - origin: options?.teamSlug - ? `https://vercel.com/${options.teamSlug}/~/stores/edge-config/${edgeConfigClient.connection.id}/items#item=${edgeConfigItemKey}` - : undefined, - async decide({ key }): Promise { - const definitions = - await edgeConfigClient.get>( - edgeConfigItemKey, - ); - - // if a defaultValue was provided this error will be caught and the defaultValue will be used - if (!definitions) { - throw new Error( - `@flags-sdk/edge-config: Edge Config item "${edgeConfigItemKey}" not found`, - ); - } - - // if a defaultValue was provided this error will be caught and the defaultValue will be used - if (!(key in definitions)) { - throw new Error( - `@flags-sdk/edge-config: Flag "${key}" not found in Edge Config item "${edgeConfigItemKey}"`, - ); - } - return definitions[key] as ValueType; - }, - }; - }; -} diff --git a/examples/snippets/app/concepts/adapters/flags.tsx b/examples/snippets/app/concepts/adapters/flags.tsx index b16eb8aa..a98e76e7 100644 --- a/examples/snippets/app/concepts/adapters/flags.tsx +++ b/examples/snippets/app/concepts/adapters/flags.tsx @@ -1,10 +1,12 @@ import { flag } from 'flags/next'; -import { createEdgeConfigAdapter } from './edge-config-adapter'; +import { createGlobalConfigAdapter } from './global-config-adapter'; -const edgeConfigAdapter = createEdgeConfigAdapter(process.env.EDGE_CONFIG!); +const globalConfigAdapter = createGlobalConfigAdapter( + process.env.GLOBAL_CONFIG!, +); export const customAdapterFlag = flag({ key: 'custom-adapter-flag', description: 'Shows how to use a custom flags adapter', - adapter: edgeConfigAdapter, + adapter: globalConfigAdapter, }); diff --git a/examples/snippets/app/concepts/adapters/global-config-adapter.ts b/examples/snippets/app/concepts/adapters/global-config-adapter.ts new file mode 100644 index 00000000..64f93acc --- /dev/null +++ b/examples/snippets/app/concepts/adapters/global-config-adapter.ts @@ -0,0 +1,55 @@ +import { createClient, type GlobalConfigClient } from '@vercel/global-config'; +import type { Adapter } from 'flags'; + +/** + * An Global Config adapter for the Flags SDK + */ +export function createGlobalConfigAdapter( + connectionString: string | GlobalConfigClient, + options?: { + globalConfigItemKey?: string; + teamSlug?: string; + }, +) { + if (!connectionString) { + throw new Error('Global Config Adapter: Missing connection string'); + } + const globalConfigClient = + typeof connectionString === 'string' + ? createClient(connectionString) + : connectionString; + + const globalConfigItemKey = options?.globalConfigItemKey ?? 'flags'; + + return function globalConfigAdapter(): Adapter< + ValueType, + EntitiesType + > { + return { + origin: options?.teamSlug + ? `https://vercel.com/${options.teamSlug}/~/stores/global-config/${globalConfigClient.connection.id}/items#item=${globalConfigItemKey}` + : undefined, + async decide({ key }): Promise { + const definitions = + await globalConfigClient.get>( + globalConfigItemKey, + ); + + // if a defaultValue was provided this error will be caught and the defaultValue will be used + if (!definitions) { + throw new Error( + `@flags-sdk/global-config: Global Config item "${globalConfigItemKey}" not found`, + ); + } + + // if a defaultValue was provided this error will be caught and the defaultValue will be used + if (!(key in definitions)) { + throw new Error( + `@flags-sdk/global-config: Flag "${key}" not found in Global Config item "${globalConfigItemKey}"`, + ); + } + return definitions[key] as ValueType; + }, + }; + }; +} diff --git a/examples/snippets/app/examples/dashboard-pages/flags.ts b/examples/snippets/app/examples/dashboard-pages/flags.ts index d07cfa9c..a51d10c3 100644 --- a/examples/snippets/app/examples/dashboard-pages/flags.ts +++ b/examples/snippets/app/examples/dashboard-pages/flags.ts @@ -18,7 +18,7 @@ export const dashboardFlag = flag({ description: 'Flag used on the Dashboard Pages example', decide({ entities }) { if (!entities?.user) return false; - // Allowed users could be loaded from Edge Config or elsewhere + // Allowed users could be loaded from Global Config or elsewhere const allowedUsers = ['user1']; return allowedUsers.includes(entities.user.id); diff --git a/examples/snippets/package.json b/examples/snippets/package.json index 489a6be5..19395eb1 100644 --- a/examples/snippets/package.json +++ b/examples/snippets/package.json @@ -13,7 +13,7 @@ "@radix-ui/react-separator": "1.1.0", "@radix-ui/react-slot": "1.1.0", "@radix-ui/react-tooltip": "1.1.4", - "@vercel/edge-config": "^1.4.3", + "@vercel/global-config": "^1.5.0", "@vercel/toolbar": "0.2.7", "class-variance-authority": "0.7.1", "clsx": "2.0.0", diff --git a/packages/adapter-edge-config/README.md b/packages/adapter-edge-config/README.md deleted file mode 100644 index b956b669..00000000 --- a/packages/adapter-edge-config/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# `@flags-sdk/edge-config` - -## Installation - -```bash -npm install @flags-sdk/edge-config -``` - -## Usage - -## Using the default adapter - -This adapter will connect to the Edge Config available under the `EDGE_CONFIG` environment variable, and read items from a key in the Edge Config called `flags`. - -```ts -import { flag } from "flags/next"; -import { edgeConfigAdapter } from "@flags-sdk/edge-config"; - -export const exampleFlag = flag({ - key: "example-flag", - adapter: edgeConfigAdapter, -}); -``` - -Your Edge Config should look like this: - -```json -{ - "flags": { - "example-flag": true - } -} -``` - -## Using a custom adapter - -You can specify a custom adapter which connects to a different Edge Config, and reads - -```ts -import { flag } from "flags/next"; -import { createEdgeConfigAdapter } from "@flags-sdk/edge-config"; - -const edgeConfigAdapter = createEdgeConfigAdapter(process.env.EDGE_CONFIG, { - teamSlug: "your-team-slug", - edgeConfigItemKey: "my-flags", -}); - -export const exampleFlag = flag({ - key: "example-flag", - adapter: edgeConfigAdapter, -}); -``` - -Your Edge Config should look like this: - -```json -{ - "my-flags": { - "example-flag": true - } -} -``` - -Supplying the custom `teamSlug` allows the adapter to generate an `origin` for your flags, which in turn allows the Flags Explorer to link to your Edge Config. This is optional and does not affect runtime behavior. diff --git a/packages/adapter-edge-config/src/index.ts b/packages/adapter-edge-config/src/index.ts deleted file mode 100644 index 00ad87be..00000000 --- a/packages/adapter-edge-config/src/index.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { createClient, type EdgeConfigClient } from '@vercel/edge-config'; -import type { Adapter, ReadonlyHeaders } from 'flags'; - -export type EdgeConfigFlags = { - [key: string]: boolean | number | string | null; -}; - -// extend the adapter definition to expose a default adapter -let defaultEdgeConfigAdapter: - | ReturnType - | undefined; - -/** - * A default Vercel adapter for Edge Config - * - */ -export function edgeConfigAdapter(): Adapter< - ValueType, - EntitiesType -> { - // Initialized lazily to avoid warning when it is not actually used and env vars are missing. - if (!defaultEdgeConfigAdapter) { - if (!process.env.EDGE_CONFIG) { - throw new Error('@flags-sdk/edge-config: Missing EDGE_CONFIG env var'); - } - - defaultEdgeConfigAdapter = createEdgeConfigAdapter(process.env.EDGE_CONFIG); - } - - return defaultEdgeConfigAdapter(); -} - -export function resetDefaultEdgeConfigAdapter() { - defaultEdgeConfigAdapter = undefined; -} - -type EdgeConfigItem = Record; - -/** - * Allows creating a custom Edge Config adapter for feature flags - */ -export function createEdgeConfigAdapter( - connectionString: string | EdgeConfigClient, - options?: { - edgeConfigItemKey?: string; - teamSlug?: string; - }, -) { - if (!connectionString) { - throw new Error('@flags-sdk/edge-config: Missing connection string'); - } - const edgeConfigClient = - typeof connectionString === 'string' - ? createClient(connectionString) - : connectionString; - - const edgeConfigItemKey = options?.edgeConfigItemKey ?? 'flags'; - - /** - * Per-request cache to ensure we only ever read Edge Config once per request. - * Uses the request headers reference as the cache key. - * - * ReadonlyHeaders -> Promise - */ - const edgeConfigItemCache = new WeakMap< - ReadonlyHeaders, - Promise - >(); - - const adapterId = Symbol('edgeConfigAdapter'); - - async function getDefinitions( - headers: ReadonlyHeaders, - ): Promise { - const cached = edgeConfigItemCache.get(headers); - if (cached) return cached; - const valuePromise = - edgeConfigClient.get(edgeConfigItemKey); - edgeConfigItemCache.set(headers, valuePromise); - return valuePromise; - } - - const adapter: Adapter = { - adapterId, - origin: options?.teamSlug - ? `https://vercel.com/${options.teamSlug}/~/stores/edge-config/${edgeConfigClient.connection.id}/items#item=${edgeConfigItemKey}` - : undefined, - async decide({ key, headers }): Promise { - const definitions = await getDefinitions(headers); - - // if a defaultValue was provided this error will be caught and the defaultValue will be used - if (!definitions) { - throw new Error( - `@flags-sdk/edge-config: Edge Config item "${edgeConfigItemKey}" not found`, - ); - } - - // if a defaultValue was provided this error will be caught and the defaultValue will be used - if (!(key in definitions)) { - throw new Error( - `@flags-sdk/edge-config: Flag "${key}" not found in Edge Config item "${edgeConfigItemKey}"`, - ); - } - return definitions[key]; - }, - async bulkDecide({ flags, headers }): Promise> { - const definitions = await getDefinitions(headers); - - if (!definitions) { - throw new Error( - `@flags-sdk/edge-config: Edge Config item "${edgeConfigItemKey}" not found`, - ); - } - - const out: Record = {}; - for (const { key } of flags) { - if (key in definitions) { - out[key] = definitions[key]; - } - } - return out; - }, - }; - - return function edgeConfigAdapter(): Adapter< - ValueType, - EntitiesType - > { - return adapter as Adapter; - }; -} diff --git a/packages/adapter-edge-config/CHANGELOG.md b/packages/adapter-global-config/CHANGELOG.md similarity index 97% rename from packages/adapter-edge-config/CHANGELOG.md rename to packages/adapter-global-config/CHANGELOG.md index e44b3cc6..c6467c2d 100644 --- a/packages/adapter-edge-config/CHANGELOG.md +++ b/packages/adapter-global-config/CHANGELOG.md @@ -1,4 +1,4 @@ -# @flags-sdk/edge-config +# @flags-sdk/global-config ## 0.2.0 diff --git a/packages/adapter-global-config/README.md b/packages/adapter-global-config/README.md new file mode 100644 index 00000000..f6afb881 --- /dev/null +++ b/packages/adapter-global-config/README.md @@ -0,0 +1,64 @@ +# `@flags-sdk/global-config` + +## Installation + +```bash +npm install @flags-sdk/global-config +``` + +## Usage + +## Using the default adapter + +This adapter will connect to the Global Config available under the `GLOBAL_CONFIG` environment variable, and read items from a key in the Global Config called `flags`. + +```ts +import { flag } from "flags/next"; +import { globalConfigAdapter } from "@flags-sdk/global-config"; + +export const exampleFlag = flag({ + key: "example-flag", + adapter: globalConfigAdapter, +}); +``` + +Your Global Config should look like this: + +```json +{ + "flags": { + "example-flag": true + } +} +``` + +## Using a custom adapter + +You can specify a custom adapter which connects to a different Global Config, and reads + +```ts +import { flag } from "flags/next"; +import { createGlobalConfigAdapter } from "@flags-sdk/global-config"; + +const globalConfigAdapter = createGlobalConfigAdapter(process.env.GLOBAL_CONFIG, { + teamSlug: "your-team-slug", + globalConfigItemKey: "my-flags", +}); + +export const exampleFlag = flag({ + key: "example-flag", + adapter: globalConfigAdapter, +}); +``` + +Your Global Config should look like this: + +```json +{ + "my-flags": { + "example-flag": true + } +} +``` + +Supplying the custom `teamSlug` allows the adapter to generate an `origin` for your flags, which in turn allows the Flags Explorer to link to your Global Config. This is optional and does not affect runtime behavior. diff --git a/packages/adapter-edge-config/package.json b/packages/adapter-global-config/package.json similarity index 89% rename from packages/adapter-edge-config/package.json rename to packages/adapter-global-config/package.json index 92600570..bb2d475c 100644 --- a/packages/adapter-edge-config/package.json +++ b/packages/adapter-global-config/package.json @@ -1,7 +1,7 @@ { - "name": "@flags-sdk/edge-config", + "name": "@flags-sdk/global-config", "version": "0.2.0", - "description": "A Flags SDK adapter for Edge Config", + "description": "A Flags SDK adapter for Global Config", "keywords": [ "vercel", "flags", @@ -44,7 +44,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@vercel/edge-config": "^1.4.3" + "@vercel/global-config": "^1.5.0" }, "devDependencies": { "@types/node": "22.14.0", diff --git a/packages/adapter-edge-config/src/index.test.ts b/packages/adapter-global-config/src/index.test.ts similarity index 58% rename from packages/adapter-edge-config/src/index.test.ts rename to packages/adapter-global-config/src/index.test.ts index bd5f70f1..330f07ff 100644 --- a/packages/adapter-edge-config/src/index.test.ts +++ b/packages/adapter-global-config/src/index.test.ts @@ -1,29 +1,29 @@ -import type { EdgeConfigClient } from '@vercel/edge-config'; +import type { GlobalConfigClient } from '@vercel/global-config'; import type { ReadonlyRequestCookies } from 'flags'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { - createEdgeConfigAdapter, - edgeConfigAdapter, - resetDefaultEdgeConfigAdapter, + createGlobalConfigAdapter, + globalConfigAdapter, + resetDefaultGlobalConfigAdapter, } from '.'; -describe('createEdgeConfigAdapter', () => { +describe('createGlobalConfigAdapter', () => { it('should allow creating an adapter with a client', () => { - const fakeEdgeConfigClient = {} as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + const fakeGlobalConfigClient = {} as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); expect(adapter).toBeDefined(); }); it('returns the same adapter instance on every call', () => { - const fakeEdgeConfigClient = {} as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + const fakeGlobalConfigClient = {} as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); expect(adapter()).toBe(adapter()); }); describe('adapterId', () => { it('shares one adapterId across all adapters from the same factory call', () => { - const fakeEdgeConfigClient = {} as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + const fakeGlobalConfigClient = {} as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); const a = adapter(); const b = adapter(); expect(a).toBe(b); @@ -32,23 +32,23 @@ describe('createEdgeConfigAdapter', () => { }); it('uses different adapterIds across separate factory calls', () => { - const fakeEdgeConfigClient = {} as EdgeConfigClient; - const adapterA = createEdgeConfigAdapter(fakeEdgeConfigClient); - const adapterB = createEdgeConfigAdapter(fakeEdgeConfigClient); + const fakeGlobalConfigClient = {} as GlobalConfigClient; + const adapterA = createGlobalConfigAdapter(fakeGlobalConfigClient); + const adapterB = createGlobalConfigAdapter(fakeGlobalConfigClient); expect(adapterA().adapterId).not.toBe(adapterB().adapterId); }); }); describe('bulkDecide', () => { - it('resolves all requested flag keys from Edge Config in one read', async () => { - const fakeEdgeConfigClient = { + it('resolves all requested flag keys from Global Config in one read', async () => { + const fakeGlobalConfigClient = { get: vi.fn(async () => ({ 'flag-a': true, 'flag-b': false, 'flag-c': true, })), - } as unknown as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + } as unknown as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); const headers = new Headers(); const result = await adapter().bulkDecide!({ @@ -59,14 +59,14 @@ describe('createEdgeConfigAdapter', () => { }); expect(result).toEqual({ 'flag-a': true, 'flag-b': false }); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledOnce(); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledOnce(); }); - it('omits keys missing from Edge Config so the SDK applies defaultValue', async () => { - const fakeEdgeConfigClient = { + it('omits keys missing from Global Config so the SDK applies defaultValue', async () => { + const fakeGlobalConfigClient = { get: vi.fn(async () => ({ 'flag-a': true })), - } as unknown as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + } as unknown as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); const headers = new Headers(); const result = await adapter().bulkDecide!({ @@ -80,10 +80,10 @@ describe('createEdgeConfigAdapter', () => { }); it('shares the per-request cache with decide', async () => { - const fakeEdgeConfigClient = { + const fakeGlobalConfigClient = { get: vi.fn(async () => ({ 'flag-a': true, 'flag-b': false })), - } as unknown as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + } as unknown as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); const headers = new Headers(); await adapter().decide({ @@ -100,22 +100,22 @@ describe('createEdgeConfigAdapter', () => { cookies: {} as ReadonlyRequestCookies, }); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledOnce(); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledOnce(); }); }); it('should allow creating an adapter with a connection string', () => { - const adapter = createEdgeConfigAdapter( - 'https://edge-config.vercel.com/ecfg_xxx?token=yyy', + const adapter = createGlobalConfigAdapter( + 'https://global-config.vercel.com/ecfg_xxx?token=yyy', ); expect(adapter).toBeDefined(); }); it('should allow deciding', async () => { - const fakeEdgeConfigClient = { + const fakeGlobalConfigClient = { get: vi.fn(async () => ({ 'test-key': true })), - } as unknown as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + } as unknown as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); await expect( adapter().decide({ key: 'test-key', @@ -124,15 +124,15 @@ describe('createEdgeConfigAdapter', () => { cookies: {} as ReadonlyRequestCookies, }), ).resolves.toEqual(true); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledWith('flags'); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledWith('flags'); }); describe('caching', () => { it('caches for the duration of a request', async () => { - const fakeEdgeConfigClient = { + const fakeGlobalConfigClient = { get: vi.fn(async () => ({ 'test-key': true })), - } as unknown as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + } as unknown as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); const headers = new Headers(); @@ -156,14 +156,14 @@ describe('createEdgeConfigAdapter', () => { cookies: {} as ReadonlyRequestCookies, }), ).resolves.toEqual(true); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledWith('flags'); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledOnce(); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledWith('flags'); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledOnce(); }); it('does not cache between requests', async () => { - const fakeEdgeConfigClient = { + const fakeGlobalConfigClient = { get: vi.fn(async () => ({ 'test-key': true })), - } as unknown as EdgeConfigClient; - const adapter = createEdgeConfigAdapter(fakeEdgeConfigClient); + } as unknown as GlobalConfigClient; + const adapter = createGlobalConfigAdapter(fakeGlobalConfigClient); // call once await expect( @@ -186,28 +186,28 @@ describe('createEdgeConfigAdapter', () => { }), ).resolves.toEqual(true); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledWith('flags'); - expect(fakeEdgeConfigClient.get).toHaveBeenCalledTimes(2); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledWith('flags'); + expect(fakeGlobalConfigClient.get).toHaveBeenCalledTimes(2); }); }); }); -describe('edgeConfigAdapter', () => { +describe('globalConfigAdapter', () => { beforeEach(() => { - resetDefaultEdgeConfigAdapter(); + resetDefaultGlobalConfigAdapter(); }); - it('default adapter should throw on usage when EDGE_CONFIG is not set', () => { - expect(() => edgeConfigAdapter()).toThrowError( - '@flags-sdk/edge-config: Missing EDGE_CONFIG env var', + it('default adapter should throw on usage when GLOBAL_CONFIG is not set', () => { + expect(() => globalConfigAdapter()).toThrowError( + '@flags-sdk/global-config: Missing GLOBAL_CONFIG env var', ); }); it('should export a default adapter', () => { - process.env.EDGE_CONFIG = - 'https://edge-config.vercel.com/ecfg_xxx?token=yyy'; - const adapter = edgeConfigAdapter(); + process.env.GLOBAL_CONFIG = + 'https://global-config.vercel.com/ecfg_xxx?token=yyy'; + const adapter = globalConfigAdapter(); expect(adapter).toBeDefined(); - delete process.env.EDGE_CONFIG; + delete process.env.GLOBAL_CONFIG; }); }); diff --git a/packages/adapter-global-config/src/index.ts b/packages/adapter-global-config/src/index.ts new file mode 100644 index 00000000..9f9a93a3 --- /dev/null +++ b/packages/adapter-global-config/src/index.ts @@ -0,0 +1,135 @@ +import { createClient, type GlobalConfigClient } from '@vercel/global-config'; +import type { Adapter, ReadonlyHeaders } from 'flags'; + +export type GlobalConfigFlags = { + [key: string]: boolean | number | string | null; +}; + +// extend the adapter definition to expose a default adapter +let defaultGlobalConfigAdapter: + | ReturnType + | undefined; + +/** + * A default Vercel adapter for Global Config + * + */ +export function globalConfigAdapter(): Adapter< + ValueType, + EntitiesType +> { + // Initialized lazily to avoid warning when it is not actually used and env vars are missing. + if (!defaultGlobalConfigAdapter) { + if (!process.env.GLOBAL_CONFIG) { + throw new Error( + '@flags-sdk/global-config: Missing GLOBAL_CONFIG env var', + ); + } + + defaultGlobalConfigAdapter = createGlobalConfigAdapter( + process.env.GLOBAL_CONFIG, + ); + } + + return defaultGlobalConfigAdapter(); +} + +export function resetDefaultGlobalConfigAdapter() { + defaultGlobalConfigAdapter = undefined; +} + +type GlobalConfigItem = Record; + +/** + * Allows creating a custom Global Config adapter for feature flags + */ +export function createGlobalConfigAdapter( + connectionString: string | GlobalConfigClient, + options?: { + globalConfigItemKey?: string; + teamSlug?: string; + }, +) { + if (!connectionString) { + throw new Error('@flags-sdk/global-config: Missing connection string'); + } + const globalConfigClient = + typeof connectionString === 'string' + ? createClient(connectionString) + : connectionString; + + const globalConfigItemKey = options?.globalConfigItemKey ?? 'flags'; + + /** + * Per-request cache to ensure we only ever read Global Config once per request. + * Uses the request headers reference as the cache key. + * + * ReadonlyHeaders -> Promise + */ + const globalConfigItemCache = new WeakMap< + ReadonlyHeaders, + Promise + >(); + + const adapterId = Symbol('globalConfigAdapter'); + + async function getDefinitions( + headers: ReadonlyHeaders, + ): Promise { + const cached = globalConfigItemCache.get(headers); + if (cached) return cached; + const valuePromise = + globalConfigClient.get(globalConfigItemKey); + globalConfigItemCache.set(headers, valuePromise); + return valuePromise; + } + + const adapter: Adapter = { + adapterId, + origin: options?.teamSlug + ? `https://vercel.com/${options.teamSlug}/~/stores/global-config/${globalConfigClient.connection.id}/items#item=${globalConfigItemKey}` + : undefined, + async decide({ key, headers }): Promise { + const definitions = await getDefinitions(headers); + + // if a defaultValue was provided this error will be caught and the defaultValue will be used + if (!definitions) { + throw new Error( + `@flags-sdk/global-config: Global Config item "${globalConfigItemKey}" not found`, + ); + } + + // if a defaultValue was provided this error will be caught and the defaultValue will be used + if (!(key in definitions)) { + throw new Error( + `@flags-sdk/global-config: Flag "${key}" not found in Global Config item "${globalConfigItemKey}"`, + ); + } + return definitions[key]; + }, + async bulkDecide({ flags, headers }): Promise> { + const definitions = await getDefinitions(headers); + + if (!definitions) { + throw new Error( + `@flags-sdk/global-config: Global Config item "${globalConfigItemKey}" not found`, + ); + } + + const out: Record = {}; + for (const { key } of flags) { + if (key in definitions) { + out[key] = definitions[key]; + } + } + return out; + }, + }; + + return function globalConfigAdapter(): Adapter< + ValueType, + EntitiesType + > { + return adapter as Adapter; + }; +} diff --git a/packages/adapter-edge-config/tsconfig.json b/packages/adapter-global-config/tsconfig.json similarity index 100% rename from packages/adapter-edge-config/tsconfig.json rename to packages/adapter-global-config/tsconfig.json diff --git a/packages/adapter-edge-config/tsup.config.js b/packages/adapter-global-config/tsup.config.js similarity index 100% rename from packages/adapter-edge-config/tsup.config.js rename to packages/adapter-global-config/tsup.config.js diff --git a/packages/adapter-edge-config/vitest.config.ts b/packages/adapter-global-config/vitest.config.ts similarity index 100% rename from packages/adapter-edge-config/vitest.config.ts rename to packages/adapter-global-config/vitest.config.ts diff --git a/packages/adapter-growthbook/package.json b/packages/adapter-growthbook/package.json index 0d0c5ae1..07dcc9d0 100644 --- a/packages/adapter-growthbook/package.json +++ b/packages/adapter-growthbook/package.json @@ -61,7 +61,7 @@ }, "dependencies": { "@growthbook/growthbook": "^1.5.1", - "@vercel/edge-config": "^1.4.3", + "@vercel/global-config": "^1.5.0", "@vercel/functions": "^1.5.2" }, "devDependencies": { diff --git a/packages/adapter-growthbook/src/index.ts b/packages/adapter-growthbook/src/index.ts index ba78f1a9..7ba13d0e 100644 --- a/packages/adapter-growthbook/src/index.ts +++ b/packages/adapter-growthbook/src/index.ts @@ -10,7 +10,7 @@ import { type TrackingCallbackWithUser, type UserContext, } from '@growthbook/growthbook'; -import { createClient } from '@vercel/edge-config'; +import { createClient } from '@vercel/global-config'; import { AsyncLocalStorage } from 'async_hooks'; import type { Adapter } from 'flags'; @@ -28,7 +28,7 @@ export { type StickyAssignmentsDocument, }; -type EdgeConfig = { +type GlobalConfig = { connectionString: string; /** Defaults to `options.clientKey` **/ itemKey?: string; @@ -62,8 +62,8 @@ export function createGrowthbookAdapter(options: { initOptions?: InitOptions; /** Optional StickyBucketService (reduces variation hopping, required for Bandits) **/ stickyBucketService?: StickyBucketService; - /** Provide Edge Config details to use the optional Edge Config adapter */ - edgeConfig?: EdgeConfig; + /** Provide Global Config details to use the optional Global Config adapter */ + globalConfig?: GlobalConfig; }): AdapterResponse { let trackingCallback = options.trackingCallback; let stickyBucketService = options.stickyBucketService; @@ -74,62 +74,63 @@ export function createGrowthbookAdapter(options: { ...(options.clientOptions || {}), }); - const edgeConfigClient = options.edgeConfig - ? createClient(options.edgeConfig.connectionString) + const globalConfigClient = options.globalConfig + ? createClient(options.globalConfig.connectionString) : null; - const edgeConfigKey = options.edgeConfig?.itemKey || options.clientKey; + const globalConfigKey = options.globalConfig?.itemKey || options.clientKey; const store = new AsyncLocalStorage(); const cache = new WeakMap>(); - const getEdgePayload = async (): Promise => { - if (!edgeConfigClient) return null; + const getGlobalConfigPayload = + async (): Promise => { + if (!globalConfigClient) return null; - // Only do this once per request using AsyncLocalStorage - const currentRequest = store.getStore(); - if (currentRequest) { - const cached = cache.get(currentRequest); - if (cached) { - return cached; + // Only do this once per request using AsyncLocalStorage + const currentRequest = store.getStore(); + if (currentRequest) { + const cached = cache.get(currentRequest); + if (cached) { + return cached; + } } - } - // Fetch from Edge Config - const payloadPromise = edgeConfigClient - .get(edgeConfigKey) - .then((payload) => { - if (!payload) { - console.error('No payload found in edge config'); - return null; - } else if (typeof payload === 'string') { - // Older GrowthBook integrations use WebHooks directly to store - // data in Edge Config, but they store the data as a string. - // - // We need to parse the string to JSON before passing it to GrowthBook. - // - // https://docs.growthbook.io/app/webhooks/sdk-webhooks#vercel-edge-config - // https://github.com/vercel/flags/issues/209 - try { - return JSON.parse(payload) as FeatureApiResponse; - } catch { - console.error('Invalid payload format'); + // Fetch from Global Config + const payloadPromise = globalConfigClient + .get(globalConfigKey) + .then((payload) => { + if (!payload) { + console.error('No payload found in global config'); return null; + } else if (typeof payload === 'string') { + // Older GrowthBook integrations use WebHooks directly to store + // data in Global Config, but they store the data as a string. + // + // We need to parse the string to JSON before passing it to GrowthBook. + // + // https://docs.growthbook.io/app/webhooks/sdk-webhooks#vercel-edge-config + // https://github.com/vercel/flags/issues/209 + try { + return JSON.parse(payload) as FeatureApiResponse; + } catch { + console.error('Invalid payload format'); + return null; + } + } else { + return payload; } - } else { - return payload; - } - }) - .catch((e) => { - console.error('Error fetching edge config', e); - return null; - }); + }) + .catch((e) => { + console.error('Error fetching global config', e); + return null; + }); - if (currentRequest) cache.set(currentRequest, payloadPromise); - return payloadPromise; - }; + if (currentRequest) cache.set(currentRequest, payloadPromise); + return payloadPromise; + }; const initializeGrowthBook = async (): Promise => { - const payload = await getEdgePayload(); + const payload = await getGlobalConfigPayload(); await growthbook.init({ streaming: false, payload: payload ?? undefined, @@ -155,8 +156,8 @@ export function createGrowthbookAdapter(options: { }; const refresh = async (): Promise => { - if (options.edgeConfig) { - const payload = await getEdgePayload(); + if (options.globalConfig) { + const payload = await getGlobalConfigPayload(); if (payload && payload !== growthbook.getPayload()) { await growthbook.setPayload(payload); } @@ -248,9 +249,9 @@ export function resetDefaultGrowthbookAdapter() { * Optional: * - `GROWTHBOOK_API_HOST` - Override the SDK API endpoint for self-hosted users * - `GROWTHBOOK_APP_ORIGIN` - Override the application URL for self-hosted users - * - `GROWTHBOOK_EDGE_CONNECTION_STRING` - Edge Config connection string - * - `EXPERIMENTATION_CONFIG` - fallback for GROWTHBOOK_EDGE_CONNECTION_STRING - * - `GROWTHBOOK_EDGE_CONFIG_ITEM_KEY` - Override the item key for Edge Config (defaults to GROWTHBOOK_CLIENT_KEY) + * - `GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING` - Global Config connection string + * - `EXPERIMENTATION_CONFIG` - fallback for GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING + * - `GROWTHBOOK_GLOBAL_CONFIG_ITEM_KEY` - Override the item key for Global Config (defaults to GROWTHBOOK_CLIENT_KEY) */ export function getOrCreateDefaultGrowthbookAdapter(): AdapterResponse { if (defaultGrowthbookAdapter) { @@ -263,13 +264,13 @@ export function getOrCreateDefaultGrowthbookAdapter(): AdapterResponse { const apiHost = process.env.GROWTHBOOK_API_HOST; const appOrigin = process.env.GROWTHBOOK_APP_ORIGIN; const connectionString = - process.env.GROWTHBOOK_EDGE_CONNECTION_STRING || + process.env.GROWTHBOOK_GLOBAL_CONFIG_CONNECTION_STRING || process.env.EXPERIMENTATION_CONFIG; - const itemKey = process.env.GROWTHBOOK_EDGE_CONFIG_ITEM_KEY; + const itemKey = process.env.GROWTHBOOK_GLOBAL_CONFIG_ITEM_KEY; - let edgeConfig: EdgeConfig | undefined; + let globalConfig: GlobalConfig | undefined; if (connectionString) { - edgeConfig = { + globalConfig = { connectionString, itemKey, }; @@ -279,7 +280,7 @@ export function getOrCreateDefaultGrowthbookAdapter(): AdapterResponse { clientKey, apiHost, appOrigin, - edgeConfig, + globalConfig, }); return defaultGrowthbookAdapter; diff --git a/packages/adapter-hypertune/README.md b/packages/adapter-hypertune/README.md index 533fdddf..19d56ff6 100644 --- a/packages/adapter-hypertune/README.md +++ b/packages/adapter-hypertune/README.md @@ -84,7 +84,7 @@ NEXT_PUBLIC_HYPERTUNE_TOKEN="123=" # For use with precompute, encrypted flag values, overrides, and the Flags Explorer FLAGS_SECRET="ReplaceThisWith32RandomBytesBase64UrlString" -# Optional: automatically configure with a VercelEdgeConfigInitDataProvider +# Optional: automatically configure with a VercelGlobalConfigInitDataProvider EXPERIMENTATION_CONFIG="ecfg_abc" EXPERIMENTATION_CONFIG_ITEM_KEY="hypertune_xyz" ``` diff --git a/packages/adapter-hypertune/package.json b/packages/adapter-hypertune/package.json index 00df7008..0c5ef1cb 100644 --- a/packages/adapter-hypertune/package.json +++ b/packages/adapter-hypertune/package.json @@ -45,7 +45,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@vercel/edge-config": "^1.4.3", + "@vercel/global-config": "^1.5.0", "hypertune": "2.8.3" }, "devDependencies": { diff --git a/packages/adapter-hypertune/src/adapter.ts b/packages/adapter-hypertune/src/adapter.ts index 038aad39..effde24f 100644 --- a/packages/adapter-hypertune/src/adapter.ts +++ b/packages/adapter-hypertune/src/adapter.ts @@ -1,4 +1,4 @@ -import { createClient } from '@vercel/edge-config'; +import { createClient } from '@vercel/global-config'; import type { Adapter, FlagDeclaration, @@ -7,7 +7,7 @@ import type { } from 'flags'; import { type CreateOptions, - VercelEdgeConfigInitDataProvider, + VercelEdgeConfigInitDataProvider as VercelGlobalConfigInitDataProvider, } from 'hypertune'; type FlagDefinition = { @@ -99,7 +99,7 @@ export const createHypertuneAdapter = < const initDataProvider = process.env.EXPERIMENTATION_CONFIG && process.env.EXPERIMENTATION_CONFIG_ITEM_KEY - ? new VercelEdgeConfigInitDataProvider({ + ? new VercelGlobalConfigInitDataProvider({ edgeConfigClient: createClient( process.env.EXPERIMENTATION_CONFIG, ), diff --git a/packages/adapter-launchdarkly/README.md b/packages/adapter-launchdarkly/README.md index 9cae5cd3..b5fbb83b 100644 --- a/packages/adapter-launchdarkly/README.md +++ b/packages/adapter-launchdarkly/README.md @@ -12,7 +12,7 @@ npm i @flags-sdk/launchdarkly ## Provider Instance -**NOTE:** The [LaunchDarkly Vercel integration](https://vercel.com/integrations/launchdarkly) must be installed on your account, as this adapter loads LaunchDarkly from Edge Config. The adapter can not be used without Edge Config. +**NOTE:** The [LaunchDarkly Vercel integration](https://vercel.com/integrations/launchdarkly) must be installed on your account, as this adapter loads LaunchDarkly from Global Config. The adapter can not be used without Global Config. Import the default adapter instance `ldAdapter` from `@flags-sdk/launchdarkly`: @@ -25,14 +25,14 @@ The default adapter uses the following environment variables to configure itself ```sh export LAUNCHDARKLY_CLIENT_SIDE_ID="612376f91b8f5713a58777a1" export LAUNCHDARKLY_PROJECT_SLUG="my-project" -# Provided by the LaunchDarkly Marketplace integration when Edge Config is +# Provided by the LaunchDarkly Marketplace integration when Global Config is # enabled for the collection. -export EXPERIMENTATION_CONFIG="https://edge-config.vercel.com/ecfg_abdc1234?token=xxx-xxx-xxx" +export EXPERIMENTATION_CONFIG="https://global-config.vercel.com/ecfg_abdc1234?token=xxx-xxx-xxx" ``` > **Using the legacy LaunchDarkly Vercel integration?** The default adapter reads -> the Edge Config connection string from `EXPERIMENTATION_CONFIG` only. If your -> project provides the connection string as `EDGE_CONFIG`, set +> the Global Config connection string from `EXPERIMENTATION_CONFIG` only. If your +> project provides the connection string as `GLOBAL_CONFIG`, set > `EXPERIMENTATION_CONFIG` to the same value, or pass it explicitly with > [`createLaunchDarklyAdapter`](#custom-adapter). @@ -65,10 +65,10 @@ import { createLaunchDarklyAdapter } from "@flags-sdk/launchdarkly"; const adapter = createLaunchDarklyAdapter({ projectSlug: "my-project", clientSideId: "612376f91b8f5713a58777a1", - // Legacy integrations that provide the connection string as `EDGE_CONFIG` + // Legacy integrations that provide the connection string as `GLOBAL_CONFIG` // can pass it explicitly here. - edgeConfigConnectionString: - process.env.EXPERIMENTATION_CONFIG ?? process.env.EDGE_CONFIG, + globalConfigConnectionString: + process.env.EXPERIMENTATION_CONFIG ?? process.env.GLOBAL_CONFIG, }); ``` diff --git a/packages/adapter-launchdarkly/package.json b/packages/adapter-launchdarkly/package.json index 39c9a216..771ea88f 100644 --- a/packages/adapter-launchdarkly/package.json +++ b/packages/adapter-launchdarkly/package.json @@ -6,7 +6,7 @@ "flags-sdk", "launchdarkly", "vercel", - "edge config", + "global config", "feature flags", "flags" ], @@ -51,7 +51,7 @@ }, "dependencies": { "@launchdarkly/vercel-server-sdk": "^1.3.34", - "@vercel/edge-config": "^1.4.3" + "@vercel/global-config": "^1.5.0" }, "devDependencies": { "@types/node": "22.14.0", diff --git a/packages/adapter-launchdarkly/src/index.test.ts b/packages/adapter-launchdarkly/src/index.test.ts index 2bcb255b..34244242 100644 --- a/packages/adapter-launchdarkly/src/index.test.ts +++ b/packages/adapter-launchdarkly/src/index.test.ts @@ -12,7 +12,7 @@ vi.mock('@launchdarkly/vercel-server-sdk', () => ({ init: vi.fn(() => ldClientMock), })); -vi.mock('@vercel/edge-config', () => ({ +vi.mock('@vercel/global-config', () => ({ createClient: vi.fn(), })); @@ -34,7 +34,7 @@ describe('ldAdapter', () => { process.env.LAUNCHDARKLY_PROJECT_SLUG = 'test-project'; process.env.LAUNCHDARKLY_CLIENT_SIDE_ID = 'test-client-side-id'; process.env.EXPERIMENTATION_CONFIG = - 'https://edge-config.com/test-experimentation-config'; + 'https://global-config.com/test-experimentation-config'; }); it('should expose the ldClient', () => { diff --git a/packages/adapter-launchdarkly/src/index.ts b/packages/adapter-launchdarkly/src/index.ts index 54779a7e..94d9cef7 100644 --- a/packages/adapter-launchdarkly/src/index.ts +++ b/packages/adapter-launchdarkly/src/index.ts @@ -3,7 +3,7 @@ import { type LDClient, type LDContext, } from '@launchdarkly/vercel-server-sdk'; -import { createClient, type EdgeConfigClient } from '@vercel/edge-config'; +import { createClient, type GlobalConfigClient } from '@vercel/global-config'; import { AsyncLocalStorage } from 'async_hooks'; import type { Adapter } from 'flags'; @@ -39,19 +39,19 @@ function assertEnv(name: string): string { export function createLaunchDarklyAdapter({ projectSlug, clientSideId, - edgeConfigConnectionString, + globalConfigConnectionString, }: { projectSlug: string; clientSideId: string; - edgeConfigConnectionString: string; + globalConfigConnectionString: string; }): AdapterResponse { - const edgeConfigClient = createClient(edgeConfigConnectionString); + const globalConfigClient = createClient(globalConfigConnectionString); const store = new AsyncLocalStorage(); const cache = new WeakMap>(); - const patchedEdgeConfigClient: EdgeConfigClient = { - ...edgeConfigClient, + const patchedGlobalConfigClient: GlobalConfigClient = { + ...globalConfigClient, get: async (key: string) => { const h = store.getStore(); if (h) { @@ -61,7 +61,7 @@ export function createLaunchDarklyAdapter({ } } - const promise = edgeConfigClient.get(key); + const promise = globalConfigClient.get(key); if (h) cache.set(h, promise); return promise; @@ -70,7 +70,7 @@ export function createLaunchDarklyAdapter({ let initPromise: Promise | null = null; - const ldClient = init(clientSideId, patchedEdgeConfigClient); + const ldClient = init(clientSideId, patchedGlobalConfigClient); function origin(key: string) { return `https://app.launchdarkly.com/projects/${projectSlug}/flags/${key}/`; @@ -108,14 +108,14 @@ export function createLaunchDarklyAdapter({ function getOrCreateDeaultAdapter() { if (!defaultLaunchDarklyAdapter) { - const edgeConfigConnectionString = assertEnv('EXPERIMENTATION_CONFIG'); + const globalConfigConnectionString = assertEnv('EXPERIMENTATION_CONFIG'); const clientSideId = assertEnv('LAUNCHDARKLY_CLIENT_SIDE_ID'); const projectSlug = assertEnv('LAUNCHDARKLY_PROJECT_SLUG'); defaultLaunchDarklyAdapter = createLaunchDarklyAdapter({ projectSlug, clientSideId, - edgeConfigConnectionString, + globalConfigConnectionString, }); } diff --git a/packages/adapter-reflag/package.json b/packages/adapter-reflag/package.json index b228d4bf..5ee53499 100644 --- a/packages/adapter-reflag/package.json +++ b/packages/adapter-reflag/package.json @@ -6,7 +6,7 @@ "flags-sdk", "reflag", "vercel", - "edge config", + "global config", "feature flags", "flags" ], diff --git a/packages/adapter-statsig/package.json b/packages/adapter-statsig/package.json index 3b4c6692..a7f5973f 100644 --- a/packages/adapter-statsig/package.json +++ b/packages/adapter-statsig/package.json @@ -7,7 +7,7 @@ "statsig", "dynamic config", "vercel", - "edge config", + "global config", "experiments", "experimentation", "ab testing" @@ -63,7 +63,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@vercel/edge-config": "^1.4.3", + "@vercel/global-config": "^1.5.0", "@vercel/functions": "^1.5.2", "statsig-node-lite": "^0.5.2", "statsig-node-vercel": "^0.7.0" diff --git a/packages/adapter-statsig/src/edge-runtime-hooks.ts b/packages/adapter-statsig/src/edge-runtime-hooks.ts index e65cb03a..a16c7afb 100644 --- a/packages/adapter-statsig/src/edge-runtime-hooks.ts +++ b/packages/adapter-statsig/src/edge-runtime-hooks.ts @@ -9,20 +9,22 @@ export const isEdgeRuntime = (): boolean => { }; /** - * The Edge Config Data Adapter is an optional peer dependency that allows - * the Statsig SDK to retrieve its data from Edge Config instead of over the network. + * The Global Config Data Adapter is an optional peer dependency that allows + * the Statsig SDK to retrieve its data from Global Config instead of over the network. */ -export async function createEdgeConfigDataAdapter(options: { - edgeConfigItemKey: string; - edgeConfigConnectionString: string; +export async function createGlobalConfigDataAdapter(options: { + globalConfigItemKey: string; + globalConfigConnectionString: string; }) { - // Edge Config adapter requires `@vercel/edge-config` and `statsig-node-vercel` + // Global Config adapter requires `@vercel/global-config` and `statsig-node-vercel` // Since it is a peer dependency, we will import it dynamically - const { EdgeConfigDataAdapter } = await import('statsig-node-vercel'); - const { createClient } = await import('@vercel/edge-config'); - return new EdgeConfigDataAdapter({ - edgeConfigItemKey: options.edgeConfigItemKey, - edgeConfigClient: createClient(options.edgeConfigConnectionString, { + const { EdgeConfigDataAdapter: GlobalConfigDataAdapter } = await import( + 'statsig-node-vercel' + ); + const { createClient } = await import('@vercel/global-config'); + return new GlobalConfigDataAdapter({ + edgeConfigItemKey: options.globalConfigItemKey, + edgeConfigClient: createClient(options.globalConfigConnectionString, { // We disable the development cache as Statsig caches for 10 seconds internally, // and we want to avoid situations where Statsig tries to read the latest value, // but hits the development cache and then caches the outdated value for another 10 seconds, @@ -46,7 +48,7 @@ export const createSyncingHandler = ( // // This needs to be fixed in statsig-node-lite in the future. // - // Ideally the Statsig SDK would not sync at all and instead always read from Edge Config, + // Ideally the Statsig SDK would not sync at all and instead always read from Global Config, // this would provide two benefits: // - changes would propagate immediately instead of being cached for 5s or 10s // - the broken syncing due to issues in Date.now in Edge Runtime would be irrelevant diff --git a/packages/adapter-statsig/src/index.ts b/packages/adapter-statsig/src/index.ts index 2518f39c..bc8cbc22 100644 --- a/packages/adapter-statsig/src/index.ts +++ b/packages/adapter-statsig/src/index.ts @@ -8,7 +8,7 @@ import Statsig, { type StatsigUser, } from 'statsig-node-lite'; import { - createEdgeConfigDataAdapter, + createGlobalConfigDataAdapter, createSyncingHandler, } from './edge-runtime-hooks'; @@ -52,18 +52,18 @@ export function createStatsigAdapter(options: { statsigOptions?: StatsigOptions; /** Provide the project ID to allow links to the Statsig console in the Vercel Toolbar */ statsigProjectId?: string; - /** Provide Edge Config details to use the optional Edge Config adapter */ - edgeConfig?: { + /** Provide Global Config details to use the optional Global Config adapter */ + globalConfig?: { connectionString: string; itemKey: string; }; }): AdapterResponse { const initializeStatsig = async (): Promise => { let dataAdapter: StatsigOptions['dataAdapter'] | undefined; - if (options.edgeConfig) { - dataAdapter = await createEdgeConfigDataAdapter({ - edgeConfigItemKey: options.edgeConfig.itemKey, - edgeConfigConnectionString: options.edgeConfig.connectionString, + if (options.globalConfig) { + dataAdapter = await createGlobalConfigDataAdapter({ + globalConfigItemKey: options.globalConfig.itemKey, + globalConfigConnectionString: options.globalConfig.connectionString, }); } @@ -101,7 +101,7 @@ export function createStatsigAdapter(options: { return user != null && typeof user === 'object'; }; - const minSyncDelayMs = options.edgeConfig ? 1_000 : 5_000; + const minSyncDelayMs = options.globalConfig ? 1_000 : 5_000; const syncHandler = createSyncingHandler(minSyncDelayMs); async function predecide(user?: StatsigUser): Promise { @@ -258,8 +258,8 @@ export function resetDefaultStatsigAdapter() { * * Optional: * - `STATSIG_PROJECT_ID` - Statsig project ID to enable link in Vercel's Flags Explorer - * - `EXPERIMENTATION_CONFIG` - Vercel Edge Config connection string - * - `EXPERIMENTATION_CONFIG_ITEM_KEY` - Vercel Edge Config item key where data is stored + * - `EXPERIMENTATION_CONFIG` - Vercel Global Config connection string + * - `EXPERIMENTATION_CONFIG_ITEM_KEY` - Vercel Global Config item key where data is stored */ export function createDefaultStatsigAdapter(): AdapterResponse { if (defaultStatsigAdapter) { @@ -267,9 +267,9 @@ export function createDefaultStatsigAdapter(): AdapterResponse { } const statsigServerApiKey = process.env.STATSIG_SERVER_API_KEY as string; const statsigProjectId = process.env.STATSIG_PROJECT_ID; - const edgeConfig = process.env.EXPERIMENTATION_CONFIG; - const edgeConfigItemKey = process.env.EXPERIMENTATION_CONFIG_ITEM_KEY; - if (!(edgeConfig && edgeConfigItemKey)) { + const globalConfig = process.env.EXPERIMENTATION_CONFIG; + const globalConfigItemKey = process.env.EXPERIMENTATION_CONFIG_ITEM_KEY; + if (!(globalConfig && globalConfigItemKey)) { defaultStatsigAdapter = createStatsigAdapter({ statsigServerApiKey, statsigProjectId, @@ -277,9 +277,9 @@ export function createDefaultStatsigAdapter(): AdapterResponse { } else { defaultStatsigAdapter = createStatsigAdapter({ statsigServerApiKey, - edgeConfig: { - connectionString: edgeConfig, - itemKey: edgeConfigItemKey, + globalConfig: { + connectionString: globalConfig, + itemKey: globalConfigItemKey, }, statsigProjectId, }); diff --git a/packages/flags/src/types.ts b/packages/flags/src/types.ts index 95e57aba..0bb9b258 100644 --- a/packages/flags/src/types.ts +++ b/packages/flags/src/types.ts @@ -26,9 +26,9 @@ export type Origin = projectId: string; } | { - provider: 'edge-config'; - edgeConfigId: string; - edgeConfigItemKey?: string; + provider: 'global-config'; + globalConfigId: string; + globalConfigItemKey?: string; teamSlug: string; } | Record; diff --git a/packages/vercel-flags-core/src/index.default.ts b/packages/vercel-flags-core/src/index.default.ts index 3431da97..b565a544 100644 --- a/packages/vercel-flags-core/src/index.default.ts +++ b/packages/vercel-flags-core/src/index.default.ts @@ -21,7 +21,7 @@ export const { * A lazily-initialized default flags client. * * - relies on process.env.FLAGS - * - does not use process.env.EDGE_CONFIG + * - does not use process.env.GLOBAL_CONFIG */ flagsClient, /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09e19044..3e0aed95 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -259,9 +259,9 @@ importers: '@vercel/edge': specifier: 1.2.1 version: 1.2.1 - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@vercel/toolbar': specifier: 0.2.7 version: 0.2.7(3524d3730989e44dd8751dbb901f98bf) @@ -326,9 +326,9 @@ importers: '@radix-ui/react-tooltip': specifier: 1.1.4 version: 1.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)) + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)) '@vercel/toolbar': specifier: 0.2.7 version: 0.2.7(e7aae08e340f7dd52d9ab2f16f5decad) @@ -434,11 +434,11 @@ importers: specifier: ^8.1.5 version: 8.1.5(@types/node@24.10.13)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) - packages/adapter-edge-config: + packages/adapter-flagsmith: dependencies: - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) + flagsmith: + specifier: ^9.0.5 + version: 9.3.2 devDependencies: '@types/node': specifier: 22.14.0 @@ -446,6 +446,9 @@ importers: flags: specifier: workspace:* version: link:../flags + msw: + specifier: 2.6.4 + version: 2.6.4(@types/node@22.14.0)(typescript@5.6.3) rimraf: specifier: 6.1.2 version: 6.1.2 @@ -462,11 +465,11 @@ importers: specifier: 4.1.10 version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.14.0)(msw@2.6.4(@types/node@22.14.0)(typescript@5.6.3))(vite@8.1.5(@types/node@22.14.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) - packages/adapter-flagsmith: + packages/adapter-global-config: dependencies: - flagsmith: - specifier: ^9.0.5 - version: 9.3.2 + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) devDependencies: '@types/node': specifier: 22.14.0 @@ -474,9 +477,6 @@ importers: flags: specifier: workspace:* version: link:../flags - msw: - specifier: 2.6.4 - version: 2.6.4(@types/node@22.14.0)(typescript@5.6.3) rimraf: specifier: 6.1.2 version: 6.1.2 @@ -498,12 +498,12 @@ importers: '@growthbook/growthbook': specifier: ^1.5.1 version: 1.6.1 - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) '@vercel/functions': specifier: ^1.5.2 version: 1.6.0 + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) devDependencies: '@types/node': specifier: 22.14.0 @@ -532,9 +532,9 @@ importers: packages/adapter-hypertune: dependencies: - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) hypertune: specifier: 2.8.3 version: 2.8.3 @@ -569,9 +569,9 @@ importers: '@launchdarkly/vercel-server-sdk': specifier: ^1.3.34 version: 1.3.34(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) devDependencies: '@types/node': specifier: 22.14.0 @@ -746,12 +746,12 @@ importers: packages/adapter-statsig: dependencies: - '@vercel/edge-config': - specifier: ^1.4.3 - version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) '@vercel/functions': specifier: ^1.5.2 version: 1.6.0 + '@vercel/global-config': + specifier: ^1.5.0 + version: 1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413)) statsig-node-lite: specifier: ^0.5.2 version: 0.5.2 @@ -4697,6 +4697,18 @@ packages: react-dom: ^19.2.3 tailwindcss: ^4.1.17 + '@vercel/global-config@1.5.0': + resolution: {integrity: sha512-YxyyzkIjlD7kHSlPpYOQun81Y1o3JUU19snytzFSex/l6h6t5kEg9UsWoG7F5BIT1aBcCmTGUtP5LpkeSN+b8w==} + engines: {node: '>=14.6'} + peerDependencies: + '@opentelemetry/api': ^1.7.0 + next: '>=1' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + next: + optional: true + '@vercel/microfrontends@2.4.0': resolution: {integrity: sha512-dpUzyjpLtE40gB+vxU3AWy5Dlkx/O91joVc/Q7PTYTtHVmw7ZkKgbR0QFEQJC0kw6SXOb35q46QN1BVwVRL5DQ==} hasBin: true @@ -12695,20 +12707,6 @@ snapshots: '@vercel/edge-config-fs@0.1.0': {} - '@vercel/edge-config@1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))': - dependencies: - '@vercel/edge-config-fs': 0.1.0 - optionalDependencies: - '@opentelemetry/api': 1.9.0 - next: 16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) - - '@vercel/edge-config@1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': - dependencies: - '@vercel/edge-config-fs': 0.1.0 - optionalDependencies: - '@opentelemetry/api': 1.9.0 - next: 16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@vercel/edge-config@1.4.3(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413))': dependencies: '@vercel/edge-config-fs': 0.1.0 @@ -12782,6 +12780,27 @@ snapshots: - vite - waku + '@vercel/global-config@1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))': + dependencies: + '@vercel/edge-config-fs': 0.1.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + next: 16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) + + '@vercel/global-config@1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': + dependencies: + '@vercel/edge-config-fs': 0.1.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + next: 16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + + '@vercel/global-config@1.5.0(@opentelemetry/api@1.9.0)(next@16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413))': + dependencies: + '@vercel/edge-config-fs': 0.1.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + next: 16.2.12(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413) + '@vercel/microfrontends@2.4.0(2703fe56f3fdc60e9aff457d6c92bf11)': dependencies: '@next/env': 16.0.10 diff --git a/skills/flags-sdk/SKILL.md b/skills/flags-sdk/SKILL.md index dc3cf017..c8596e12 100644 --- a/skills/flags-sdk/SKILL.md +++ b/skills/flags-sdk/SKILL.md @@ -5,7 +5,7 @@ description: > Use when: declaring flags with `flag()`, using `vercelAdapter` or `vercel flags` CLI (add, list, enable, disable, inspect, archive, rm, sdk-keys), setting up providers/adapters (Vercel, Statsig, LaunchDarkly, PostHog, GrowthBook, Hypertune, - Edge Config, OpenFeature, Split, Flagsmith, Reflag, Optimizely, or custom adapters), + Global Config, OpenFeature, Split, Flagsmith, Reflag, Optimizely, or custom adapters), implementing precompute patterns for static pages, setting up `identify`/`dedupe`, integrating Flags Explorer/Toolbar, working with flags in Next.js (App Router, Pages Router, Middleware) or SvelteKit, @@ -365,5 +365,5 @@ Detailed framework and provider guides are in separate files to keep context lea - **[references/nextjs.md](references/nextjs.md)**: Next.js quickstart, toolbar, App Router, Pages Router, middleware/proxy, precompute, dedupe, dashboard pages, marketing pages, suspense fallbacks - **[references/sveltekit.md](references/sveltekit.md)**: SvelteKit quickstart, toolbar, hooks setup, precompute with reroute + middleware, dashboard pages, marketing pages -- **[references/providers.md](references/providers.md)**: All provider adapters — Vercel, Edge Config, Statsig, LaunchDarkly, PostHog, GrowthBook, Hypertune, Flagsmith, Reflag, Split, Optimizely, OpenFeature, and custom adapters +- **[references/providers.md](references/providers.md)**: All provider adapters — Vercel, Global Config, Statsig, LaunchDarkly, PostHog, GrowthBook, Hypertune, Flagsmith, Reflag, Split, Optimizely, OpenFeature, and custom adapters - **[references/api.md](references/api.md)**: Full API reference for `flags`, `flags/react`, `flags/next`, and `flags/sveltekit` diff --git a/skills/flags-sdk/references/providers.md b/skills/flags-sdk/references/providers.md index f1737f77..5706bb4b 100644 --- a/skills/flags-sdk/references/providers.md +++ b/skills/flags-sdk/references/providers.md @@ -3,7 +3,7 @@ ## Table of Contents - [Vercel](#vercel) -- [Edge Config](#edge-config) +- [Global Config](#global-config) - [Statsig](#statsig) - [LaunchDarkly](#launchdarkly) - [PostHog](#posthog) @@ -192,29 +192,29 @@ Full CLI reference: https://vercel.com/docs/cli/flags --- -## Edge Config +## Global Config -Package: `@flags-sdk/edge-config` +Package: `@flags-sdk/global-config` ```bash -pnpm i @flags-sdk/edge-config +pnpm i @flags-sdk/global-config ``` -Env: `EDGE_CONFIG="edge-config-connection-string"` +Env: `GLOBAL_CONFIG="global-config-connection-string"` ### Usage ```ts import { flag } from 'flags/next'; -import { edgeConfigAdapter } from '@flags-sdk/edge-config'; +import { globalConfigAdapter } from '@flags-sdk/global-config'; export const exampleFlag = flag({ - adapter: edgeConfigAdapter, + adapter: globalConfigAdapter, key: 'example-flag', }); ``` -Edge Config should contain: +Global Config should contain: ```json { @@ -228,12 +228,12 @@ Edge Config should contain: ### Custom configuration ```ts -import { createEdgeConfigAdapter } from '@flags-sdk/edge-config'; +import { createGlobalConfigAdapter } from '@flags-sdk/global-config'; -const myAdapter = createEdgeConfigAdapter({ - connectionString: process.env.OTHER_EDGE_CONFIG, +const myAdapter = createGlobalConfigAdapter({ + connectionString: process.env.OTHER_GLOBAL_CONFIG, options: { - edgeConfigItemKey: 'other-flags-key', + globalConfigItemKey: 'other-flags-key', teamSlug: 'my-team', }, }); @@ -252,7 +252,7 @@ pnpm i @flags-sdk/statsig Env vars: - `STATSIG_SERVER_API_KEY` (required) - `STATSIG_PROJECT_ID` (optional) -- `EXPERIMENTATION_CONFIG` (optional, Edge Config) +- `EXPERIMENTATION_CONFIG` (optional, Global Config) - `EXPERIMENTATION_CONFIG_ITEM_KEY` (optional) ### Methods @@ -356,7 +356,7 @@ pnpm i @flags-sdk/launchdarkly Env vars: - `LAUNCHDARKLY_CLIENT_SIDE_ID` (required) - `LAUNCHDARKLY_PROJECT_SLUG` (required) -- `EDGE_CONFIG` (required) +- `GLOBAL_CONFIG` (required) ### Usage @@ -484,7 +484,7 @@ export const myFlag = flag({ }); ``` -### Edge Config +### Global Config Set `GROWTHBOOK_EDGE_CONNECTION_STRING` or `EXPERIMENTATION_CONFIG` (Vercel Marketplace). @@ -505,7 +505,7 @@ growthbookAdapter.setTrackingCallback((experiment, result) => { Package: `@flags-sdk/hypertune` ```bash -pnpm i hypertune flags server-only @flags-sdk/hypertune @vercel/edge-config +pnpm i hypertune flags server-only @flags-sdk/hypertune @vercel/global-config ``` Requires code generation: `npx hypertune` diff --git a/turbo.json b/turbo.json index 875d6057..60693278 100644 --- a/turbo.json +++ b/turbo.json @@ -15,7 +15,7 @@ "build": { "dependsOn": ["^build"], "env": [ - "EDGE_CONFIG", + "GLOBAL_CONFIG", "FLAGS_SECRET", "LAUNCHDARKLY_CLIENT_SIDE_ID", "LAUNCHDARKLY_PROJECT_SLUG",