posthog-node
Version:
PostHog Node.js integration
118 lines (117 loc) • 4.63 kB
JavaScript
import { FeatureFlagError } from "./types.mjs";
class FeatureFlagEvaluations {
constructor(init){
this._host = init.host;
this._distinctId = init.distinctId;
this._groups = init.groups;
this._disableGeoip = init.disableGeoip;
this._flags = init.flags;
this._requestId = init.requestId;
this._evaluatedAt = init.evaluatedAt;
this._flagDefinitionsLoadedAt = init.flagDefinitionsLoadedAt;
this._errorsWhileComputing = init.errorsWhileComputing ?? false;
this._quotaLimited = init.quotaLimited ?? false;
this._accessed = init.accessed ?? new Set();
this._isSlice = init.isSlice ?? false;
}
isEnabled(key) {
const flag = this._flags[key];
this._recordAccess(key);
return flag?.enabled ?? false;
}
getFlag(key) {
const flag = this._flags[key];
this._recordAccess(key);
if (!flag) return;
if (!flag.enabled) return false;
return flag.variant ?? true;
}
getFlagPayload(key) {
return this._flags[key]?.payload;
}
onlyAccessed() {
const filtered = {};
for (const key of this._accessed){
const flag = this._flags[key];
if (flag) filtered[key] = flag;
}
return this._cloneWith(filtered);
}
only(keys) {
const filtered = {};
const missing = [];
for (const key of keys){
const flag = this._flags[key];
if (flag) filtered[key] = flag;
else missing.push(key);
}
if (missing.length > 0) this._host.logWarning(`FeatureFlagEvaluations.only() was called with flag keys that are not in the evaluation set and will be dropped: ${missing.join(', ')}`);
return this._cloneWith(filtered);
}
get keys() {
return Object.keys(this._flags);
}
_getEventProperties() {
const properties = {};
const activeFlags = [];
for (const [key, flag] of Object.entries(this._flags)){
const value = false === flag.enabled ? false : flag.variant ?? true;
properties[`$feature/${key}`] = value;
if (flag.enabled) activeFlags.push(key);
}
if (activeFlags.length > 0) {
activeFlags.sort();
properties['$active_feature_flags'] = activeFlags;
}
return properties;
}
_cloneWith(flags) {
return new FeatureFlagEvaluations({
host: this._host,
distinctId: this._distinctId,
groups: this._groups,
disableGeoip: this._disableGeoip,
flags,
requestId: this._requestId,
evaluatedAt: this._evaluatedAt,
flagDefinitionsLoadedAt: this._flagDefinitionsLoadedAt,
errorsWhileComputing: this._errorsWhileComputing,
quotaLimited: this._quotaLimited,
accessed: new Set(this._accessed),
isSlice: true
});
}
_recordAccess(key) {
this._accessed.add(key);
if ('' === this._distinctId) return;
if (this._isSlice && !(key in this._flags)) return;
const flag = this._flags[key];
const response = void 0 === flag ? void 0 : false === flag.enabled ? false : flag.variant ?? true;
const properties = {
$feature_flag: key,
$feature_flag_response: response,
$feature_flag_id: flag?.id,
$feature_flag_version: flag?.version,
$feature_flag_reason: flag?.reason,
locally_evaluated: flag?.locallyEvaluated ?? false,
[`$feature/${key}`]: response,
$feature_flag_request_id: this._requestId,
$feature_flag_evaluated_at: flag?.locallyEvaluated ? Date.now() : this._evaluatedAt
};
if (flag?.locallyEvaluated && void 0 !== this._flagDefinitionsLoadedAt) properties.$feature_flag_definitions_loaded_at = this._flagDefinitionsLoadedAt;
const errors = [];
if (this._errorsWhileComputing) errors.push(FeatureFlagError.ERRORS_WHILE_COMPUTING);
if (this._quotaLimited) errors.push(FeatureFlagError.QUOTA_LIMITED);
if (void 0 === flag) errors.push(FeatureFlagError.FLAG_MISSING);
if (errors.length > 0) properties.$feature_flag_error = errors.join(',');
this._host.captureFlagCalledEventIfNeeded({
distinctId: this._distinctId,
key,
response,
groups: this._groups,
disableGeoip: this._disableGeoip,
properties
});
}
}
export { FeatureFlagEvaluations };