services/FeatureFlagService.jsjavascript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeatureFlagKey = void 0;
const winston_1 = __importDefault(require("../plugins/winston.js"));
const unleash_client_1 = require("unleash-client");
/**
* Keys for available feature flags used by the application.
*/
var FeatureFlagKey;
(function (FeatureFlagKey) {
FeatureFlagKey["MOBILE_EDITING"] = "mobile-editing";
FeatureFlagKey["SOCIAL_LOGIN"] = "social-login";
FeatureFlagKey["ACCESS_SHARING"] = "access-sharing";
})(FeatureFlagKey || (exports.FeatureFlagKey = FeatureFlagKey = {}));
/**
* Service responsible for initializing and querying feature flags.
*
* This service initializes the client once and exposes helper
* methods to validate configuration and to read feature flag values.
*/
class FeatureFlagService {
initialization;
unleash;
_ready = false;
/**
* Create a new FeatureFlagService and start initialization.
* The `initialization` promise resolves when the client emits
* the `synchronized` event.
*/
constructor() {
this.unleash = {}; // only for type safety
if (!process.env.UNLEASH_API_KEY) {
this._ready = false;
this.initialization = Promise.resolve();
return;
}
this.initialization = new Promise((resolve) => {
this.unleash = (0, unleash_client_1.initialize)({
url: "https://features.choreo-planer.de/api",
appName: "choreo-planer-server",
customHeaders: {
Authorization: process.env.UNLEASH_API_KEY ?? "",
},
});
this.unleash.on("synchronized", () => {
this._ready = true;
resolve();
});
});
}
isConfigured() {
return !!process.env.UNLEASH_API_KEY;
}
isReady() {
return this._ready;
}
/**
* Check whether a feature flag is enabled.
*
* Waits for the client to finish initialization before querying.
* Returns `false` when feature flags are not configured.
*
* @param {FeatureFlagKey} flagName - The feature flag key to check.
* @returns {Promise<boolean>} True if the flag is enabled; otherwise false.
*/
async isEnabled(flagName) {
if (!this.isConfigured()) {
winston_1.default.warn(`FeatureFlagService.isEnabled "${flagName}" — UNLEASH_API_KEY not set, returning false`);
return false;
}
winston_1.default.debug(`FeatureFlagService.isEnabled "${flagName}"`);
await this.initialization;
const result = this.unleash.isEnabled(flagName);
winston_1.default.debug(`Feature flag "${flagName}" is ${result ? "enabled" : "disabled"}`);
return result;
}
/**
* Retrieve all feature flag definitions.
*
* Filters out stale flags and returns an array of simplified flag states.
* Returns an empty array when feature flags are not configured.
*
* @returns {Promise<Array<{name: string, enabled: boolean}>>}
* Array of feature flag states.
*/
async getAll() {
if (!this.isConfigured()) {
winston_1.default.warn("FeatureFlagService.getAll — UNLEASH_API_KEY not set, returning empty array");
return [];
}
winston_1.default.debug(`FeatureFlagService.getAll`);
await this.initialization;
const result = this.unleash.getFeatureToggleDefinitions();
winston_1.default.debug(`Feature Flags: ${JSON.stringify(result)}`);
return result.map(({ name, enabled, stale, description }) => ({
name,
enabled: enabled && !stale,
description: description || name,
}));
}
}
exports.default = new FeatureFlagService();