Skip to content

feat(node-sdk): support for remote configuration #295

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 57 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
4f6ccb6
Add support for feature-specific config payloads
pavkam Jan 10, 2025
7b3a4af
Refactor flag evaluation logic and update SDK version.
pavkam Jan 13, 2025
70f2393
Add feature configuration support and enhance fallback features
pavkam Jan 13, 2025
2e30def
Merge remote-tracking branch 'origin/main' into buc-3198-extend-the-w…
pavkam Jan 13, 2025
d2e9de6
Bump version to 0.4.0
pavkam Jan 13, 2025
5af7fd3
Merge branch 'main' into buc-3198-extend-the-web-sdks-to-expose-the-c…
pavkam Jan 22, 2025
340fc9c
feat(browser-sdk): add format script, improve README formatting, and …
pavkam Jan 22, 2025
a6c6678
feat(browser-sdk): update feature configuration handling and improve …
pavkam Jan 22, 2025
f5f250e
feat(react-sdk): enhance feature handling in useFeature hook
pavkam Jan 22, 2025
66f661a
feat(browser-sdk, react-sdk, openfeature-browser-sdk): enhance featur…
pavkam Jan 22, 2025
38975e1
feat(openfeature-browser-provider): revert changes to openfeature ada…
pavkam Jan 24, 2025
f2ba839
chore(browser-sdk, react-sdk): Respond to comments
pavkam Jan 24, 2025
f1383e6
fix(browser-sdk): update README to reflect changes in feature configu…
pavkam Jan 24, 2025
cd276f4
feat(openfeature-browser-provider): update browser-sdk dependency and…
pavkam Jan 24, 2025
e61be44
feat(node-sdk): enhance feature configuration and fallback handling
pavkam Jan 27, 2025
3d12581
docs(node-sdk): update README with remote configuration and type-safe…
pavkam Jan 27, 2025
5f02bb8
Merge branch 'main' into buc-3198-extend-the-web-sdks-to-expose-the-c…
pavkam Jan 27, 2025
295f05d
fix(browser-sdk): update feature remote config type definition
pavkam Jan 27, 2025
0dd5757
chore(react-sdk): remove unused import from index.tsx
pavkam Jan 27, 2025
7173423
feat(browser-sdk): enhance fallback feature configuration handling
pavkam Jan 27, 2025
862df25
test(browser-sdk): remove .only from features test
pavkam Jan 27, 2025
7678334
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 27, 2025
bfb4276
test(browser-sdk): update feature test assertions
pavkam Jan 27, 2025
e22475b
test(browser-sdk): update feature test expectations
pavkam Jan 27, 2025
da09414
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 27, 2025
7d45486
chore: remove artifacts from this PR
pavkam Jan 27, 2025
2e62475
refactor(react-sdk): simplify feature config access and reduce payload
pavkam Jan 27, 2025
34fd9b0
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 27, 2025
cedeb14
test(browser-sdk): remove trailing newline in test file
pavkam Jan 27, 2025
2f74252
Merge branch 'main' into buc-3198-extend-the-web-sdks-to-expose-the-c…
pavkam Jan 28, 2025
fa735d8
docs(browser-sdk,react-sdk): clarify remote config documentation
pavkam Jan 28, 2025
a6eb451
Merge remote-tracking branch 'origin/main' into buc-3198-extend-the-w…
pavkam Jan 28, 2025
ff3e85a
Merge remote-tracking branch 'origin/buc-3198-extend-the-web-sdks-to-…
pavkam Jan 28, 2025
441ab2e
feat(node-sdk): update feature override and configuration handling
pavkam Jan 28, 2025
a659f05
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 28, 2025
a51a495
docs(node-sdk): Update README with detailed remote config explanation…
pavkam Jan 28, 2025
f986feb
feat(browser-sdk): export FallbackFeatureOverride type
pavkam Jan 28, 2025
7c6c47c
chore(release): bump browser-sdk and react-sdk to 3.0.0-alpha.1
pavkam Jan 28, 2025
99a9186
Merge branch 'main' into buc-3197-extend-the-node-sdk-to-expose-the-c…
pavkam Jan 28, 2025
7012ae4
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 28, 2025
352a462
Merge branch 'main' into buc-3198-extend-the-web-sdks-to-expose-the-c…
pavkam Jan 28, 2025
941bb42
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 28, 2025
713b0d2
feat(node-sdk): Enhance feature override validation and configuration…
pavkam Jan 28, 2025
5a8fffe
Merge branch 'main' into buc-3198-extend-the-web-sdks-to-expose-the-c…
pavkam Jan 29, 2025
f4b6643
Merge branch 'main' into buc-3198-extend-the-web-sdks-to-expose-the-c…
pavkam Jan 29, 2025
dde88b5
fix: ensure feature config always has key and payload properties
pavkam Jan 29, 2025
bb506b4
refactor: simplify feature config type definition
pavkam Jan 29, 2025
564332a
Merge remote-tracking branch 'origin/buc-3198-extend-the-web-sdks-to-…
pavkam Jan 29, 2025
8a36cf0
Merge branch 'buc-3198-extend-the-web-sdks-to-expose-the-config' into…
pavkam Jan 29, 2025
6e84e64
fix: ensure feature config returns undefined key and payload when no …
pavkam Jan 29, 2025
9351f5b
refactor: remove redundant comment in Feature interface
pavkam Jan 29, 2025
9f5efd7
docs: update README with type-safe feature flag configuration example
pavkam Jan 29, 2025
b2328cc
Merge branch 'main' into buc-3197-extend-the-node-sdk-to-expose-the-c…
pavkam Jan 29, 2025
813cde1
feat(node-sdk): extend node SDK to support feature configuration with…
pavkam Jan 29, 2025
c452976
feat(node-sdk): add type-safe generics for feature retrieval methods
pavkam Jan 29, 2025
07743eb
fix(node-sdk): improve type safety for feature config getter
pavkam Jan 29, 2025
60a3568
Merge branch 'main' into buc-3197-extend-the-node-sdk-to-expose-the-c…
pavkam Jan 29, 2025
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
95 changes: 91 additions & 4 deletions packages/node-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,18 @@ const boundClient = bucketClient.bindClient({

// get the huddle feature using company, user and custom context to
// evaluate the targeting.
const { isEnabled, track } = boundClient.getFeature("huddle");
const { isEnabled, track, config } = boundClient.getFeature("huddle");

if (isEnabled) {
// this is your feature gated code ...
// send an event when the feature is used:
track();

if (config?.key === "zoom") {
// this code will run if a given remote configuration
// is set up.
}

// CAUTION: if you plan to use the event for automated feedback surveys
// call `flush` immediately after `track`. It can optionally be awaited
// to guarantee the sent happened.
Expand Down Expand Up @@ -108,6 +113,34 @@ to `getFeatures()` (or through `bindClient(..).getFeatures()`). That means the
`initialize()` has completed. `BucketClient` will continue to periodically
download the targeting rules from the Bucket servers in the background.

### Remote config

Similar to `isEnabled`, each feature has a `config` property. This configuration is managed from within Bucket.
It is managed similar to the way access to features is managed, but instead of the binary `isEnabled` you can have
multiple configuration values which are given to different user/companies.

```ts
const features = bucketClient.getFeatures();
// {
// huddle: {
// isEnabled: true,
// targetingVersion: 42,
// config: {
// key: "gpt-3.5",
// payload: { maxTokens: 10000, model: "gpt-3.5-beta1" }
// }
// }
// }
```

The `key` is always present while the `payload` is a optional JSON value for arbitrary configuration needs.
If feature has no configuration or, no configuration value was matched against the context, the `config` object
will be empty, thus, `key` will be `undefined`. Make sure to check against this case when trying to use the
configuration in your application.

Just as `isEnabled`, accessing `config` on the object returned by `getFeatures` does not automatically
generate a `check` event, contrary to the `config` property on the object returned by `getFeature`.

## Configuring

The Bucket `Node.js` SDK can be configured through environment variables,
Expand Down Expand Up @@ -136,7 +169,13 @@ Note: BUCKET_FEATURES_ENABLED, BUCKET_FEATURES_DISABLED are comma separated list
"apiBaseUrl": "https://proxy.slick-demo.com",
"featureOverrides": {
"huddles": true,
"voiceChat": false
"voiceChat": false,
"aiAssist": {
"key": "gpt-4.0",
"payload": {
"maxTokens": 50000
}
}
}
}
```
Expand All @@ -162,8 +201,11 @@ import { BucketClient } from "@bucketco/node-sdk";
declare module "@bucketco/node-sdk" {
interface Features {
"show-todos": boolean;
"create-todos": boolean;
"delete-todos": boolean;
"create-todos": { isEnabled: boolean };
"delete-todos": {
isEnabled: boolean,
config: any
};
}
}

Expand All @@ -173,7 +215,52 @@ bucketClient.initialize().then({
console.log("Bucket initialized!")
bucketClient.getFeature("invalid-feature") // feature doesn't exist
})
```

The following example show how to add strongly typed payloads when using remote configuration:

```typescript
import { BucketClient } from "@bucketco/node-sdk";

type ConfirmationConfig = {
shouldShowConfirmation: boolean;
};

declare module "@bucketco/node-sdk" {
interface Features {
"delete-todos": {
isEnabled: boolean;
config: {
key: string;
payload: ConfirmationConfig;
};
};
}
}

export const bucketClient = new BucketClient();

function deleteTodo(todoId: string) {
// get the feature information
const {
isEnabled,
config: { payload: confirmationConfig },
} = bucketClient.getFeature("delete-todos");

// check that feature is enabled for user
if (!isEnabled) {
return;
}

// finally, check if we enabled the "confirmation" dialog for this user and only
// show it in that case.
// since we defined `ConfirmationConfig` as the only valid payload for `delete-todos`,
// we have type-safety helping us with the payload value.
if (confirmationConfig.shouldShowConfirmation) {
showMessage("Are you really sure you want to delete this item?");
// ... rest of the code
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a screenshot at the bottom here. It refers to the first section about useFeature and typesafety and is unrelated to configs. Let's move the screenshot up:

Screenshot 2025-02-03 at 09 15 51

```

![Type check failed](docs/type-check-failed.png "Type check failed")
Expand Down
10 changes: 9 additions & 1 deletion packages/node-sdk/example/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,18 @@ app.post("/todos", (req, res) => {
return res.status(400).json({ error: "Invalid todo" });
}

const { track, isEnabled } = res.locals.bucketUser.getFeature("create-todos");
const { track, isEnabled, config } =
res.locals.bucketUser.getFeature("create-todos");

// Check if the user has the "create-todos" feature enabled
if (isEnabled) {
// Check if the todo is at least N characters long
if (todo.length < config.payload.minimumLength) {
return res
.status(400)
.json({ error: "Todo must be at least 5 characters long" });
}

// Track the feature usage
track();
todos.push(todo);
Expand Down
27 changes: 24 additions & 3 deletions packages/node-sdk/example/bucket.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
import { BucketClient, Context } from "../src";
import { FeatureOverrides } from "../src/types";

type CreateConfig = {
minimumLength: number;
};

// Extending the Features interface to define the available features
declare module "../src/types" {
interface Features {
"show-todos": boolean;
"create-todos": boolean;
"create-todos": {
isEnabled: boolean;
config: {
key: string;
payload: CreateConfig;
};
};
"delete-todos": boolean;
"some-else": {};
}
}

let featureOverrides = (context: Context): FeatureOverrides => {
return { "delete-todos": true }; // feature keys checked at compile time
let featureOverrides = (_: Context): FeatureOverrides => {
return {
"create-todos": {
isEnabled: true,
config: {
key: "short",
payload: {
minimumLength: 10,
},
},
},
}; // feature keys checked at compile time
};

let host = undefined;
Expand Down
4 changes: 2 additions & 2 deletions packages/node-sdk/example/bucketConfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"overrides": {
"myFeature": true,
"myFeatureFalse": false
"show-todos": true,
"create-todos": true
}
}
Loading