UNPKG

unleash-server

Version:

Unleash is an enterprise ready feature toggles service. It provides different strategies for handling feature toggles.

148 lines 6.17 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const memoizee_1 = __importDefault(require("memoizee")); const controller_1 = __importDefault(require("../controller")); const feature_schema_1 = require("../../schema/feature-schema"); const notfound_error_1 = __importDefault(require("../../error/notfound-error")); const api_user_1 = __importDefault(require("../../types/api-user")); const api_token_1 = require("../../types/models/api-token"); const permissions_1 = require("../../types/permissions"); const create_response_schema_1 = require("../../openapi/util/create-response-schema"); const client_feature_schema_1 = require("../../openapi/spec/client-feature-schema"); const client_features_schema_1 = require("../../openapi/spec/client-features-schema"); const version = 2; class FeatureController extends controller_1.default { constructor({ featureToggleServiceV2, segmentService, clientSpecService, openApiService, }, config) { super(config); const { clientFeatureCaching } = config; this.featureToggleServiceV2 = featureToggleServiceV2; this.segmentService = segmentService; this.clientSpecService = clientSpecService; this.openApiService = openApiService; this.logger = config.getLogger('client-api/feature.js'); this.route({ method: 'get', path: '/:featureName', handler: this.getFeatureToggle, permission: permissions_1.NONE, middleware: [ openApiService.validPath({ operationId: 'getClientFeature', tags: ['Client'], responses: { 200: (0, create_response_schema_1.createResponseSchema)('clientFeaturesSchema'), }, }), ], }); this.route({ method: 'get', path: '', handler: this.getAll, permission: permissions_1.NONE, middleware: [ openApiService.validPath({ operationId: 'getAllClientFeatures', tags: ['Client'], responses: { 200: (0, create_response_schema_1.createResponseSchema)('clientFeaturesSchema'), }, }), ], }); if (clientFeatureCaching?.enabled) { this.cache = true; this.cachedFeatures = (0, memoizee_1.default)((query) => this.resolveFeaturesAndSegments(query), { promise: true, maxAge: clientFeatureCaching.maxAge, normalizer(args) { // args is arguments object as accessible in memoized function return JSON.stringify(args[0]); }, }); } } async resolveFeaturesAndSegments(query) { return Promise.all([ this.featureToggleServiceV2.getClientFeatures(query), this.segmentService.getActive(), ]); } async resolveQuery(req) { const { user, query } = req; const override = {}; if (user instanceof api_user_1.default) { if (!(0, api_token_1.isAllProjects)(user.projects)) { override.project = user.projects; } if (user.environment !== api_token_1.ALL) { override.environment = user.environment; } } const inlineSegmentConstraints = !this.clientSpecService.requestSupportsSpec(req, 'segments'); return this.prepQuery({ ...query, ...override, inlineSegmentConstraints, }); } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types paramToArray(param) { if (!param) { return param; } return Array.isArray(param) ? param : [param]; } async prepQuery({ tag, project, namePrefix, environment, inlineSegmentConstraints, }) { if (!tag && !project && !namePrefix && !environment && !inlineSegmentConstraints) { return null; } const tagQuery = this.paramToArray(tag); const projectQuery = this.paramToArray(project); const query = await feature_schema_1.querySchema.validateAsync({ tag: tagQuery, project: projectQuery, namePrefix, environment, inlineSegmentConstraints, }); if (query.tag) { query.tag = query.tag.map((q) => q.split(':')); } return query; } async getAll(req, res) { const query = await this.resolveQuery(req); const [features, segments] = this.cache ? await this.cachedFeatures(query) : await this.resolveFeaturesAndSegments(query); if (this.clientSpecService.requestSupportsSpec(req, 'segments')) { this.openApiService.respondWithValidation(200, res, client_features_schema_1.clientFeaturesSchema.$id, { version, features, query: { ...query }, segments }); } else { this.openApiService.respondWithValidation(200, res, client_features_schema_1.clientFeaturesSchema.$id, { version, features, query }); } } async getFeatureToggle(req, res) { const name = req.params.featureName; const featureQuery = await this.resolveQuery(req); const q = { ...featureQuery, namePrefix: name }; const toggles = await this.featureToggleServiceV2.getClientFeatures(q); const toggle = toggles.find((t) => t.name === name); if (!toggle) { throw new notfound_error_1.default(`Could not find feature toggle ${name}`); } this.openApiService.respondWithValidation(200, res, client_feature_schema_1.clientFeatureSchema.$id, { ...toggle, }); } } exports.default = FeatureController; //# sourceMappingURL=feature.js.map