diff --git a/.gitignore b/.gitignore index 88dc724c5f..37ff832f46 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ yarn-error.log .DS_Store .vscode dump.rdb +.wrangler diff --git a/.prettierignore b/.prettierignore index 2ef3c10866..e43a1c6132 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ coverage .vscode **/*/CHANGELOG.md packages/sdk/akamai-edgekv/src/edgekv/edgekv.js +packages/sdk/cloudflare/src/createPlatformInfo.ts diff --git a/.yarnrc.yml b/.yarnrc.yml index 41bc1d890d..5a857bef1a 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -2,6 +2,10 @@ nodeLinker: node-modules npmPublishAccess: public +npmScopes: + jsr: + npmRegistryServer: 'https://npm.jsr.io' + plugins: - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs spec: '@yarnpkg/plugin-workspace-tools' diff --git a/packages/sdk/cloudflare/README.md b/packages/sdk/cloudflare/README.md index 3d06f21fdd..56171ce9f4 100644 --- a/packages/sdk/cloudflare/README.md +++ b/packages/sdk/cloudflare/README.md @@ -15,7 +15,14 @@ For more information, see the [complete reference guide for this SDK](https://do ## Install ```shell +# npm npm i @launchdarkly/cloudflare-server-sdk + +# yarn +yarn add @launchdarkly/cloudflare-server-sdk + +# jsr +npx jsr add @launchdarkly/cloudflare-server-sdk ``` Then turn on the Node.js compatibility flag in your `wrangler.toml`. This allows the SDK to use `node:events`: @@ -24,6 +31,10 @@ Then turn on the Node.js compatibility flag in your `wrangler.toml`. This allows compatibility_flags = [ "nodejs_compat" ] ``` +## Additional JSR setup + +If you want to install this package as a JSR package, you will need to use [`esbuild` version >= 19.7](https://github.com/evanw/esbuild/releases/tag/v0.19.7) to enable support for `import attributes`. + ## Quickstart Initialize the ldClient with your client side sdk key and the [Cloudflare KV namespace](https://developers.cloudflare.com/workers/runtime-apis/kv#kv-bindings): @@ -33,12 +44,12 @@ import { init as initLD } from '@launchdarkly/cloudflare-server-sdk'; export default { async fetch(request: Request, env: Bindings): Promise { - const sdkKey = 'test-sdk-key'; + const clientSideID = 'test-client-side-id'; const flagKey = 'testFlag1'; const context = { kind: 'user', key: 'test-user-key-1' }; // init the ldClient, wait and finally evaluate - const client = initLD(sdkKey, env.LD_KV); + const client = initLD(clientSideID, env.LD_KV); await client.waitForInitialization(); const flagValue = await client.variation(flagKey, context, false); diff --git a/packages/sdk/cloudflare/example/README.md b/packages/sdk/cloudflare/example/README.md index 1cf8915388..4a96552020 100644 --- a/packages/sdk/cloudflare/example/README.md +++ b/packages/sdk/cloudflare/example/README.md @@ -25,20 +25,26 @@ yarn && yarn build kv_namespaces = [{ binding = "LD_KV", id = "YOUR_KV_ID", preview_id = "YOUR_PREVIEW_KV_ID" }] ``` -3. Insert test data to the preview environment: +3. Insert test data to the preview environment. You must use your own clientSideID and prefix it with `LD-Env-`. In the example below, the clientSideID is `test-client-side-id`. Internally, the Cloudflare SDK uses this `LD-Env-` namespace to distinguish LaunchDarkly data from others. ```shell -# The Cloudflare SDK automatically adds the "LD-Env-" prefix to your sdk key -npx wrangler kv:key put --binding=LD_KV "LD-Env-test-sdk-key" --path ./src/testData.json --preview +npx wrangler kv:key put --binding=LD_KV "LD-Env-test-client-side-id" --path ./src/testData.json --preview ``` 4. View that test data to ensure it's present: ```shell -npx wrangler kv:key get --binding=LD_KV "LD-Env-test-sdk-key" --preview +npx wrangler kv:key get --binding=LD_KV "LD-Env-test-client-side-id" --preview ``` -5. Finally: +5. Edit [index.ts](https://github.com/launchdarkly/js-core/blob/main/packages/sdk/cloudflare/example/src/index.ts#L6) to use your clientSideID and a valid flag key from the test data you just inserted. + +```ts + const clientSideID = 'test-client-side-id'; + const flagKey = 'test-boolean-flag'; +``` + +6. Finally: ```shell yarn start diff --git a/packages/sdk/cloudflare/example/package.json b/packages/sdk/cloudflare/example/package.json index fbabf0d18d..94f5ea7bb4 100644 --- a/packages/sdk/cloudflare/example/package.json +++ b/packages/sdk/cloudflare/example/package.json @@ -10,11 +10,11 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20230321.0", "@types/jest": "^29.5.5", - "esbuild": "^0.14.41", + "esbuild": "^0.20.2", "jest": "^29.7.0", "jest-environment-miniflare": "^2.5.0", "miniflare": "^2.5.0", - "prettier": "^2.6.2", + "prettier": "^3.2.5", "ts-jest": "^28.0.3", "typescript": "5.1.6", "wrangler": "2.20.2" diff --git a/packages/sdk/cloudflare/example/src/index.test.ts b/packages/sdk/cloudflare/example/src/index.test.ts index 4ae6b27c8d..d8bf5e0c31 100644 --- a/packages/sdk/cloudflare/example/src/index.test.ts +++ b/packages/sdk/cloudflare/example/src/index.test.ts @@ -16,7 +16,7 @@ describe('test', () => { }; env = getMiniflareBindings(); const { LD_KV } = env; - await LD_KV.put('LD-Env-test-sdk-key', JSON.stringify(testData)); + await LD_KV.put('LD-Env-test-client-side-id', JSON.stringify(testData)); }); afterEach(() => { diff --git a/packages/sdk/cloudflare/jsr.json b/packages/sdk/cloudflare/jsr.json new file mode 100644 index 0000000000..2770ea1534 --- /dev/null +++ b/packages/sdk/cloudflare/jsr.json @@ -0,0 +1,9 @@ +{ + "name": "@launchdarkly/cloudflare-server-sdk", + "version": "0.0.3", + "exports": "./src/index.ts", + "publish": { + "include": ["LICENSE", "README.md", "package.json", "jsr.json", "src/**/*.ts"], + "exclude": ["src/**/*.test.ts"] + } +} diff --git a/packages/sdk/cloudflare/src/createPlatformInfo.ts b/packages/sdk/cloudflare/src/createPlatformInfo.ts index e66971d953..fe9c7d6c22 100644 --- a/packages/sdk/cloudflare/src/createPlatformInfo.ts +++ b/packages/sdk/cloudflare/src/createPlatformInfo.ts @@ -1,6 +1,10 @@ import type { Info, PlatformData, SdkData } from '@launchdarkly/js-server-sdk-common-edge'; -import { name, version } from '../package.json'; +// @ts-ignore +// eslint-disable-next-line prettier/prettier +import * as packageJson from '../package.json' assert { type: "json" } + +const { name, version } = packageJson class CloudflarePlatformInfo implements Info { platformData(): PlatformData { @@ -18,6 +22,6 @@ class CloudflarePlatformInfo implements Info { } } -const createPlatformInfo = () => new CloudflarePlatformInfo(); +const createPlatformInfo = (): CloudflarePlatformInfo => new CloudflarePlatformInfo() export default createPlatformInfo; diff --git a/packages/sdk/cloudflare/src/index.test.ts b/packages/sdk/cloudflare/src/index.test.ts index 978d525d63..747bc75e17 100644 --- a/packages/sdk/cloudflare/src/index.test.ts +++ b/packages/sdk/cloudflare/src/index.test.ts @@ -12,13 +12,13 @@ const mf = new Miniflare({ kvNamespaces: ['TEST_NAMESPACE'], }); -const sdkKey = 'test-sdk-key'; +const clientSideID = 'test-client-side-id'; const flagKey1 = 'testFlag1'; const flagKey2 = 'testFlag2'; const flagKey3 = 'testFlag3'; const context: LDContext = { kind: 'user', key: 'test-user-key-1' }; const namespace = 'LD_KV'; -const rootEnvKey = `LD-Env-${sdkKey}`; +const rootEnvKey = `LD-Env-${clientSideID}`; describe('init', () => { let kv: KVNamespace; @@ -27,7 +27,7 @@ describe('init', () => { beforeAll(async () => { kv = (await mf.getKVNamespace(namespace)) as unknown as KVNamespace; await kv.put(rootEnvKey, JSON.stringify(allFlagsSegments)); - ldClient = init(sdkKey, kv); + ldClient = init(clientSideID, kv); await ldClient.waitForInitialization(); }); diff --git a/packages/sdk/cloudflare/src/index.ts b/packages/sdk/cloudflare/src/index.ts index 692a0c6fc4..064e6e969b 100644 --- a/packages/sdk/cloudflare/src/index.ts +++ b/packages/sdk/cloudflare/src/index.ts @@ -14,8 +14,8 @@ import { BasicLogger, EdgeFeatureStore, init as initEdge, - LDClient, - LDOptions, + type LDClient, + type LDOptions, } from '@launchdarkly/js-server-sdk-common-edge'; import createPlatformInfo from './createPlatformInfo'; @@ -45,7 +45,11 @@ export type { LDClient }; * @return * The new {@link LDClient} instance. */ -export const init = (clientSideID: string, kvNamespace: KVNamespace, options: LDOptions = {}) => { +export const init = ( + clientSideID: string, + kvNamespace: KVNamespace, + options: LDOptions = {}, +): LDClient => { const logger = options.logger ?? BasicLogger.get(); return initEdge(clientSideID, createPlatformInfo(), { featureStore: new EdgeFeatureStore(kvNamespace, clientSideID, 'Cloudflare', logger),