Skip to content

Commit

Permalink
feat(flipt): Add Flipt provider in openfeature-js (#724)
Browse files Browse the repository at this point in the history
Signed-off-by: Yoofi Quansah <ybquansah@gmail.com>
Signed-off-by: Mark Phelps <209477+markphelps@users.noreply.github.com>
  • Loading branch information
yquansah authored Jan 19, 2024
1 parent 40bbaf6 commit 6ec1b0e
Show file tree
Hide file tree
Showing 21 changed files with 810 additions and 37 deletions.
2 changes: 2 additions & 0 deletions .github/component_owners.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ components:
- kinyoklion
- mateoc
- sago2k8
libs/providers/flipt:
- yquansah

ignored-authors:
- renovate-bot
3 changes: 2 additions & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"libs/providers/config-cat": "0.4.0",
"libs/providers/launchdarkly-client": "0.2.0",
"libs/providers/go-feature-flag-web": "0.1.5",
"libs/shared/flagd-core": "0.1.8"
"libs/shared/flagd-core": "0.1.8",
"libs/providers/flipt": "0.0.1"
}
25 changes: 25 additions & 0 deletions libs/providers/flipt/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": "error"
}
}
]
}
76 changes: 76 additions & 0 deletions libs/providers/flipt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Flipt Provider

[Flipt](https://www.flipt.io/) is an open source developer friendly feature flagging solution, that allows for easy management and fast feature evaluation.

This provider is an implementation on top of the official [Flipt Node Server Side SDK](https://www.npmjs.com/package/@flipt-io/flipt).

## Installation

```
$ npm install @openfeature/flipt-provider
```

### Peer Dependencies

Both the OpenFeature SDK and the Flipt Node Server SDK are required as peer dependencies.

Please make sure to install `@flipt/flipt-io` at versions >= `1.0.0`, as the client API is different in earlier versions.

The peer dependency will also enforce the above version.

## Example initialization and usage

To initialize the OpenFeature client with Flipt, you can use the following code snippet:

```ts
import { FliptProvider } from '@openfeature/flipt';

const provider = new FliptProvider('namespace-of-choice', { url: 'http://your.upstream.flipt.host' });
OpenFeature.setProvider(provider);
```

After the provider gets initialized, you can start evaluations of feature flags like so:

```ts
const client = OpenFeature.getClient();
const details = await client.getStringDetails('nonExistent', 'default', {
targetingKey: 'myentity',
email: 'john@flipt.io',
});
```

## Evaluation Context Transformation

OpenFeature standardizes the evaluation context to include a `targetingKey`, and some other additional arbitrary properties that each provider can use fit for their use case.

For Flipt, we translate the `targetingKey` as the `entityId`, and the rest of the OpenFeature evaluation context as the `context` in Flipt vernacular. You can find the meaning of those two words [here](https://www.flipt.io/docs/reference/evaluation/variant-evaluation) in our API docs.

For example, an OpenFeature Evaluation context that has this structure:

```json
{
"targetingKey": "my-targeting-id",
"email": "john@flipt.io",
"userId": "this-very-long-user-id"
}
```

will get transformed to the following for Flipt:

```json
{
"entityId": "my-targeting-id",
"context": {
"email": "john@flipt.io",
"userId": "this-very-long-user-id"
}
}
```

## Building

Run `nx package providers-flipt` to build the library.

## Running unit tests

Run `nx test providers-flipt` to execute the unit tests via [Jest](https://jestjs.io).
3 changes: 3 additions & 0 deletions libs/providers/flipt/babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": [["minify", { "builtIns": false }]]
}
10 changes: 10 additions & 0 deletions libs/providers/flipt/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable */
export default {
displayName: 'providers-flipt',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../../coverage/libs/providers/flipt',
};
47 changes: 47 additions & 0 deletions libs/providers/flipt/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions libs/providers/flipt/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@openfeature/flipt-provider",
"version": "0.0.1",
"dependencies": {
"tslib": "^2.3.0"
},
"main": "./src/index.js",
"typings": "./src/index.d.ts",
"scripts": {
"publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi",
"current-version": "echo $npm_package_version"
},
"peerDependencies": {
"@openfeature/server-sdk": "^1.6.0",
"@flipt-io/flipt": "^1.0.0"
}
}
76 changes: 76 additions & 0 deletions libs/providers/flipt/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"name": "providers-flipt",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/providers/flipt/src",
"projectType": "library",
"targets": {
"publish": {
"executor": "nx:run-commands",
"options": {
"command": "npm run publish-if-not-exists",
"cwd": "dist/libs/providers/flipt"
},
"dependsOn": [
{
"projects": "self",
"target": "package"
}
]
},
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/providers/flipt/**/*.ts", "libs/providers/flipt/package.json"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/providers/flipt/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"package": {
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"project": "libs/providers/flipt/package.json",
"outputPath": "dist/libs/providers/flipt",
"entryFile": "libs/providers/flipt/src/index.ts",
"tsConfig": "libs/providers/flipt/tsconfig.lib.json",
"buildableProjectDepsInPackageJsonType": "dependencies",
"compiler": "tsc",
"generateExportsField": true,
"umdName": "flipt",
"external": "all",
"format": ["cjs", "esm"],
"assets": [
{
"glob": "package.json",
"input": "./assets",
"output": "./src/"
},
{
"glob": "LICENSE",
"input": "./",
"output": "./"
},
{
"glob": "README.md",
"input": "./libs/providers/flipt",
"output": "./"
}
]
}
}
},
"tags": []
}
1 change: 1 addition & 0 deletions libs/providers/flipt/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/flipt-provider';
18 changes: 18 additions & 0 deletions libs/providers/flipt/src/lib/context-transformer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { EvaluationContext } from '@openfeature/server-sdk';
import { transformContext } from './context-transformer';

describe('context-transformer', () => {
describe('transformContext', () => {
it('should transform context correctly', () => {
const context: EvaluationContext = {
targetingKey: 'entity',
customProp: 'test',
};

const transformedContext: Record<string, string> = transformContext(context);

expect(transformedContext['customProp']).toBe('test');
expect(transformedContext['targetingKey']).toBeUndefined();
});
});
});
12 changes: 12 additions & 0 deletions libs/providers/flipt/src/lib/context-transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { EvaluationContext } from '@openfeature/server-sdk';

export function transformContext(context: EvaluationContext): Record<string, string> {
const evalContext: Record<string, string> = {};
for (const value in context) {
if (value !== 'targetingKey') {
evalContext[value] = context[value]?.toString() ?? '';
}
}

return evalContext;
}
Loading

0 comments on commit 6ec1b0e

Please sign in to comment.