/* eslint camelcase: "off" */
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import { each, extend, include, stripEmptyProperties } from './utils';
import { cookieStore, localPlusCookieStore, localStore, memoryStore, sessionStore } from './storage';
import { ENABLED_FEATURE_FLAGS, EVENT_TIMERS_KEY, INITIAL_CAMPAIGN_PARAMS, INITIAL_PERSON_INFO, INITIAL_REFERRER_INFO, PERSISTENCE_RESERVED_PROPERTIES, } from './constants';
import { isEmptyObject, isObject, isUndefined } from './utils/type-utils';
import { Info } from './utils/event-utils';
import { logger } from './utils/logger';
import { stripLeadingDollar } from './utils/string-utils';
var CASE_INSENSITIVE_PERSISTENCE_TYPES = [
'cookie',
'localstorage',
'localstorage+cookie',
'sessionstorage',
'memory',
];
var parseName = function (config) {
var token = '';
if (config['token']) {
token = config['token'].replace(/\+/g, 'PL').replace(/\//g, 'SL').replace(/=/g, 'EQ');
}
if (config['persistence_name']) {
return 'ph_' + config['persistence_name'];
}
else {
return 'ph_' + token + '_posthog';
}
};
/**
* PostHog Persistence Object
* @constructor
*/
var PostHogPersistence = /** @class */ (function () {
function PostHogPersistence(config) {
this.config = config;
this.props = {};
this.campaign_params_saved = false;
this.name = parseName(config);
this.storage = this.buildStorage(config);
this.load();
if (config.debug) {
logger.info('Persistence loaded', config['persistence'], __assign({}, this.props));
}
this.update_config(config, config);
this.save();
}
PostHogPersistence.prototype.buildStorage = function (config) {
if (CASE_INSENSITIVE_PERSISTENCE_TYPES.indexOf(config['persistence'].toLowerCase()) === -1) {
logger.critical('Unknown persistence type ' + config['persistence'] + '; falling back to localStorage+cookie');
config['persistence'] = 'localStorage+cookie';
}
var store;
// We handle storage type in a case-insensitive way for backwards compatibility
var storage_type = config['persistence'].toLowerCase();
if (storage_type === 'localstorage' && localStore.is_supported()) {
store = localStore;
}
else if (storage_type === 'localstorage+cookie' && localPlusCookieStore.is_supported()) {
store = localPlusCookieStore;
}
else if (storage_type === 'sessionstorage' && sessionStore.is_supported()) {
store = sessionStore;
}
else if (storage_type === 'memory') {
store = memoryStore;
}
else if (storage_type === 'cookie') {
store = cookieStore;
}
else if (localPlusCookieStore.is_supported()) {
// selected storage type wasn't supported, fallback to 'localstorage+cookie' if possible
store = localPlusCookieStore;
}
else {
store = cookieStore;
}
return store;
};
PostHogPersistence.prototype.properties = function () {
var p = {};
// Filter out reserved properties
each(this.props, function (v, k) {
if (k === ENABLED_FEATURE_FLAGS && isObject(v)) {
var keys = Object.keys(v);
for (var i = 0; i < keys.length; i++) {
p["$feature/".concat(keys[i])] = v[keys[i]];
}
}
else if (!include(PERSISTENCE_RESERVED_PROPERTIES, k)) {
p[k] = v;
}
});
return p;
};
PostHogPersistence.prototype.load = function () {
if (this.disabled) {
return;
}
var entry = this.storage.parse(this.name);
if (entry) {
this.props = extend({}, entry);
}
};
/**
* NOTE: Saving frequently causes issues with Recordings and Consent Management Platform (CMP) tools which
* observe cookie changes, and modify their UI, often causing infinite loops.
* As such callers of this should ideally check that the data has changed beforehand
*/
PostHogPersistence.prototype.save = function () {
if (this.disabled) {
return;
}
this.storage.set(this.name, this.props, this.expire_days, this.cross_subdomain, this.secure, this.config.debug);
};
PostHogPersistence.prototype.remove = function () {
// remove both domain and subdomain cookies
this.storage.remove(this.name, false);
this.storage.remove(this.name, true);
};
// removes the storage entry and deletes all loaded data
// forced name for tests
PostHogPersistence.prototype.clear = function () {
this.remove();
this.props = {};
};
/**
* @param {Object} props
* @param {*=} default_value
* @param {number=} days
*/
PostHogPersistence.prototype.register_once = function (props, default_value, days) {
var _this = this;
if (isObject(props)) {
if (isUndefined(default_value)) {
default_value = 'None';
}
this.expire_days = isUndefined(days) ? this.default_expiry : days;
var hasChanges_1 = false;
each(props, function (val, prop) {
if (!_this.props.hasOwnProperty(prop) || _this.props[prop] === default_value) {
_this.props[prop] = val;
hasChanges_1 = true;
}
});
if (hasChanges_1) {
this.save();
return true;
}
}
return false;
};
/**
* @param {Object} props
* @param {number=} days
*/
PostHogPersistence.prototype.register = function (props, days) {
var _this = this;
if (isObject(props)) {
this.expire_days = isUndefined(days) ? this.default_expiry : days;
var hasChanges_2 = false;
each(props, function (val, prop) {
if (props.hasOwnProperty(prop) && _this.props[prop] !== val) {
_this.props[prop] = val;
hasChanges_2 = true;
}
});
if (hasChanges_2) {
this.save();
return true;
}
}
return false;
};
PostHogPersistence.prototype.unregister = function (prop) {
if (prop in this.props) {
delete this.props[prop];
this.save();
}
};
PostHogPersistence.prototype.update_campaign_params = function () {
if (!this.campaign_params_saved) {
var campaignParams = Info.campaignParams({
customTrackedParams: this.config.custom_campaign_params,
maskPersonalDataProperties: this.config.mask_personal_data_properties,
customPersonalDataProperties: this.config.custom_personal_data_properties,
});
// only save campaign params if there were any
if (!isEmptyObject(stripEmptyProperties(campaignParams))) {
this.register(campaignParams);
}
this.campaign_params_saved = true;
}
};
PostHogPersistence.prototype.update_search_keyword = function () {
this.register(Info.searchInfo());
};
PostHogPersistence.prototype.update_referrer_info = function () {
this.register_once(Info.referrerInfo(), undefined);
};
PostHogPersistence.prototype.set_initial_person_info = function () {
var _a;
if (this.props[INITIAL_CAMPAIGN_PARAMS] || this.props[INITIAL_REFERRER_INFO]) {
// the user has initial properties stored the previous way, don't save them again
return;
}
this.register_once((_a = {},
_a[INITIAL_PERSON_INFO] = Info.personInfo({
maskPersonalDataProperties: this.config.mask_personal_data_properties,
customPersonalDataProperties: this.config.custom_personal_data_properties,
}),
_a), undefined);
};
PostHogPersistence.prototype.get_referrer_info = function () {
return stripEmptyProperties({
$referrer: this['props']['$referrer'],
$referring_domain: this['props']['$referring_domain'],
});
};
PostHogPersistence.prototype.get_initial_props = function () {
var _this = this;
var p = {};
// this section isn't written to anymore, but we should keep reading from it for backwards compatibility
// for a while
each([INITIAL_REFERRER_INFO, INITIAL_CAMPAIGN_PARAMS], function (key) {
var initialReferrerInfo = _this.props[key];
if (initialReferrerInfo) {
each(initialReferrerInfo, function (v, k) {
p['$initial_' + stripLeadingDollar(k)] = v;
});
}
});
var initialPersonInfo = this.props[INITIAL_PERSON_INFO];
if (initialPersonInfo) {
var initialPersonProps = Info.initialPersonPropsFromInfo(initialPersonInfo);
extend(p, initialPersonProps);
}
return p;
};
// safely fills the passed in object with stored properties,
// does not override any properties defined in both
// returns the passed in object
PostHogPersistence.prototype.safe_merge = function (props) {
each(this.props, function (val, prop) {
if (!(prop in props)) {
props[prop] = val;
}
});
return props;
};
PostHogPersistence.prototype.update_config = function (config, oldConfig) {
this.default_expiry = this.expire_days = config['cookie_expiration'];
this.set_disabled(config['disable_persistence']);
this.set_cross_subdomain(config['cross_subdomain_cookie']);
this.set_secure(config['secure_cookie']);
if (config.persistence !== oldConfig.persistence) {
// If the persistence type has changed, we need to migrate the data.
var newStore = this.buildStorage(config);
var props = this.props;
// clear the old store
this.clear();
this.storage = newStore;
this.props = props;
this.save();
}
};
PostHogPersistence.prototype.set_disabled = function (disabled) {
this.disabled = disabled;
if (this.disabled) {
this.remove();
}
else {
this.save();
}
};
PostHogPersistence.prototype.set_cross_subdomain = function (cross_subdomain) {
if (cross_subdomain !== this.cross_subdomain) {
this.cross_subdomain = cross_subdomain;
this.remove();
this.save();
}
};
PostHogPersistence.prototype.get_cross_subdomain = function () {
return !!this.cross_subdomain;
};
PostHogPersistence.prototype.set_secure = function (secure) {
if (secure !== this.secure) {
this.secure = secure;
this.remove();
this.save();
}
};
PostHogPersistence.prototype.set_event_timer = function (event_name, timestamp) {
var timers = this.props[EVENT_TIMERS_KEY] || {};
timers[event_name] = timestamp;
this.props[EVENT_TIMERS_KEY] = timers;
this.save();
};
PostHogPersistence.prototype.remove_event_timer = function (event_name) {
var timers = this.props[EVENT_TIMERS_KEY] || {};
var timestamp = timers[event_name];
if (!isUndefined(timestamp)) {
delete this.props[EVENT_TIMERS_KEY][event_name];
this.save();
}
return timestamp;
};
PostHogPersistence.prototype.get_property = function (prop) {
return this.props[prop];
};
PostHogPersistence.prototype.set_property = function (prop, to) {
this.props[prop] = to;
this.save();
};
return PostHogPersistence;
}());
export { PostHogPersistence };
//# sourceMappingURL=posthog-persistence.js.map