Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bucketco/node-sdk

Package Overview
Dependencies
Maintainers
0
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bucketco/node-sdk - npm Package Compare versions

Comparing version 1.1.1 to 1.2.0

2

dist/package.json
{
"name": "@bucketco/node-sdk",
"version": "1.1.1",
"version": "1.2.0",
"license": "MIT",

@@ -5,0 +5,0 @@ "repository": {

@@ -346,10 +346,3 @@ "use strict";

}
/**
* Gets the evaluated feature for the current context which includes the user, company, and custom context.
*
* @returns The evaluated features.
* @remarks
* Call `initialize` before calling this method to ensure the feature definitions are cached, no features will be returned otherwise.
**/
getFeatures(context) {
_getFeatures(context) {
var _a, _b;

@@ -388,27 +381,66 @@ const featureDefinitions = this.getFeaturesCache().get();

}
return (0, utils_1.maskedProxy)(evaluatedFeatures, (features, key) => {
var _a;
void this.sendFeatureEvent({
action: "check",
key: key,
targetingVersion: features[key].targetingVersion,
evalResult: features[key].isEnabled,
}).catch((err) => {
var _a;
(_a = this._config.logger) === null || _a === void 0 ? void 0 : _a.error(`failed to send check event for "${key}": ${err}`, err);
});
const feature = features[key];
return {
key,
isEnabled: (_a = feature === null || feature === void 0 ? void 0 : feature.isEnabled) !== null && _a !== void 0 ? _a : false,
track: () => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const userId = (_a = context.user) === null || _a === void 0 ? void 0 : _a.id;
if (!userId) {
(_b = this._config.logger) === null || _b === void 0 ? void 0 : _b.warn("feature.track(): no user set, cannot track event");
return;
}
yield this.track(userId, key, { companyId: (_c = context.company) === null || _c === void 0 ? void 0 : _c.id });
}),
};
return evaluatedFeatures;
}
_wrapRawFeature(context, { key, isEnabled, targetingVersion }) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const client = this;
return {
get isEnabled() {
void client
.sendFeatureEvent({
action: "check",
key,
targetingVersion,
evalResult: isEnabled,
})
.catch((err) => {
var _a;
(_a = client._config.logger) === null || _a === void 0 ? void 0 : _a.error(`failed to send check event for "${key}": ${err}`, err);
});
return isEnabled;
},
key,
track: () => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const userId = (_a = context.user) === null || _a === void 0 ? void 0 : _a.id;
if (!userId) {
(_b = this._config.logger) === null || _b === void 0 ? void 0 : _b.warn("feature.track(): no user set, cannot track event");
return;
}
yield this.track(userId, key, {
companyId: (_c = context.company) === null || _c === void 0 ? void 0 : _c.id,
});
}),
};
}
/**
* Gets the evaluated feature for the current context which includes the user, company, and custom context.
*
* @returns The evaluated features.
* @remarks
* Call `initialize` before calling this method to ensure the feature definitions are cached, no features will be returned otherwise.
**/
getFeatures(context) {
const features = this._getFeatures(context);
return Object.fromEntries(Object.entries(features).map(([k, v]) => [
k,
this._wrapRawFeature(context, v),
]));
}
/**
* Gets the evaluated feature for the current context which includes the user, company, and custom context.
* Using the `isEnabled` property sends a `check` event to Bucket.
*
* @returns The evaluated features.
* @remarks
* Call `initialize` before calling this method to ensure the feature definitions are cached, no features will be returned otherwise.
**/
getFeature(context, key) {
var _a;
const features = this._getFeatures(context);
const feature = features[key];
return this._wrapRawFeature(context, {
key,
isEnabled: (_a = feature === null || feature === void 0 ? void 0 : feature.isEnabled) !== null && _a !== void 0 ? _a : false,
targetingVersion: feature === null || feature === void 0 ? void 0 : feature.targetingVersion,
});

@@ -460,2 +492,3 @@ }

* Get features for the user/company/other context bound to this client.
* Meant for use in serialization of features for transferring to the client-side/browser.
*

@@ -468,2 +501,11 @@ * @returns Features for the given user/company and whether each one is enabled or not

/**
* Get a specific feature for the user/company/other context bound to this client.
* Using the `isEnabled` property sends a `check` event to Bucket.
*
* @returns Features for the given user/company and whether each one is enabled or not
*/
getFeature(key) {
return this._client.getFeature(this._context, key);
}
/**
* Track an event in Bucket.

@@ -504,4 +546,12 @@ *

}
/**
* Flushes the batch buffer.
*/
flush() {
return __awaiter(this, void 0, void 0, function* () {
yield this._client.flush();
});
}
}
exports.BoundBucketClient = BoundBucketClient;
//# sourceMappingURL=client.js.map

@@ -5,3 +5,2 @@ "use strict";

exports.checkWithinAllottedTimeWindow = checkWithinAllottedTimeWindow;
exports.maskedProxy = maskedProxy;
exports.ok = ok;

@@ -31,27 +30,2 @@ exports.isObject = isObject;

/**
* Create a read-only masked proxy for the given object that notifies a
* callback when a property is accessed. The callback is then responsible
* for returning the masked value for the given property.
*
* @param obj - The object to proxy.
* @param callback - The callback to notify.
*
* @returns The proxy object.
**/
function maskedProxy(obj, valueFunc) {
return new Proxy(obj, {
get(target, prop) {
const val = target[prop];
if (val !== undefined) {
return valueFunc(target, prop);
}
return undefined;
},
set(_target, prop, _value) {
console.error(`Cannot modify property '${String(prop)}' of the object.`);
return true;
},
});
}
/**
* Assert that the given condition is `true`.

@@ -58,0 +32,0 @@ *

@@ -1,2 +0,2 @@

import { ClientOptions, Context, Logger, TrackOptions, TypedFeatures } from "./types";
import { ClientOptions, Context, Feature, Logger, TrackOptions, TypedFeatures } from "./types";
/**

@@ -134,2 +134,4 @@ * The SDK client.

flush(): Promise<void>;
private _getFeatures;
private _wrapRawFeature;
/**

@@ -143,2 +145,11 @@ * Gets the evaluated feature for the current context which includes the user, company, and custom context.

getFeatures(context: Context): TypedFeatures;
/**
* Gets the evaluated feature for the current context which includes the user, company, and custom context.
* Using the `isEnabled` property sends a `check` event to Bucket.
*
* @returns The evaluated features.
* @remarks
* Call `initialize` before calling this method to ensure the feature definitions are cached, no features will be returned otherwise.
**/
getFeature(context: Context, key: keyof TypedFeatures): Feature;
}

@@ -179,7 +190,15 @@ /**

* Get features for the user/company/other context bound to this client.
* Meant for use in serialization of features for transferring to the client-side/browser.
*
* @returns Features for the given user/company and whether each one is enabled or not
*/
getFeatures(): Record<string, import("./types").Feature>;
getFeatures(): Record<string, Feature>;
/**
* Get a specific feature for the user/company/other context bound to this client.
* Using the `isEnabled` property sends a `check` event to Bucket.
*
* @returns Features for the given user/company and whether each one is enabled or not
*/
getFeature(key: keyof TypedFeatures): Feature;
/**
* Track an event in Bucket.

@@ -205,2 +224,6 @@ *

bindClient({ user, company, other }: Context): BoundBucketClient;
/**
* Flushes the batch buffer.
*/
flush(): Promise<void>;
}
export { BoundBucketClient, BucketClient } from "./client";
export type { Attributes, ClientOptions, Context, Features, HttpClient, Logger, TrackingMeta, } from "./types";
export type { Attributes, ClientOptions, Context, Features, HttpClient, Logger, RawFeature, TrackingMeta, } from "./types";

@@ -51,3 +51,3 @@ import { FeatureData } from "@bucketco/flag-evaluation";

*/
export interface InternalFeature {
export interface RawFeature {
/**

@@ -54,0 +54,0 @@ * The key of the feature.

@@ -5,13 +5,2 @@ import { Logger } from "./types";

/**
* Create a read-only masked proxy for the given object that notifies a
* callback when a property is accessed. The callback is then responsible
* for returning the masked value for the given property.
*
* @param obj - The object to proxy.
* @param callback - The callback to notify.
*
* @returns The proxy object.
**/
export declare function maskedProxy<T extends object, K extends keyof T, O>(obj: T, valueFunc: (target: T, prop: K) => O): Readonly<Record<K, O>>;
/**
* Assert that the given condition is `true`.

@@ -18,0 +7,0 @@ *

{
"name": "@bucketco/node-sdk",
"version": "1.1.1",
"version": "1.2.0",
"license": "MIT",

@@ -49,3 +49,3 @@ "repository": {

},
"gitHead": "dc3944c6f7ad6a63f403b8ed0c12a1f1de3f919f"
"gitHead": "a20fbcbe0216c1c99a155eb92b0723a7ceb87b2b"
}

@@ -53,3 +53,3 @@ # Bucket Node.js SDK

Once the client is initialized, you can obtain features along with the isEnabled status to indicate whether the feature is targeted for this user/company:
Once the client is initialized, you can obtain features along with the `isEnabled` status to indicate whether the feature is targeted for this user/company:

@@ -63,16 +63,45 @@ ```ts

// get the current features (uses company, user and custom context to evaluate the features).
const { huddle } = boundClient.getFeatures();
// get the huddle feature using company, user and custom context to evaluate the targeting.
const { isEnabled, track } = boundClient.getFeature("huddle");
if (huddle.isEnabled) {
if (isEnabled) {
// this is your feature gated code ...
// send an event when the feature is used:
huddle.track();
track();
// CAUTION: if need the track event to be sent to Bucket as soon as possible,
// always call `flush`. It can optionally be awaited to guarantee the sent happened.
client.flush();
// 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.
boundClient.flush();
}
```
You can also use the `getFeatures` method which returns a map of all features:
```ts
// get the current features (uses company, user and custom context to evaluate the features).
const features = boundClient.getFeatures();
const bothEnabled =
features.huddle?.isEnabled && features.voiceHuddle?.isEnabled;
```
When using `getFeatures` be careful not to assume that a feature exists, this could be a dangerous pattern:
```ts
// warning: if the `huddle` feature does not exist because it wasn't created in Bucket
// or because the client was unable to reach our servers for some reason, this will cause an exception:
const { isEnabled } = boundClient.getFeatures()["huddle"];
```
## High performance feature targeting
The Bucket Node SDK contacts the Bucket servers when you call `initialize`
and downloads the features with their targeting rules.
These rules are then matched against the user/company information you provide
to `getFeatures` (or through `bindClient(..).getFeatures()`). That means the
`getFeatures` call does not need to contact the Bucket servers once initialize
has completed. `BucketClient` will continue to periodically download the
targeting rules from the Bucket servers in the background.
## Flushing
It is highly recommended that users of this SDK manually call `client.flush()` method on process shutdown. The SDK employs

@@ -84,10 +113,11 @@ a batching technique to minimize the number of calls that are sent to Bucket's servers. During process shutdown, some

````ts
```ts
process.on("SIGINT", () => {
console.log("Flushing batch buffer...");
client.flush().then(() => {
process.exit(0)
})
process.exit(0);
});
});
```
When you bind a client to a user/company, this data is matched against the targeting rules.

@@ -98,12 +128,2 @@ To get accurate targeting, you must ensure that the user/company information provided is sufficient to match against the targeting rules you've created.

## High performance feature targeting
The Bucket Node SDK contacts the Bucket servers when you call `initialize`
and downloads the features with their targeting rules.
These rules are then matched against the user/company information you provide
to `getFeatures` (or through `bindClient(..).getFeatures()`). That means the
`getFeatures` call does not need to contact the Bucket servers once initialize
has completed. `BucketClient` will continue to periodically download the
targeting rules from the Bucket servers in the background.
## Tracking custom events and setting custom attributes

@@ -128,3 +148,3 @@

client.track("user_id", "huddle", { attributes: { voice: true } });
````
```

@@ -186,3 +206,3 @@ It's also possible to achieve the same through a bound client in the following manner:

secretKey: string,
// The host to send requests to (optional).
// Override Bucket server address
host?: string = "https://front.bucket.co",

@@ -193,3 +213,3 @@ // The logger you can supply. By default no logging is performed.

httpClient?: HttpClient = fetchClient,
// A list of fallback features that will be enabled the Bucket servers
// A list of fallback features that will be enabled if the Bucket servers
// have not been contacted yet.

@@ -224,1 +244,5 @@ fallbackFeatures?: string[]

> Copyright (c) 2024 Bucket ApS
```
```

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc