Skip to content

Commit

Permalink
feat: multi provider implementation for Node
Browse files Browse the repository at this point in the history
  • Loading branch information
ajwootto committed May 23, 2024
1 parent c2adbfb commit bb17e3f
Show file tree
Hide file tree
Showing 24 changed files with 6,249 additions and 2,274 deletions.
1 change: 1 addition & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
"libs/providers/flipt": "0.1.0",
"libs/providers/flagsmith-client": "0.1.2",
"libs/providers/flipt-web": "0.1.0",
"libs/providers/multi-provider": "0.1.0",
"libs/providers/growthbook-client": "0.1.1"
}
25 changes: 25 additions & 0 deletions libs/providers/multi-provider/.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"
}
}
]
}
15 changes: 15 additions & 0 deletions libs/providers/multi-provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Multi Provider

## Installation

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

## Building

Run `nx package providers-multi-provider` to build the library.

## Running unit tests

Run `nx test providers-multi-provider` to execute the unit tests via [Jest](https://jestjs.io).
3 changes: 3 additions & 0 deletions libs/providers/multi-provider/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/multi-provider/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable */
export default {
displayName: 'providers-multi-provider',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../../coverage/libs/providers/multi-provider',
};
16 changes: 16 additions & 0 deletions libs/providers/multi-provider/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@openfeature/vendor-migration-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"
}
}
76 changes: 76 additions & 0 deletions libs/providers/multi-provider/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"name": "providers-multi-provider",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/providers/multi-provider/src",
"projectType": "library",
"targets": {
"publish": {
"executor": "nx:run-commands",
"options": {
"command": "npm run publish-if-not-exists",
"cwd": "dist/libs/providers/multi"
},
"dependsOn": [
{
"projects": "self",
"target": "package"
}
]
},
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/providers/multi-provider/**/*.ts", "libs/providers/multi-provider/package.json"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/providers/multi-provider/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"package": {
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"project": "libs/providers/multi-provider/package.json",
"outputPath": "dist/libs/providers/multi",
"entryFile": "libs/providers/multi-provider/src/index.ts",
"tsConfig": "libs/providers/multi-provider/tsconfig.lib.json",
"buildableProjectDepsInPackageJsonType": "dependencies",
"compiler": "tsc",
"generateExportsField": true,
"umdName": "multi",
"external": "all",
"format": ["cjs", "esm"],
"assets": [
{
"glob": "package.json",
"input": "./assets",
"output": "./src/"
},
{
"glob": "LICENSE",
"input": "./",
"output": "./"
},
{
"glob": "README.md",
"input": "./libs/providers/multi",
"output": "./"
}
]
}
}
},
"tags": []
}
2 changes: 2 additions & 0 deletions libs/providers/multi-provider/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lib/multi-provider';
export * from './lib/errors';
19 changes: 19 additions & 0 deletions libs/providers/multi-provider/src/lib/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ErrorCode, GeneralError, OpenFeatureError } from '@openfeature/server-sdk';

export class ErrorWithCode extends OpenFeatureError {
constructor(
public code: ErrorCode,
message: string,
) {
super(message);
}
}

export class AggregateError extends GeneralError {
constructor(
message: string,
public originalErrors: { source: string; error: unknown }[],
) {
super(message);
}
}
65 changes: 65 additions & 0 deletions libs/providers/multi-provider/src/lib/hook-executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { EvaluationDetails, FlagValue, Hook, HookContext, HookHints, Logger } from '@openfeature/server-sdk';

/**
* Utility for executing a set of hooks of each type. Implementation is largely copied from the main OpenFeature SDK.
*/
export class HookExecutor {
constructor(private logger: Logger) {}

async beforeHooks(hooks: Hook[] | undefined, hookContext: HookContext, hints: HookHints) {
const newContext = { ...hookContext.context };
for (const hook of hooks ?? []) {
// freeze the hookContext
Object.freeze(hookContext);

Object.assign(newContext, {
...(await hook?.before?.(hookContext, Object.freeze(hints))),
});
}

// after before hooks, freeze the EvaluationContext.
return Object.freeze(newContext);
}

async afterHooks(
hooks: Hook[] | undefined,
hookContext: HookContext,
evaluationDetails: EvaluationDetails<FlagValue>,
hints: HookHints,
) {
// run "after" hooks sequentially
for (const hook of hooks ?? []) {
await hook?.after?.(hookContext, evaluationDetails, hints);
}
}

async errorHooks(hooks: Hook[] | undefined, hookContext: HookContext, err: unknown, hints: HookHints) {
// run "error" hooks sequentially
for (const hook of hooks ?? []) {
try {
await hook?.error?.(hookContext, err, hints);
} catch (err) {
this.logger.error(`Unhandled error during 'error' hook: ${err}`);
if (err instanceof Error) {
this.logger.error(err.stack);
}
this.logger.error((err as Error)?.stack);
}
}
}

async finallyHooks(hooks: Hook[] | undefined, hookContext: HookContext, hints: HookHints) {
// run "finally" hooks sequentially
for (const hook of hooks ?? []) {
try {
await hook?.finally?.(hookContext, hints);
} catch (err) {
this.logger.error(`Unhandled error during 'finally' hook: ${err}`);
if (err instanceof Error) {
this.logger.error(err.stack);
}
this.logger.error((err as Error)?.stack);
}
}
}
}
Loading

0 comments on commit bb17e3f

Please sign in to comment.