Skip to content

feat: cloudflare sdk base #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6a874f3
chore: setup src folder and example app dependencies
yusinto Apr 3, 2023
d673756
chore: remove redundant tsconfig watch options
yusinto Apr 3, 2023
393d0fe
chore: replaced workspace deps with version numbers. Convert featureS…
yusinto Apr 3, 2023
5be4a3b
chore: implemented platform and ldclient
yusinto Apr 3, 2023
6540a15
chore: added randomUUID implementation
yusinto Apr 3, 2023
03321ae
chore: added Requests with MockEventSource
yusinto Apr 4, 2023
a23964e
chore: implemented crypto using crypto-js. Renamed platform files. Fi…
yusinto Apr 5, 2023
de700c1
fix: import events to node:events
yusinto Apr 5, 2023
00f4b1e
test: first round debugging. preview data not visible for some reason.
yusinto Apr 5, 2023
2819240
chore: improved logging and test data.
yusinto Apr 5, 2023
618e96d
chore: improve folder and file structures
yusinto Apr 7, 2023
1f97b12
chore: miniflare and unit tests now works
yusinto Apr 8, 2023
796df24
chore: added unit tests
yusinto Apr 10, 2023
b05c234
chore: test store using async facade
yusinto Apr 10, 2023
b2da58e
chore: added more unit tests. added util functions. dryd unit tests.
yusinto Apr 10, 2023
ff2eb84
fix: eslint single export issue.
yusinto Apr 10, 2023
c9d7cb4
chore: remove internal to generate types for AsyncStoreFacade.
yusinto Apr 10, 2023
bf3e849
fix: ignore dist folder from jest config
yusinto Apr 10, 2023
b861a94
chore: remove example folder for now
yusinto Apr 10, 2023
cabd14d
chore: remove example app from workspace for now
yusinto Apr 10, 2023
a534b23
chore: improve comments
yusinto Apr 10, 2023
0abc6ec
Update README.md
yusinto Apr 12, 2023
45a3566
Create CHANGELOG.md
yusinto Apr 12, 2023
f41cbe6
Update README.md
yusinto Apr 12, 2023
0b06609
chore: added typedoc comments
yusinto Apr 12, 2023
92d2311
Merge branch 'main' into yus/sc-195479/move-cloudflare-sdk-to-js-core
yusinto Apr 12, 2023
c5c3220
Update tsconfig.json
yusinto Apr 12, 2023
5e5eb4d
Merge branch 'yus/sc-195479/move-cloudflare-sdk-to-js-core' of github…
yusinto Apr 12, 2023
cb2470d
chore: use package.json name and version
yusinto Apr 12, 2023
a7f5aa0
chore: add ci config (#78)
yusinto Apr 13, 2023
2c98021
chore: add miniflare tests (#76)
yusinto Apr 13, 2023
2667e9e
chore: moved MockEventSource for sharing (#75)
yusinto Apr 13, 2023
6f7d2ba
chore: prettier ignore coverage folder
yusinto Apr 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ module.exports = {
ignorePatterns: ['**/dist/**'],
rules: {
'prettier/prettier': ['error'],
'class-methods-use-this': 'off',
},
};
24 changes: 24 additions & 0 deletions .github/workflows/cloudflare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: sdk/cloudflare

on:
push:
branches: [main]
paths-ignore:
- '**.md' #Do not need to run CI for markdown changes.
pull_request:
branches: [main]
paths-ignore:
- '**.md'

jobs:
build-test-cloudflare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- id: shared
name: Shared CI Steps
uses: ./actions/ci
with:
workspace_name: '@launchdarkly/cloudflare-server-sdk'
workspace_path: packages/sdk/cloudflare
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ docs/
!.yarn/sdks
!.yarn/versions
yarn-error.log
.DS_Store
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.vscode-test/
out/
dist/
test-fixtures/
node_modules/
docs/
.yarn
coverage
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"workspaces": [
"packages/shared/common",
"packages/shared/sdk-server",
"packages/sdk/server-node"
"packages/sdk/server-node",
"packages/sdk/cloudflare"
],
"private": true,
"scripts": {
Expand Down
15 changes: 15 additions & 0 deletions packages/sdk/cloudflare/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog

All notable changes to the LaunchDarkly SDK for Cloudflare Workers will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org).

## [1.0.0] - 2022-10-13

Bump `launchdarkly-node-server-sdk` and move SDK out of beta.

## [0.1.1] - 2022-07-07

Fix TypeScript definition

## [0.1.0] - 2021-10-19

This is the first public release of the LaunchDarkly Cloudflare Edge SDK. The SDK is considered to be unsupported and in beta until release 1.0.0.
57 changes: 57 additions & 0 deletions packages/sdk/cloudflare/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# LaunchDarkly Cloudflare SDK

[![NPM][sdk-server-cloudflare-npm-badge]][sdk-server-cloudflare-npm-link]
[![Actions Status][sdk-server-cloudflare-ci-badge]][sdk-server-cloudflare-ci]
[![Documentation](https://img.shields.io/static/v1?label=GitHub+Pages&message=API+reference&color=00add8)](https://launchdarkly.github.io/js-core/packages/sdk/server-cloudflare/docs/)

This library supports using Cloudflare [Workers KV](https://developers.cloudflare.com/workers/learning/how-kv-works) to replace the default in-memory feature store of the [LaunchDarkly Node.js SDK](https://github.com/launchdarkly/cloudflare-server-sdk).

For more information, see the [SDK features guide](https://docs.launchdarkly.com/sdk/features/storing-data).

## Installation

```shell
npm i @launchdarkly/cloudflare-server-sdk
```

or yarn:

```shell
yarn add -D @launchdarkly/cloudflare-server-sdk
```

## Quickstart

Initialize the ldClient with the [Cloudflare KV namespace](https://developers.cloudflare.com/workers/runtime-apis/kv#kv-bindings) and your client side sdk key:

```typescript
import ldInit from '@launchdarkly/cloudflare-server-sdk';

const ldClient = ldInit(KV_NAMESPACE, 'YOUR CLIENT-SIDE SDK KEY');
```

To learn more, head straight to the [complete reference guide for this SDK](https://docs.launchdarkly.com/sdk/server-side/cloudflare).

## Developing this SDK

```shell
# at js-core repo root
yarn && yarn build && cd packages/sdk/cloudflare

# run tests
yarn test
```

## 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
9 changes: 9 additions & 0 deletions packages/sdk/cloudflare/jest.config.json
Original file line number Diff line number Diff line change
@@ -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"]
}
52 changes: 52 additions & 0 deletions packages/sdk/cloudflare/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@launchdarkly/cloudflare-server-sdk",
"version": "0.0.1",
"description": "LaunchDarkly Server-Side SDK for Cloudflare workers",
"packageManager": "yarn@3.4.1",
"keywords": [
"launchdarkly",
"cloudflare",
"edge",
"worker"
],
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"type": "module",
"files": [
"/dist"
],
"scripts": {
"build": "rimraf dist && yarn tsc",
"tsw": "yarn tsc --watch",
"start": "rimraf dist && yarn tsw",
"lint": "eslint . --ext .ts",
"prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
"test": "NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" jest --ci --runInBand --coverage",
"check": "yarn prettier && yarn lint && yarn tsc && yarn test"
},
"dependencies": {
"@cloudflare/workers-types": "^4.20230321.0",
"@launchdarkly/js-server-sdk-common": "0.2.0",
"crypto-js": "^4.1.1"
},
"devDependencies": {
"@types/crypto-js": "^4.1.1",
"@types/jest": "^29.5.0",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"eslint": "^8.37.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.5.0",
"launchdarkly-js-test-helpers": "^2.2.0",
"miniflare": "^2.13.0",
"prettier": "^2.8.7",
"rimraf": "^5.0.0",
"ts-jest": "^29.1.0",
"typedoc": "0.23.26",
"typescript": "^5.0.3"
}
}
23 changes: 23 additions & 0 deletions packages/sdk/cloudflare/src/createLDClient/CloudflareImpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { KVNamespace } from '@cloudflare/workers-types';
import { EventEmitter } from 'node:events';
import { LDClientImpl, LDOptions } from '@launchdarkly/js-server-sdk-common';
import CloudflarePlatform from '../platform';
import createOptions from './createOptions';
import createCallbacks from './createCallbacks';

export default class CloudflareImpl extends LDClientImpl {
emitter: EventEmitter;

// sdkKey is only used to query the KV, not to initialize with LD servers
constructor(kvNamespace: KVNamespace, sdkKey: string, options: LDOptions = {}) {
const emitter = new EventEmitter();

super(
'n/a',
new CloudflarePlatform(),
createOptions(kvNamespace, sdkKey, options),
createCallbacks(emitter)
);
this.emitter = emitter;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { EventEmitter } from 'node:events';
import createCallbacks from './createCallbacks';
import noop from '../utils/noop';

describe('createCallbacks', () => {
let emitter: EventEmitter;
const err = new Error('test error');

beforeEach(() => {
emitter = new EventEmitter();
emitter.emit = jest.fn();
});

afterEach(() => {
jest.resetAllMocks();
});

test('onError', () => {
emitter.on('error', noop);

const { onError } = createCallbacks(emitter);
onError(err);

expect(emitter.emit).toHaveBeenNthCalledWith(1, 'error', err);
});

test('onError should not be called', () => {
const { onError } = createCallbacks(emitter);
onError(err);

expect(emitter.emit).not.toHaveBeenCalled();
});

test('onFailed', () => {
const { onFailed } = createCallbacks(emitter);
onFailed(err);

expect(emitter.emit).toHaveBeenNthCalledWith(1, 'failed', err);
});

test('onReady', () => {
const { onReady } = createCallbacks(emitter);
onReady();

expect(emitter.emit).toHaveBeenNthCalledWith(1, 'ready');
});

test('onUpdate should be noop', () => {
const { onUpdate } = createCallbacks(emitter);

expect(onUpdate.toString()).toEqual(noop.toString());
});

test('hasEventListeners', () => {
const { hasEventListeners } = createCallbacks(emitter);

expect(hasEventListeners()).toBeFalsy();
});
});
20 changes: 20 additions & 0 deletions packages/sdk/cloudflare/src/createLDClient/createCallbacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { EventEmitter } from 'node:events';
import noop from '../utils/noop';

const createCallbacks = (emitter: EventEmitter) => ({
onError: (err: Error) => {
if (emitter.listenerCount('error')) {
emitter.emit('error', err);
}
},
onFailed: (err: Error) => {
emitter.emit('failed', err);
},
onReady: () => {
emitter.emit('ready');
},
onUpdate: noop,
hasEventListeners: () => false,
});

export default createCallbacks;
Loading