diff --git a/.babelrc b/.babelrc index efbf12ab..6034133e 100644 --- a/.babelrc +++ b/.babelrc @@ -8,7 +8,7 @@ "plugins": [ "es6-promise", "@babel/plugin-transform-flow-comments", - "@babel/plugin-transform-runtime" + ["@babel/plugin-transform-runtime", {"version": "7.18.10"}] ], "overrides": [ { diff --git a/.eslintrc b/.eslintrc index 3175db7d..ddfefbf3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -51,7 +51,8 @@ ], "eol-last": "error", "@typescript-eslint/ban-types": "warn", - "@typescript-eslint/explicit-module-boundary-types": "off" + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-namespace": "warn" } }, { diff --git a/CHANGELOG.md b/CHANGELOG.md index 995d5ff3..e7262c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ -### Version 5.3.1 (8st August 2022) +### Version 5.4.0 (20th September 2022) +#### Added +- Added support of Data Residency. +- Added Smart Banner `onCreated` and `onDismissed` optional callbacks. To set callbacks pass them to `initSmartBanner` method. +- Added `showSmartBanner` and `hideSmartBanner` methods to control Smart Banner visibility after initialisation. + + +#### Fixed +- Fixed issue when Url Strategy ignored SDK config. + +--- +### Version 5.3.1 (8th August 2022) #### Added - Added sending of `deduplication_id` parameter in `event` package. - Added SRI feature support. diff --git a/README.md b/README.md index 4473e877..fd03948c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ To lazy load the Adjust Web SDK through CDN paste th The Adjust Web SDK should be loaded only once per page and it should be initiated once per page load. -When loading the sdk through CDN we suggest using minified version. You can target specific version like `https://cdn.adjust.com/adjust-5.3.1.min.js`, or you can target latest version `https://cdn.adjust.com/adjust-latest.min.js` if you want automatic updates without need to change the target file. The sdk files are cached so they are served as fast as possible, and the cache is refreshed every half an hour. If you want updates immediately make sure to target specific version. +When loading the sdk through CDN we suggest using minified version. You can target specific version like `https://cdn.adjust.com/adjust-5.4.0.min.js`, or you can target latest version `https://cdn.adjust.com/adjust-latest.min.js` if you want automatic updates without need to change the target file. The sdk files are cached so they are served as fast as possible, and the cache is refreshed every half an hour. If you want updates immediately make sure to target specific version. You may want to use [Subresource Integrity (SRI)](sri-mdn) feature to mitigate XSS attacks risk. In this case you could use the loading snippet that enables SRI check instructing browser to validate the script before running it: ```html diff --git a/VERSION b/VERSION index c7cb1311..8a30e8f9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.3.1 +5.4.0 diff --git a/dist/INTEGRITY b/dist/INTEGRITY index 8d997e12..7d84a93e 100644 --- a/dist/INTEGRITY +++ b/dist/INTEGRITY @@ -1 +1 @@ -sha384-+pCaiYvw8skhJvXi2IbObtUjc5tGhCdevXsPqeJelEVHz0/mKzMnkvQ758kbYM1k +sha384-LI7u4QN3zwrvM7cl2KryLTxj5wtSZqQ8aV6ORY7gm/zm0lQb32ZQb7l7k0oKIxMq \ No newline at end of file diff --git a/dist/adjust-latest.d.ts b/dist/adjust-latest.d.ts index 04216c53..cb73fc20 100644 --- a/dist/adjust-latest.d.ts +++ b/dist/adjust-latest.d.ts @@ -68,7 +68,7 @@ declare namespace Adjust { } type LogLevel = 'none' | 'error' | 'warning' | 'info' | 'verbose' - + interface Attribution { /** Adjust device identifier */ @@ -116,16 +116,21 @@ declare namespace Adjust { /** Optional. */ externalDeviceId?: string; - /** Optional. By default all requests go to Adjust's endpoints. You are able to redirect all requests to your custom - * endpoint. */ - customUrl?: string; - /** Optional. By default this param is set to `10`. It is possible to override this limit but make sure that it is a * positive number and not too big. This will cache last `n` deduplication ids (defined by this param) and use them * to deduplicate events with repeating ids. */ eventDeduplicationListLimit?: number; - /** Optional. */ + /** Optional. By default all requests go to Adjust's endpoints. You are able to redirect all requests to your custom + * endpoint. */ + customUrl?: string; + + /** Optional. The data residency feature allows you to choose the country in which Adjust will store your data. This + * is useful if you are operating in a country with strict privacy requirements. When you set up data residency, + * Adjust will store your data in a data center located in the region your have chosen. */ + dataResidency?: 'EU' | 'TR' | 'US'; + + /** Optional. The Adjust SDK can use the url strategy setting to prioritise regional endpoints. */ urlStrategy?: 'india' | 'china'; /** @@ -202,7 +207,7 @@ declare namespace Adjust { * @example * const attribution = Adjust.getAttribution(); */ - function getAttribution (): Attribution | undefined + function getAttribution(): Attribution | undefined /** * Get web_uuid - a unique ID of user generated per subdomain and per browser @@ -212,7 +217,7 @@ declare namespace Adjust { * @example * const webUuid = Adjust.getWebUUID(); */ - function getWebUUID (): string | undefined + function getWebUUID(): string | undefined /** * Track event with already initiated Adjust SDK instance @@ -363,6 +368,17 @@ declare namespace Adjust { * - `none` - won't print anything */ logLevel?: LogLevel; + + /** Optional. The data residency feature allows you to choose the country in which Adjust will store your data. This + * is useful if you are operating in a country with strict privacy requirements. When you set up data residency, + * Adjust will store your data in a data center located in the region your have chosen. */ + dataResidency?: 'EU' | 'TR' | 'US'; + + /** Optional. Callback which is called when SmartBanner view is created and shown. */ + onCreated?: () => any; + + /** Optional. Callback which is called when SmartBanner is being dismissed with a closing button on it. */ + onDismissed?: () => any; } /** @@ -377,6 +393,13 @@ declare namespace Adjust { * webToken: 'YOUR_WEB_TOKEN', * logLevel: 'verbose' * }); + * + * @example + * Adjust.initSmartBanner({ + * webToken: 'YOUR_WEB_TOKEN', + * logLevel: 'error', + * dataResidency: 'EU', + * }); */ function initSmartBanner(options: SmartBannerOptions): void diff --git a/dist/adjust-latest.js b/dist/adjust-latest.js index f7343293..1eacc3cd 100644 --- a/dist/adjust-latest.js +++ b/dist/adjust-latest.js @@ -1822,6 +1822,34 @@ function _defineProperty(obj, key, value) { return obj; } +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/objectSpread2.js + + +function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); + } + + return keys; +} + +function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + + return target; +} ;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; @@ -1965,6 +1993,38 @@ var STORAGE_TYPES = { INDEXED_DB: 'indexedDB', LOCAL_STORAGE: 'localStorage' }; +var ENDPOINTS = { + default: { + endpointName: 'Default', + app: 'https://app.adjust.com', + gdpr: 'https://gdpr.adjust.com' + }, + india: { + endpointName: 'Indian', + app: 'https://app.adjust.net.in', + gdpr: 'https://gdpr.adjust.net.in' + }, + china: { + endpointName: 'Chinese', + app: 'https://app.adjust.world', + gdpr: 'https://gdpr.adjust.world' + }, + EU: { + endpointName: 'EU', + app: 'https://app.eu.adjust.com', + gdpr: 'https://gdpr.eu.adjust.com' + }, + TR: { + endpointName: 'TR', + app: 'https://app.tr.adjust.com', + gdpr: 'https://gdpr.tr.adjust.com' + }, + US: { + endpointName: 'US', + app: 'https://app.us.adjust.com', + gdpr: 'https://gdpr.us.adjust.com' + } +}; ;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/typeof.js function _typeof(obj) { "@babel/helpers - typeof"; @@ -1980,9 +2040,6 @@ function _typeof(obj) { -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } /** * Build human readable list @@ -2092,7 +2149,7 @@ function convertToMap /*: Array<{ key: string, value: T }>*/ = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; return array.reduce(function (acc, o) { - return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, o.key, o.value)); + return _objectSpread2(_objectSpread2({}, acc), {}, _defineProperty({}, o.key, o.value)); }, {}); } /** @@ -2161,7 +2218,7 @@ function reducer key = _ref2[0], value = _ref2[1]; - return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, key, value)); + return _objectSpread2(_objectSpread2({}, acc), {}, _defineProperty({}, key, value)); } /** * Extracts object entries in the [key, value] format @@ -2230,7 +2287,7 @@ function isEmptyEntry(value |}*/ var Globals = { namespace: "adjust-sdk" || 0, - version: "5.3.1" || 0, + version: "5.4.0" || 0, env: "production" }; /* harmony default export */ const globals = (Globals); @@ -2423,10 +2480,6 @@ var Logger = { -function config_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function config_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? config_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : config_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - /*:: // import { type BaseParamsT, type CustomConfigT, type InitOptionsT, type BaseParamsListT, type BaseParamsMandatoryListT, type CustomConfigListT } from './types';*/ @@ -2488,7 +2541,7 @@ var _allowedParams var _allowedConfig /*: CustomConfigListT*/ -= ['urlStrategy', 'customUrl', 'eventDeduplicationListLimit', 'namespace']; += ['customUrl', 'dataResidency', 'urlStrategy', 'eventDeduplicationListLimit', 'namespace']; /** * Global configuration object used across the sdk * @@ -2529,7 +2582,7 @@ function isInitialised() function getBaseParams() /*: BaseParamsT*/ { - return config_objectSpread({}, _baseParams); + return _objectSpread2({}, _baseParams); } /** * Set base params and custom config for the sdk to run @@ -2575,7 +2628,7 @@ function set(options function getCustomConfig() /*: CustomConfigT*/ { - return config_objectSpread({}, _customConfig); + return _objectSpread2({}, _customConfig); } /** * Check if there are missing mandatory parameters @@ -2614,7 +2667,7 @@ function destroy() _customConfig = {}; } -var Config = config_objectSpread(config_objectSpread({}, _baseConfig), {}, { +var Config = _objectSpread2(_objectSpread2({}, _baseConfig), {}, { set: set, getBaseParams: getBaseParams, getCustomConfig: getCustomConfig, @@ -2885,11 +2938,6 @@ function isComplexStoreField(field -function scheme_map_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function scheme_map_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? scheme_map_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : scheme_map_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - - /** @@ -2978,7 +3026,7 @@ function _flipStoreScheme(storeName return _getShortKey(storeName, key); }) } : {}; - return scheme_map_objectSpread(scheme_map_objectSpread(scheme_map_objectSpread({ + return _objectSpread2(_objectSpread2(_objectSpread2({ key: key }, values), keys), composite); } @@ -3175,10 +3223,6 @@ function valueIsRecord(value -function converter_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function converter_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? converter_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : converter_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - @@ -3273,7 +3317,7 @@ function convertRecord(storeName key = _ref4[0], value = _ref4[1]; - return converter_objectSpread(converter_objectSpread({}, acc), {}, _defineProperty({}, key, value)); + return _objectSpread2(_objectSpread2({}, acc), {}, _defineProperty({}, key, value)); }, {}); } /** @@ -3541,16 +3585,13 @@ function timePassed(d1 ;// CONCATENATED MODULE: ./src/sdk/activity-state.js -function activity_state_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function activity_state_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? activity_state_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : activity_state_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - /*:: // import { type UrlT, type ActivityStateMapT, type AttributionMapT, type CommonRequestParams } from './types';*/ + /** * Reference to the activity state * @@ -3590,7 +3631,7 @@ var _active function currentGetter() /*: ActivityStateMapT*/ { - return _started ? activity_state_objectSpread({}, _activityState) : {}; + return _started ? _objectSpread2({}, _activityState) : {}; } /** * Set current activity state @@ -3603,7 +3644,7 @@ function currentSetter() { var params /*: ActivityStateMapT*/ = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - _activityState = _started ? activity_state_objectSpread({}, params) : {}; + _activityState = _started ? _objectSpread2({}, params) : {}; } /** * Initiate in-memory activity state @@ -3658,7 +3699,7 @@ function _update(params ) /*: void*/ { - _activityState = activity_state_objectSpread(activity_state_objectSpread({}, _activityState), params); + _activityState = _objectSpread2(_objectSpread2({}, _activityState), params); } /** * Set active flag to true when going foreground @@ -4290,11 +4331,6 @@ var QuickStorage = /*#__PURE__*/function () { ;// CONCATENATED MODULE: ./src/sdk/preferences.js -function preferences_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function preferences_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? preferences_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : preferences_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - - @@ -4347,7 +4383,7 @@ function _getPreferences() _setPreferences(); } - return _preferences ? preferences_objectSpread({}, _preferences) : null; + return _preferences ? _objectSpread2({}, _preferences) : null; } /** * Set local reference of the preserved preferences @@ -4387,8 +4423,8 @@ function setDisabled(value ) /*: void*/ { - var sdkDisabled = value ? preferences_objectSpread({}, value) : null; - quick_storage.stores[_storeName] = preferences_objectSpread(preferences_objectSpread({}, _getPreferences()), {}, { + var sdkDisabled = value ? _objectSpread2({}, value) : null; + quick_storage.stores[_storeName] = _objectSpread2(_objectSpread2({}, _getPreferences()), {}, { sdkDisabled: sdkDisabled }); @@ -4422,8 +4458,8 @@ function setThirdPartySharing(value ) /*: void*/ { - var thirdPartySharingDisabled = value ? preferences_objectSpread({}, value) : null; - quick_storage.stores[_storeName] = preferences_objectSpread(preferences_objectSpread({}, _getPreferences()), {}, { + var thirdPartySharingDisabled = value ? _objectSpread2({}, value) : null; + quick_storage.stores[_storeName] = _objectSpread2(_objectSpread2({}, _getPreferences()), {}, { thirdPartySharingDisabled: thirdPartySharingDisabled }); @@ -4463,7 +4499,7 @@ function recover() = quick_storage.stores[_storeName]; if (!stored) { - quick_storage.stores[_storeName] = preferences_objectSpread({}, _preferences); + quick_storage.stores[_storeName] = _objectSpread2({}, _preferences); } } @@ -4474,9 +4510,6 @@ function recover() -function indexeddb_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function indexeddb_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? indexeddb_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : indexeddb_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } var indexeddb_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; @@ -4950,7 +4983,7 @@ var IndexedDBWrapper = /*#__PURE__*/function () { if (this.targetIsObject(target)) { // target is a StoredRecord // extend target with composite path if needed and return it - return composite ? indexeddb_objectSpread(_defineProperty({}, options.keyPath, composite.map(function (key) { + return composite ? _objectSpread2(_defineProperty({}, options.keyPath, composite.map(function (key) { return target[key]; }).join('')), target) : target; } @@ -5553,17 +5586,18 @@ var IndexedDBWrapper = /*#__PURE__*/function () { if (IndexedDBWrapper.isSupportedPromise) { return IndexedDBWrapper.isSupportedPromise; } else { + var notSupportedMessage = 'IndexedDB is not supported in this browser'; IndexedDBWrapper.isSupportedPromise = new indexeddb_Promise(function (resolve) { var indexedDB = IndexedDBWrapper.getIndexedDB(); var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); if (!indexedDB || iOS) { - logger.warn('IndexedDB is not supported in this browser'); + logger.warn(notSupportedMessage); resolve(false); } else { var dbOpenablePromise = IndexedDBWrapper.tryOpen(indexedDB).then(function (dbOpenable) { if (!dbOpenable) { - logger.warn('IndexedDB is not supported in this browser'); + logger.warn(notSupportedMessage); } return dbOpenable; @@ -5603,9 +5637,6 @@ _defineProperty(IndexedDBWrapper, "isSupportedPromise", null); -function localstorage_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function localstorage_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? localstorage_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : localstorage_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } var localstorage_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; @@ -5760,7 +5791,7 @@ var LocalStorageWrapper = /*#__PURE__*/function () { ; if (!id) { - target = localstorage_objectSpread({}, item); + target = _objectSpread2({}, item); } else { var ids = Array.isArray(id) ? id.slice() : [id]; target = keys.map(function (key, index) { @@ -5836,9 +5867,9 @@ var LocalStorageWrapper = /*#__PURE__*/function () { /*: StoredRecord*/ { var composite = this.getCompositeKeys(options); - return composite ? localstorage_objectSpread(_defineProperty({}, options.keyPath, composite.map(function (key) { + return composite ? _objectSpread2(_defineProperty({}, options.keyPath, composite.map(function (key) { return target[key]; - }).join('')), target) : options.autoIncrement && next ? localstorage_objectSpread(_defineProperty({}, options.keyPath, next), target) : localstorage_objectSpread({}, target); + }).join('')), target) : options.autoIncrement && next ? _objectSpread2(_defineProperty({}, options.keyPath, next), target) : _objectSpread2({}, target); } /** * Prepare the result to be return depending on the composite key definition @@ -6358,10 +6389,6 @@ _defineProperty(LocalStorageWrapper, "isSupportedPromise", null); -function storage_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function storage_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? storage_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : storage_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var storage_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; @@ -6738,7 +6765,7 @@ function storage_init(dbName return _initializationPromise; } -/* harmony default export */ const storage = (storage_objectSpread({ +/* harmony default export */ const storage = (_objectSpread2({ init: storage_init, getType: getType }, _augment())); @@ -6746,10 +6773,6 @@ function storage_init(dbName -function default_params_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function default_params_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? default_params_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : default_params_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var default_params_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type NavigatorT, type CreatedAtT, type SentAtT, type WebUuidT, type TrackEnabledT, type PlatformT, type LanguageT, type MachineTypeT, type QueueSizeT, type DefaultParamsT } from './types';*/ @@ -6913,17 +6936,13 @@ function defaultParams() /*: Promise*/ { return _getQueueSize().then(function (queueSize) { - return default_params_objectSpread(default_params_objectSpread(default_params_objectSpread(default_params_objectSpread(default_params_objectSpread(default_params_objectSpread(default_params_objectSpread(default_params_objectSpread({}, _getCreatedAt()), _getSentAt()), _getWebUuid()), _getTrackEnabled()), _getPlatform()), _getLanguage()), _getMachineType()), queueSize); + return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, _getCreatedAt()), _getSentAt()), _getWebUuid()), _getTrackEnabled()), _getPlatform()), _getLanguage()), _getMachineType()), queueSize); }); } ;// CONCATENATED MODULE: ./src/sdk/http.js -function http_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function http_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? http_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : http_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var http_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type UrlT, type DefaultParamsT, type HttpSuccessResponseT, type HttpErrorResponseT, type HttpRequestParamsT, type ErrorCodeT } from './types';*/ @@ -7088,7 +7107,7 @@ function _encodeParams(params }); }; - var allParams = entries(http_objectSpread(http_objectSpread(http_objectSpread({}, config.getBaseParams()), defaultParams), params)).map(function (_ref5 + var allParams = entries(_objectSpread2(_objectSpread2(_objectSpread2({}, config.getBaseParams()), defaultParams), params)).map(function (_ref5 /*:: */ ) { var _ref6 = _slicedToArray(_ref5 @@ -7609,9 +7628,8 @@ function listeners_destroy() ;// CONCATENATED MODULE: ./src/sdk/url-strategy.ts -var _endpointMap, _endpointNiceNames; +var _endpointMap; -var url_strategy_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; @@ -7623,24 +7641,54 @@ var UrlStrategy; UrlStrategy["China"] = "china"; })(UrlStrategy || (UrlStrategy = {})); +var DataResidency; + +(function (DataResidency) { + DataResidency["EU"] = "EU"; + DataResidency["TR"] = "TR"; + DataResidency["US"] = "US"; +})(DataResidency || (DataResidency = {})); + +function incorrectOptionIgnoredMessage(higherPriority +/*: string*/ +, lowerPriority +/*: string*/ +) { + logger.warn("Both ".concat(higherPriority, " and ").concat(lowerPriority, " are set in config, ").concat(lowerPriority, " will be ignored")); +} /** * Returns a map of base URLs or a list of endpoint names depending on SDK configuration */ + + function getEndpointPreference() /*: BaseUrlsMap | EndpointName[]*/ { var _Config$getCustomConf = config.getCustomConfig(), customUrl = _Config$getCustomConf.customUrl, - urlStrategy = _Config$getCustomConf.urlStrategy; + urlStrategy = _Config$getCustomConf.urlStrategy, + dataResidency = _Config$getCustomConf.dataResidency; if (customUrl) { // If custom URL is set then send all requests there + if (dataResidency || urlStrategy) { + incorrectOptionIgnoredMessage('customUrl', dataResidency ? 'dataResidency' : 'urlStrategy'); + } + return { app: customUrl, gdpr: customUrl }; } + if (dataResidency && urlStrategy) { + incorrectOptionIgnoredMessage('dataResidency', 'urlStrategy'); + } + + if (dataResidency) { + return [dataResidency]; + } + if (urlStrategy === UrlStrategy.India) { return [UrlStrategy.India, UrlStrategy.Default]; } @@ -7653,78 +7701,20 @@ function getEndpointPreference() } var endpointMap -/*: Record*/ -= (_endpointMap = {}, _defineProperty(_endpointMap, UrlStrategy.Default, { - app: 'https://app.adjust.com', - gdpr: 'https://gdpr.adjust.com' -}), _defineProperty(_endpointMap, UrlStrategy.India, { - app: 'https://app.adjust.net.in', - gdpr: 'https://gdpr.adjust.net.in' -}), _defineProperty(_endpointMap, UrlStrategy.China, { - app: 'https://app.adjust.world', - gdpr: 'https://gdpr.adjust.world' -}), _endpointMap); -var endpointNiceNames -/*: Record*/ -= (_endpointNiceNames = {}, _defineProperty(_endpointNiceNames, UrlStrategy.Default, 'default'), _defineProperty(_endpointNiceNames, UrlStrategy.India, 'Indian'), _defineProperty(_endpointNiceNames, UrlStrategy.China, 'Chinese'), _endpointNiceNames); -/** - * Gets the list of preferred endpoints and wraps `sendRequest` function with iterative retries until available - * endpoint found or another error occurred. - */ - -function urlStrategyRetries -/*:: */ -(sendRequest -/*: (urls: BaseUrlsMap) => Promise*/ -) -/*: Promise*/ -{ - var endpoints - /*: Record*/ - = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : endpointMap; - var preferredUrls = getEndpointPreference(); - - if (!Array.isArray(preferredUrls)) { - // There is only one endpoint - return sendRequest(preferredUrls); - } else { - var attempt = 0; - - var trySendRequest = function trySendRequest() - /*: Promise*/ - { - var endpointKey = preferredUrls[attempt++]; - var urlsMap = endpoints[endpointKey]; - return sendRequest(urlsMap).catch(function (reason) { - if (reason.code === 'NO_CONNECTION') { - logger.log("Failed to connect ".concat(endpointNiceNames[endpointKey], " endpoint")); - - if (attempt < preferredUrls.length) { - logger.log("Trying ".concat(endpointNiceNames[preferredUrls[attempt]], " one")); - return trySendRequest(); // Trying next endpoint - } - } // Another error occurred or we ran out of attempts, re-throw - - - throw reason; - }); - }; - - return trySendRequest(); - } -} +/*: Record*/ += (_endpointMap = {}, _defineProperty(_endpointMap, UrlStrategy.Default, ENDPOINTS["default"]), _defineProperty(_endpointMap, UrlStrategy.India, ENDPOINTS.india), _defineProperty(_endpointMap, UrlStrategy.China, ENDPOINTS.china), _defineProperty(_endpointMap, DataResidency.EU, ENDPOINTS.EU), _defineProperty(_endpointMap, DataResidency.TR, ENDPOINTS.TR), _defineProperty(_endpointMap, DataResidency.US, ENDPOINTS.US), _endpointMap); function getPreferredUrls(endpoints /*: Partial>*/ ) /*: BaseUrlsMap[]*/ { - var preferredUrls = getEndpointPreference(); + var preference = getEndpointPreference(); - if (!Array.isArray(preferredUrls)) { - return [preferredUrls]; + if (!Array.isArray(preference)) { + return [preference]; } else { - var res = preferredUrls.map(function (strategy) { + var res = preference.map(function (strategy) { return endpoints[strategy] || null; }).filter(function (i) { return ( @@ -7740,7 +7730,7 @@ function getBaseUrlsIterator() /*: BaseUrlsIterator*/ { var endpoints - /*: Partial>*/ + /*: Partial>*/ = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : endpointMap; var _urls = getPreferredUrls(endpoints); @@ -7771,10 +7761,6 @@ function getBaseUrlsIterator() -function request_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function request_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? request_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : request_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var request_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type HttpSuccessResponseT, type HttpErrorResponseT, type HttpContinueCbT, type BackOffStrategyT, type WaitT, type UrlT, type MethodT, type RequestParamsT, type HttpRequestParamsT } from './types';*/ @@ -7874,7 +7860,7 @@ var Request = function Request() { var _params /*: RequestParamsT*/ - = request_objectSpread({}, params); + = _objectSpread2({}, params); /** * Optional continue callback per instance or per request * @@ -7902,7 +7888,7 @@ var Request = function Request() { var _baseUrlsIterator /*: BaseUrlsIterator*/ - = getBaseUrlsIterator(); + ; /** * Current base urls map to send request */ @@ -7910,7 +7896,7 @@ var Request = function Request() { var _baseUrlsIteratorCurrent /*: { value: BaseUrlsMap, done: boolean }*/ - = _baseUrlsIterator.next(); + ; /** * Reset iterator state and get the first endpoint to use it in the next try */ @@ -8038,10 +8024,10 @@ var Request = function Request() { } if (!isEmpty(params)) { - _params = request_objectSpread({}, params); + _params = _objectSpread2({}, params); } - _params = request_objectSpread({ + _params = _objectSpread2({ createdAt: getTimestamp() }, _params); @@ -8100,6 +8086,12 @@ var Request = function Request() { retrying = _ref3 /*:: */ .retrying; + + if (!_baseUrlsIterator) { + _baseUrlsIterator = getBaseUrlsIterator(); + _baseUrlsIteratorCurrent = _baseUrlsIterator.next(); + } + _wait = wait ? _prepareWait(wait) : _wait; if (_skip(wait)) { @@ -8129,7 +8121,7 @@ var Request = function Request() { endpoint: _getBaseUrl(_baseUrlsIteratorCurrent.value, _url), url: _url, method: _method, - params: request_objectSpread({ + params: _objectSpread2({ attempts: 1 }, _params) }); @@ -8189,7 +8181,7 @@ var Request = function Request() { endpoint: options.endpoint, url: options.url, method: options.method, - params: request_objectSpread(request_objectSpread({}, filteredParams), {}, { + params: _objectSpread2(_objectSpread2({}, filteredParams), {}, { attempts: (_attempts.request ? _attempts.request + 1 : 1) + _attempts.connection }) }).then(function (result) { @@ -8212,7 +8204,7 @@ var Request = function Request() { { _url = _default.url; _method = _default.method; - _params = request_objectSpread({}, _default.params); + _params = _objectSpread2({}, _default.params); _continueCb = _default.continueCb; } /** @@ -8610,10 +8602,6 @@ function disable_status() ;// CONCATENATED MODULE: ./src/sdk/identity.js -function identity_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function identity_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? identity_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : identity_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var identity_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type ActivityStateMapT } from './types';*/ @@ -8764,7 +8752,7 @@ function persist() return identity_Promise.resolve(null); } - var activityState = identity_objectSpread(identity_objectSpread({}, activity_state.current), {}, { + var activityState = _objectSpread2(_objectSpread2({}, activity_state.current), {}, { lastActive: Date.now() }); @@ -8837,10 +8825,6 @@ function identity_destroy() -function queue_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function queue_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? queue_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : queue_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var queue_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type HttpSuccessResponseT, type HttpErrorResponseT, type HttpFinishCbT, type WaitT, type UrlT, type MethodT, type RequestParamsT, type ActivityStateMapT } from './types';*/ @@ -9025,7 +9009,7 @@ function push(_ref timestamp: _prepareTimestamp(), url: url, method: method, - params: queue_objectSpread(queue_objectSpread({}, activity_state.getParams(url)), filteredParams) + params: _objectSpread2(_objectSpread2({}, activity_state.getParams(url)), filteredParams) }; if (timestamp) { @@ -9077,7 +9061,7 @@ function _prepareToSend() return _request.send({ url: url, method: method, - params: queue_objectSpread(queue_objectSpread({}, params), {}, { + params: _objectSpread2(_objectSpread2({}, params), {}, { createdAt: getTimestamp(createdAt || timestamp) }), wait: wait || _checkWait() @@ -9735,10 +9719,6 @@ function _checkSession() -function attribution_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function attribution_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? attribution_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : attribution_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var attribution_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type HttpSuccessResponseT, type HttpErrorResponseT, type HttpFinishCbT, type HttpRetryCbT, type AttributionStateT, type AttributionWhiteListT, type ActivityStateMapT, type AttributionMapT } from './types';*/ @@ -9855,7 +9835,7 @@ function _setAttribution(result }).reduce(reducer, { adid: result.adid }); - activity_state.current = attribution_objectSpread(attribution_objectSpread({}, activity_state.current), {}, { + activity_state.current = _objectSpread2(_objectSpread2({}, activity_state.current), {}, { attribution: attribution }); return persist().then(function () { @@ -9921,7 +9901,7 @@ function check(sessionResult } attribution_request.send({ - params: attribution_objectSpread({ + params: _objectSpread2({ initiatedBy: !sessionResult ? 'sdk' : 'backend' }, activity_state.getParams()), wait: askIn @@ -9945,11 +9925,6 @@ function attribution_destroy() ;// CONCATENATED MODULE: ./src/sdk/gdpr-forget-device.js -function gdpr_forget_device_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function gdpr_forget_device_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? gdpr_forget_device_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : gdpr_forget_device_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - - @@ -10007,7 +9982,7 @@ function forget(force } gdpr_forget_device_request.send({ - params: gdpr_forget_device_objectSpread({}, activity_state.getParams()) + params: _objectSpread2({}, activity_state.getParams()) }).then(function () { publish('sdk:gdpr-forget-me'); }); @@ -10276,10 +10251,6 @@ function scheduler_destroy() ;// CONCATENATED MODULE: ./src/sdk/event.js -function event_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function event_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? event_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : event_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var event_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type EventParamsT, type EventRequestParamsT, type GlobalParamsMapT, type GlobalKeyValueParamsT } from './types';*/ @@ -10367,18 +10338,18 @@ function event_prepareParams(params .partnerParams; var globalParams = {}; - var baseParams = event_objectSpread({ + var baseParams = _objectSpread2({ eventToken: params.eventToken, deduplicationId: params.deduplicationId }, _getRevenue(params.revenue, params.currency)); var eventCallbackParams /*: GlobalKeyValueParamsT*/ - = event_objectSpread(event_objectSpread({}, convertToMap(callbackParams)), convertToMap(params.callbackParams)); + = _objectSpread2(_objectSpread2({}, convertToMap(callbackParams)), convertToMap(params.callbackParams)); var eventPartnerParams /*: GlobalKeyValueParamsT*/ - = event_objectSpread(event_objectSpread({}, convertToMap(partnerParams)), convertToMap(params.partnerParams)); + = _objectSpread2(_objectSpread2({}, convertToMap(partnerParams)), convertToMap(params.partnerParams)); if (!isEmpty(eventCallbackParams)) { globalParams.callbackParams = eventCallbackParams; @@ -10388,7 +10359,7 @@ function event_prepareParams(params globalParams.partnerParams = eventPartnerParams; } - return event_objectSpread(event_objectSpread({}, baseParams), globalParams); + return _objectSpread2(_objectSpread2({}, baseParams), globalParams); } /** * Get event deduplication ids @@ -10655,162 +10626,10 @@ var local_storage_storage = { getItem: getItem, setItem: setItem }; -;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/errors.ts -/*:: export interface NetworkError { - status: number; - code?: string; - message: string; -}*/ -var NoConnectionError -/*: NetworkError*/ -= { - status: 0, - code: 'NO_CONNECTION', - // for compatibility with UrlStrategy - message: 'No internet connectivity' -}; -;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/network.ts - - - - - -var network_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; - - - - - -var Network = /*#__PURE__*/function () { - function Network() { - _classCallCheck(this, Network); - } - - _createClass(Network, null, [{ - key: "xhr", - value: - /** - * Creates an XMLHttpRequest object and sends a GET request with provided encoded URL - * @param url encoded URL - */ - function xhr - /*:: */ - (url - /*: string*/ - ) - /*: Promise*/ - { - return new network_Promise(function (resolve, reject - /*: (err: NetworkError) => void*/ - ) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url); - var headers = [['Client-SDK', "js".concat(globals.version)], ['Content-Type', 'application/json']]; - headers.forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - key = _ref2[0], - value = _ref2[1]; - - xhr.setRequestHeader(key, value); - }); - - xhr.onerror = function () { - return reject(NoConnectionError); - }; - - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4) { - return; - } - - var okStatus = xhr.status >= 200 && xhr.status < 300; - var json = parseJson(xhr.responseText); - - if (xhr.status === 0) { - reject(NoConnectionError); - } else { - if (okStatus) { - resolve(json); - } else { - reject({ - status: xhr.status, - message: json || xhr.responseText || '' - }); - } - } - }; - - xhr.send(); - }); - } - }, { - key: "encodeParams", - value: function encodeParams(params - /*: Record*/ - ) - /*: string*/ - { - return Object.keys(params).map(function (key) { - return [encodeURIComponent(key), encodeURIComponent(params[key])].join('='); - }).join('&'); - } - /** - * Returns last succesfull endpoint or default (`https://app.adjust.com`) one - */ - - }, { - key: "getEndpoint", - value: function getEndpoint() - /*: string*/ - { - return Network.lastSuccessfulEndpoint || Network.defaultEndpoint; - } - /** - * Sends a request to provided path choosing origin with `urlStrategyRetries` - * @param path - * @param params non-encoded parameters of the request - */ - - }, { - key: "request", - value: function request - /*:: */ - (path - /*: string*/ - , params - /*: Record*/ - ) - /*: Promise*/ - { - return urlStrategyRetries(function (baseUrlsMap) { - var origin = baseUrlsMap.app; - var encodedParams = params ? "?".concat(Network.encodeParams(params)) : ''; - return Network.xhr("".concat(origin).concat(path).concat(encodedParams)).then(function (result - /*: T*/ - ) { - Network.lastSuccessfulEndpoint = baseUrlsMap.app; - return result; - }).catch(function (err - /*: NetworkError*/ - ) { - Network.lastSuccessfulEndpoint = undefined; - throw err; - }); - }); - } - }]); - - return Network; -}(); - -_defineProperty(Network, "defaultEndpoint", 'https://app.adjust.com'); - -_defineProperty(Network, "lastSuccessfulEndpoint", void 0); -;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/api.ts +;// CONCATENATED MODULE: ./src/sdk/smart-banner/api.ts var api_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; - var Position; (function (Position) { @@ -10870,11 +10689,13 @@ function fetchSmartBannerData(webToken /*: string*/ , deviceOs /*: DeviceOS*/ +, network +/*: Network*/ ) /*: Promise*/ { var path = '/smart_banner'; - return Network.request(path, { + return network.request(path, { 'app_web_token': webToken }).then(function (banners) { var banner = banners.find(function (item) { @@ -11155,56 +10976,715 @@ var SmartBannerView = /*#__PURE__*/function () { return SmartBannerView; }(); -;// CONCATENATED MODULE: ./src/sdk/smart-banner/smart-banner.ts - - - - -var smart_banner_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; - - - +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/errors.ts +/*:: export interface NetworkError { + status: number; + message: string; +}*/ +var NoConnectionError +/*: NetworkError*/ += { + status: 0, + message: 'No internet connectivity' +}; +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/xhr-network.ts +var xhr_network_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; -/** - * Adjust Web SDK Smart Banner - */ -var SmartBanner = /*#__PURE__*/function () { - function SmartBanner() { - _classCallCheck(this, SmartBanner); - _defineProperty(this, "dismissedStorageKey", 'closed'); - _defineProperty(this, "timer", null); - _defineProperty(this, "dataFetchPromise", void 0); - _defineProperty(this, "banner", void 0); +/** Sends HTTP GET request using XMLHttpRequest */ +var XhrNetwork = /*#__PURE__*/function () { + function XhrNetwork(origin + /*: string*/ + ) { + _classCallCheck(this, XhrNetwork); - _defineProperty(this, "logLevel", void 0); + this.origin + /*:: ?*/ + = origin + /*:: ?*/ + ; } - _createClass(SmartBanner, [{ - key: "init", - value: - /** - * Initiate Smart Banner - * - * @param webToken token used to get data from backend - */ - function init(webToken + _createClass(XhrNetwork, [{ + key: "endpoint", + get: function get() /*: string*/ - ) { + { + if (!this.origin) { + throw Error('XhrNetwork: Origin not defined'); + } + + return this.origin; + }, + set: function set(value + /*: string*/ + ) { + this.origin = value; + } + /** + * Creates an XMLHttpRequest object and sends a GET request with provided encoded URL + * @param url encoded URL + */ + + }, { + key: "xhr", + value: function xhr + /*:: */ + (url + /*: string*/ + ) + /*: Promise*/ + { + return new xhr_network_Promise(function (resolve, reject + /*: (err: NetworkError) => void*/ + ) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + var headers = [['Client-SDK', "js".concat(globals.version)], ['Content-Type', 'application/json']]; + headers.forEach(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + key = _ref2[0], + value = _ref2[1]; + + xhr.setRequestHeader(key, value); + }); + + xhr.onerror = function () { + return reject(NoConnectionError); + }; + + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4) { + return; + } + + var okStatus = xhr.status >= 200 && xhr.status < 300; + var json = parseJson(xhr.responseText); + + if (xhr.status === 0) { + reject(NoConnectionError); + } else { + if (okStatus) { + resolve(json); + } else { + reject({ + status: xhr.status, + message: json || xhr.responseText || '' + }); + } + } + }; + + xhr.send(); + }); + } + }, { + key: "encodeParams", + value: function encodeParams(params + /*: Record*/ + ) + /*: string*/ + { + return Object.keys(params).map(function (key) { + return [encodeURIComponent(key), encodeURIComponent(params[key])].join('='); + }).join('&'); + } + }, { + key: "request", + value: function request + /*:: */ + (path + /*: string*/ + , params + /*: Record*/ + ) + /*: Promise*/ + { + var encodedParams = params ? "?".concat(this.encodeParams(params)) : ''; + return this.xhr("".concat(this.endpoint).concat(path).concat(encodedParams)); + } + }]); + + return XhrNetwork; +}(); +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js +function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return self; +} +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js +function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; + return _setPrototypeOf(o, p); +} +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/inherits.js + +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true + } + }); + Object.defineProperty(subClass, "prototype", { + writable: false + }); + if (superClass) _setPrototypeOf(subClass, superClass); +} +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/getPrototypeOf.js +function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + return _getPrototypeOf(o); +} +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/isNativeReflectConstruct.js +function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); + return true; + } catch (e) { + return false; + } +} +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/possibleConstructorReturn.js + + +function _possibleConstructorReturn(self, call) { + if (call && (_typeof(call) === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); + } + + return _assertThisInitialized(self); +} +;// CONCATENATED MODULE: ./node_modules/@babel/runtime/helpers/esm/createSuper.js + + + +function _createSuper(Derived) { + var hasNativeReflectConstruct = _isNativeReflectConstruct(); + return function _createSuperInternal() { + var Super = _getPrototypeOf(Derived), + result; + + if (hasNativeReflectConstruct) { + var NewTarget = _getPrototypeOf(this).constructor; + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + + return _possibleConstructorReturn(this, result); + }; +} +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/network.ts + + + +var network_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; +/*:: export interface Network { + endpoint: string; + request: (path: string, params?: Record) => Promise; +}*/ + + +var NetworkDecorator = /*#__PURE__*/function () { + function NetworkDecorator(network + /*: Network*/ + ) { + _classCallCheck(this, NetworkDecorator); + + this.network + /*:: */ + = network + /*:: */ + ; + } + + _createClass(NetworkDecorator, [{ + key: "endpoint", + get: function get() + /*: string*/ + { + return this.network.endpoint; + }, + set: function set(value + /*: string*/ + ) { + this.network.endpoint = value; + } + }, { + key: "request", + value: function request + /*:: */ + (path + /*: string*/ + , params + /*: Record*/ + ) + /*: Promise*/ + { + return this.network.request(path, params); + } + }]); + + return NetworkDecorator; +}(); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/url-strategy/url-strategy.ts + + + + +var url_strategy_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; + + + +/*:: export type BaseUrlsMap = { + endpointName: string; + app: string; + gdpr: string; +}*/ + +var url_strategy_UrlStrategy = /*#__PURE__*/function () { + function UrlStrategy(preferredUrls + /*: () => BaseUrlsMap[]*/ + ) { + _classCallCheck(this, UrlStrategy); + + this.preferredUrls + /*:: */ + = preferredUrls + /*:: */ + ; + } + /** + * Gets the list of preferred endpoints and wraps `sendRequest` function with iterative retries until available + * endpoint found or another error occurred. + */ + + + _createClass(UrlStrategy, [{ + key: "retries", + value: function retries + /*:: */ + (sendRequest + /*: (urls: BaseUrlsMap) => Promise*/ + ) + /*: Promise*/ + { var _this = this; - var logLevel - /*: LogLevel*/ - = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'error'; - this.logLevel = logLevel; - logger.setLogLevel(logLevel); + var attempt = 0; + + var trySendRequest = function trySendRequest() + /*: Promise*/ + { + var preferredUrls = _this.preferredUrls(); + + if (!preferredUrls || preferredUrls.length === 0) { + logger.error(UrlStrategy.NoPreferredUrlsDefinedError.message); + throw UrlStrategy.NoPreferredUrlsDefinedError; + } + + var urlsMap = preferredUrls[attempt++]; + return sendRequest(urlsMap).catch(function (reason + /*: NetworkError*/ + ) { + if (reason === NoConnectionError) { + logger.log("Failed to connect ".concat(urlsMap.endpointName, " endpoint")); + + if (attempt < preferredUrls.length) { + logger.log("Trying ".concat(preferredUrls[attempt].endpointName, " one")); + return trySendRequest(); // Trying next endpoint + } + } // Another error occurred or we ran out of attempts, re-throw + + + throw reason; + }); + }; + + return trySendRequest(); + } + }]); + + return UrlStrategy; +}(); + +_defineProperty(url_strategy_UrlStrategy, "NoPreferredUrlsDefinedError", new ReferenceError('UrlStrategy: No preferred URL defined')); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/url-strategy/blocked-url-bypass.ts + + +var BlockedUrlBypass; + +(function (_BlockedUrlBypass) { + var _endpoints; + + var Default = _BlockedUrlBypass.Default = 'default'; + var India = _BlockedUrlBypass.India = 'india'; + var China = _BlockedUrlBypass.China = 'china'; + /*:: */ + + var endpoints + /*:: */ + = (_endpoints = {}, _defineProperty(_endpoints, BlockedUrlBypass.Default, ENDPOINTS["default"]), _defineProperty(_endpoints, BlockedUrlBypass.India, ENDPOINTS.india), _defineProperty(_endpoints, BlockedUrlBypass.China, ENDPOINTS.china), _endpoints); + + var getPreferredUrlsWithOption = function getPreferredUrlsWithOption(endpoints + /*:: */ + , option + /*:: */ + ) { + if (option === BlockedUrlBypass.India) { + return [endpoints[BlockedUrlBypass.India], endpoints[BlockedUrlBypass.Default]]; + } + + if (option === BlockedUrlBypass.China) { + return [endpoints[BlockedUrlBypass.China], endpoints[BlockedUrlBypass.Default]]; + } + + return [endpoints[BlockedUrlBypass.Default], endpoints[BlockedUrlBypass.India], endpoints[BlockedUrlBypass.China]]; + }; + + function preferredUrlsGetter(option + /*:: */ + ) { + var endpointsMap + /*:: */ + = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : endpoints; + return function () { + return getPreferredUrlsWithOption(endpointsMap, option); + }; + } + + _BlockedUrlBypass.preferredUrlsGetter = preferredUrlsGetter; +})(BlockedUrlBypass || (BlockedUrlBypass = {})); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/url-strategy/custom-url.ts +var CustomUrl; + +(function (_CustomUrl) { + var getPreferredUrlsWithOption = function getPreferredUrlsWithOption(customUrl + /*:: */ + ) { + return [{ + endpointName: "Custom (".concat(customUrl, ")"), + app: customUrl, + gdpr: customUrl + }]; + }; + + function preferredUrlsGetter(customUrl + /*:: */ + ) { + return function () { + return getPreferredUrlsWithOption(customUrl); + }; + } + + _CustomUrl.preferredUrlsGetter = preferredUrlsGetter; +})(CustomUrl || (CustomUrl = {})); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/url-strategy/data-residency.ts + + +var data_residency_DataResidency; + +(function (_DataResidency) { + var _endpoints; + + var EU = _DataResidency.EU = 'EU'; + var TR = _DataResidency.TR = 'TR'; + var US = _DataResidency.US = 'US'; + /*:: */ + + var endpoints + /*:: */ + = (_endpoints = {}, _defineProperty(_endpoints, data_residency_DataResidency.EU, ENDPOINTS.EU), _defineProperty(_endpoints, data_residency_DataResidency.TR, ENDPOINTS.TR), _defineProperty(_endpoints, data_residency_DataResidency.US, ENDPOINTS.US), _endpoints); + + var getPreferredUrlsWithOption = function getPreferredUrlsWithOption(endpoints + /*:: */ + , option + /*:: */ + ) { + return [endpoints[option]]; + }; + + function preferredUrlsGetter(option + /*:: */ + ) { + var endpointsMap + /*:: */ + = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : endpoints; + return function () { + return getPreferredUrlsWithOption(endpointsMap, option); + }; + } + + _DataResidency.preferredUrlsGetter = preferredUrlsGetter; +})(data_residency_DataResidency || (data_residency_DataResidency = {})); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/url-strategy/url-strategy-factory.ts + + + + + +/*:: export type UrlStrategyConfig = { + customUrl: string; + urlStrategy?: never; + dataResidency?: never; +} | { + customUrl?: never; + dataResidency: DataResidency.Region; + urlStrategy?: never; +} | { + customUrl?: never; + dataResidency?: never; + urlStrategy?: BlockedUrlBypass.Strategy; +}*/ + +var UrlStrategyFactory; + +(function (_UrlStrategyFactory) { + var incorrectOptionIgnoredMessage = function incorrectOptionIgnoredMessage(higherPriority + /*:: */ + , lowerPriority + /*:: */ + ) { + logger.warn("Both ".concat(higherPriority, " and ").concat(lowerPriority, " are set in config, ").concat(lowerPriority, " will be ignored")); + }; + + function create(config + /*:: */ + ) + /*:: */ + { + var customUrl = config.customUrl, + dataResidency = config.dataResidency, + urlStrategy = config.urlStrategy; + + if (customUrl) { + if (dataResidency || urlStrategy) { + incorrectOptionIgnoredMessage('customUrl', dataResidency ? 'dataResidency' : 'urlStrategy'); + } + + return new url_strategy_UrlStrategy(CustomUrl.preferredUrlsGetter(customUrl)); + } else if (dataResidency) { + if (urlStrategy) { + incorrectOptionIgnoredMessage('dataResidency', 'urlStrategy'); + } + + return new url_strategy_UrlStrategy(data_residency_DataResidency.preferredUrlsGetter(dataResidency)); + } else { + return new url_strategy_UrlStrategy(BlockedUrlBypass.preferredUrlsGetter(urlStrategy)); + } + } + + _UrlStrategyFactory.create = create; +})(UrlStrategyFactory || (UrlStrategyFactory = {})); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/network/url-startegy-network.ts + + + + + + + +var url_startegy_network_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; + + + + +var NetworkWithUrlStrategy = /*#__PURE__*/function (_NetworkDecorator) { + _inherits(NetworkWithUrlStrategy, _NetworkDecorator); + + var _super = _createSuper(NetworkWithUrlStrategy); + + function NetworkWithUrlStrategy(network + /*: Network*/ + , _ref + /*:: */ + ) { + var _this; + + var urlStrategy = _ref + /*:: */ + .urlStrategy, + urlStrategyConfig = _ref + /*:: */ + .urlStrategyConfig; + + _classCallCheck(this, NetworkWithUrlStrategy); + + _this = _super.call(this, network); + + _defineProperty(_assertThisInitialized(_this), "lastSuccessfulEndpoint", void 0); + + _defineProperty(_assertThisInitialized(_this), "urlStrategy", void 0); + + _this.urlStrategy = urlStrategy || UrlStrategyFactory.create(urlStrategyConfig); + return _this; + } + /** + * Returns last succesfull endpoint or default (`https://app.adjust.com`) one + */ + + + _createClass(NetworkWithUrlStrategy, [{ + key: "endpoint", + get: function get() + /*: string*/ + { + return this.lastSuccessfulEndpoint || NetworkWithUrlStrategy.DEFAULT_ENDPOINT; + } + /** + * Sends a request to provided path choosing origin with UrlStrategy and caches used origin if it was successfully + * reached + * + * @param path + * @param params non-encoded parameters of the request + */ + + }, { + key: "request", + value: function request + /*:: */ + (path + /*: string*/ + , params + /*: Record*/ + ) + /*: Promise*/ + { + var _this2 = this; + + return this.urlStrategy.retries(function (baseUrlsMap) { + _this2.network.endpoint = baseUrlsMap.app; + return _this2.network.request(path, params).then(function (result + /*: T*/ + ) { + _this2.lastSuccessfulEndpoint = baseUrlsMap.app; + return result; + }).catch(function (err + /*: NetworkError*/ + ) { + _this2.lastSuccessfulEndpoint = undefined; + throw err; + }); + }); + } + }]); + + return NetworkWithUrlStrategy; +}(NetworkDecorator); + +_defineProperty(NetworkWithUrlStrategy, "DEFAULT_ENDPOINT", ENDPOINTS["default"].app); + +(function (_NetworkWithUrlStrategy) { + /*:: */ +})(NetworkWithUrlStrategy || (NetworkWithUrlStrategy = {})); +;// CONCATENATED MODULE: ./src/sdk/smart-banner/smart-banner.ts + + + + +var smart_banner_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; + + + + + + + + + +/** + * Adjust Web SDK Smart Banner + */ +var SmartBanner = /*#__PURE__*/function () { + function SmartBanner(_ref + /*:: */ + , network + /*: Network*/ + ) { + var webToken = _ref + /*:: */ + .webToken, + _ref$logLevel = _ref + /*:: */ + .logLevel, + logLevel = _ref$logLevel === void 0 ? 'error' : _ref$logLevel, + dataResidency = _ref + /*:: */ + .dataResidency, + onCreated = _ref + /*:: */ + .onCreated, + onDismissed = _ref + /*:: */ + .onDismissed; + + _classCallCheck(this, SmartBanner); + + _defineProperty(this, "STORAGE_KEY_DISMISSED", 'closed'); + + _defineProperty(this, "network", void 0); + + _defineProperty(this, "timer", null); + + _defineProperty(this, "dataFetchPromise", void 0); + + _defineProperty(this, "banner", void 0); + + _defineProperty(this, "onCreated", void 0); + + _defineProperty(this, "onDismissed", void 0); + + this.onCreated = onCreated; + this.onDismissed = onDismissed; + logger.setLogLevel(logLevel); + var config = dataResidency ? { + dataResidency: dataResidency + } : {}; + this.network = network || new NetworkWithUrlStrategy(new XhrNetwork(), { + urlStrategyConfig: config + }); + this.init(webToken); + } + /** + * Initiate Smart Banner + * + * @param webToken token used to get data from backend + */ + + + _createClass(SmartBanner, [{ + key: "init", + value: function init(webToken + /*: string*/ + ) { + var _this = this; if (this.banner) { logger.error('Smart Banner already exists'); @@ -11223,7 +11703,7 @@ var SmartBanner = /*#__PURE__*/function () { return; } - this.dataFetchPromise = fetchSmartBannerData(webToken, deviceOs); + this.dataFetchPromise = fetchSmartBannerData(webToken, deviceOs, this.network); this.dataFetchPromise.then(function (bannerData) { _this.dataFetchPromise = null; @@ -11245,8 +11725,12 @@ var SmartBanner = /*#__PURE__*/function () { logger.log('Creating Smart Banner'); _this.banner = new SmartBannerView(bannerData, function () { return _this.dismiss(webToken, bannerData.dismissInterval); - }, Network.getEndpoint()); + }, _this.network.endpoint); logger.log('Smart Banner created'); + + if (_this.onCreated) { + _this.onCreated(); + } }); } /** @@ -11332,10 +11816,14 @@ var SmartBanner = /*#__PURE__*/function () { /*: number*/ ) { logger.log('Smart Banner dismissed'); - local_storage_storage.setItem(this.dismissedStorageKey, Date.now()); + local_storage_storage.setItem(this.STORAGE_KEY_DISMISSED, Date.now()); var whenToShow = this.getDateToShowAgain(dismissInterval); this.scheduleCreation(webToken, whenToShow); this.destroy(); + + if (this.onDismissed) { + this.onDismissed(); + } } /** * Sets a timeout to schedule next Smart Banner show @@ -11360,7 +11848,7 @@ var SmartBanner = /*#__PURE__*/function () { this.timer = setTimeout(function () { _this4.timer = null; - _this4.init(webToken, _this4.logLevel); + _this4.init(webToken); }, delay); logger.log('Smart Banner creation scheduled on ' + new Date(when)); } @@ -11375,7 +11863,7 @@ var SmartBanner = /*#__PURE__*/function () { ) /*: number*/ { - var dismissedDate = local_storage_storage.getItem(this.dismissedStorageKey); + var dismissedDate = local_storage_storage.getItem(this.STORAGE_KEY_DISMISSED); if (!dismissedDate) { return Date.now(); @@ -11387,23 +11875,34 @@ var SmartBanner = /*#__PURE__*/function () { return SmartBanner; }(); - -var smartBanner = new SmartBanner(); - ;// CONCATENATED MODULE: ./src/sdk/main.js var _excluded = ["logLevel", "logOutput"]; -function main_ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - -function main_objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? main_ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : main_ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - var main_Promise = typeof Promise === 'undefined' ? (__webpack_require__(702).Promise) : Promise; /*:: // import { type InitOptionsT, type LogOptionsT, type EventParamsT, type GlobalParamsT, type CustomErrorT, type ActivityStateMapT, type SmartBannerOptionsT, type AttributionMapT } from './types';*/ + + + + + + + + + + + + + + + + + + /*:: type InitConfigT = $ReadOnly<{|...InitOptionsT, ...LogOptionsT|}>*/ @@ -11446,6 +11945,15 @@ var _isStarted var _isInstalled /*: boolean*/ = false; +/** + * SmartBanner instance + * + * @private + */ + +var _smartBanner +/*: ?SmartBanner*/ += null; /** * Initiate the instance with parameters * @@ -11481,7 +11989,7 @@ function initSdk() } logger.info("Available storage is ".concat(availableStorage.type)); - main_options = main_objectSpread({}, options); + main_options = _objectSpread2({}, options); _start(options); }); @@ -11707,18 +12215,39 @@ function disableThirdPartySharing() }); } -function initSmartBanner(_ref2 -/*:: */ +function initSmartBanner(options +/*: SmartBannerOptionsT*/ ) /*: void*/ { - var webToken = _ref2 - /*:: */ - .webToken, - logLevel = _ref2 - /*:: */ - .logLevel; - smartBanner.init(webToken, logLevel); + if (_smartBanner) { + logger.error('Smart Banner already initialised'); + return; + } + + _smartBanner = new SmartBanner(options); +} + +function showSmartBanner() +/*: void*/ +{ + if (!_smartBanner) { + logger.error('Smart Banner is not initialised yet'); + return; + } + + _smartBanner.show(); +} + +function hideSmartBanner() +/*: void*/ +{ + if (!_smartBanner) { + logger.error('Smart Banner is not initialised yet'); + return; + } + + _smartBanner.hide(); } /** * Handle third party sharing disable @@ -11996,9 +12525,9 @@ function _preCheck(description ) /*: mixed*/ { - var _ref3 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, - schedule = _ref3.schedule, - stopBeforeInit = _ref3.stopBeforeInit; + var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + schedule = _ref2.schedule, + stopBeforeInit = _ref2.stopBeforeInit; if (storage.getType() === STORAGE_TYPES.NO_STORAGE) { logger.log("Adjust SDK can not ".concat(description, ", no storage available")); @@ -12047,6 +12576,8 @@ var Adjust = { gdprForgetMe: gdprForgetMe, disableThirdPartySharing: disableThirdPartySharing, initSmartBanner: initSmartBanner, + showSmartBanner: showSmartBanner, + hideSmartBanner: hideSmartBanner, __testonly__: { destroy: main_destroy, clearDatabase: _clearDatabase diff --git a/dist/adjust-latest.min.js b/dist/adjust-latest.min.js index 9f2a92b3..5777e54d 100644 --- a/dist/adjust-latest.min.js +++ b/dist/adjust-latest.min.js @@ -1,2 +1,2 @@ /*! For license information please see adjust-latest.min.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Adjust=t():e.Adjust=t()}(self,(()=>(()=>{var e={841:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(81),o=n.n(r),i=n(645),a=n.n(i),s=n(667),u=n.n(s),c=new URL(n(529),n.b),l=a()(o()),d=u()(c);l.push([e.id,".adjust-smart-banner__AEqYlWgPonspKfseFq2N{height:76px}@media(min-width: 428px){.adjust-smart-banner__AEqYlWgPonspKfseFq2N{height:0}}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq{position:fixed;left:0;right:0;z-index:10000000}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq.adjust-smart-banner__jOV7BvlxDT7ATfbLPh3j{top:0}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq.adjust-smart-banner__XmomYv1VVQYz0lEtn9Q2{bottom:0}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK{margin:0 auto;max-width:428px;background:#fff}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI{display:flex;align-items:center;padding:10px 8px 10px 4px}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__VFuxsD_KzqNSxQecFmao{width:32px;height:32px;border:none;background:url("+d+");background-repeat:no-repeat;background-position:center center;background-size:8px 8px,auto;cursor:pointer}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__hqvH8Y5fwbegVLKnoYv_{width:56px;height:56px;overflow:hidden;background-color:#6e7492;border-radius:8px}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__hqvH8Y5fwbegVLKnoYv_ .adjust-smart-banner__Ll9XMTDiX4Drgeydp0Oc{display:flex;align-items:center;justify-content:center;width:100%;height:100%;color:#353a52;font-weight:bold;font-size:23px;font-family:ArialMt,Arial,sans-serif;line-height:32px;background-color:#e0e2ec}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__hqvH8Y5fwbegVLKnoYv_ .adjust-smart-banner__VYRfEif2Ph2_984rXQy8{width:100%}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__I8xX0C5dUcR53pY0aEys{flex:1 1 0%;min-height:0;min-width:0;margin:0 12px}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__JJLdp2l7YvnsUXudojWA{overflow:hidden;text-overflow:ellipsis}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI h4{margin:5px 0 8px;color:#353a52;font-family:Arial-BoldMT,ArialMt,Arial,sans-serif;font-size:12px;font-weight:bold;line-height:16px;white-space:nowrap}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI p{margin:8px 0 7px;color:#353a52;font-family:ArialMt,Arial,sans-serif;font-size:9px;line-height:11px;max-height:22px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.adjust-smart-banner__NVk5vwju_4kdaKzGWJPq .adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK .adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI .adjust-smart-banner__risKVvV3T0vjKiSTR9l0{color:#6e7492;background:#f9fafc;border:1px solid #cdd0e0;border-radius:4px;border-color:#6e7492;box-shadow:inset 0px -1px 0px 0px #e0e2ec;padding:4px 6.5px;display:inline-block;vertical-align:middle;text-align:center;font-family:ArialMt,Arial,sans-serif;font-size:12px;font-weight:500;line-height:16px;cursor:pointer;text-decoration:none}",""]),l.locals={bannerContainer:"adjust-smart-banner__AEqYlWgPonspKfseFq2N",banner:"adjust-smart-banner__NVk5vwju_4kdaKzGWJPq",stickyToTop:"adjust-smart-banner__jOV7BvlxDT7ATfbLPh3j",stickyToBottom:"adjust-smart-banner__XmomYv1VVQYz0lEtn9Q2",bannerBody:"adjust-smart-banner__eXKzWnRDn4RWUiSSeVYK",content:"adjust-smart-banner__r3JnN_RNhpzArrmKQ8jI",dismiss:"adjust-smart-banner__VFuxsD_KzqNSxQecFmao",appIcon:"adjust-smart-banner__hqvH8Y5fwbegVLKnoYv_",placeholder:"adjust-smart-banner__Ll9XMTDiX4Drgeydp0Oc",image:"adjust-smart-banner__VYRfEif2Ph2_984rXQy8",textContainer:"adjust-smart-banner__I8xX0C5dUcR53pY0aEys",bannerText:"adjust-smart-banner__JJLdp2l7YvnsUXudojWA",action:"adjust-smart-banner__risKVvV3T0vjKiSTR9l0"};const f=l},645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",r=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),r&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),r&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,r,o,i){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var s=0;s0?" ".concat(l[5]):""," {").concat(l[1],"}")),l[5]=i),n&&(l[2]?(l[1]="@media ".concat(l[2]," {").concat(l[1],"}"),l[2]=n):l[2]=n),o&&(l[4]?(l[1]="@supports (".concat(l[4],") {").concat(l[1],"}"),l[4]=o):l[4]="".concat(o)),t.push(l))}},t}},667:e=>{"use strict";e.exports=function(e,t){return t||(t={}),e?(e=String(e.__esModule?e.default:e),/^['"].*['"]$/.test(e)&&(e=e.slice(1,-1)),t.hash&&(e+=t.hash),/["'() \t\n]|(%20)/.test(e)||t.needQuotes?'"'.concat(e.replace(/"/g,'\\"').replace(/\n/g,"\\n"),'"'):e):e}},81:e=>{"use strict";e.exports=function(e){return e[1]}},702:function(e,t,n){e.exports=function(){"use strict";function e(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function t(e){return"function"==typeof e}var r=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)},o=0,i=void 0,a=void 0,s=function(e,t){O[o]=e,O[o+1]=t,2===(o+=2)&&(a?a(w):P())};function u(e){a=e}function c(e){s=e}var l="undefined"!=typeof window?window:void 0,d=l||{},f=d.MutationObserver||d.WebKitMutationObserver,p="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),h="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel;function m(){return function(){return process.nextTick(w)}}function v(){return void 0!==i?function(){i(w)}:b()}function g(){var e=0,t=new f(w),n=document.createTextNode("");return t.observe(n,{characterData:!0}),function(){n.data=e=++e%2}}function y(){var e=new MessageChannel;return e.port1.onmessage=w,function(){return e.port2.postMessage(0)}}function b(){var e=setTimeout;return function(){return e(w,1)}}var O=new Array(1e3);function w(){for(var e=0;e{"use strict";var t=[];function n(e){for(var n=-1,r=0;r{"use strict";var t={};e.exports=function(e,n){var r=function(e){if(void 0===t[e]){var n=document.querySelector(e);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}t[e]=n}return t[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(n)}},216:e=>{"use strict";e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{"use strict";e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{"use strict";e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var r="";n.supports&&(r+="@supports (".concat(n.supports,") {")),n.media&&(r+="@media ".concat(n.media," {"));var o=void 0!==n.layer;o&&(r+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),r+=n.css,o&&(r+="}"),n.media&&(r+="}"),n.supports&&(r+="}");var i=n.sourceMap;i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),t.styleTagTransform(r,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},529:e=>{"use strict";e.exports="data:image/svg+xml;utf8, "}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={id:r,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.exports}n.m=e,n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.b=document.baseURI||self.location.href,n.nc=void 0;var r={};return(()=>{"use strict";function e(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function t(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);nUo});var u=1e3,c=36e5,l=24*c,d="general",f="gdpr",p={TRANSACTION_ERROR:"XHR transaction failed due to an error",SERVER_MALFORMED_RESPONSE:"Response from server is malformed",SERVER_INTERNAL_ERROR:"Internal error occurred on the server",SERVER_CANNOT_PROCESS:"Server was not able to process the request, probably due to error coming from the client",NO_CONNECTION:"No internet connectivity",SKIP:"Skipping slower attempt",MISSING_URL:"Url is not provided"},h="noStorage",m="indexedDB",v="localStorage";function g(e){return g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},g(e)}function y(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function b(t){for(var n=1;n0&&void 0!==arguments[0]?arguments[0]:[];return t.reduce((function(t,n){return b(b({},t),{},e({},n.key,n.value))}),{})}function _(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];return e.filter((function(e){return-1!==t.indexOf(e)}))}function S(e,t){return new RegExp("\\/".concat(t,"(\\/.*|\\?.*){0,1}$")).test(e)}function D(t,n){var r=a(n,2),o=r[0],i=r[1];return b(b({},t),{},e({},o,i))}function x(e){return Object.keys(e).map((function(t){return[t,e[t]]}))}function N(e){return Object.keys(e).map((function(t){return e[t]}))}function I(e){return w(e)?!O(e):!!e||0===e}const E={namespace:"adjust-sdk",version:"5.3.1",env:"production"};var A,T="error",C="warning",R="info",K="verbose",B=(e(A={},"none",-1),e(A,T,0),e(A,C,1),e(A,R,2),e(A,K,3),A),q={log:" ",info:" ",warn:" ",error:""},L={development:K,production:T,test:K},M=W(),U="";function W(){return L[E.env]||T}function V(e,t){var n;if(!(B[M]2?s-2:0),c=2;c2&&void 0!==arguments[2]?arguments[2]:[];return n.map((function(n){return Ae(e,t,n)}))}function Ce(e,t,n){var r=Pe[t][Ke(e,De.right)],o=r.fields[r.keyPath],i=n instanceof Array?n.slice():[n],a=(le(o)?o.composite:[r.keyPath]).map((function(e,t){var n=r.fields[e];return Ee(ue(n)?n.values:null,i[t])}));return 1===a.length?a[0]:a}function Re(e){return Pe.values[e]||e}function Ke(e,t){return(Pe.storeNames[t][e]||{}).name||e}function Be(e,t){return{name:t.name,message:t.message.replace('"'.concat(e,'"'),Ke(e,De.right))}}function qe(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Le(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:1,n=e+"",r=1;r<=t;r+=1)e0?"-":"+")+Ue(Math.floor(Math.abs(t)/60))+Ue(Math.abs(t)%60)}(t);return"".concat(n,"T").concat(r,"Z").concat(o)}function Ve(e,t){return isNaN(e)||isNaN(t)?0:Math.abs(t-e)}function ze(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Fe(t){for(var n=1;n0&&void 0!==arguments[0]?arguments[0]:{};Ye=Je?Fe({},e):{}}function Qe(){Je&&(Ye.lastInterval=function(){var e=Ye.lastActive;if(e)return Math.round(Ve(e,Date.now())/u);return-1}(),Ye.lastActive=Date.now())}function He(e){Ye=Fe(Fe({},Ye),e)}function Ze(){Ge=!0}function $e(){var e=Ye.lastActive;return Math.round(Ve(e,Date.now())/u)}function et(){return(Ye.timeSpent||0)+(Ge?$e():0)}function tt(){var e=Ve(Ye.lastActive,Date.now())=0?Ye.lastInterval:0,n={timeSpent:Ye.timeSpent||0,sessionLength:Ye.sessionLength||0,sessionCount:Ye.sessionCount||1,lastInterval:t||0};return e&&S(e,"event")&&(n.eventCount=Ye.eventCount),n},updateParams:function(e,t){if(Je){var n={};n.timeSpent=et(),n.sessionLength=tt(),S(e,"session")&&(n.sessionCount=(Ye.sessionCount||0)+1),S(e,"event")&&(n.eventCount=(Ye.eventCount||0)+1),He(n),t||Qe()}},updateInstalled:function(){Je&&(Ye.installed||He({installed:!0}))},updateSessionOffset:nt,updateSessionLength:function(){Je&&(He({sessionLength:tt()}),Qe())},resetSessionOffset:function(){Je&&He({timeSpent:0,sessionLength:0})},updateLastActive:Qe,destroy:function(){Ye={},Je=!1,Ge=!1},getAttribution:function(){return Je?Ye.attribution?Ye.attribution:(F.log("No attribution data yet"),null):null},getWebUUID:function(){return Je?Ye.uuid:null}};var ot={},it=[];function at(e,t){var n="id"+Math.random().toString(36).substr(2,16),r={id:n,cb:t};return ot[e]||(ot[e]=[]),ot[e].push(r),n}function st(e,t){ot[e]&&ot[e].forEach((function(n){"function"==typeof n.cb&&it.push(setTimeout((function(){return n.cb(e,t)})))}))}const ut=new(function(){function t(){var n=this;qe(this,t),e(this,"defaultName",E.namespace),e(this,"storageName",this.defaultName),e(this,"storeNames",Pe.storeNames.left),e(this,"storesMap",void 0),this.storesMap={};var r=this.read.bind(this),o=this.write.bind(this);N(this.storeNames).forEach((function(e){var t=e.name;Object.defineProperty(n.storesMap,t,{get:function(){return r(t)},set:function(e){o(t,e)}})})),Object.freeze(this.storesMap)}return Me(t,[{key:"read",value:function(e){var t=localStorage.getItem("".concat(this.storageName,".").concat(e)),n=t?JSON.parse(t):null;return e===ae.Preferences&&n?Ae(ae.Preferences,De.right,n):n}},{key:"write",value:function(e,t){t?localStorage.setItem("".concat(this.storageName,".").concat(e),JSON.stringify(t instanceof Array?t:Ae(ae.Preferences,De.left,t))):localStorage.removeItem("".concat(this.storageName,".").concat(e))}},{key:"clear",value:function(){this.deleteData()}},{key:"deleteData",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];N(this.storeNames).forEach((function(n){!t&&n.permanent||localStorage.removeItem("".concat(e.storageName,".").concat(n.name))}))}},{key:"setCustomName",value:function(e){var t=this;if(e&&e.length){var n="".concat(E.namespace,"-").concat(e);N(this.storeNames).forEach((function(e){var r=e.name,o=localStorage.getItem("".concat(t.storageName,".").concat(r));o&&localStorage.setItem("".concat(n,".").concat(r),o)})),this.deleteData(!0),this.storageName=n}}},{key:"stores",get:function(){return this.storesMap}}]),t}());function ct(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function lt(t){for(var n=1;n0?(this.dbName="".concat(E.namespace,"-").concat(e),this.migrateDb(this.dbDefaultName,this.dbName)):Pt.resolve()}},{key:"openDatabase",value:function(e,n,r){var o=this;return t.isSupported().then((function(t){return t?new Pt((function(t,i){var a=o.idbFactory.open(e,r);n&&(a.onupgradeneeded=function(e){return n(e,i)}),a.onsuccess=function(e){var n=e.target.result;n?t(n):i(o.databaseOpenError)},a.onerror=i})):Pt.reject(o.notSupportedError)}))}},{key:"databaseExists",value:function(e){var t=this;return new Pt((function(n){var r=!0;t.openDatabase(e,(function(){r=!1})).then((function(n){if(n.close(),!r)return t.deleteDatabaseByName(e)})).then((function(){return n(r)}))}))}},{key:"cloneData",value:function(e,t){var n=this;return N(Pe.storeNames.left).map((function(e){return e.name})).filter((function(e){return"p"!==e})).map((function(r){return function(){return o=r,i=n.indexedDbConnection,n.indexedDbConnection=e,n.getAll(o).then((function(e){if(n.indexedDbConnection=t,!(e.length<1))return n.addBulk(o,e,!0)})).then((function(){n.indexedDbConnection=i}));var o,i}})).reduce((function(e,t){return e.then(t)}),Pt.resolve())}},{key:"migrateDb",value:function(e,t){var n=this;return this.databaseExists(e).then((function(r){return r?Pt.all([n.openDatabase(e,n.handleUpgradeNeeded,n.dbVersion),n.openDatabase(t,n.handleUpgradeNeeded,n.dbVersion)]).then((function(t){var r=a(t,2),o=r[0],i=r[1];return n.cloneData(o,i).then((function(){return n.indexedDbConnection=i,o.close(),n.deleteDatabaseByName(e)}))})).then((function(){return F.info("Database migration finished")})):n.openDatabase(t,n.handleUpgradeNeeded,n.dbVersion).then((function(e){n.indexedDbConnection=e}))}))}},{key:"handleUpgradeNeeded",value:function(e,t){var n=e.target.result;e.target.transaction.onerror=t,e.target.transaction.onabort=t;var r=Pe.storeNames.left,o=rt.current||{},i=o&&!O(o);x(r).filter((function(e){return!a(e,2)[1].permanent})).forEach((function(e){var t=a(e,2),r=t[0],s=t[1].name,u=Pe.right[r],c=n.createObjectStore(s,{keyPath:u.keyPath,autoIncrement:u.autoIncrement||!1});if(u.index&&c.createIndex("".concat(u.index,"Index"),u.index),s===ie.ActivityState&&i)return c.add(Ae(r,De.left,o)),void F.info("Activity state has been recovered");var l=ut.stores[s];l&&(l.forEach((function(e){return c.add(e)})),F.info("Migration from localStorage done for ".concat(r," store")))})),bt(),ut.clear()}},{key:"open",value:function(){var e=this;return this.indexedDbConnection?Pt.resolve({success:!0}):this.openDatabase(this.dbName,this.handleUpgradeNeeded,this.dbVersion).then((function(t){return e.indexedDbConnection=t,e.indexedDbConnection.onclose=function(){return e.destroy},{success:!0}}))}},{key:"getTransactionStore",value:function(e,t,n){var r,o=e.storeName,i=e.mode,a=n.transaction([o],i),s=a.objectStore(o),u=Pe.right[Ke(o,De.right)];return u.index&&(r=s.index("".concat(u.index,"Index"))),a.onerror=t,a.onabort=t,{transaction:a,store:s,index:r,options:u}}},{key:"overrideError",value:function(e,t){var n=t.target.error;return e({name:n.name,message:n.message})}},{key:"getCompositeKeys",value:function(e){var t=e.fields[e.keyPath];return le(t)?t.composite:null}},{key:"targetIsObject",value:function(e){return w(e)}},{key:"prepareTarget",value:function(t,n,r){if(r===wt.clear||!n)return null;var o=this.getCompositeKeys(t);return-1!==[wt.add,wt.put].indexOf(r)?this.targetIsObject(n)?o?function(t){for(var n=1;n1&&void 0!==arguments[1]&&arguments[1];return this.openCursor({storeName:e,action:wt.list,firstOnly:t})}},{key:"getFirst",value:function(e){return this.getAll(e,!0).then((function(e){return e.length?e[0]:void 0}))}},{key:"getItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:wt.get})}},{key:"filterBy",value:function(e,t){var n=IDBKeyRange.only(t);return this.openCursor({storeName:e,action:wt.list,range:n})}},{key:"addItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:wt.add,mode:jt.readwrite})}},{key:"addBulk",value:function(e,t,n){return this.initBulkRequest({storeName:e,target:t,action:n?wt.put:wt.add,mode:jt.readwrite})}},{key:"updateItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:wt.put,mode:jt.readwrite})}},{key:"deleteItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:wt.delete,mode:jt.readwrite})}},{key:"deleteBulk",value:function(e,t,n){var r=n?IDBKeyRange[n](t):IDBKeyRange.only(t);return this.openCursor({storeName:e,action:wt.delete,range:r,mode:jt.readwrite})}},{key:"trimItems",value:function(e,t){var n=this,r=Pe.right[Ke(e,De.right)];return this.getAll(e).then((function(e){return e.length?e[t-1]:null})).then((function(t){return t?n.deleteBulk(e,t[r.keyPath],Se.UpperBound):[]}))}},{key:"count",value:function(e){var t=this;return this.open().then((function(){return new Pt((function(n,r){if(t.indexedDbConnection){var o=t.getTransactionStore({storeName:e,mode:jt.readonly},r,t.indexedDbConnection).store.count();o.onsuccess=function(){return n(o.result)},o.onerror=function(e){return t.overrideError(r,e)}}else r(t.noConnectionError)}))}))}},{key:"clear",value:function(e){return this.initRequest({storeName:e,action:wt.clear,mode:jt.readwrite})}},{key:"destroy",value:function(){this.indexedDbConnection&&this.indexedDbConnection.close(),this.indexedDbConnection=null}},{key:"deleteDatabase",value:function(){return this.destroy(),this.deleteDatabaseByName(this.dbName)}}],[{key:"tryOpen",value:function(e){return new Pt((function(n){try{var r=e.open(t.dbValidationName);r.onsuccess=function(){r.result.close(),e.deleteDatabase(t.dbValidationName),n(!0)},r.onerror=function(){return n(!1)}}catch(e){n(!1)}}))}},{key:"isSupported",value:function(){return t.isSupportedPromise||(t.isSupportedPromise=new Pt((function(e){var n=t.getIndexedDB(),r=!!navigator.platform&&/iPad|iPhone|iPod/.test(navigator.platform);!n||r?(F.warn("IndexedDB is not supported in this browser"),e(!1)):e(t.tryOpen(n).then((function(e){return e||F.warn("IndexedDB is not supported in this browser"),e})))}))),t.isSupportedPromise}},{key:"getIndexedDB",value:function(){return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB}}]),t}();function _t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function St(t){for(var n=1;ne[r]:e[r]>t[r];return o?-1:i?1:0}(e,t,o)}),0)}))}},{key:"prepareTarget",value:function(t,n,r){var o=this.getCompositeKeys(t);return o?St(e({},t.keyPath,o.map((function(e){return n[e]})).join("")),n):t.autoIncrement&&r?St(e({},t.keyPath,r),n):St({},n)}},{key:"prepareResult",value:function(e,t){var n=this.getCompositeKeys(e);return n?n.map((function(e){return t[e]})).filter((function(e){return!xe(e)})):t[e.keyPath]}},{key:"getAll",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return this.open().then((function(r){return"error"===r.status?Dt.reject(r.error):new Dt((function(r,o){var i=ut.stores[e];i instanceof Array?r(n?[i[0]]:t.sort(i,t.getKeys(e))):o({name:"NotFoundError",message:"No objectStore named ".concat(e," in this database")})}))}))}},{key:"getFirst",value:function(e){return this.getAll(e,!0).then((function(e){return e.length?e[0]:void 0}))}},{key:"getItem",value:function(e,t){var n=this;return this.initRequest({storeName:e,id:t},(function(t,r,o){var i=o.items,a=o.index,s=o.options;-1===a?r({name:"NotRecordFoundError",message:'Requested record not found in "'.concat(e,'" store')}):t(n.prepareTarget(s,i[a]))}))}},{key:"filterBy",value:function(e,t){return this.getAll(e).then((function(n){return n.filter((function(n){var r=Pe.right[Ke(e,De.right)];return(r.index&&n[r.index])===t}))}))}},{key:"addItem",value:function(e,t){var n=this;return this.initRequest({storeName:e,item:t},(function(r,o,i){var a=i.items,s=i.index,u=i.options,c=i.lastId;-1!==s?o({name:"ConstraintError",message:'Constraint was not satisfied, trying to add existing item into "'.concat(e,'" store')}):(a.push(n.prepareTarget(u,t,n.nextIndex(c))),ut.stores[e]=a,r(n.prepareResult(u,t)))}))}},{key:"addBulk",value:function(e,t,n){var r=this;return this.initRequest({storeName:e},(function(o,i,a){var u=a.keys,c=a.items,l=a.options,d=a.lastId;if(!t||t&&!t.length)i({name:"NoTargetDefined",message:'No array provided to perform add bulk operation into "'.concat(e,'" store')});else{var f=d,p=t.map((function(e){return r.prepareTarget(l,e,f=r.nextIndex(f))})),h=p.filter((function(e){return-1!==P(c,u,e)})).map((function(e){return e[l.keyPath]})),m=n?c.filter((function(e){return-1===h.indexOf(e[l.keyPath])})):s(c);if(h.length&&!n)i({name:"ConstraintError",message:'Constraint was not satisfied, trying to add existing items into "'.concat(e,'" store')});else ut.stores[e]=r.sort([].concat(s(m),s(p)),u),o(t.map((function(e){return r.prepareResult(l,e)})))}}))}},{key:"updateItem",value:function(e,t){var n=this;return this.initRequest({storeName:e,item:t},(function(r,o,i){var a=i.items,s=i.index,u=i.options,c=i.lastId,l=-1===s?n.nextIndex(c):void 0,d=n.prepareTarget(u,t,l);-1===s?a.push(d):a.splice(s,1,d),ut.stores[e]=a,r(n.prepareResult(u,t))}))}},{key:"deleteItem",value:function(e,t){return this.initRequest({storeName:e,id:t},(function(n,r,o){var i=o.items,a=o.index;-1!==a&&(i.splice(a,1),ut.stores[e]=i),n(t)}))}},{key:"findMax",value:function(e,t,n){if(!e.length)return-1;for(var r={index:-1,value:"string"==typeof n?"":0},o=0;o=r.value&&(r={value:e[o][t],index:o})}return r.index}},{key:"deleteBulk",value:function(e,t,n){var r=this;return this.getAll(e).then((function(o){var i=r.getKeys(e),a=Pe.right[Ke(e,De.right)].index||i[0],s=n?null:t,u=r.sort(o,i,s),c=r.findMax(u,a,t);if(-1===c)return[];var l=n===Se.LowerBound?c:0,d=n&&n!==Se.UpperBound?u.length:c+1,f=u.splice(l,d).map((function(e){return 1===i.length?e[a]:i.map((function(t){return e[t]}))}));return ut.stores[e]=u,f}))}},{key:"trimItems",value:function(e,t){var n=this,r=Ke(e,De.right),o=Pe.right[r];return this.getAll(e).then((function(e){return e.length?e[t-1]:null})).then((function(t){return t?n.deleteBulk(e,t[o.keyPath],Se.UpperBound):[]}))}},{key:"count",value:function(e){return this.open().then((function(t){if("error"===t.status)return Dt.reject(t.error);var n=ut.stores[e];return Dt.resolve(n instanceof Array?n.length:1)}))}},{key:"clear",value:function(e){return this.open().then((function(t){return"error"===t.status?Dt.reject(t.error):new Dt((function(t){ut.stores[e]=[],t()}))}))}},{key:"destroy",value:function(){}},{key:"deleteDatabase",value:function(){}}],[{key:"isSupported",value:function(){if(t.isSupportedPromise)return t.isSupportedPromise;var e=(new Date).toString(),n=window.localStorage;return t.isSupportedPromise=new Dt((function(t){n.setItem(e,e);var r=n.getItem(e)===e;n.removeItem(e),t(!(!r||!n))})).catch((function(){return F.warn("LocalStorage is not supported in this browser"),Dt.resolve(!1)})),t.isSupportedPromise}}]),t}();function Nt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}e(xt,"isSupportedPromise",null);var It,Et="undefined"==typeof Promise?n(702).Promise:Promise;!function(e){e[e.noStorage=h]="noStorage",e[e.indexedDB=m]="indexedDB",e[e.localStorage=v]="localStorage"}(It||(It={}));var At,Tt={getAll:function(e,t,n){return e.getAll(t,n).then((function(e){return Te(t,De.right,e)}))},getFirst:function(e,t){return e.getFirst(t).then((function(e){return Ae(t,De.right,e)}))},getItem:function(e,t,n){return e.getItem(t,Ce(t,De.left,n)).then((function(e){return Ae(t,De.right,e)})).catch((function(e){return Et.reject(Be(t,e))}))},filterBy:function(e,t,n){return e.filterBy(t,Re(n)).then((function(e){return Te(t,De.right,e)}))},addItem:function(e,t,n){var r=Ae(t,De.left,n);return e.addItem(t,r).then((function(e){return Ce(t,De.right,e)})).catch((function(e){return Et.reject(Be(t,e))}))},addBulk:function(e,t,n,r){var o=Te(t,De.left,n);return e.addBulk(t,o,r).then((function(e){return e.map((function(e){return Ce(t,De.right,e)}))})).catch((function(e){return Et.reject(Be(t,e))}))},updateItem:function(e,t,n){var r=Ae(t,De.left,n);return e.updateItem(t,r).then((function(e){return Ce(t,De.right,e)}))},deleteItem:function(e,t,n){return e.deleteItem(t,Ce(t,De.left,n)).then((function(e){return Ce(t,De.right,e)}))},deleteBulk:function(e,t,n,r){return e.deleteBulk(t,Re(n),r).then((function(e){return e.map((function(e){return Ce(t,De.right,e)}))}))},trimItems:function(e,t,n){return e.trimItems(t,n)},count:function(e,t){return e.count(t)},clear:function(e,t){return e.clear(t)},destroy:function(e){return e.destroy()},deleteDatabase:function(e){return e.deleteDatabase()}};var Ct=null;function Rt(e){var t=null;return null!==Ct?Ct:Ct=Et.all([kt.isSupported(),xt.isSupported()]).then((function(n){var r=a(n,2),o=r[0],i=r[1];if(ut.setCustomName(e),o){At=It.indexedDB;var s=new kt;return s.setCustomName(e).then((function(){return t=s}))}return i?(At=It.localStorage,t=new xt,Et.resolve(t)):(F.error("There is no storage available, app will run with minimum set of features"),At=It.noStorage,t=null,Et.resolve(t))})).then((function(){return{type:At,storage:t}}))}const Kt=function(t){for(var n=1;n1?t-1:0),o=1;o2&&void 0!==arguments[2]&&arguments[2];return{status:"error",action:n?"CONTINUE":"RETRY",response:j(e.responseText)?JSON.parse(e.responseText):e.responseText,message:p[t],code:t}}function Ft(e,t){var n=e.slice(0,e.length-t.length-1).split("").reduce((function(e){return e.concat(" ")}),"");return"".concat(t).concat(n,":")}function Yt(e,t){var n="REQUEST PARAMETERS:",r=function(e){return e.replace(/([A-Z])/g,(function(e){return"_".concat(e.toLowerCase())}))},o=x(Wt(Wt(Wt({},te.getBaseParams()),t),e)).map((function(e){var t=a(e,2),n=t[0],o=t[1];return[r(n),o]}));return F.log(n),o.filter((function(e){return I(a(e,2)[1])})).map((function(e){var t=a(e,2),r=t[0],o=t[1];return F.log(Ft(n,r),o),function(e){var t=a(e,2),n=t[0],r=t[1],o=encodeURIComponent(n),i=r;return"string"==typeof r&&(i=encodeURIComponent(r)),w(r)&&(i=encodeURIComponent(JSON.stringify(r)||"")),[o,i].join("=")}([r,o])})).join("&")}function Jt(e,t,n){var r=n.xhr,o=n.url;if(4===r.readyState){var i=r.status>=200&&r.status<300,s=j(r.responseText);if(0!==r.status)return s?t(i?function(e,t){var n=JSON.parse(e.responseText),r={status:"success",adid:n.adid,timestamp:n.timestamp,ask_in:n.ask_in,retry_in:n.retry_in,continue_in:n.continue_in,tracking_state:n.tracking_state,attribution:void 0,message:void 0};return S(t,"attribution")&&(r.attribution=n.attribution,r.message=n.message),x(r).filter((function(e){return!!a(e,2)[1]})).reduce(D,{})}(r,o):zt(r,"SERVER_CANNOT_PROCESS",!0)):e(zt(r,i?"SERVER_MALFORMED_RESPONSE":"SERVER_INTERNAL_ERROR"));e(zt(r,"NO_CONNECTION"))}}function Gt(e,t){var n=e.endpoint,r=e.url,o=e.method,i=void 0===o?"GET":o,s=e.params,u=function(e,t){var n=e.endpoint,r=e.url,o=e.method,i=Yt(e.params,t);return{fullUrl:n+r+("GET"===o?"?".concat(i):""),encodedParams:i}}({endpoint:n,url:r,method:i,params:void 0===s?{}:s},t),c=u.fullUrl,l=u.encodedParams;return new Vt((function(e,t){var n=new XMLHttpRequest;n.open(i,c,!0),function(e,t){var n="REQUEST HEADERS:",r=[["Client-SDK","js".concat(E.version)],["Content-Type","POST"===t?"application/x-www-form-urlencoded":"application/json"]];F.log(n),r.forEach((function(t){var r=a(t,2),o=r[0],i=r[1];e.setRequestHeader(o,i),F.log(Ft(n,o),i)}))}(n,i),n.onreadystatechange=function(){return Jt(t,e,{xhr:n,url:r})},n.onerror=function(){return t(zt(n,"TRANSACTION_ERROR"))},n.send("GET"===i?void 0:l)}))}function Xt(e,t){return"success"===e.status?function(e,t){var n=S(t,"gdpr_forget_device"),r=S(t,"attribution"),o=S(t,"session"),i=S(t,"disable_third_party_sharing"),a="opted_out"===e.tracking_state;if(!n&&a)return st("sdk:gdpr-forget-me"),e;r||n||a||!e.ask_in||st("attribution:check",e);o&&st("session:finished",e);if(i)return st("sdk:third-party-sharing-opt-out"),e;return e}(e,t):e}function Qt(e){return Mt().then((function(t){return Gt(e,t)})).then((function(t){return Xt(t,e.url)}))}var Ht={long:{delay:12e4,maxDelay:l,minRange:.5,maxRange:1},short:{delay:200,maxDelay:c,minRange:.5,maxRange:1},test:{delay:100,maxDelay:300}};function Zt(e,t){var n,r,o=Ht[t=t||"long"],i=o.delay*Math.pow(2,e-1);return i=Math.min(i,o.maxDelay),o.minRange&&o.maxRange&&(i*=(n=o.minRange,r=o.maxRange,Math.random()*(r-n)+n)),Math.round(i)}var $t,en,tn=navigator.onLine;function nn(){tn=!0}function rn(){tn=!1}function on(e,t,n){e.addEventListener&&e.addEventListener(t,n,!1)}function an(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}function sn(){return tn}var un;"undefined"==typeof Promise&&n(702).Promise;function cn(){var e=te.getCustomConfig(),t=e.customUrl,n=e.urlStrategy;return t?{app:t,gdpr:t}:n===un.India?[un.India,un.Default]:n===un.China?[un.China,un.Default]:[un.Default,un.India,un.China]}!function(e){e.Default="default",e.India="india",e.China="china"}(un||(un={}));var ln=(e($t={},un.Default,{app:"https://app.adjust.com",gdpr:"https://gdpr.adjust.com"}),e($t,un.India,{app:"https://app.adjust.net.in",gdpr:"https://gdpr.adjust.net.in"}),e($t,un.China,{app:"https://app.adjust.world",gdpr:"https://gdpr.adjust.world"}),$t),dn=(e(en={},un.Default,"default"),e(en,un.India,"Indian"),e(en,un.China,"Chinese"),en);function fn(e){var t=cn();return Array.isArray(t)?t.map((function(t){return e[t]||null})).filter((function(e){return!!e})):[t]}function pn(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:ln,t=fn(e),n=0;return{next:function(){return n0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,n=e.method,r=void 0===n?"GET":n,o=e.params,i=void 0===o?{}:o,s=e.continueCb,u=e.strategy,c=e.wait,l={url:t,method:r,params:i,continueCb:s},d=t,f=r,h=mn({},i),m=s,v=u,g=pn(),y=g.next(),b=function(){g.reset(),y=g.next()},w=function(e,t){return e["/gdpr_forget_device"===t?"gdpr":"app"]},j=null,P={request:0,connection:0},k=S(c),_=null;function S(e){return(e=e||gn)>yn?yn:e}function N(e){var t=e.url,n=e.method,r=e.params,o=e.continueCb;t&&(d=t),n&&(f=n),O(r)||(h=mn({},r)),h=mn({createdAt:We()},h),"function"==typeof o&&(m=o)}function E(e){if(!_)return!1;if(j){var t=k-(Date.now()-_);if(e&&t0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,n=e.method,r=e.params,o=void 0===r?{}:r,i=e.continueCb,a=e.wait;return N({url:t,method:n,params:o,continueCb:i}),A({wait:a})}function U(){return!!j}function W(){j&&clearTimeout(j),j=null}function V(){var e=!!_;W(),_=null,e&&(k=gn,P.request=0,P.connection=0,F.log("Previous ".concat(d||"unknown"," request attempt canceled")),R())}return{send:M,isRunning:U,clear:V}};var wn=function(e){return e===f?"GDPR disable":"disable"},jn=function(e){return{start:{inProgress:"Adjust SDK ".concat(wn(e)," process has already started"),done:"Adjust SDK ".concat(wn(e)," process is now started")},finish:{inProgress:"Adjust SDK ".concat(wn(e)," process has already finished"),done:"Adjust SDK ".concat(wn(e)," process is now finished")}}};function Pn(e,t){var n=e.reason,r=e.pending,o=mt()||{},i="start"===t&&o.pending?"start":"finish",a="start"===t&&o.reason,s="finish"===t&&o.reason&&!o.pending;return a||s?(F.log(jn(o.reason)[i].inProgress),!1):(F.log(jn(n)[i].done),vt({reason:n||d,pending:r}),!0)}function kn(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return Pn({reason:e,pending:t||!1},"start")}function _n(){var e=mt()||{};return e.reason===d||e.reason===f&&!e.pending?"off":e.reason===f&&e.pending?"paused":"on"}function Sn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Dn(t){for(var n=1;n1&&void 0!==arguments[1]?arguments[1]:{},i=o.auto,s=o.timestamp;rt.updateParams(t,i);var u=x(r||{}).filter((function(e){return I(a(e,2)[1])})).reduce(D,{}),c={timestamp:Un(),url:t,method:n,params:Rn(Rn({},rt.getParams(t)),u)};return s&&(c.createdAt=s),Kt.addItem(Ln,c).then((function(){return Wn(t)})).then((function(){return Mn.running?{}:Yn()}))}function zn(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.timestamp,n=e.createdAt,r=e.url,o=e.method,i=e.params,a=arguments.length>1?arguments[1]:void 0,s=rt.current||{},u="/session"===r&&!s.installed,c=!r&&!o&&!i;return qn&&!u||c?(Mn.running=!1,Kn.resolve({})):Bn.send({url:r,method:o,params:Rn(Rn({},i),{},{createdAt:We(n||t)}),wait:a||Fn()})}function Fn(){var e=Mn.pause||{},t=e.timestamp,n=e.wait,r=Date.now()-(t||0);return r0&&void 0!==arguments[0]?arguments[0]:{},t=e.cleanUp,n=e.wait;if(Mn.running)return Kn.resolve({});Mn.running=!0;var r=Kn.resolve({});return t&&(r=r.then(Gn)),r.then((function(){return Kt.getFirst(Ln)})).then((function(e){return zn(e,n)}))}function Jn(e){if(void 0!==e)if(e!==qn){var t=qn;qn=e,!e&&t&&Yn(),F.info("The app is now in ".concat(e?"offline":"online"," mode"))}else F.error("The app is already in ".concat(e?"offline":"online"," mode"));else F.error("State not provided, true or false has to be defined")}function Gn(){var e=Date.now()-te.requestValidityWindow;return Kt.deleteBulk(Ln,e,"upperBound")}var Xn="undefined"==typeof Promise?n(702).Promise:Promise,Qn="globalParams",Hn="No type provided",Zn="Global parameter type not provided, `callback` or `partner` types are available";function $n(e){return(e||[]).map((function(e){return{key:e.key,value:e.value}}))}function er(){return Xn.all([Kt.filterBy(Qn,"callback"),Kt.filterBy(Qn,"partner")]).then((function(e){var t=a(e,2),n=t[0],r=t[1];return{callbackParams:$n(n),partnerParams:$n(r)}}))}function tr(e,t){if(void 0===t)return F.error(Zn),Xn.reject({message:Hn});var n=k(e),r=Object.keys(n).map((function(e){return{key:e,value:n[e],type:t}}));return Xn.all([Kt.filterBy(Qn,t),Kt.addBulk(Qn,r,!0)]).then((function(e){var n=a(e,2),o=n[0],i=n[1],s=_(o.map((function(e){return e.key})),i.map((function(e){return e[0]})));return F.log("Following ".concat(t," parameters have been saved: ").concat(r.map((function(e){return"".concat(e.key,":").concat(e.value)})).join(", "))),s.length&&F.log("Keys: ".concat(s.join(", ")," already existed so their values have been updated")),i}))}function nr(e,t){return void 0===t?(F.error(Zn),Xn.reject({message:Hn})):Kt.deleteItem(Qn,[e,t]).then((function(n){return F.log("".concat(e," ").concat(t," parameter has been deleted")),n}))}function rr(e){return void 0===e?(F.error(Zn),Xn.reject({message:Hn})):Kt.deleteBulk(Qn,e).then((function(t){return F.log("All ".concat(e," parameters have been deleted")),t}))}var or,ir,ar,sr="undefined"==typeof Promise?n(702).Promise:Promise,ur=!1,cr=document;function lr(){return ar=function(){var e=document;if(void 0!==e.hidden)return{hidden:"hidden",visibilityChange:"visibilitychange"};for(var t=x({mozHidden:"mozvisibilitychange",msHidden:"msvisibilitychange",oHidden:"ovisibilitychange",webkitHidden:"webkitvisibilitychange"}),n=0;n0;return!n||n&&t*u>=te.sessionWindow?er().then((function(e){var t,n,r;Vn({url:"/session",method:"POST",params:(t=e,n=t.callbackParams,r=t.partnerParams,{callbackParams:n.length?k(n):null,partnerParams:r.length?k(r):null})},{auto:!0})})):(st("attribution:check"),Tn())}function gr(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function yr(t){for(var n=1;n0?t:10;return Kt.count(Mr).then((function(e){var t=Lr.resolve();if(e>=n){var r=e-n+1;F.log("Event deduplication list limit has been reached. Oldest ids are about to be removed (".concat(r," of them)")),t=Kt.trimItems(Mr,r)}return t})).then((function(){return F.info("New event deduplication id is added to the list: ".concat(e)),Kt.addItem(Mr,{id:e})}))}(e):Lr.reject({message:"Event won't be tracked, since it was previously tracked with the same deduplication id ".concat(e)})})):Lr.resolve()}function Vr(e){return{clickTime:We(),source:"web_referrer",referrer:decodeURIComponent(e)}}function zr(){var e=window.location.search.substring(1).split("&").map((function(e){return e.split("=")})).reduce(D,{}).adjust_referrer;e&&Vn({url:"/sdk_click",method:"POST",params:Vr(e)})}function Fr(){var e,t,n=null===(e=navigator)||void 0===e||null===(t=e.userAgent)||void 0===t?void 0:t.toLowerCase();if(n&&!(n.length<1))return/ipad|iphone|ipod/.test(n)?qr.iOS:n.includes("windows")?/phone|mobile/.test(n)?qr.WindowsPhone:qr.WindowsPC:n.includes("android")?qr.Android:void 0}function Yr(e){if(!e)return null;try{return JSON.parse(e)}catch(e){return null}}!function(e){e.Android="android",e.iOS="ios",e.WindowsPC="windows",e.WindowsPhone="windows-phone"}(qr||(qr={}));var Jr="adjust-smart-banner";var Gr={getItem:function(e){return Yr(localStorage.getItem("".concat(Jr,".").concat(e)))},setItem:function(e,t){t?localStorage.setItem("".concat(Jr,".").concat(e),JSON.stringify(t)):localStorage.removeItem("".concat(Jr,".").concat(e))}},Xr={status:0,code:"NO_CONNECTION",message:"No internet connectivity"},Qr="undefined"==typeof Promise?n(702).Promise:Promise,Hr=function(){function e(){qe(this,e)}return Me(e,null,[{key:"xhr",value:function(e){return new Qr((function(t,n){var r=new XMLHttpRequest;r.open("GET",e),[["Client-SDK","js".concat(E.version)],["Content-Type","application/json"]].forEach((function(e){var t=a(e,2),n=t[0],o=t[1];r.setRequestHeader(n,o)})),r.onerror=function(){return n(Xr)},r.onreadystatechange=function(){if(4===r.readyState){var e=r.status>=200&&r.status<300,o=Yr(r.responseText);0===r.status?n(Xr):e?t(o):n({status:r.status,message:o||r.responseText||""})}},r.send()}))}},{key:"encodeParams",value:function(e){return Object.keys(e).map((function(t){return[encodeURIComponent(t),encodeURIComponent(e[t])].join("=")})).join("&")}},{key:"getEndpoint",value:function(){return e.lastSuccessfulEndpoint||e.defaultEndpoint}},{key:"request",value:function(t,n){return function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:ln,n=cn();if(Array.isArray(n)){var r=0;return function o(){var i=n[r++],a=t[i];return e(a).catch((function(e){if("NO_CONNECTION"===e.code&&(F.log("Failed to connect ".concat(dn[i]," endpoint")),r\n
\n
\n \n
\n
\n ').concat(t,'\n
\n
\n

').concat(t,'

\n

').concat(n,'

\n
\n {"use strict";e.exports=function(e){return e[1]}},702:function(e,t,n){e.exports=function(){"use strict";function e(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function t(e){return"function"==typeof e}var r=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)},o=0,i=void 0,a=void 0,s=function(e,t){k[o]=e,k[o+1]=t,2===(o+=2)&&(a?a(w):S())};function u(e){a=e}function c(e){s=e}var l="undefined"!=typeof window?window:void 0,d=l||{},f=d.MutationObserver||d.WebKitMutationObserver,p="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),h="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel;function m(){return function(){return process.nextTick(w)}}function v(){return void 0!==i?function(){i(w)}:b()}function g(){var e=0,t=new f(w),n=document.createTextNode("");return t.observe(n,{characterData:!0}),function(){n.data=e=++e%2}}function y(){var e=new MessageChannel;return e.port1.onmessage=w,function(){return e.port2.postMessage(0)}}function b(){var e=setTimeout;return function(){return e(w,1)}}var k=new Array(1e3);function w(){for(var e=0;e{"use strict";var t=[];function n(e){for(var n=-1,r=0;r{"use strict";var t={};e.exports=function(e,n){var r=function(e){if(void 0===t[e]){var n=document.querySelector(e);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}t[e]=n}return t[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(n)}},216:e=>{"use strict";e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{"use strict";e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{"use strict";e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var r="";n.supports&&(r+="@supports (".concat(n.supports,") {")),n.media&&(r+="@media ".concat(n.media," {"));var o=void 0!==n.layer;o&&(r+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),r+=n.css,o&&(r+="}"),n.media&&(r+="}"),n.supports&&(r+="}");var i=n.sourceMap;i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),t.styleTagTransform(r,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},529:e=>{"use strict";e.exports="data:image/svg+xml;utf8, "}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={id:r,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.exports}n.m=e,n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.b=document.baseURI||self.location.href,n.nc=void 0;var r={};return(()=>{"use strict";function e(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(n){for(var r=1;r=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);nPo});var l=1e3,d=36e5,f=24*d,p="general",h="gdpr",m={TRANSACTION_ERROR:"XHR transaction failed due to an error",SERVER_MALFORMED_RESPONSE:"Response from server is malformed",SERVER_INTERNAL_ERROR:"Internal error occurred on the server",SERVER_CANNOT_PROCESS:"Server was not able to process the request, probably due to error coming from the client",NO_CONNECTION:"No internet connectivity",SKIP:"Skipping slower attempt",MISSING_URL:"Url is not provided"},v="noStorage",g="indexedDB",y="localStorage",b={endpointName:"Default",app:"https://app.adjust.com",gdpr:"https://gdpr.adjust.com"},k={endpointName:"Indian",app:"https://app.adjust.net.in",gdpr:"https://gdpr.adjust.net.in"},w={endpointName:"Chinese",app:"https://app.adjust.world",gdpr:"https://gdpr.adjust.world"},_={endpointName:"EU",app:"https://app.eu.adjust.com",gdpr:"https://gdpr.eu.adjust.com"},S={endpointName:"TR",app:"https://app.tr.adjust.com",gdpr:"https://gdpr.tr.adjust.com"},x={endpointName:"US",app:"https://app.us.adjust.com",gdpr:"https://gdpr.us.adjust.com"};function P(e){return P="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},P(e)}function j(e){return!Object.keys(e).length&&e.constructor===Object}function D(e){return"object"===P(e)&&null!==e&&!(e instanceof Array)}function N(e){try{return D(JSON.parse(e))}catch(e){return!1}}function I(e,t,n){function r(e){return Array.isArray(t)?t.every((function(t){return e[t]===n[t]})):e[t]===n}for(var o=0;o0&&void 0!==arguments[0]?arguments[0]:[];return t.reduce((function(t,n){return o(o({},t),{},e({},n.key,n.value))}),{})}function R(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];return e.filter((function(e){return-1!==t.indexOf(e)}))}function A(e,t){return new RegExp("\\/".concat(t,"(\\/.*|\\?.*){0,1}$")).test(e)}function C(t,n){var r=u(n,2),i=r[0],a=r[1];return o(o({},t),{},e({},i,a))}function E(e){return Object.keys(e).map((function(t){return[t,e[t]]}))}function O(e){return Object.keys(e).map((function(t){return e[t]}))}function B(e){return D(e)?!j(e):!!e||0===e}const K={namespace:"adjust-sdk",version:"5.4.0",env:"production"};var U,q="error",L="warning",M="info",W="verbose",V=(e(U={},"none",-1),e(U,q,0),e(U,L,1),e(U,M,2),e(U,W,3),U),z={log:" ",info:" ",warn:" ",error:""},F={development:W,production:q,test:W},G=J(),Y="";function J(){return F[K.env]||q}function X(e,t){var n;if(!(V[G]2?s-2:0),c=2;c2&&void 0!==arguments[2]?arguments[2]:[];return n.map((function(n){return Ae(e,t,n)}))}function Ee(e,t,n){var r=Pe[t][Be(e,Ie.right)],o=r.fields[r.keyPath],i=n instanceof Array?n.slice():[n],a=(he(o)?o.composite:[r.keyPath]).map((function(e,t){var n=r.fields[e];return Re(fe(n)?n.values:null,i[t])}));return 1===a.length?a[0]:a}function Oe(e){return Pe.values[e]||e}function Be(e,t){return(Pe.storeNames[t][e]||{}).name||e}function Ke(e,t){return{name:t.name,message:t.message.replace('"'.concat(e,'"'),Be(e,Ie.right))}}function Ue(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function qe(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:1,n=e+"",r=1;r<=t;r+=1)e0?"-":"+")+Me(Math.floor(Math.abs(t)/60))+Me(Math.abs(t)%60)}(t);return"".concat(n,"T").concat(r,"Z").concat(o)}function Ve(e,t){return isNaN(e)||isNaN(t)?0:Math.abs(t-e)}!function(e){e.LowerBound="lowerBound",e.UpperBound="upperBound"}(Ne||(Ne={})),function(e){e.right="right",e.left="left"}(Ie||(Ie={}));var ze={},Fe=!1,Ge=!1;function Ye(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};ze=Fe?o({},e):{}}function Je(){Fe&&(ze.lastInterval=function(){var e=ze.lastActive;if(e)return Math.round(Ve(e,Date.now())/l);return-1}(),ze.lastActive=Date.now())}function Xe(e){ze=o(o({},ze),e)}function Qe(){Ge=!0}function He(){var e=ze.lastActive;return Math.round(Ve(e,Date.now())/l)}function Ze(){return(ze.timeSpent||0)+(Ge?He():0)}function $e(){var e=Ve(ze.lastActive,Date.now())=0?ze.lastInterval:0,n={timeSpent:ze.timeSpent||0,sessionLength:ze.sessionLength||0,sessionCount:ze.sessionCount||1,lastInterval:t||0};return e&&A(e,"event")&&(n.eventCount=ze.eventCount),n},updateParams:function(e,t){if(Fe){var n={};n.timeSpent=Ze(),n.sessionLength=$e(),A(e,"session")&&(n.sessionCount=(ze.sessionCount||0)+1),A(e,"event")&&(n.eventCount=(ze.eventCount||0)+1),Xe(n),t||Je()}},updateInstalled:function(){Fe&&(ze.installed||Xe({installed:!0}))},updateSessionOffset:et,updateSessionLength:function(){Fe&&(Xe({sessionLength:$e()}),Je())},resetSessionOffset:function(){Fe&&Xe({timeSpent:0,sessionLength:0})},updateLastActive:Je,destroy:function(){ze={},Fe=!1,Ge=!1},getAttribution:function(){return Fe?ze.attribution?ze.attribution:(H.log("No attribution data yet"),null):null},getWebUUID:function(){return Fe?ze.uuid:null}};var nt={},rt=[];function ot(e,t){var n="id"+Math.random().toString(36).substr(2,16),r={id:n,cb:t};return nt[e]||(nt[e]=[]),nt[e].push(r),n}function it(e,t){nt[e]&&nt[e].forEach((function(n){"function"==typeof n.cb&&rt.push(setTimeout((function(){return n.cb(e,t)})))}))}const at=new(function(){function t(){var n=this;Ue(this,t),e(this,"defaultName",K.namespace),e(this,"storageName",this.defaultName),e(this,"storeNames",Pe.storeNames.left),e(this,"storesMap",void 0),this.storesMap={};var r=this.read.bind(this),o=this.write.bind(this);O(this.storeNames).forEach((function(e){var t=e.name;Object.defineProperty(n.storesMap,t,{get:function(){return r(t)},set:function(e){o(t,e)}})})),Object.freeze(this.storesMap)}return Le(t,[{key:"read",value:function(e){var t=localStorage.getItem("".concat(this.storageName,".").concat(e)),n=t?JSON.parse(t):null;return e===le.Preferences&&n?Ae(le.Preferences,Ie.right,n):n}},{key:"write",value:function(e,t){t?localStorage.setItem("".concat(this.storageName,".").concat(e),JSON.stringify(t instanceof Array?t:Ae(le.Preferences,Ie.left,t))):localStorage.removeItem("".concat(this.storageName,".").concat(e))}},{key:"clear",value:function(){this.deleteData()}},{key:"deleteData",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];O(this.storeNames).forEach((function(n){!t&&n.permanent||localStorage.removeItem("".concat(e.storageName,".").concat(n.name))}))}},{key:"setCustomName",value:function(e){var t=this;if(e&&e.length){var n="".concat(K.namespace,"-").concat(e);O(this.storeNames).forEach((function(e){var r=e.name,o=localStorage.getItem("".concat(t.storageName,".").concat(r));o&&localStorage.setItem("".concat(n,".").concat(r),o)})),this.deleteData(!0),this.storageName=n}}},{key:"stores",get:function(){return this.storesMap}}]),t}());var st=ve.preferences.name,ut=ct();function ct(){return ut||lt(),ut?o({},ut):null}function lt(){ut=at.stores[st]}function dt(){var e=ct();return e?e.sdkDisabled:null}function ft(e){var t=e?o({},e):null;at.stores[st]=o(o({},ct()),{},{sdkDisabled:t}),lt()}function pt(){var e=ct();return e?e.thirdPartySharingDisabled:null}function ht(){var e=at.stores[st]||{},t=(ut||{}).sdkDisabled||null;e.sdkDisabled&&!t&&it("sdk:shutdown"),lt()}function mt(){at.stores[st]||(at.stores[st]=o({},ut))}var vt,gt,yt="undefined"==typeof Promise?n(702).Promise:Promise;!function(e){e.add="add",e.put="put",e.get="get",e.list="list",e.clear="clear",e.delete="delete"}(vt||(vt={})),function(e){e.readonly="readonly",e.readwrite="readwrite"}(gt||(gt={}));var bt=function(){function t(){Ue(this,t),e(this,"dbDefaultName",K.namespace),e(this,"dbName",this.dbDefaultName),e(this,"dbVersion",1),e(this,"idbFactory",void 0),e(this,"indexedDbConnection",null),e(this,"notSupportedError",{name:"IDBNotSupported",message:"IndexedDB is not supported"}),e(this,"databaseOpenError",{name:"CannotOpenDatabaseError",message:"Cannot open a database"}),e(this,"noConnectionError",{name:"NoDatabaseConnection",message:"Cannot open a transaction"});var n=t.getIndexedDB();if(!n)throw this.notSupportedError;this.idbFactory=n}return Le(t,[{key:"setCustomName",value:function(e){return e&&e.length>0?(this.dbName="".concat(K.namespace,"-").concat(e),this.migrateDb(this.dbDefaultName,this.dbName)):yt.resolve()}},{key:"openDatabase",value:function(e,n,r){var o=this;return t.isSupported().then((function(t){return t?new yt((function(t,i){var a=o.idbFactory.open(e,r);n&&(a.onupgradeneeded=function(e){return n(e,i)}),a.onsuccess=function(e){var n=e.target.result;n?t(n):i(o.databaseOpenError)},a.onerror=i})):yt.reject(o.notSupportedError)}))}},{key:"databaseExists",value:function(e){var t=this;return new yt((function(n){var r=!0;t.openDatabase(e,(function(){r=!1})).then((function(n){if(n.close(),!r)return t.deleteDatabaseByName(e)})).then((function(){return n(r)}))}))}},{key:"cloneData",value:function(e,t){var n=this;return O(Pe.storeNames.left).map((function(e){return e.name})).filter((function(e){return"p"!==e})).map((function(r){return function(){return o=r,i=n.indexedDbConnection,n.indexedDbConnection=e,n.getAll(o).then((function(e){if(n.indexedDbConnection=t,!(e.length<1))return n.addBulk(o,e,!0)})).then((function(){n.indexedDbConnection=i}));var o,i}})).reduce((function(e,t){return e.then(t)}),yt.resolve())}},{key:"migrateDb",value:function(e,t){var n=this;return this.databaseExists(e).then((function(r){return r?yt.all([n.openDatabase(e,n.handleUpgradeNeeded,n.dbVersion),n.openDatabase(t,n.handleUpgradeNeeded,n.dbVersion)]).then((function(t){var r=u(t,2),o=r[0],i=r[1];return n.cloneData(o,i).then((function(){return n.indexedDbConnection=i,o.close(),n.deleteDatabaseByName(e)}))})).then((function(){return H.info("Database migration finished")})):n.openDatabase(t,n.handleUpgradeNeeded,n.dbVersion).then((function(e){n.indexedDbConnection=e}))}))}},{key:"handleUpgradeNeeded",value:function(e,t){var n=e.target.result;e.target.transaction.onerror=t,e.target.transaction.onabort=t;var r=Pe.storeNames.left,o=tt.current||{},i=o&&!j(o);E(r).filter((function(e){return!u(e,2)[1].permanent})).forEach((function(e){var t=u(e,2),r=t[0],a=t[1].name,s=Pe.right[r],c=n.createObjectStore(a,{keyPath:s.keyPath,autoIncrement:s.autoIncrement||!1});if(s.index&&c.createIndex("".concat(s.index,"Index"),s.index),a===ce.ActivityState&&i)return c.add(Ae(r,Ie.left,o)),void H.info("Activity state has been recovered");var l=at.stores[a];l&&(l.forEach((function(e){return c.add(e)})),H.info("Migration from localStorage done for ".concat(r," store")))})),mt(),at.clear()}},{key:"open",value:function(){var e=this;return this.indexedDbConnection?yt.resolve({success:!0}):this.openDatabase(this.dbName,this.handleUpgradeNeeded,this.dbVersion).then((function(t){return e.indexedDbConnection=t,e.indexedDbConnection.onclose=function(){return e.destroy},{success:!0}}))}},{key:"getTransactionStore",value:function(e,t,n){var r,o=e.storeName,i=e.mode,a=n.transaction([o],i),s=a.objectStore(o),u=Pe.right[Be(o,Ie.right)];return u.index&&(r=s.index("".concat(u.index,"Index"))),a.onerror=t,a.onabort=t,{transaction:a,store:s,index:r,options:u}}},{key:"overrideError",value:function(e,t){var n=t.target.error;return e({name:n.name,message:n.message})}},{key:"getCompositeKeys",value:function(e){var t=e.fields[e.keyPath];return he(t)?t.composite:null}},{key:"targetIsObject",value:function(e){return D(e)}},{key:"prepareTarget",value:function(t,n,r){if(r===vt.clear||!n)return null;var i=this.getCompositeKeys(t);return-1!==[vt.add,vt.put].indexOf(r)?this.targetIsObject(n)?i?o(e({},t.keyPath,i.map((function(e){return n[e]})).join("")),n):n:null:n instanceof Array?n.join(""):n}},{key:"prepareResult",value:function(e,t){var n=this.getCompositeKeys(e);return n&&this.targetIsObject(t)?n.map((function(e){return t[e]})):null}},{key:"initRequest",value:function(e){var t=this,n=e.storeName,r=e.target,o=void 0===r?null:r,i=e.action,a=e.mode,s=void 0===a?gt.readonly:a;return this.open().then((function(){return new yt((function(e,r){if(t.indexedDbConnection){var a=t.getTransactionStore({storeName:n,mode:s},r,t.indexedDbConnection),u=a.store,c=a.options,l=u[i](t.prepareTarget(c,o,i)),d=t.prepareResult(c,o);l.onsuccess=function(){i!==vt.get||l.result?e(d||l.result||o):r({name:"NotRecordFoundError",message:'Requested record not found in "'.concat(n,'" store')})},l.onerror=function(e){return t.overrideError(r,e)}}else r(t.noConnectionError)}))}))}},{key:"initBulkRequest",value:function(e){var t=this,n=e.storeName,r=e.target,o=e.action,i=e.mode,a=void 0===i?gt.readwrite:i;return!r||r&&!r.length?yt.reject({name:"NoTargetDefined",message:"No array provided to perform ".concat(o,' bulk operation into "').concat(n,'" store')}):this.open().then((function(){return new yt((function(e,i){if(t.indexedDbConnection){var s=t.getTransactionStore({storeName:n,mode:a},i,t.indexedDbConnection),u=s.transaction,c=s.store,l=s.options,d=new Array,f=r[0];u.oncomplete=function(){return e(d)};!function e(n){n.onerror=function(e){return t.overrideError(i,e)},n.onsuccess=function(){d.push(t.prepareResult(l,f)||n.result),f=r[d.length],d.length1&&void 0!==arguments[1]&&arguments[1];return this.openCursor({storeName:e,action:vt.list,firstOnly:t})}},{key:"getFirst",value:function(e){return this.getAll(e,!0).then((function(e){return e.length?e[0]:void 0}))}},{key:"getItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:vt.get})}},{key:"filterBy",value:function(e,t){var n=IDBKeyRange.only(t);return this.openCursor({storeName:e,action:vt.list,range:n})}},{key:"addItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:vt.add,mode:gt.readwrite})}},{key:"addBulk",value:function(e,t,n){return this.initBulkRequest({storeName:e,target:t,action:n?vt.put:vt.add,mode:gt.readwrite})}},{key:"updateItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:vt.put,mode:gt.readwrite})}},{key:"deleteItem",value:function(e,t){return this.initRequest({storeName:e,target:t,action:vt.delete,mode:gt.readwrite})}},{key:"deleteBulk",value:function(e,t,n){var r=n?IDBKeyRange[n](t):IDBKeyRange.only(t);return this.openCursor({storeName:e,action:vt.delete,range:r,mode:gt.readwrite})}},{key:"trimItems",value:function(e,t){var n=this,r=Pe.right[Be(e,Ie.right)];return this.getAll(e).then((function(e){return e.length?e[t-1]:null})).then((function(t){return t?n.deleteBulk(e,t[r.keyPath],Ne.UpperBound):[]}))}},{key:"count",value:function(e){var t=this;return this.open().then((function(){return new yt((function(n,r){if(t.indexedDbConnection){var o=t.getTransactionStore({storeName:e,mode:gt.readonly},r,t.indexedDbConnection).store.count();o.onsuccess=function(){return n(o.result)},o.onerror=function(e){return t.overrideError(r,e)}}else r(t.noConnectionError)}))}))}},{key:"clear",value:function(e){return this.initRequest({storeName:e,action:vt.clear,mode:gt.readwrite})}},{key:"destroy",value:function(){this.indexedDbConnection&&this.indexedDbConnection.close(),this.indexedDbConnection=null}},{key:"deleteDatabase",value:function(){return this.destroy(),this.deleteDatabaseByName(this.dbName)}}],[{key:"tryOpen",value:function(e){return new yt((function(n){try{var r=e.open(t.dbValidationName);r.onsuccess=function(){r.result.close(),e.deleteDatabase(t.dbValidationName),n(!0)},r.onerror=function(){return n(!1)}}catch(e){n(!1)}}))}},{key:"isSupported",value:function(){if(t.isSupportedPromise)return t.isSupportedPromise;var e="IndexedDB is not supported in this browser";return t.isSupportedPromise=new yt((function(n){var r=t.getIndexedDB(),o=!!navigator.platform&&/iPad|iPhone|iPod/.test(navigator.platform);!r||o?(H.warn(e),n(!1)):n(t.tryOpen(r).then((function(t){return t||H.warn(e),t})))})),t.isSupportedPromise}},{key:"getIndexedDB",value:function(){return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB}}]),t}();e(bt,"dbValidationName","validate-db-openable"),e(bt,"isSupportedPromise",null);var kt="undefined"==typeof Promise?n(702).Promise:Promise,wt=function(){function t(){Ue(this,t)}return Le(t,[{key:"open",value:function(){return t.isSupported().then((function(e){if(!e)return{status:"error",error:{name:"LSNotSupported",message:"LocalStorage is not supported"}};var t=Pe.storeNames.left,n=tt.current||{},r=n&&!j(n);return E(t).filter((function(e){return!u(e,2)[1].permanent})).forEach((function(e){var t=u(e,2),o=t[0],i=t[1].name;i!==ce.ActivityState||at.stores[i]?at.stores[i]||(at.stores[i]=[]):at.stores[i]=r?[Ae(o,Ie.left,n)]:[]})),mt(),{status:"success"}}))}},{key:"getCompositeKeys",value:function(e){var t=e.fields[e.keyPath];return he(t)?t.composite:null}},{key:"getKeys",value:function(e){var t=Be(e,Ie.right),n=Pe.right[t];return this.getCompositeKeys(n)||[n.keyPath]}},{key:"nextIndex",value:function(e){return"number"==typeof e?e+1:void 0}},{key:"initRequest",value:function(e,t){var n=this,r=e.storeName,i=e.id,a=e.item,s=Pe.right[Be(r,Ie.right)];return this.open().then((function(e){return"error"===e.status?kt.reject(e.error):new kt((function(e,u){var c,l=at.stores[r],d=n.getKeys(r),f=(l[l.length-1]||{})[s.keyPath]||0;if(i){var p=Array.isArray(i)?i.slice():[i];c=d.map((function(e,t){return[e,p[t]]})).reduce(C,{})}else c=o({},a);var h=c?I(l,d,c):0;return t(e,u,{keys:d,items:l,index:h,options:s,lastId:f})}))}))}},{key:"sort",value:function(e,t,n){var r=c(e),o=t.slice().reverse();return r.sort((function(e,t){return o.reduce((function(r,o){return r||function(e,t,r){var o=n?n===e[r]:e[r]e[r]:e[r]>t[r];return o?-1:i?1:0}(e,t,o)}),0)}))}},{key:"prepareTarget",value:function(t,n,r){var i=this.getCompositeKeys(t);return i?o(e({},t.keyPath,i.map((function(e){return n[e]})).join("")),n):t.autoIncrement&&r?o(e({},t.keyPath,r),n):o({},n)}},{key:"prepareResult",value:function(e,t){var n=this.getCompositeKeys(e);return n?n.map((function(e){return t[e]})).filter((function(e){return!Te(e)})):t[e.keyPath]}},{key:"getAll",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return this.open().then((function(r){return"error"===r.status?kt.reject(r.error):new kt((function(r,o){var i=at.stores[e];i instanceof Array?r(n?[i[0]]:t.sort(i,t.getKeys(e))):o({name:"NotFoundError",message:"No objectStore named ".concat(e," in this database")})}))}))}},{key:"getFirst",value:function(e){return this.getAll(e,!0).then((function(e){return e.length?e[0]:void 0}))}},{key:"getItem",value:function(e,t){var n=this;return this.initRequest({storeName:e,id:t},(function(t,r,o){var i=o.items,a=o.index,s=o.options;-1===a?r({name:"NotRecordFoundError",message:'Requested record not found in "'.concat(e,'" store')}):t(n.prepareTarget(s,i[a]))}))}},{key:"filterBy",value:function(e,t){return this.getAll(e).then((function(n){return n.filter((function(n){var r=Pe.right[Be(e,Ie.right)];return(r.index&&n[r.index])===t}))}))}},{key:"addItem",value:function(e,t){var n=this;return this.initRequest({storeName:e,item:t},(function(r,o,i){var a=i.items,s=i.index,u=i.options,c=i.lastId;-1!==s?o({name:"ConstraintError",message:'Constraint was not satisfied, trying to add existing item into "'.concat(e,'" store')}):(a.push(n.prepareTarget(u,t,n.nextIndex(c))),at.stores[e]=a,r(n.prepareResult(u,t)))}))}},{key:"addBulk",value:function(e,t,n){var r=this;return this.initRequest({storeName:e},(function(o,i,a){var s=a.keys,u=a.items,l=a.options,d=a.lastId;if(!t||t&&!t.length)i({name:"NoTargetDefined",message:'No array provided to perform add bulk operation into "'.concat(e,'" store')});else{var f=d,p=t.map((function(e){return r.prepareTarget(l,e,f=r.nextIndex(f))})),h=p.filter((function(e){return-1!==I(u,s,e)})).map((function(e){return e[l.keyPath]})),m=n?u.filter((function(e){return-1===h.indexOf(e[l.keyPath])})):c(u);if(h.length&&!n)i({name:"ConstraintError",message:'Constraint was not satisfied, trying to add existing items into "'.concat(e,'" store')});else at.stores[e]=r.sort([].concat(c(m),c(p)),s),o(t.map((function(e){return r.prepareResult(l,e)})))}}))}},{key:"updateItem",value:function(e,t){var n=this;return this.initRequest({storeName:e,item:t},(function(r,o,i){var a=i.items,s=i.index,u=i.options,c=i.lastId,l=-1===s?n.nextIndex(c):void 0,d=n.prepareTarget(u,t,l);-1===s?a.push(d):a.splice(s,1,d),at.stores[e]=a,r(n.prepareResult(u,t))}))}},{key:"deleteItem",value:function(e,t){return this.initRequest({storeName:e,id:t},(function(n,r,o){var i=o.items,a=o.index;-1!==a&&(i.splice(a,1),at.stores[e]=i),n(t)}))}},{key:"findMax",value:function(e,t,n){if(!e.length)return-1;for(var r={index:-1,value:"string"==typeof n?"":0},o=0;o=r.value&&(r={value:e[o][t],index:o})}return r.index}},{key:"deleteBulk",value:function(e,t,n){var r=this;return this.getAll(e).then((function(o){var i=r.getKeys(e),a=Pe.right[Be(e,Ie.right)].index||i[0],s=n?null:t,u=r.sort(o,i,s),c=r.findMax(u,a,t);if(-1===c)return[];var l=n===Ne.LowerBound?c:0,d=n&&n!==Ne.UpperBound?u.length:c+1,f=u.splice(l,d).map((function(e){return 1===i.length?e[a]:i.map((function(t){return e[t]}))}));return at.stores[e]=u,f}))}},{key:"trimItems",value:function(e,t){var n=this,r=Be(e,Ie.right),o=Pe.right[r];return this.getAll(e).then((function(e){return e.length?e[t-1]:null})).then((function(t){return t?n.deleteBulk(e,t[o.keyPath],Ne.UpperBound):[]}))}},{key:"count",value:function(e){return this.open().then((function(t){if("error"===t.status)return kt.reject(t.error);var n=at.stores[e];return kt.resolve(n instanceof Array?n.length:1)}))}},{key:"clear",value:function(e){return this.open().then((function(t){return"error"===t.status?kt.reject(t.error):new kt((function(t){at.stores[e]=[],t()}))}))}},{key:"destroy",value:function(){}},{key:"deleteDatabase",value:function(){}}],[{key:"isSupported",value:function(){if(t.isSupportedPromise)return t.isSupportedPromise;var e=(new Date).toString(),n=window.localStorage;return t.isSupportedPromise=new kt((function(t){n.setItem(e,e);var r=n.getItem(e)===e;n.removeItem(e),t(!(!r||!n))})).catch((function(){return H.warn("LocalStorage is not supported in this browser"),kt.resolve(!1)})),t.isSupportedPromise}}]),t}();e(wt,"isSupportedPromise",null);var _t,St="undefined"==typeof Promise?n(702).Promise:Promise;!function(e){e[e.noStorage=v]="noStorage",e[e.indexedDB=g]="indexedDB",e[e.localStorage=y]="localStorage"}(_t||(_t={}));var xt,Pt={getAll:function(e,t,n){return e.getAll(t,n).then((function(e){return Ce(t,Ie.right,e)}))},getFirst:function(e,t){return e.getFirst(t).then((function(e){return Ae(t,Ie.right,e)}))},getItem:function(e,t,n){return e.getItem(t,Ee(t,Ie.left,n)).then((function(e){return Ae(t,Ie.right,e)})).catch((function(e){return St.reject(Ke(t,e))}))},filterBy:function(e,t,n){return e.filterBy(t,Oe(n)).then((function(e){return Ce(t,Ie.right,e)}))},addItem:function(e,t,n){var r=Ae(t,Ie.left,n);return e.addItem(t,r).then((function(e){return Ee(t,Ie.right,e)})).catch((function(e){return St.reject(Ke(t,e))}))},addBulk:function(e,t,n,r){var o=Ce(t,Ie.left,n);return e.addBulk(t,o,r).then((function(e){return e.map((function(e){return Ee(t,Ie.right,e)}))})).catch((function(e){return St.reject(Ke(t,e))}))},updateItem:function(e,t,n){var r=Ae(t,Ie.left,n);return e.updateItem(t,r).then((function(e){return Ee(t,Ie.right,e)}))},deleteItem:function(e,t,n){return e.deleteItem(t,Ee(t,Ie.left,n)).then((function(e){return Ee(t,Ie.right,e)}))},deleteBulk:function(e,t,n,r){return e.deleteBulk(t,Oe(n),r).then((function(e){return e.map((function(e){return Ee(t,Ie.right,e)}))}))},trimItems:function(e,t,n){return e.trimItems(t,n)},count:function(e,t){return e.count(t)},clear:function(e,t){return e.clear(t)},destroy:function(e){return e.destroy()},deleteDatabase:function(e){return e.deleteDatabase()}};var jt=null;function Dt(e){var t=null;return null!==jt?jt:jt=St.all([bt.isSupported(),wt.isSupported()]).then((function(n){var r=u(n,2),o=r[0],i=r[1];if(at.setCustomName(e),o){xt=_t.indexedDB;var a=new bt;return a.setCustomName(e).then((function(){return t=a}))}return i?(xt=_t.localStorage,t=new wt,St.resolve(t)):(H.error("There is no storage available, app will run with minimum set of features"),xt=_t.noStorage,t=null,St.resolve(t))})).then((function(){return{type:xt,storage:t}}))}const Nt=o({init:Dt,getType:function(){return xt}},(It=E(Pt).map((function(e){var t=u(e,2),n=t[0],r=t[1];return[n,function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o2&&void 0!==arguments[2]&&arguments[2];return{status:"error",action:n?"CONTINUE":"RETRY",response:N(e.responseText)?JSON.parse(e.responseText):e.responseText,message:m[t],code:t}}function Ct(e,t){var n=e.slice(0,e.length-t.length-1).split("").reduce((function(e){return e.concat(" ")}),"");return"".concat(t).concat(n,":")}function Et(e,t){var n="REQUEST PARAMETERS:",r=function(e){return e.replace(/([A-Z])/g,(function(e){return"_".concat(e.toLowerCase())}))},i=E(o(o(o({},ie.getBaseParams()),t),e)).map((function(e){var t=u(e,2),n=t[0],o=t[1];return[r(n),o]}));return H.log(n),i.filter((function(e){return B(u(e,2)[1])})).map((function(e){var t=u(e,2),r=t[0],o=t[1];return H.log(Ct(n,r),o),function(e){var t=u(e,2),n=t[0],r=t[1],o=encodeURIComponent(n),i=r;return"string"==typeof r&&(i=encodeURIComponent(r)),D(r)&&(i=encodeURIComponent(JSON.stringify(r)||"")),[o,i].join("=")}([r,o])})).join("&")}function Ot(e,t,n){var r=n.xhr,o=n.url;if(4===r.readyState){var i=r.status>=200&&r.status<300,a=N(r.responseText);if(0!==r.status)return a?t(i?function(e,t){var n=JSON.parse(e.responseText),r={status:"success",adid:n.adid,timestamp:n.timestamp,ask_in:n.ask_in,retry_in:n.retry_in,continue_in:n.continue_in,tracking_state:n.tracking_state,attribution:void 0,message:void 0};return A(t,"attribution")&&(r.attribution=n.attribution,r.message=n.message),E(r).filter((function(e){return!!u(e,2)[1]})).reduce(C,{})}(r,o):At(r,"SERVER_CANNOT_PROCESS",!0)):e(At(r,i?"SERVER_MALFORMED_RESPONSE":"SERVER_INTERNAL_ERROR"));e(At(r,"NO_CONNECTION"))}}function Bt(e,t){var n=e.endpoint,r=e.url,o=e.method,i=void 0===o?"GET":o,a=e.params,s=function(e,t){var n=e.endpoint,r=e.url,o=e.method,i=Et(e.params,t);return{fullUrl:n+r+("GET"===o?"?".concat(i):""),encodedParams:i}}({endpoint:n,url:r,method:i,params:void 0===a?{}:a},t),c=s.fullUrl,l=s.encodedParams;return new Rt((function(e,t){var n=new XMLHttpRequest;n.open(i,c,!0),function(e,t){var n="REQUEST HEADERS:",r=[["Client-SDK","js".concat(K.version)],["Content-Type","POST"===t?"application/x-www-form-urlencoded":"application/json"]];H.log(n),r.forEach((function(t){var r=u(t,2),o=r[0],i=r[1];e.setRequestHeader(o,i),H.log(Ct(n,o),i)}))}(n,i),n.onreadystatechange=function(){return Ot(t,e,{xhr:n,url:r})},n.onerror=function(){return t(At(n,"TRANSACTION_ERROR"))},n.send("GET"===i?void 0:l)}))}function Kt(e,t){return"success"===e.status?function(e,t){var n=A(t,"gdpr_forget_device"),r=A(t,"attribution"),o=A(t,"session"),i=A(t,"disable_third_party_sharing"),a="opted_out"===e.tracking_state;if(!n&&a)return it("sdk:gdpr-forget-me"),e;r||n||a||!e.ask_in||it("attribution:check",e);o&&it("session:finished",e);if(i)return it("sdk:third-party-sharing-opt-out"),e;return e}(e,t):e}function Ut(e){return Tt().then((function(t){return Bt(e,t)})).then((function(t){return Kt(t,e.url)}))}var qt={long:{delay:12e4,maxDelay:f,minRange:.5,maxRange:1},short:{delay:200,maxDelay:d,minRange:.5,maxRange:1},test:{delay:100,maxDelay:300}};function Lt(e,t){var n,r,o=qt[t=t||"long"],i=o.delay*Math.pow(2,e-1);return i=Math.min(i,o.maxDelay),o.minRange&&o.maxRange&&(i*=(n=o.minRange,r=o.maxRange,Math.random()*(r-n)+n)),Math.round(i)}var Mt,Wt,Vt,zt=navigator.onLine;function Ft(){zt=!0}function Gt(){zt=!1}function Yt(e,t,n){e.addEventListener&&e.addEventListener(t,n,!1)}function Jt(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}function Xt(){return zt}function Qt(e,t){H.warn("Both ".concat(e," and ").concat(t," are set in config, ").concat(t," will be ignored"))}!function(e){e.Default="default",e.India="india",e.China="china"}(Wt||(Wt={})),function(e){e.EU="EU",e.TR="TR",e.US="US"}(Vt||(Vt={}));var Ht=(e(Mt={},Wt.Default,b),e(Mt,Wt.India,k),e(Mt,Wt.China,w),e(Mt,Vt.EU,_),e(Mt,Vt.TR,S),e(Mt,Vt.US,x),Mt);function Zt(e){var t,n,r,o,i=(t=ie.getCustomConfig(),n=t.customUrl,r=t.urlStrategy,o=t.dataResidency,n?((o||r)&&Qt("customUrl",o?"dataResidency":"urlStrategy"),{app:n,gdpr:n}):(o&&r&&Qt("dataResidency","urlStrategy"),o?[o]:r===Wt.India?[Wt.India,Wt.Default]:r===Wt.China?[Wt.China,Wt.Default]:[Wt.Default,Wt.India,Wt.China]));return Array.isArray(i)?i.map((function(t){return e[t]||null})).filter((function(e){return!!e})):[i]}function $t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Ht,t=Zt(e),n=0;return{next:function(){return n0&&void 0!==arguments[0]?arguments[0]:{},r=n.url,i=n.method,a=void 0===i?"GET":i,s=n.params,c=void 0===s?{}:s,l=n.continueCb,d=n.strategy,f=n.wait,p={url:r,method:a,params:c,continueCb:l},h=r,v=a,g=o({},c),y=l,b=d,k=function(){e.reset(),t=e.next()},w=function(e,t){return e["/gdpr_forget_device"===t?"gdpr":"app"]},_=null,S={request:0,connection:0},x=D(f),P=null;function D(e){return(e=e||tn)>nn?nn:e}function N(e){var t=e.url,n=e.method,r=e.params,i=e.continueCb;t&&(h=t),n&&(v=n),j(r)||(g=o({},r)),g=o({createdAt:We()},g),"function"==typeof i&&(y=i)}function I(e){if(!P)return!1;if(_){var t=x-(Date.now()-P);if(e&&t0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,n=e.method,r=e.params,o=void 0===r?{}:r,i=e.continueCb,a=e.wait;return N({url:t,method:n,params:o,continueCb:i}),T({wait:a})}function W(){return!!_}function V(){_&&clearTimeout(_),_=null}function z(){var e=!!P;V(),P=null,e&&(x=tn,S.request=0,S.connection=0,H.log("Previous ".concat(h||"unknown"," request attempt canceled")),O())}return{send:M,isRunning:W,clear:z}};var an=function(e){return e===h?"GDPR disable":"disable"},sn=function(e){return{start:{inProgress:"Adjust SDK ".concat(an(e)," process has already started"),done:"Adjust SDK ".concat(an(e)," process is now started")},finish:{inProgress:"Adjust SDK ".concat(an(e)," process has already finished"),done:"Adjust SDK ".concat(an(e)," process is now finished")}}};function un(e,t){var n=e.reason,r=e.pending,o=dt()||{},i="start"===t&&o.pending?"start":"finish",a="start"===t&&o.reason,s="finish"===t&&o.reason&&!o.pending;return a||s?(H.log(sn(o.reason)[i].inProgress),!1):(H.log(sn(n)[i].done),ft({reason:n||p,pending:r}),!0)}function cn(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return un({reason:e,pending:t||!1},"start")}function ln(){var e=dt()||{};return e.reason===p||e.reason===h&&!e.pending?"off":e.reason===h&&e.pending?"paused":"on"}var dn="undefined"==typeof Promise?n(702).Promise:Promise,fn="activityState",pn=!1;function hn(e){return e?"unknown"===e.uuid?(cn({reason:h}),tt.destroy(),{exists:!0,stored:null}):(tt.init(e),{exists:!0,stored:e}):{exists:!1}}function mn(){return"off"!==ln()&&tt.isStarted()}function vn(){if(!mn())return dn.resolve(null);var e=o(o({},tt.current),{},{lastActive:Date.now()});return Nt.updateItem(fn,e).then((function(){return tt.current=e}))}var gn="undefined"==typeof Promise?n(702).Promise:Promise,yn=on({strategy:"long",continueCb:function(e,t){var n=e&&e.continue_in||null;return wn.pause=n?{timestamp:Date.now(),wait:n}:null,Nt.getFirst(kn).then((function(e){return e?Nt.deleteItem(kn,e.timestamp):null})).then((function(){return t(),wn.running=!1,Dn({wait:n})}))}}),bn=!1,kn="queue",wn={running:!1,timestamp:null,pause:null};function _n(){var e=Date.now();return wn.timestamp&&e<=wn.timestamp&&(e=wn.timestamp+1),wn.timestamp=e,e}function Sn(e){return A(e,"session")&&tt.resetSessionOffset(),tt.updateLastActive(),vn()}function xn(e){var t=e.url,n=e.method,r=e.params,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=i.auto,s=i.timestamp;tt.updateParams(t,a);var c=E(r||{}).filter((function(e){return B(u(e,2)[1])})).reduce(C,{}),l={timestamp:_n(),url:t,method:n,params:o(o({},tt.getParams(t)),c)};return s&&(l.createdAt=s),Nt.addItem(kn,l).then((function(){return Sn(t)})).then((function(){return wn.running?{}:Dn()}))}function Pn(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.timestamp,n=e.createdAt,r=e.url,i=e.method,a=e.params,s=arguments.length>1?arguments[1]:void 0,u=tt.current||{},c="/session"===r&&!u.installed,l=!r&&!i&&!a;return bn&&!c||l?(wn.running=!1,gn.resolve({})):yn.send({url:r,method:i,params:o(o({},a),{},{createdAt:We(n||t)}),wait:s||jn()})}function jn(){var e=wn.pause||{},t=e.timestamp,n=e.wait,r=Date.now()-(t||0);return r0&&void 0!==arguments[0]?arguments[0]:{},t=e.cleanUp,n=e.wait;if(wn.running)return gn.resolve({});wn.running=!0;var r=gn.resolve({});return t&&(r=r.then(In)),r.then((function(){return Nt.getFirst(kn)})).then((function(e){return Pn(e,n)}))}function Nn(e){if(void 0!==e)if(e!==bn){var t=bn;bn=e,!e&&t&&Dn(),H.info("The app is now in ".concat(e?"offline":"online"," mode"))}else H.error("The app is already in ".concat(e?"offline":"online"," mode"));else H.error("State not provided, true or false has to be defined")}function In(){var e=Date.now()-ie.requestValidityWindow;return Nt.deleteBulk(kn,e,"upperBound")}var Tn="undefined"==typeof Promise?n(702).Promise:Promise,Rn="globalParams",An="No type provided",Cn="Global parameter type not provided, `callback` or `partner` types are available";function En(e){return(e||[]).map((function(e){return{key:e.key,value:e.value}}))}function On(){return Tn.all([Nt.filterBy(Rn,"callback"),Nt.filterBy(Rn,"partner")]).then((function(e){var t=u(e,2),n=t[0],r=t[1];return{callbackParams:En(n),partnerParams:En(r)}}))}function Bn(e,t){if(void 0===t)return H.error(Cn),Tn.reject({message:An});var n=T(e),r=Object.keys(n).map((function(e){return{key:e,value:n[e],type:t}}));return Tn.all([Nt.filterBy(Rn,t),Nt.addBulk(Rn,r,!0)]).then((function(e){var n=u(e,2),o=n[0],i=n[1],a=R(o.map((function(e){return e.key})),i.map((function(e){return e[0]})));return H.log("Following ".concat(t," parameters have been saved: ").concat(r.map((function(e){return"".concat(e.key,":").concat(e.value)})).join(", "))),a.length&&H.log("Keys: ".concat(a.join(", ")," already existed so their values have been updated")),i}))}function Kn(e,t){return void 0===t?(H.error(Cn),Tn.reject({message:An})):Nt.deleteItem(Rn,[e,t]).then((function(n){return H.log("".concat(e," ").concat(t," parameter has been deleted")),n}))}function Un(e){return void 0===e?(H.error(Cn),Tn.reject({message:An})):Nt.deleteBulk(Rn,e).then((function(t){return H.log("All ".concat(e," parameters have been deleted")),t}))}var qn,Ln,Mn,Wn="undefined"==typeof Promise?n(702).Promise:Promise,Vn=!1,zn=document;function Fn(){return Mn=function(){var e=document;if(void 0!==e.hidden)return{hidden:"hidden",visibilityChange:"visibilitychange"};for(var t=E({mozHidden:"mozvisibilitychange",msHidden:"msvisibilitychange",oHidden:"ovisibilitychange",webkitHidden:"webkitvisibilitychange"}),n=0;n0;return!n||n&&t*l>=ie.sessionWindow?On().then((function(e){var t,n,r;xn({url:"/session",method:"POST",params:(t=e,n=t.callbackParams,r=t.partnerParams,{callbackParams:n.length?T(n):null,partnerParams:r.length?T(r):null})},{auto:!0})})):(it("attribution:check"),vn())}var Zn="undefined"==typeof Promise?n(702).Promise:Promise,$n=on({url:"/attribution",strategy:"short",continueCb:function(e,t,n){if(!e||e&&"error"===e.status)return t(),Zn.resolve({state:"unknown"});if(!e.ask_in)return t(),function(e){if(j(e)||!function(e){var t=e.adid,n=void 0===t?"":t,r=e.attribution,o=void 0===r?{}:r;return!!n&&!!R(er,Object.keys(o)).length}(e)||function(e){var t=e.adid,n=e.attribution,r=tt.current.attribution||{};return!(n&&er.some((function(e){return r[e]!==n[e]})))&&t===r.adid}(e))return Zn.resolve({state:"same"});var t=E(e.attribution).filter((function(e){var t=u(e,1)[0];return-1!==er.indexOf(t)})).reduce(C,{adid:e.adid});return tt.current=o(o({},tt.current),{},{attribution:t}),vn().then((function(){return it("attribution:change",t),H.info("Attribution has been updated"),{state:"changed"}}))}(e);return n(e.ask_in)}}),er=["tracker_token","tracker_name","network","campaign","adgroup","creative","click_label","state"];var tr=on({url:"/gdpr_forget_device",method:"POST",strategy:"short"}),nr={running:"Adjust SDK is running pending GDPR Forget Me request",pending:"Adjust SDK will run GDPR Forget Me request after initialisation",paused:"Adjust SDK is already prepared to send GDPR Forget Me request",off:"Adjust SDK is already disabled"};function rr(e){var t=ln();return e||"on"===t?ie.isInitialised()?(tr.send({params:o({},tt.getParams())}).then((function(){it("sdk:gdpr-forget-me")})),!0):(H.log(nr.pending),!0):(H.log(nr[t]),!1)}function or(){return un({reason:h,pending:!1},"finish")}var ir={running:"Adjust SDK is running pending third-party sharing opt-out request",delayed:"Adjust SDK will run third-party sharing opt-out request after initialisation",pending:"Adjust SDK already queued third-party sharing opt-out request",off:"Third-party sharing opt-out is already done",start:{inProgress:"Third-party sharing opt-out has already started",done:"Third-party sharing opt-out is now started"},finish:{inProgress:"Third-party sharing opt-out has already finished",done:"Third-party sharing opt-out is now finished"}};function ar(){var e=pt()||{};return e.reason?e.pending?"pending":"off":"on"}function sr(e){var t=ar();return e||"on"===t?ie.isInitialised()?(xn({url:"/disable_third_party_sharing",method:"POST"}),!0):(H.log(ir.delayed),!0):(H.log(ir[t]),!1)}function ur(e,t){var n,r,i=pt()||{},a="start"===t&&e?"start":"finish",s="start"===t&&i.reason,u="finish"===t&&i.reason&&!i.pending;return s||u?(H.log(ir[a].inProgress),!1):(H.log(ir[a].done),r=(n={reason:p,pending:e})?o({},n):null,at.stores[st]=o(o({},ct()),{},{thirdPartySharingDisabled:r}),lt(),!0)}function cr(){return ur(!1,"finish")}function lr(){"pending"===ar()&&(H.log(ir.running),sr(!0))}var dr=[];function fr(e,t){dr.push({method:e,description:t,timestamp:Date.now()})}var pr,hr="undefined"==typeof Promise?n(702).Promise:Promise,mr="eventDeduplication";function vr(e,t){var n,r,i=t.callbackParams,a=t.partnerParams,s={},u=o({eventToken:e.eventToken,deduplicationId:e.deduplicationId},(n=e.revenue,r=e.currency,isNaN(n)||(n=parseFloat(n))<0||!r?{}:{revenue:n.toFixed(5),currency:r})),c=o(o({},T(i)),T(e.callbackParams)),l=o(o({},T(a)),T(e.partnerParams));return j(c)||(s.callbackParams=c),j(l)||(s.partnerParams=l),o(o({},u),s)}function gr(e){return e?Nt.getAll(mr).then((function(e){return e.map((function(e){return e.id}))})).then((function(t){return-1===t.indexOf(e)?function(e){var t=ie.getCustomConfig().eventDeduplicationListLimit,n=t>0?t:10;return Nt.count(mr).then((function(e){var t=hr.resolve();if(e>=n){var r=e-n+1;H.log("Event deduplication list limit has been reached. Oldest ids are about to be removed (".concat(r," of them)")),t=Nt.trimItems(mr,r)}return t})).then((function(){return H.info("New event deduplication id is added to the list: ".concat(e)),Nt.addItem(mr,{id:e})}))}(e):hr.reject({message:"Event won't be tracked, since it was previously tracked with the same deduplication id ".concat(e)})})):hr.resolve()}function yr(e){return{clickTime:We(),source:"web_referrer",referrer:decodeURIComponent(e)}}function br(){var e=window.location.search.substring(1).split("&").map((function(e){return e.split("=")})).reduce(C,{}).adjust_referrer;e&&xn({url:"/sdk_click",method:"POST",params:yr(e)})}function kr(e){if(!e)return null;try{return JSON.parse(e)}catch(e){return null}}!function(e){e.Android="android",e.iOS="ios",e.WindowsPC="windows",e.WindowsPhone="windows-phone"}(pr||(pr={}));var wr="adjust-smart-banner";var _r,Sr={getItem:function(e){return kr(localStorage.getItem("".concat(wr,".").concat(e)))},setItem:function(e,t){t?localStorage.setItem("".concat(wr,".").concat(e),JSON.stringify(t)):localStorage.removeItem("".concat(wr,".").concat(e))}};"undefined"==typeof Promise&&n(702).Promise;function xr(e,t,n){return n.request("/smart_banner",{app_web_token:e}).then((function(e){var n,r,o,i,a,s,u,c=e.find((function(e){return e.platform===t}));return c?(i=(n=c).title,a=n.description,s=n.button_label,u=n.tracker_token,i&&a&&s&&u?{appId:(null===(r=n.app)||void 0===r?void 0:r.default_store_app_id)||"",appName:(null===(o=n.app)||void 0===o?void 0:o.name)||"",position:n.position||_r.Bottom,imageUrl:n.image_url,header:i,description:a,buttonText:s,trackerToken:u,deeplinkPath:n.deeplink_path,dismissInterval:864e5}:null):null})).catch((function(e){return H.error("Network error occurred during loading Smart Banner: "+JSON.stringify(e)),null}))}!function(e){e.Top="top",e.Bottom="bottom"}(_r||(_r={}));var Pr=n(379),jr=n.n(Pr),Dr=n(795),Nr=n.n(Dr),Ir=n(569),Tr=n.n(Ir),Rr=n(565),Ar=n.n(Rr),Cr=n(216),Er=n.n(Cr),Or=n(589),Br=n.n(Or),Kr=n(841),Ur={};Ur.styleTagTransform=Br(),Ur.setAttributes=Ar(),Ur.insert=Tr().bind(null,"head"),Ur.domAPI=Nr(),Ur.insertStyleElement=Er();jr()(Kr.Z,Ur);const qr=Kr.Z&&Kr.Z.locals?Kr.Z.locals:void 0;var Lr="undefined"==typeof Promise?n(702).Promise:Promise,Mr=function(){function t(n,r,o){Ue(this,t),e(this,"appTraceUrl",(function(e){return"https://www.apptrace.com/api/app/".concat(e,"/artwork_url_small")})),e(this,"appName",void 0),e(this,"image",void 0),e(this,"placeholder",void 0),this.image=r,this.placeholder=o,this.appName=n.appName;var i=this.getSources(n);this.showImage(i)}return Le(t,[{key:"getSources",value:function(e){var t=[];return e.imageUrl&&t.push(e.imageUrl),t.push(this.appTraceUrl(e.appId)),t}},{key:"showImage",value:function(e){var t=this;return e.reduce((function(e,n){return e.catch((function(){return t.loadImage(n,t.image)}))}),Lr.reject()).then((function(){t.placeholder.remove()})).catch((function(){t.image.remove(),t.placeholder.innerText=t.appName.length?t.appName[0].toUpperCase():""}))}},{key:"loadImage",value:function(e,t){return new Lr((function(n,r){t.onload=n,t.onerror=r,t.src=e}))}}]),t}(),Wr=function(){function t(n,r,o){Ue(this,t),e(this,"parent",document.body),e(this,"banner",void 0),e(this,"dismissButton",null),e(this,"onDismiss",void 0),this.onDismiss=r,this.render(n,o)}return Le(t,[{key:"render",value:function(e,t){this.banner=document.createElement("div"),this.banner.setAttribute("class",qr.bannerContainer);var n=e.position===_r.Top?qr.stickyToTop:qr.stickyToBottom,r=e.deeplinkPath?"?deeplink=".concat(encodeURIComponent(e.deeplinkPath)):"",o="".concat(t,"/").concat(e.trackerToken).concat(r);this.banner.innerHTML=function(e,t,n,r,o){return'\n
\n
\n
\n \n
\n
\n ').concat(t,'\n
\n
\n

').concat(t,'

\n

').concat(n,'

\n
\n
1&&void 0!==arguments[1]?arguments[1]:r;return function(){return o(t,e)}}}(Hr||(Hr={})),(Zr||(Zr={})).preferredUrlsGetter=function(e){return function(){return function(e){return[{endpointName:"Custom (".concat(e,")"),app:e,gdpr:e}]}(e)}},function(t){t.EU="EU",t.TR="TR",t.US="US";var n,r=(e(n={},$r.EU,_),e(n,$r.TR,S),e(n,$r.US,x),n),o=function(e,t){return[e[t]]};t.preferredUrlsGetter=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:r;return function(){return o(t,e)}}}($r||($r={})),function(e){var t=function(e,t){H.warn("Both ".concat(e," and ").concat(t," are set in config, ").concat(t," will be ignored"))};e.create=function(e){var n=e.customUrl,r=e.dataResidency,o=e.urlStrategy;return n?((r||o)&&t("customUrl",r?"dataResidency":"urlStrategy"),new no(Zr.preferredUrlsGetter(n))):r?(o&&t("dataResidency","urlStrategy"),new no($r.preferredUrlsGetter(r))):new no(Hr.preferredUrlsGetter(o))}}(eo||(eo={}));"undefined"==typeof Promise&&n(702).Promise;var ro=function(t){!function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,"prototype",{writable:!1}),t&&Yr(e,t)}(r,t);var n=Qr(r);function r(t,o){var i,a=o.urlStrategy,s=o.urlStrategyConfig;return Ue(this,r),e(Gr(i=n.call(this,t)),"lastSuccessfulEndpoint",void 0),e(Gr(i),"urlStrategy",void 0),i.urlStrategy=a||eo.create(s),i}return Le(r,[{key:"endpoint",get:function(){return this.lastSuccessfulEndpoint||r.DEFAULT_ENDPOINT}},{key:"request",value:function(e,t){var n=this;return this.urlStrategy.retries((function(r){return n.network.endpoint=r.app,n.network.request(e,t).then((function(e){return n.lastSuccessfulEndpoint=r.app,e})).catch((function(e){throw n.lastSuccessfulEndpoint=void 0,e}))}))}}]),r}(to);e(ro,"DEFAULT_ENDPOINT",b.app),ro||(ro={});"undefined"==typeof Promise&&n(702).Promise;var oo=function(){function t(n,r){var o=n.webToken,i=n.logLevel,a=void 0===i?"error":i,s=n.dataResidency,u=n.onCreated,c=n.onDismissed;Ue(this,t),e(this,"STORAGE_KEY_DISMISSED","closed"),e(this,"network",void 0),e(this,"timer",null),e(this,"dataFetchPromise",void 0),e(this,"banner",void 0),e(this,"onCreated",void 0),e(this,"onDismissed",void 0),this.onCreated=u,this.onDismissed=c,H.setLogLevel(a);var l=s?{dataResidency:s}:{};this.network=r||new ro(new Fr,{urlStrategyConfig:l}),this.init(o)}return Le(t,[{key:"init",value:function(e){var t=this;if(this.banner)H.error("Smart Banner already exists");else if(this.dataFetchPromise)H.error("Smart Banner is initialising already");else{var n=function(){var e,t,n=null===(e=navigator)||void 0===e||null===(t=e.userAgent)||void 0===t?void 0:t.toLowerCase();if(n&&!(n.length<1))return/ipad|iphone|ipod/.test(n)?pr.iOS:n.includes("windows")?/phone|mobile/.test(n)?pr.WindowsPhone:pr.WindowsPC:n.includes("android")?pr.Android:void 0}();n?(this.dataFetchPromise=xr(e,n,this.network),this.dataFetchPromise.then((function(r){if(t.dataFetchPromise=null,r){var o=t.getDateToShowAgain(r.dismissInterval);if(Date.now()
+
+ + +
+ +
+ + +
+
-
- - -
- -
- - -
+ +
+ + + +

diff --git a/src/demo/tabs/tabs.js b/src/demo/tabs/tabs.js
index 69cf6e72..9535c9ee 100644
--- a/src/demo/tabs/tabs.js
+++ b/src/demo/tabs/tabs.js
@@ -1,6 +1,6 @@
 import {hyphenToCamelCase} from '../utils'
 import {getItem, setItem, clear} from '../storage'
-import {write} from '../log'
+import {write, clear as clearLog} from '../log'
 import Adjust from '../../sdk/main'
 
 const _ui = {}
@@ -15,11 +15,13 @@ function init (defaultAppConfig) {
 
   _ui.logTab = document.getElementById('log-tab')
   _ui.logTabContainer = document.getElementById('log-tab-container')
+  _ui.logClearButton = document.getElementById('log-tab-clear-button')
   _ui.appConfigTab = document.getElementById('app-config-tab')
   _ui.appConfigTabContainer = document.getElementById('app-config-tab-container')
   _ui.appConfigForm = document.getElementById('app-config-form')
   _ui.appConfigJson = document.getElementById('app-config-json')
   _ui.submitButton = _ui.appConfigForm.querySelector('button[type="submit"]')
+  _ui.restoreDefaultConfig = _ui.appConfigForm.querySelector('#restore-default-config')
   _ui.resetButton = _ui.appConfigForm.querySelector('#reset')
 
   _prepareForm()
@@ -28,8 +30,10 @@ function init (defaultAppConfig) {
   _active.container = _ui.logTabContainer
 
   _ui.logTab.addEventListener('click', _handleTab, false)
+  _ui.logClearButton.addEventListener('click', _handleClearLog, false)
   _ui.appConfigTab.addEventListener('click', _handleTab, false)
   _ui.appConfigForm.addEventListener('submit', _handleSave, false)
+  _ui.restoreDefaultConfig.addEventListener('click', _handleRestoreDefaultConfig, false)
   _ui.resetButton.addEventListener('click', _handleReset, false)
 }
 
@@ -51,6 +55,21 @@ function _handleTab (e) {
   _active.container = container
 }
 
+function _getAppConfig (form) {
+  return Object.keys(form)
+    .map(key => [key, form[key].value])
+    .filter(([, value]) => value)
+    .reduce((acc, [key, value]) => ({...acc, [key]: value}), {})
+}
+
+function _reflectConfigInForm (appConfig, form) {
+  Object.keys(form).map(key => form[key].value = appConfig[key] || '')
+}
+
+function _handleClearLog () {
+  clearLog()
+}
+
 function _handleSave (e) {
   e.preventDefault()
 
@@ -62,12 +81,9 @@ function _handleSave (e) {
   _ui.submitButton.classList.add('loading')
   _ui.submitButton.disabled = true
 
-  const appConfig = Object.keys(_form)
-    .map(key => [key, _form[key].value])
-    .filter(([, value]) => value)
-    .reduce((acc, [key, value]) => ({...acc, [key]: value}), {})
-
+  const appConfig = _getAppConfig(_form)
   _setJson(appConfig)
+
   setItem('appConfig', appConfig)
   clearTimeout(_timeoutId)
   _timeoutId = setTimeout(() => {
@@ -84,6 +100,30 @@ function _handleSave (e) {
   })
 }
 
+function _handleRestoreDefaultConfig () {
+  if (_disabled) {
+    return
+  }
+
+  _disabled = true
+  _ui.submitButton.classList.add('loading')
+  _ui.submitButton.disabled = true
+
+  setItem('appConfig', null)
+
+  const appConfig = {..._defaultAppConfig}
+
+  _reflectConfigInForm(appConfig, _form)
+  _setJson(appConfig)
+
+  clearTimeout(_timeoutId)
+  _timeoutId = setTimeout(() => {
+    _disabled = false
+    _ui.submitButton.classList.remove('loading')
+    _ui.submitButton.disabled = false
+  })
+}
+
 function _handleReset () {
   if (_disabled) {
     return
@@ -93,9 +133,9 @@ function _handleReset () {
   _ui.resetButton.classList.add('loading')
   _ui.resetButton.disabled = true
 
-  const appConfig = {..._defaultAppConfig}
-
+  const appConfig = _getAppConfig(_form)
   _setJson(appConfig)
+
   clear()
   Adjust.__testonly__.clearDatabase()
     .catch(error => {
@@ -124,8 +164,11 @@ function _prepareForm () {
     attributionCallback: _handleAttributionChange
   })
   Adjust.initSmartBanner({
+    ...appConfig,
     webToken: 'p6o2pnb1zkzk',
-    logLevel: 'verbose'
+    logLevel: 'verbose',
+    onCreated: () => write('Hey, where is a Smart Banner!'),
+    onDismissed: () => write('Oh, you have dismissed the Smart Banner'),
   })
 
   _form.appToken = _ui.appConfigForm.querySelector('#app-token')
@@ -133,12 +176,13 @@ function _prepareForm () {
   _form.defaultTracker = _ui.appConfigForm.querySelector('#default-tracker')
   _form.customUrl = _ui.appConfigForm.querySelector('#custom-url')
   _form.logLevel = _ui.appConfigForm.querySelector('#log-level')
+  _form.dataResidency = _ui.appConfigForm.querySelector('#data-residency')
+  _form.urlStrategy = _ui.appConfigForm.querySelector('#url-strategy')
   _form.logOutput = _ui.appConfigForm.querySelector('#log-output')
   _form.eventDeduplicationListLimit = _ui.appConfigForm.querySelector('#event-deduplication-list-limit')
   _form.externalDeviceId = _ui.appConfigForm.querySelector('#external-device-id')
 
-  Object.keys(_form).map(key => _form[key].value = appConfig[key] || '')
-
+  _reflectConfigInForm(appConfig, _form)
   _setJson(appConfig)
 }
 
diff --git a/src/demo/tabs/tabs.scss b/src/demo/tabs/tabs.scss
index 3ad926c2..d4dd3e12 100644
--- a/src/demo/tabs/tabs.scss
+++ b/src/demo/tabs/tabs.scss
@@ -1,6 +1,6 @@
 @import "../../assets/scss/variables";
 
-$height: 240px;
+$height: 300px;
 
 .tabs {
   @extend .flex-box-row;
@@ -35,17 +35,46 @@ $height: 240px;
   }
 }
 
+.fab {
+  position: relative;
+  top: - $fabSize - $fabMargin;
+  float: right;
+  margin-right: $fabMargin;
+  margin-bottom: - $fabSize;
+  height: $fabSize;
+  width: $fabSize;
+  background-color: $headerBgColor;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 2px 5px 0 rgb(0 0 0 / 16%), 0 2px 10px 0 rgb(0 0 0 / 12%);
+
+  img {
+    user-select: none;
+    width: 50%;
+    height: 50%;
+  }
+
+  &:hover {
+    cursor: pointer;
+  }
+
+  &:active {
+    background-color: #383f49;
+    transition: all linear;
+  }
+}
+
 .log {
-  color: $logFontColor;
-  background: $logBgColor;
-  border-color: $headerBgColor;
   padding: 10px 5px 10px 10px;
   height: 100%;
   box-sizing: border-box;
 }
 
 .config {
-  @extend .log;
+  padding: 10px 5px 10px 10px;
+  box-sizing: border-box;
   border: none;
 }
 
@@ -58,7 +87,7 @@ $height: 240px;
   padding: 0;
 
   & > .flex-box-row {
-    height: 100%;
+    align-items: stretch;
   }
 
   form {
@@ -67,11 +96,14 @@ $height: 240px;
 }
 
 .inline-actions {
+  display: flex;
+
   button {
     display: inline-block;
+    flex: 1 0 0%;
   }
 
-  #reset {
-    float: right;
+  :nth-child(n+2) {
+    margin-left: 10px;
   }
 }
diff --git a/src/sdk/__mocks__/url-strategy.ts b/src/sdk/__mocks__/url-strategy.ts
index 421b6308..5655b679 100644
--- a/src/sdk/__mocks__/url-strategy.ts
+++ b/src/sdk/__mocks__/url-strategy.ts
@@ -1,6 +1,6 @@
 import type { BaseUrlsMap, UrlStrategy } from '../url-strategy'
 
-const urlStartegyModule = jest.requireActual('../url-strategy')
+const urlStrategyModule = jest.requireActual('../url-strategy')
 
 const testEndpoints = {
   default: { app: 'app.default', gdpr: '' },
@@ -19,9 +19,9 @@ export function urlStrategyRetries(
   sendRequest: (urls: BaseUrlsMap) => Promise,
   endpoints: Partial> = mockEndpoints.endpoints
 ) {
-  return urlStartegyModule.urlStrategyRetries(sendRequest, endpoints)
+  return urlStrategyModule.urlStrategyRetries(sendRequest, endpoints)
 }
 
 export function getBaseUrlsIterator(endpoints: Partial> = mockEndpoints.singleEndpoint) {
-  return urlStartegyModule.getBaseUrlsIterator(endpoints)
+  return urlStrategyModule.getBaseUrlsIterator(endpoints)
 }
diff --git a/src/sdk/__tests__/smart-banner/network/api.spec.ts b/src/sdk/__tests__/smart-banner/network/api.spec.ts
index 88a036e6..fb2000a4 100644
--- a/src/sdk/__tests__/smart-banner/network/api.spec.ts
+++ b/src/sdk/__tests__/smart-banner/network/api.spec.ts
@@ -1,6 +1,6 @@
 import Logger from '../../../logger'
 import { DeviceOS } from '../../../smart-banner/detect-os'
-import { fetchSmartBannerData, Position } from '../../../smart-banner/network/api'
+import { fetchSmartBannerData, Position } from '../../../smart-banner/api'
 import { Network } from '../../../smart-banner/network/network'
 
 jest.mock('../../../logger')
@@ -19,12 +19,17 @@ describe('Smart banner API tests', () => {
       button_label: 'Go!'
     }
 
+    const testNetwork: Network = {
+      endpoint: 'test-endpoint',
+      request: jest.fn()
+    }
+
     let requestSpy: jest.SpyInstance
 
     beforeAll(() => {
       jest.spyOn(Logger, 'error')
 
-      requestSpy = jest.spyOn(Network, 'request')
+      requestSpy = jest.spyOn(testNetwork, 'request')
     })
 
     afterEach(() => {
@@ -35,7 +40,7 @@ describe('Smart banner API tests', () => {
       expect.assertions(2)
       requestSpy.mockResolvedValueOnce([serverResponseMock])
 
-      const smartBannerData = await fetchSmartBannerData(webToken, platform)
+      const smartBannerData = await fetchSmartBannerData(webToken, platform, testNetwork)
 
       expect(smartBannerData).not.toBeNull()
       expect(smartBannerData).toEqual({
@@ -54,7 +59,7 @@ describe('Smart banner API tests', () => {
       expect.assertions(1)
       requestSpy.mockResolvedValueOnce([{ ...serverResponseMock, platform: 'android' }])
 
-      const smartBannerData = await fetchSmartBannerData(webToken, platform)
+      const smartBannerData = await fetchSmartBannerData(webToken, platform, testNetwork)
 
       expect(smartBannerData).toBeNull()
     })
@@ -63,7 +68,7 @@ describe('Smart banner API tests', () => {
       expect.assertions(1)
       requestSpy.mockResolvedValueOnce([{ ...serverResponseMock, title: '' }])
 
-      const smartBannerData = await fetchSmartBannerData(webToken, platform)
+      const smartBannerData = await fetchSmartBannerData(webToken, platform, testNetwork)
 
       expect(smartBannerData).toBeNull()
     })
@@ -74,7 +79,7 @@ describe('Smart banner API tests', () => {
       const error = { status: 404, message: 'Not found' }
       requestSpy.mockRejectedValueOnce(error)
 
-      const smartBannerData = await fetchSmartBannerData(webToken, platform)
+      const smartBannerData = await fetchSmartBannerData(webToken, platform, testNetwork)
 
       expect(smartBannerData).toBeNull()
       expect(Logger.error).toHaveBeenCalledWith('Network error occurred during loading Smart Banner: ' + JSON.stringify(error))
diff --git a/src/sdk/__tests__/smart-banner/network/network.spec.ts b/src/sdk/__tests__/smart-banner/network/network.spec.ts
deleted file mode 100644
index c8cd538a..00000000
--- a/src/sdk/__tests__/smart-banner/network/network.spec.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-import { NetworkError, NoConnectionError } from '../../../smart-banner/network/errors'
-
-jest.mock('../../../logger')
-jest.mock('../../../url-strategy')
-
-const UrlStartegyMock = jest.requireMock('../../../url-strategy')
-const testEndpoints = UrlStartegyMock.mockEndpoints.endpoints
-
-describe('Network tests', () => {
-  const defaultEndpoint = 'https://app.adjust.com'
-  let Network
-  let xhrMock: jest.SpyInstance
-
-  beforeEach(() => {
-    Network = require('../../../smart-banner/network/network').Network
-    xhrMock = jest.spyOn(Network, 'xhr')
-  })
-
-  afterEach(() => {
-    jest.clearAllMocks()
-    jest.resetModules()
-  })
-
-  describe('request', () => {
-    it('sends request to path with encoded params', async () => {
-      expect.assertions(1)
-      xhrMock.mockResolvedValue({})
-
-      await Network.request('/whatever', { foo: 'bar', n: 42 })
-
-      const expectedUrl = `${testEndpoints.default.app}/whatever?foo=bar&n=42`
-
-      expect(xhrMock).toHaveBeenCalledWith(expectedUrl)
-    })
-
-    it('sends request to path without params', async () => {
-      expect.assertions(1)
-      xhrMock.mockResolvedValue({})
-
-      await Network.request('/whatever')
-
-      const expectedUrl = `${testEndpoints.default.app}/whatever`
-
-      expect(xhrMock).toHaveBeenCalledWith(expectedUrl)
-    })
-
-    it('retries endpoints if request failed due to no network connection', async () => {
-      expect.assertions(4)
-      xhrMock
-        .mockRejectedValueOnce(NoConnectionError)
-        .mockRejectedValueOnce(NoConnectionError)
-        .mockResolvedValue({})
-
-      await Network.request('/whatever')
-
-      expect(xhrMock).toHaveBeenCalledTimes(3)
-      expect(xhrMock).toHaveBeenCalledWith(`${testEndpoints.default.app}/whatever`)
-      expect(xhrMock).toHaveBeenCalledWith(`${testEndpoints.india.app}/whatever`)
-      expect(xhrMock).toHaveBeenCalledWith(`${testEndpoints.china.app}/whatever`)
-    })
-
-    it('throws an error if request failed', async () => {
-      expect.assertions(2)
-
-      const err: NetworkError = { status: 400, message: 'Bad request' }
-      xhrMock.mockRejectedValueOnce(err)
-
-      try {
-        await Network.request('/whatever')
-      } catch (error) {
-        expect(error).toEqual(err)
-      }
-
-      expect(xhrMock).toHaveBeenCalledTimes(1)
-    })
-  })
-
-  describe('getEndpoint', () => {
-    it('returns default endpoint until request sent', () => {
-      expect(Network.getEndpoint()).toEqual(defaultEndpoint)
-    })
-
-    it('returns default endpoint if request failed', async () => {
-      expect.assertions(1)
-
-      xhrMock.mockRejectedValue({})
-      try {
-        await Network.request('/whatever')
-      } catch (err) {
-        // nothing to do here
-      }
-
-      expect(Network.getEndpoint()).toEqual(defaultEndpoint)
-    })
-
-    it('returns last successful endpoint', async () => {
-      expect.assertions(1)
-
-      xhrMock
-        .mockRejectedValueOnce(NoConnectionError)
-        .mockResolvedValueOnce({})
-
-      await Network.request('/whatever')
-
-      expect(Network.getEndpoint()).toEqual(testEndpoints.india.app)
-    })
-  })
-})
diff --git a/src/sdk/__tests__/smart-banner/network/url-startegy-network.spec.ts b/src/sdk/__tests__/smart-banner/network/url-startegy-network.spec.ts
new file mode 100644
index 00000000..effcd7cb
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/url-startegy-network.spec.ts
@@ -0,0 +1,111 @@
+import { Network } from '../../../smart-banner/network/network'
+import { NetworkWithUrlStrategy } from '../../../smart-banner/network/url-startegy-network'
+import { UrlStrategy } from '../../../smart-banner/network/url-strategy/url-strategy'
+import { UrlStrategyFactory } from '../../../smart-banner/network/url-strategy/url-strategy-factory'
+
+jest.mock('../../../logger')
+
+describe('NetworkWithUrlStrategy', () => {
+
+  const baseUrls = {
+    endpointName: 'test',
+    app: 'app.test',
+    gdpr: 'gdpr.test'
+  }
+
+  const urlStrategyMock = new UrlStrategy(() => [baseUrls])
+
+  const networkMock: Network = {
+    endpoint: '',
+    request: (path: string, params?: Record) => Promise.resolve('all good') as any
+  }
+
+  describe('instantiation', () => {
+
+    beforeAll(() => {
+      jest.resetAllMocks()
+      jest.spyOn(UrlStrategyFactory, 'create').mockImplementation(() => urlStrategyMock)
+    })
+
+    afterEach(() => {
+      jest.clearAllMocks()
+    })
+
+    it('could be instantiated with provided UrlStrategy', () => {
+      const network = new NetworkWithUrlStrategy(networkMock, { urlStrategy: urlStrategyMock })
+
+      expect(UrlStrategyFactory.create).not.toHaveBeenCalled()
+      expect(network).toBeInstanceOf(NetworkWithUrlStrategy)
+    })
+
+    it('could be instantiated with UrlStrategyConfig', () => {
+      const urlStrategyConfig = {}
+      const network = new NetworkWithUrlStrategy(networkMock, { urlStrategyConfig })
+
+      expect(UrlStrategyFactory.create).toHaveBeenCalledWith(urlStrategyConfig)
+      expect(network).toBeInstanceOf(NetworkWithUrlStrategy)
+    })
+  })
+
+  describe('request', () => {
+    beforeAll(() => {
+      jest.spyOn(networkMock, 'request')
+      jest.spyOn(urlStrategyMock, 'retries')
+    })
+
+    afterEach(() => {
+      jest.clearAllMocks()
+    })
+
+    it('sends request with inner Network instance and uses UrlStrategy retries', async () => {
+      expect.assertions(3)
+
+      const network = new NetworkWithUrlStrategy(networkMock, { urlStrategy: urlStrategyMock })
+      const result = await network.request('/whatever', { foo: 'bar', n: 42 })
+
+      expect(result).toEqual('all good')
+      expect(urlStrategyMock.retries).toHaveBeenCalled()
+      expect(networkMock.request).toHaveBeenCalledWith('/whatever', { foo: 'bar', n: 42 })
+    })
+  })
+
+  describe('endpoint property', () => {
+    beforeAll(() => {
+      jest.spyOn(networkMock, 'request')
+      jest.spyOn(urlStrategyMock, 'retries')
+    })
+
+    afterEach(() => {
+      jest.clearAllMocks()
+    })
+
+    const defaultEndpoint = 'https://app.adjust.com'
+
+    it('returns default endpoint before the first request', () => {
+      const network = new NetworkWithUrlStrategy(networkMock, { urlStrategy: urlStrategyMock })
+
+      expect(network.endpoint).toEqual(defaultEndpoint)
+    })
+
+    it('returns last endpoint after successful request', async () => {
+      const network = new NetworkWithUrlStrategy(networkMock, { urlStrategy: urlStrategyMock })
+
+      await network.request('/whatever')
+
+      expect(network.endpoint).toEqual(baseUrls.app)
+    })
+
+    it('returns default endpoint after failed request', async () => {
+      const network = new NetworkWithUrlStrategy(networkMock, { urlStrategy: urlStrategyMock })
+      jest.spyOn(networkMock, 'request').mockRejectedValueOnce('Error!')
+
+      try {
+        await network.request('/whatever')
+      } catch (err) {
+        // nothing to do here
+      }
+
+      expect(network.endpoint).toEqual(defaultEndpoint)
+    })
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/network/url-strategy/blocked-url-bypass.spec.ts b/src/sdk/__tests__/smart-banner/network/url-strategy/blocked-url-bypass.spec.ts
new file mode 100644
index 00000000..b6812c86
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/url-strategy/blocked-url-bypass.spec.ts
@@ -0,0 +1,54 @@
+import { BlockedUrlBypass } from '../../../../smart-banner/network/url-strategy/blocked-url-bypass'
+import { BaseUrlsMap } from '../../../../smart-banner/network/url-strategy/url-strategy'
+
+describe('BlockedUrlBypass', () => {
+  const testEndpoints: Record = {
+    [BlockedUrlBypass.Default]: {
+      endpointName: BlockedUrlBypass.Default,
+      app: 'app',
+      gdpr: 'gdpr'
+    },
+    [BlockedUrlBypass.India]: {
+      endpointName: 'Indian',
+      app: 'app.adjust.net.in',
+      gdpr: 'gdpr.adjust.net.in'
+    },
+    [BlockedUrlBypass.China]: {
+      endpointName: 'Chinese',
+      app: 'app.adjust.world',
+      gdpr: 'gdpr.adjust.world'
+    }
+  }
+
+  it.each([
+    [BlockedUrlBypass.China, 2, [BlockedUrlBypass.Default]],
+    [BlockedUrlBypass.India, 2, [BlockedUrlBypass.Default]],
+    [BlockedUrlBypass.Default, 3, [BlockedUrlBypass.India, BlockedUrlBypass.China]],
+  ])('returns urls map array depending on strategy', (strategy: BlockedUrlBypass.Strategy, retriesNumber, nextEndpoints) => {
+    const resultingFn = BlockedUrlBypass.preferredUrlsGetter(strategy, testEndpoints)
+
+    expect(resultingFn).toEqual(expect.any(Function))
+
+    const baseUrlsMap = resultingFn()
+
+    expect(baseUrlsMap.length).toEqual(retriesNumber)
+    expect(baseUrlsMap[0]).toEqual(testEndpoints[strategy])
+
+    for (let i = 0; i < nextEndpoints.length; i++) {
+      expect(baseUrlsMap[i + 1]).toEqual(testEndpoints[nextEndpoints[i]])
+    }
+  })
+
+  it('returns default strategy if option is undefined', () => {
+    const resultingFn = BlockedUrlBypass.preferredUrlsGetter(undefined, testEndpoints)
+
+    expect(resultingFn).toEqual(expect.any(Function))
+
+    const baseUrlsMap = resultingFn()
+
+    expect(baseUrlsMap.length).toEqual(3)
+    expect(baseUrlsMap[0]).toEqual(testEndpoints[BlockedUrlBypass.Default])
+    expect(baseUrlsMap[1]).toEqual(testEndpoints[BlockedUrlBypass.India])
+    expect(baseUrlsMap[2]).toEqual(testEndpoints[BlockedUrlBypass.China])
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/network/url-strategy/custom-url.spec.ts b/src/sdk/__tests__/smart-banner/network/url-strategy/custom-url.spec.ts
new file mode 100644
index 00000000..678516a6
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/url-strategy/custom-url.spec.ts
@@ -0,0 +1,18 @@
+import { CustomUrl } from '../../../../smart-banner/network/url-strategy/custom-url'
+
+describe('CustomUrl', () => {
+  it('returns urls map with custom url', () => {
+    const url = 'custom.url'
+
+    const expectedUrlMap = {
+      endpointName: `Custom (${url})`,
+      app: url,
+      gdpr: url
+    }
+
+    const resultingFn = CustomUrl.preferredUrlsGetter(url)
+
+    expect(resultingFn).toEqual(expect.any(Function))
+    expect(resultingFn()).toEqual([expectedUrlMap])
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/network/url-strategy/data-residency.spec.ts b/src/sdk/__tests__/smart-banner/network/url-strategy/data-residency.spec.ts
new file mode 100644
index 00000000..4beed27b
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/url-strategy/data-residency.spec.ts
@@ -0,0 +1,38 @@
+import { DataResidency } from '../../../../smart-banner/network/url-strategy/data-residency'
+import { BaseUrlsMap } from '../../../../smart-banner/network/url-strategy/url-strategy'
+
+describe('DataResidency', () => {
+
+  const testEndpoints: Record = {
+    [DataResidency.EU]: {
+      endpointName: 'EU',
+      app: 'app.eu',
+      gdpr: 'gdpr.eu'
+    },
+    [DataResidency.TR]: {
+      endpointName: 'TR',
+      app: 'app.tr',
+      gdpr: 'gdpr.tr'
+    },
+    [DataResidency.US]: {
+      endpointName: 'US',
+      app: 'app.us',
+      gdpr: 'gdpr.us'
+    }
+  }
+
+  it.each([
+    DataResidency.EU,
+    DataResidency.TR,
+    DataResidency.US
+  ])('returns urls map depending on region', (dataResidency: DataResidency.Region) => {
+    const resultingFn = DataResidency.preferredUrlsGetter(dataResidency, testEndpoints)
+
+    expect(resultingFn).toEqual(expect.any(Function))
+
+    const baseUrlsMap = resultingFn()
+
+    expect(baseUrlsMap.length).toEqual(1)
+    expect(baseUrlsMap[0]).toEqual(testEndpoints[dataResidency])
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/network/url-strategy/url-strategy-factory.spec.ts b/src/sdk/__tests__/smart-banner/network/url-strategy/url-strategy-factory.spec.ts
new file mode 100644
index 00000000..7f0eeb94
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/url-strategy/url-strategy-factory.spec.ts
@@ -0,0 +1,81 @@
+import Logger from '../../../../logger'
+import * as UrlStrategyModule from '../../../../smart-banner/network/url-strategy/url-strategy'
+import { UrlStrategyFactory } from '../../../../smart-banner/network/url-strategy/url-strategy-factory'
+import { BlockedUrlBypass } from '../../../../smart-banner/network/url-strategy//blocked-url-bypass'
+import { CustomUrl } from '../../../../smart-banner/network/url-strategy//custom-url'
+import { DataResidency } from '../../../../smart-banner/network/url-strategy//data-residency'
+
+jest.mock('../../../../logger')
+
+describe('UrlStrategyFactory', () => {
+  const urlStrategyConstructorMock = jest.fn()
+
+  const urlsMap = { endpointName: 'foo.bar', app: 'app', gdpr: 'gdpr' }
+
+  const customUrlMock = () => [urlsMap]
+  const dataResidencyMock = () => [urlsMap]
+  const blockedUrlBypassMock = () => [urlsMap]
+
+  beforeAll(() => {
+    jest.spyOn(UrlStrategyModule, 'UrlStrategy').mockImplementation(urlStrategyConstructorMock)
+    jest.spyOn(CustomUrl, 'preferredUrlsGetter').mockImplementation(() => customUrlMock)
+    jest.spyOn(DataResidency, 'preferredUrlsGetter').mockImplementation(() => dataResidencyMock)
+    jest.spyOn(BlockedUrlBypass, 'preferredUrlsGetter').mockImplementation(() => blockedUrlBypassMock)
+  })
+
+  afterEach(() => {
+    jest.clearAllMocks()
+  })
+
+  it('creates CustomStrategy if customUrl is set in config', () => {
+    UrlStrategyFactory.create({ customUrl: 'custom.url' })
+
+    expect(CustomUrl.preferredUrlsGetter).toHaveBeenCalledWith('custom.url')
+    expect(urlStrategyConstructorMock).toHaveBeenCalledWith(customUrlMock)
+  })
+
+  it.each([
+    DataResidency.EU,
+    DataResidency.TR,
+    DataResidency.US
+  ])('creates DataResidency if dataResidency is set in config', (region: DataResidency.Region) => {
+    UrlStrategyFactory.create({ dataResidency: region })
+
+    expect(DataResidency.preferredUrlsGetter).toHaveBeenCalledWith(region)
+    expect(urlStrategyConstructorMock).toHaveBeenCalledWith(dataResidencyMock)
+  })
+
+  it.each([
+    BlockedUrlBypass.China,
+    BlockedUrlBypass.India
+  ])('creates BlockedUrlBypass if urlStrategy is set in config', (strategy: BlockedUrlBypass.Strategy) => {
+    UrlStrategyFactory.create({ urlStrategy: strategy })
+
+    expect(BlockedUrlBypass.preferredUrlsGetter).toHaveBeenCalledWith(strategy)
+    expect(urlStrategyConstructorMock).toHaveBeenCalledWith(blockedUrlBypassMock)
+  })
+
+  it('creates BlockedUrlBypass if config is empty', () => {
+    UrlStrategyFactory.create({})
+
+    expect(BlockedUrlBypass.preferredUrlsGetter).toHaveBeenCalled()
+    expect(urlStrategyConstructorMock).toHaveBeenCalledWith(blockedUrlBypassMock)
+  })
+
+  it.each([
+    [BlockedUrlBypass.China, DataResidency.EU],
+    [BlockedUrlBypass.China, DataResidency.US],
+    [BlockedUrlBypass.China, DataResidency.TR],
+    [BlockedUrlBypass.India, DataResidency.EU],
+    [BlockedUrlBypass.India, DataResidency.US],
+    [BlockedUrlBypass.India, DataResidency.TR]
+  ])('prefers DataResidency and prints warning if both dataResidency and urlStartegy are set in config', (strategy, region) => {
+    jest.spyOn(Logger, 'warn')
+
+    UrlStrategyFactory.create({ urlStrategy: strategy, dataResidency: region } as any)
+
+    expect(DataResidency.preferredUrlsGetter).toHaveBeenCalledWith(region)
+    expect(urlStrategyConstructorMock).toHaveBeenCalledWith(dataResidencyMock)
+    expect(Logger.warn).toHaveBeenCalledWith('Both dataResidency and urlStrategy are set in config, urlStrategy will be ignored')
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/network/url-strategy/url-strategy.spec.ts b/src/sdk/__tests__/smart-banner/network/url-strategy/url-strategy.spec.ts
new file mode 100644
index 00000000..504bf532
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/url-strategy/url-strategy.spec.ts
@@ -0,0 +1,114 @@
+import Logger from '../../../../logger'
+import { BaseUrlsMap, UrlStrategy } from '../../../../smart-banner/network/url-strategy/url-strategy'
+import { NoConnectionError } from '../../../../smart-banner/network/errors'
+
+jest.mock('../../../../logger')
+
+describe('UrlStrategy', () => {
+  const urls: BaseUrlsMap[] = [{
+    endpointName: 'foo',
+    app: 'foo',
+    gdpr: 'foo'
+  }, {
+    endpointName: 'bar',
+    app: 'bar',
+    gdpr: 'bar'
+  }]
+
+  const preferredUrlsMock = jest.fn()
+  const testedUrlStrategy = new UrlStrategy(preferredUrlsMock)
+  const sendRequestMock = jest.fn()
+
+  beforeAll(() => {
+    jest.spyOn(Logger, 'error')
+    jest.spyOn(Logger, 'log')
+  })
+
+  afterEach(() => {
+    jest.clearAllMocks()
+  })
+
+  describe('preferredUrls sanity check', () => {
+    it('throws error if there is no enpoint defined', async () => {
+      preferredUrlsMock.mockImplementation(() => undefined)
+
+      expect.assertions(2)
+
+      try {
+        await testedUrlStrategy.retries(sendRequestMock)
+      } catch (err) {
+        expect(err).toBe(UrlStrategy.NoPreferredUrlsDefinedError)
+        expect(Logger.error).toHaveBeenCalledWith(UrlStrategy.NoPreferredUrlsDefinedError.message)
+      }
+    })
+
+    it('throws error if array of endpoints is empty', async () => {
+      preferredUrlsMock.mockImplementation(() => [])
+
+      expect.assertions(2)
+
+      try {
+        await testedUrlStrategy.retries(sendRequestMock)
+      } catch (err) {
+        expect(err).toBe(UrlStrategy.NoPreferredUrlsDefinedError)
+        expect(Logger.error).toHaveBeenCalledWith(UrlStrategy.NoPreferredUrlsDefinedError.message)
+      }
+    })
+  })
+
+  describe('retries functionality', () => {
+    beforeAll(() => {
+      preferredUrlsMock.mockImplementation(() => urls)
+    })
+
+    it('tries to reach next endpoint if could not connect', async () => {
+      sendRequestMock
+        .mockRejectedValueOnce(NoConnectionError)
+        .mockResolvedValueOnce('all good')
+
+      expect.assertions(4)
+
+      const result = await testedUrlStrategy.retries(sendRequestMock)
+
+      expect(sendRequestMock).toHaveBeenCalledTimes(urls.length)
+      expect(Logger.log).toHaveBeenCalledWith(`Failed to connect ${urls[0].endpointName} endpoint`)
+      expect(Logger.log).toHaveBeenCalledWith(`Trying ${urls[1].endpointName} one`)
+      expect(result).toEqual('all good')
+    })
+
+    it('re-throws if there is no available endpoint', async () => {
+      sendRequestMock.mockRejectedValue(NoConnectionError)
+
+      expect.assertions(6)
+
+      try {
+        await testedUrlStrategy.retries(sendRequestMock)
+      }
+      catch (err) {
+        expect(err).toEqual(NoConnectionError)
+      }
+
+      expect(sendRequestMock).toHaveBeenCalledTimes(urls.length)
+      expect(Logger.log).toHaveBeenCalledWith(`Failed to connect ${urls[0].endpointName} endpoint`)
+      expect(Logger.log).toHaveBeenCalledWith(`Trying ${urls[1].endpointName} one`)
+      expect(Logger.log).toHaveBeenCalledWith(`Failed to connect ${urls[1].endpointName} endpoint`)
+      expect(testedUrlStrategy.retries).toThrow()
+    })
+
+    it('re-throws if other error occured', async () => {
+      sendRequestMock.mockRejectedValue({ status: 404, message: 'not found' })
+
+      expect.assertions(3)
+
+      try {
+        await testedUrlStrategy.retries(sendRequestMock)
+      }
+      catch (err) {
+        expect(err).toEqual({ status: 404, message: 'not found' })
+      }
+
+      expect(sendRequestMock).toHaveBeenCalledTimes(1)
+      expect(testedUrlStrategy.retries).toThrow()
+    })
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/network/xhr-network.spec.ts b/src/sdk/__tests__/smart-banner/network/xhr-network.spec.ts
new file mode 100644
index 00000000..0247c302
--- /dev/null
+++ b/src/sdk/__tests__/smart-banner/network/xhr-network.spec.ts
@@ -0,0 +1,86 @@
+import { XhrNetwork } from '../../../smart-banner/network/xhr-network'
+import { NoConnectionError } from '../../../smart-banner/network/errors'
+
+jest.mock('../../../logger')
+
+describe('XhrNetwork tests', () => {
+  const testEndpoint = 'test.test'
+
+  const xhrMock: Partial = {
+    open: jest.fn(),
+    setRequestHeader: jest.fn(),
+    send: jest.fn(),
+    onerror: jest.fn(),
+    onreadystatechange: jest.fn()
+  }
+
+  const testedNetwork = new XhrNetwork(testEndpoint)
+
+  beforeAll(() => {
+    jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMock as XMLHttpRequest)
+  })
+
+  afterEach(() => {
+    jest.clearAllMocks()
+  })
+
+  describe('request method', () => {
+    it('sends request to path with encoded params', async () => {
+      expect.assertions(1)
+
+      testedNetwork.request('/whatever', { foo: 'bar', n: 42 })
+
+      const expectedUrl = `${testEndpoint}/whatever?foo=bar&n=42`
+
+      expect(xhrMock.open).toHaveBeenCalledWith('GET', expectedUrl)
+    })
+
+    it('sends request to path without params', async () => {
+      expect.assertions(1)
+
+      testedNetwork.request('/whatever')
+
+      const expectedUrl = `${testEndpoint}/whatever`
+
+      expect(xhrMock.open).toHaveBeenCalledWith('GET', expectedUrl)
+    })
+
+    it('throws NoConnectionError if request failed due to network connection issue', async () => {
+      expect.assertions(1)
+
+      jest.spyOn(xhrMock, 'send').mockImplementationOnce(() => { (xhrMock as any).onerror() })
+
+      try {
+        await testedNetwork.request('/whatever')
+      } catch (error) {
+        expect(error).toEqual(NoConnectionError)
+      }
+    })
+
+    it('throws an error if request failed', async () => {
+      expect.assertions(1)
+
+      const err = { status: 400, message: 'Bad request' }
+
+      jest.spyOn(xhrMock, 'send').mockImplementationOnce(() => {
+        const xhrFailedMock = xhrMock as any
+        xhrFailedMock.readyState = 4
+        xhrFailedMock.status = err.status
+        xhrFailedMock.responseText = err.message
+        xhrFailedMock.onreadystatechange()
+      })
+
+      try {
+        await testedNetwork.request('/whatever')
+      } catch (error) {
+        expect(error).toEqual(err)
+      }
+    })
+  })
+
+  describe('endpoint property', () => {
+    it('returns endpoint', () => {
+      expect(testedNetwork.endpoint).toEqual(testEndpoint)
+    })
+  })
+})
diff --git a/src/sdk/__tests__/smart-banner/smart-banner.spec.ts b/src/sdk/__tests__/smart-banner/smart-banner.spec.ts
index 9fff6df7..ccfe7db9 100644
--- a/src/sdk/__tests__/smart-banner/smart-banner.spec.ts
+++ b/src/sdk/__tests__/smart-banner/smart-banner.spec.ts
@@ -1,7 +1,8 @@
 import Logger from '../../logger'
-import * as Api from '../../smart-banner/network/api'
+import * as Api from '../../smart-banner/api'
 import * as DetectOS from '../../smart-banner/detect-os'
 import { storage } from '../../smart-banner/local-storage'
+import { SmartBanner } from '../../smart-banner/smart-banner'
 
 jest.mock('../../logger')
 jest.useFakeTimers()
@@ -20,6 +21,8 @@ describe('Smart Banner tests', () => {
     position: Api.Position.Top,
     trackerToken: 'abcd'
   }
+  const onCreatedCallbackSpy = jest.fn()
+  const onDismissedCallbackSpy = jest.fn()
 
   let smartBanner
 
@@ -29,7 +32,7 @@ describe('Smart Banner tests', () => {
     jest.spyOn(Logger, 'error')
     jest.spyOn(global, 'setTimeout')
 
-    smartBanner = require('../../smart-banner/smart-banner').SmartBanner
+    smartBanner = new SmartBanner({ webToken, onCreated: onCreatedCallbackSpy, onDismissed: onDismissedCallbackSpy })
   })
 
   beforeEach(() => {
@@ -48,7 +51,7 @@ describe('Smart Banner tests', () => {
     })
 
     it(('initialises and renders banner'), async () => {
-      expect.assertions(5)
+      expect.assertions(6)
 
       smartBanner.init(webToken)
       await Utils.flushPromises() // resolves data fetch promise that allows initialisation to finish
@@ -58,11 +61,12 @@ describe('Smart Banner tests', () => {
       expect(smartBanner.banner).not.toBeNull()
       expect(smartBanner.dismissButton).not.toBeNull()
       expect(Logger.log).toHaveBeenCalledWith('Smart Banner created')
+      expect(onCreatedCallbackSpy).toHaveBeenCalled()
     })
 
     describe('can not call init repeatedly', () => {
       it('initialisation in progress', async () => {
-        expect.assertions(1)
+        expect.assertions(2)
 
         smartBanner.init(webToken) // setup
 
@@ -71,10 +75,12 @@ describe('Smart Banner tests', () => {
         expect(Logger.error).toHaveBeenCalledWith('Smart Banner is initialising already')
 
         await Utils.flushPromises() // tear down
+
+        expect(onCreatedCallbackSpy).toHaveBeenCalledTimes(1)
       })
 
       it('initialisation finished', async () => {
-        expect.assertions(1)
+        expect.assertions(2)
 
         smartBanner.init(webToken) // setup
         await Utils.flushPromises() // allow initialisation to finish
@@ -82,18 +88,20 @@ describe('Smart Banner tests', () => {
         smartBanner.init(webToken)
 
         expect(Logger.error).toHaveBeenCalledWith('Smart Banner already exists')
+        expect(onCreatedCallbackSpy).toHaveBeenCalledTimes(1)
       })
     })
 
     it('logs message when no banner for platform', async () => {
       jest.spyOn(Api, 'fetchSmartBannerData').mockResolvedValueOnce(null)
 
-      expect.assertions(1)
+      expect.assertions(2)
 
       smartBanner.init(webToken)
       await Utils.flushPromises()
 
       expect(Logger.log).toHaveBeenCalledWith(`No Smart Banners for ${platform} platform found`)
+      expect(onCreatedCallbackSpy).not.toHaveBeenCalled()
     })
 
     it('logs message when no target platform', () => {
@@ -102,6 +110,7 @@ describe('Smart Banner tests', () => {
       smartBanner.init(webToken)
 
       expect(Logger.log).toHaveBeenCalledWith('This platform is not one of the targeting ones, Smart Banner will not be shown')
+      expect(onCreatedCallbackSpy).not.toHaveBeenCalled()
     })
   })
 
@@ -213,9 +222,9 @@ describe('Smart Banner tests', () => {
     })
 
     it('banner removed from DOM when dismissed', () => {
-      expect.assertions(7)
+      expect.assertions(8)
 
-      expect(storage.setItem).toHaveBeenCalledWith(smartBanner.dismissedStorageKey, now) // add timestamp in Local Storage
+      expect(storage.setItem).toHaveBeenCalledWith(smartBanner.STORAGE_KEY_DISMISSED, now) // add timestamp in Local Storage
 
       expect(Logger.log).toHaveBeenCalledWith('Smart Banner dismissed')
       expect(smartBanner.destroy).toHaveBeenCalled()
@@ -225,10 +234,12 @@ describe('Smart Banner tests', () => {
 
       expect(Logger.log).toHaveBeenCalledWith('Smart Banner removed') // banner removed from DOM
       expect(smartBanner.banner).toBeNull()
+
+      expect(onDismissedCallbackSpy).toHaveBeenCalled()
     })
 
     it('intialisation reschedules banner display when dismiss interval has not over', async () => {
-      expect.assertions(4)
+      expect.assertions(6)
 
       smartBanner.init(webToken)
       await Utils.flushPromises()
@@ -238,10 +249,13 @@ describe('Smart Banner tests', () => {
 
       expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), defaultDismissInterval) // initialisation scheduled
       expect(Logger.log).toHaveBeenCalledWith('Smart Banner creation scheduled on ' + new Date(now + defaultDismissInterval))
+
+      expect(onCreatedCallbackSpy).not.toHaveBeenCalled()
+      expect(onDismissedCallbackSpy).toHaveBeenCalledTimes(1)
     })
 
     it('banner is displayed again when dismiss interval is over', async () => {
-      expect.assertions(6)
+      expect.assertions(7)
 
       jest.spyOn(Date, 'now').mockReturnValue(now + defaultDismissInterval)
       jest.advanceTimersByTime(defaultDismissInterval)
@@ -255,6 +269,7 @@ describe('Smart Banner tests', () => {
       expect(smartBanner.banner).not.toBeNull()
       expect(smartBanner.dismissButton).not.toBeNull()
       expect(Logger.log).toHaveBeenCalledWith('Smart Banner created')
+      expect(onCreatedCallbackSpy).toHaveBeenCalled()
 
       smartBanner.destroy()
     })
diff --git a/src/sdk/__tests__/url-strategy.spec.ts b/src/sdk/__tests__/url-strategy.spec.ts
index 191fa544..488ecfd4 100644
--- a/src/sdk/__tests__/url-strategy.spec.ts
+++ b/src/sdk/__tests__/url-strategy.spec.ts
@@ -1,21 +1,34 @@
-import { UrlStrategy, urlStrategyRetries, getBaseUrlsIterator, BaseUrlsMap, BaseUrlsIterator } from '../url-strategy'
+import { UrlStrategy, getBaseUrlsIterator, BaseUrlsMap, BaseUrlsIterator, DataResidency } from '../url-strategy'
 import * as Globals from '../globals'
+import * as Logger from '../logger'
 
 jest.mock('../logger')
 
 describe('test url strategy', () => {
   const testEndpoints = {
-    default: {
+    [UrlStrategy.Default]: {
       app: 'app.default',
       gdpr: 'gdpr.default'
     },
-    india: {
+    [UrlStrategy.India]: {
       app: 'app.india',
       gdpr: 'gdpr.india'
     },
-    china: {
+    [UrlStrategy.China]: {
       app: 'app.china',
       gdpr: 'gdpr.china'
+    },
+    [DataResidency.EU]: {
+      app: 'app.eu',
+      gdpr: 'gdpr.eu'
+    },
+    [DataResidency.TR]: {
+      app: 'app.tr',
+      gdpr: 'gdpr.tr'
+    },
+    [DataResidency.US]: {
+      app: 'app.us',
+      gdpr: 'gdpr.us'
     }
   }
 
@@ -32,6 +45,7 @@ describe('test url strategy', () => {
 
   beforeAll(() => {
     Globals.default.env = 'development'
+    jest.spyOn(Logger.default, 'warn')
   })
 
   beforeEach(() => {
@@ -48,86 +62,8 @@ describe('test url strategy', () => {
     jest.restoreAllMocks()
   })
 
-  describe('Promise-based urlStrategyRetries tests', () => {
-
-    it('does not override custom url', () => {
-      const customUrl = 'custom-url'
-      Config.set({ ...options, customUrl })
-
-      expect.assertions(2)
-
-      return urlStrategyRetries(sendRequestMock, testEndpoints)
-        .catch(reason => expect(reason).toEqual({ code: 'NO_CONNECTION' }))
-        .then(() => expect(sendRequestMock).toHaveBeenCalledWith({ app: customUrl, gdpr: customUrl }))
-    })
-
-    it('retries to send request to endpoints iteratively', () => {
-      expect.assertions(5)
-
-      return urlStrategyRetries(sendRequestMock, testEndpoints)
-        .catch(reason => expect(reason).toEqual({ code: 'NO_CONNECTION' }))
-        .then(() => {
-          expect(sendRequestMock).toHaveBeenCalledTimes(3)
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.default.app, gdpr: testEndpoints.default.gdpr })
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.india.app, gdpr: testEndpoints.india.gdpr })
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.china.app, gdpr: testEndpoints.china.gdpr })
-        })
-    })
-
-    it('prefers Indian enpoint and does not try reach Chinese one when india url strategy set', () => {
-      Config.set({ ...options, urlStrategy: UrlStrategy.India })
-
-      expect.assertions(4)
-
-      return urlStrategyRetries(sendRequestMock, testEndpoints)
-        .catch(reason => expect(reason).toEqual({ code: 'NO_CONNECTION' }))
-        .then(() => {
-          expect(sendRequestMock).toHaveBeenCalledTimes(2)
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.india.app, gdpr: testEndpoints.india.gdpr })
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.default.app, gdpr: testEndpoints.default.gdpr })
-        })
-    })
-
-    it('prefers Chinese enpoint and does not try reach Indian one when china url strategy set', () => {
-      Config.set({ ...options, urlStrategy: UrlStrategy.China })
-
-      expect.assertions(4)
-
-      return urlStrategyRetries(sendRequestMock, testEndpoints)
-        .catch(reason => expect(reason).toEqual({ code: 'NO_CONNECTION' }))
-        .then(() => {
-          expect(sendRequestMock).toHaveBeenCalledTimes(2)
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.china.app, gdpr: testEndpoints.china.gdpr })
-          expect(sendRequestMock).toHaveBeenCalledWith({ app: testEndpoints.default.app, gdpr: testEndpoints.default.gdpr })
-        })
-    })
-
-    it('stops to iterate endpoints if connected succesfully', () => {
-      const sendRequestMock = jest.fn()
-        .mockImplementationOnce(() => Promise.reject({ code: 'NO_CONNECTION' }))
-        .mockImplementationOnce(() => Promise.resolve())
-
-      expect.assertions(1)
-
-      return urlStrategyRetries(sendRequestMock, testEndpoints)
-        .then(() => expect(sendRequestMock).toHaveBeenCalledTimes(2))
-    })
-
-    it('does not iterate endpoints if another error happened', () => {
-      const sendRequestMock = jest.fn(() => Promise.reject({ code: 'UNKNOWN' }))
-
-      expect.assertions(1)
-
-      return urlStrategyRetries(sendRequestMock, testEndpoints)
-        .catch(() => expect(sendRequestMock).toHaveBeenCalledTimes(1))
-    })
-
-  })
-
   describe('BaseUrlsIterator tests', () => {
 
-    const numberOfIterations = Object.keys(testEndpoints).length
-
     const iterateThrough = (iterator: BaseUrlsIterator, iterationsNumber?: number) => {
       const results: BaseUrlsMap[] = []
       let current
@@ -146,10 +82,10 @@ describe('test url strategy', () => {
     it('returns all values through iteration when default url startegy used', () => {
       const iterator = getBaseUrlsIterator(testEndpoints)
 
-      expect(iterator.next()).toEqual({value: testEndpoints.default, done: false})
-      expect(iterator.next()).toEqual({value: testEndpoints.india, done: false})
-      expect(iterator.next()).toEqual({value: testEndpoints.china, done: false})
-      expect(iterator.next()).toEqual({value: undefined, done: true})
+      expect(iterator.next()).toEqual({ value: testEndpoints.default, done: false })
+      expect(iterator.next()).toEqual({ value: testEndpoints.india, done: false })
+      expect(iterator.next()).toEqual({ value: testEndpoints.china, done: false })
+      expect(iterator.next()).toEqual({ value: undefined, done: true })
     })
 
     it('prefers Indian enpoint and does not try reach Chinese one when india url strategy set', () => {
@@ -184,7 +120,9 @@ describe('test url strategy', () => {
 
     describe('reset allows to restart iteration', () => {
 
-      it('iterate through all endpoints twice', () => {
+      it('iterates through all endpoints twice in default order', () => {
+        const defaultEndpointsNumber = 3 // number of endpoints to try if default url strategy used
+
         const iterator = getBaseUrlsIterator(testEndpoints)
 
         const first = iterateThrough(iterator)
@@ -193,12 +131,12 @@ describe('test url strategy', () => {
 
         const second = iterateThrough(iterator)
 
-        expect(first.length).toEqual(numberOfIterations)
-        expect(second.length).toEqual(numberOfIterations)
+        expect(first.length).toEqual(defaultEndpointsNumber)
+        expect(second.length).toEqual(defaultEndpointsNumber)
         expect(second).toEqual(first)
       })
 
-      it('iterate partially then reset', () => {
+      it('iterates partially then reset', () => {
         const iterator = getBaseUrlsIterator(testEndpoints)
 
         const firstIteration = iterateThrough(iterator, 1)
@@ -222,5 +160,38 @@ describe('test url strategy', () => {
         expect(thirdIteration[2]).toEqual(testEndpoints.china)
       })
     })
+
+    describe('data residency', () => {
+
+      it.each([
+        DataResidency.EU,
+        DataResidency.US,
+        DataResidency.TR
+      ])('tries to reach only regional endpoint if data residency set', (dataResidency) => {
+        Config.set({ ...options, dataResidency: dataResidency })
+
+        const values = iterateThrough(getBaseUrlsIterator(testEndpoints))
+
+        expect(values.length).toEqual(1)
+        expect(values[0]).toEqual(testEndpoints[dataResidency])
+      })
+
+      it.each([
+        [UrlStrategy.China, DataResidency.EU],
+        [UrlStrategy.China, DataResidency.US],
+        [UrlStrategy.China, DataResidency.TR],
+        [UrlStrategy.India, DataResidency.EU],
+        [UrlStrategy.India, DataResidency.US],
+        [UrlStrategy.India, DataResidency.TR]
+      ])('drops url strategy if data residency set', (urlStrategy, dataResidency) => {
+        Config.set({ ...options, urlStrategy: urlStrategy, dataResidency: dataResidency })
+
+        const values = iterateThrough(getBaseUrlsIterator(testEndpoints))
+
+        expect(Logger.default.warn).toHaveBeenCalledWith('Both dataResidency and urlStrategy are set in config, urlStrategy will be ignored')
+        expect(values.length).toEqual(1)
+        expect(values[0]).toEqual(testEndpoints[dataResidency])
+      })
+    })
   })
 })
diff --git a/src/sdk/config.js b/src/sdk/config.js
index 85fff763..1c0f610c 100644
--- a/src/sdk/config.js
+++ b/src/sdk/config.js
@@ -63,8 +63,9 @@ const _allowedParams: BaseParamsListT = [
  * @private
  */
 const _allowedConfig: CustomConfigListT = [
-  'urlStrategy',
   'customUrl',
+  'dataResidency',
+  'urlStrategy',
   'eventDeduplicationListLimit',
   'namespace'
 ]
diff --git a/src/sdk/constants.js b/src/sdk/constants.js
index f65f137e..b67b86e9 100644
--- a/src/sdk/constants.js
+++ b/src/sdk/constants.js
@@ -19,3 +19,36 @@ export const STORAGE_TYPES = {
   INDEXED_DB: 'indexedDB',
   LOCAL_STORAGE: 'localStorage'
 }
+
+export const ENDPOINTS = {
+  default: {
+    endpointName: 'Default',
+    app: 'https://app.adjust.com',
+    gdpr: 'https://gdpr.adjust.com'
+  },
+  india: {
+    endpointName: 'Indian',
+    app: 'https://app.adjust.net.in',
+    gdpr: 'https://gdpr.adjust.net.in'
+  },
+  china: {
+    endpointName: 'Chinese',
+    app: 'https://app.adjust.world',
+    gdpr: 'https://gdpr.adjust.world'
+  },
+  EU: {
+    endpointName: 'EU',
+    app: 'https://app.eu.adjust.com',
+    gdpr: 'https://gdpr.eu.adjust.com'
+  },
+  TR: {
+    endpointName: 'TR',
+    app: 'https://app.tr.adjust.com',
+    gdpr: 'https://gdpr.tr.adjust.com'
+  },
+  US: {
+    endpointName: 'US',
+    app: 'https://app.us.adjust.com',
+    gdpr: 'https://gdpr.us.adjust.com'
+  }
+}
diff --git a/src/sdk/main.js b/src/sdk/main.js
index 4c2d44b6..66024309 100644
--- a/src/sdk/main.js
+++ b/src/sdk/main.js
@@ -63,6 +63,13 @@ let _isStarted: boolean = false
  */
 let _isInstalled: boolean = false
 
+/**
+ * SmartBanner instance
+ *
+ * @private
+ */
+let _smartBanner: ?SmartBanner = null
+
 /**
  * Initiate the instance with parameters
  *
@@ -243,8 +250,31 @@ function disableThirdPartySharing (): void {
   })
 }
 
-function initSmartBanner ({ webToken, logLevel }: SmartBannerOptionsT): void {
-  SmartBanner.init(webToken, logLevel)
+function initSmartBanner (options: SmartBannerOptionsT): void {
+  if (_smartBanner) {
+    Logger.error('Smart Banner already initialised')
+    return
+  }
+
+  _smartBanner = new SmartBanner(options)
+}
+
+function showSmartBanner (): void {
+  if (!_smartBanner) {
+    Logger.error('Smart Banner is not initialised yet')
+    return
+  }
+
+  _smartBanner.show()
+}
+
+function hideSmartBanner (): void {
+  if (!_smartBanner) {
+    Logger.error('Smart Banner is not initialised yet')
+    return
+  }
+
+  _smartBanner.hide()
 }
 
 /**
@@ -526,6 +556,8 @@ const Adjust = {
   gdprForgetMe,
   disableThirdPartySharing,
   initSmartBanner,
+  showSmartBanner,
+  hideSmartBanner,
   __testonly__: {
     destroy: _destroy,
     clearDatabase: _clearDatabase
diff --git a/src/sdk/request.js b/src/sdk/request.js
index f07de4e9..dd7c5a01 100644
--- a/src/sdk/request.js
+++ b/src/sdk/request.js
@@ -95,12 +95,12 @@ const Request = ({url, method = 'GET', params = {}, continueCb, strategy, wait}:
   /**
    * Url Startegy iterator to go through endpoints to retry to send request
    */
-  const _baseUrlsIterator: BaseUrlsIterator = getBaseUrlsIterator()
+  let _baseUrlsIterator: BaseUrlsIterator
 
   /**
    * Current base urls map to send request
    */
-  let _baseUrlsIteratorCurrent: { value: BaseUrlsMap, done: boolean } = _baseUrlsIterator.next()
+  let _baseUrlsIteratorCurrent: { value: BaseUrlsMap, done: boolean }
 
 
   /**
@@ -236,6 +236,11 @@ const Request = ({url, method = 'GET', params = {}, continueCb, strategy, wait}:
    * @private
    */
   function _prepareRequest ({wait, retrying}: {wait?: ?WaitT, retrying?: boolean}): Promise {
+    if (!_baseUrlsIterator) {
+      _baseUrlsIterator = getBaseUrlsIterator()
+      _baseUrlsIteratorCurrent = _baseUrlsIterator.next()
+    }
+
     _wait = wait ? _prepareWait(wait) : _wait
 
     if (_skip(wait)) {
diff --git a/src/sdk/smart-banner/network/api.ts b/src/sdk/smart-banner/api.ts
similarity index 88%
rename from src/sdk/smart-banner/network/api.ts
rename to src/sdk/smart-banner/api.ts
index c0dd24e1..4fe0f936 100644
--- a/src/sdk/smart-banner/network/api.ts
+++ b/src/sdk/smart-banner/api.ts
@@ -1,6 +1,6 @@
-import Logger from '../../logger'
-import { DeviceOS } from '../detect-os'
-import { Network } from './network'
+import Logger from '../logger'
+import { DeviceOS } from './detect-os'
+import { Network } from './network/network'
 
 export enum Position {
   Top = 'top',
@@ -60,10 +60,10 @@ function validate(response: Partial): SmartBannerData | nul
   return null
 }
 
-export function fetchSmartBannerData(webToken: string, deviceOs: DeviceOS): Promise {
+export function fetchSmartBannerData(webToken: string, deviceOs: DeviceOS, network: Network): Promise {
   const path = '/smart_banner'
 
-  return Network.request[]>(path, { 'app_web_token': webToken })
+  return network.request[]>(path, { 'app_web_token': webToken })
     .then(banners => {
       const banner = banners.find(item => item.platform === deviceOs)
 
diff --git a/src/sdk/smart-banner/network/errors.ts b/src/sdk/smart-banner/network/errors.ts
index 439a5b84..fca73b0a 100644
--- a/src/sdk/smart-banner/network/errors.ts
+++ b/src/sdk/smart-banner/network/errors.ts
@@ -1,11 +1,9 @@
 export interface NetworkError {
   status: number;
-  code?: string;
   message: string;
 }
 
 export const NoConnectionError: NetworkError = {
   status: 0,
-  code: 'NO_CONNECTION', // for compatibility with UrlStrategy
   message: 'No internet connectivity'
 }
diff --git a/src/sdk/smart-banner/network/network.ts b/src/sdk/smart-banner/network/network.ts
index f42b256d..0fff4805 100644
--- a/src/sdk/smart-banner/network/network.ts
+++ b/src/sdk/smart-banner/network/network.ts
@@ -1,90 +1,20 @@
-import { parseJson } from '../utilities'
-import Globals from '../../globals'
-import { urlStrategyRetries } from '../../url-strategy'
-import { NetworkError, NoConnectionError } from './errors'
-
-type Primitive = string | number | boolean
-
-export class Network {
-  private static defaultEndpoint = 'https://app.adjust.com'
-
-  private static lastSuccessfulEndpoint: string | undefined
-
-  /**
-   * Creates an XMLHttpRequest object and sends a GET request with provided encoded URL
-   * @param url encoded URL
-   */
-  private static xhr(url: string): Promise {
-    return new Promise((resolve, reject: (err: NetworkError) => void) => {
-      const xhr = new XMLHttpRequest()
-      xhr.open('GET', url)
-
-      const headers = [
-        ['Client-SDK', `js${Globals.version}`],
-        ['Content-Type', 'application/json']
-      ]
-
-      headers.forEach(([key, value]) => {
-        xhr.setRequestHeader(key, value)
-      })
-
-      xhr.onerror = () => reject(NoConnectionError)
-
-      xhr.onreadystatechange = () => {
-        if (xhr.readyState !== 4) {
-          return
-        }
-
-        const okStatus = xhr.status >= 200 && xhr.status < 300
-        const json = parseJson(xhr.responseText)
-
-        if (xhr.status === 0) {
-          reject(NoConnectionError)
-        } else {
-          if (okStatus) {
-            resolve(json)
-          } else {
-            reject({ status: xhr.status, message: json || xhr.responseText || '' })
-          }
-        }
-      }
+export interface Network {
+  endpoint: string;
+  request: (path: string, params?: Record) => Promise;
+}
 
-      xhr.send()
-    })
-  }
+export class NetworkDecorator implements Network {
+  constructor(protected network: Network) { }
 
-  private static encodeParams(params: Record): string {
-    return Object.keys(params)
-      .map(key => [encodeURIComponent(key), encodeURIComponent(params[key])].join('='))
-      .join('&')
+  public get endpoint(): string {
+    return this.network.endpoint
   }
 
-  /**
-   * Returns last succesfull endpoint or default (`https://app.adjust.com`) one
-   */
-  public static getEndpoint(): string {
-    return Network.lastSuccessfulEndpoint || Network.defaultEndpoint
+  public set endpoint(value: string) {
+    this.network.endpoint = value
   }
 
-  /**
-   * Sends a request to provided path choosing origin with `urlStrategyRetries`
-   * @param path
-   * @param params non-encoded parameters of the request
-   */
-  public static request(path: string, params?: Record): Promise {
-    return urlStrategyRetries(baseUrlsMap => {
-      const origin = baseUrlsMap.app
-      const encodedParams = params ? `?${Network.encodeParams(params)}` : ''
-
-      return Network.xhr(`${origin}${path}${encodedParams}`)
-        .then((result: T) => {
-          Network.lastSuccessfulEndpoint = baseUrlsMap.app
-          return result
-        })
-        .catch((err: NetworkError) => {
-          Network.lastSuccessfulEndpoint = undefined
-          throw err
-        })
-    })
+  request(path: string, params?: Record): Promise {
+    return this.network.request(path, params)
   }
 }
diff --git a/src/sdk/smart-banner/network/url-startegy-network.ts b/src/sdk/smart-banner/network/url-startegy-network.ts
new file mode 100644
index 00000000..e6f0a3a0
--- /dev/null
+++ b/src/sdk/smart-banner/network/url-startegy-network.ts
@@ -0,0 +1,58 @@
+import { ENDPOINTS } from '../../constants'
+import { NetworkDecorator, Network } from '../network/network'
+import { UrlStrategy } from './url-strategy/url-strategy'
+import { UrlStrategyFactory, UrlStrategyConfig } from './url-strategy/url-strategy-factory'
+import { NetworkError } from './errors'
+
+export class NetworkWithUrlStrategy extends NetworkDecorator {
+  private static readonly DEFAULT_ENDPOINT = ENDPOINTS.default.app
+  private lastSuccessfulEndpoint: string | undefined
+  private urlStrategy: UrlStrategy
+
+  constructor(network: Network, { urlStrategy, urlStrategyConfig }: NetworkWithUrlStrategy.UrlStrategyParameters) {
+    super(network)
+
+    this.urlStrategy = urlStrategy || UrlStrategyFactory.create(urlStrategyConfig)
+  }
+
+  /**
+   * Returns last succesfull endpoint or default (`https://app.adjust.com`) one
+   */
+  public get endpoint(): string {
+    return this.lastSuccessfulEndpoint || NetworkWithUrlStrategy.DEFAULT_ENDPOINT
+  }
+
+  /**
+   * Sends a request to provided path choosing origin with UrlStrategy and caches used origin if it was successfully
+   * reached
+   *
+   * @param path
+   * @param params non-encoded parameters of the request
+   */
+  public request(path: string, params?: Record): Promise {
+
+    return this.urlStrategy.retries((baseUrlsMap) => {
+      this.network.endpoint = baseUrlsMap.app
+
+      return this.network.request(path, params)
+        .then((result: T) => {
+          this.lastSuccessfulEndpoint = baseUrlsMap.app
+          return result
+        })
+        .catch((err: NetworkError) => {
+          this.lastSuccessfulEndpoint = undefined
+          throw err
+        })
+    })
+  }
+}
+
+namespace NetworkWithUrlStrategy {
+  export type UrlStrategyParameters = {
+    urlStrategy: UrlStrategy;
+    urlStrategyConfig?: never;
+  } | {
+    urlStrategy?: never;
+    urlStrategyConfig: UrlStrategyConfig;
+  }
+}
diff --git a/src/sdk/smart-banner/network/url-strategy/blocked-url-bypass.ts b/src/sdk/smart-banner/network/url-strategy/blocked-url-bypass.ts
new file mode 100644
index 00000000..f432f570
--- /dev/null
+++ b/src/sdk/smart-banner/network/url-strategy/blocked-url-bypass.ts
@@ -0,0 +1,43 @@
+import { BaseUrlsMap } from './url-strategy'
+import { ENDPOINTS } from '../../../constants'
+
+export namespace BlockedUrlBypass {
+  export const Default = 'default'
+  export const India = 'india'
+  export const China = 'china'
+
+  export type Strategy = typeof Default | typeof India | typeof China
+
+  const endpoints: Record = {
+    [BlockedUrlBypass.Default]: ENDPOINTS.default,
+    [BlockedUrlBypass.India]: ENDPOINTS.india,
+    [BlockedUrlBypass.China]: ENDPOINTS.china,
+  }
+
+  const getPreferredUrlsWithOption = (endpoints: Record, option?: BlockedUrlBypass.Strategy) => {
+
+    if (option === BlockedUrlBypass.India) {
+      return [
+        endpoints[BlockedUrlBypass.India],
+        endpoints[BlockedUrlBypass.Default]
+      ]
+    }
+
+    if (option === BlockedUrlBypass.China) {
+      return [
+        endpoints[BlockedUrlBypass.China],
+        endpoints[BlockedUrlBypass.Default]
+      ]
+    }
+
+    return [
+      endpoints[BlockedUrlBypass.Default],
+      endpoints[BlockedUrlBypass.India],
+      endpoints[BlockedUrlBypass.China]
+    ]
+  }
+
+  export function preferredUrlsGetter(option?: BlockedUrlBypass.Strategy, endpointsMap: Record = endpoints) {
+    return () => getPreferredUrlsWithOption(endpointsMap, option)
+  }
+}
diff --git a/src/sdk/smart-banner/network/url-strategy/custom-url.ts b/src/sdk/smart-banner/network/url-strategy/custom-url.ts
new file mode 100644
index 00000000..abef7f88
--- /dev/null
+++ b/src/sdk/smart-banner/network/url-strategy/custom-url.ts
@@ -0,0 +1,14 @@
+export namespace CustomUrl {
+  const getPreferredUrlsWithOption = (customUrl: string) => {
+
+    return [{
+      endpointName: `Custom (${customUrl})`,
+      app: customUrl,
+      gdpr: customUrl
+    }]
+  }
+
+  export function preferredUrlsGetter(customUrl: string) {
+    return () => getPreferredUrlsWithOption(customUrl)
+  }
+}
diff --git a/src/sdk/smart-banner/network/url-strategy/data-residency.ts b/src/sdk/smart-banner/network/url-strategy/data-residency.ts
new file mode 100644
index 00000000..0ce32096
--- /dev/null
+++ b/src/sdk/smart-banner/network/url-strategy/data-residency.ts
@@ -0,0 +1,24 @@
+import { BaseUrlsMap } from './url-strategy'
+import { ENDPOINTS } from '../../../constants'
+
+export namespace DataResidency {
+  export const EU = 'EU'
+  export const TR = 'TR'
+  export const US = 'US'
+
+  export type Region = typeof EU | typeof TR | typeof US
+
+  const endpoints: Record = {
+    [DataResidency.EU]: ENDPOINTS.EU,
+    [DataResidency.TR]: ENDPOINTS.TR,
+    [DataResidency.US]: ENDPOINTS.US,
+  }
+
+  const getPreferredUrlsWithOption = (endpoints: Record, option: DataResidency.Region) => {
+    return [endpoints[option]]
+  }
+
+  export function preferredUrlsGetter(option: DataResidency.Region, endpointsMap: Record = endpoints) {
+    return () => getPreferredUrlsWithOption(endpointsMap, option)
+  }
+}
diff --git a/src/sdk/smart-banner/network/url-strategy/url-strategy-factory.ts b/src/sdk/smart-banner/network/url-strategy/url-strategy-factory.ts
new file mode 100644
index 00000000..3815df8d
--- /dev/null
+++ b/src/sdk/smart-banner/network/url-strategy/url-strategy-factory.ts
@@ -0,0 +1,45 @@
+import Logger from '../../../logger'
+import { UrlStrategy } from './url-strategy'
+import { BlockedUrlBypass } from './blocked-url-bypass'
+import { CustomUrl } from './custom-url'
+import { DataResidency } from './data-residency'
+
+export type UrlStrategyConfig = {
+  customUrl: string;
+  urlStrategy?: never;
+  dataResidency?: never;
+} | {
+  customUrl?: never;
+  dataResidency: DataResidency.Region;
+  urlStrategy?: never;
+} | {
+  customUrl?: never;
+  dataResidency?: never;
+  urlStrategy?: BlockedUrlBypass.Strategy;
+}
+
+export namespace UrlStrategyFactory {
+  const incorrectOptionIgnoredMessage = (higherPriority: string, lowerPriority: string) => {
+    Logger.warn(`Both ${higherPriority} and ${lowerPriority} are set in config, ${lowerPriority} will be ignored`)
+  }
+
+  export function create(config: UrlStrategyConfig): UrlStrategy {
+    const { customUrl, dataResidency, urlStrategy } = config
+
+    if (customUrl) {
+      if (dataResidency || urlStrategy) {
+        incorrectOptionIgnoredMessage('customUrl', dataResidency ? 'dataResidency' : 'urlStrategy')
+      }
+
+      return new UrlStrategy(CustomUrl.preferredUrlsGetter(customUrl))
+    } else if (dataResidency) {
+      if (urlStrategy) {
+        incorrectOptionIgnoredMessage('dataResidency', 'urlStrategy')
+      }
+
+      return new UrlStrategy(DataResidency.preferredUrlsGetter(dataResidency))
+    } else {
+      return new UrlStrategy(BlockedUrlBypass.preferredUrlsGetter(urlStrategy))
+    }
+  }
+}
diff --git a/src/sdk/smart-banner/network/url-strategy/url-strategy.ts b/src/sdk/smart-banner/network/url-strategy/url-strategy.ts
new file mode 100644
index 00000000..be109ec7
--- /dev/null
+++ b/src/sdk/smart-banner/network/url-strategy/url-strategy.ts
@@ -0,0 +1,51 @@
+import Logger from '../../../logger'
+import { NetworkError, NoConnectionError } from '../errors'
+
+export type BaseUrlsMap = {
+  endpointName: string;
+  app: string;
+  gdpr: string;
+}
+
+export class UrlStrategy {
+  static NoPreferredUrlsDefinedError = new ReferenceError('UrlStrategy: No preferred URL defined')
+
+  constructor(private preferredUrls: () => BaseUrlsMap[]) { }
+
+  /**
+   * Gets the list of preferred endpoints and wraps `sendRequest` function with iterative retries until available
+   * endpoint found or another error occurred.
+   */
+  public retries(sendRequest: (urls: BaseUrlsMap) => Promise): Promise {
+    let attempt = 0
+
+    const trySendRequest = (): Promise => {
+      const preferredUrls = this.preferredUrls()
+
+      if (!preferredUrls || preferredUrls.length === 0) {
+        Logger.error(UrlStrategy.NoPreferredUrlsDefinedError.message)
+        throw UrlStrategy.NoPreferredUrlsDefinedError
+      }
+
+      const urlsMap = preferredUrls[attempt++]
+
+      return sendRequest(urlsMap)
+        .catch((reason: NetworkError) => {
+          if (reason === NoConnectionError) {
+            Logger.log(`Failed to connect ${urlsMap.endpointName} endpoint`)
+
+            if (attempt < preferredUrls.length) {
+              Logger.log(`Trying ${preferredUrls[attempt].endpointName} one`)
+
+              return trySendRequest() // Trying next endpoint
+            }
+          }
+
+          // Another error occurred or we ran out of attempts, re-throw
+          throw reason
+        })
+    }
+
+    return trySendRequest()
+  }
+}
diff --git a/src/sdk/smart-banner/network/xhr-network.ts b/src/sdk/smart-banner/network/xhr-network.ts
new file mode 100644
index 00000000..e6b2a64f
--- /dev/null
+++ b/src/sdk/smart-banner/network/xhr-network.ts
@@ -0,0 +1,78 @@
+import Globals from '../../globals'
+import { Network } from './network'
+import { parseJson } from '../utilities'
+import { NetworkError, NoConnectionError } from './errors'
+
+type Primitive = string | number | boolean
+
+/** Sends HTTP GET request using XMLHttpRequest */
+export class XhrNetwork implements Network {
+  constructor(public origin?: string) { }
+
+  public get endpoint(): string {
+    if (!this.origin) {
+      throw Error('XhrNetwork: Origin not defined')
+    }
+
+    return this.origin
+  }
+
+  public set endpoint(value: string) {
+    this.origin = value
+  }
+
+  /**
+   * Creates an XMLHttpRequest object and sends a GET request with provided encoded URL
+   * @param url encoded URL
+   */
+  private xhr(url: string): Promise {
+    return new Promise((resolve, reject: (err: NetworkError) => void) => {
+      const xhr = new XMLHttpRequest()
+      xhr.open('GET', url)
+
+      const headers = [
+        ['Client-SDK', `js${Globals.version}`],
+        ['Content-Type', 'application/json']
+      ]
+
+      headers.forEach(([key, value]) => {
+        xhr.setRequestHeader(key, value)
+      })
+
+      xhr.onerror = () => reject(NoConnectionError)
+
+      xhr.onreadystatechange = () => {
+        if (xhr.readyState !== 4) {
+          return
+        }
+
+        const okStatus = xhr.status >= 200 && xhr.status < 300
+        const json = parseJson(xhr.responseText)
+
+        if (xhr.status === 0) {
+          reject(NoConnectionError)
+        } else {
+          if (okStatus) {
+            resolve(json)
+          } else {
+            reject({ status: xhr.status, message: json || xhr.responseText || '' })
+          }
+        }
+      }
+
+      xhr.send()
+    })
+  }
+
+  private encodeParams(params: Record): string {
+    return Object.keys(params)
+      .map(key => [encodeURIComponent(key), encodeURIComponent(params[key])].join('='))
+      .join('&')
+  }
+
+  public request(path: string, params?: Record): Promise {
+    const encodedParams = params ? `?${this.encodeParams(params)}` : ''
+
+    return this.xhr(`${this.endpoint}${path}${encodedParams}`)
+  }
+}
diff --git a/src/sdk/smart-banner/smart-banner.ts b/src/sdk/smart-banner/smart-banner.ts
index c47cd29b..9560bf81 100644
--- a/src/sdk/smart-banner/smart-banner.ts
+++ b/src/sdk/smart-banner/smart-banner.ts
@@ -1,31 +1,55 @@
 import Logger from '../logger'
 import { getDeviceOS } from './detect-os'
 import { storage } from './local-storage'
-import { fetchSmartBannerData, SmartBannerData } from './network/api'
+import { fetchSmartBannerData, SmartBannerData } from './api'
 import { SmartBannerView } from './view/smart-banner-view'
 import { Network } from './network/network'
+import { XhrNetwork } from './network/xhr-network'
+import { NetworkWithUrlStrategy } from './network/url-startegy-network'
+import { DataResidency } from './network/url-strategy/data-residency'
 
 type LogLevel = 'none' | 'error' | 'warning' | 'info' | 'verbose'
 
+type Callback = () => any;
+
+interface SmartBannerOptions {
+  webToken: string;
+  logLevel?: LogLevel;
+  dataResidency?: DataResidency.Region;
+  onCreated?: Callback;
+  onDismissed?: Callback;
+}
+
 /**
  * Adjust Web SDK Smart Banner
  */
-class SmartBanner {
-  private dismissedStorageKey = 'closed'
-  private timer: NodeJS.Timeout | null = null
+export class SmartBanner {
+  private readonly STORAGE_KEY_DISMISSED = 'closed'
+  private network: Network
+  private timer: ReturnType | null = null
   private dataFetchPromise: Promise | null
   private banner: SmartBannerView | null
-  private logLevel: LogLevel
+  private onCreated?: Callback
+  private onDismissed?: Callback
+
+  constructor({ webToken, logLevel = 'error', dataResidency, onCreated, onDismissed }: SmartBannerOptions, network?: Network) {
+    this.onCreated = onCreated
+    this.onDismissed = onDismissed
+
+    Logger.setLogLevel(logLevel)
+
+    const config = dataResidency ? { dataResidency } : {}
+    this.network = network || new NetworkWithUrlStrategy(new XhrNetwork(), { urlStrategyConfig: config })
+
+    this.init(webToken)
+  }
 
   /**
    * Initiate Smart Banner
    *
    * @param webToken token used to get data from backend
    */
-  init(webToken: string, logLevel: LogLevel = 'error') {
-    this.logLevel = logLevel
-    Logger.setLogLevel(logLevel)
-
+  init(webToken: string) {
     if (this.banner) {
       Logger.error('Smart Banner already exists')
       return
@@ -42,7 +66,7 @@ class SmartBanner {
       return
     }
 
-    this.dataFetchPromise = fetchSmartBannerData(webToken, deviceOs)
+    this.dataFetchPromise = fetchSmartBannerData(webToken, deviceOs, this.network)
 
     this.dataFetchPromise.then(bannerData => {
       this.dataFetchPromise = null
@@ -64,10 +88,14 @@ class SmartBanner {
       this.banner = new SmartBannerView(
         bannerData,
         () => this.dismiss(webToken, bannerData.dismissInterval),
-        Network.getEndpoint()
+        this.network.endpoint
       )
 
       Logger.log('Smart Banner created')
+
+      if (this.onCreated) {
+        this.onCreated()
+      }
     })
   }
 
@@ -138,11 +166,15 @@ class SmartBanner {
   private dismiss(webToken: string, dismissInterval: number) {
     Logger.log('Smart Banner dismissed')
 
-    storage.setItem(this.dismissedStorageKey, Date.now())
+    storage.setItem(this.STORAGE_KEY_DISMISSED, Date.now())
     const whenToShow = this.getDateToShowAgain(dismissInterval)
     this.scheduleCreation(webToken, whenToShow)
 
     this.destroy()
+
+    if (this.onDismissed) {
+      this.onDismissed()
+    }
   }
 
   /**
@@ -159,7 +191,7 @@ class SmartBanner {
     this.timer = setTimeout(
       () => {
         this.timer = null
-        this.init(webToken, this.logLevel)
+        this.init(webToken)
       },
       delay)
 
@@ -170,7 +202,7 @@ class SmartBanner {
    * Returns date when Smart Banner should be shown again
    */
   private getDateToShowAgain(dismissInterval: number): number {
-    const dismissedDate = storage.getItem(this.dismissedStorageKey)
+    const dismissedDate = storage.getItem(this.STORAGE_KEY_DISMISSED)
     if (!dismissedDate) {
       return Date.now()
     }
@@ -178,7 +210,3 @@ class SmartBanner {
     return dismissedDate + dismissInterval
   }
 }
-
-const smartBanner = new SmartBanner()
-
-export { smartBanner as SmartBanner }
diff --git a/src/sdk/smart-banner/view/app-icon.ts b/src/sdk/smart-banner/view/app-icon.ts
index 54f52350..6ef1cace 100644
--- a/src/sdk/smart-banner/view/app-icon.ts
+++ b/src/sdk/smart-banner/view/app-icon.ts
@@ -1,4 +1,4 @@
-import { SmartBannerData } from '../network/api'
+import { SmartBannerData } from '../api'
 
 type AppIconData = Pick
 
diff --git a/src/sdk/smart-banner/view/smart-banner-view.ts b/src/sdk/smart-banner/view/smart-banner-view.ts
index 162d1bee..a1609be0 100644
--- a/src/sdk/smart-banner/view/smart-banner-view.ts
+++ b/src/sdk/smart-banner/view/smart-banner-view.ts
@@ -1,6 +1,6 @@
 import styles from '../assets/styles.module.scss'
 import render from '../assets/template'
-import { Position, SmartBannerData } from '../network/api'
+import { Position, SmartBannerData } from '../api'
 import { AppIcon } from './app-icon'
 
 export class SmartBannerView {
diff --git a/src/sdk/storage/indexeddb.ts b/src/sdk/storage/indexeddb.ts
index ae9545e2..3b630047 100644
--- a/src/sdk/storage/indexeddb.ts
+++ b/src/sdk/storage/indexeddb.ts
@@ -98,18 +98,20 @@ class IndexedDBWrapper implements IStorage {
     if (IndexedDBWrapper.isSupportedPromise) {
       return IndexedDBWrapper.isSupportedPromise
     } else {
+      const notSupportedMessage = 'IndexedDB is not supported in this browser'
+
       IndexedDBWrapper.isSupportedPromise = new Promise((resolve) => {
         const indexedDB = IndexedDBWrapper.getIndexedDB()
         const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)
 
         if (!indexedDB || iOS) {
-          Logger.warn('IndexedDB is not supported in this browser')
+          Logger.warn(notSupportedMessage)
           resolve(false)
         } else {
           const dbOpenablePromise = IndexedDBWrapper.tryOpen(indexedDB)
             .then((dbOpenable) => {
               if (!dbOpenable) {
-                Logger.warn('IndexedDB is not supported in this browser')
+                Logger.warn(notSupportedMessage)
               }
 
               return dbOpenable
diff --git a/src/sdk/types.js b/src/sdk/types.js
index 2775f947..0ce6d6f5 100644
--- a/src/sdk/types.js
+++ b/src/sdk/types.js
@@ -161,8 +161,9 @@ export type BaseParamsT = $ReadOnly<$Shape<{
 }>>
 
 export type CustomConfigT = $ReadOnly<$Shape<{
-  urlStrategy: 'india' | 'china',
   customUrl: string,
+  urlStrategy: 'india' | 'china',
+  dataResidency: 'EU' | 'TR' | 'US',
   eventDeduplicationListLimit: number,
   namespace: string
 }>>
@@ -177,8 +178,9 @@ export type InitOptionsT = $ReadOnly<$Shape<{|
   environment: $PropertyType,
   defaultTracker: $PropertyType,
   externalDeviceId: $PropertyType,
-  urlStrategy: $PropertyType,
   customUrl: $PropertyType,
+  dataResidency: $PropertyType,
+  urlStrategy: $PropertyType,
   eventDeduplicationListLimit: $PropertyType,
   namespace: $PropertyType,
   attributionCallback: (string, Object) => mixed
@@ -232,6 +234,7 @@ export type QueueSizeT = {|
 export type SmartBannerOptionsT = {|
   webToken: string,
   logLevel: 'none' | 'error' | 'warning' | 'info' | 'verbose',
+  dataResidency: 'EU' | 'TR' | 'US',
 |}
 
 export type DefaultParamsT = {|
diff --git a/src/sdk/url-strategy.ts b/src/sdk/url-strategy.ts
index 2d59419d..bc984b43 100644
--- a/src/sdk/url-strategy.ts
+++ b/src/sdk/url-strategy.ts
@@ -1,5 +1,6 @@
 import Config from './config'
 import Logger from './logger'
+import { ENDPOINTS } from './constants'
 
 enum UrlStrategy {
   Default = 'default',
@@ -7,23 +8,45 @@ enum UrlStrategy {
   China = 'china'
 }
 
-type EndpointName = UrlStrategy
+enum DataResidency {
+  EU = 'EU',
+  TR = 'TR',
+  US = 'US'
+}
+
+type EndpointName = UrlStrategy | DataResidency
 
 type BaseUrlsMap = {
   app: string;
   gdpr: string;
 }
 
+function incorrectOptionIgnoredMessage(higherPriority: string, lowerPriority: string) {
+  Logger.warn(`Both ${higherPriority} and ${lowerPriority} are set in config, ${lowerPriority} will be ignored`)
+}
+
 /**
  * Returns a map of base URLs or a list of endpoint names depending on SDK configuration
  */
 function getEndpointPreference(): BaseUrlsMap | EndpointName[] {
-  const { customUrl, urlStrategy } = Config.getCustomConfig()
+  const { customUrl, urlStrategy, dataResidency } = Config.getCustomConfig()
 
   if (customUrl) { // If custom URL is set then send all requests there
+    if (dataResidency || urlStrategy) {
+      incorrectOptionIgnoredMessage('customUrl', dataResidency ? 'dataResidency' : 'urlStrategy')
+    }
+
     return { app: customUrl, gdpr: customUrl }
   }
 
+  if (dataResidency && urlStrategy) {
+    incorrectOptionIgnoredMessage('dataResidency', 'urlStrategy')
+  }
+
+  if (dataResidency) {
+    return [dataResidency]
+  }
+
   if (urlStrategy === UrlStrategy.India) {
     return [UrlStrategy.India, UrlStrategy.Default]
   }
@@ -35,66 +58,13 @@ function getEndpointPreference(): BaseUrlsMap | EndpointName[] {
   return [UrlStrategy.Default, UrlStrategy.India, UrlStrategy.China]
 }
 
-const endpointMap: Record = {
-  [UrlStrategy.Default]: {
-    app: 'https://app.adjust.com',
-    gdpr: 'https://gdpr.adjust.com'
-  },
-  [UrlStrategy.India]: {
-    app: 'https://app.adjust.net.in',
-    gdpr: 'https://gdpr.adjust.net.in'
-  },
-  [UrlStrategy.China]: {
-    app: 'https://app.adjust.world',
-    gdpr: 'https://gdpr.adjust.world'
-  }
-}
-
-const endpointNiceNames: Record = {
-  [UrlStrategy.Default]: 'default',
-  [UrlStrategy.India]: 'Indian',
-  [UrlStrategy.China]: 'Chinese'
-}
-
-/**
- * Gets the list of preferred endpoints and wraps `sendRequest` function with iterative retries until available
- * endpoint found or another error occurred.
- */
-function urlStrategyRetries(
-  sendRequest: (urls: BaseUrlsMap) => Promise,
-  endpoints: Record = endpointMap
-): Promise {
-  const preferredUrls = getEndpointPreference()
-
-  if (!Array.isArray(preferredUrls)) {
-    // There is only one endpoint
-    return sendRequest(preferredUrls)
-  } else {
-    let attempt = 0
-
-    const trySendRequest = (): Promise => {
-      const endpointKey = preferredUrls[attempt++]
-      const urlsMap = endpoints[endpointKey]
-
-      return sendRequest(urlsMap)
-        .catch((reason) => {
-          if (reason.code === 'NO_CONNECTION') {
-            Logger.log(`Failed to connect ${endpointNiceNames[endpointKey]} endpoint`)
-
-            if (attempt < preferredUrls.length) {
-              Logger.log(`Trying ${endpointNiceNames[preferredUrls[attempt]]} one`)
-
-              return trySendRequest() // Trying next endpoint
-            }
-          }
-
-          // Another error occurred or we ran out of attempts, re-throw
-          throw reason
-        })
-    }
-
-    return trySendRequest()
-  }
+const endpointMap: Record = {
+  [UrlStrategy.Default]: ENDPOINTS.default,
+  [UrlStrategy.India]: ENDPOINTS.india,
+  [UrlStrategy.China]: ENDPOINTS.china,
+  [DataResidency.EU]: ENDPOINTS.EU,
+  [DataResidency.TR]: ENDPOINTS.TR,
+  [DataResidency.US]: ENDPOINTS.US
 }
 
 interface BaseUrlsIterator extends Iterator {
@@ -102,12 +72,12 @@ interface BaseUrlsIterator extends Iterator {
 }
 
 function getPreferredUrls(endpoints: Partial>): BaseUrlsMap[] {
-  const preferredUrls = getEndpointPreference()
+  const preference = getEndpointPreference()
 
-  if (!Array.isArray(preferredUrls)) {
-    return [preferredUrls]
+  if (!Array.isArray(preference)) {
+    return [preference]
   } else {
-    const res = preferredUrls
+    const res = preference
       .map(strategy => endpoints[strategy] || null)
       .filter((i): i is BaseUrlsMap => !!i)
 
@@ -115,7 +85,7 @@ function getPreferredUrls(endpoints: Partial>):
   }
 }
 
-function getBaseUrlsIterator(endpoints: Partial> = endpointMap): BaseUrlsIterator {
+function getBaseUrlsIterator(endpoints: Partial> = endpointMap): BaseUrlsIterator {
   const _urls = getPreferredUrls(endpoints)
 
   let _counter = 0
@@ -134,5 +104,4 @@ function getBaseUrlsIterator(endpoints: Partial
   }
 }
 
-
-export { urlStrategyRetries, getBaseUrlsIterator, BaseUrlsIterator, UrlStrategy, BaseUrlsMap }
+export { getBaseUrlsIterator, BaseUrlsIterator, UrlStrategy, DataResidency, BaseUrlsMap }
diff --git a/src/snippet.js b/src/snippet.js
index c883e3c8..f576a016 100644
--- a/src/snippet.js
+++ b/src/snippet.js
@@ -52,7 +52,9 @@
     'restart',
     'gdprForgetMe',
     'disableThirdPartySharing',
-    'initSmartBanner'
+    'initSmartBanner',
+    'showSmartBanner',
+    'hideSmartBanner',
   ],
   function (context, queue, methodName) {
     context[methodName] = function () {