@amplitude/analytics-browser
Version:
Official Amplitude SDK for Web
427 lines • 23.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTopLevelDomain = exports.createTransport = exports.shouldFetchRemoteConfig = exports.createCookieStorage = exports.useBrowserConfig = exports.BrowserConfig = void 0;
var tslib_1 = require("tslib");
var analytics_core_1 = require("@amplitude/analytics-core");
var local_storage_1 = require("./storage/local-storage");
var session_storage_1 = require("./storage/session-storage");
var xhr_1 = require("./transports/xhr");
var send_beacon_1 = require("./transports/send-beacon");
var cookie_migration_1 = require("./cookie-migration");
var constants_1 = require("./constants");
var version_1 = require("./version");
// Exported for testing purposes only. Do not expose to public interface.
var BrowserConfig = /** @class */ (function (_super) {
tslib_1.__extends(BrowserConfig, _super);
function BrowserConfig(apiKey, appVersion, cookieStorage, cookieOptions, defaultTracking, autocapture, deviceId, flushIntervalMillis, flushMaxRetries, flushQueueSize, identityStorage, ingestionMetadata, instanceName, lastEventId, lastEventTime, loggerProvider, logLevel, minIdLength, offline, optOut, partnerId, plan, serverUrl, serverZone, sessionId, sessionTimeout, storageProvider, trackingOptions, transport, useBatch, fetchRemoteConfig, userId, pageCounter, debugLogsEnabled, networkTrackingOptions, identify, enableDiagnostics, diagnosticsSampleRate, diagnosticsClient, remoteConfig) {
if (cookieStorage === void 0) { cookieStorage = new analytics_core_1.MemoryStorage(); }
if (cookieOptions === void 0) { cookieOptions = {
domain: '',
expiration: 365,
sameSite: 'Lax',
secure: false,
upgrade: true,
}; }
if (flushIntervalMillis === void 0) { flushIntervalMillis = 1000; }
if (flushMaxRetries === void 0) { flushMaxRetries = 5; }
if (flushQueueSize === void 0) { flushQueueSize = 30; }
if (identityStorage === void 0) { identityStorage = constants_1.DEFAULT_IDENTITY_STORAGE; }
if (loggerProvider === void 0) { loggerProvider = new analytics_core_1.Logger(); }
if (logLevel === void 0) { logLevel = analytics_core_1.LogLevel.Warn; }
if (offline === void 0) { offline = false; }
if (optOut === void 0) { optOut = false; }
if (serverUrl === void 0) { serverUrl = ''; }
if (serverZone === void 0) { serverZone = constants_1.DEFAULT_SERVER_ZONE; }
if (sessionTimeout === void 0) { sessionTimeout = 30 * 60 * 1000; }
if (storageProvider === void 0) { storageProvider = new local_storage_1.LocalStorage({ loggerProvider: loggerProvider }); }
if (trackingOptions === void 0) { trackingOptions = {
ipAddress: true,
language: true,
platform: true,
}; }
if (transport === void 0) { transport = 'fetch'; }
if (useBatch === void 0) { useBatch = false; }
if (fetchRemoteConfig === void 0) { fetchRemoteConfig = true; }
if (enableDiagnostics === void 0) { enableDiagnostics = true; }
if (diagnosticsSampleRate === void 0) { diagnosticsSampleRate = 0; }
var _this = this;
var _a;
_this = _super.call(this, { apiKey: apiKey, storageProvider: storageProvider, transportProvider: (0, exports.createTransport)(transport) }) || this;
_this.apiKey = apiKey;
_this.appVersion = appVersion;
_this.cookieOptions = cookieOptions;
_this.defaultTracking = defaultTracking;
_this.autocapture = autocapture;
_this.flushIntervalMillis = flushIntervalMillis;
_this.flushMaxRetries = flushMaxRetries;
_this.flushQueueSize = flushQueueSize;
_this.identityStorage = identityStorage;
_this.ingestionMetadata = ingestionMetadata;
_this.instanceName = instanceName;
_this.loggerProvider = loggerProvider;
_this.logLevel = logLevel;
_this.minIdLength = minIdLength;
_this.offline = offline;
_this.partnerId = partnerId;
_this.plan = plan;
_this.serverUrl = serverUrl;
_this.serverZone = serverZone;
_this.sessionTimeout = sessionTimeout;
_this.storageProvider = storageProvider;
_this.trackingOptions = trackingOptions;
_this.transport = transport;
_this.useBatch = useBatch;
_this.fetchRemoteConfig = fetchRemoteConfig;
_this.networkTrackingOptions = networkTrackingOptions;
_this.identify = identify;
_this.enableDiagnostics = enableDiagnostics;
_this.diagnosticsSampleRate = diagnosticsSampleRate;
_this.diagnosticsClient = diagnosticsClient;
_this.remoteConfig = remoteConfig;
_this.version = version_1.VERSION;
_this._optOut = false;
_this._cookieStorage = cookieStorage;
_this.deviceId = deviceId;
_this.lastEventId = lastEventId;
_this.lastEventTime = lastEventTime;
_this.optOut = optOut;
_this.sessionId = sessionId;
_this.pageCounter = pageCounter;
_this.userId = userId;
_this.debugLogsEnabled = debugLogsEnabled;
_this.loggerProvider.enable(debugLogsEnabled ? analytics_core_1.LogLevel.Debug : _this.logLevel);
_this.networkTrackingOptions = networkTrackingOptions;
_this.identify = identify;
_this.enableDiagnostics = enableDiagnostics;
_this.diagnosticsSampleRate = diagnosticsSampleRate;
_this.diagnosticsClient = diagnosticsClient;
// Note: The canonical logic for determining fetchRemoteConfig is in shouldFetchRemoteConfig().
// This logic is duplicated here to maintain the BrowserConfig constructor contract and ensure
// the config object has the correct fetchRemoteConfig value set on its properties.
// The value passed to this constructor should already be computed via shouldFetchRemoteConfig().
var _fetchRemoteConfig = (_a = remoteConfig === null || remoteConfig === void 0 ? void 0 : remoteConfig.fetchRemoteConfig) !== null && _a !== void 0 ? _a : fetchRemoteConfig;
_this.remoteConfig = _this.remoteConfig || {};
_this.remoteConfig.fetchRemoteConfig = _fetchRemoteConfig;
_this.fetchRemoteConfig = _fetchRemoteConfig;
return _this;
}
Object.defineProperty(BrowserConfig.prototype, "cookieStorage", {
get: function () {
return this._cookieStorage;
},
set: function (cookieStorage) {
if (this._cookieStorage !== cookieStorage) {
this._cookieStorage = cookieStorage;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "deviceId", {
get: function () {
return this._deviceId;
},
set: function (deviceId) {
if (this._deviceId !== deviceId) {
this._deviceId = deviceId;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "userId", {
get: function () {
return this._userId;
},
set: function (userId) {
if (this._userId !== userId) {
this._userId = userId;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "sessionId", {
get: function () {
return this._sessionId;
},
set: function (sessionId) {
if (this._sessionId !== sessionId) {
this._sessionId = sessionId;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "optOut", {
get: function () {
return this._optOut;
},
set: function (optOut) {
if (this._optOut !== optOut) {
this._optOut = optOut;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "lastEventTime", {
get: function () {
return this._lastEventTime;
},
set: function (lastEventTime) {
if (this._lastEventTime !== lastEventTime) {
this._lastEventTime = lastEventTime;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "lastEventId", {
get: function () {
return this._lastEventId;
},
set: function (lastEventId) {
if (this._lastEventId !== lastEventId) {
this._lastEventId = lastEventId;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "pageCounter", {
get: function () {
return this._pageCounter;
},
set: function (pageCounter) {
if (this._pageCounter !== pageCounter) {
this._pageCounter = pageCounter;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BrowserConfig.prototype, "debugLogsEnabled", {
set: function (debugLogsEnabled) {
if (this._debugLogsEnabled !== debugLogsEnabled) {
this._debugLogsEnabled = debugLogsEnabled;
this.updateStorage();
}
},
enumerable: false,
configurable: true
});
BrowserConfig.prototype.updateStorage = function () {
var cache = {
deviceId: this._deviceId,
userId: this._userId,
sessionId: this._sessionId,
optOut: this._optOut,
lastEventTime: this._lastEventTime,
lastEventId: this._lastEventId,
pageCounter: this._pageCounter,
debugLogsEnabled: this._debugLogsEnabled,
cookieDomain: undefined,
};
if (this.cookieStorage instanceof analytics_core_1.CookieStorage) {
cache.cookieDomain = this.cookieStorage.options.domain;
}
void this.cookieStorage.set((0, analytics_core_1.getCookieName)(this.apiKey), cache);
};
return BrowserConfig;
}(analytics_core_1.Config));
exports.BrowserConfig = BrowserConfig;
var useBrowserConfig = function (apiKey, options, amplitudeInstance, diagnosticsClient, earlyConfig) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(void 0, void 0, void 0, function () {
var identityStorage, cookieOptions, _a, _b, cookieConfig, cookieStorage, legacyCookies, previousCookies, queryParams, ampTimestamp, isWithinTimeLimit, deviceId, lastEventId, lastEventTime, optOut, sessionId, userId, trackingOptions, pageCounter, debugLogsEnabled, browserConfig;
var _c;
var _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
return tslib_1.__generator(this, function (_7) {
switch (_7.label) {
case 0:
identityStorage = options.identityStorage || constants_1.DEFAULT_IDENTITY_STORAGE;
_c = {};
if (!(identityStorage !== constants_1.DEFAULT_IDENTITY_STORAGE)) return [3 /*break*/, 1];
_a = '';
return [3 /*break*/, 5];
case 1:
if (!((_e = (_d = options.cookieOptions) === null || _d === void 0 ? void 0 : _d.domain) !== null && _e !== void 0)) return [3 /*break*/, 2];
_b = _e;
return [3 /*break*/, 4];
case 2: return [4 /*yield*/, (0, exports.getTopLevelDomain)()];
case 3:
_b = (_7.sent());
_7.label = 4;
case 4:
_a = _b;
_7.label = 5;
case 5:
cookieOptions = tslib_1.__assign.apply(void 0, [(_c.domain = _a, _c.expiration = 365, _c.sameSite = 'Lax', _c.secure = false, _c.upgrade = true, _c), options.cookieOptions]);
cookieConfig = {
// if more than one cookie with the same key exists,
// look for the cookie that has the domain attribute set to cookieOptions.domain
duplicateResolverFn: function (value) {
var decodedValue = (0, analytics_core_1.decodeCookieValue)(value);
if (!decodedValue) {
return false;
}
var parsed = JSON.parse(decodedValue);
return (0, analytics_core_1.isDomainEqual)(parsed.cookieDomain, cookieOptions.domain);
},
diagnosticsClient: diagnosticsClient,
};
cookieStorage = (0, exports.createCookieStorage)(options.identityStorage, cookieOptions, cookieConfig);
return [4 /*yield*/, (0, cookie_migration_1.parseLegacyCookies)(apiKey, cookieStorage, (_g = (_f = options.cookieOptions) === null || _f === void 0 ? void 0 : _f.upgrade) !== null && _g !== void 0 ? _g : true)];
case 6:
legacyCookies = _7.sent();
return [4 /*yield*/, cookieStorage.get((0, analytics_core_1.getCookieName)(apiKey))];
case 7:
previousCookies = _7.sent();
queryParams = (0, analytics_core_1.getQueryParams)();
ampTimestamp = queryParams.ampTimestamp ? Number(queryParams.ampTimestamp) : undefined;
isWithinTimeLimit = ampTimestamp ? Date.now() < ampTimestamp : true;
deviceId = (_m = (_l = (_k = (_h = options.deviceId) !== null && _h !== void 0 ? _h : (isWithinTimeLimit ? (_j = queryParams.ampDeviceId) !== null && _j !== void 0 ? _j : queryParams.deviceId : undefined)) !== null && _k !== void 0 ? _k : previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.deviceId) !== null && _l !== void 0 ? _l : legacyCookies.deviceId) !== null && _m !== void 0 ? _m : (0, analytics_core_1.UUID)();
lastEventId = (_o = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.lastEventId) !== null && _o !== void 0 ? _o : legacyCookies.lastEventId;
lastEventTime = (_p = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.lastEventTime) !== null && _p !== void 0 ? _p : legacyCookies.lastEventTime;
optOut = (_r = (_q = options.optOut) !== null && _q !== void 0 ? _q : previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.optOut) !== null && _r !== void 0 ? _r : legacyCookies.optOut;
sessionId = (_s = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.sessionId) !== null && _s !== void 0 ? _s : legacyCookies.sessionId;
userId = (_u = (_t = options.userId) !== null && _t !== void 0 ? _t : previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.userId) !== null && _u !== void 0 ? _u : legacyCookies.userId;
amplitudeInstance.previousSessionDeviceId = (_v = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.deviceId) !== null && _v !== void 0 ? _v : legacyCookies.deviceId;
amplitudeInstance.previousSessionUserId = (_w = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.userId) !== null && _w !== void 0 ? _w : legacyCookies.userId;
trackingOptions = {
ipAddress: (_y = (_x = options.trackingOptions) === null || _x === void 0 ? void 0 : _x.ipAddress) !== null && _y !== void 0 ? _y : true,
language: (_0 = (_z = options.trackingOptions) === null || _z === void 0 ? void 0 : _z.language) !== null && _0 !== void 0 ? _0 : true,
platform: (_2 = (_1 = options.trackingOptions) === null || _1 === void 0 ? void 0 : _1.platform) !== null && _2 !== void 0 ? _2 : true,
};
pageCounter = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.pageCounter;
debugLogsEnabled = previousCookies === null || previousCookies === void 0 ? void 0 : previousCookies.debugLogsEnabled;
// Override default tracking options if autocapture is set
if (options.autocapture !== undefined) {
options.defaultTracking = options.autocapture;
}
browserConfig = new BrowserConfig(apiKey, options.appVersion, cookieStorage, cookieOptions, options.defaultTracking, options.autocapture, deviceId, options.flushIntervalMillis, options.flushMaxRetries, options.flushQueueSize, identityStorage, options.ingestionMetadata, options.instanceName, lastEventId, lastEventTime,
// Use earlyConfig.loggerProvider to ensure consistent logger across DiagnosticsClient/RemoteConfigClient/BrowserConfig
(_3 = earlyConfig === null || earlyConfig === void 0 ? void 0 : earlyConfig.loggerProvider) !== null && _3 !== void 0 ? _3 : options.loggerProvider, options.logLevel, options.minIdLength, options.offline, optOut, options.partnerId, options.plan, options.serverUrl,
// Use earlyConfig.serverZone to ensure consistent serverZone
(_4 = earlyConfig === null || earlyConfig === void 0 ? void 0 : earlyConfig.serverZone) !== null && _4 !== void 0 ? _4 : options.serverZone, sessionId, options.sessionTimeout, options.storageProvider, trackingOptions, options.transport, options.useBatch, options.fetchRemoteConfig, userId, pageCounter, debugLogsEnabled, options.networkTrackingOptions, options.identify,
// Use earlyConfig values (already has remote config applied), otherwise fall back to options
(_5 = earlyConfig === null || earlyConfig === void 0 ? void 0 : earlyConfig.enableDiagnostics) !== null && _5 !== void 0 ? _5 : options.enableDiagnostics, (_6 = earlyConfig === null || earlyConfig === void 0 ? void 0 : earlyConfig.diagnosticsSampleRate) !== null && _6 !== void 0 ? _6 : amplitudeInstance._diagnosticsSampleRate, diagnosticsClient, options.remoteConfig);
return [4 /*yield*/, browserConfig.storageProvider.isEnabled()];
case 8:
if (!(_7.sent())) {
browserConfig.loggerProvider.warn("Storage provider ".concat(browserConfig.storageProvider.constructor.name, " is not enabled. Falling back to MemoryStorage."));
browserConfig.storageProvider = new analytics_core_1.MemoryStorage();
}
return [2 /*return*/, browserConfig];
}
});
});
};
exports.useBrowserConfig = useBrowserConfig;
var createCookieStorage = function (identityStorage, cookieOptions, cookieConfig) {
if (identityStorage === void 0) { identityStorage = constants_1.DEFAULT_IDENTITY_STORAGE; }
if (cookieOptions === void 0) { cookieOptions = {}; }
switch (identityStorage) {
case 'localStorage':
return new local_storage_1.LocalStorage();
case 'sessionStorage':
return new session_storage_1.SessionStorage();
case 'none':
return new analytics_core_1.MemoryStorage();
case 'cookie':
default:
return new analytics_core_1.CookieStorage(tslib_1.__assign(tslib_1.__assign({}, cookieOptions), { expirationDays: cookieOptions.expiration }), cookieConfig);
}
};
exports.createCookieStorage = createCookieStorage;
/**
* Determines whether to fetch remote config based on options.
* Extracted to allow early determination before useBrowserConfig is called.
*/
var shouldFetchRemoteConfig = function (options) {
var _a, _b;
if (options === void 0) { options = {}; }
if (((_a = options.remoteConfig) === null || _a === void 0 ? void 0 : _a.fetchRemoteConfig) === true) {
// set to true if remoteConfig explicitly set to true
return true;
}
else if (((_b = options.remoteConfig) === null || _b === void 0 ? void 0 : _b.fetchRemoteConfig) === false || options.fetchRemoteConfig === false) {
// set to false if either are set to false explicitly
return false;
}
else {
// default to true if both undefined
return true;
}
};
exports.shouldFetchRemoteConfig = shouldFetchRemoteConfig;
var createTransport = function (transport) {
var type = typeof transport === 'object' ? transport.type : transport;
var headers = typeof transport === 'object' ? transport.headers : undefined;
if (type === 'xhr') {
return new xhr_1.XHRTransport(headers);
}
if (type === 'beacon') {
// SendBeacon does not support custom headers
return new send_beacon_1.SendBeaconTransport();
}
return new analytics_core_1.FetchTransport(headers);
};
exports.createTransport = createTransport;
var getTopLevelDomain = function (url) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
var host, parts, levels, cookieKeyUniqueId, storageKey, i, i, domain, options, storage, value;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new analytics_core_1.CookieStorage().isEnabled()];
case 1:
if (!(_a.sent()) ||
(!url && (typeof location === 'undefined' || !location.hostname))) {
return [2 /*return*/, ''];
}
host = url !== null && url !== void 0 ? url : location.hostname;
parts = host.split('.');
levels = [];
cookieKeyUniqueId = (0, analytics_core_1.UUID)();
storageKey = "AMP_TLDTEST_".concat(cookieKeyUniqueId.substring(0, 8));
for (i = parts.length - 2; i >= 0; --i) {
levels.push(parts.slice(i).join('.'));
}
i = 0;
_a.label = 2;
case 2:
if (!(i < levels.length)) return [3 /*break*/, 7];
domain = levels[i];
options = {
domain: '.' + domain,
expirationDays: 0.003, // expire in ~5 minutes
};
storage = new analytics_core_1.CookieStorage(options);
return [4 /*yield*/, storage.set(storageKey, 1)];
case 3:
_a.sent();
return [4 /*yield*/, storage.get(storageKey)];
case 4:
value = _a.sent();
if (!value) return [3 /*break*/, 6];
return [4 /*yield*/, storage.remove(storageKey)];
case 5:
_a.sent();
return [2 /*return*/, '.' + domain];
case 6:
i++;
return [3 /*break*/, 2];
case 7: return [2 /*return*/, ''];
}
});
}); };
exports.getTopLevelDomain = getTopLevelDomain;
//# sourceMappingURL=config.js.map