amplitude-js
Version:
Javascript library for Amplitude Analytics
1,648 lines (1,387 loc) • 191 kB
JavaScript
var amplitude = (function () {
'use strict';
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
_defineProperty(target, key, source[key]);
});
}
return target;
}
var Constants = {
DEFAULT_INSTANCE: '$default_instance',
API_VERSION: 2,
MAX_STRING_LENGTH: 4096,
MAX_PROPERTY_KEYS: 1000,
IDENTIFY_EVENT: '$identify',
GROUP_IDENTIFY_EVENT: '$groupidentify',
// localStorageKeys
LAST_EVENT_ID: 'amplitude_lastEventId',
LAST_EVENT_TIME: 'amplitude_lastEventTime',
LAST_IDENTIFY_ID: 'amplitude_lastIdentifyId',
LAST_SEQUENCE_NUMBER: 'amplitude_lastSequenceNumber',
SESSION_ID: 'amplitude_sessionId',
// Used in cookie as well
DEVICE_ID: 'amplitude_deviceId',
OPT_OUT: 'amplitude_optOut',
USER_ID: 'amplitude_userId',
COOKIE_TEST_PREFIX: 'amp_cookie_test',
COOKIE_PREFIX: "amp",
// revenue keys
REVENUE_EVENT: 'revenue_amount',
REVENUE_PRODUCT_ID: '$productId',
REVENUE_QUANTITY: '$quantity',
REVENUE_PRICE: '$price',
REVENUE_REVENUE_TYPE: '$revenueType',
AMP_DEVICE_ID_PARAM: 'amp_device_id',
// url param
REFERRER: 'referrer',
// UTM Params
UTM_SOURCE: 'utm_source',
UTM_MEDIUM: 'utm_medium',
UTM_CAMPAIGN: 'utm_campaign',
UTM_TERM: 'utm_term',
UTM_CONTENT: 'utm_content',
ATTRIBUTION_EVENT: '[Amplitude] Attribution Captured'
};
/* jshint bitwise: false */
/*
* UTF-8 encoder/decoder
* http://www.webtoolkit.info/
*/
var UTF8 = {
encode: function encode(s) {
var utftext = '';
for (var n = 0; n < s.length; n++) {
var c = s.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode(c >> 6 | 192);
utftext += String.fromCharCode(c & 63 | 128);
} else {
utftext += String.fromCharCode(c >> 12 | 224);
utftext += String.fromCharCode(c >> 6 & 63 | 128);
utftext += String.fromCharCode(c & 63 | 128);
}
}
return utftext;
},
decode: function decode(utftext) {
var s = '';
var i = 0;
var c = 0,
c1 = 0,
c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
s += String.fromCharCode(c);
i++;
} else if (c > 191 && c < 224) {
c1 = utftext.charCodeAt(i + 1);
s += String.fromCharCode((c & 31) << 6 | c1 & 63);
i += 2;
} else {
c1 = utftext.charCodeAt(i + 1);
c2 = utftext.charCodeAt(i + 2);
s += String.fromCharCode((c & 15) << 12 | (c1 & 63) << 6 | c2 & 63);
i += 3;
}
}
return s;
}
};
/* jshint bitwise: false */
/*
* Base64 encoder/decoder
* http://www.webtoolkit.info/
*/
var Base64 = {
_keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode: function encode(input) {
try {
if (window.btoa && window.atob) {
return window.btoa(unescape(encodeURIComponent(input)));
}
} catch (e) {//log(e);
}
return Base64._encode(input);
},
_encode: function _encode(input) {
var output = '';
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = UTF8.encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = (chr1 & 3) << 4 | chr2 >> 4;
enc3 = (chr2 & 15) << 2 | chr3 >> 6;
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) + Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);
}
return output;
},
decode: function decode(input) {
try {
if (window.btoa && window.atob) {
return decodeURIComponent(escape(window.atob(input)));
}
} catch (e) {//log(e);
}
return Base64._decode(input);
},
_decode: function _decode(input) {
var output = '';
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
while (i < input.length) {
enc1 = Base64._keyStr.indexOf(input.charAt(i++));
enc2 = Base64._keyStr.indexOf(input.charAt(i++));
enc3 = Base64._keyStr.indexOf(input.charAt(i++));
enc4 = Base64._keyStr.indexOf(input.charAt(i++));
chr1 = enc1 << 2 | enc2 >> 4;
chr2 = (enc2 & 15) << 4 | enc3 >> 2;
chr3 = (enc3 & 3) << 6 | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 !== 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 !== 64) {
output = output + String.fromCharCode(chr3);
}
}
output = UTF8.decode(output);
return output;
}
};
/**
* toString ref.
* @private
*/
var toString = Object.prototype.toString;
/**
* Return the type of `val`.
* @private
* @param {Mixed} val
* @return {String}
* @api public
*/
function type (val) {
switch (toString.call(val)) {
case '[object Date]':
return 'date';
case '[object RegExp]':
return 'regexp';
case '[object Arguments]':
return 'arguments';
case '[object Array]':
return 'array';
case '[object Error]':
return 'error';
}
if (val === null) {
return 'null';
}
if (val === undefined) {
return 'undefined';
}
if (val !== val) {
return 'nan';
}
if (val && val.nodeType === 1) {
return 'element';
}
if (typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function' && Buffer.isBuffer(val)) {
return 'buffer';
}
val = val.valueOf ? val.valueOf() : Object.prototype.valueOf.apply(val);
return _typeof(val);
}
var logLevels = {
DISABLE: 0,
ERROR: 1,
WARN: 2,
INFO: 3
};
var logLevel = logLevels.WARN;
var setLogLevel = function setLogLevel(logLevelName) {
if (logLevels.hasOwnProperty(logLevelName)) {
logLevel = logLevels[logLevelName];
}
};
var getLogLevel = function getLogLevel() {
return logLevel;
};
var log = {
error: function error(s) {
if (logLevel >= logLevels.ERROR) {
_log(s);
}
},
warn: function warn(s) {
if (logLevel >= logLevels.WARN) {
_log(s);
}
},
info: function info(s) {
if (logLevel >= logLevels.INFO) {
_log(s);
}
}
};
var _log = function _log(s) {
try {
console.log('[Amplitude] ' + s);
} catch (e) {// console logging not available
}
};
var isEmptyString = function isEmptyString(str) {
return !str || str.length === 0;
};
var sessionStorageEnabled = function sessionStorageEnabled() {
try {
if (window.sessionStorage) {
return true;
}
} catch (e) {} // sessionStorage disabled
return false;
}; // truncate string values in event and user properties so that request size does not get too large
var truncate = function truncate(value) {
if (type(value) === 'array') {
for (var i = 0; i < value.length; i++) {
value[i] = truncate(value[i]);
}
} else if (type(value) === 'object') {
for (var key in value) {
if (value.hasOwnProperty(key)) {
value[key] = truncate(value[key]);
}
}
} else {
value = _truncateValue(value);
}
return value;
};
var _truncateValue = function _truncateValue(value) {
if (type(value) === 'string') {
return value.length > Constants.MAX_STRING_LENGTH ? value.substring(0, Constants.MAX_STRING_LENGTH) : value;
}
return value;
};
var validateInput = function validateInput(input, name, expectedType) {
if (type(input) !== expectedType) {
log.error('Invalid ' + name + ' input type. Expected ' + expectedType + ' but received ' + type(input));
return false;
}
return true;
}; // do some basic sanitization and type checking, also catch property dicts with more than 1000 key/value pairs
var validateProperties = function validateProperties(properties) {
var propsType = type(properties);
if (propsType !== 'object') {
log.error('Error: invalid properties format. Expecting Javascript object, received ' + propsType + ', ignoring');
return {};
}
if (Object.keys(properties).length > Constants.MAX_PROPERTY_KEYS) {
log.error('Error: too many properties (more than 1000), ignoring');
return {};
}
var copy = {}; // create a copy with all of the valid properties
for (var property in properties) {
if (!properties.hasOwnProperty(property)) {
continue;
} // validate key
var key = property;
var keyType = type(key);
if (keyType !== 'string') {
key = String(key);
log.warn('WARNING: Non-string property key, received type ' + keyType + ', coercing to string "' + key + '"');
} // validate value
var value = validatePropertyValue(key, properties[property]);
if (value === null) {
continue;
}
copy[key] = value;
}
return copy;
};
var invalidValueTypes = ['nan', 'function', 'arguments', 'regexp', 'element'];
var validatePropertyValue = function validatePropertyValue(key, value) {
var valueType = type(value);
if (invalidValueTypes.indexOf(valueType) !== -1) {
log.warn('WARNING: Property key "' + key + '" with invalid value type ' + valueType + ', ignoring');
value = null;
} else if (valueType === 'undefined') {
value = null;
} else if (valueType === 'error') {
value = String(value);
log.warn('WARNING: Property key "' + key + '" with value type error, coercing to ' + value);
} else if (valueType === 'array') {
// check for nested arrays or objects
var arrayCopy = [];
for (var i = 0; i < value.length; i++) {
var element = value[i];
var elemType = type(element);
if (elemType === 'array') {
log.warn('WARNING: Cannot have ' + elemType + ' nested in an array property value, skipping');
continue;
} else if (elemType === 'object') {
arrayCopy.push(validateProperties(element));
} else {
arrayCopy.push(validatePropertyValue(key, element));
}
}
value = arrayCopy;
} else if (valueType === 'object') {
value = validateProperties(value);
}
return value;
};
var validateGroups = function validateGroups(groups) {
var groupsType = type(groups);
if (groupsType !== 'object') {
log.error('Error: invalid groups format. Expecting Javascript object, received ' + groupsType + ', ignoring');
return {};
}
var copy = {}; // create a copy with all of the valid properties
for (var group in groups) {
if (!groups.hasOwnProperty(group)) {
continue;
} // validate key
var key = group;
var keyType = type(key);
if (keyType !== 'string') {
key = String(key);
log.warn('WARNING: Non-string groupType, received type ' + keyType + ', coercing to string "' + key + '"');
} // validate value
var value = validateGroupName(key, groups[group]);
if (value === null) {
continue;
}
copy[key] = value;
}
return copy;
};
var validateGroupName = function validateGroupName(key, groupName) {
var groupNameType = type(groupName);
if (groupNameType === 'string') {
return groupName;
}
if (groupNameType === 'date' || groupNameType === 'number' || groupNameType === 'boolean') {
groupName = String(groupName);
log.warn('WARNING: Non-string groupName, received type ' + groupNameType + ', coercing to string "' + groupName + '"');
return groupName;
}
if (groupNameType === 'array') {
// check for nested arrays or objects
var arrayCopy = [];
for (var i = 0; i < groupName.length; i++) {
var element = groupName[i];
var elemType = type(element);
if (elemType === 'array' || elemType === 'object') {
log.warn('WARNING: Skipping nested ' + elemType + ' in array groupName');
continue;
} else if (elemType === 'string') {
arrayCopy.push(element);
} else if (elemType === 'date' || elemType === 'number' || elemType === 'boolean') {
element = String(element);
log.warn('WARNING: Non-string groupName, received type ' + elemType + ', coercing to string "' + element + '"');
arrayCopy.push(element);
}
}
return arrayCopy;
}
log.warn('WARNING: Non-string groupName, received type ' + groupNameType + '. Please use strings or array of strings for groupName');
}; // parses the value of a url param (for example ?gclid=1234&...)
var getQueryParam = function getQueryParam(name, query) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
var results = regex.exec(query);
return results === null ? undefined : decodeURIComponent(results[1].replace(/\+/g, " "));
};
var utils = {
setLogLevel: setLogLevel,
getLogLevel: getLogLevel,
logLevels: logLevels,
log: log,
isEmptyString: isEmptyString,
getQueryParam: getQueryParam,
sessionStorageEnabled: sessionStorageEnabled,
truncate: truncate,
validateGroups: validateGroups,
validateInput: validateInput,
validateProperties: validateProperties
};
var getLocation = function getLocation() {
return window.location;
};
// A URL safe variation on the the list of Base64 characters
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
var base64Id = function base64Id() {
var str = '';
for (var i = 0; i < 22; ++i) {
str += base64Chars.charAt(Math.floor(Math.random() * 64));
}
return str;
};
var get = function get(name) {
try {
var ca = document.cookie.split(';');
var value = null;
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(name) === 0) {
value = c.substring(name.length, c.length);
break;
}
}
return value;
} catch (e) {
return null;
}
};
var set = function set(name, value, opts) {
var expires = value !== null ? opts.expirationDays : -1;
if (expires) {
var date = new Date();
date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);
expires = date;
}
var str = name + '=' + value;
if (expires) {
str += '; expires=' + expires.toUTCString();
}
str += '; path=/';
if (opts.domain) {
str += '; domain=' + opts.domain;
}
if (opts.secure) {
str += '; Secure';
}
if (opts.sameSite) {
str += '; SameSite=' + opts.sameSite;
}
document.cookie = str;
}; // test that cookies are enabled - navigator.cookiesEnabled yields false positives in IE, need to test directly
var areCookiesEnabled = function areCookiesEnabled() {
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var uid = String(new Date());
try {
var cookieName = Constants.COOKIE_TEST_PREFIX + base64Id();
set(cookieName, uid, opts);
var _areCookiesEnabled = get(cookieName + '=') === uid;
set(cookieName, null, opts);
return _areCookiesEnabled;
} catch (e) {}
return false;
};
var baseCookie = {
set: set,
get: get,
areCookiesEnabled: areCookiesEnabled
};
var getHost = function getHost(url) {
var a = document.createElement('a');
a.href = url;
return a.hostname || location.hostname;
};
var topDomain = function topDomain(url) {
var host = getHost(url);
var parts = host.split('.');
var levels = [];
var cname = '_tldtest_' + base64Id();
for (var i = parts.length - 2; i >= 0; --i) {
levels.push(parts.slice(i).join('.'));
}
for (var _i = 0; _i < levels.length; ++_i) {
var domain = levels[_i];
var opts = {
domain: '.' + domain
};
baseCookie.set(cname, 1, opts);
if (baseCookie.get(cname)) {
baseCookie.set(cname, null, opts);
return domain;
}
}
return '';
};
/*
* Cookie data
*/
var _options = {
expirationDays: undefined,
domain: undefined
};
var reset = function reset() {
_options = {
expirationDays: undefined,
domain: undefined
};
};
var options = function options(opts) {
if (arguments.length === 0) {
return _options;
}
opts = opts || {};
_options.expirationDays = opts.expirationDays;
_options.secure = opts.secure;
_options.sameSite = opts.sameSite;
var domain = !utils.isEmptyString(opts.domain) ? opts.domain : '.' + topDomain(getLocation().href);
var token = Math.random();
_options.domain = domain;
set$1('amplitude_test', token);
var stored = get$1('amplitude_test');
if (!stored || stored !== token) {
domain = null;
}
remove('amplitude_test');
_options.domain = domain;
return _options;
};
var _domainSpecific = function _domainSpecific(name) {
// differentiate between cookies on different domains
var suffix = '';
if (_options.domain) {
suffix = _options.domain.charAt(0) === '.' ? _options.domain.substring(1) : _options.domain;
}
return name + suffix;
};
var get$1 = function get(name) {
var nameEq = _domainSpecific(name) + '=';
var value = baseCookie.get(nameEq);
try {
if (value) {
return JSON.parse(Base64.decode(value));
}
} catch (e) {
return null;
}
return null;
};
var set$1 = function set(name, value) {
try {
baseCookie.set(_domainSpecific(name), Base64.encode(JSON.stringify(value)), _options);
return true;
} catch (e) {
return false;
}
};
var setRaw = function setRaw(name, value) {
try {
baseCookie.set(_domainSpecific(name), value, _options);
return true;
} catch (e) {
return false;
}
};
var getRaw = function getRaw(name) {
var nameEq = _domainSpecific(name) + '=';
return baseCookie.get(nameEq);
};
var remove = function remove(name) {
try {
baseCookie.set(_domainSpecific(name), null, _options);
return true;
} catch (e) {
return false;
}
};
var Cookie = {
reset: reset,
options: options,
get: get$1,
set: set$1,
remove: remove,
setRaw: setRaw,
getRaw: getRaw
};
/* jshint -W020, unused: false, noempty: false, boss: true */
/*
* Implement localStorage to support Firefox 2-3 and IE 5-7
*/
var localStorage; // jshint ignore:line
{
// test that Window.localStorage is available and works
var windowLocalStorageAvailable = function windowLocalStorageAvailable() {
var uid = new Date();
var result;
try {
window.localStorage.setItem(uid, uid);
result = window.localStorage.getItem(uid) === String(uid);
window.localStorage.removeItem(uid);
return result;
} catch (e) {// localStorage not available
}
return false;
};
if (windowLocalStorageAvailable()) {
localStorage = window.localStorage;
} else if (window.globalStorage) {
// Firefox 2-3 use globalStorage
// See https://developer.mozilla.org/en/dom/storage#globalStorage
try {
localStorage = window.globalStorage[window.location.hostname];
} catch (e) {// Something bad happened...
}
} else if (typeof document !== 'undefined') {
// IE 5-7 use userData
// See http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
var div = document.createElement('div'),
attrKey = 'localStorage';
div.style.display = 'none';
document.getElementsByTagName('head')[0].appendChild(div);
if (div.addBehavior) {
div.addBehavior('#default#userdata');
localStorage = {
length: 0,
setItem: function setItem(k, v) {
div.load(attrKey);
if (!div.getAttribute(k)) {
this.length++;
}
div.setAttribute(k, v);
div.save(attrKey);
},
getItem: function getItem(k) {
div.load(attrKey);
return div.getAttribute(k);
},
removeItem: function removeItem(k) {
div.load(attrKey);
if (div.getAttribute(k)) {
this.length--;
}
div.removeAttribute(k);
div.save(attrKey);
},
clear: function clear() {
div.load(attrKey);
var i = 0;
var attr;
while (attr = div.XMLDocument.documentElement.attributes[i++]) {
div.removeAttribute(attr.name);
}
div.save(attrKey);
this.length = 0;
},
key: function key(k) {
div.load(attrKey);
return div.XMLDocument.documentElement.attributes[k];
}
};
div.load(attrKey);
localStorage.length = div.XMLDocument.documentElement.attributes.length;
}
}
if (!localStorage) {
localStorage = {
length: 0,
setItem: function setItem(k, v) {},
getItem: function getItem(k) {},
removeItem: function removeItem(k) {},
clear: function clear() {},
key: function key(k) {}
};
}
}
var localStorage$1 = localStorage;
/* jshint -W020, unused: false, noempty: false, boss: true */
var cookieStorage = function cookieStorage() {
this.storage = null;
};
cookieStorage.prototype.getStorage = function () {
if (this.storage !== null) {
return this.storage;
}
if (baseCookie.areCookiesEnabled()) {
this.storage = Cookie;
} else {
// if cookies disabled, fallback to localstorage
// note: localstorage does not persist across subdomains
var keyPrefix = 'amp_cookiestore_';
this.storage = {
_options: {
expirationDays: undefined,
domain: undefined,
secure: false
},
reset: function reset() {
this._options = {
expirationDays: undefined,
domain: undefined,
secure: false
};
},
options: function options(opts) {
if (arguments.length === 0) {
return this._options;
}
opts = opts || {};
this._options.expirationDays = opts.expirationDays || this._options.expirationDays; // localStorage is specific to subdomains
this._options.domain = opts.domain || this._options.domain || window && window.location && window.location.hostname;
return this._options.secure = opts.secure || false;
},
get: function get(name) {
try {
return JSON.parse(localStorage$1.getItem(keyPrefix + name));
} catch (e) {}
return null;
},
set: function set(name, value) {
try {
localStorage$1.setItem(keyPrefix + name, JSON.stringify(value));
return true;
} catch (e) {}
return false;
},
remove: function remove(name) {
try {
localStorage$1.removeItem(keyPrefix + name);
} catch (e) {
return false;
}
}
};
}
return this.storage;
};
/**
* MetadataStorage involves SDK data persistance
* storage priority: cookies -> localStorage -> in memory
* if in localStorage, unable track users between subdomains
* if in memory, then memory can't be shared between different tabs
*/
var MetadataStorage =
/*#__PURE__*/
function () {
function MetadataStorage(_ref) {
var storageKey = _ref.storageKey,
disableCookies = _ref.disableCookies,
domain = _ref.domain,
secure = _ref.secure,
sameSite = _ref.sameSite,
expirationDays = _ref.expirationDays;
_classCallCheck(this, MetadataStorage);
this.storageKey = storageKey;
this.domain = domain;
this.secure = secure;
this.sameSite = sameSite;
this.expirationDays = expirationDays;
this.cookieDomain = '';
{
var writableTopDomain = topDomain(getLocation().href);
this.cookieDomain = domain || (writableTopDomain ? '.' + writableTopDomain : null);
}
this.disableCookieStorage = disableCookies || !baseCookie.areCookiesEnabled({
domain: this.cookieDomain,
secure: this.secure,
sameSite: this.sameSite,
expirationDays: this.expirationDays
});
}
_createClass(MetadataStorage, [{
key: "getCookieStorageKey",
value: function getCookieStorageKey() {
if (!this.domain) {
return this.storageKey;
}
var suffix = this.domain.charAt(0) === '.' ? this.domain.substring(1) : this.domain;
return "".concat(this.storageKey).concat(suffix ? "_".concat(suffix) : '');
}
/*
* Data is saved as delimited values rather than JSO to minimize cookie space
* Should not change order of the items
*/
}, {
key: "save",
value: function save(_ref2) {
var deviceId = _ref2.deviceId,
userId = _ref2.userId,
optOut = _ref2.optOut,
sessionId = _ref2.sessionId,
lastEventTime = _ref2.lastEventTime,
eventId = _ref2.eventId,
identifyId = _ref2.identifyId,
sequenceNumber = _ref2.sequenceNumber;
var value = [deviceId, Base64.encode(userId || ''), // used to convert not unicode to alphanumeric since cookies only use alphanumeric
optOut ? '1' : '', sessionId ? sessionId.toString(32) : '0', // generated when instantiated, timestamp (but re-uses session id in cookie if not expired) @TODO clients may want custom session id
lastEventTime ? lastEventTime.toString(32) : '0', // last time an event was set
eventId ? eventId.toString(32) : '0', identifyId ? identifyId.toString(32) : '0', sequenceNumber ? sequenceNumber.toString(32) : '0'].join('.');
if (this.disableCookieStorage) {
localStorage$1.setItem(this.storageKey, value);
} else {
baseCookie.set(this.getCookieStorageKey(), value, {
domain: this.cookieDomain,
secure: this.secure,
sameSite: this.sameSite,
expirationDays: this.expirationDays
});
}
}
}, {
key: "load",
value: function load() {
var str;
if (!this.disableCookieStorage) {
str = baseCookie.get(this.getCookieStorageKey() + '=');
}
if (!str) {
str = localStorage$1.getItem(this.storageKey);
}
if (!str) {
return null;
}
var values = str.split('.');
var userId = null;
if (values[1]) {
try {
userId = Base64.decode(values[1]);
} catch (e) {
userId = null;
}
}
return {
deviceId: values[0],
userId: userId,
optOut: values[2] === '1',
sessionId: parseInt(values[3], 32),
lastEventTime: parseInt(values[4], 32),
eventId: parseInt(values[5], 32),
identifyId: parseInt(values[6], 32),
sequenceNumber: parseInt(values[7], 32)
};
}
}]);
return MetadataStorage;
}();
var getUtmData = function getUtmData(rawCookie, query) {
// Translate the utmz cookie format into url query string format.
var cookie = rawCookie ? '?' + rawCookie.split('.').slice(-1)[0].replace(/\|/g, '&') : '';
var fetchParam = function fetchParam(queryName, query, cookieName, cookie) {
return utils.getQueryParam(queryName, query) || utils.getQueryParam(cookieName, cookie);
};
var utmSource = fetchParam(Constants.UTM_SOURCE, query, 'utmcsr', cookie);
var utmMedium = fetchParam(Constants.UTM_MEDIUM, query, 'utmcmd', cookie);
var utmCampaign = fetchParam(Constants.UTM_CAMPAIGN, query, 'utmccn', cookie);
var utmTerm = fetchParam(Constants.UTM_TERM, query, 'utmctr', cookie);
var utmContent = fetchParam(Constants.UTM_CONTENT, query, 'utmcct', cookie);
var utmData = {};
var addIfNotNull = function addIfNotNull(key, value) {
if (!utils.isEmptyString(value)) {
utmData[key] = value;
}
};
addIfNotNull(Constants.UTM_SOURCE, utmSource);
addIfNotNull(Constants.UTM_MEDIUM, utmMedium);
addIfNotNull(Constants.UTM_CAMPAIGN, utmCampaign);
addIfNotNull(Constants.UTM_TERM, utmTerm);
addIfNotNull(Constants.UTM_CONTENT, utmContent);
return utmData;
};
/*
* Wrapper for a user properties JSON object that supports operations.
* Note: if a user property is used in multiple operations on the same Identify object,
* only the first operation will be saved, and the rest will be ignored.
*/
var AMP_OP_ADD = '$add';
var AMP_OP_APPEND = '$append';
var AMP_OP_CLEAR_ALL = '$clearAll';
var AMP_OP_PREPEND = '$prepend';
var AMP_OP_SET = '$set';
var AMP_OP_SET_ONCE = '$setOnce';
var AMP_OP_UNSET = '$unset';
/**
* Identify API - instance constructor. Identify objects are a wrapper for user property operations.
* Each method adds a user property operation to the Identify object, and returns the same Identify object,
* allowing you to chain multiple method calls together.
* Note: if the same user property is used in multiple operations on a single Identify object,
* only the first operation on that property will be saved, and the rest will be ignored.
* @constructor Identify
* @public
* @example var identify = new amplitude.Identify();
*/
var Identify = function Identify() {
this.userPropertiesOperations = {};
this.properties = []; // keep track of keys that have been added
};
/**
* Increment a user property by a given value (can also be negative to decrement).
* If the user property does not have a value set yet, it will be initialized to 0 before being incremented.
* @public
* @param {string} property - The user property key.
* @param {number|string} value - The amount by which to increment the user property. Allows numbers as strings (ex: '123').
* @return {Identify} Returns the same Identify object, allowing you to chain multiple method calls together.
* @example var identify = new amplitude.Identify().add('karma', 1).add('friends', 1);
* amplitude.identify(identify); // send the Identify call
*/
Identify.prototype.add = function (property, value) {
if (type(value) === 'number' || type(value) === 'string') {
this._addOperation(AMP_OP_ADD, property, value);
} else {
utils.log.error('Unsupported type for value: ' + type(value) + ', expecting number or string');
}
return this;
};
/**
* Append a value or values to a user property.
* If the user property does not have a value set yet,
* it will be initialized to an empty list before the new values are appended.
* If the user property has an existing value and it is not a list,
* the existing value will be converted into a list with the new values appended.
* @public
* @param {string} property - The user property key.
* @param {number|string|list|object} value - A value or values to append.
* Values can be numbers, strings, lists, or object (key:value dict will be flattened).
* @return {Identify} Returns the same Identify object, allowing you to chain multiple method calls together.
* @example var identify = new amplitude.Identify().append('ab-tests', 'new-user-tests');
* identify.append('some_list', [1, 2, 3, 4, 'values']);
* amplitude.identify(identify); // send the Identify call
*/
Identify.prototype.append = function (property, value) {
this._addOperation(AMP_OP_APPEND, property, value);
return this;
};
/**
* Clear all user properties for the current user.
* SDK user should instead call amplitude.clearUserProperties() instead of using this.
* $clearAll needs to be sent on its own Identify object. If there are already other operations, then don't add $clearAll.
* If $clearAll already in an Identify object, don't allow other operations to be added.
* @private
*/
Identify.prototype.clearAll = function () {
if (Object.keys(this.userPropertiesOperations).length > 0) {
if (!this.userPropertiesOperations.hasOwnProperty(AMP_OP_CLEAR_ALL)) {
utils.log.error('Need to send $clearAll on its own Identify object without any other operations, skipping $clearAll');
}
return this;
}
this.userPropertiesOperations[AMP_OP_CLEAR_ALL] = '-';
return this;
};
/**
* Prepend a value or values to a user property.
* Prepend means inserting the value or values at the front of a list.
* If the user property does not have a value set yet,
* it will be initialized to an empty list before the new values are prepended.
* If the user property has an existing value and it is not a list,
* the existing value will be converted into a list with the new values prepended.
* @public
* @param {string} property - The user property key.
* @param {number|string|list|object} value - A value or values to prepend.
* Values can be numbers, strings, lists, or object (key:value dict will be flattened).
* @return {Identify} Returns the same Identify object, allowing you to chain multiple method calls together.
* @example var identify = new amplitude.Identify().prepend('ab-tests', 'new-user-tests');
* identify.prepend('some_list', [1, 2, 3, 4, 'values']);
* amplitude.identify(identify); // send the Identify call
*/
Identify.prototype.prepend = function (property, value) {
this._addOperation(AMP_OP_PREPEND, property, value);
return this;
};
/**
* Sets the value of a given user property. If a value already exists, it will be overwriten with the new value.
* @public
* @param {string} property - The user property key.
* @param {number|string|list|boolean|object} value - A value or values to set.
* Values can be numbers, strings, lists, or object (key:value dict will be flattened).
* @return {Identify} Returns the same Identify object, allowing you to chain multiple method calls together.
* @example var identify = new amplitude.Identify().set('user_type', 'beta');
* identify.set('name', {'first': 'John', 'last': 'Doe'}); // dict is flattened and becomes name.first: John, name.last: Doe
* amplitude.identify(identify); // send the Identify call
*/
Identify.prototype.set = function (property, value) {
this._addOperation(AMP_OP_SET, property, value);
return this;
};
/**
* Sets the value of a given user property only once. Subsequent setOnce operations on that user property will be ignored;
* however, that user property can still be modified through any of the other operations.
* Useful for capturing properties such as 'initial_signup_date', 'initial_referrer', etc.
* @public
* @param {string} property - The user property key.
* @param {number|string|list|boolean|object} value - A value or values to set once.
* Values can be numbers, strings, lists, or object (key:value dict will be flattened).
* @return {Identify} Returns the same Identify object, allowing you to chain multiple method calls together.
* @example var identify = new amplitude.Identify().setOnce('sign_up_date', '2016-04-01');
* amplitude.identify(identify); // send the Identify call
*/
Identify.prototype.setOnce = function (property, value) {
this._addOperation(AMP_OP_SET_ONCE, property, value);
return this;
};
/**
* Unset and remove a user property. This user property will no longer show up in a user's profile.
* @public
* @param {string} property - The user property key.
* @return {Identify} Returns the same Identify object, allowing you to chain multiple method calls together.
* @example var identify = new amplitude.Identify().unset('user_type').unset('age');
* amplitude.identify(identify); // send the Identify call
*/
Identify.prototype.unset = function (property) {
this._addOperation(AMP_OP_UNSET, property, '-');
return this;
};
/**
* Helper function that adds operation to the Identify's object
* Handle's filtering of duplicate user property keys, and filtering for clearAll.
* @private
*/
Identify.prototype._addOperation = function (operation, property, value) {
// check that the identify doesn't already contain a clearAll
if (this.userPropertiesOperations.hasOwnProperty(AMP_OP_CLEAR_ALL)) {
utils.log.error('This identify already contains a $clearAll operation, skipping operation ' + operation);
return;
} // check that property wasn't already used in this Identify
if (this.properties.indexOf(property) !== -1) {
utils.log.error('User property "' + property + '" already used in this identify, skipping operation ' + operation);
return;
}
if (!this.userPropertiesOperations.hasOwnProperty(operation)) {
this.userPropertiesOperations[operation] = {};
}
this.userPropertiesOperations[operation][property] = value;
this.properties.push(property);
};
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var md5 = createCommonjsModule(function (module) {
(function ($) {
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safeAdd (x, y) {
var lsw = (x & 0xffff) + (y & 0xffff);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xffff)
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bitRotateLeft (num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5cmn (q, a, b, x, s, t) {
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
}
function md5ff (a, b, c, d, x, s, t) {
return md5cmn((b & c) | (~b & d), a, b, x, s, t)
}
function md5gg (a, b, c, d, x, s, t) {
return md5cmn((b & d) | (c & ~d), a, b, x, s, t)
}
function md5hh (a, b, c, d, x, s, t) {
return md5cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5ii (a, b, c, d, x, s, t) {
return md5cmn(c ^ (b | ~d), a, b, x, s, t)
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function binlMD5 (x, len) {
/* append padding */
x[len >> 5] |= 0x80 << (len % 32);
x[((len + 64) >>> 9 << 4) + 14] = len;
var i;
var olda;
var oldb;
var oldc;
var oldd;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (i = 0; i < x.length; i += 16) {
olda = a;
oldb = b;
oldc = c;
oldd = d;
a = md5ff(a, b, c, d, x[i], 7, -680876936);
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5gg(b, c, d, a, x[i], 20, -373897302);
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5hh(d, a, b, c, x[i], 11, -358537222);
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5ii(a, b, c, d, x[i], 6, -198630844);
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safeAdd(a, olda);
b = safeAdd(b, oldb);
c = safeAdd(c, oldc);
d = safeAdd(d, oldd);
}
return [a, b, c, d]
}
/*
* Convert an array of little-endian words to a string
*/
function binl2rstr (input) {
var i;
var output = '';
var length32 = input.length * 32;
for (i = 0; i < length32; i += 8) {
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff);
}
return output
}
/*
* Convert a raw string to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
function rstr2binl (input) {
var i;
var output = [];
output[(input.length >> 2) - 1] = undefined;
for (i = 0; i < output.length; i += 1) {
output[i] = 0;
}
var length8 = input.length * 8;
for (i = 0; i < length8; i += 8) {
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32);
}
return output
}
/*
* Calculate the MD5 of a raw string
*/
function rstrMD5 (s) {
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8))
}
/*
* Calculate the HMAC-MD5, of a key and some data (raw strings)
*/
function rstrHMACMD5 (key, data) {
var i;
var bkey = rstr2binl(key);
var ipad = [];
var opad = [];
var hash;
ipad[15] = opad[15] = undefined;
if (bkey.length > 16) {
bkey = binlMD5(bkey, key.length * 8);
}
for (i = 0; i < 16; i += 1) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5c5c5c5c;
}
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
return binl2rstr(binlMD5(opad.concat(hash), 512 + 128))
}
/*
* Convert a raw string to a hex string
*/
function rstr2hex (input) {
var hexTab = '0123456789abcdef';
var output = '';
var x;
var i;
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i);
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f);
}
return output
}
/*
* Encode a string as utf-8
*/
function str2rstrUTF8 (input) {
return unescape(encodeURIComponent(input))
}
/*
* Take string arguments and return either raw or hex encoded strings
*/
function rawMD5 (s) {
return rstrMD5(str2rstrUTF8(s))
}
function hexMD5 (s) {
return rstr2hex(rawMD5(s))
}
function rawHMACMD5 (k, d) {
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d))
}
function hexHMACMD5 (k, d) {
return rstr2hex(rawHMACMD5(k, d))
}
function md5 (string, key, raw) {
if (!key) {
if (!raw) {
return hexMD5(string)
}
return rawMD5(string)
}
if (!raw) {
return hexHMACMD5(key, string)
}
return rawHMACMD5(key, string)
}
if (module.exports) {
module.exports = md5;
} else {
$.md5 = md5;
}
})(commonjsGlobal);
});
var strictUriEncode = function (str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
});
};
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(tes