UNPKG

@absmartly/javascript-sdk

Version:

A/B Smartly Javascript SDK

1,176 lines (1,142 loc) 341 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["absmartly"] = factory(); else root["absmartly"] = factory(); })(self, function() { return /******/ (function() { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./js/abort-controller-shim.js": /*!*************************************!*\ !*** ./js/abort-controller-shim.js ***! \*************************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; __webpack_require__(/*! core-js/modules/es.date.to-primitive.js */ "./node_modules/core-js/modules/es.date.to-primitive.js"); __webpack_require__(/*! core-js/modules/es.number.constructor.js */ "./node_modules/core-js/modules/es.number.constructor.js"); function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AbortController = exports.AbortSignal = void 0; var AbortSignal = /*#__PURE__*/function () { function AbortSignal() { _classCallCheck(this, AbortSignal); this.aborted = false; this._events = {}; } _createClass(AbortSignal, [{ key: "addEventListener", value: function addEventListener(type, listener) { var listeners = this._events[type]; if (!listeners) { listeners = []; this._events[type] = listeners; } listeners.push(listener); } }, { key: "removeEventListener", value: function removeEventListener(type, listener) { var listeners = this._events[type]; if (listeners) { var index = listeners.findIndex(function (x) { return x === listener; }); if (index !== -1) { listeners.splice(index, 1); if (listeners.length === 0) { delete this._events[type]; } } } } }, { key: "dispatchEvent", value: function dispatchEvent(evt) { this["on".concat(evt.type)] && this["on".concat(evt.type)](evt); var listeners = this._events[evt.type]; if (listeners) { var _iterator = _createForOfIteratorHelper(listeners), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var listener = _step.value; listener.call(null, evt); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } } }, { key: "toString", value: function toString() { return "[object AbortSignal]"; } }]); return AbortSignal; }(); exports.AbortSignal = AbortSignal; var AbortController = /*#__PURE__*/function () { function AbortController() { _classCallCheck(this, AbortController); this.signal = new AbortSignal(); } _createClass(AbortController, [{ key: "abort", value: function abort() { var evt; try { evt = new Event("abort"); } catch (e) { evt = { type: "abort", bubbles: false, cancelable: false }; } this.signal.aborted = true; this.signal.dispatchEvent(evt); } }, { key: "toString", value: function toString() { return "[object AbortController]"; } }]); return AbortController; }(); exports.AbortController = AbortController; if (typeof Symbol !== "undefined" && Symbol.toStringTag !== undefined) { Object.defineProperty(AbortSignal.prototype, Symbol.toStringTag, { configurable: true, value: "AbortSignal" }); Object.defineProperty(AbortController.prototype, Symbol.toStringTag, { configurable: true, value: "AbortController" }); } exports["default"] = AbortController; /***/ }), /***/ "./js/abort.js": /*!*********************!*\ !*** ./js/abort.js ***! \*********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; var __importDefault = void 0 && (void 0).__importDefault || function (mod) { return mod && mod.__esModule ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AbortController = void 0; var utils_1 = __webpack_require__(/*! ./utils */ "./js/utils.js"); var abort_controller_shim_1 = __importDefault(__webpack_require__(/*! ./abort-controller-shim */ "./js/abort-controller-shim.js")); exports.AbortController = (0, utils_1.isLongLivedApp)() && window.AbortController ? window.AbortController : (0, utils_1.isWorker)() && self.AbortController ? self.AbortController : __webpack_require__.g && __webpack_require__.g.AbortController ? __webpack_require__.g.AbortController : abort_controller_shim_1.default; /***/ }), /***/ "./js/algorithm.js": /*!*************************!*\ !*** ./js/algorithm.js ***! \*************************/ /***/ (function(__unused_webpack_module, exports) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.insertUniqueSorted = void 0; var insertUniqueSorted = function insertUniqueSorted(arr, value, isSorted) { var left = 0; var right = arr.length - 1; while (left <= right) { var mid = Math.floor(left + (right - left) / 2); if (isSorted(arr[mid], value)) { left = mid + 1; } else if (isSorted(value, arr[mid])) { right = mid - 1; } else { return; } } arr.splice(left, 0, value); }; exports.insertUniqueSorted = insertUniqueSorted; /***/ }), /***/ "./js/assigner.js": /*!************************!*\ !*** ./js/assigner.js ***! \************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; __webpack_require__(/*! core-js/modules/es.date.to-primitive.js */ "./node_modules/core-js/modules/es.date.to-primitive.js"); __webpack_require__(/*! core-js/modules/es.number.constructor.js */ "./node_modules/core-js/modules/es.number.constructor.js"); function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } Object.defineProperty(exports, "__esModule", ({ value: true })); exports.VariantAssigner = void 0; var utils_1 = __webpack_require__(/*! ./utils */ "./js/utils.js"); var murmur3_32_1 = __webpack_require__(/*! ./murmur3_32 */ "./js/murmur3_32.js"); var VariantAssigner = /*#__PURE__*/function () { function VariantAssigner(unit) { _classCallCheck(this, VariantAssigner); this._unitHash = (0, murmur3_32_1.murmur3_32)((0, utils_1.stringToUint8Array)(unit).buffer); } _createClass(VariantAssigner, [{ key: "assign", value: function assign(split, seedHi, seedLo) { var prob = this._probability(seedHi, seedLo); return (0, utils_1.chooseVariant)(split, prob); } }, { key: "_probability", value: function _probability(seedHi, seedLo) { var key = this._unitHash; var buffer = new ArrayBuffer(12); var view = new DataView(buffer); view.setUint32(0, seedLo, true); view.setUint32(4, seedHi, true); view.setUint32(8, key, true); return (0, murmur3_32_1.murmur3_32)(buffer) * (1.0 / 0xffffffff); } }]); return VariantAssigner; }(); exports.VariantAssigner = VariantAssigner; /***/ }), /***/ "./js/client.js": /*!**********************!*\ !*** ./js/client.js ***! \**********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; __webpack_require__(/*! core-js/modules/es.object.assign.js */ "./node_modules/core-js/modules/es.object.assign.js"); __webpack_require__(/*! core-js/modules/es.date.to-primitive.js */ "./node_modules/core-js/modules/es.date.to-primitive.js"); __webpack_require__(/*! core-js/modules/es.number.constructor.js */ "./node_modules/core-js/modules/es.number.constructor.js"); function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var __importDefault = void 0 && (void 0).__importDefault || function (mod) { return mod && mod.__esModule ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); var fetch_1 = __importDefault(__webpack_require__(/*! ./fetch */ "./js/fetch.js")); var abort_1 = __webpack_require__(/*! ./abort */ "./js/abort.js"); var errors_1 = __webpack_require__(/*! ./errors */ "./js/errors.js"); var utils_1 = __webpack_require__(/*! ./utils */ "./js/utils.js"); var Client = /*#__PURE__*/function () { function Client(opts) { _classCallCheck(this, Client); this._opts = Object.assign({ agent: "javascript-client", apiKey: undefined, application: undefined, endpoint: undefined, environment: undefined, retries: 5, timeout: 3000, keepalive: true }, opts); for (var _i = 0, _arr = ["agent", "application", "apiKey", "endpoint", "environment"]; _i < _arr.length; _i++) { var key = _arr[_i]; if (key in this._opts && this._opts[key] !== undefined) { var value = this._opts[key]; if (typeof value !== "string" || value.length === 0) { if (key === "application") { if (value !== null && _typeof(value) === "object" && "name" in value) { continue; } } throw new Error("Invalid '".concat(key, "' in options argument")); } } else { throw new Error("Missing '".concat(key, "' in options argument")); } } if (typeof this._opts.application === "string") { this._opts.application = { name: this._opts.application, version: 0 }; } this._delay = 50; } _createClass(Client, [{ key: "getContext", value: function getContext(options) { return this.getUnauthed(Object.assign(Object.assign({}, options), { path: "/context", query: { application: (0, utils_1.getApplicationName)(this._opts.application), environment: this._opts.environment } })); } }, { key: "createContext", value: function createContext(params, options) { var body = { units: params.units }; return this.post(Object.assign(Object.assign({}, options), { path: "/context", body: body })); } }, { key: "publish", value: function publish(params, options) { var body = { units: params.units, hashed: params.hashed, publishedAt: params.publishedAt || Date.now() }; if (Array.isArray(params.goals) && params.goals.length > 0) { body.goals = params.goals; } if (Array.isArray(params.exposures) && params.exposures.length > 0) { body.exposures = params.exposures; } if (Array.isArray(params.attributes) && params.attributes.length > 0) { body.attributes = params.attributes; } return this.put(Object.assign(Object.assign({}, options), { path: "/context", body: body })); } }, { key: "request", value: function request(options) { var _this = this; var _a, _b; var url = "".concat(this._opts.endpoint).concat(options.path); if (options.query) { var keys = Object.keys(options.query); if (keys.length > 0) { var encoded = keys.map(function (k) { return options.query ? "".concat(k, "=").concat(encodeURIComponent(options.query[k])) : null; }).join("&"); url = "".concat(url, "?").concat(encoded); } } var controller = new abort_1.AbortController(); var tryOnce = function tryOnce() { var opts = { method: options.method, body: options.body !== undefined ? JSON.stringify(options.body, null, 0) : undefined, signal: controller.signal, keepalive: _this._opts.keepalive }; if (options.auth) { opts.headers = { "Content-Type": "application/json", "X-API-Key": _this._opts.apiKey, "X-Agent": _this._opts.agent, "X-Environment": _this._opts.environment, "X-Application": (0, utils_1.getApplicationName)(_this._opts.application), "X-Application-Version": (0, utils_1.getApplicationVersion)(_this._opts.application) }; } return (0, fetch_1.default)(url, opts).then(function (response) { if (!response.ok) { var bail = response.status >= 400 && response.status < 500; return response.text().then(function (text) { var error = new Error(text !== null && text.length > 0 ? text : response.statusText); error._bail = bail; return Promise.reject(error); }); } return response.json(); }); }; var wait = function wait(ms) { return new Promise(function (resolve, reject) { var timeoutId = setTimeout(function () { delete wait.reject; resolve(); }, ms); wait.reject = function (reason) { clearTimeout(timeoutId); reject(reason); }; }); }; var tryWith = function tryWith(retries, timeout) { var tries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var waited = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; delete tryWith.timedout; return tryOnce().catch(function (reason) { console.warn(reason); if (reason._bail || retries <= 0) { throw new Error(reason.message); } else if (tries >= retries) { throw new errors_1.RetryError(tries, reason, url); } else if (waited >= timeout || reason.name === "AbortError") { if (tryWith.timedout) { throw new errors_1.TimeoutError(timeout); } throw reason; } var delay = (1 << tries) * _this._delay + 0.5 * Math.random() * _this._delay; if (waited + delay > timeout) { delay = timeout - waited; } return wait(delay).then(function () { return tryWith(retries, timeout, tries + 1, waited + delay); }); }); }; var abort = function abort() { if (wait.reject) { wait.reject(new errors_1.AbortError()); } else { controller.abort(); } }; if (options.signal) { options.signal.addEventListener("abort", abort); } var timeout = options.timeout || this._opts.timeout || 0; var timeoutId = timeout > 0 ? setTimeout(function () { tryWith.timedout = true; abort(); }, timeout) : 0; var finalCleanUp = function finalCleanUp() { clearTimeout(timeoutId); if (options.signal) { options.signal.removeEventListener("abort", abort); } }; return tryWith((_a = this._opts.retries) !== null && _a !== void 0 ? _a : 5, (_b = this._opts.timeout) !== null && _b !== void 0 ? _b : 3000).then(function (value) { finalCleanUp(); return value; }).catch(function (error) { finalCleanUp(); throw error; }); } }, { key: "post", value: function post(options) { return this.request(Object.assign(Object.assign({}, options), { auth: true, method: "POST" })); } }, { key: "put", value: function put(options) { return this.request(Object.assign(Object.assign({}, options), { auth: true, method: "PUT" })); } }, { key: "getUnauthed", value: function getUnauthed(options) { return this.request(Object.assign(Object.assign({}, options), { method: "GET" })); } }]); return Client; }(); exports["default"] = Client; /***/ }), /***/ "./js/config.js": /*!**********************!*\ !*** ./js/config.js ***! \**********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; __webpack_require__(/*! core-js/modules/es.object.entries.js */ "./node_modules/core-js/modules/es.object.entries.js"); function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } var __importDefault = void 0 && (void 0).__importDefault || function (mod) { return mod && mod.__esModule ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.mergeConfig = void 0; var default_1 = __importDefault(__webpack_require__(/*! rfdc/default */ "./node_modules/rfdc/default.js")); var utils_1 = __webpack_require__(/*! ./utils */ "./js/utils.js"); function mergeConfig(context, previousConfig) { var merged = (0, default_1.default)(previousConfig); var keys = context.variableKeys(); var _loop = function _loop() { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), variableKey = _Object$entries$_i[0], experimentName = _Object$entries$_i[1]; var target = merged; var frags = variableKey.split("."); var _loop2 = function _loop2() { var frag = frags[index]; if ("_".concat(frag, "_setter") in target) { console.error("Config key '".concat(frags.slice(0, index + 1).join("."), "' already set by experiment '").concat(target["_".concat(frag, "_setter")], "'.")); target = undefined; return "break"; } if (frag in target) { if (index < frags.length - 1) { if (!(0, utils_1.isObject)(target[frag])) { console.warn("Config key '".concat(variableKey, "' for experiment '").concat(experimentName, "' is overriding non-object value at '").concat(frags.slice(0, index + 1).join("."), "' with an object.")); target = target[frag] = {}; } else { target = target[frag]; } } } if (index === frags.length - 1) { var defaultValue = target[frag]; Object.defineProperty(target, "_".concat(frag, "_setter"), { value: experimentName, writable: false }); Object.defineProperty(target, frag, { get: function get() { return context.variableValue(variableKey, defaultValue); } }); } }; for (var index = 0; index < frags.length; ++index) { var _ret = _loop2(); if (_ret === "break") break; } }; for (var _i = 0, _Object$entries = Object.entries(keys); _i < _Object$entries.length; _i++) { _loop(); } return merged; } exports.mergeConfig = mergeConfig; /***/ }), /***/ "./js/context.js": /*!***********************!*\ !*** ./js/context.js ***! \***********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; __webpack_require__(/*! core-js/modules/es.object.entries.js */ "./node_modules/core-js/modules/es.object.entries.js"); __webpack_require__(/*! core-js/modules/es.object.assign.js */ "./node_modules/core-js/modules/es.object.assign.js"); __webpack_require__(/*! core-js/modules/es.array.find.js */ "./node_modules/core-js/modules/es.array.find.js"); __webpack_require__(/*! core-js/modules/es.number.constructor.js */ "./node_modules/core-js/modules/es.number.constructor.js"); __webpack_require__(/*! core-js/modules/es.date.to-primitive.js */ "./node_modules/core-js/modules/es.date.to-primitive.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } Object.defineProperty(exports, "__esModule", ({ value: true })); var utils_1 = __webpack_require__(/*! ./utils */ "./js/utils.js"); var assigner_1 = __webpack_require__(/*! ./assigner */ "./js/assigner.js"); var matcher_1 = __webpack_require__(/*! ./matcher */ "./js/matcher.js"); var algorithm_1 = __webpack_require__(/*! ./algorithm */ "./js/algorithm.js"); var Context = /*#__PURE__*/function () { function Context(sdk, options, params, promise) { var _this = this; _classCallCheck(this, Context); this._sdk = sdk; this._publisher = options.publisher || this._sdk.getContextPublisher(); this._dataProvider = options.dataProvider || this._sdk.getContextDataProvider(); this._eventLogger = options.eventLogger || this._sdk.getEventLogger(); this._opts = options; this._pending = 0; this._failed = false; this._finalized = false; this._attrs = []; this._goals = []; this._exposures = []; this._overrides = {}; this._cassignments = {}; this._units = {}; this._assigners = {}; this._audienceMatcher = new matcher_1.AudienceMatcher(); if (params.units) { this.units(params.units); } if ((0, utils_1.isPromise)(promise)) { this._promise = promise.then(function (data) { _this._init(data); delete _this._promise; _this._logEvent("ready", data); if (_this.pending() > 0) { _this._setTimeout(); } }).catch(function (error) { _this._init({}); _this._failed = true; delete _this._promise; _this._logError(error); }); } else { promise = promise; this._init(promise); this._logEvent("ready", promise); } } _createClass(Context, [{ key: "isReady", value: function isReady() { return this._promise === undefined; } }, { key: "isFinalizing", value: function isFinalizing() { return !this._finalized && this._finalizing != null; } }, { key: "isFinalized", value: function isFinalized() { return this._finalized; } }, { key: "isFailed", value: function isFailed() { return this._failed; } }, { key: "ready", value: function ready() { var _this2 = this; if (this.isReady()) { return Promise.resolve(true); } return new Promise(function (resolve) { var _a; (_a = _this2._promise) === null || _a === void 0 ? void 0 : _a.then(function () { return resolve(true); }).catch(function (e) { return resolve(e); }); }); } }, { key: "pending", value: function pending() { return this._pending; } }, { key: "data", value: function data() { this._checkReady(); return this._data; } }, { key: "eventLogger", value: function eventLogger() { return this._eventLogger; } }, { key: "publisher", value: function publisher() { return this._publisher; } }, { key: "provider", value: function provider() { return this._dataProvider; } }, { key: "publish", value: function publish(requestOptions) { var _this3 = this; this._checkReady(true); return new Promise(function (resolve, reject) { _this3._flush(function (error) { if (error) { reject(error); } else { resolve(); } }, requestOptions); }); } }, { key: "refresh", value: function refresh(requestOptions) { var _this4 = this; this._checkReady(true); return new Promise(function (resolve, reject) { _this4._refresh(function (error) { if (error) { reject(error); } else { resolve(); } }, requestOptions); }); } }, { key: "getUnit", value: function getUnit(unitType) { return this._units[unitType]; } }, { key: "unit", value: function unit(unitType, uid) { this._checkNotFinalized(); switch (_typeof(uid)) { case "string": uid = uid.trim(); if (uid.length === 0) throw new Error("Unit '".concat(unitType, "' UID must not be blank.")); break; case "number": break; default: throw new Error("Unit '".concat(unitType, "' must be a string or a number.")); } var previous = this._units[unitType]; if (previous !== undefined && previous !== uid) { throw new Error("Unit '".concat(unitType, "' UID already set.")); } this._units[unitType] = uid; } }, { key: "getUnits", value: function getUnits() { return this._units; } }, { key: "units", value: function units(_units) { var _this5 = this; Object.entries(_units).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), unitType = _ref2[0], uid = _ref2[1]; _this5.unit(unitType, uid); }); } }, { key: "getAttribute", value: function getAttribute(attrName) { var result; this._attrs.forEach(function (attr) { if (attr.name === attrName) result = attr.value; }); return result; } }, { key: "attribute", value: function attribute(attrName, value) { this._checkNotFinalized(); this._attrs.push({ name: attrName, value: value, setAt: Date.now() }); } }, { key: "getAttributes", value: function getAttributes() { var attributes = {}; this._attrs.map(function (a) { return [a.name, a.value]; }).forEach(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), key = _ref4[0], value = _ref4[1]; attributes[key] = value; }); return attributes; } }, { key: "attributes", value: function attributes(attrs) { var _this6 = this; Object.entries(attrs).forEach(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), attrName = _ref6[0], value = _ref6[1]; _this6.attribute(attrName, value); }); } }, { key: "peek", value: function peek(experimentName) { this._checkReady(true); return this._peek(experimentName).variant; } }, { key: "treatment", value: function treatment(experimentName) { this._checkReady(true); return this._treatment(experimentName).variant; } }, { key: "track", value: function track(goalName, properties) { this._checkNotFinalized(); return this._track(goalName, properties); } }, { key: "finalize", value: function finalize(requestOptions) { return this._finalize(requestOptions); } }, { key: "experiments", value: function experiments() { var _a; this._checkReady(); return (_a = this._data.experiments) === null || _a === void 0 ? void 0 : _a.map(function (x) { return x.name; }); } }, { key: "variableValue", value: function variableValue(key, defaultValue) { this._checkReady(true); return this._variableValue(key, defaultValue); } }, { key: "peekVariableValue", value: function peekVariableValue(key, defaultValue) { this._checkReady(true); return this._peekVariable(key, defaultValue); } }, { key: "variableKeys", value: function variableKeys() { this._checkReady(true); var variableExperiments = {}; Object.entries(this._indexVariables).forEach(function (_ref7) { var _ref8 = _slicedToArray(_ref7, 2), key = _ref8[0], values = _ref8[1]; values.forEach(function (value) { if (variableExperiments[key]) variableExperiments[key].push(value.data.name);else variableExperiments[key] = [value.data.name]; }); }); return variableExperiments; } }, { key: "override", value: function override(experimentName, variant) { this._overrides = Object.assign(this._overrides, _defineProperty({}, experimentName, variant)); } }, { key: "overrides", value: function overrides(experimentVariants) { var _this7 = this; Object.entries(experimentVariants).forEach(function (_ref9) { var _ref10 = _slicedToArray(_ref9, 2), experimentName = _ref10[0], variant = _ref10[1]; _this7.override(experimentName, variant); }); } }, { key: "customAssignment", value: function customAssignment(experimentName, variant) { this._checkNotFinalized(); this._cassignments[experimentName] = variant; } }, { key: "customAssignments", value: function customAssignments(experimentVariants) { var _this8 = this; Object.entries(experimentVariants).forEach(function (_ref11) { var _ref12 = _slicedToArray(_ref11, 2), experimentName = _ref12[0], variant = _ref12[1]; _this8.customAssignment(experimentName, variant); }); } }, { key: "_checkNotFinalized", value: function _checkNotFinalized() { if (this.isFinalized()) { throw new Error("ABSmartly Context is finalized."); } else if (this.isFinalizing()) { throw new Error("ABSmartly Context is finalizing."); } } }, { key: "_checkReady", value: function _checkReady(expectNotFinalized) { if (!this.isReady()) { throw new Error("ABSmartly Context is not yet ready."); } if (expectNotFinalized) { this._checkNotFinalized(); } } }, { key: "_assign", value: function _assign(experimentName) { var experimentMatches = function experimentMatches(experiment, assignment) { return experiment.id === assignment.id && experiment.unitType === assignment.unitType && experiment.iteration === assignment.iteration && experiment.fullOnVariant === assignment.fullOnVariant && (0, utils_1.arrayEqualsShallow)(experiment.trafficSplit, assignment.trafficSplit); }; var hasCustom = (experimentName in this._cassignments); var hasOverride = (experimentName in this._overrides); var experiment = experimentName in this._index ? this._index[experimentName] : null; if (experimentName in this._assignments) { var _assignment = this._assignments[experimentName]; if (hasOverride) { if (_assignment.overridden && _assignment.variant === this._overrides[experimentName]) { return _assignment; } } else if (experiment == null) { if (!_assignment.assigned) { return _assignment; } } else if (!hasCustom || this._cassignments[experimentName] === _assignment.variant) { if (experimentMatches(experiment.data, _assignment)) { return _assignment; } } } var assignment = { id: 0, iteration: 0, fullOnVariant: 0, unitType: null, variant: 0, overridden: false, assigned: false, exposed: false, eligible: true, fullOn: false, custom: false, audienceMismatch: false }; this._assignments[experimentName] = assignment; if (hasOverride) { if (experiment != null) { assignment.id = experiment.data.id; assignment.unitType = experiment.data.unitType; } assignment.overridden = true; assignment.variant = this._overrides[experimentName]; } else { if (experiment != null) { var unitType = experiment.data.unitType; if (experiment.data.audience && experiment.data.audience.length > 0) { var attrs = {}; this._attrs.forEach(function (attr) { attrs[attr.name] = attr.value; }); var result = this._audienceMatcher.evaluate(experiment.data.audience, attrs); if (typeof result === "boolean") { assignment.audienceMismatch = !result; } } if (experiment.data.audienceStrict && assignment.audienceMismatch) { assignment.variant = 0; } else if (experiment.data.fullOnVariant === 0) { if (unitType !== null) { if (unitType in this._units) { var unit = this._unitHash(unitType); if (unit !== null) { var assigner = unitType in this._assigners ? this._assigners[unitType] : this._assigners[unitType] = new assigner_1.VariantAssigner(unit); var eligible = assigner.assign(experiment.data.trafficSplit, experiment.data.trafficSeedHi, experiment.data.trafficSeedLo) === 1; assignment.assigned = true; assignment.eligible = eligible; if (eligible) { if (hasCustom) { assignment.variant = this._cassignments[experimentName]; assignment.custom = true; } else { assignment.variant = assigner.assign(experiment.data.split, experiment.data.seedHi, experiment.data.seedLo); } } else { assignment.variant = 0; } } } } } else { assignment.assigned = true; assignment.eligible = true; assignment.variant = experiment.data.fullOnVariant; assignment.fullOn = true; } assignment.unitType = unitType; assignment.id = experiment.data.id; assignment.iteration = experiment.data.iteration; assignment.trafficSplit = experiment.data.trafficSplit; assignment.fullOnVariant = experiment.data.fullOnVariant; } } if (experiment != null && assignment.variant < experiment.data.variants.length) { assignment.variables = experiment.variables[assignment.variant]; } return assignment; } }, { key: "_peek", value: function _peek(experimentName) { return this._assign(experimentName); } }, { key: "_treatment", value: function _treatment(experimentName) { var assignment = this._assign(experimentName); if (!assignment.exposed) { assignment.exposed = true; this._queueExposure(experimentName, assignment); } return assignment; } }, { key: "_queueExposure", value: function _queueExposure(experimentName, assignment) { var exposureEvent = { id: assignment.id, name: experimentName, exposedAt: Date.now(), unit: assignment.unitType, variant: assignment.variant, assigned: assignment.assigned, eligible: assignment.eligible, overridden: assignment.overridden, fullOn: assignment.fullOn, custom: assignment.custom, audienceMismatch: assignment.audienceMismatch }; this._logEvent("exposure", exposureEvent); this._exposures.push(exposureEvent); this._pending++; this._setTimeout(); } }, { key: "_customFieldKeys", value: function _customFieldKeys() { var keys = new Set(); if (!this._data.experiments) return []; var _iterator = _createForOfIteratorHelper(this._data.experiments), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var experiment = _step.value; if (experiment.customFieldValues != null) { var _iterator2 = _createForOfIteratorHelper(experiment.customFieldValues), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var customFieldValues = _step2.value; keys.add(customFieldValues.name); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return Array.from(keys); } }, { key: "customFieldKeys", value: function customFieldKeys() { this._checkReady(true); return this._customFieldKeys(); } }, { key: "_customFieldValue", value: function _customFieldValue(experimentName, key) { var _a; var experiment = this._index[experimentName]; if (experiment != null) { var field = (_a = experiment.data.customFieldValues) === null || _a === void 0 ? void 0 : _a.find(function (x) { return x.name === key; }); if (field != null) { switch (field.type) { case "text": case "string": return field.value; case "number": return Number(field.value); case "json": try { if (field.value === "null") return null; if (field.value === "") return ""; return JSON.parse(field.value); } catch (e) { console.error("Failed to parse JSON custom field value '".concat(key, "' for experiment '").concat(experimentName, "'")); return null; } case "boolean": return field.value === "true"; default: console.error("Unknown custom field type '".concat(field.type, "' for experiment '").concat(experimentName, "' and key '").concat(key, "' - you may need to upgrade to the latest SDK version")); return null; } } } return null; } }, { key: "customFieldValue", value: function customFieldValue(experimentName, key) { this._checkReady(true); return this._customFieldValue(experimentName, key); } }, { key: "_customFieldValueType", value: function _customFieldValueType(experimentName, key) { var _a; var experiment = this._index[experimentName]; if (experiment != null) { var field = (_a = experiment.data.customFieldValues) === null || _a === void 0 ? void 0 : _a.find(function (x) { return x.name === key; }); if (field != null) { return f