From 00ecc9a70050063c4410183b0476e19c6c182989 Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 13 Dec 2024 15:51:50 +0000 Subject: [PATCH 01/11] Start on Fastly SDK --- package.json | 2 + packages/sdk/fastly/README.md | 1 + packages/sdk/fastly/example/.gitignore | 4 + packages/sdk/fastly/example/README copy.md | 44 ++++++ packages/sdk/fastly/example/README.md | 1 + packages/sdk/fastly/example/fastly copy.toml | 28 ++++ packages/sdk/fastly/example/fastly.toml | 28 ++++ packages/sdk/fastly/example/package.json | 27 ++++ packages/sdk/fastly/example/src/index.ts | 125 ++++++++++++++++++ .../example/src/welcome-to-compute.html | 30 +++++ packages/sdk/fastly/example/tsconfig.json | 28 ++++ .../sdk/fastly/example/webpack.config.cjs | 51 +++++++ packages/sdk/fastly/package.json | 50 +++++++ packages/sdk/fastly/src/createPlatformInfo.ts | 21 +++ packages/sdk/fastly/src/index.ts | 32 +++++ packages/sdk/fastly/tsconfig.json | 33 +++++ packages/sdk/fastly/typedoc.json | 5 + .../sdk-server-edge/src/api/LDClient.ts | 10 +- packages/shared/sdk-server-edge/src/index.ts | 1 + .../sdk-server-edge/src/platform/index.ts | 8 +- .../sdk-server-edge/src/platform/requests.ts | 15 ++- .../src/utils/validateOptions.ts | 10 +- 22 files changed, 543 insertions(+), 11 deletions(-) create mode 100644 packages/sdk/fastly/README.md create mode 100644 packages/sdk/fastly/example/.gitignore create mode 100644 packages/sdk/fastly/example/README copy.md create mode 100644 packages/sdk/fastly/example/README.md create mode 100644 packages/sdk/fastly/example/fastly copy.toml create mode 100644 packages/sdk/fastly/example/fastly.toml create mode 100644 packages/sdk/fastly/example/package.json create mode 100644 packages/sdk/fastly/example/src/index.ts create mode 100644 packages/sdk/fastly/example/src/welcome-to-compute.html create mode 100644 packages/sdk/fastly/example/tsconfig.json create mode 100644 packages/sdk/fastly/example/webpack.config.cjs create mode 100644 packages/sdk/fastly/package.json create mode 100644 packages/sdk/fastly/src/createPlatformInfo.ts create mode 100644 packages/sdk/fastly/src/index.ts create mode 100644 packages/sdk/fastly/tsconfig.json create mode 100644 packages/sdk/fastly/typedoc.json diff --git a/package.json b/package.json index 4444b7c8fe..8d886ff736 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "packages/sdk/server-node", "packages/sdk/cloudflare", "packages/sdk/cloudflare/example", + "packages/sdk/fastly", + "packages/sdk/fastly/example", "packages/sdk/react-native", "packages/sdk/react-native/example", "packages/sdk/react-universal", diff --git a/packages/sdk/fastly/README.md b/packages/sdk/fastly/README.md new file mode 100644 index 0000000000..fe2288c1d4 --- /dev/null +++ b/packages/sdk/fastly/README.md @@ -0,0 +1 @@ +# fastly diff --git a/packages/sdk/fastly/example/.gitignore b/packages/sdk/fastly/example/.gitignore new file mode 100644 index 0000000000..e409a41625 --- /dev/null +++ b/packages/sdk/fastly/example/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/bin +/build +/pkg diff --git a/packages/sdk/fastly/example/README copy.md b/packages/sdk/fastly/example/README copy.md new file mode 100644 index 0000000000..838d9296e8 --- /dev/null +++ b/packages/sdk/fastly/example/README copy.md @@ -0,0 +1,44 @@ +# Default Starter Kit For TypeScript + +[![Deploy to Fastly](https://deploy.edgecompute.app/button)](https://deploy.edgecompute.app/deploy) + +Get to know the Fastly Compute environment with a basic starter that demonstrates routing, simple synthetic responses and code comments that cover common patterns. + +**For more details about other starter kits for Compute, see the [Fastly Documentation Hub](https://www.fastly.com/documentation/solutions/starters)** + +## Features +* Allow only requests with particular HTTP methods +* Match request URL path and methods for routing +* Build synthetic responses at the edge + +## Understanding the code + +This starter is intentionally lightweight, and requires no dependencies aside from the [`@fastly/js-compute`](https://www.npmjs.com/package/@fastly/js-compute) npm package. It will help you understand the basics of processing requests at the edge using Fastly. This starter includes implementations of common patterns explained in our [using Compute](https://www.fastly.com/documentation/guides/compute/javascript/) and [VCL migration](https://www.fastly.com/documentation/guides/compute/migrate/) guides. + +The starter doesn't require the use of any backends. Once deployed, you will have a Fastly service running on Compute that can generate synthetic responses at the edge. + +The template uses TypeScript to compile source files in `./src` into JS files in `./build`, which are then wrapped into `./bin/index.wasm` using the `js-compute-runtime` CLI tool bundled with the `@fastly/js-compute` npm package, and bundled into a `.tar.gz` file ready for deployment to Compute. + +## Running the application + +To create an application using this starter kit, create a new directory for your application and switch to it, and then type the following command: + +```shell +npm create @fastly/compute@latest -- --language=typescript --default-starter-kit +``` + +To build and run your new application in the local development environment, type the following command: + +```shell +npm run start +``` + +To build and deploy your application to your Fastly account, type the following command. The first time you deploy the application, you will be prompted to create a new service in your account. + +```shell +npm run deploy +``` + +## Security issues + +Please see our [SECURITY.md](SECURITY.md) for guidance on reporting security-related issues. diff --git a/packages/sdk/fastly/example/README.md b/packages/sdk/fastly/example/README.md new file mode 100644 index 0000000000..02dc8ac17f --- /dev/null +++ b/packages/sdk/fastly/example/README.md @@ -0,0 +1 @@ +# example diff --git a/packages/sdk/fastly/example/fastly copy.toml b/packages/sdk/fastly/example/fastly copy.toml new file mode 100644 index 0000000000..48ef458f2b --- /dev/null +++ b/packages/sdk/fastly/example/fastly copy.toml @@ -0,0 +1,28 @@ +# This file describes a Fastly Compute package. To learn more visit: +# https://www.fastly.com/documentation/reference/compute/fastly-toml + +authors = [] +cloned_from = "J4RQReO3g9zZdp3eDM8Sr5" +description = "A basic starter kit that demonstrates routing, simple synthetic responses and overriding caching rules." +language = "javascript" +manifest_version = 3 +name = "Default starter for TypeScript" +service_id = "J4RQReO3g9zZdp3eDM8Sr5" + +[scripts] +build = "npm run build" +post_init = "npm install" + +[local_server] + + [local_server.backends] + + [local_server.kv_stores] + + [[local_server.kv_stores.testkv]] + data = "placeholder" + key = "placeholder" + + [[local_server.kv_stores.testkv]] + key = "readme" + path = "./README.md" \ No newline at end of file diff --git a/packages/sdk/fastly/example/fastly.toml b/packages/sdk/fastly/example/fastly.toml new file mode 100644 index 0000000000..4541de83d5 --- /dev/null +++ b/packages/sdk/fastly/example/fastly.toml @@ -0,0 +1,28 @@ +# This file describes a Fastly Compute package. To learn more visit: +# https://www.fastly.com/documentation/reference/compute/fastly-toml + +authors = [] +cloned_from = "J4RQReO3g9zZdp3eDM8Sr5" +description = "A basic starter kit that demonstrates routing, simple synthetic responses and overriding caching rules." +language = "javascript" +manifest_version = 3 +name = "Default starter for TypeScript" +service_id = "J4RQReO3g9zZdp3eDM8Sr5" + +[scripts] +build = "yarn build" +post_init = "yarn install" + +[local_server] + + [local_server.backends] + + [local_server.kv_stores] + + [[local_server.kv_stores.testkv]] + data = "placeholder" + key = "placeholder" + + [[local_server.kv_stores.testkv]] + key = "readme" + path = "./README.md" \ No newline at end of file diff --git a/packages/sdk/fastly/example/package.json b/packages/sdk/fastly/example/package.json new file mode 100644 index 0000000000..cada903cae --- /dev/null +++ b/packages/sdk/fastly/example/package.json @@ -0,0 +1,27 @@ +{ + "name": "fastly-example", + "packageManager": "yarn@3.4.1", + "type": "module", + "engines": { + "node": "^16 || >=18" + }, + "devDependencies": { + "@fastly/cli": "^10.14.0", + "node-polyfill-webpack-plugin": "^4.1.0", + "ts-loader": "^9.5.1", + "typescript": "^5.2.2", + "webpack": "^5.97.1", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "@fastly/js-compute": "^3.7.0", + "@launchdarkly/fastly-server-sdk": "workspace:^", + "eventemitter3": "^5.0.1", + "events": "^3.3.0" + }, + "scripts": { + "build": "webpack && js-compute-runtime dist/index.js bin/main.wasm", + "start": "fastly compute serve", + "deploy": "fastly compute publish" + } +} diff --git a/packages/sdk/fastly/example/src/index.ts b/packages/sdk/fastly/example/src/index.ts new file mode 100644 index 0000000000..c26f122591 --- /dev/null +++ b/packages/sdk/fastly/example/src/index.ts @@ -0,0 +1,125 @@ +//! Default Compute template program. +/// +// import { CacheOverride } from "fastly:cache-override"; +import { env } from 'fastly:env'; +import { allowDynamicBackends, includeBytes } from 'fastly:experimental'; +import { KVStore } from 'fastly:kv-store'; +import { Logger } from 'fastly:logger'; + +import { init } from '@launchdarkly/fastly-server-sdk'; +import { LDContext } from '@launchdarkly/js-sdk-common'; +import { LDClient } from '@launchdarkly/js-server-sdk-common-edge'; + +// Load a static file as a Uint8Array at compile time. +// File path is relative to root of project, not to this file +const welcomePage = includeBytes('./src/welcome-to-compute.html'); + +// The entry point for your application. +// +// Use this fetch event listener to define your main request handling logic. It +// could be used to route based on the request properties (such as method or +// path), send the request to a backend, make completely new requests, and/or +// generate synthetic responses. + +addEventListener('fetch', (event) => event.respondWith(handleRequest(event))); + +async function flushEvents(ldClient: LDClient) { + console.log('Flushing events'); + await ldClient.flush(); + console.log('Events flushed'); +} + +async function handleRequest(event: FetchEvent) { + const logger = new Logger('handleRequest'); + + // Log service version + console.log('FASTLY_SERVICE_VERSION:', env('FASTLY_SERVICE_VERSION') || 'local'); + + // Get the client request. + let req = event.request; + + // Filter requests that have unexpected methods. + if (!['HEAD', 'GET', 'PURGE'].includes(req.method)) { + return new Response('This method is not allowed', { + status: 405, + }); + } + + let url = new URL(req.url); + + // If request is to the `/` path... + if (url.pathname == '/') { + // Below are some common patterns for Fastly Compute services using JavaScript. + // Head to https://developer.fastly.com/learning/compute/javascript/ to discover more. + + // Create a new request. + // let bereq = new Request("http://example.com"); + + // Add request headers. + // req.headers.set("X-Custom-Header", "Welcome to Fastly Compute!"); + // req.headers.set( + // "X-Another-Custom-Header", + // "Recommended reading: https://developer.fastly.com/learning/compute" + // ); + + // Create a cache override. + // To use this, uncomment the import statement at the top of this file for CacheOverride. + // let cacheOverride = new CacheOverride("override", { ttl: 60 }); + + // Forward the request to a backend. + // let beresp = await fetch(req, { + // backend: "backend_name", + // cacheOverride, + // }); + + // Remove response headers. + // beresp.headers.delete("X-Another-Custom-Header"); + + // Log to a Fastly endpoint. + // To use this, uncomment the import statement at the top of this file for Logger. + // const logger = new Logger("my_endpoint"); + // logger.log("Hello from the edge!"); + + // Send a default synthetic response. + + return new Response(welcomePage, { + status: 200, + headers: new Headers({ 'Content-Type': 'text/html; charset=utf-8' }), + }); + } + + const store = new KVStore('testkv'); + const ldClient = init(store, '675aea6b1b327709c85da941', { + sendEvents: true, + }); + await ldClient.waitForInitialization(); + const flagKey = 'enable-2025-brand-refresh'; + const flagContext: LDContext = { + key: 'test-user', + custom: { + fastly_service_version: env('FASTLY_SERVICE_VERSION'), + fastly_cache_generation: env('FASTLY_CACHE_GENERATION'), + fastly_hostname: env('FASTLY_HOSTNAME'), + fastly_pop: env('FASTLY_POP'), + fastly_region: env('FASTLY_REGION'), + fastly_service_id: env('FASTLY_SERVICE_ID'), + fastly_trace_id: env('FASTLY_TRACE_ID'), + }, + }; + const variationDetail = await ldClient.boolVariationDetail(flagKey, flagContext, false); + logger.log(`Flag value: ${variationDetail}`); + + const output = { + flagContext, + variationDetail: variationDetail, + }; + event.waitUntil(flushEvents(ldClient)); + await flushEvents(ldClient); + + // // Catch all other requests and return a 404. + // const text = (await readme?.text()) || 'The page you requested could not be found'; + return new Response(JSON.stringify(output, undefined, 2), { + status: 404, + headers: new Headers({ 'Content-Type': 'application/json' }), + }); +} diff --git a/packages/sdk/fastly/example/src/welcome-to-compute.html b/packages/sdk/fastly/example/src/welcome-to-compute.html new file mode 100644 index 0000000000..cc18336ddb --- /dev/null +++ b/packages/sdk/fastly/example/src/welcome-to-compute.html @@ -0,0 +1,30 @@ + + + + + + + Welcome to Fastly Compute + + + + + + diff --git a/packages/sdk/fastly/example/tsconfig.json b/packages/sdk/fastly/example/tsconfig.json new file mode 100644 index 0000000000..c58b2cb87f --- /dev/null +++ b/packages/sdk/fastly/example/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "strict": true, + "module": "ES2022", + "target": "ES2022", + "moduleResolution": "bundler", + "customConditions": [ + "fastly" + ], + "esModuleInterop": true, + "lib": [ + "ES2022" + ], + "rootDir": "src", + "outDir": "build", + "types": [ + "@fastly/js-compute" + ], + "skipLibCheck": true + }, + "include": [ + "./src/**/*.js", + "./src/**/*.ts", + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/packages/sdk/fastly/example/webpack.config.cjs b/packages/sdk/fastly/example/webpack.config.cjs new file mode 100644 index 0000000000..bf0dcfd56a --- /dev/null +++ b/packages/sdk/fastly/example/webpack.config.cjs @@ -0,0 +1,51 @@ +const path = require('path'); +const webpack = require('webpack'); + +module.exports = { + entry: './src/index.ts', + optimization: { + minimize: false, + }, + target: 'webworker', + module: { + rules: [ + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /\.js$/, + type: 'javascript/auto', + resolve: { + fullySpecified: false, + }, + }, + ], + }, + resolve: { + extensions: ['.tsx', '.ts', '.js'], + extensionAlias: { + '.js': ['.js', '.ts'], + }, + fullySpecified: false, + mainFields: ['module', 'main'], + fallback: { + events: require.resolve('events/'), + }, + }, + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + }, + externals: [ + ({ request }, callback) => { + if (/^fastly:.*$/.test(request)) { + return callback(null, 'commonjs ' + request); + } + callback(); + }, + ], + mode: 'production', + plugins: [new webpack.NormalModuleReplacementPlugin(/^node:events$/, require.resolve('events/'))], +}; diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json new file mode 100644 index 0000000000..82643f83a3 --- /dev/null +++ b/packages/sdk/fastly/package.json @@ -0,0 +1,50 @@ +{ + "name": "@launchdarkly/fastly-server-sdk", + "version": "0.0.1", + "packageManager": "yarn@3.4.1", + "description": "Cloudflare LaunchDarkly SDK", + "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/cloudflare", + "repository": { + "type": "git", + "url": "https://github.com/launchdarkly/js-core.git" + }, + "license": "Apache-2.0", + "keywords": [ + "launchdarkly", + "fastly", + "edge", + "compute", + "kv" + ], + "type": "module", + "exports": { + "require": "./dist/cjs/src/index.js", + "import": "./dist/esm/src/index.js" + }, + "main": "./dist/cjs/src/index.js", + "types": "./dist/cjs/src/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "../../../scripts/build-package.sh && ../../../scripts/replace-version.sh .", + "clean": "rimraf dist", + "tsw": "yarn tsc --watch", + "start": "rimraf dist && yarn tsw", + "lint": "eslint . --ext .ts", + "prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore", + "check": "yarn prettier && yarn lint && yarn build && yarn test" + }, + "dependencies": { + "@fastly/js-compute": "^3.28.0" + }, + "devDependencies": { + "@launchdarkly/js-server-sdk-common-edge": "2.5.2", + "eslint": "^8.45.0", + "prettier": "^3.4.2", + "rimraf": "^6.0.1", + "rollup": "^4.28.1", + "typedoc": "^0.27.4", + "typescript": "^5.7.2" + } +} diff --git a/packages/sdk/fastly/src/createPlatformInfo.ts b/packages/sdk/fastly/src/createPlatformInfo.ts new file mode 100644 index 0000000000..57fb569179 --- /dev/null +++ b/packages/sdk/fastly/src/createPlatformInfo.ts @@ -0,0 +1,21 @@ +import type { Info, PlatformData, SdkData } from '@launchdarkly/js-server-sdk-common-edge'; + +class VercelPlatformInfo implements Info { + platformData(): PlatformData { + return { + name: 'Fastly Edge', + }; + } + + sdkData(): SdkData { + return { + name: '@launchdarkly/fastly-server-sdk', + version: '__LD_VERSION__', + userAgentBase: 'FastlyEdgeSDK', + }; + } +} + +const createPlatformInfo = () => new VercelPlatformInfo(); + +export default createPlatformInfo; diff --git a/packages/sdk/fastly/src/index.ts b/packages/sdk/fastly/src/index.ts new file mode 100644 index 0000000000..dc3af43a2e --- /dev/null +++ b/packages/sdk/fastly/src/index.ts @@ -0,0 +1,32 @@ +/// +import { KVStore } from 'fastly:kv-store'; + +import { + BasicLogger, + EdgeFeatureStore, + EdgeProvider, + init as initEdge, + LDOptions, +} from '@launchdarkly/js-server-sdk-common-edge'; + +import createPlatformInfo from './createPlatformInfo'; + +export const init = (kvStore: KVStore, sdkKey: string, options: LDOptions = {}) => { + const logger = options.logger ?? BasicLogger.get(); + + const edgeProvider: EdgeProvider = { + get: async (rootKey: string) => { + const entry = await kvStore.get(rootKey); + return entry ? await entry.text() : null; + }, + }; + + return initEdge(sdkKey, createPlatformInfo(), { + featureStore: new EdgeFeatureStore(edgeProvider, sdkKey, 'Fastly', logger), + logger, + additionalFetchOptions: { + backend: 'launchdarkly', + }, + ...options, + }); +}; diff --git a/packages/sdk/fastly/tsconfig.json b/packages/sdk/fastly/tsconfig.json new file mode 100644 index 0000000000..78ac937afe --- /dev/null +++ b/packages/sdk/fastly/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + // Uses "." so it can load package.json. + "rootDir": ".", + "outDir": "dist", + "target": "es2017", + "lib": [ + "es6" + ], + "module": "commonjs", + "strict": true, + "noImplicitOverride": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "declaration": true, + "declarationMap": true, // enables importers to jump to source + "resolveJsonModule": true, + "stripInternal": true, + "moduleResolution": "node", + "types": [ + "jest", + "node" + ], + "skipLibCheck": true + }, + "exclude": [ + "**/*.test.ts", + "dist", + "node_modules", + "__tests__", + "example" + ] +} \ No newline at end of file diff --git a/packages/sdk/fastly/typedoc.json b/packages/sdk/fastly/typedoc.json new file mode 100644 index 0000000000..7ac616b544 --- /dev/null +++ b/packages/sdk/fastly/typedoc.json @@ -0,0 +1,5 @@ +{ + "extends": ["../../../typedoc.base.json"], + "entryPoints": ["src/index.ts"], + "out": "docs" +} diff --git a/packages/shared/sdk-server-edge/src/api/LDClient.ts b/packages/shared/sdk-server-edge/src/api/LDClient.ts index 503c30ba28..f7f7810184 100644 --- a/packages/shared/sdk-server-edge/src/api/LDClient.ts +++ b/packages/shared/sdk-server-edge/src/api/LDClient.ts @@ -1,8 +1,9 @@ import { EventEmitter } from 'node:events'; -import { Info, internal, LDClientImpl, LDOptions } from '@launchdarkly/js-server-sdk-common'; +import { Info, internal, LDClientImpl } from '@launchdarkly/js-server-sdk-common'; import EdgePlatform from '../platform'; +import { LDOptionsInternal } from '../utils/validateOptions'; import createCallbacks from './createCallbacks'; import createOptions from './createOptions'; @@ -13,16 +14,17 @@ export default class LDClient extends LDClientImpl { emitter: EventEmitter; // clientSideID is only used to query the edge key-value store and send analytics, not to initialize with LD servers - constructor(clientSideID: string, platformInfo: Info, options: LDOptions) { + constructor(clientSideID: string, platformInfo: Info, options: LDOptionsInternal) { const em = new EventEmitter(); - const platform = new EdgePlatform(platformInfo); + const { additionalFetchOptions, ...remainingOptions } = options; + const platform = new EdgePlatform(platformInfo, additionalFetchOptions); const internalOptions: internal.LDInternalOptions = { analyticsEventPath: `/events/bulk/${clientSideID}`, diagnosticEventPath: `/events/diagnostic/${clientSideID}`, includeAuthorizationHeader: false, }; - const finalOptions = createOptions(options); + const finalOptions = createOptions(remainingOptions); super( clientSideID, diff --git a/packages/shared/sdk-server-edge/src/index.ts b/packages/shared/sdk-server-edge/src/index.ts index 24a6c49b77..6ec534092f 100644 --- a/packages/shared/sdk-server-edge/src/index.ts +++ b/packages/shared/sdk-server-edge/src/index.ts @@ -22,6 +22,7 @@ export type { LDClient, LDOptions, EdgeProvider }; export const init = (clientSideID: string, platformInfo: Info, options: LDOptionsInternal) => { // this throws if options are invalid validateOptions(clientSideID, options); + console.log('options', options); return new LDClient(clientSideID, platformInfo, options); }; diff --git a/packages/shared/sdk-server-edge/src/platform/index.ts b/packages/shared/sdk-server-edge/src/platform/index.ts index 9210f6b024..35795031ce 100644 --- a/packages/shared/sdk-server-edge/src/platform/index.ts +++ b/packages/shared/sdk-server-edge/src/platform/index.ts @@ -1,16 +1,18 @@ import type { Crypto, Info, Platform, Requests } from '@launchdarkly/js-server-sdk-common'; import EdgeCrypto from './crypto'; -import EdgeRequests from './requests'; +import EdgeRequests, { EdgeRequestsOptions } from './requests'; export default class EdgePlatform implements Platform { info: Info; crypto: Crypto = new EdgeCrypto(); - requests: Requests = new EdgeRequests(); + requests: Requests; - constructor(info: Info) { + constructor(info: Info, edgeRequestsOptions: Record = {}) { + console.log('edgeRequestsOptions', edgeRequestsOptions); this.info = info; + this.requests = new EdgeRequests({ additionalFetchOptions: edgeRequestsOptions }); } } diff --git a/packages/shared/sdk-server-edge/src/platform/requests.ts b/packages/shared/sdk-server-edge/src/platform/requests.ts index 413bbb6b32..32aba96c08 100644 --- a/packages/shared/sdk-server-edge/src/platform/requests.ts +++ b/packages/shared/sdk-server-edge/src/platform/requests.ts @@ -8,10 +8,23 @@ import type { Response, } from '@launchdarkly/js-server-sdk-common'; +export interface EdgeRequestsOptions { + additionalFetchOptions?: Record; +} + export default class EdgeRequests implements Requests { + private options: EdgeRequestsOptions; + + constructor(options: EdgeRequestsOptions = {}) { + this.options = options; + } + fetch(url: string, options: Options = {}): Promise { + const finalOptions = { ...options, ...this.options.additionalFetchOptions }; + console.log(finalOptions); + console.log('Additional options', this.options.additionalFetchOptions); // @ts-ignore - return fetch(url, options); + return fetch(url, finalOptions); } createEventSource(url: string, eventSourceInitDict: EventSourceInitDict): EventSource { diff --git a/packages/shared/sdk-server-edge/src/utils/validateOptions.ts b/packages/shared/sdk-server-edge/src/utils/validateOptions.ts index c65fa083aa..c867502096 100644 --- a/packages/shared/sdk-server-edge/src/utils/validateOptions.ts +++ b/packages/shared/sdk-server-edge/src/utils/validateOptions.ts @@ -1,20 +1,24 @@ import { LDOptions as LDOptionsCommon } from '@launchdarkly/js-server-sdk-common'; +import { EdgeRequestsOptions } from '../platform/requests'; + /** * The Launchdarkly Edge SDKs configuration options. Only logger is officially * supported. sendEvents is unsupported and is only included as a beta * preview. */ -export type LDOptions = Pick; +export type LDOptions = Pick; /** * The internal options include featureStore because that's how the LDClient * implementation expects it. */ -export type LDOptionsInternal = LDOptions & Pick; +export type LDOptionsInternal = LDOptions & + EdgeRequestsOptions & + Pick; const validateOptions = (sdkKey: string, options: LDOptionsInternal) => { - const { featureStore, logger, sendEvents, ...rest } = options; + const { featureStore, logger, sendEvents, additionalFetchOptions, ...rest } = options; if (!sdkKey) { throw new Error('You must configure the client with a client key'); } From 809e1cd7345f3c3555f192308d1c3de9910f36eb Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Wed, 18 Dec 2024 15:25:13 -0800 Subject: [PATCH 02/11] polyfill node:events in fastly sdk instead of example --- packages/sdk/fastly/example/README copy.md | 44 --------- packages/sdk/fastly/example/fastly copy.toml | 28 ------ packages/sdk/fastly/example/package.json | 12 +-- packages/sdk/fastly/example/src/cat.jpeg | Bin 0 -> 5629 bytes packages/sdk/fastly/example/src/dog.jpeg | Bin 0 -> 159620 bytes packages/sdk/fastly/example/src/index.ts | 78 ++++++++++----- .../sdk/fastly/example/webpack.config.cjs | 51 ---------- packages/sdk/fastly/package.json | 24 ++++- packages/sdk/fastly/rollup.config.js | 90 ++++++++++++++++++ .../sdk-server-edge/src/platform/index.ts | 3 +- .../sdk-server-edge/src/platform/requests.ts | 8 +- 11 files changed, 168 insertions(+), 170 deletions(-) delete mode 100644 packages/sdk/fastly/example/README copy.md delete mode 100644 packages/sdk/fastly/example/fastly copy.toml create mode 100644 packages/sdk/fastly/example/src/cat.jpeg create mode 100644 packages/sdk/fastly/example/src/dog.jpeg delete mode 100644 packages/sdk/fastly/example/webpack.config.cjs create mode 100644 packages/sdk/fastly/rollup.config.js diff --git a/packages/sdk/fastly/example/README copy.md b/packages/sdk/fastly/example/README copy.md deleted file mode 100644 index 838d9296e8..0000000000 --- a/packages/sdk/fastly/example/README copy.md +++ /dev/null @@ -1,44 +0,0 @@ -# Default Starter Kit For TypeScript - -[![Deploy to Fastly](https://deploy.edgecompute.app/button)](https://deploy.edgecompute.app/deploy) - -Get to know the Fastly Compute environment with a basic starter that demonstrates routing, simple synthetic responses and code comments that cover common patterns. - -**For more details about other starter kits for Compute, see the [Fastly Documentation Hub](https://www.fastly.com/documentation/solutions/starters)** - -## Features -* Allow only requests with particular HTTP methods -* Match request URL path and methods for routing -* Build synthetic responses at the edge - -## Understanding the code - -This starter is intentionally lightweight, and requires no dependencies aside from the [`@fastly/js-compute`](https://www.npmjs.com/package/@fastly/js-compute) npm package. It will help you understand the basics of processing requests at the edge using Fastly. This starter includes implementations of common patterns explained in our [using Compute](https://www.fastly.com/documentation/guides/compute/javascript/) and [VCL migration](https://www.fastly.com/documentation/guides/compute/migrate/) guides. - -The starter doesn't require the use of any backends. Once deployed, you will have a Fastly service running on Compute that can generate synthetic responses at the edge. - -The template uses TypeScript to compile source files in `./src` into JS files in `./build`, which are then wrapped into `./bin/index.wasm` using the `js-compute-runtime` CLI tool bundled with the `@fastly/js-compute` npm package, and bundled into a `.tar.gz` file ready for deployment to Compute. - -## Running the application - -To create an application using this starter kit, create a new directory for your application and switch to it, and then type the following command: - -```shell -npm create @fastly/compute@latest -- --language=typescript --default-starter-kit -``` - -To build and run your new application in the local development environment, type the following command: - -```shell -npm run start -``` - -To build and deploy your application to your Fastly account, type the following command. The first time you deploy the application, you will be prompted to create a new service in your account. - -```shell -npm run deploy -``` - -## Security issues - -Please see our [SECURITY.md](SECURITY.md) for guidance on reporting security-related issues. diff --git a/packages/sdk/fastly/example/fastly copy.toml b/packages/sdk/fastly/example/fastly copy.toml deleted file mode 100644 index 48ef458f2b..0000000000 --- a/packages/sdk/fastly/example/fastly copy.toml +++ /dev/null @@ -1,28 +0,0 @@ -# This file describes a Fastly Compute package. To learn more visit: -# https://www.fastly.com/documentation/reference/compute/fastly-toml - -authors = [] -cloned_from = "J4RQReO3g9zZdp3eDM8Sr5" -description = "A basic starter kit that demonstrates routing, simple synthetic responses and overriding caching rules." -language = "javascript" -manifest_version = 3 -name = "Default starter for TypeScript" -service_id = "J4RQReO3g9zZdp3eDM8Sr5" - -[scripts] -build = "npm run build" -post_init = "npm install" - -[local_server] - - [local_server.backends] - - [local_server.kv_stores] - - [[local_server.kv_stores.testkv]] - data = "placeholder" - key = "placeholder" - - [[local_server.kv_stores.testkv]] - key = "readme" - path = "./README.md" \ No newline at end of file diff --git a/packages/sdk/fastly/example/package.json b/packages/sdk/fastly/example/package.json index cada903cae..85920a549d 100644 --- a/packages/sdk/fastly/example/package.json +++ b/packages/sdk/fastly/example/package.json @@ -7,20 +7,14 @@ }, "devDependencies": { "@fastly/cli": "^10.14.0", - "node-polyfill-webpack-plugin": "^4.1.0", - "ts-loader": "^9.5.1", - "typescript": "^5.2.2", - "webpack": "^5.97.1", - "webpack-cli": "^5.1.4" + "typescript": "^5.2.2" }, "dependencies": { "@fastly/js-compute": "^3.7.0", - "@launchdarkly/fastly-server-sdk": "workspace:^", - "eventemitter3": "^5.0.1", - "events": "^3.3.0" + "@launchdarkly/fastly-server-sdk": "workspace:^" }, "scripts": { - "build": "webpack && js-compute-runtime dist/index.js bin/main.wasm", + "build": "tsc && js-compute-runtime build/index.js bin/main.wasm", "start": "fastly compute serve", "deploy": "fastly compute publish" } diff --git a/packages/sdk/fastly/example/src/cat.jpeg b/packages/sdk/fastly/example/src/cat.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..fa7ab2357d49476ed4ef6b24b6de2291e2aaa291 GIT binary patch literal 5629 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%0DcIQn!% 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�m9W{{UFR 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 // import { CacheOverride } from "fastly:cache-override"; import { env } from 'fastly:env'; -import { allowDynamicBackends, includeBytes } from 'fastly:experimental'; +import { includeBytes } from 'fastly:experimental'; import { KVStore } from 'fastly:kv-store'; import { Logger } from 'fastly:logger'; import { init } from '@launchdarkly/fastly-server-sdk'; -import { LDContext } from '@launchdarkly/js-sdk-common'; -import { LDClient } from '@launchdarkly/js-server-sdk-common-edge'; // Load a static file as a Uint8Array at compile time. // File path is relative to root of project, not to this file const welcomePage = includeBytes('./src/welcome-to-compute.html'); +const cat = includeBytes('./src/cat.jpeg'); +const dog = includeBytes('./src/dog.jpeg'); + // The entry point for your application. // // Use this fetch event listener to define your main request handling logic. It @@ -23,7 +24,7 @@ const welcomePage = includeBytes('./src/welcome-to-compute.html'); addEventListener('fetch', (event) => event.respondWith(handleRequest(event))); -async function flushEvents(ldClient: LDClient) { +async function flushEvents(ldClient: any) { console.log('Flushing events'); await ldClient.flush(); console.log('Events flushed'); @@ -36,7 +37,7 @@ async function handleRequest(event: FetchEvent) { console.log('FASTLY_SERVICE_VERSION:', env('FASTLY_SERVICE_VERSION') || 'local'); // Get the client request. - let req = event.request; + const req = event.request; // Filter requests that have unexpected methods. if (!['HEAD', 'GET', 'PURGE'].includes(req.method)) { @@ -45,10 +46,53 @@ async function handleRequest(event: FetchEvent) { }); } - let url = new URL(req.url); + const store = new KVStore('testkv'); + const ldClient = init(store, '675aea6b1b327709c85da941', { + sendEvents: true, + }); + await ldClient.waitForInitialization(); + + const flagContext = { + key: env('FASTLY_TRACE_ID'), + custom: { + fastly_service_version: env('FASTLY_SERVICE_VERSION'), + fastly_cache_generation: env('FASTLY_CACHE_GENERATION'), + fastly_hostname: env('FASTLY_HOSTNAME'), + fastly_pop: env('FASTLY_POP'), + fastly_region: env('FASTLY_REGION'), + fastly_service_id: env('FASTLY_SERVICE_ID'), + fastly_trace_id: env('FASTLY_TRACE_ID'), + henry: 'barrow', + }, + }; + + const url = new URL(req.url); + + if (url.pathname === '/cat') { + return new Response(cat, { + status: 200, + headers: new Headers({ 'Content-Type': 'image/jpeg' }), + }); + } + if (url.pathname === '/dog') { + return new Response(dog, { + status: 200, + headers: new Headers({ 'Content-Type': 'image/jpeg' }), + }); + } + if (url.pathname === '/animal') { + const animal = await ldClient.stringVariation('animal', flagContext, 'cat'); + const image = animal === 'cat' ? cat : dog; + + event.waitUntil(flushEvents(ldClient)); + return new Response(image, { + status: 200, + headers: new Headers({ 'Content-Type': 'image/jpeg' }), + }); + } // If request is to the `/` path... - if (url.pathname == '/') { + if (url.pathname === '/') { // Below are some common patterns for Fastly Compute services using JavaScript. // Head to https://developer.fastly.com/learning/compute/javascript/ to discover more. @@ -88,33 +132,15 @@ async function handleRequest(event: FetchEvent) { }); } - const store = new KVStore('testkv'); - const ldClient = init(store, '675aea6b1b327709c85da941', { - sendEvents: true, - }); - await ldClient.waitForInitialization(); const flagKey = 'enable-2025-brand-refresh'; - const flagContext: LDContext = { - key: 'test-user', - custom: { - fastly_service_version: env('FASTLY_SERVICE_VERSION'), - fastly_cache_generation: env('FASTLY_CACHE_GENERATION'), - fastly_hostname: env('FASTLY_HOSTNAME'), - fastly_pop: env('FASTLY_POP'), - fastly_region: env('FASTLY_REGION'), - fastly_service_id: env('FASTLY_SERVICE_ID'), - fastly_trace_id: env('FASTLY_TRACE_ID'), - }, - }; const variationDetail = await ldClient.boolVariationDetail(flagKey, flagContext, false); logger.log(`Flag value: ${variationDetail}`); const output = { flagContext, - variationDetail: variationDetail, + variationDetail, }; event.waitUntil(flushEvents(ldClient)); - await flushEvents(ldClient); // // Catch all other requests and return a 404. // const text = (await readme?.text()) || 'The page you requested could not be found'; diff --git a/packages/sdk/fastly/example/webpack.config.cjs b/packages/sdk/fastly/example/webpack.config.cjs deleted file mode 100644 index bf0dcfd56a..0000000000 --- a/packages/sdk/fastly/example/webpack.config.cjs +++ /dev/null @@ -1,51 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); - -module.exports = { - entry: './src/index.ts', - optimization: { - minimize: false, - }, - target: 'webworker', - module: { - rules: [ - { - test: /\.tsx?$/, - use: 'ts-loader', - exclude: /node_modules/, - }, - { - test: /\.js$/, - type: 'javascript/auto', - resolve: { - fullySpecified: false, - }, - }, - ], - }, - resolve: { - extensions: ['.tsx', '.ts', '.js'], - extensionAlias: { - '.js': ['.js', '.ts'], - }, - fullySpecified: false, - mainFields: ['module', 'main'], - fallback: { - events: require.resolve('events/'), - }, - }, - output: { - filename: 'index.js', - path: path.resolve(__dirname, 'dist'), - }, - externals: [ - ({ request }, callback) => { - if (/^fastly:.*$/.test(request)) { - return callback(null, 'commonjs ' + request); - } - callback(); - }, - ], - mode: 'production', - plugins: [new webpack.NormalModuleReplacementPlugin(/^node:events$/, require.resolve('events/'))], -}; diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json index 82643f83a3..3a3e773ec5 100644 --- a/packages/sdk/fastly/package.json +++ b/packages/sdk/fastly/package.json @@ -18,8 +18,16 @@ ], "type": "module", "exports": { - "require": "./dist/cjs/src/index.js", - "import": "./dist/esm/src/index.js" + ".": { + "import": { + "types": "./dist/esm/src/index.d.ts", + "default": "./dist/esm/bundle.es.js" + }, + "require": { + "types": "./dist/cjs/src/index.d.ts", + "default": "./dist/cjs/bundle.cjs.js" + } + } }, "main": "./dist/cjs/src/index.js", "types": "./dist/cjs/src/index.d.ts", @@ -27,7 +35,7 @@ "dist" ], "scripts": { - "build": "../../../scripts/build-package.sh && ../../../scripts/replace-version.sh .", + "build": "rollup -c rollup.config.js && ../../../scripts/replace-version.sh .", "clean": "rimraf dist", "tsw": "yarn tsc --watch", "start": "rimraf dist && yarn tsw", @@ -36,14 +44,20 @@ "check": "yarn prettier && yarn lint && yarn build && yarn test" }, "dependencies": { - "@fastly/js-compute": "^3.28.0" + "@fastly/js-compute": "^3.28.0", + "events": "^3.3.0", + "rollup-plugin-polyfill-node": "^0.13.0" }, "devDependencies": { "@launchdarkly/js-server-sdk-common-edge": "2.5.2", - "eslint": "^8.45.0", + "@rollup/plugin-commonjs": "^28.0.1", + "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-replace": "^6.0.2", + "@rollup/plugin-typescript": "^12.1.1", "prettier": "^3.4.2", "rimraf": "^6.0.1", "rollup": "^4.28.1", + "rollup-plugin-generate-package-json": "^3.2.0", "typedoc": "^0.27.4", "typescript": "^5.7.2" } diff --git a/packages/sdk/fastly/rollup.config.js b/packages/sdk/fastly/rollup.config.js new file mode 100644 index 0000000000..97231db404 --- /dev/null +++ b/packages/sdk/fastly/rollup.config.js @@ -0,0 +1,90 @@ +import common from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import replace from '@rollup/plugin-replace'; +import terser from '@rollup/plugin-terser'; +import typescript from '@rollup/plugin-typescript'; +import generatePackageJson from 'rollup-plugin-generate-package-json'; +import nodePolyfills from 'rollup-plugin-node-polyfills'; + +const getSharedConfig = (format, file) => ({ + input: 'src/index.ts', + output: [ + { + format: format, + sourcemap: true, + file: file, + preserveModules: false, + }, + ], + external: ['node:events'], + onwarn: (warning) => { + if (warning.code !== 'CIRCULAR_DEPENDENCY') { + console.error(`(!) ${warning.message}`); + } + }, +}); + +export default [ + { + ...getSharedConfig('es', 'dist/esm/bundle.es.js'), + plugins: [ + replace({ + preventAssignment: true, + values: { + 'node:events': 'events', + 'from "node:events"': 'from "events"', + "from 'node:events'": "from 'events'", + }, + }), + resolve({ + preferBuiltins: false, + browser: true, + mainFields: ['browser', 'module', 'main'], + }), + common({ + transformMixedEsModules: true, + esmExternals: true, + }), + nodePolyfills({ + include: ['events'], + }), + typescript({ + module: 'esnext', + outDir: './dist/esm', + declarationDir: './dist/esm', + }), + terser(), + ], + }, + { + ...getSharedConfig('cjs', 'dist/cjs/bundle.cjs.js'), + plugins: [ + { + name: 'replace-node-events', + resolveId(source) { + if (source === 'node:events') { + return 'events'; + } + return null; + }, + }, + nodePolyfills({ + include: ['events'], + }), + generatePackageJson({ + baseContents: (pkg) => ({ + name: pkg.name, + version: pkg.version, + type: 'commonjs', + }), + }), + typescript({ + outDir: './dist/cjs', + declarationDir: './dist/cjs', + }), + common(), + resolve(), + terser(), + ], + }, +]; diff --git a/packages/shared/sdk-server-edge/src/platform/index.ts b/packages/shared/sdk-server-edge/src/platform/index.ts index 35795031ce..3d77c45b49 100644 --- a/packages/shared/sdk-server-edge/src/platform/index.ts +++ b/packages/shared/sdk-server-edge/src/platform/index.ts @@ -1,7 +1,7 @@ import type { Crypto, Info, Platform, Requests } from '@launchdarkly/js-server-sdk-common'; import EdgeCrypto from './crypto'; -import EdgeRequests, { EdgeRequestsOptions } from './requests'; +import EdgeRequests from './requests'; export default class EdgePlatform implements Platform { info: Info; @@ -11,7 +11,6 @@ export default class EdgePlatform implements Platform { requests: Requests; constructor(info: Info, edgeRequestsOptions: Record = {}) { - console.log('edgeRequestsOptions', edgeRequestsOptions); this.info = info; this.requests = new EdgeRequests({ additionalFetchOptions: edgeRequestsOptions }); } diff --git a/packages/shared/sdk-server-edge/src/platform/requests.ts b/packages/shared/sdk-server-edge/src/platform/requests.ts index 32aba96c08..07972c7de0 100644 --- a/packages/shared/sdk-server-edge/src/platform/requests.ts +++ b/packages/shared/sdk-server-edge/src/platform/requests.ts @@ -13,16 +13,14 @@ export interface EdgeRequestsOptions { } export default class EdgeRequests implements Requests { - private options: EdgeRequestsOptions; + private _options: EdgeRequestsOptions; constructor(options: EdgeRequestsOptions = {}) { - this.options = options; + this._options = options; } fetch(url: string, options: Options = {}): Promise { - const finalOptions = { ...options, ...this.options.additionalFetchOptions }; - console.log(finalOptions); - console.log('Additional options', this.options.additionalFetchOptions); + const finalOptions = { ...options, ...this._options.additionalFetchOptions }; // @ts-ignore return fetch(url, finalOptions); } From 0914d822e529d00c2feff3df8e5f7aaafeb6102f Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 15:54:36 +0000 Subject: [PATCH 03/11] Add tests and cleanup --- packages/sdk/fastly/README.md | 63 ++++++- .../sdk/fastly/__mocks__/fastly:kv-store.ts | 8 + .../__tests__/api/EdgeFeatureStore.test.ts | 125 +++++++++++++ .../sdk/fastly/__tests__/api/LDClient.test.ts | 41 +++++ .../__tests__/api/createOptions.test.ts | 17 ++ .../sdk/fastly/__tests__/api/testData.json | 171 ++++++++++++++++++ .../fastly/__tests__/createBasicPlatform.ts | 59 ++++++ .../__tests__/createPlatformInfo.test.ts | 17 ++ packages/sdk/fastly/__tests__/index.test.ts | 110 +++++++++++ packages/sdk/fastly/__tests__/setupCrypto.ts | 20 ++ .../sdk/fastly/__tests__/utils/testData.json | 171 ++++++++++++++++++ .../__tests__/utils/validateOptions.test.ts | 46 +++++ packages/sdk/fastly/example/.gitignore | 1 + packages/sdk/fastly/example/README.md | 71 +++++++- packages/sdk/fastly/example/fastly.toml | 22 +-- packages/sdk/fastly/example/localData.json | 67 +++++++ packages/sdk/fastly/example/package.json | 8 +- packages/sdk/fastly/example/src/cat.jpeg | Bin 5629 -> 58484 bytes packages/sdk/fastly/example/src/index.ts | 117 +++++------- .../example/src/welcome-to-compute.html | 30 --- packages/sdk/fastly/example/tsconfig.json | 23 +-- packages/sdk/fastly/jest.config.json | 9 + packages/sdk/fastly/package.json | 34 ++-- packages/sdk/fastly/rollup.config.js | 90 --------- .../sdk/fastly/src/api/EdgeFeatureStore.ts | 116 ++++++++++++ packages/sdk/fastly/src/api/LDClient.ts | 24 +++ .../sdk/fastly/src/api/createCallbacks.ts | 9 + packages/sdk/fastly/src/api/createOptions.ts | 17 ++ packages/sdk/fastly/src/api/index.ts | 4 + packages/sdk/fastly/src/createPlatformInfo.ts | 2 +- packages/sdk/fastly/src/index.ts | 46 +++-- .../src/platform/crypto/cryptoJSHasher.ts | 49 +++++ .../src/platform/crypto/cryptoJSHmac.ts | 45 +++++ .../sdk/fastly/src/platform/crypto/index.ts | 24 +++ .../sdk/fastly/src/platform/crypto/types.ts | 2 + packages/sdk/fastly/src/platform/index.ts | 17 ++ packages/sdk/fastly/src/platform/requests.ts | 34 ++++ .../sdk/fastly/src/utils/mockEdgeProvider.ts | 7 + .../sdk/fastly/src/utils/mockFeatureStore.ts | 13 ++ .../sdk/fastly/src/utils/validateOptions.ts | 37 ++++ packages/sdk/fastly/tsconfig.eslint.json | 9 + packages/sdk/fastly/tsconfig.json | 19 +- packages/sdk/fastly/tsup.config.ts | 26 +++ .../sdk-server-edge/src/api/LDClient.ts | 9 +- packages/shared/sdk-server-edge/src/index.ts | 1 - .../sdk-server-edge/src/platform/index.ts | 5 +- .../sdk-server-edge/src/platform/requests.ts | 13 +- .../src/utils/validateOptions.ts | 10 +- 48 files changed, 1552 insertions(+), 306 deletions(-) create mode 100644 packages/sdk/fastly/__mocks__/fastly:kv-store.ts create mode 100644 packages/sdk/fastly/__tests__/api/EdgeFeatureStore.test.ts create mode 100644 packages/sdk/fastly/__tests__/api/LDClient.test.ts create mode 100644 packages/sdk/fastly/__tests__/api/createOptions.test.ts create mode 100644 packages/sdk/fastly/__tests__/api/testData.json create mode 100644 packages/sdk/fastly/__tests__/createBasicPlatform.ts create mode 100644 packages/sdk/fastly/__tests__/createPlatformInfo.test.ts create mode 100644 packages/sdk/fastly/__tests__/index.test.ts create mode 100644 packages/sdk/fastly/__tests__/setupCrypto.ts create mode 100644 packages/sdk/fastly/__tests__/utils/testData.json create mode 100644 packages/sdk/fastly/__tests__/utils/validateOptions.test.ts create mode 100644 packages/sdk/fastly/example/localData.json delete mode 100644 packages/sdk/fastly/example/src/welcome-to-compute.html create mode 100644 packages/sdk/fastly/jest.config.json delete mode 100644 packages/sdk/fastly/rollup.config.js create mode 100644 packages/sdk/fastly/src/api/EdgeFeatureStore.ts create mode 100644 packages/sdk/fastly/src/api/LDClient.ts create mode 100644 packages/sdk/fastly/src/api/createCallbacks.ts create mode 100644 packages/sdk/fastly/src/api/createOptions.ts create mode 100644 packages/sdk/fastly/src/api/index.ts create mode 100644 packages/sdk/fastly/src/platform/crypto/cryptoJSHasher.ts create mode 100644 packages/sdk/fastly/src/platform/crypto/cryptoJSHmac.ts create mode 100644 packages/sdk/fastly/src/platform/crypto/index.ts create mode 100644 packages/sdk/fastly/src/platform/crypto/types.ts create mode 100644 packages/sdk/fastly/src/platform/index.ts create mode 100644 packages/sdk/fastly/src/platform/requests.ts create mode 100644 packages/sdk/fastly/src/utils/mockEdgeProvider.ts create mode 100644 packages/sdk/fastly/src/utils/mockFeatureStore.ts create mode 100644 packages/sdk/fastly/src/utils/validateOptions.ts create mode 100644 packages/sdk/fastly/tsconfig.eslint.json create mode 100644 packages/sdk/fastly/tsup.config.ts diff --git a/packages/sdk/fastly/README.md b/packages/sdk/fastly/README.md index fe2288c1d4..0f14072ade 100644 --- a/packages/sdk/fastly/README.md +++ b/packages/sdk/fastly/README.md @@ -1 +1,62 @@ -# fastly +# LaunchDarkly SDK for Fastly + +The LaunchDarkly SDK for Fastly is designed primarily for use in [Fastly Compute Platform](https://www.fastly.com/documentation/guides/compute/). It follows the server-side LaunchDarkly model for multi-user contexts. It is not intended for use in desktop and embedded systems applications. + +# ⛔️⛔️⛔️⛔️ + +> [!CAUTION] +> This library is an alpha version and should not be considered ready for production use while this message is visible. + +# ☝️☝️☝️☝️☝️☝️ + +## Install + +```shell +# npm +npm i @launchdarkly/fastly-server-sdk + +# yarn +yarn add @launchdarkly/fastly-server-sdk +``` + +## Quickstart + +See the full [example app](https://github.com/launchdarkly/js-core/tree/main/packages/sdk/fastly/example). + +## Developing this SDK + +```shell +# at js-core repo root +yarn && yarn build && cd packages/sdk/fastly + +# run tests +yarn test +``` + +## Verifying SDK build provenance with the SLSA framework + +LaunchDarkly uses the [SLSA framework](https://slsa.dev/spec/v1.0/about) (Supply-chain Levels for Software Artifacts) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages. To learn more, see the [provenance guide](PROVENANCE.md). + +## About LaunchDarkly + +- LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can: + - Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases. + - Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?). + - Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file. + - Grant access to certain features based on user attributes, like payment plan (eg: users on the 'gold' plan get access to more features than users in the 'silver' plan). + - Disable parts of your application to facilitate maintenance, without taking everything offline. +- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Read [our documentation](https://docs.launchdarkly.com/sdk) for a complete list. +- Explore LaunchDarkly + - [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information + - [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK reference guides + - [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ 'LaunchDarkly API Documentation') for our API documentation + - [blog.launchdarkly.com](https://blog.launchdarkly.com/ 'LaunchDarkly Blog Documentation') for the latest product updates + +[sdk-fastly-ci-badge]: https://github.com/launchdarkly/js-core/actions/workflows/fastly.yml/badge.svg +[sdk-fastly-ci]: https://github.com/launchdarkly/js-core/actions/workflows/fastly.yml +[sdk-fastly-npm-badge]: https://img.shields.io/npm/v/@launchdarkly/fastly-server-sdk.svg?style=flat-square +[sdk-fastly-npm-link]: https://www.npmjs.com/package/@launchdarkly/fastly-server-sdk +[sdk-fastly-ghp-badge]: https://img.shields.io/static/v1?label=GitHub+Pages&message=API+reference&color=00add8 +[sdk-fastly-ghp-link]: https://launchdarkly.github.io/js-core/packages/sdk/fastly/docs/ +[sdk-fastly-dm-badge]: https://img.shields.io/npm/dm/@launchdarkly/fastly-server-sdk.svg?style=flat-square +[sdk-fastly-dt-badge]: https://img.shields.io/npm/dt/@launchdarkly/fastly-server-sdk.svg?style=flat-square diff --git a/packages/sdk/fastly/__mocks__/fastly:kv-store.ts b/packages/sdk/fastly/__mocks__/fastly:kv-store.ts new file mode 100644 index 0000000000..583bcc1d7e --- /dev/null +++ b/packages/sdk/fastly/__mocks__/fastly:kv-store.ts @@ -0,0 +1,8 @@ +export const KVStore = jest.fn().mockImplementation(() => ({ + get: jest.fn(), + put: jest.fn(), + delete: jest.fn(), + getMulti: jest.fn(), + putMulti: jest.fn(), + deleteMulti: jest.fn(), +})); diff --git a/packages/sdk/fastly/__tests__/api/EdgeFeatureStore.test.ts b/packages/sdk/fastly/__tests__/api/EdgeFeatureStore.test.ts new file mode 100644 index 0000000000..203d0bee06 --- /dev/null +++ b/packages/sdk/fastly/__tests__/api/EdgeFeatureStore.test.ts @@ -0,0 +1,125 @@ +import { AsyncStoreFacade, LDFeatureStore } from '@launchdarkly/js-server-sdk-common'; + +import { EdgeFeatureStore } from '../../src/api/EdgeFeatureStore'; +import mockEdgeProvider from '../../src/utils/mockEdgeProvider'; +import * as testData from './testData.json'; + +describe('EdgeFeatureStore', () => { + const sdkKey = 'sdkKey'; + const kvKey = `LD-Env-${sdkKey}`; + const mockLogger = { + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + debug: jest.fn(), + }; + const mockGet = mockEdgeProvider.get as jest.Mock; + let featureStore: LDFeatureStore; + let asyncFeatureStore: AsyncStoreFacade; + + beforeEach(() => { + mockGet.mockImplementation(() => Promise.resolve(JSON.stringify(testData))); + featureStore = new EdgeFeatureStore(mockEdgeProvider, sdkKey, 'MockEdgeProvider', mockLogger); + asyncFeatureStore = new AsyncStoreFacade(featureStore); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('get', () => { + test('get flag', async () => { + const flag = await asyncFeatureStore.get({ namespace: 'features' }, 'testFlag1'); + + expect(mockGet).toHaveBeenCalledWith(kvKey); + expect(flag).toMatchObject(testData.flags.testFlag1); + }); + + test('invalid flag key', async () => { + const flag = await asyncFeatureStore.get({ namespace: 'features' }, 'invalid'); + + expect(flag).toBeUndefined(); + }); + + test('get segment', async () => { + const segment = await asyncFeatureStore.get({ namespace: 'segments' }, 'testSegment1'); + + expect(mockGet).toHaveBeenCalledWith(kvKey); + expect(segment).toMatchObject(testData.segments.testSegment1); + }); + + test('invalid segment key', async () => { + const segment = await asyncFeatureStore.get({ namespace: 'segments' }, 'invalid'); + + expect(segment).toBeUndefined(); + }); + + test('invalid kv key', async () => { + mockGet.mockImplementation(() => Promise.resolve(null)); + const flag = await asyncFeatureStore.get({ namespace: 'features' }, 'testFlag1'); + + expect(flag).toBeNull(); + }); + }); + + describe('all', () => { + test('all flags', async () => { + const flags = await asyncFeatureStore.all({ namespace: 'features' }); + + expect(mockGet).toHaveBeenCalledWith(kvKey); + expect(flags).toMatchObject(testData.flags); + }); + + test('all segments', async () => { + const segment = await asyncFeatureStore.all({ namespace: 'segments' }); + + expect(mockGet).toHaveBeenCalledWith(kvKey); + expect(segment).toMatchObject(testData.segments); + }); + + test('invalid DataKind', async () => { + const flag = await asyncFeatureStore.all({ namespace: 'InvalidDataKind' }); + + expect(flag).toEqual({}); + }); + + test('invalid kv key', async () => { + mockGet.mockImplementation(() => Promise.resolve(null)); + const segment = await asyncFeatureStore.all({ namespace: 'segments' }); + + expect(segment).toEqual({}); + }); + }); + + describe('initialized', () => { + test('is initialized', async () => { + const isInitialized = await asyncFeatureStore.initialized(); + + expect(mockGet).toHaveBeenCalledWith(kvKey); + expect(isInitialized).toBeTruthy(); + }); + + test('not initialized', async () => { + mockGet.mockImplementation(() => Promise.resolve(null)); + const isInitialized = await asyncFeatureStore.initialized(); + + expect(mockGet).toHaveBeenCalledWith(kvKey); + expect(isInitialized).toBeFalsy(); + }); + }); + + describe('init & getDescription', () => { + test('init', (done) => { + const cb = jest.fn(() => { + done(); + }); + featureStore.init(testData, cb); + }); + + test('getDescription', async () => { + const description = featureStore.getDescription?.(); + + expect(description).toEqual('MockEdgeProvider'); + }); + }); +}); diff --git a/packages/sdk/fastly/__tests__/api/LDClient.test.ts b/packages/sdk/fastly/__tests__/api/LDClient.test.ts new file mode 100644 index 0000000000..26bad83fae --- /dev/null +++ b/packages/sdk/fastly/__tests__/api/LDClient.test.ts @@ -0,0 +1,41 @@ +import { internal } from '@launchdarkly/js-server-sdk-common'; + +import LDClient from '../../src/api/LDClient'; +import { createBasicPlatform } from '../createBasicPlatform'; + +jest.mock('@launchdarkly/js-sdk-common', () => { + const actual = jest.requireActual('@launchdarkly/js-sdk-common'); + return { + ...actual, + ...{ + internal: { + ...actual.internal, + DiagnosticsManager: jest.fn(), + EventProcessor: jest.fn(), + }, + }, + }; +}); + +const mockEventProcessor = internal.EventProcessor as jest.Mock; +describe('Edge LDClient', () => { + it('uses clientSideID endpoints', async () => { + const client = new LDClient('client-side-id', createBasicPlatform().info, { + sendEvents: true, + }); + await client.waitForInitialization({ timeout: 10 }); + const passedConfig = mockEventProcessor.mock.calls[0][0]; + + expect(passedConfig).toMatchObject({ + sendEvents: true, + serviceEndpoints: { + includeAuthorizationHeader: false, + analyticsEventPath: '/events/bulk/client-side-id', + diagnosticEventPath: '/events/diagnostic/client-side-id', + events: 'https://events.launchdarkly.com', + polling: 'https://sdk.launchdarkly.com', + streaming: 'https://stream.launchdarkly.com', + }, + }); + }); +}); diff --git a/packages/sdk/fastly/__tests__/api/createOptions.test.ts b/packages/sdk/fastly/__tests__/api/createOptions.test.ts new file mode 100644 index 0000000000..02fcc4b45d --- /dev/null +++ b/packages/sdk/fastly/__tests__/api/createOptions.test.ts @@ -0,0 +1,17 @@ +import { BasicLogger } from '@launchdarkly/js-server-sdk-common'; + +import createOptions, { defaultOptions } from '../../src/api/createOptions'; + +describe('createOptions', () => { + test('default options', () => { + expect(createOptions({})).toEqual(defaultOptions); + }); + + test('override logger', () => { + const logger = new BasicLogger({ name: 'test' }); + expect(createOptions({ logger })).toEqual({ + ...defaultOptions, + logger, + }); + }); +}); diff --git a/packages/sdk/fastly/__tests__/api/testData.json b/packages/sdk/fastly/__tests__/api/testData.json new file mode 100644 index 0000000000..b9e5296c03 --- /dev/null +++ b/packages/sdk/fastly/__tests__/api/testData.json @@ -0,0 +1,171 @@ +{ + "flags": { + "testFlag1": { + "key": "testFlag1", + "on": true, + "prerequisites": [], + "targets": [], + "rules": [ + { + "variation": 1, + "id": "rule1", + "clauses": [ + { + "contextKind": "user", + "attribute": "/email", + "op": "contains", + "values": ["gmail"], + "negate": false + } + ], + "trackEvents": false, + "rollout": { + "bucketBy": "bucket", + "variations": [{ "variation": 1, "weight": 100 }] + } + } + ], + "fallthrough": { + "variation": 0 + }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { + "usingMobileKey": true, + "usingEnvironmentId": true + }, + "clientSide": true, + "salt": "aef830243d6640d0a973be89988e008d", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": 2000, + "version": 2, + "deleted": false + }, + "testFlag2": { + "key": "testFlag2", + "on": true, + "prerequisites": [], + "targets": [], + "rules": [], + "fallthrough": { + "variation": 0, + "rollout": { + "bucketBy": "bucket", + "variations": [{ "variation": 1, "weight": 100 }], + "contextKind:": "user", + "attribute": "/email" + } + }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { + "usingMobileKey": true, + "usingEnvironmentId": true + }, + "clientSide": true, + "salt": "aef830243d6640d0a973be89988e008d", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": 2000, + "version": 2, + "deleted": false + }, + "testFlag3": { + "key": "testFlag3", + "on": true, + "prerequisites": [], + "targets": [], + "rules": [ + { + "variation": 1, + "id": "rule1", + "clauses": [ + { + "op": "segmentMatch", + "values": ["testSegment1"], + "negate": false + } + ], + "trackEvents": false + } + ], + "fallthrough": { + "variation": 0 + }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { + "usingMobileKey": true, + "usingEnvironmentId": true + }, + "clientSide": true, + "salt": "aef830243d6640d0a973be89988e008d", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": 2000, + "version": 2, + "deleted": false + } + }, + "segments": { + "testSegment1": { + "name": "testSegment1", + "tags": [], + "creationDate": 1676063792158, + "key": "testSegment1", + "included": [], + "excluded": [], + "includedContexts": [], + "excludedContexts": [], + "_links": { + "parent": { "href": "/api/v2/segments/default/test", "type": "application/json" }, + "self": { + "href": "/api/v2/segments/default/test/beta-users-1", + "type": "application/json" + }, + "site": { "href": "/default/test/segments/beta-users-1", "type": "text/html" } + }, + "rules": [ + { + "id": "rule-country", + "clauses": [ + { + "attribute": "country", + "op": "in", + "values": ["australia"], + "negate": false + } + ] + } + ], + "version": 1, + "deleted": false, + "_access": { "denied": [], "allowed": [] }, + "generation": 1 + }, + "testSegment2": { + "name": "testSegment2", + "tags": [], + "creationDate": 1676063792158, + "key": "testSegment2", + "included": [], + "excluded": [], + "includedContexts": [], + "excludedContexts": [], + "_links": { + "parent": { "href": "/api/v2/segments/default/test", "type": "application/json" }, + "self": { + "href": "/api/v2/segments/default/test/beta-users-1", + "type": "application/json" + }, + "site": { "href": "/default/test/segments/beta-users-1", "type": "text/html" } + }, + "rules": [], + "version": 1, + "deleted": false, + "_access": { "denied": [], "allowed": [] }, + "generation": 1 + } + } +} diff --git a/packages/sdk/fastly/__tests__/createBasicPlatform.ts b/packages/sdk/fastly/__tests__/createBasicPlatform.ts new file mode 100644 index 0000000000..e5139ccec6 --- /dev/null +++ b/packages/sdk/fastly/__tests__/createBasicPlatform.ts @@ -0,0 +1,59 @@ +import { PlatformData, SdkData } from '@launchdarkly/js-server-sdk-common'; + +import { setupCrypto } from './setupCrypto'; + +const setupInfo = () => ({ + platformData: jest.fn( + (): PlatformData => ({ + os: { + name: 'An OS', + version: '1.0.1', + arch: 'An Arch', + }, + name: 'The SDK Name', + additional: { + nodeVersion: '42', + }, + ld_application: { + key: '', + envAttributesVersion: '1.0', + id: 'com.testapp.ld', + name: 'LDApplication.TestApp', + version: '1.1.1', + }, + ld_device: { + key: '', + envAttributesVersion: '1.0', + os: { name: 'Another OS', version: '99', family: 'orange' }, + manufacturer: 'coconut', + }, + }), + ), + sdkData: jest.fn( + (): SdkData => ({ + name: 'An SDK', + version: '2.0.2', + userAgentBase: 'TestUserAgent', + wrapperName: 'Rapper', + wrapperVersion: '1.2.3', + }), + ), +}); + +export const createBasicPlatform = () => ({ + encoding: { + btoa: (s: string) => Buffer.from(s).toString('base64'), + }, + info: setupInfo(), + crypto: setupCrypto(), + requests: { + fetch: jest.fn(), + createEventSource: jest.fn(), + getEventSourceCapabilities: jest.fn(), + }, + storage: { + get: jest.fn(), + set: jest.fn(), + clear: jest.fn(), + }, +}); diff --git a/packages/sdk/fastly/__tests__/createPlatformInfo.test.ts b/packages/sdk/fastly/__tests__/createPlatformInfo.test.ts new file mode 100644 index 0000000000..8698a53ac3 --- /dev/null +++ b/packages/sdk/fastly/__tests__/createPlatformInfo.test.ts @@ -0,0 +1,17 @@ +import createPlatformInfo from '../src/createPlatformInfo'; + +describe('Fastly Platform Info', () => { + it('platformData shows correct information', () => { + const platformData = createPlatformInfo(); + + expect(platformData.platformData()).toEqual({ + name: 'Fastly Edge', + }); + + expect(platformData.sdkData()).toEqual({ + name: '@launchdarkly/fastly-server-sdk', + version: '__LD_VERSION__', + userAgentBase: 'FastlyEdgeSDK', + }); + }); +}); diff --git a/packages/sdk/fastly/__tests__/index.test.ts b/packages/sdk/fastly/__tests__/index.test.ts new file mode 100644 index 0000000000..bd3debb37d --- /dev/null +++ b/packages/sdk/fastly/__tests__/index.test.ts @@ -0,0 +1,110 @@ +/// +import { KVStore } from 'fastly:kv-store'; + +import { LDClient } from '../src/api'; +import { init } from '../src/index'; +import * as testData from './utils/testData.json'; + +// Tell Jest to use the manual mock +jest.mock('fastly:kv-store'); + +const sdkKey = 'test-sdk-key'; +const flagKey1 = 'testFlag1'; +const flagKey2 = 'testFlag2'; +const flagKey3 = 'testFlag3'; +const context = { kind: 'user', key: 'test-user-key-1' }; + +describe('init', () => { + let ldClient: LDClient; + let mockKVStore: jest.Mocked; + + beforeAll(async () => { + mockKVStore = new KVStore('test-kv-store') as jest.Mocked; + const testDataString = JSON.stringify(testData); + mockKVStore.get.mockResolvedValue({ + text: jest.fn().mockResolvedValue(testDataString), + json: jest.fn().mockResolvedValue(testData), + arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(0)), + body: new ReadableStream(), + bodyUsed: false, + metadata: () => null, + metadataText: () => null, + }); + ldClient = init(sdkKey, mockKVStore); + await ldClient.waitForInitialization(); + }); + + afterAll(() => { + ldClient.close(); + }); + + describe('flags', () => { + test('variation default', async () => { + const value = await ldClient.variation(flagKey1, context, false); + expect(value).toBeTruthy(); + }); + + test('variation default rollout', async () => { + const contextWithEmail = { ...context, email: 'test@yahoo.com' }; + const value = await ldClient.variation(flagKey2, contextWithEmail, false); + const detail = await ldClient.variationDetail(flagKey2, contextWithEmail, false); + + expect(detail).toEqual({ reason: { kind: 'FALLTHROUGH' }, value: true, variationIndex: 0 }); + expect(value).toBeTruthy(); + }); + + test('rule match', async () => { + const contextWithEmail = { ...context, email: 'test@gmail.com' }; + const value = await ldClient.variation(flagKey1, contextWithEmail, false); + const detail = await ldClient.variationDetail(flagKey1, contextWithEmail, false); + + expect(detail).toEqual({ + reason: { kind: 'RULE_MATCH', ruleId: 'rule1', ruleIndex: 0 }, + value: false, + variationIndex: 1, + }); + expect(value).toBeFalsy(); + }); + + test('fallthrough', async () => { + const contextWithEmail = { ...context, email: 'test@yahoo.com' }; + const value = await ldClient.variation(flagKey1, contextWithEmail, false); + const detail = await ldClient.variationDetail(flagKey1, contextWithEmail, false); + + expect(detail).toEqual({ reason: { kind: 'FALLTHROUGH' }, value: true, variationIndex: 0 }); + expect(value).toBeTruthy(); + }); + + test('allFlags fallthrough', async () => { + const allFlags = await ldClient.allFlagsState(context); + + expect(allFlags).toBeDefined(); + expect(allFlags.toJSON()).toEqual({ + $flagsState: { + testFlag1: { debugEventsUntilDate: 2000, variation: 0, version: 2 }, + testFlag2: { debugEventsUntilDate: 2000, variation: 0, version: 2 }, + testFlag3: { debugEventsUntilDate: 2000, variation: 0, version: 2 }, + }, + $valid: true, + testFlag1: true, + testFlag2: true, + testFlag3: true, + }); + }); + }); + + describe('segments', () => { + test('segment by country', async () => { + const contextWithCountry = { ...context, country: 'australia' }; + const value = await ldClient.variation(flagKey3, contextWithCountry, false); + const detail = await ldClient.variationDetail(flagKey3, contextWithCountry, false); + + expect(detail).toEqual({ + reason: { kind: 'RULE_MATCH', ruleId: 'rule1', ruleIndex: 0 }, + value: false, + variationIndex: 1, + }); + expect(value).toBeFalsy(); + }); + }); +}); diff --git a/packages/sdk/fastly/__tests__/setupCrypto.ts b/packages/sdk/fastly/__tests__/setupCrypto.ts new file mode 100644 index 0000000000..bdf62024fc --- /dev/null +++ b/packages/sdk/fastly/__tests__/setupCrypto.ts @@ -0,0 +1,20 @@ +import { Hasher } from '@launchdarkly/js-server-sdk-common'; + +export const setupCrypto = () => { + let counter = 0; + const hasher = { + update: jest.fn((): Hasher => hasher), + digest: jest.fn(() => '1234567890123456'), + }; + + return { + createHash: jest.fn(() => hasher), + createHmac: jest.fn(), + randomUUID: jest.fn(() => { + counter += 1; + // Will provide a unique value for tests. + // Very much not a UUID of course. + return `${counter}`; + }), + }; +}; diff --git a/packages/sdk/fastly/__tests__/utils/testData.json b/packages/sdk/fastly/__tests__/utils/testData.json new file mode 100644 index 0000000000..b9e5296c03 --- /dev/null +++ b/packages/sdk/fastly/__tests__/utils/testData.json @@ -0,0 +1,171 @@ +{ + "flags": { + "testFlag1": { + "key": "testFlag1", + "on": true, + "prerequisites": [], + "targets": [], + "rules": [ + { + "variation": 1, + "id": "rule1", + "clauses": [ + { + "contextKind": "user", + "attribute": "/email", + "op": "contains", + "values": ["gmail"], + "negate": false + } + ], + "trackEvents": false, + "rollout": { + "bucketBy": "bucket", + "variations": [{ "variation": 1, "weight": 100 }] + } + } + ], + "fallthrough": { + "variation": 0 + }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { + "usingMobileKey": true, + "usingEnvironmentId": true + }, + "clientSide": true, + "salt": "aef830243d6640d0a973be89988e008d", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": 2000, + "version": 2, + "deleted": false + }, + "testFlag2": { + "key": "testFlag2", + "on": true, + "prerequisites": [], + "targets": [], + "rules": [], + "fallthrough": { + "variation": 0, + "rollout": { + "bucketBy": "bucket", + "variations": [{ "variation": 1, "weight": 100 }], + "contextKind:": "user", + "attribute": "/email" + } + }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { + "usingMobileKey": true, + "usingEnvironmentId": true + }, + "clientSide": true, + "salt": "aef830243d6640d0a973be89988e008d", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": 2000, + "version": 2, + "deleted": false + }, + "testFlag3": { + "key": "testFlag3", + "on": true, + "prerequisites": [], + "targets": [], + "rules": [ + { + "variation": 1, + "id": "rule1", + "clauses": [ + { + "op": "segmentMatch", + "values": ["testSegment1"], + "negate": false + } + ], + "trackEvents": false + } + ], + "fallthrough": { + "variation": 0 + }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { + "usingMobileKey": true, + "usingEnvironmentId": true + }, + "clientSide": true, + "salt": "aef830243d6640d0a973be89988e008d", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": 2000, + "version": 2, + "deleted": false + } + }, + "segments": { + "testSegment1": { + "name": "testSegment1", + "tags": [], + "creationDate": 1676063792158, + "key": "testSegment1", + "included": [], + "excluded": [], + "includedContexts": [], + "excludedContexts": [], + "_links": { + "parent": { "href": "/api/v2/segments/default/test", "type": "application/json" }, + "self": { + "href": "/api/v2/segments/default/test/beta-users-1", + "type": "application/json" + }, + "site": { "href": "/default/test/segments/beta-users-1", "type": "text/html" } + }, + "rules": [ + { + "id": "rule-country", + "clauses": [ + { + "attribute": "country", + "op": "in", + "values": ["australia"], + "negate": false + } + ] + } + ], + "version": 1, + "deleted": false, + "_access": { "denied": [], "allowed": [] }, + "generation": 1 + }, + "testSegment2": { + "name": "testSegment2", + "tags": [], + "creationDate": 1676063792158, + "key": "testSegment2", + "included": [], + "excluded": [], + "includedContexts": [], + "excludedContexts": [], + "_links": { + "parent": { "href": "/api/v2/segments/default/test", "type": "application/json" }, + "self": { + "href": "/api/v2/segments/default/test/beta-users-1", + "type": "application/json" + }, + "site": { "href": "/default/test/segments/beta-users-1", "type": "text/html" } + }, + "rules": [], + "version": 1, + "deleted": false, + "_access": { "denied": [], "allowed": [] }, + "generation": 1 + } + } +} diff --git a/packages/sdk/fastly/__tests__/utils/validateOptions.test.ts b/packages/sdk/fastly/__tests__/utils/validateOptions.test.ts new file mode 100644 index 0000000000..3b5826352e --- /dev/null +++ b/packages/sdk/fastly/__tests__/utils/validateOptions.test.ts @@ -0,0 +1,46 @@ +import { BasicLogger } from '@launchdarkly/js-server-sdk-common'; + +import mockFeatureStore from '../../src/utils/mockFeatureStore'; +import validateOptions from '../../src/utils/validateOptions'; + +describe('validateOptions', () => { + test('throws without SDK key', () => { + expect(() => { + validateOptions('', {}); + }).toThrowError(/You must configure the client with a client key/); + }); + + test('throws without featureStore', () => { + expect(() => { + validateOptions('test-sdk-key', {}); + }).toThrowError(/You must configure the client with a feature store/); + }); + + test('throws without logger', () => { + expect(() => { + validateOptions('test-sdk-key', { featureStore: mockFeatureStore }); + }).toThrowError(/You must configure the client with a logger/); + }); + + test('success valid options', () => { + expect( + validateOptions('test-sdk-key', { + featureStore: mockFeatureStore, + logger: BasicLogger.get(), + sendEvents: false, + }), + ).toBeTruthy(); + }); + + test('throws with invalid options', () => { + expect(() => { + validateOptions('test-sdk-key', { + featureStore: mockFeatureStore, + logger: BasicLogger.get(), + // @ts-ignore + streamUri: 'invalid-option', + proxyOptions: 'another-invalid-option', + }); + }).toThrow(/Invalid configuration: streamUri,proxyOptions not supported/); + }); +}); diff --git a/packages/sdk/fastly/example/.gitignore b/packages/sdk/fastly/example/.gitignore index e409a41625..ab78770b99 100644 --- a/packages/sdk/fastly/example/.gitignore +++ b/packages/sdk/fastly/example/.gitignore @@ -2,3 +2,4 @@ /bin /build /pkg +.env diff --git a/packages/sdk/fastly/example/README.md b/packages/sdk/fastly/example/README.md index 02dc8ac17f..5b26a65699 100644 --- a/packages/sdk/fastly/example/README.md +++ b/packages/sdk/fastly/example/README.md @@ -1 +1,70 @@ -# example +# Example test app for Fastly LaunchDarkly SDK + +This is an example test app to showcase the usage of the Fastly LaunchDarkly SDK in a [Fastly Compute@Edge](https://docs.fastly.com/products/compute-at-edge) application. The example demonstrates: + +1. Initializing the LaunchDarkly SDK with a Fastly KV Store +2. Evaluating boolean and string feature flags +3. Using multi-kind contexts to include Fastly-specific data +4. Serving different images based on feature flag variations + +Most of the LaunchDarkly-related code can be found in [src/index.ts](src/index.ts). + +## Prerequisites + +A node environment of version 16 and yarn are required to develop in this repository. +You will also need the [Fastly CLI](https://developer.fastly.com/learning/tools/cli) installed and a Fastly account to setup +the test data required by this example. + +## Setting up your LaunchDarkly environment + +For simplicity, we recommend [creating a new LaunchDarkly project](https://docs.launchdarkly.com/home/organize/projects/?q=create+proj) for this example app. After creating a new project, create the following feature flags: + +- `example-flag` - (Boolean) - This flag is evaluated in the root endpoint +- `animal` - (String) - This flag determines which animal image to show (values: "cat" or "dog") + +## Setting up your development environment + +1. At the root of the js-core repo: + +```shell +yarn && yarn build +``` + +2. Replace `LAUNCHDARKLY_CLIENT_ID` in [src/index.ts](src/index.ts) with your LaunchDarkly SDK key. + +3. Create a new Fastly Compute service and KV Store: + +```shell +# Login to Fastly CLI +fastly login + +# Create a new Compute@Edge service +fastly compute init + +# Create a new KV Store +fastly kv-store create --name launchdarkly +``` + +4. Run the following command to install dependencies: + +```shell +yarn +``` + +5. Start the local development server: + +```shell +yarn start +``` + +6. Test the endpoints: + +- Visit `http://127.0.0.1:7676/` for the boolean flag evaluation +- Visit `http://127.0.0.1:7676/animal` to see an image controlled by the string flag +- Visit `http://127.0.0.1:7676/cat` or `http://127.0.0.1:7676/dog` for direct image access + +7. Deploy to Fastly: + +```shell +yarn deploy +``` diff --git a/packages/sdk/fastly/example/fastly.toml b/packages/sdk/fastly/example/fastly.toml index 4541de83d5..21b8c30665 100644 --- a/packages/sdk/fastly/example/fastly.toml +++ b/packages/sdk/fastly/example/fastly.toml @@ -2,12 +2,11 @@ # https://www.fastly.com/documentation/reference/compute/fastly-toml authors = [] -cloned_from = "J4RQReO3g9zZdp3eDM8Sr5" -description = "A basic starter kit that demonstrates routing, simple synthetic responses and overriding caching rules." +description = "A basic example of using the LaunchDarkly SDK for Fastly" language = "javascript" manifest_version = 3 -name = "Default starter for TypeScript" -service_id = "J4RQReO3g9zZdp3eDM8Sr5" +name = "LaunchDarkly SDK for Fastly Example" +service_id = "" [scripts] build = "yarn build" @@ -15,14 +14,13 @@ post_init = "yarn install" [local_server] - [local_server.backends] +[local_server.backends] - [local_server.kv_stores] +[local_server.backends.launchdarkly] +url = "https://events.launchdarkly.com" - [[local_server.kv_stores.testkv]] - data = "placeholder" - key = "placeholder" +[local_server.kv_stores] - [[local_server.kv_stores.testkv]] - key = "readme" - path = "./README.md" \ No newline at end of file +[[local_server.kv_stores.launchdarkly_local]] +key = "LD-Env-local" +path = "./localData.json" diff --git a/packages/sdk/fastly/example/localData.json b/packages/sdk/fastly/example/localData.json new file mode 100644 index 0000000000..572030202b --- /dev/null +++ b/packages/sdk/fastly/example/localData.json @@ -0,0 +1,67 @@ +{ + "flags": { + "animal": { + "key": "animal", + "on": true, + "prerequisites": [], + "targets": [], + "contextTargets": [], + "rules": [], + "fallthrough": { + "rollout": { + "contextKind": "fastly-request", + "variations": [ + { "variation": 0, "weight": 50000 }, + { "variation": 1, "weight": 50000 } + ], + "bucketBy": "key" + } + }, + "offVariation": 1, + "variations": ["cat", "dog"], + "clientSideAvailability": { "usingMobileKey": false, "usingEnvironmentId": false }, + "clientSide": false, + "salt": "0ab7b96471ff4edb98113157355cbb9f", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": null, + "version": 5, + "deleted": false + }, + "example-flag": { + "key": "example-flag", + "on": true, + "prerequisites": [], + "targets": [], + "contextTargets": [], + "rules": [ + { + "variation": 1, + "id": "8b96123e-759f-4f73-b91e-884ac56d0a06", + "clauses": [ + { + "contextKind": "fastly-request", + "attribute": "fastly_region", + "op": "in", + "values": ["US-West"], + "negate": false + } + ], + "trackEvents": false + } + ], + "fallthrough": { "variation": 0 }, + "offVariation": 1, + "variations": [true, false], + "clientSideAvailability": { "usingMobileKey": false, "usingEnvironmentId": false }, + "clientSide": false, + "salt": "ca17f93252064631bacb2cffea217f20", + "trackEvents": false, + "trackEventsFallthrough": false, + "debugEventsUntilDate": null, + "version": 8, + "deleted": false + } + }, + "segments": {} +} diff --git a/packages/sdk/fastly/example/package.json b/packages/sdk/fastly/example/package.json index 85920a549d..e7961c1d30 100644 --- a/packages/sdk/fastly/example/package.json +++ b/packages/sdk/fastly/example/package.json @@ -6,14 +6,16 @@ "node": "^16 || >=18" }, "devDependencies": { - "@fastly/cli": "^10.14.0", - "typescript": "^5.2.2" + "@fastly/cli": "^10.17.1", + "rimraf": "^6.0.1", + "typescript": "^5.7.2" }, "dependencies": { - "@fastly/js-compute": "^3.7.0", + "@fastly/js-compute": "^3.28.0", "@launchdarkly/fastly-server-sdk": "workspace:^" }, "scripts": { + "clean": "rimraf build && rimraf bin", "build": "tsc && js-compute-runtime build/index.js bin/main.wasm", "start": "fastly compute serve", "deploy": "fastly compute publish" diff --git a/packages/sdk/fastly/example/src/cat.jpeg b/packages/sdk/fastly/example/src/cat.jpeg index fa7ab2357d49476ed4ef6b24b6de2291e2aaa291..eaedfdb979009f71e6b8ee74427962689d278853 100644 GIT binary patch literal 58484 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 GbN>%Bp1~FX literal 5629 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 -// import { CacheOverride } from "fastly:cache-override"; import { env } from 'fastly:env'; import { includeBytes } from 'fastly:experimental'; import { KVStore } from 'fastly:kv-store'; -import { Logger } from 'fastly:logger'; import { init } from '@launchdarkly/fastly-server-sdk'; +import type { LDMultiKindContext } from '@launchdarkly/js-server-sdk-common'; -// Load a static file as a Uint8Array at compile time. -// File path is relative to root of project, not to this file -const welcomePage = includeBytes('./src/welcome-to-compute.html'); +// Set your LaunchDarkly client ID here +const LAUNCHDARKLY_CLIENT_ID = ''; +// Set the KV store name used to store the LaunchDarkly data here +const KV_STORE_NAME = 'launchdarkly'; +// Set the Fastly Backend name used to send LaunchDarkly events here +const EVENTS_BACKEND_NAME = 'launchdarkly'; const cat = includeBytes('./src/cat.jpeg'); const dog = includeBytes('./src/dog.jpeg'); @@ -24,15 +26,7 @@ const dog = includeBytes('./src/dog.jpeg'); addEventListener('fetch', (event) => event.respondWith(handleRequest(event))); -async function flushEvents(ldClient: any) { - console.log('Flushing events'); - await ldClient.flush(); - console.log('Events flushed'); -} - async function handleRequest(event: FetchEvent) { - const logger = new Logger('handleRequest'); - // Log service version console.log('FASTLY_SERVICE_VERSION:', env('FASTLY_SERVICE_VERSION') || 'local'); @@ -46,15 +40,25 @@ async function handleRequest(event: FetchEvent) { }); } - const store = new KVStore('testkv'); - const ldClient = init(store, '675aea6b1b327709c85da941', { + const isLocal = env('FASTLY_HOSTNAME') === 'localhost'; + const kvStoreName = isLocal ? 'launchdarkly_local' : KV_STORE_NAME; + const ldClientId = isLocal ? 'local' : LAUNCHDARKLY_CLIENT_ID; + + const store = new KVStore(kvStoreName); + const ldClient = init(ldClientId, store, { sendEvents: true, + eventsBackendName: EVENTS_BACKEND_NAME, }); await ldClient.waitForInitialization(); - const flagContext = { - key: env('FASTLY_TRACE_ID'), - custom: { + const flagContext: LDMultiKindContext = { + kind: 'multi', + user: { + // In a real-world scenario, you would use get the user key from a cookie, header, or other source + key: 'test-user', + }, + 'fastly-request': { + key: env('FASTLY_TRACE_ID'), fastly_service_version: env('FASTLY_SERVICE_VERSION'), fastly_cache_generation: env('FASTLY_CACHE_GENERATION'), fastly_hostname: env('FASTLY_HOSTNAME'), @@ -62,12 +66,28 @@ async function handleRequest(event: FetchEvent) { fastly_region: env('FASTLY_REGION'), fastly_service_id: env('FASTLY_SERVICE_ID'), fastly_trace_id: env('FASTLY_TRACE_ID'), - henry: 'barrow', }, }; const url = new URL(req.url); + if (url.pathname === '/') { + const flagKey = 'example-flag'; + const variationDetail = await ldClient.boolVariationDetail(flagKey, flagContext, false); + + const output = { + flagContext, + flagKey, + variationDetail, + }; + event.waitUntil(ldClient.flush()); + + return new Response(JSON.stringify(output, undefined, 2), { + status: 200, + headers: new Headers({ 'Content-Type': 'application/json' }), + }); + } + if (url.pathname === '/cat') { return new Response(cat, { status: 200, @@ -84,68 +104,15 @@ async function handleRequest(event: FetchEvent) { const animal = await ldClient.stringVariation('animal', flagContext, 'cat'); const image = animal === 'cat' ? cat : dog; - event.waitUntil(flushEvents(ldClient)); + event.waitUntil(ldClient.flush()); return new Response(image, { status: 200, headers: new Headers({ 'Content-Type': 'image/jpeg' }), }); } - // If request is to the `/` path... - if (url.pathname === '/') { - // Below are some common patterns for Fastly Compute services using JavaScript. - // Head to https://developer.fastly.com/learning/compute/javascript/ to discover more. - - // Create a new request. - // let bereq = new Request("http://example.com"); - - // Add request headers. - // req.headers.set("X-Custom-Header", "Welcome to Fastly Compute!"); - // req.headers.set( - // "X-Another-Custom-Header", - // "Recommended reading: https://developer.fastly.com/learning/compute" - // ); - - // Create a cache override. - // To use this, uncomment the import statement at the top of this file for CacheOverride. - // let cacheOverride = new CacheOverride("override", { ttl: 60 }); - - // Forward the request to a backend. - // let beresp = await fetch(req, { - // backend: "backend_name", - // cacheOverride, - // }); - - // Remove response headers. - // beresp.headers.delete("X-Another-Custom-Header"); - - // Log to a Fastly endpoint. - // To use this, uncomment the import statement at the top of this file for Logger. - // const logger = new Logger("my_endpoint"); - // logger.log("Hello from the edge!"); - - // Send a default synthetic response. - - return new Response(welcomePage, { - status: 200, - headers: new Headers({ 'Content-Type': 'text/html; charset=utf-8' }), - }); - } - - const flagKey = 'enable-2025-brand-refresh'; - const variationDetail = await ldClient.boolVariationDetail(flagKey, flagContext, false); - logger.log(`Flag value: ${variationDetail}`); - - const output = { - flagContext, - variationDetail, - }; - event.waitUntil(flushEvents(ldClient)); - // // Catch all other requests and return a 404. - // const text = (await readme?.text()) || 'The page you requested could not be found'; - return new Response(JSON.stringify(output, undefined, 2), { + return new Response('not found', { status: 404, - headers: new Headers({ 'Content-Type': 'application/json' }), }); } diff --git a/packages/sdk/fastly/example/src/welcome-to-compute.html b/packages/sdk/fastly/example/src/welcome-to-compute.html deleted file mode 100644 index cc18336ddb..0000000000 --- a/packages/sdk/fastly/example/src/welcome-to-compute.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - Welcome to Fastly Compute - - - - - - diff --git a/packages/sdk/fastly/example/tsconfig.json b/packages/sdk/fastly/example/tsconfig.json index c58b2cb87f..9f2c981cc9 100644 --- a/packages/sdk/fastly/example/tsconfig.json +++ b/packages/sdk/fastly/example/tsconfig.json @@ -4,25 +4,14 @@ "module": "ES2022", "target": "ES2022", "moduleResolution": "bundler", - "customConditions": [ - "fastly" - ], + "customConditions": ["fastly"], "esModuleInterop": true, - "lib": [ - "ES2022" - ], + "lib": ["ES2022"], "rootDir": "src", "outDir": "build", - "types": [ - "@fastly/js-compute" - ], + "types": ["@fastly/js-compute"], "skipLibCheck": true }, - "include": [ - "./src/**/*.js", - "./src/**/*.ts", - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["./src/**/*.js", "./src/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/sdk/fastly/jest.config.json b/packages/sdk/fastly/jest.config.json new file mode 100644 index 0000000000..6174807746 --- /dev/null +++ b/packages/sdk/fastly/jest.config.json @@ -0,0 +1,9 @@ +{ + "transform": { "^.+\\.ts?$": "ts-jest" }, + "testMatch": ["**/*.test.ts?(x)"], + "testPathIgnorePatterns": ["node_modules", "example", "dist"], + "modulePathIgnorePatterns": ["dist"], + "testEnvironment": "node", + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], + "collectCoverageFrom": ["src/**/*.ts"] +} diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json index 3a3e773ec5..6a3f1f60e7 100644 --- a/packages/sdk/fastly/package.json +++ b/packages/sdk/fastly/package.json @@ -19,45 +19,43 @@ "type": "module", "exports": { ".": { - "import": { - "types": "./dist/esm/src/index.d.ts", - "default": "./dist/esm/bundle.es.js" - }, "require": { - "types": "./dist/cjs/src/index.d.ts", - "default": "./dist/cjs/bundle.cjs.js" + "types": "./dist/index.d.cts", + "require": "./dist/index.cjs" + }, + "import": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" } } }, - "main": "./dist/cjs/src/index.js", - "types": "./dist/cjs/src/index.d.ts", + "main": "../dist/index.cjs", + "types": "./dist/index.d.cts", "files": [ "dist" ], "scripts": { - "build": "rollup -c rollup.config.js && ../../../scripts/replace-version.sh .", + "build": "tsup", "clean": "rimraf dist", "tsw": "yarn tsc --watch", "start": "rimraf dist && yarn tsw", "lint": "eslint . --ext .ts", + "test": "npx jest --runInBand", + "coverage": "yarn test --coverage", "prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore", "check": "yarn prettier && yarn lint && yarn build && yarn test" }, "dependencies": { "@fastly/js-compute": "^3.28.0", - "events": "^3.3.0", - "rollup-plugin-polyfill-node": "^0.13.0" + "@launchdarkly/js-server-sdk-common": "2.10.0", + "crypto-js": "^4.2.0" }, "devDependencies": { - "@launchdarkly/js-server-sdk-common-edge": "2.5.2", - "@rollup/plugin-commonjs": "^28.0.1", - "@rollup/plugin-node-resolve": "^15.3.0", - "@rollup/plugin-replace": "^6.0.2", - "@rollup/plugin-typescript": "^12.1.1", + "eslint": "^8.45.0", + "jest": "^29.7.0", "prettier": "^3.4.2", "rimraf": "^6.0.1", - "rollup": "^4.28.1", - "rollup-plugin-generate-package-json": "^3.2.0", + "tsup": "^8.3.5", "typedoc": "^0.27.4", "typescript": "^5.7.2" } diff --git a/packages/sdk/fastly/rollup.config.js b/packages/sdk/fastly/rollup.config.js deleted file mode 100644 index 97231db404..0000000000 --- a/packages/sdk/fastly/rollup.config.js +++ /dev/null @@ -1,90 +0,0 @@ -import common from '@rollup/plugin-commonjs'; -import resolve from '@rollup/plugin-node-resolve'; -import replace from '@rollup/plugin-replace'; -import terser from '@rollup/plugin-terser'; -import typescript from '@rollup/plugin-typescript'; -import generatePackageJson from 'rollup-plugin-generate-package-json'; -import nodePolyfills from 'rollup-plugin-node-polyfills'; - -const getSharedConfig = (format, file) => ({ - input: 'src/index.ts', - output: [ - { - format: format, - sourcemap: true, - file: file, - preserveModules: false, - }, - ], - external: ['node:events'], - onwarn: (warning) => { - if (warning.code !== 'CIRCULAR_DEPENDENCY') { - console.error(`(!) ${warning.message}`); - } - }, -}); - -export default [ - { - ...getSharedConfig('es', 'dist/esm/bundle.es.js'), - plugins: [ - replace({ - preventAssignment: true, - values: { - 'node:events': 'events', - 'from "node:events"': 'from "events"', - "from 'node:events'": "from 'events'", - }, - }), - resolve({ - preferBuiltins: false, - browser: true, - mainFields: ['browser', 'module', 'main'], - }), - common({ - transformMixedEsModules: true, - esmExternals: true, - }), - nodePolyfills({ - include: ['events'], - }), - typescript({ - module: 'esnext', - outDir: './dist/esm', - declarationDir: './dist/esm', - }), - terser(), - ], - }, - { - ...getSharedConfig('cjs', 'dist/cjs/bundle.cjs.js'), - plugins: [ - { - name: 'replace-node-events', - resolveId(source) { - if (source === 'node:events') { - return 'events'; - } - return null; - }, - }, - nodePolyfills({ - include: ['events'], - }), - generatePackageJson({ - baseContents: (pkg) => ({ - name: pkg.name, - version: pkg.version, - type: 'commonjs', - }), - }), - typescript({ - outDir: './dist/cjs', - declarationDir: './dist/cjs', - }), - common(), - resolve(), - terser(), - ], - }, -]; diff --git a/packages/sdk/fastly/src/api/EdgeFeatureStore.ts b/packages/sdk/fastly/src/api/EdgeFeatureStore.ts new file mode 100644 index 0000000000..039ee4a300 --- /dev/null +++ b/packages/sdk/fastly/src/api/EdgeFeatureStore.ts @@ -0,0 +1,116 @@ +import type { + DataKind, + LDFeatureStore, + LDFeatureStoreDataStorage, + LDFeatureStoreItem, + LDFeatureStoreKindData, + LDLogger, +} from '@launchdarkly/js-server-sdk-common'; +import { deserializePoll, noop } from '@launchdarkly/js-server-sdk-common'; + +export interface EdgeProvider { + get: (rootKey: string) => Promise; +} + +export class EdgeFeatureStore implements LDFeatureStore { + private readonly _rootKey: string; + + constructor( + private readonly _edgeProvider: EdgeProvider, + sdkKey: string, + private readonly _description: string, + private _logger: LDLogger, + ) { + this._rootKey = `LD-Env-${sdkKey}`; + } + + async get( + kind: DataKind, + dataKey: string, + callback: (res: LDFeatureStoreItem | null) => void, + ): Promise { + const { namespace } = kind; + const kindKey = namespace === 'features' ? 'flags' : namespace; + this._logger.debug(`Requesting ${dataKey} from ${this._rootKey}.${kindKey}`); + + try { + const i = await this._edgeProvider.get(this._rootKey); + + if (!i) { + throw new Error(`${this._rootKey}.${kindKey} is not found in KV.`); + } + + const item = deserializePoll(i); + if (!item) { + throw new Error(`Error deserializing ${kindKey}`); + } + + switch (namespace) { + case 'features': + callback(item.flags[dataKey]); + break; + case 'segments': + callback(item.segments[dataKey]); + break; + default: + callback(null); + } + } catch (err) { + this._logger.error(err); + callback(null); + } + } + + async all(kind: DataKind, callback: (res: LDFeatureStoreKindData) => void = noop): Promise { + const { namespace } = kind; + const kindKey = namespace === 'features' ? 'flags' : namespace; + this._logger.debug(`Requesting all from ${this._rootKey}.${kindKey}`); + try { + const i = await this._edgeProvider.get(this._rootKey); + if (!i) { + throw new Error(`${this._rootKey}.${kindKey} is not found in KV.`); + } + + const item = deserializePoll(i); + if (!item) { + throw new Error(`Error deserializing ${kindKey}`); + } + + switch (namespace) { + case 'features': + callback(item.flags); + break; + case 'segments': + callback(item.segments); + break; + default: + callback({}); + } + } catch (err) { + this._logger.error(err); + callback({}); + } + } + + async initialized(callback: (isInitialized: boolean) => void = noop): Promise { + const config = await this._edgeProvider.get(this._rootKey); + const result = config !== null; + this._logger.debug(`Is ${this._rootKey} initialized? ${result}`); + callback(result); + } + + init(allData: LDFeatureStoreDataStorage, callback: () => void): void { + callback(); + } + + getDescription(): string { + return this._description; + } + + // unused + close = noop; + + delete = noop; + + upsert = noop; +} diff --git a/packages/sdk/fastly/src/api/LDClient.ts b/packages/sdk/fastly/src/api/LDClient.ts new file mode 100644 index 0000000000..b4bc5ce9e2 --- /dev/null +++ b/packages/sdk/fastly/src/api/LDClient.ts @@ -0,0 +1,24 @@ +import { Info, internal, LDClientImpl, LDOptions } from '@launchdarkly/js-server-sdk-common'; + +import EdgePlatform from '../platform'; +import createCallbacks from './createCallbacks'; +import createOptions from './createOptions'; + +/** + * The LaunchDarkly SDK edge client object. + */ +export default class LDClient extends LDClientImpl { + // clientSideID is only used to query the edge key-value store and send analytics, not to initialize with LD servers + constructor(clientSideID: string, platformInfo: Info, options: LDOptions, eventsBackend: string) { + const platform = new EdgePlatform(platformInfo, eventsBackend); + const internalOptions: internal.LDInternalOptions = { + analyticsEventPath: `/events/bulk/${clientSideID}`, + diagnosticEventPath: `/events/diagnostic/${clientSideID}`, + includeAuthorizationHeader: false, + }; + + const finalOptions = createOptions(options); + + super(clientSideID, platform, finalOptions, createCallbacks(), internalOptions); + } +} diff --git a/packages/sdk/fastly/src/api/createCallbacks.ts b/packages/sdk/fastly/src/api/createCallbacks.ts new file mode 100644 index 0000000000..922a4b9e08 --- /dev/null +++ b/packages/sdk/fastly/src/api/createCallbacks.ts @@ -0,0 +1,9 @@ +const createCallbacks = () => ({ + onError: () => {}, + onFailed: () => {}, + onReady: () => {}, + onUpdate: () => {}, + hasEventListeners: () => false, +}); + +export default createCallbacks; diff --git a/packages/sdk/fastly/src/api/createOptions.ts b/packages/sdk/fastly/src/api/createOptions.ts new file mode 100644 index 0000000000..2999934e8d --- /dev/null +++ b/packages/sdk/fastly/src/api/createOptions.ts @@ -0,0 +1,17 @@ +import { BasicLogger, LDOptions } from '@launchdarkly/js-server-sdk-common'; + +export const defaultOptions: LDOptions = { + stream: false, + sendEvents: true, + useLdd: true, + diagnosticOptOut: true, + logger: BasicLogger.get(), +}; + +const createOptions = (options: LDOptions) => { + const finalOptions = { ...defaultOptions, ...options }; + finalOptions.logger?.debug(`Using LD options: ${JSON.stringify(finalOptions)}`); + return finalOptions; +}; + +export default createOptions; diff --git a/packages/sdk/fastly/src/api/index.ts b/packages/sdk/fastly/src/api/index.ts new file mode 100644 index 0000000000..c4ae612f9d --- /dev/null +++ b/packages/sdk/fastly/src/api/index.ts @@ -0,0 +1,4 @@ +import LDClient from './LDClient'; + +export * from './EdgeFeatureStore'; +export { LDClient }; diff --git a/packages/sdk/fastly/src/createPlatformInfo.ts b/packages/sdk/fastly/src/createPlatformInfo.ts index 57fb569179..ee6fffffd6 100644 --- a/packages/sdk/fastly/src/createPlatformInfo.ts +++ b/packages/sdk/fastly/src/createPlatformInfo.ts @@ -1,4 +1,4 @@ -import type { Info, PlatformData, SdkData } from '@launchdarkly/js-server-sdk-common-edge'; +import { Info, PlatformData, SdkData } from '@launchdarkly/js-server-sdk-common'; class VercelPlatformInfo implements Info { platformData(): PlatformData { diff --git a/packages/sdk/fastly/src/index.ts b/packages/sdk/fastly/src/index.ts index dc3af43a2e..5e4d14ae3e 100644 --- a/packages/sdk/fastly/src/index.ts +++ b/packages/sdk/fastly/src/index.ts @@ -1,32 +1,48 @@ /// import { KVStore } from 'fastly:kv-store'; -import { - BasicLogger, - EdgeFeatureStore, - EdgeProvider, - init as initEdge, - LDOptions, -} from '@launchdarkly/js-server-sdk-common-edge'; +import { BasicLogger, LDOptions } from '@launchdarkly/js-server-sdk-common'; +import { EdgeFeatureStore, EdgeProvider, LDClient } from './api'; import createPlatformInfo from './createPlatformInfo'; +import validateOptions from './utils/validateOptions'; -export const init = (kvStore: KVStore, sdkKey: string, options: LDOptions = {}) => { +const DEFAULT_EVENTS_BACKEND_NAME = 'launchdarkly'; + +export type FastlySDKOptions = LDOptions & { + /** + * The Fastly Backend name to send LaunchDarkly events. Backends are configured using the Fastly service backend configuration. This option can be ignored if the `sendEvents` option is set to `false`. See [Fastly's Backend documentation](https://developer.fastly.com/reference/api/services/backend/) for more information. The default value is `launchdarkly`. + */ + eventsBackendName?: string; +}; + +export const init = ( + sdkKey: string, + kvStore: KVStore, + options: FastlySDKOptions = { eventsBackendName: DEFAULT_EVENTS_BACKEND_NAME }, +) => { const logger = options.logger ?? BasicLogger.get(); const edgeProvider: EdgeProvider = { get: async (rootKey: string) => { const entry = await kvStore.get(rootKey); - return entry ? await entry.text() : null; + return entry ? entry.text() : null; }, }; - return initEdge(sdkKey, createPlatformInfo(), { + const { eventsBackendName, ...ldOptions } = options; + + const finalOptions = { featureStore: new EdgeFeatureStore(edgeProvider, sdkKey, 'Fastly', logger), logger, - additionalFetchOptions: { - backend: 'launchdarkly', - }, - ...options, - }); + ...ldOptions, + }; + + validateOptions(sdkKey, finalOptions); + return new LDClient( + sdkKey, + createPlatformInfo(), + finalOptions, + eventsBackendName || DEFAULT_EVENTS_BACKEND_NAME, + ); }; diff --git a/packages/sdk/fastly/src/platform/crypto/cryptoJSHasher.ts b/packages/sdk/fastly/src/platform/crypto/cryptoJSHasher.ts new file mode 100644 index 0000000000..4aec221057 --- /dev/null +++ b/packages/sdk/fastly/src/platform/crypto/cryptoJSHasher.ts @@ -0,0 +1,49 @@ +import CryptoJS from 'crypto-js'; + +import { Hasher as LDHasher } from '@launchdarkly/js-server-sdk-common'; + +import { SupportedHashAlgorithm, SupportedOutputEncoding } from './types'; + +export default class CryptoJSHasher implements LDHasher { + private _cryptoJSHasher; + + constructor(algorithm: SupportedHashAlgorithm) { + let algo; + + switch (algorithm) { + case 'sha1': + algo = CryptoJS.algo.SHA1; + break; + case 'sha256': + algo = CryptoJS.algo.SHA256; + break; + default: + throw new Error('unsupported hash algorithm. Only sha1 and sha256 are supported.'); + } + + this._cryptoJSHasher = algo.create(); + } + + digest(encoding: SupportedOutputEncoding): string { + const result = this._cryptoJSHasher.finalize(); + + let enc; + switch (encoding) { + case 'base64': + enc = CryptoJS.enc.Base64; + break; + case 'hex': + enc = CryptoJS.enc.Hex; + break; + default: + throw new Error('unsupported output encoding. Only base64 and hex are supported.'); + } + + return result.toString(enc); + } + + update(data: string): this { + this._cryptoJSHasher.update(data); + return this; + } +} diff --git a/packages/sdk/fastly/src/platform/crypto/cryptoJSHmac.ts b/packages/sdk/fastly/src/platform/crypto/cryptoJSHmac.ts new file mode 100644 index 0000000000..98e8976bb0 --- /dev/null +++ b/packages/sdk/fastly/src/platform/crypto/cryptoJSHmac.ts @@ -0,0 +1,45 @@ +import CryptoJS from 'crypto-js'; + +import { Hmac as LDHmac } from '@launchdarkly/js-server-sdk-common'; + +import { SupportedHashAlgorithm, SupportedOutputEncoding } from './types'; + +export default class CryptoJSHmac implements LDHmac { + private _cryptoJSHmac; + + constructor(algorithm: SupportedHashAlgorithm, key: string) { + let algo; + + switch (algorithm) { + case 'sha1': + algo = CryptoJS.algo.SHA1; + break; + case 'sha256': + algo = CryptoJS.algo.SHA256; + break; + default: + throw new Error('unsupported hash algorithm. Only sha1 and sha256 are supported.'); + } + + this._cryptoJSHmac = CryptoJS.algo.HMAC.create(algo, key); + } + + digest(encoding: SupportedOutputEncoding): string { + const result = this._cryptoJSHmac.finalize(); + + if (encoding === 'base64') { + return result.toString(CryptoJS.enc.Base64); + } + + if (encoding === 'hex') { + return result.toString(CryptoJS.enc.Hex); + } + + throw new Error('unsupported output encoding. Only base64 and hex are supported.'); + } + + update(data: string): this { + this._cryptoJSHmac.update(data); + return this; + } +} diff --git a/packages/sdk/fastly/src/platform/crypto/index.ts b/packages/sdk/fastly/src/platform/crypto/index.ts new file mode 100644 index 0000000000..7a25f59036 --- /dev/null +++ b/packages/sdk/fastly/src/platform/crypto/index.ts @@ -0,0 +1,24 @@ +import type { Crypto, Hasher, Hmac } from '@launchdarkly/js-server-sdk-common'; + +import CryptoJSHasher from './cryptoJSHasher'; +import CryptoJSHmac from './cryptoJSHmac'; +import { SupportedHashAlgorithm } from './types'; + +/** + * Uses crypto-js as substitute to node:crypto because the latter + * is not yet supported in some runtimes. + * https://cryptojs.gitbook.io/docs/ + */ +export default class EdgeCrypto implements Crypto { + createHash(algorithm: SupportedHashAlgorithm): Hasher { + return new CryptoJSHasher(algorithm); + } + + createHmac(algorithm: SupportedHashAlgorithm, key: string): Hmac { + return new CryptoJSHmac(algorithm, key); + } + + randomUUID(): string { + return crypto.randomUUID(); + } +} diff --git a/packages/sdk/fastly/src/platform/crypto/types.ts b/packages/sdk/fastly/src/platform/crypto/types.ts new file mode 100644 index 0000000000..3cf314d1f4 --- /dev/null +++ b/packages/sdk/fastly/src/platform/crypto/types.ts @@ -0,0 +1,2 @@ +export type SupportedHashAlgorithm = 'sha1' | 'sha256'; +export type SupportedOutputEncoding = 'base64' | 'hex'; diff --git a/packages/sdk/fastly/src/platform/index.ts b/packages/sdk/fastly/src/platform/index.ts new file mode 100644 index 0000000000..e4d34ea977 --- /dev/null +++ b/packages/sdk/fastly/src/platform/index.ts @@ -0,0 +1,17 @@ +import type { Crypto, Info, Platform, Requests } from '@launchdarkly/js-server-sdk-common'; + +import EdgeCrypto from './crypto'; +import EdgeRequests from './requests'; + +export default class EdgePlatform implements Platform { + info: Info; + + crypto: Crypto = new EdgeCrypto(); + + requests: Requests; + + constructor(info: Info, eventsBackend: string) { + this.info = info; + this.requests = new EdgeRequests(eventsBackend); + } +} diff --git a/packages/sdk/fastly/src/platform/requests.ts b/packages/sdk/fastly/src/platform/requests.ts new file mode 100644 index 0000000000..3ac39ae7cb --- /dev/null +++ b/packages/sdk/fastly/src/platform/requests.ts @@ -0,0 +1,34 @@ +import { NullEventSource } from '@launchdarkly/js-server-sdk-common'; +import type { + EventSource, + EventSourceCapabilities, + EventSourceInitDict, + Options, + Requests, + Response, +} from '@launchdarkly/js-server-sdk-common'; + +export default class EdgeRequests implements Requests { + eventsBackend: string; + + constructor(eventsBackend: string) { + this.eventsBackend = eventsBackend; + } + + fetch(url: string, options: Options = {}): Promise { + // @ts-ignore + return fetch(url, { ...options, backend: this.eventsBackend }); + } + + createEventSource(url: string, eventSourceInitDict: EventSourceInitDict): EventSource { + return new NullEventSource(url, eventSourceInitDict); + } + + getEventSourceCapabilities(): EventSourceCapabilities { + return { + readTimeout: false, + headers: false, + customMethod: false, + }; + } +} diff --git a/packages/sdk/fastly/src/utils/mockEdgeProvider.ts b/packages/sdk/fastly/src/utils/mockEdgeProvider.ts new file mode 100644 index 0000000000..bdf8791af0 --- /dev/null +++ b/packages/sdk/fastly/src/utils/mockEdgeProvider.ts @@ -0,0 +1,7 @@ +import { EdgeProvider } from '../api'; + +const mockEdgeProvider: EdgeProvider = { + get: jest.fn(), +}; + +export default mockEdgeProvider; diff --git a/packages/sdk/fastly/src/utils/mockFeatureStore.ts b/packages/sdk/fastly/src/utils/mockFeatureStore.ts new file mode 100644 index 0000000000..037bed69ec --- /dev/null +++ b/packages/sdk/fastly/src/utils/mockFeatureStore.ts @@ -0,0 +1,13 @@ +import type { LDFeatureStore } from '@launchdarkly/js-server-sdk-common'; + +const mockFeatureStore: LDFeatureStore = { + all: jest.fn(), + close: jest.fn(), + init: jest.fn(), + initialized: jest.fn(), + upsert: jest.fn(), + get: jest.fn(), + delete: jest.fn(), +}; + +export default mockFeatureStore; diff --git a/packages/sdk/fastly/src/utils/validateOptions.ts b/packages/sdk/fastly/src/utils/validateOptions.ts new file mode 100644 index 0000000000..c65fa083aa --- /dev/null +++ b/packages/sdk/fastly/src/utils/validateOptions.ts @@ -0,0 +1,37 @@ +import { LDOptions as LDOptionsCommon } from '@launchdarkly/js-server-sdk-common'; + +/** + * The Launchdarkly Edge SDKs configuration options. Only logger is officially + * supported. sendEvents is unsupported and is only included as a beta + * preview. + */ +export type LDOptions = Pick; + +/** + * The internal options include featureStore because that's how the LDClient + * implementation expects it. + */ +export type LDOptionsInternal = LDOptions & Pick; + +const validateOptions = (sdkKey: string, options: LDOptionsInternal) => { + const { featureStore, logger, sendEvents, ...rest } = options; + if (!sdkKey) { + throw new Error('You must configure the client with a client key'); + } + + if (!featureStore || typeof featureStore !== 'object' || !featureStore.get) { + throw new Error('You must configure the client with a feature store'); + } + + if (!logger) { + throw new Error('You must configure the client with a logger'); + } + + if (JSON.stringify(rest) !== '{}') { + throw new Error(`Invalid configuration: ${Object.keys(rest).toString()} not supported`); + } + + return true; +}; + +export default validateOptions; diff --git a/packages/sdk/fastly/tsconfig.eslint.json b/packages/sdk/fastly/tsconfig.eslint.json new file mode 100644 index 0000000000..60b2be2a49 --- /dev/null +++ b/packages/sdk/fastly/tsconfig.eslint.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "include": [ + "/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/packages/sdk/fastly/tsconfig.json b/packages/sdk/fastly/tsconfig.json index 78ac937afe..7ff06dea45 100644 --- a/packages/sdk/fastly/tsconfig.json +++ b/packages/sdk/fastly/tsconfig.json @@ -4,9 +4,7 @@ "rootDir": ".", "outDir": "dist", "target": "es2017", - "lib": [ - "es6" - ], + "lib": ["es6"], "module": "commonjs", "strict": true, "noImplicitOverride": true, @@ -17,17 +15,8 @@ "resolveJsonModule": true, "stripInternal": true, "moduleResolution": "node", - "types": [ - "jest", - "node" - ], + "types": ["jest", "node"], "skipLibCheck": true }, - "exclude": [ - "**/*.test.ts", - "dist", - "node_modules", - "__tests__", - "example" - ] -} \ No newline at end of file + "exclude": ["**/*.test.ts", "dist", "node_modules", "__tests__", "example"] +} diff --git a/packages/sdk/fastly/tsup.config.ts b/packages/sdk/fastly/tsup.config.ts new file mode 100644 index 0000000000..7ec3b3486b --- /dev/null +++ b/packages/sdk/fastly/tsup.config.ts @@ -0,0 +1,26 @@ +// It is a dev dependency and the linter doesn't understand. +// eslint-disable-next-line import/no-extraneous-dependencies +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: { + index: 'src/index.ts', + }, + minify: true, + format: ['esm', 'cjs'], + splitting: false, + sourcemap: false, + clean: true, + noExternal: ['@launchdarkly/js-server-sdk-common'], + dts: true, + metafile: true, + esbuildOptions(opts) { + // This would normally be `^_(?!meta|_)`, but go doesn't support negative look-ahead assertions, + // so we need to craft something that works without it. + // So start of line followed by a character that isn't followed by m or underscore, but we + // want other things that do start with m, so we need to progressively handle more characters + // of meta with exclusions. + // eslint-disable-next-line no-param-reassign + opts.mangleProps = /^_([^m|_]|m[^e]|me[^t]|met[^a])/; + }, +}); diff --git a/packages/shared/sdk-server-edge/src/api/LDClient.ts b/packages/shared/sdk-server-edge/src/api/LDClient.ts index f7f7810184..d943329218 100644 --- a/packages/shared/sdk-server-edge/src/api/LDClient.ts +++ b/packages/shared/sdk-server-edge/src/api/LDClient.ts @@ -3,7 +3,7 @@ import { EventEmitter } from 'node:events'; import { Info, internal, LDClientImpl } from '@launchdarkly/js-server-sdk-common'; import EdgePlatform from '../platform'; -import { LDOptionsInternal } from '../utils/validateOptions'; +import { LDOptions } from '../utils/validateOptions'; import createCallbacks from './createCallbacks'; import createOptions from './createOptions'; @@ -14,17 +14,16 @@ export default class LDClient extends LDClientImpl { emitter: EventEmitter; // clientSideID is only used to query the edge key-value store and send analytics, not to initialize with LD servers - constructor(clientSideID: string, platformInfo: Info, options: LDOptionsInternal) { + constructor(clientSideID: string, platformInfo: Info, options: LDOptions) { const em = new EventEmitter(); - const { additionalFetchOptions, ...remainingOptions } = options; - const platform = new EdgePlatform(platformInfo, additionalFetchOptions); + const platform = new EdgePlatform(platformInfo); const internalOptions: internal.LDInternalOptions = { analyticsEventPath: `/events/bulk/${clientSideID}`, diagnosticEventPath: `/events/diagnostic/${clientSideID}`, includeAuthorizationHeader: false, }; - const finalOptions = createOptions(remainingOptions); + const finalOptions = createOptions(options); super( clientSideID, diff --git a/packages/shared/sdk-server-edge/src/index.ts b/packages/shared/sdk-server-edge/src/index.ts index 6ec534092f..24a6c49b77 100644 --- a/packages/shared/sdk-server-edge/src/index.ts +++ b/packages/shared/sdk-server-edge/src/index.ts @@ -22,7 +22,6 @@ export type { LDClient, LDOptions, EdgeProvider }; export const init = (clientSideID: string, platformInfo: Info, options: LDOptionsInternal) => { // this throws if options are invalid validateOptions(clientSideID, options); - console.log('options', options); return new LDClient(clientSideID, platformInfo, options); }; diff --git a/packages/shared/sdk-server-edge/src/platform/index.ts b/packages/shared/sdk-server-edge/src/platform/index.ts index 3d77c45b49..9210f6b024 100644 --- a/packages/shared/sdk-server-edge/src/platform/index.ts +++ b/packages/shared/sdk-server-edge/src/platform/index.ts @@ -8,10 +8,9 @@ export default class EdgePlatform implements Platform { crypto: Crypto = new EdgeCrypto(); - requests: Requests; + requests: Requests = new EdgeRequests(); - constructor(info: Info, edgeRequestsOptions: Record = {}) { + constructor(info: Info) { this.info = info; - this.requests = new EdgeRequests({ additionalFetchOptions: edgeRequestsOptions }); } } diff --git a/packages/shared/sdk-server-edge/src/platform/requests.ts b/packages/shared/sdk-server-edge/src/platform/requests.ts index 07972c7de0..413bbb6b32 100644 --- a/packages/shared/sdk-server-edge/src/platform/requests.ts +++ b/packages/shared/sdk-server-edge/src/platform/requests.ts @@ -8,21 +8,10 @@ import type { Response, } from '@launchdarkly/js-server-sdk-common'; -export interface EdgeRequestsOptions { - additionalFetchOptions?: Record; -} - export default class EdgeRequests implements Requests { - private _options: EdgeRequestsOptions; - - constructor(options: EdgeRequestsOptions = {}) { - this._options = options; - } - fetch(url: string, options: Options = {}): Promise { - const finalOptions = { ...options, ...this._options.additionalFetchOptions }; // @ts-ignore - return fetch(url, finalOptions); + return fetch(url, options); } createEventSource(url: string, eventSourceInitDict: EventSourceInitDict): EventSource { diff --git a/packages/shared/sdk-server-edge/src/utils/validateOptions.ts b/packages/shared/sdk-server-edge/src/utils/validateOptions.ts index c867502096..c65fa083aa 100644 --- a/packages/shared/sdk-server-edge/src/utils/validateOptions.ts +++ b/packages/shared/sdk-server-edge/src/utils/validateOptions.ts @@ -1,24 +1,20 @@ import { LDOptions as LDOptionsCommon } from '@launchdarkly/js-server-sdk-common'; -import { EdgeRequestsOptions } from '../platform/requests'; - /** * The Launchdarkly Edge SDKs configuration options. Only logger is officially * supported. sendEvents is unsupported and is only included as a beta * preview. */ -export type LDOptions = Pick; +export type LDOptions = Pick; /** * The internal options include featureStore because that's how the LDClient * implementation expects it. */ -export type LDOptionsInternal = LDOptions & - EdgeRequestsOptions & - Pick; +export type LDOptionsInternal = LDOptions & Pick; const validateOptions = (sdkKey: string, options: LDOptionsInternal) => { - const { featureStore, logger, sendEvents, additionalFetchOptions, ...rest } = options; + const { featureStore, logger, sendEvents, ...rest } = options; if (!sdkKey) { throw new Error('You must configure the client with a client key'); } From be7aa07e8e011dae8103423a7ddc1659501e454d Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 16:03:13 +0000 Subject: [PATCH 04/11] Fix test and revert change to sdk-server-edge --- packages/sdk/fastly/__tests__/api/LDClient.test.ts | 11 ++++++++--- packages/shared/sdk-server-edge/src/api/LDClient.ts | 3 +-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/sdk/fastly/__tests__/api/LDClient.test.ts b/packages/sdk/fastly/__tests__/api/LDClient.test.ts index 26bad83fae..cc5488e67f 100644 --- a/packages/sdk/fastly/__tests__/api/LDClient.test.ts +++ b/packages/sdk/fastly/__tests__/api/LDClient.test.ts @@ -20,9 +20,14 @@ jest.mock('@launchdarkly/js-sdk-common', () => { const mockEventProcessor = internal.EventProcessor as jest.Mock; describe('Edge LDClient', () => { it('uses clientSideID endpoints', async () => { - const client = new LDClient('client-side-id', createBasicPlatform().info, { - sendEvents: true, - }); + const client = new LDClient( + 'client-side-id', + createBasicPlatform().info, + { + sendEvents: true, + }, + 'launchdarkly', + ); await client.waitForInitialization({ timeout: 10 }); const passedConfig = mockEventProcessor.mock.calls[0][0]; diff --git a/packages/shared/sdk-server-edge/src/api/LDClient.ts b/packages/shared/sdk-server-edge/src/api/LDClient.ts index d943329218..503c30ba28 100644 --- a/packages/shared/sdk-server-edge/src/api/LDClient.ts +++ b/packages/shared/sdk-server-edge/src/api/LDClient.ts @@ -1,9 +1,8 @@ import { EventEmitter } from 'node:events'; -import { Info, internal, LDClientImpl } from '@launchdarkly/js-server-sdk-common'; +import { Info, internal, LDClientImpl, LDOptions } from '@launchdarkly/js-server-sdk-common'; import EdgePlatform from '../platform'; -import { LDOptions } from '../utils/validateOptions'; import createCallbacks from './createCallbacks'; import createOptions from './createOptions'; From 40f05ab1898bcd01df5c8ad67ddf4d7d7b837e51 Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 16:09:36 +0000 Subject: [PATCH 05/11] Add CI --- .github/workflows/fastly.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/fastly.yml diff --git a/.github/workflows/fastly.yml b/.github/workflows/fastly.yml new file mode 100644 index 0000000000..51939efb3f --- /dev/null +++ b/.github/workflows/fastly.yml @@ -0,0 +1,24 @@ +name: sdk/fastly + +on: + push: + branches: [main, 'feat/**'] + paths-ignore: + - '**.md' #Do not need to run CI for markdown changes. + pull_request: + branches: [main, 'feat/**'] + paths-ignore: + - '**.md' + +jobs: + build-test-fastly: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - id: shared + name: Shared CI Steps + uses: ./actions/ci + with: + workspace_name: '@launchdarkly/fastly-server-sdk' + workspace_path: packages/sdk/fastly From 77485da0fec91809258b29279f14ee99132deaf7 Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 16:15:01 +0000 Subject: [PATCH 06/11] Add crypto-js types --- packages/sdk/fastly/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json index 6a3f1f60e7..75ce738c54 100644 --- a/packages/sdk/fastly/package.json +++ b/packages/sdk/fastly/package.json @@ -51,6 +51,7 @@ "crypto-js": "^4.2.0" }, "devDependencies": { + "@types/crypto-js": "^4.2.2", "eslint": "^8.45.0", "jest": "^29.7.0", "prettier": "^3.4.2", From aff265d38daae7ec53afd64a18b446449fb06545 Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 16:27:10 +0000 Subject: [PATCH 07/11] fix typedoc --- packages/sdk/fastly/tsconfig.eslint.json | 10 +++------- packages/sdk/fastly/tsconfig.ref.json | 7 +++++++ tsconfig.json | 5 ++++- 3 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 packages/sdk/fastly/tsconfig.ref.json diff --git a/packages/sdk/fastly/tsconfig.eslint.json b/packages/sdk/fastly/tsconfig.eslint.json index 60b2be2a49..56c9b38305 100644 --- a/packages/sdk/fastly/tsconfig.eslint.json +++ b/packages/sdk/fastly/tsconfig.eslint.json @@ -1,9 +1,5 @@ { "extends": "./tsconfig.json", - "include": [ - "/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/sdk/fastly/tsconfig.ref.json b/packages/sdk/fastly/tsconfig.ref.json new file mode 100644 index 0000000000..832c1d8dd7 --- /dev/null +++ b/packages/sdk/fastly/tsconfig.ref.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*", "package.json", "src/**/testData.json"], + "compilerOptions": { + "composite": true + } +} diff --git a/tsconfig.json b/tsconfig.json index 5110eb7541..3d39f7356d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -66,6 +66,9 @@ }, { "path": "./packages/telemetry/browser-telemetry/tsconfig.ref.json" + }, + { + "path": "./packages/sdk/fastly/tsconfig.ref.json" } ] -} +} \ No newline at end of file From 7d47d1237436991fcf996ae70fd8f1ccf4703c4e Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 17:11:48 +0000 Subject: [PATCH 08/11] Add fastly to release-please --- .github/workflows/manual-publish-docs.yml | 1 + .github/workflows/manual-publish.yml | 1 + .github/workflows/release-please.yml | 21 +++++++++++++++++++++ release-please-config.json | 9 +++++++++ 4 files changed, 32 insertions(+) diff --git a/.github/workflows/manual-publish-docs.yml b/.github/workflows/manual-publish-docs.yml index 907b270001..617664c430 100644 --- a/.github/workflows/manual-publish-docs.yml +++ b/.github/workflows/manual-publish-docs.yml @@ -12,6 +12,7 @@ on: - packages/shared/sdk-server-edge - packages/shared/akamai-edgeworker-sdk - packages/sdk/cloudflare + - packages/sdk/fastly - packages/sdk/server-node - packages/sdk/vercel - packages/sdk/akamai-base diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index c1ca69e3b3..46ef1d4e16 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -22,6 +22,7 @@ on: - packages/shared/sdk-server-edge - packages/shared/akamai-edgeworker-sdk - packages/sdk/cloudflare + - packages/sdk/fastly - packages/sdk/react-native - packages/sdk/server-node - packages/sdk/react-universal diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 33b7a55f1f..dd597d7d21 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -14,6 +14,7 @@ jobs: package-sdk-server-edge-released: ${{ steps.release.outputs['packages/shared/sdk-server-edge--release_created'] }} package-akamai-edgeworker-sdk-released: ${{ steps.release.outputs['packages/shared/akamai-edgeworker-sdk--release_created'] }} package-cloudflare-released: ${{ steps.release.outputs['packages/sdk/cloudflare--release_created'] }} + package-fastly-released: ${{ steps.release.outputs['packages/sdk/fastly--release_created'] }} package-react-native-released: ${{ steps.release.outputs['packages/sdk/react-native--release_created'] }} package-server-node-released: ${{ steps.release.outputs['packages/sdk/server-node--release_created'] }} package-vercel-released: ${{ steps.release.outputs['packages/sdk/vercel--release_created'] }} @@ -152,6 +153,26 @@ jobs: workspace_path: packages/sdk/cloudflare aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + release-fastly: + runs-on: ubuntu-latest + needs: ['release-please', 'release-sdk-server'] + permissions: + id-token: write + contents: write + if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-fastly-released == 'true'}} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + registry-url: 'https://registry.npmjs.org' + - id: release-fastly + name: Full release of packages/sdk/fastly + uses: ./actions/full-release + with: + workspace_path: packages/sdk/fastly + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + release-react-native: runs-on: ubuntu-latest needs: ['release-please', 'release-sdk-client'] diff --git a/release-please-config.json b/release-please-config.json index b25cbcf8eb..6d542753ba 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -20,6 +20,15 @@ "src/createPlatformInfo.ts" ] }, + "packages/sdk/fastly": { + "extra-files": [ + { + "type": "json", + "path": "example/package.json", + "jsonpath": "$.dependencies['@launchdarkly/fastly-server-sdk']" + } + ] + }, "packages/sdk/react-native": {}, "packages/sdk/server-node": {}, "packages/sdk/vercel": { From cfddcdc281104f58a2f2e8b454fd4944613b23ed Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 17:34:40 +0000 Subject: [PATCH 09/11] Prep for alpha release --- .release-please-manifest.json | 1 + .sdk_metadata.json | 9 +++++++++ packages/sdk/fastly/package.json | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b6f350b608..bf581535cb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -3,6 +3,7 @@ "packages/shared/sdk-server": "2.10.0", "packages/sdk/server-node": "9.7.2", "packages/sdk/cloudflare": "2.6.2", + "packages/sdk/fastly": "0.0.1", "packages/shared/sdk-server-edge": "2.5.2", "packages/sdk/vercel": "1.3.21", "packages/sdk/akamai-base": "2.1.20", diff --git a/.sdk_metadata.json b/.sdk_metadata.json index fe6500fadc..462a1cf7c0 100644 --- a/.sdk_metadata.json +++ b/.sdk_metadata.json @@ -28,6 +28,15 @@ "tag-prefix": "cloudflare-server-sdk-" } }, + "Fastly": { + "name": "Fastly SDK", + "type": "edge", + "path": "packages/sdk/fastly", + "languages": ["JavaScript", "TypeScript"], + "releases": { + "tag-prefix": "faslty-server-sdk-" + } + }, "react-native": { "name": "React Native SDK", "type": "client-side", diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json index 75ce738c54..f641146820 100644 --- a/packages/sdk/fastly/package.json +++ b/packages/sdk/fastly/package.json @@ -1,6 +1,6 @@ { "name": "@launchdarkly/fastly-server-sdk", - "version": "0.0.1", + "version": "0.0.1-alpha.1", "packageManager": "yarn@3.4.1", "description": "Cloudflare LaunchDarkly SDK", "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/cloudflare", @@ -35,7 +35,7 @@ "dist" ], "scripts": { - "build": "tsup", + "build": "tsup && ../../../scripts/replace-version.sh .", "clean": "rimraf dist", "tsw": "yarn tsc --watch", "start": "rimraf dist && yarn tsw", From f9b95610c4dbe2214608cb3c0fe0638228848807 Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 17:46:32 +0000 Subject: [PATCH 10/11] Prep for 0.0.1 release --- packages/sdk/fastly/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json index f641146820..87ca31d027 100644 --- a/packages/sdk/fastly/package.json +++ b/packages/sdk/fastly/package.json @@ -1,6 +1,6 @@ { "name": "@launchdarkly/fastly-server-sdk", - "version": "0.0.1-alpha.1", + "version": "0.0.1", "packageManager": "yarn@3.4.1", "description": "Cloudflare LaunchDarkly SDK", "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/cloudflare", From 7fd2d960dab1a2e78c1e64d4442b581340995382 Mon Sep 17 00:00:00 2001 From: Henry Barrow Date: Fri, 3 Jan 2025 17:59:17 +0000 Subject: [PATCH 11/11] Update homepage url --- packages/sdk/fastly/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/fastly/package.json b/packages/sdk/fastly/package.json index 87ca31d027..02eb1dff75 100644 --- a/packages/sdk/fastly/package.json +++ b/packages/sdk/fastly/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "packageManager": "yarn@3.4.1", "description": "Cloudflare LaunchDarkly SDK", - "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/cloudflare", + "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/fastly", "repository": { "type": "git", "url": "https://github.com/launchdarkly/js-core.git"