UNPKG

vwo-fme-node-sdk

Version:

VWO Node/JavaScript SDK for Feature Management and Experimentation

396 lines 19.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getSettingsPath = getSettingsPath; exports.getTrackEventPath = getTrackEventPath; exports.getEventsBaseProperties = getEventsBaseProperties; exports._getEventBasePayload = _getEventBasePayload; exports.getTrackUserPayloadData = getTrackUserPayloadData; exports.getTrackGoalPayloadData = getTrackGoalPayloadData; exports.getAttributePayloadData = getAttributePayloadData; exports.sendPostApiRequest = sendPostApiRequest; exports.getShouldWaitForTrackingCalls = getShouldWaitForTrackingCalls; exports.setShouldWaitForTrackingCalls = setShouldWaitForTrackingCalls; exports.getMessagingEventPayload = getMessagingEventPayload; exports.sendMessagingEvent = sendMessagingEvent; /** * Copyright 2024-2025 Wingify Software Pvt. Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var FunctionUtil_1 = require("./FunctionUtil"); var UuidUtil_1 = require("./UuidUtil"); var constants_1 = require("../constants"); var HeadersEnum_1 = require("../enums/HeadersEnum"); var HttpMethodEnum_1 = require("../enums/HttpMethodEnum"); var UrlEnum_1 = require("../enums/UrlEnum"); var log_messages_1 = require("../enums/log-messages"); var logger_1 = require("../packages/logger"); var network_layer_1 = require("../packages/network-layer"); var SettingsService_1 = require("../services/SettingsService"); var DataTypeUtil_1 = require("./DataTypeUtil"); var LogMessageUtil_1 = require("./LogMessageUtil"); var UrlUtil_1 = require("./UrlUtil"); var PromiseUtil_1 = require("./PromiseUtil"); var Url_1 = require("../constants/Url"); var UsageStatsUtil_1 = require("./UsageStatsUtil"); /** * Constructs the settings path with API key and account ID. * @param {string} sdkKey - The API key. * @param {any} accountId - The account identifier. * @returns {Record<string, dynamic>} - The settings path including API key, random number, and account ID. */ function getSettingsPath(sdkKey, accountId) { var path = { i: "".concat(sdkKey), // Inject API key r: Math.random(), // Random number for cache busting a: accountId, // Account ID }; return path; } /** * Constructs the tracking path for an event. * @param {string} event - The event type. * @param {string} accountId - The account identifier. * @param {string} userId - The user identifier. * @returns {Record<string, dynamic>} - The tracking path for the event. */ function getTrackEventPath(event, accountId, userId) { var path = { event_type: event, // Type of the event account_id: accountId, // Account ID uId: userId, // User ID u: (0, UuidUtil_1.getUUID)(userId, accountId), // UUID generated for the user sdk: constants_1.Constants.SDK_NAME, // SDK name constant 'sdk-v': constants_1.Constants.SDK_VERSION, // SDK version random: (0, FunctionUtil_1.getRandomNumber)(), // Random number for uniqueness ap: constants_1.Constants.PLATFORM, // Application platform sId: (0, FunctionUtil_1.getCurrentUnixTimestamp)(), // Session ID ed: JSON.stringify({ p: 'server' }), // Additional encoded data }; return path; } /** * Builds generic properties for different tracking calls required by VWO servers. * @param {Object} configObj * @param {String} eventName * @returns properties */ function getEventsBaseProperties(eventName, visitorUserAgent, ipAddress) { if (visitorUserAgent === void 0) { visitorUserAgent = ''; } if (ipAddress === void 0) { ipAddress = ''; } var sdkKey = SettingsService_1.SettingsService.Instance.sdkKey; var properties = Object.assign({ en: eventName, a: SettingsService_1.SettingsService.Instance.accountId, env: sdkKey, eTime: (0, FunctionUtil_1.getCurrentUnixTimestampInMillis)(), random: (0, FunctionUtil_1.getRandomNumber)(), p: 'FS', visitor_ua: visitorUserAgent, visitor_ip: ipAddress, }); properties.url = constants_1.Constants.HTTPS_PROTOCOL + UrlUtil_1.UrlUtil.getBaseUrl() + UrlEnum_1.UrlEnum.EVENTS; return properties; } /** * Builds generic payload required by all the different tracking calls. * @param {Object} settings settings file * @param {String} userId user id * @param {String} eventName event name * @returns properties */ function _getEventBasePayload(settings, userId, eventName, visitorUserAgent, ipAddress) { if (visitorUserAgent === void 0) { visitorUserAgent = ''; } if (ipAddress === void 0) { ipAddress = ''; } var uuid = (0, UuidUtil_1.getUUID)(userId.toString(), SettingsService_1.SettingsService.Instance.accountId.toString()); var sdkKey = SettingsService_1.SettingsService.Instance.sdkKey; var props = { vwo_sdkName: constants_1.Constants.SDK_NAME, vwo_sdkVersion: constants_1.Constants.SDK_VERSION, vwo_envKey: sdkKey, }; var properties = { d: { msgId: "".concat(uuid, "-").concat((0, FunctionUtil_1.getCurrentUnixTimestampInMillis)()), visId: uuid, sessionId: (0, FunctionUtil_1.getCurrentUnixTimestamp)(), visitor_ua: visitorUserAgent, visitor_ip: ipAddress, event: { props: props, name: eventName, time: (0, FunctionUtil_1.getCurrentUnixTimestampInMillis)(), }, visitor: { props: { vwo_fs_environment: sdkKey, }, }, }, }; return properties; } /** * Builds payload to track the visitor. * @param {Object} configObj * @param {String} userId * @param {String} eventName * @param {String} campaignId * @param {Number} variationId * @returns track-user payload */ function getTrackUserPayloadData(settings, userId, eventName, campaignId, variationId, visitorUserAgent, ipAddress) { if (visitorUserAgent === void 0) { visitorUserAgent = ''; } if (ipAddress === void 0) { ipAddress = ''; } var properties = _getEventBasePayload(settings, userId, eventName, visitorUserAgent, ipAddress); properties.d.event.props.id = campaignId; properties.d.event.props.variation = variationId; properties.d.event.props.isFirst = 1; // add usageStats as a new meta key to properties.d.events.props.vwoMeta if (Object.keys(UsageStatsUtil_1.UsageStatsUtil.getInstance().getUsageStats()).length > 0) { properties.d.event.props.vwoMeta = UsageStatsUtil_1.UsageStatsUtil.getInstance().getUsageStats(); } logger_1.LogManager.Instance.debug((0, LogMessageUtil_1.buildMessage)(log_messages_1.DebugLogMessagesEnum.IMPRESSION_FOR_TRACK_USER, { accountId: settings.getAccountId(), userId: userId, campaignId: campaignId, })); return properties; } /** * Constructs the payload data for tracking goals with custom event properties. * @param {any} settings - Configuration settings. * @param {any} userId - User identifier. * @param {string} eventName - Name of the event. * @param {any} eventProperties - Custom properties for the event. * @param {string} [visitorUserAgent=''] - Visitor's user agent. * @param {string} [ipAddress=''] - Visitor's IP address. * @returns {any} - The constructed payload data. */ function getTrackGoalPayloadData(settings, userId, eventName, eventProperties, visitorUserAgent, ipAddress) { if (visitorUserAgent === void 0) { visitorUserAgent = ''; } if (ipAddress === void 0) { ipAddress = ''; } var properties = _getEventBasePayload(settings, userId, eventName, visitorUserAgent, ipAddress); properties.d.event.props.isCustomEvent = true; // Mark as a custom event properties.d.event.props.variation = 1; // Temporary value for variation properties.d.event.props.id = 1; // Temporary value for ID // Add custom event properties if provided if (eventProperties && (0, DataTypeUtil_1.isObject)(eventProperties) && Object.keys(eventProperties).length > 0) { for (var prop in eventProperties) { properties.d.event.props[prop] = eventProperties[prop]; } } logger_1.LogManager.Instance.debug((0, LogMessageUtil_1.buildMessage)(log_messages_1.DebugLogMessagesEnum.IMPRESSION_FOR_TRACK_GOAL, { eventName: eventName, accountId: settings.getAccountId(), userId: userId, })); return properties; } /** * Constructs the payload data for syncing multiple visitor attributes. * @param {SettingsModel} settings - Configuration settings. * @param {string | number} userId - User ID. * @param {string} eventName - Event name. * @param {Record<string, any>} attributes - Key-value map of attributes. * @param {string} [visitorUserAgent=''] - Visitor's User-Agent (optional). * @param {string} [ipAddress=''] - Visitor's IP Address (optional). * @returns {Record<string, any>} - Payload object to be sent in the request. */ function getAttributePayloadData(settings, userId, eventName, attributes, visitorUserAgent, ipAddress) { if (visitorUserAgent === void 0) { visitorUserAgent = ''; } if (ipAddress === void 0) { ipAddress = ''; } var properties = _getEventBasePayload(settings, userId, eventName, visitorUserAgent, ipAddress); properties.d.event.props.isCustomEvent = true; // Mark as a custom event properties.d.event.props[constants_1.Constants.VWO_FS_ENVIRONMENT] = settings.getSdkkey(); // Set environment key // Iterate over the attributes map and append to the visitor properties for (var _i = 0, _a = Object.entries(attributes); _i < _a.length; _i++) { var _b = _a[_i], key = _b[0], value = _b[1]; properties.d.visitor.props[key] = value; } logger_1.LogManager.Instance.debug((0, LogMessageUtil_1.buildMessage)(log_messages_1.DebugLogMessagesEnum.IMPRESSION_FOR_SYNC_VISITOR_PROP, { eventName: eventName, accountId: settings.getAccountId(), userId: userId, })); return properties; } /** * Sends a POST API request with the specified properties and payload. * @param {any} properties - Properties for the request. * @param {any} payload - Payload for the request. * @param {string} userId - User ID. */ function sendPostApiRequest(properties, payload, userId) { return __awaiter(this, void 0, void 0, function () { var networkManager, retryConfig, headers, userAgent, ipAddress, baseUrl, request; return __generator(this, function (_a) { switch (_a.label) { case 0: networkManager = network_layer_1.NetworkManager.Instance; networkManager.attachClient(); retryConfig = networkManager.getRetryConfig(); headers = {}; userAgent = payload.d.visitor_ua; ipAddress = payload.d.visitor_ip; // Set headers if available if (userAgent) headers[HeadersEnum_1.HeadersEnum.USER_AGENT] = userAgent; if (ipAddress) headers[HeadersEnum_1.HeadersEnum.IP] = ipAddress; baseUrl = UrlUtil_1.UrlUtil.getBaseUrl(); baseUrl = UrlUtil_1.UrlUtil.getUpdatedBaseUrl(baseUrl); request = new network_layer_1.RequestModel(baseUrl, HttpMethodEnum_1.HttpMethodEnum.POST, UrlEnum_1.UrlEnum.EVENTS, properties, payload, headers, SettingsService_1.SettingsService.Instance.protocol, SettingsService_1.SettingsService.Instance.port, retryConfig); return [4 /*yield*/, network_layer_1.NetworkManager.Instance.post(request) .then(function () { // clear usage stats only if network call is successful if (Object.keys(UsageStatsUtil_1.UsageStatsUtil.getInstance().getUsageStats()).length > 0) { UsageStatsUtil_1.UsageStatsUtil.getInstance().clearUsageStats(); } logger_1.LogManager.Instance.info((0, LogMessageUtil_1.buildMessage)(log_messages_1.InfoLogMessagesEnum.NETWORK_CALL_SUCCESS, { event: properties.en, endPoint: UrlEnum_1.UrlEnum.EVENTS, accountId: SettingsService_1.SettingsService.Instance.accountId, userId: userId, uuid: payload.d.visId, })); }) .catch(function (err) { logger_1.LogManager.Instance.error((0, LogMessageUtil_1.buildMessage)(log_messages_1.ErrorLogMessagesEnum.NETWORK_CALL_FAILED, { method: HttpMethodEnum_1.HttpMethodEnum.POST, err: (0, DataTypeUtil_1.isObject)(err) ? JSON.stringify(err) : err, })); })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); } // Flag to determine if the SDK should wait for a network response. var shouldWaitForTrackingCalls = false; /** * Checks if the SDK should wait for a network response. * @returns {boolean} - True if the SDK should wait for a network response, false otherwise. */ function getShouldWaitForTrackingCalls() { return shouldWaitForTrackingCalls; } /** * Sets the value to determine if the SDK should wait for a network response. * @param value - The value to set. */ function setShouldWaitForTrackingCalls(value) { shouldWaitForTrackingCalls = value; } /** * Constructs the payload for a messaging event. * @param messageType - The type of the message. * @param message - The message to send. * @param eventName - The name of the event. * @returns The constructed payload. */ function getMessagingEventPayload(messageType, message, eventName) { var userId = SettingsService_1.SettingsService.Instance.accountId + '_' + SettingsService_1.SettingsService.Instance.sdkKey; var properties = _getEventBasePayload(null, userId, eventName, null, null); properties.d.event.props[constants_1.Constants.VWO_FS_ENVIRONMENT] = SettingsService_1.SettingsService.Instance.sdkKey; // Set environment key properties.d.event.props.product = 'fme'; var data = { type: messageType, content: { title: message, dateTime: (0, FunctionUtil_1.getCurrentUnixTimestampInMillis)(), }, }; properties.d.event.props.data = data; return properties; } /** * Sends a messaging event to DACDN * @param properties - Query parameters for the request. * @param payload - The payload for the request. * @returns A promise that resolves to the response from DACDN. */ function sendMessagingEvent(properties, payload) { return __awaiter(this, void 0, void 0, function () { var deferredObject, networkInstance, retryConfig, baseUrl, request; return __generator(this, function (_a) { deferredObject = new PromiseUtil_1.Deferred(); networkInstance = network_layer_1.NetworkManager.Instance; retryConfig = networkInstance.getRetryConfig(); // disable retry for messaging event retryConfig.shouldRetry = false; baseUrl = UrlUtil_1.UrlUtil.getBaseUrl(); baseUrl = UrlUtil_1.UrlUtil.getUpdatedBaseUrl(baseUrl); try { request = new network_layer_1.RequestModel(baseUrl, HttpMethodEnum_1.HttpMethodEnum.POST, UrlEnum_1.UrlEnum.EVENTS, properties, payload, null, Url_1.HTTPS, null, retryConfig); // Perform the network GET request networkInstance .post(request) .then(function (response) { // Resolve the deferred object with the data from the response deferredObject.resolve(response.getData()); }) .catch(function (err) { // Reject the deferred object with the error response deferredObject.reject(err); }); return [2 /*return*/, deferredObject.promise]; } catch (err) { // Resolve the promise with false as fallback deferredObject.resolve(false); return [2 /*return*/, deferredObject.promise]; } return [2 /*return*/]; }); }); } //# sourceMappingURL=NetworkUtil.js.map