diff --git a/package.json b/package.json index 0de39840af..9bf5e3b8fe 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "packages/sdk/react-native/example", "packages/sdk/react-native/contract-tests/entity", "packages/sdk/vercel", + "packages/sdk/vercel/examples/hello-vercel", "packages/sdk/svelte", "packages/sdk/svelte/example", "packages/sdk/akamai-base", diff --git a/packages/sdk/react/examples/vercel-edge/package.json b/packages/sdk/react/examples/vercel-edge/package.json index 64511ce6f3..9cea183258 100644 --- a/packages/sdk/react/examples/vercel-edge/package.json +++ b/packages/sdk/react/examples/vercel-edge/package.json @@ -1,5 +1,5 @@ { - "name": "@internal/react-sdk-example-vercel-edge", + "name": "@launchdarkly/react-sdk-example-vercel-edge", "private": true, "scripts": { "dev": "next dev", diff --git a/packages/sdk/vercel/examples/hello-vercel/.env.example b/packages/sdk/vercel/examples/hello-vercel/.env.example new file mode 100644 index 0000000000..a2f340ba13 --- /dev/null +++ b/packages/sdk/vercel/examples/hello-vercel/.env.example @@ -0,0 +1,3 @@ +LD_CLIENT_SIDE_ID= +VERCEL_EDGE_CONFIG= +LAUNCHDARKLY_FLAG_KEY=sample-feature diff --git a/packages/sdk/vercel/examples/hello-vercel/.gitignore b/packages/sdk/vercel/examples/hello-vercel/.gitignore new file mode 100644 index 0000000000..125e2118ea --- /dev/null +++ b/packages/sdk/vercel/examples/hello-vercel/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.env* +!.env.example diff --git a/packages/sdk/vercel/examples/hello-vercel/README.md b/packages/sdk/vercel/examples/hello-vercel/README.md new file mode 100644 index 0000000000..4440377956 --- /dev/null +++ b/packages/sdk/vercel/examples/hello-vercel/README.md @@ -0,0 +1,51 @@ +# LaunchDarkly sample Vercel application + +We've built a simple console application that demonstrates how the LaunchDarkly Vercel server SDK works. +The app evaluates feature flags using data stored in +[Vercel Edge Config](https://vercel.com/docs/edge-config/overview). + +Below, you'll find the build procedure. For more comprehensive instructions, you can visit your +[Quickstart page](https://app.launchdarkly.com/quickstart#/) or the +[Vercel SDK reference guide](https://docs.launchdarkly.com/sdk/server-side/vercel). + +## Prerequisites + +This example requires the [LaunchDarkly Vercel integration](https://vercel.com/integrations/launchdarkly) +to be configured. The integration syncs your LaunchDarkly flag data to Vercel Edge Config so that +the Vercel SDK can read it without connecting to LaunchDarkly servers. + +## Build instructions + +1. Set the `VERCEL_EDGE_CONFIG` environment variable to your Vercel Edge Config connection string. + You can find this in your Vercel project settings under Edge Config. + + ```bash + export VERCEL_EDGE_CONFIG="https://edge-config.vercel.com/ecfg_..." + ``` + +2. Set the `LD_CLIENT_SIDE_ID` environment variable to your LaunchDarkly client-side ID. + The Vercel SDK uses this to look up flag data in Edge Config. + + ```bash + export LD_CLIENT_SIDE_ID="my-client-side-id" + ``` + +3. If there is an existing boolean feature flag in your LaunchDarkly project that you want to + evaluate, set `LAUNCHDARKLY_FLAG_KEY`: + + ```bash + export LAUNCHDARKLY_FLAG_KEY="my-flag-key" + ``` + + Otherwise, `sample-feature` will be used by default. + +4. On the command line, run `yarn start`: + + ```bash + yarn start + ``` + + You should receive the message: + > "The sample-feature feature flag evaluates to true." + +The application will run continuously and react to the flag changes in LaunchDarkly. diff --git a/packages/sdk/vercel/examples/hello-vercel/package.json b/packages/sdk/vercel/examples/hello-vercel/package.json new file mode 100644 index 0000000000..a68d198b04 --- /dev/null +++ b/packages/sdk/vercel/examples/hello-vercel/package.json @@ -0,0 +1,18 @@ +{ + "name": "@launchdarkly/hello-vercel", + "private": true, + "version": "1.0.0", + "type": "commonjs", + "scripts": { + "build": "tsc", + "start": "yarn build && node ./dist/index.js" + }, + "dependencies": { + "@launchdarkly/vercel-server-sdk": "1.3.43", + "@vercel/edge-config": "^1.1.0" + }, + "devDependencies": { + "@types/node": "^20", + "typescript": "^5" + } +} diff --git a/packages/sdk/vercel/examples/hello-vercel/src/index.ts b/packages/sdk/vercel/examples/hello-vercel/src/index.ts new file mode 100644 index 0000000000..a8f97c94e1 --- /dev/null +++ b/packages/sdk/vercel/examples/hello-vercel/src/index.ts @@ -0,0 +1,81 @@ +/* eslint-disable no-console */ +import { createClient } from '@vercel/edge-config'; + +import { init } from '@launchdarkly/vercel-server-sdk'; + +const clientSideId = process.env.LD_CLIENT_SIDE_ID; +const edgeConfig = process.env.VERCEL_EDGE_CONFIG; + +// Set flagKey to the feature flag key you want to evaluate. +const flagKey = process.env.LAUNCHDARKLY_FLAG_KEY || 'sample-feature'; + +// Set up the evaluation context. This context should appear on your +// LaunchDarkly contexts dashboard soon after you run the demo. +const context = { kind: 'user' as const, key: 'example-user-key', name: 'Sandy' }; + +const ASCII_ART = ` + ██ + ██ + ████████ + ███████ +██ LAUNCHDARKLY █ + ███████ + ████████ + ██ + ██ +`; + +if (!clientSideId) { + console.error( + 'LaunchDarkly client-side ID is required: set the LD_CLIENT_SIDE_ID environment variable and try again.', + ); + process.exit(1); +} + +if (!edgeConfig) { + console.error( + 'Vercel Edge Config is required: set the VERCEL_EDGE_CONFIG environment variable and try again.', + ); + process.exit(1); +} + +const edgeConfigClient = createClient(edgeConfig); +const ldClient = init(clientSideId, edgeConfigClient); + +async function main() { + try { + await ldClient.waitForInitialization(); + console.log('*** SDK successfully initialized!'); + } catch { + console.error( + '*** SDK failed to initialize. Please check your Edge Config connection and LaunchDarkly client-side ID for any issues.', + ); + process.exit(1); + } + + let previousValue: boolean | undefined; + + const evaluate = async () => { + const flagValue = await ldClient.boolVariation(flagKey, context, false); + + if (flagValue !== previousValue) { + console.log(`\n*** The ${flagKey} feature flag evaluates to ${flagValue}.`); + + if (flagValue) { + console.log(ASCII_ART); + } + + previousValue = flagValue; + } + }; + + await evaluate(); + + // In CI mode, evaluate once and exit. Otherwise, poll every second to pick + // up flag changes — the "run continuously" behavior required by the spec. + if (!process.env.CI) { + setInterval(() => evaluate().catch(console.error), 1000); + } +} + +main().catch(console.error); diff --git a/packages/sdk/vercel/examples/hello-vercel/tsconfig.json b/packages/sdk/vercel/examples/hello-vercel/tsconfig.json new file mode 100644 index 0000000000..0754720dcf --- /dev/null +++ b/packages/sdk/vercel/examples/hello-vercel/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "Node", + "outDir": "dist", + "noEmit": false, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] +} diff --git a/release-please-config.json b/release-please-config.json index a667b4b38c..68d49ebf42 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -177,6 +177,11 @@ "type": "json", "path": "/packages/sdk/react/examples/vercel-edge/package.json", "jsonpath": "$.dependencies['@launchdarkly/vercel-server-sdk']" + }, + { + "type": "json", + "path": "/packages/sdk/vercel/examples/hello-vercel/package.json", + "jsonpath": "$.dependencies['@launchdarkly/vercel-server-sdk']" } ] },