UNPKG

@devcycle/js-cloud-server-sdk

Version:

The DevCycle JS Cloud Bucketing Server SDK used for feature management.

169 lines 7.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DevCycleCloudClient = void 0; const variable_1 = require("./models/variable"); const paramUtils_1 = require("./utils/paramUtils"); const logger_1 = require("./utils/logger"); const populatedUser_1 = require("./models/populatedUser"); const types_1 = require("@devcycle/types"); const request_1 = require("./request"); const user_1 = require("./models/user"); const server_request_1 = require("../server-request/src"); const EvalHooksRunner_1 = require("./hooks/EvalHooksRunner"); const castIncomingUser = (user) => { if (!(user instanceof user_1.DevCycleUser)) { return new user_1.DevCycleUser(user); } return user; }; /** * Handle response errors from API * Suppress 5xx errors and log them instead while returning defaults to the caller * Throw 4XX errors back to the caller to notify of invalid SDK usage * Special handling of 404 error, which indicates "variable not found" * @param err */ const throwIfUserError = (err) => { if (err instanceof server_request_1.ResponseError) { const code = err.status; // throw the error if it indicates there was user error in this call // (e.g. invalid auth credentials or bad user data) if (code !== 404 && code < 500) { throw new Error(`DevCycle request failed with status ${code}. ${err.message || ''}`); } // Catch non-4xx errors so we can log them instead return; } if (err instanceof SyntaxError) { // JSON parse error, log instead of throwing return; } // if not a ResponseError, throw it throw err; }; class DevCycleCloudClient { constructor(sdkKey, options, platformDetails) { this.sdkKey = sdkKey; this.logger = options.logger || (0, logger_1.dvcDefaultLogger)({ level: options.logLevel }); this.options = options; this.platformDetails = platformDetails; this.hooksRunner = new EvalHooksRunner_1.EvalHooksRunner(options.hooks); this.logger.info('Running DevCycle NodeJS SDK in Cloud Bucketing mode'); } /** * Always returns true for Cloud Client because once the client is created, * it is initialized as all request are async to the API. */ get isInitialized() { return true; } async variable(user, key, defaultValue) { return this.hooksRunner.runHooksForEvaluation(user, key, defaultValue, {}, async (context) => { var _a; return this._variable((_a = context === null || context === void 0 ? void 0 : context.user) !== null && _a !== void 0 ? _a : user, key, defaultValue); }); } async _variable(user, key, defaultValue) { const incomingUser = castIncomingUser(user); const populatedUser = populatedUser_1.DVCPopulatedUser.fromDVCUser(incomingUser, this.platformDetails); (0, paramUtils_1.checkParamDefined)('key', key); (0, paramUtils_1.checkParamDefined)('defaultValue', defaultValue); const type = (0, types_1.getVariableTypeFromValue)(defaultValue, key, this.logger, true); try { const res = await (0, request_1.getVariable)(populatedUser, this.sdkKey, key, this.options); const variableResponse = await res.json(); if (variableResponse.type !== type) { this.logger.error(`Type mismatch for variable ${key}. Expected ${type}, got ${variableResponse.type}`); // Default Variable return new variable_1.DVCVariable({ key, type, defaultValue, eval: { reason: types_1.EVAL_REASONS.DEFAULT, details: types_1.DEFAULT_REASON_DETAILS.TYPE_MISMATCH, }, }); } return new variable_1.DVCVariable({ key, type, defaultValue, value: variableResponse.value, eval: variableResponse.eval, }); } catch (err) { throwIfUserError(err); if (err instanceof server_request_1.ResponseError && err.status !== 404) { this.logger.error(`Request to get variable: ${key} failed with response message: ${err.message}`); } // Default Variable return new variable_1.DVCVariable({ key, type, defaultValue, eval: { reason: types_1.EVAL_REASONS.DEFAULT, details: types_1.DEFAULT_REASON_DETAILS.ERROR, }, }); } } async variableValue(user, key, defaultValue) { return (await this.variable(user, key, defaultValue)).value; } async allVariables(user) { const incomingUser = castIncomingUser(user); const populatedUser = populatedUser_1.DVCPopulatedUser.fromDVCUser(incomingUser, this.platformDetails); try { const res = await (0, request_1.getAllVariables)(populatedUser, this.sdkKey, this.options); const variablesResponse = await res.json(); return (variablesResponse || {}); } catch (err) { throwIfUserError(err); this.logger.error(`Request to get all variable failed with response message: ${err.message}`); return {}; } } async allFeatures(user) { const incomingUser = castIncomingUser(user); const populatedUser = populatedUser_1.DVCPopulatedUser.fromDVCUser(incomingUser, this.platformDetails); try { const res = await (0, request_1.getAllFeatures)(populatedUser, this.sdkKey, this.options); const featuresResponse = await res.json(); return (featuresResponse || {}); } catch (err) { throwIfUserError(err); this.logger.error(`Request to get all features failed with response message: ${err.message}`); return {}; } } async track(user, event) { const incomingUser = castIncomingUser(user); if (event === undefined || event === null || typeof event.type !== 'string' || event.type.length === 0) { throw new Error('Invalid Event'); } (0, paramUtils_1.checkParamDefined)('type', event.type); const populatedUser = populatedUser_1.DVCPopulatedUser.fromDVCUser(incomingUser, this.platformDetails); try { await (0, request_1.postTrack)(populatedUser, event, this.sdkKey, this.options); this.logger.debug('DVC Event Tracked'); } catch (err) { throwIfUserError(err); this.logger.error(`DVC Error Tracking Event. Response message: ${err.message}`); } } async addHook(hook) { this.hooksRunner.enqueue(hook); } async clearHooks() { this.hooksRunner.clear(); } } exports.DevCycleCloudClient = DevCycleCloudClient; //# sourceMappingURL=cloudClient.js.map