Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
"libs/providers/unleash-web": "0.1.1",
"libs/providers/growthbook": "0.1.2",
"libs/providers/aws-ssm": "0.1.3",
"libs/providers/flagsmith": "0.1.2"
"libs/providers/flagsmith": "0.1.2",
"libs/hooks/debounce": "0.1.0"
}
30 changes: 30 additions & 0 deletions libs/hooks/debounce/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"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",
{
"ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"]
}
]
}
}
]
}
58 changes: 58 additions & 0 deletions libs/hooks/debounce/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Debounce Hook

This is a utility "meta" hook, which can be used to effectively debounce or rate limit other hooks based on various parameters.
This can be especially useful for certain UI frameworks and SDKs that frequently re-render and re-evaluate flags (React, Angular, etc).

## Installation

```
$ npm install @openfeature/debounce-hook
```

### Peer dependencies

This package only requires the `@openfeature/core` dependency, which is installed automatically no matter which OpenFeature JavaScript SDK you are using.

## Usage

Simply wrap your hook with the debounce hook by passing it as a constructor arg, and then configure the remaining options.
In the example below, we wrap a logging hook.
This debounces all its stages, so it only logs a maximum of once a minute for each flag key, no matter how many times that flag is evaluated.

```ts
const debounceHook = new DebounceHook(loggingHook, {
debounceTime: 60_000, // how long to wait before the hook can fire again
maxCacheItems: 100, // max amount of items to keep in the cache; if exceeded, the oldest item is dropped
});

// add the hook globally
OpenFeature.addHooks(debounceHook);

// or at a specific client
client.addHooks(debounceHook);
```

The hook maintains a simple expiring cache with a fixed max size and keeps a record of recent evaluations based on an optional key-generation function (cacheKeySupplier).
Be default, the key-generation function is purely based on the flag key.
Particularly in server use-cases, you may want to take the targetingKey or other contextual information into account in your debouncing.
Below we see an example using this, as well as other advanced options:

```ts
const debounceHook = new DebounceHook<string>(loggingHook, {
cacheKeySupplier: (flagKey, context) => flagKey + context.targetingKey, // cache on a combination of user and flag key
debounceTime: 60_000, // debounce for 60 seconds (per user due to our cacheKeySupplier above)
maxCacheItems: 1000, // cache a maximum of 1000 records
cacheErrors: false, // don't debounce errors; always re-run if the last run threw
logger: console, // optional logger
});
```

## Development

### Building

Run `nx package hooks-debounce` to build the library.

### Running unit tests

Run `nx test hooks-debounce` to execute the unit tests via [Jest](https://jestjs.io).
3 changes: 3 additions & 0 deletions libs/hooks/debounce/babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": [["minify", { "builtIns": false }]]
}
9 changes: 9 additions & 0 deletions libs/hooks/debounce/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default {
displayName: 'debounce',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../coverage/hooks',
};
17 changes: 17 additions & 0 deletions libs/hooks/debounce/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@openfeature/debounce-hook",
"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"
},
"license": "Apache-2.0",
"peerDependencies": {
"@openfeature/core": "^1.9.1"
}
}
77 changes: 77 additions & 0 deletions libs/hooks/debounce/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"name": "debounce",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "hooks/src",
"projectType": "library",
"release": {
"version": {
"generatorOptions": {
"packageRoot": "dist/{projectRoot}",
"currentVersionResolver": "git-tag"
}
}
},
"tags": [],
"targets": {
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"lint": {
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "{projectRoot}/jest.config.ts"
}
},
"package": {
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"project": "libs/hooks/debounce/package.json",
"outputPath": "dist/libs/hooks/debounce",
"entryFile": "libs/hooks/debounce/src/index.ts",
"tsConfig": "libs/hooks/debounce/tsconfig.lib.json",
"compiler": "tsc",
"generateExportsField": true,
"umdName": "debounce",
"external": "all",
"format": ["cjs", "esm"],
"assets": [
{
"glob": "package.json",
"input": "./assets",
"output": "./src/"
},
{
"glob": "LICENSE",
"input": "./",
"output": "./"
},
{
"glob": "README.md",
"input": "./libs/hooks/debounce",
"output": "./"
}
]
}
},
"publish": {
"executor": "nx:run-commands",
"options": {
"command": "npm run publish-if-not-exists",
"cwd": "dist/libs/hooks/debounce"
},
"dependsOn": [
{
"projects": "self",
"target": "package"
}
]
}
}
}
1 change: 1 addition & 0 deletions libs/hooks/debounce/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/debounce-hook';
Loading