UNPKG

@optimizely/optimizely-sdk

Version:
1,497 lines (1,415 loc) 316 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.optimizelySdk = {})); }(this, (function (exports) { 'use strict'; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var errorHandler = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @export * @class NoopErrorHandler * @implements {ErrorHandler} */ var NoopErrorHandler = /** @class */ (function () { function NoopErrorHandler() { } /** * @param {Error} exception * @memberof NoopErrorHandler */ NoopErrorHandler.prototype.handleError = function (exception) { // no-op return; }; return NoopErrorHandler; }()); exports.NoopErrorHandler = NoopErrorHandler; var globalErrorHandler = new NoopErrorHandler(); /** * @export * @param {ErrorHandler} handler */ function setErrorHandler(handler) { globalErrorHandler = handler; } exports.setErrorHandler = setErrorHandler; /** * @export * @returns {ErrorHandler} */ function getErrorHandler() { return globalErrorHandler; } exports.getErrorHandler = getErrorHandler; /** * @export */ function resetErrorHandler() { globalErrorHandler = new NoopErrorHandler(); } exports.resetErrorHandler = resetErrorHandler; }); unwrapExports(errorHandler); var errorHandler_1 = errorHandler.NoopErrorHandler; var errorHandler_2 = errorHandler.setErrorHandler; var errorHandler_3 = errorHandler.getErrorHandler; var errorHandler_4 = errorHandler.resetErrorHandler; var models = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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 LogLevel; (function (LogLevel) { LogLevel[LogLevel["NOTSET"] = 0] = "NOTSET"; LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG"; LogLevel[LogLevel["INFO"] = 2] = "INFO"; LogLevel[LogLevel["WARNING"] = 3] = "WARNING"; LogLevel[LogLevel["ERROR"] = 4] = "ERROR"; })(LogLevel = exports.LogLevel || (exports.LogLevel = {})); }); unwrapExports(models); var models_1 = models.LogLevel; var rngBrowser = createCommonjsModule(function (module) { // Unique ID creation requires a high quality random # generator. In the // browser this is a little complicated due to unknown quality of Math.random() // and inconsistent support for the `crypto` API. We do the best we can via // feature-detection // getRandomValues needs to be invoked in a context where "this" is a Crypto // implementation. Also, find the complete implementation of crypto on IE11. var getRandomValues = (typeof(crypto) != 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto)) || (typeof(msCrypto) != 'undefined' && typeof window.msCrypto.getRandomValues == 'function' && msCrypto.getRandomValues.bind(msCrypto)); if (getRandomValues) { // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto var rnds8 = new Uint8Array(16); // eslint-disable-line no-undef module.exports = function whatwgRNG() { getRandomValues(rnds8); return rnds8; }; } else { // Math.random()-based (RNG) // // If all else fails, use Math.random(). It's fast, but is of unspecified // quality. var rnds = new Array(16); module.exports = function mathRNG() { for (var i = 0, r; i < 16; i++) { if ((i & 0x03) === 0) r = Math.random() * 0x100000000; rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; } return rnds; }; } }); /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ var byteToHex = []; for (var i = 0; i < 256; ++i) { byteToHex[i] = (i + 0x100).toString(16).substr(1); } function bytesToUuid(buf, offset) { var i = offset || 0; var bth = byteToHex; // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4 return ([bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], '-', bth[buf[i++]], bth[buf[i++]], '-', bth[buf[i++]], bth[buf[i++]], '-', bth[buf[i++]], bth[buf[i++]], '-', bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], bth[buf[i++]], bth[buf[i++]]]).join(''); } var bytesToUuid_1 = bytesToUuid; // **`v1()` - Generate time-based UUID** // // Inspired by https://github.com/LiosK/UUID.js // and http://docs.python.org/library/uuid.html var _nodeId; var _clockseq; // Previous uuid creation time var _lastMSecs = 0; var _lastNSecs = 0; // See https://github.com/broofa/node-uuid for API details function v1(options, buf, offset) { var i = buf && offset || 0; var b = buf || []; options = options || {}; var node = options.node || _nodeId; var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not // specified. We do this lazily to minimize issues related to insufficient // system entropy. See #189 if (node == null || clockseq == null) { var seedBytes = rngBrowser(); if (node == null) { // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) node = _nodeId = [ seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5] ]; } if (clockseq == null) { // Per 4.2.2, randomize (14 bit) clockseq clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; } } // UUID timestamps are 100 nano-second units since the Gregorian epoch, // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime(); // Per 4.2.1.2, use count of uuid's generated during the current clock // cycle to simulate higher resolution clock var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000; // Per 4.2.1.2, Bump clockseq on clock regression if (dt < 0 && options.clockseq === undefined) { clockseq = clockseq + 1 & 0x3fff; } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new // time interval if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { nsecs = 0; } // Per 4.2.1.2 Throw error if too many uuids are requested if (nsecs >= 10000) { throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec'); } _lastMSecs = msecs; _lastNSecs = nsecs; _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch msecs += 12219292800000; // `time_low` var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; b[i++] = tl >>> 24 & 0xff; b[i++] = tl >>> 16 & 0xff; b[i++] = tl >>> 8 & 0xff; b[i++] = tl & 0xff; // `time_mid` var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; b[i++] = tmh >>> 8 & 0xff; b[i++] = tmh & 0xff; // `time_high_and_version` b[i++] = tmh >>> 24 & 0xf | 0x10; // include version b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` b[i++] = clockseq & 0xff; // `node` for (var n = 0; n < 6; ++n) { b[i + n] = node[n]; } return buf ? buf : bytesToUuid_1(b); } var v1_1 = v1; function v4(options, buf, offset) { var i = buf && offset || 0; if (typeof(options) == 'string') { buf = options === 'binary' ? new Array(16) : null; options = null; } options = options || {}; var rnds = options.random || (options.rng || rngBrowser)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` rnds[6] = (rnds[6] & 0x0f) | 0x40; rnds[8] = (rnds[8] & 0x3f) | 0x80; // Copy bytes to buffer, if provided if (buf) { for (var ii = 0; ii < 16; ++ii) { buf[i + ii] = rnds[ii]; } } return buf || bytesToUuid_1(rnds); } var v4_1 = v4; var uuid = v4_1; uuid.v1 = v1_1; uuid.v4 = v4_1; var uuid_1 = uuid; var lib = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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. */ function getTimestamp() { return new Date().getTime(); } exports.getTimestamp = getTimestamp; function generateUUID() { return uuid_1.v4(); } exports.generateUUID = generateUUID; /** * Validates a value is a valid TypeScript enum * * @export * @param {object} enumToCheck * @param {*} value * @returns {boolean} */ function isValidEnum(enumToCheck, value) { var found = false; var keys = Object.keys(enumToCheck); for (var index = 0; index < keys.length; index++) { if (value === enumToCheck[keys[index]]) { found = true; break; } } return found; } exports.isValidEnum = isValidEnum; function groupBy(arr, grouperFn) { var grouper = {}; arr.forEach(function (item) { var key = grouperFn(item); grouper[key] = grouper[key] || []; grouper[key].push(item); }); return objectValues(grouper); } exports.groupBy = groupBy; function objectValues(obj) { return Object.keys(obj).map(function (key) { return obj[key]; }); } exports.objectValues = objectValues; function find(arr, cond) { var found; for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) { var item = arr_1[_i]; if (cond(item)) { found = item; break; } } return found; } exports.find = find; function keyBy(arr, keyByFn) { var map = {}; arr.forEach(function (item) { var key = keyByFn(item); map[key] = item; }); return map; } exports.keyBy = keyBy; function sprintf(format) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var i = 0; return format.replace(/%s/g, function () { var arg = args[i++]; var type = typeof arg; if (type === 'function') { return arg(); } else if (type === 'string') { return arg; } else { return String(arg); } }); } exports.sprintf = sprintf; }); unwrapExports(lib); var lib_1 = lib.getTimestamp; var lib_2 = lib.generateUUID; var lib_3 = lib.isValidEnum; var lib_4 = lib.groupBy; var lib_5 = lib.objectValues; var lib_6 = lib.find; var lib_7 = lib.keyBy; var lib_8 = lib.sprintf; var logger = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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 stringToLogLevel = { NOTSET: 0, DEBUG: 1, INFO: 2, WARNING: 3, ERROR: 4, }; function coerceLogLevel(level) { if (typeof level !== 'string') { return level; } level = level.toUpperCase(); if (level === 'WARN') { level = 'WARNING'; } if (!stringToLogLevel[level]) { return level; } return stringToLogLevel[level]; } var DefaultLogManager = /** @class */ (function () { function DefaultLogManager() { this.defaultLoggerFacade = new OptimizelyLogger(); this.loggers = {}; } DefaultLogManager.prototype.getLogger = function (name) { if (!name) { return this.defaultLoggerFacade; } if (!this.loggers[name]) { this.loggers[name] = new OptimizelyLogger({ messagePrefix: name }); } return this.loggers[name]; }; return DefaultLogManager; }()); var ConsoleLogHandler = /** @class */ (function () { /** * Creates an instance of ConsoleLogger. * @param {ConsoleLogHandlerConfig} config * @memberof ConsoleLogger */ function ConsoleLogHandler(config) { if (config === void 0) { config = {}; } this.logLevel = models.LogLevel.NOTSET; if (config.logLevel !== undefined && lib.isValidEnum(models.LogLevel, config.logLevel)) { this.setLogLevel(config.logLevel); } this.logToConsole = config.logToConsole !== undefined ? !!config.logToConsole : true; this.prefix = config.prefix !== undefined ? config.prefix : '[OPTIMIZELY]'; } /** * @param {LogLevel} level * @param {string} message * @memberof ConsoleLogger */ ConsoleLogHandler.prototype.log = function (level, message) { if (!this.shouldLog(level) || !this.logToConsole) { return; } var logMessage = this.prefix + " - " + this.getLogLevelName(level) + " " + this.getTime() + " " + message; this.consoleLog(level, [logMessage]); }; /** * @param {LogLevel} level * @memberof ConsoleLogger */ ConsoleLogHandler.prototype.setLogLevel = function (level) { level = coerceLogLevel(level); if (!lib.isValidEnum(models.LogLevel, level) || level === undefined) { this.logLevel = models.LogLevel.ERROR; } else { this.logLevel = level; } }; /** * @returns {string} * @memberof ConsoleLogger */ ConsoleLogHandler.prototype.getTime = function () { return new Date().toISOString(); }; /** * @private * @param {LogLevel} targetLogLevel * @returns {boolean} * @memberof ConsoleLogger */ ConsoleLogHandler.prototype.shouldLog = function (targetLogLevel) { return targetLogLevel >= this.logLevel; }; /** * @private * @param {LogLevel} logLevel * @returns {string} * @memberof ConsoleLogger */ ConsoleLogHandler.prototype.getLogLevelName = function (logLevel) { switch (logLevel) { case models.LogLevel.DEBUG: return 'DEBUG'; case models.LogLevel.INFO: return 'INFO '; case models.LogLevel.WARNING: return 'WARN '; case models.LogLevel.ERROR: return 'ERROR'; default: return 'NOTSET'; } }; /** * @private * @param {LogLevel} logLevel * @param {string[]} logArguments * @memberof ConsoleLogger */ ConsoleLogHandler.prototype.consoleLog = function (logLevel, logArguments) { switch (logLevel) { case models.LogLevel.DEBUG: console.log.apply(console, logArguments); break; case models.LogLevel.INFO: console.info.apply(console, logArguments); break; case models.LogLevel.WARNING: console.warn.apply(console, logArguments); break; case models.LogLevel.ERROR: console.error.apply(console, logArguments); break; default: console.log.apply(console, logArguments); } }; return ConsoleLogHandler; }()); exports.ConsoleLogHandler = ConsoleLogHandler; var globalLogLevel = models.LogLevel.NOTSET; var globalLogHandler = null; var OptimizelyLogger = /** @class */ (function () { function OptimizelyLogger(opts) { if (opts === void 0) { opts = {}; } this.messagePrefix = ''; if (opts.messagePrefix) { this.messagePrefix = opts.messagePrefix; } } /** * @param {(LogLevel | LogInputObject)} levelOrObj * @param {string} [message] * @memberof OptimizelyLogger */ OptimizelyLogger.prototype.log = function (level, message) { this.internalLog(coerceLogLevel(level), { message: message, splat: [], }); }; OptimizelyLogger.prototype.info = function (message) { var splat = []; for (var _i = 1; _i < arguments.length; _i++) { splat[_i - 1] = arguments[_i]; } this.namedLog(models.LogLevel.INFO, message, splat); }; OptimizelyLogger.prototype.debug = function (message) { var splat = []; for (var _i = 1; _i < arguments.length; _i++) { splat[_i - 1] = arguments[_i]; } this.namedLog(models.LogLevel.DEBUG, message, splat); }; OptimizelyLogger.prototype.warn = function (message) { var splat = []; for (var _i = 1; _i < arguments.length; _i++) { splat[_i - 1] = arguments[_i]; } this.namedLog(models.LogLevel.WARNING, message, splat); }; OptimizelyLogger.prototype.error = function (message) { var splat = []; for (var _i = 1; _i < arguments.length; _i++) { splat[_i - 1] = arguments[_i]; } this.namedLog(models.LogLevel.ERROR, message, splat); }; OptimizelyLogger.prototype.format = function (data) { return "" + (this.messagePrefix ? this.messagePrefix + ': ' : '') + lib.sprintf.apply(void 0, [data.message].concat(data.splat)); }; OptimizelyLogger.prototype.internalLog = function (level, data) { if (!globalLogHandler) { return; } if (level < globalLogLevel) { return; } globalLogHandler.log(level, this.format(data)); if (data.error && data.error instanceof Error) { errorHandler.getErrorHandler().handleError(data.error); } }; OptimizelyLogger.prototype.namedLog = function (level, message, splat) { var error; if (message instanceof Error) { error = message; message = error.message; this.internalLog(level, { error: error, message: message, splat: splat, }); return; } if (splat.length === 0) { this.internalLog(level, { message: message, splat: splat, }); return; } var last = splat[splat.length - 1]; if (last instanceof Error) { error = last; splat.splice(-1); } this.internalLog(level, { message: message, error: error, splat: splat }); }; return OptimizelyLogger; }()); var globalLogManager = new DefaultLogManager(); function getLogger(name) { return globalLogManager.getLogger(name); } exports.getLogger = getLogger; function setLogHandler(logger) { globalLogHandler = logger; } exports.setLogHandler = setLogHandler; function setLogLevel(level) { level = coerceLogLevel(level); if (!lib.isValidEnum(models.LogLevel, level) || level === undefined) { globalLogLevel = models.LogLevel.ERROR; } else { globalLogLevel = level; } } exports.setLogLevel = setLogLevel; function getLogLevel() { return globalLogLevel; } exports.getLogLevel = getLogLevel; /** * Resets all global logger state to it's original */ function resetLogger() { globalLogManager = new DefaultLogManager(); globalLogLevel = models.LogLevel.NOTSET; } exports.resetLogger = resetLogger; }); unwrapExports(logger); var logger_1 = logger.ConsoleLogHandler; var logger_2 = logger.getLogger; var logger_3 = logger.setLogHandler; var logger_4 = logger.setLogLevel; var logger_5 = logger.getLogLevel; var logger_6 = logger.resetLogger; var lib$1 = createCommonjsModule(function (module, exports) { function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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. */ __export(errorHandler); __export(models); __export(logger); }); unwrapExports(lib$1); var lib_1$1 = lib$1.ConsoleLogHandler; var lib_2$1 = lib$1.getLogger; var lib_3$1 = lib$1.setLogLevel; var lib_4$1 = lib$1.LogLevel; var lib_5$1 = lib$1.setLogHandler; var lib_6$1 = lib$1.setErrorHandler; var lib_7$1 = lib$1.getErrorHandler; var events = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); function areEventContextsEqual(eventA, eventB) { var contextA = eventA.context; var contextB = eventB.context; return (contextA.accountId === contextB.accountId && contextA.projectId === contextB.projectId && contextA.clientName === contextB.clientName && contextA.clientVersion === contextB.clientVersion && contextA.revision === contextB.revision && contextA.anonymizeIP === contextB.anonymizeIP && contextA.botFiltering === contextB.botFiltering); } exports.areEventContextsEqual = areEventContextsEqual; }); unwrapExports(events); var events_1 = events.areEventContextsEqual; var eventQueue = createCommonjsModule(function (module, exports) { /** * Copyright 2019, Optimizely * * 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. */ Object.defineProperty(exports, "__esModule", { value: true }); var logger = lib$1.getLogger('EventProcessor'); var Timer = /** @class */ (function () { function Timer(_a) { var timeout = _a.timeout, callback = _a.callback; this.timeout = Math.max(timeout, 0); this.callback = callback; } Timer.prototype.start = function () { this.timeoutId = setTimeout(this.callback, this.timeout); }; Timer.prototype.refresh = function () { this.stop(); this.start(); }; Timer.prototype.stop = function () { if (this.timeoutId) { clearTimeout(this.timeoutId); } }; return Timer; }()); var SingleEventQueue = /** @class */ (function () { function SingleEventQueue(_a) { var sink = _a.sink; this.sink = sink; } SingleEventQueue.prototype.start = function () { // no-op }; SingleEventQueue.prototype.stop = function () { // no-op return Promise.resolve(); }; SingleEventQueue.prototype.enqueue = function (event) { this.sink([event]); }; return SingleEventQueue; }()); exports.SingleEventQueue = SingleEventQueue; var DefaultEventQueue = /** @class */ (function () { function DefaultEventQueue(_a) { var flushInterval = _a.flushInterval, maxQueueSize = _a.maxQueueSize, sink = _a.sink, batchComparator = _a.batchComparator; this.buffer = []; this.maxQueueSize = Math.max(maxQueueSize, 1); this.sink = sink; this.batchComparator = batchComparator; this.timer = new Timer({ callback: this.flush.bind(this), timeout: flushInterval, }); this.started = false; } DefaultEventQueue.prototype.start = function () { this.started = true; // dont start the timer until the first event is enqueued }; DefaultEventQueue.prototype.stop = function () { this.started = false; var result = this.sink(this.buffer); this.buffer = []; this.timer.stop(); return result; }; DefaultEventQueue.prototype.enqueue = function (event) { if (!this.started) { logger.warn('Queue is stopped, not accepting event'); return; } // If new event cannot be included into the current batch, flush so it can // be in its own new batch. var bufferedEvent = this.buffer[0]; if (bufferedEvent && !this.batchComparator(bufferedEvent, event)) { this.flush(); } // start the timer when the first event is put in if (this.buffer.length === 0) { this.timer.refresh(); } this.buffer.push(event); if (this.buffer.length >= this.maxQueueSize) { this.flush(); } }; DefaultEventQueue.prototype.flush = function () { this.sink(this.buffer); this.buffer = []; this.timer.stop(); }; return DefaultEventQueue; }()); exports.DefaultEventQueue = DefaultEventQueue; }); unwrapExports(eventQueue); var eventQueue_1 = eventQueue.SingleEventQueue; var eventQueue_2 = eventQueue.DefaultEventQueue; var lib$2 = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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. */ function generateUUID() { return uuid_1.v4(); } exports.generateUUID = generateUUID; function getTimestamp() { return new Date().getTime(); } exports.getTimestamp = getTimestamp; /** * Validates a value is a valid TypeScript enum * * @export * @param {object} enumToCheck * @param {*} value * @returns {boolean} */ function isValidEnum(enumToCheck, value) { var found = false; var keys = Object.keys(enumToCheck); for (var index = 0; index < keys.length; index++) { if (value === enumToCheck[keys[index]]) { found = true; break; } } return found; } exports.isValidEnum = isValidEnum; function groupBy(arr, grouperFn) { var grouper = {}; arr.forEach(function (item) { var key = grouperFn(item); grouper[key] = grouper[key] || []; grouper[key].push(item); }); return objectValues(grouper); } exports.groupBy = groupBy; function objectValues(obj) { return Object.keys(obj).map(function (key) { return obj[key]; }); } exports.objectValues = objectValues; function objectEntries(obj) { return Object.keys(obj).map(function (key) { return [key, obj[key]]; }); } exports.objectEntries = objectEntries; function find(arr, cond) { var found; for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) { var item = arr_1[_i]; if (cond(item)) { found = item; break; } } return found; } exports.find = find; function keyBy(arr, keyByFn) { var map = {}; arr.forEach(function (item) { var key = keyByFn(item); map[key] = item; }); return map; } exports.keyBy = keyBy; function sprintf(format) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var i = 0; return format.replace(/%s/g, function () { var arg = args[i++]; var type = typeof arg; if (type === 'function') { return arg(); } else if (type === 'string') { return arg; } else { return String(arg); } }); } exports.sprintf = sprintf; /* * Notification types for use with NotificationCenter * Format is EVENT: <list of parameters to callback> * * SDK consumers can use these to register callbacks with the notification center. * * @deprecated since 3.1.0 * ACTIVATE: An impression event will be sent to Optimizely * Callbacks will receive an object argument with the following properties: * - experiment {Object} * - userId {string} * - attributes {Object|undefined} * - variation {Object} * - logEvent {Object} * * DECISION: A decision is made in the system. i.e. user activation, * feature access or feature-variable value retrieval * Callbacks will receive an object argument with the following properties: * - type {string} * - userId {string} * - attributes {Object|undefined} * - decisionInfo {Object|undefined} * * LOG_EVENT: A batch of events, which could contain impressions and/or conversions, * will be sent to Optimizely * Callbacks will receive an object argument with the following properties: * - url {string} * - httpVerb {string} * - params {Object} * * OPTIMIZELY_CONFIG_UPDATE: This Optimizely instance has been updated with a new * config * * TRACK: A conversion event will be sent to Optimizely * Callbacks will receive the an object argument with the following properties: * - eventKey {string} * - userId {string} * - attributes {Object|undefined} * - eventTags {Object|undefined} * - logEvent {Object} * */ var NOTIFICATION_TYPES; (function (NOTIFICATION_TYPES) { NOTIFICATION_TYPES["ACTIVATE"] = "ACTIVATE:experiment, user_id,attributes, variation, event"; NOTIFICATION_TYPES["DECISION"] = "DECISION:type, userId, attributes, decisionInfo"; NOTIFICATION_TYPES["LOG_EVENT"] = "LOG_EVENT:logEvent"; NOTIFICATION_TYPES["OPTIMIZELY_CONFIG_UPDATE"] = "OPTIMIZELY_CONFIG_UPDATE"; NOTIFICATION_TYPES["TRACK"] = "TRACK:event_key, user_id, attributes, event_tags, event"; })(NOTIFICATION_TYPES = exports.NOTIFICATION_TYPES || (exports.NOTIFICATION_TYPES = {})); }); unwrapExports(lib$2); var lib_1$2 = lib$2.generateUUID; var lib_2$2 = lib$2.getTimestamp; var lib_3$2 = lib$2.isValidEnum; var lib_4$2 = lib$2.groupBy; var lib_5$2 = lib$2.objectValues; var lib_6$2 = lib$2.objectEntries; var lib_7$2 = lib$2.find; var lib_8$1 = lib$2.keyBy; var lib_9 = lib$2.sprintf; var lib_10 = lib$2.NOTIFICATION_TYPES; var eventProcessor = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_FLUSH_INTERVAL = 30000; // Unit is ms - default flush interval is 30s exports.DEFAULT_BATCH_SIZE = 10; var logger = lib$1.getLogger('EventProcessor'); function validateAndGetFlushInterval(flushInterval) { if (flushInterval <= 0) { logger.warn("Invalid flushInterval " + flushInterval + ", defaulting to " + exports.DEFAULT_FLUSH_INTERVAL); flushInterval = exports.DEFAULT_FLUSH_INTERVAL; } return flushInterval; } exports.validateAndGetFlushInterval = validateAndGetFlushInterval; function validateAndGetBatchSize(batchSize) { batchSize = Math.floor(batchSize); if (batchSize < 1) { logger.warn("Invalid batchSize " + batchSize + ", defaulting to " + exports.DEFAULT_BATCH_SIZE); batchSize = exports.DEFAULT_BATCH_SIZE; } batchSize = Math.max(1, batchSize); return batchSize; } exports.validateAndGetBatchSize = validateAndGetBatchSize; function getQueue(batchSize, flushInterval, sink, batchComparator) { var queue; if (batchSize > 1) { queue = new eventQueue.DefaultEventQueue({ flushInterval: flushInterval, maxQueueSize: batchSize, sink: sink, batchComparator: batchComparator, }); } else { queue = new eventQueue.SingleEventQueue({ sink: sink }); } return queue; } exports.getQueue = getQueue; function sendEventNotification(notificationCenter, event) { if (notificationCenter) { notificationCenter.sendNotifications(lib$2.NOTIFICATION_TYPES.LOG_EVENT, event); } } exports.sendEventNotification = sendEventNotification; }); unwrapExports(eventProcessor); var eventProcessor_1 = eventProcessor.DEFAULT_FLUSH_INTERVAL; var eventProcessor_2 = eventProcessor.DEFAULT_BATCH_SIZE; var eventProcessor_3 = eventProcessor.validateAndGetFlushInterval; var eventProcessor_4 = eventProcessor.validateAndGetBatchSize; var eventProcessor_5 = eventProcessor.getQueue; var eventProcessor_6 = eventProcessor.sendEventNotification; var pendingEventsStore = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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 logger = lib$1.getLogger('EventProcessor'); var LocalStorageStore = /** @class */ (function () { function LocalStorageStore(_a) { var key = _a.key, _b = _a.maxValues, maxValues = _b === void 0 ? 1000 : _b; this.LS_KEY = key; this.maxValues = maxValues; } LocalStorageStore.prototype.get = function (key) { return this.getMap()[key] || null; }; LocalStorageStore.prototype.set = function (key, value) { var map = this.getMap(); map[key] = value; this.replace(map); }; LocalStorageStore.prototype.remove = function (key) { var map = this.getMap(); delete map[key]; this.replace(map); }; LocalStorageStore.prototype.values = function () { return lib$2.objectValues(this.getMap()); }; LocalStorageStore.prototype.clear = function () { this.replace({}); }; LocalStorageStore.prototype.replace = function (map) { try { // This is a temporary fix to support React Native which does not have localStorage. window.localStorage && localStorage.setItem(this.LS_KEY, JSON.stringify(map)); this.clean(); } catch (e) { logger.error(e); } }; LocalStorageStore.prototype.clean = function () { var map = this.getMap(); var keys = Object.keys(map); var toRemove = keys.length - this.maxValues; if (toRemove < 1) { return; } var entries = keys.map(function (key) { return ({ key: key, value: map[key] }); }); entries.sort(function (a, b) { return a.value.timestamp - b.value.timestamp; }); for (var i = 0; i < toRemove; i++) { delete map[entries[i].key]; } this.replace(map); }; LocalStorageStore.prototype.getMap = function () { try { // This is a temporary fix to support React Native which does not have localStorage. var data = window.localStorage && localStorage.getItem(this.LS_KEY); if (data) { return JSON.parse(data) || {}; } } catch (e) { logger.error(e); } return {}; }; return LocalStorageStore; }()); exports.LocalStorageStore = LocalStorageStore; }); unwrapExports(pendingEventsStore); var pendingEventsStore_1 = pendingEventsStore.LocalStorageStore; var pendingEventsDispatcher = createCommonjsModule(function (module, exports) { var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright 2019, Optimizely * * 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 logger = lib$1.getLogger('EventProcessor'); var PendingEventsDispatcher = /** @class */ (function () { function PendingEventsDispatcher(_a) { var eventDispatcher = _a.eventDispatcher, store = _a.store; this.dispatcher = eventDispatcher; this.store = store; } PendingEventsDispatcher.prototype.dispatchEvent = function (request, callback) { this.send({ uuid: lib$2.generateUUID(), timestamp: lib$2.getTimestamp(), request: request, }, callback); }; PendingEventsDispatcher.prototype.sendPendingEvents = function () { var _this = this; var pendingEvents = this.store.values(); logger.debug('Sending %s pending events from previous page', pendingEvents.length); pendingEvents.forEach(function (item) { try { _this.send(item, function () { }); } catch (e) { } }); }; PendingEventsDispatcher.prototype.send = function (entry, callback) { var _this = this; this.store.set(entry.uuid, entry); this.dispatcher.dispatchEvent(entry.request, function (response) { _this.store.remove(entry.uuid); callback(response); }); }; return PendingEventsDispatcher; }()); exports.PendingEventsDispatcher = PendingEventsDispatcher; var LocalStoragePendingEventsDispatcher = /** @class */ (function (_super) { __extends(LocalStoragePendingEventsDispatcher, _super); function LocalStoragePendingEventsDispatcher(_a) { var eventDispatcher = _a.eventDispatcher; return _super.call(this, { eventDispatcher: eventDispatcher, store: new pendingEventsStore.LocalStorageStore({ // TODO make this configurable maxValues: 100, key: 'fs_optly_pending_events', }), }) || this; } return LocalStoragePendingEventsDispatcher; }(PendingEventsDispatcher)); exports.LocalStoragePendingEventsDispatcher = LocalStoragePendingEventsDispatcher; }); unwrapExports(pendingEventsDispatcher); var pendingEventsDispatcher_1 = pendingEventsDispatcher.PendingEventsDispatcher; var pendingEventsDispatcher_2 = pendingEventsDispatcher.LocalStoragePendingEventsDispatcher; var buildEventV1 = createCommonjsModule(function (module, exports) { var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var ACTIVATE_EVENT_KEY = 'campaign_activated'; var CUSTOM_ATTRIBUTE_FEATURE_TYPE = 'custom'; var BOT_FILTERING_KEY = '$opt_bot_filtering'; /** * Given an array of batchable Decision or ConversionEvent events it returns * a single EventV1 with proper batching * * @param {ProcessableEvent[]} events * @returns {EventV1} */ function makeBatchedEventV1(events) { var visitors = []; var data = events[0]; events.forEach(function (event) { if (event.type === 'conversion' || event.type === 'impression') { var visitor = makeVisitor(event); if (event.type === 'impression') { visitor.snapshots.push(makeDecisionSnapshot(event)); } else if (event.type === 'conversion') { visitor.snapshots.push(makeConversionSnapshot(event)); } visitors.push(visitor); } }); return { client_name: data.context.clientName, client_version: data.context.clientVersion, account_id: data.context.accountId, project_id: data.context.projectId, revision: data.context.revision, anonymize_ip: data.context.anonymizeIP, enrich_decisions: true, visitors: visitors, }; } exports.makeBatchedEventV1 = makeBatchedEventV1; function makeConversionSnapshot(conversion) { var tags = __assign({}, conversion.tags); delete tags['revenue']; delete tags['value']; var event = { entity_id: conversion.event.id, key: conversion.event.key, timestamp: conversion.timestamp, uuid: conversion.uuid, }; if (conversion.tags) { event.tags = conversion.tags; } if (conversion.value != null) { event.value = conversion.value; } if (conversion.revenue != null) { event.revenue = conversion.revenue; } return { events: [event], }; } function makeDecisionSnapshot(event) { var layer = event.layer, experiment = event.experiment, variation = event.variation; var layerId = layer ? layer.id : null; var experimentId = experiment ? experiment.id : null; var variationId = variation ? variation.id : null; return { decisions: [ { campaign_id: layerId, experiment_id: experimentId, variation_id: variationId, }, ], events: [ { entity_id: layerId, timestamp: event.timestamp, key: ACTIVATE_EVENT_KEY, uuid: event.uuid, }, ], }; } function makeVisitor(data) { var visitor = { snapshots: [], visitor_id: data.user.id, attributes: [], }; data.user.attributes.forEach(function (attr) { visitor.attributes.push({ entity_id: attr.entityId, key: attr.key, type: 'custom', value: attr.value, }); }); if (typeof data.context.botFiltering === 'boolean') { visitor.attributes.push({ entity_id: BOT_FILTERING_KEY, key: BOT_FILTERING_KEY, type: CUSTOM_ATTRIBUTE_FEATURE_TYPE, value: data.context.botFiltering, }); } return visitor; } /** * Event for usage with v1 logtier * * @export * @interface EventBuilderV1 */ function buildImpressionEventV1(data) { var visitor = makeVisitor(data); visitor.snapshots.push(makeDecisionSnapshot(data)); return { client_name: data.context.clientName, client_version: data.context.clientVersion, account_id: data.context.accountId, project_id: data.context.projectId, revision: data.context.revision, anonymize_ip: data.context.anonymizeIP, enrich_decisions: true, visitors: [visitor], }; } exports.buildImpressionEventV1 = buildImpressionEventV1; function buildConversionEventV1(data) { var visitor = makeVisitor(data); visitor.snapshots.push(makeConversionSnapshot(data)); return { client_name: data.context.clientName, client_version: data.context.clientVersion, account_id: data.context.accountId, project_id: data.context.projectId, revision: data.context.revision, anonymize_ip: data.context.anonymizeIP, enrich_decisions: true, visitors: [visitor], }; } exports.buildConversionEventV1 = buildConversionEventV1; function formatEvents(events) { return { url: 'https://logx.optimizely.com/v1/events', httpVerb: 'POST', params: makeBatchedEventV1(events), }; } exports.formatEvents = formatEvents; }); unwrapExports(buildEventV1); var buildEventV1_1 = buildEventV1.makeBatchedEventV1; var buildEventV1_2 = buildEventV1.buildImpressionEventV1; var buildEventV1_3 = buildEventV1.buildConversionEventV1; var buildEventV1_4 = buildEventV1.formatEvents; var requestTracker = createCommonjsModule(function (module, exports) { /** * Copyright 2020, Optimizely * * 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. */ Object.defineProperty(exports, "__esModule", { value: true }); /** * RequestTracker keeps track of in-flight requests for EventProcessor using * an internal counter. It exposes methods for adding a new request to be * tracked, and getting a Promise representing the completion of currently * tracked requests. */ var RequestTracker = /** @class */ (function () { function RequestTracker() { this.reqsInFlightCount = 0; this.reqsCompleteResolvers = []; } /** * Track the argument request (represented by a Promise). reqPromise will feed * into the state of Promises returned by onRequestsComplete. * @param {Promise<void>} reqPromise */ RequestTracker.prototype.trackRequest = function (reqPromise) { var _this = this; this.reqsInFlightCount++; var onReqComplete = function () { _this.reqsInF