@amplitude/session-replay-browser 1.47.0-sr-trc-debug-log.2 → 1.47.0-sr-trc-debug-log.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/diagnostics.d.ts +2 -0
- package/lib/cjs/diagnostics.d.ts.map +1 -1
- package/lib/cjs/diagnostics.js +4 -1
- package/lib/cjs/diagnostics.js.map +1 -1
- package/lib/cjs/plugins/url-tracking-plugin.d.ts +7 -0
- package/lib/cjs/plugins/url-tracking-plugin.d.ts.map +1 -1
- package/lib/cjs/plugins/url-tracking-plugin.js +5 -3
- package/lib/cjs/plugins/url-tracking-plugin.js.map +1 -1
- package/lib/cjs/session-replay.d.ts +1 -0
- package/lib/cjs/session-replay.d.ts.map +1 -1
- package/lib/cjs/session-replay.js +15 -0
- package/lib/cjs/session-replay.js.map +1 -1
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/cjs/version.js.map +1 -1
- package/lib/esm/diagnostics.d.ts +2 -0
- package/lib/esm/diagnostics.d.ts.map +1 -1
- package/lib/esm/diagnostics.js +4 -1
- package/lib/esm/diagnostics.js.map +1 -1
- package/lib/esm/plugins/url-tracking-plugin.d.ts +7 -0
- package/lib/esm/plugins/url-tracking-plugin.d.ts.map +1 -1
- package/lib/esm/plugins/url-tracking-plugin.js +5 -3
- package/lib/esm/plugins/url-tracking-plugin.js.map +1 -1
- package/lib/esm/session-replay.d.ts +1 -0
- package/lib/esm/session-replay.d.ts.map +1 -1
- package/lib/esm/session-replay.js +15 -0
- package/lib/esm/session-replay.js.map +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/esm/version.js.map +1 -1
- package/lib/scripts/index-min.js +1 -1
- package/lib/scripts/index-min.js.gz +0 -0
- package/lib/scripts/index-min.js.map +1 -1
- package/lib/scripts/session-replay-browser-min.js +1 -1
- package/lib/scripts/session-replay-browser-min.js.gz +0 -0
- package/lib/scripts/session-replay-browser-min.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-min.js","sources":["../../../analytics-core/lib/esm/types/event/event.js","../../../analytics-core/lib/esm/types/constants.js","../../../analytics-core/lib/esm/types/status.js","../../../analytics-core/lib/esm/global-scope.js","../../../analytics-core/lib/esm/types/loglevel.js","../../../analytics-core/lib/esm/utils/uuid.js","../../../analytics-core/lib/esm/utils/return-wrapper.js","../../../analytics-core/lib/esm/logger.js","../../../analytics-core/lib/esm/config.js","../../../analytics-core/lib/esm/utils/debug.js","../../../../node_modules/.pnpm/@amplitude+analytics-connector@1.6.4/node_modules/@amplitude/analytics-connector/dist/analytics-connector.esm.js","../../../analytics-core/lib/esm/types/server-zone.js","../../../analytics-core/lib/esm/utils/sampling.js","../../../analytics-core/lib/esm/diagnostics/diagnostics-storage.js","../../../analytics-core/lib/esm/diagnostics/uncaught-sdk-errors.js","../../../analytics-core/lib/esm/diagnostics/diagnostics-client.js","../../../analytics-core/lib/esm/transports/base.js","../../../analytics-core/lib/esm/utils/status-code.js","../../../analytics-core/lib/esm/transports/fetch.js","../../../analytics-core/lib/esm/remote-config/remote-config-localstorage.js","../../../analytics-core/lib/esm/remote-config/remote-config.js","../../../analytics-core/lib/esm/messenger/constants.js","../../../analytics-core/lib/esm/messenger/base-window-messenger.js","../../../analytics-core/lib/esm/messenger/utils.js","../../../analytics-core/lib/esm/messenger/background-capture.js","../../../src/constants.ts","../../../src/logger.ts","../../../src/config/types.ts","../../../src/utils/server-url.ts","../../../src/helpers.ts","../../../src/utils/get-input-type.ts","../../../src/config/local-config.ts","../../../../node_modules/.pnpm/@amplitude+rrweb-types@2.0.0-alpha.40/node_modules/@amplitude/rrweb-types/dist/rrweb-types.js","../../../src/diagnostics.ts","../../../src/config/joined-config.ts","../../../src/events/merge-mutation-events.ts","../../../src/events/event-compressor.ts","../../../src/messages.ts","../../../src/version.ts","../../../src/track-destination.ts","../../../src/utils/gzip.ts","../../../src/events/base-events-store.ts","../../../src/utils/is-abort-error.ts","../../../src/events/events-idb-store.ts","../../../src/events/events-memory-store.ts","../../../src/events/events-manager.ts","../../../src/events/multi-manager.ts","../../../src/libs/finder.ts","../../../src/hooks/click.ts","../../../src/utils/rrweb.ts","../../../src/beacon-transport.ts","../../../src/hooks/scroll.ts","../../../src/identifiers.ts","../../../src/replay-start-time-store.ts","../../../src/targeting/targeting-idb-store.ts","../../../src/sampling.ts","../../../src/plugins/url-tracking-plugin.ts","../../../src/cross-origin-iframes.ts","../../../src/session-replay.ts","../../../src/targeting/targeting-manager.ts","../../../analytics-core/lib/esm/analytics-connector.js","../../../src/session-replay-factory.ts","../../../src/index.ts"],"sourcesContent":["export var IdentifyOperation;\n(function (IdentifyOperation) {\n // Base Operations to set values\n IdentifyOperation[\"SET\"] = \"$set\";\n IdentifyOperation[\"SET_ONCE\"] = \"$setOnce\";\n // Operations around modifying existing values\n IdentifyOperation[\"ADD\"] = \"$add\";\n IdentifyOperation[\"APPEND\"] = \"$append\";\n IdentifyOperation[\"PREPEND\"] = \"$prepend\";\n IdentifyOperation[\"REMOVE\"] = \"$remove\";\n // Operations around appending values *if* they aren't present\n IdentifyOperation[\"PREINSERT\"] = \"$preInsert\";\n IdentifyOperation[\"POSTINSERT\"] = \"$postInsert\";\n // Operations around removing properties/values\n IdentifyOperation[\"UNSET\"] = \"$unset\";\n IdentifyOperation[\"CLEAR_ALL\"] = \"$clearAll\";\n})(IdentifyOperation || (IdentifyOperation = {}));\n/**\n * Strings that have special meaning when used as an event's type\n * and have different specifications.\n */\nexport var SpecialEventType;\n(function (SpecialEventType) {\n SpecialEventType[\"IDENTIFY\"] = \"$identify\";\n SpecialEventType[\"GROUP_IDENTIFY\"] = \"$groupidentify\";\n SpecialEventType[\"REVENUE\"] = \"revenue_amount\";\n})(SpecialEventType || (SpecialEventType = {}));\n//# sourceMappingURL=event.js.map","export var UNSET_VALUE = '-';\nexport var AMPLITUDE_PREFIX = 'AMP';\nexport var STORAGE_PREFIX = \"\".concat(AMPLITUDE_PREFIX, \"_unsent\");\nexport var DEFAULT_INSTANCE_NAME = '$default_instance';\nexport var AMPLITUDE_SERVER_URL = 'https://api2.amplitude.com/2/httpapi';\nexport var EU_AMPLITUDE_SERVER_URL = 'https://api.eu.amplitude.com/2/httpapi';\nexport var AMPLITUDE_BATCH_SERVER_URL = 'https://api2.amplitude.com/batch';\nexport var EU_AMPLITUDE_BATCH_SERVER_URL = 'https://api.eu.amplitude.com/batch';\n// Campaign constants\nexport var UTM_CAMPAIGN = 'utm_campaign';\nexport var UTM_CONTENT = 'utm_content';\nexport var UTM_ID = 'utm_id';\nexport var UTM_MEDIUM = 'utm_medium';\nexport var UTM_SOURCE = 'utm_source';\nexport var UTM_TERM = 'utm_term';\nexport var DCLID = 'dclid';\nexport var FBCLID = 'fbclid';\nexport var GBRAID = 'gbraid';\nexport var GCLID = 'gclid';\nexport var KO_CLICK_ID = 'ko_click_id';\nexport var LI_FAT_ID = 'li_fat_id';\nexport var MSCLKID = 'msclkid';\nexport var RDT_CID = 'rdt_cid';\nexport var TTCLID = 'ttclid';\nexport var TWCLID = 'twclid';\nexport var WBRAID = 'wbraid';\nexport var EMPTY_VALUE = 'EMPTY';\nexport var BASE_CAMPAIGN = {\n utm_campaign: undefined,\n utm_content: undefined,\n utm_id: undefined,\n utm_medium: undefined,\n utm_source: undefined,\n utm_term: undefined,\n referrer: undefined,\n referring_domain: undefined,\n dclid: undefined,\n gbraid: undefined,\n gclid: undefined,\n fbclid: undefined,\n ko_click_id: undefined,\n li_fat_id: undefined,\n msclkid: undefined,\n rdt_cid: undefined,\n ttclid: undefined,\n twclid: undefined,\n wbraid: undefined,\n};\nexport var MKTG = 'MKTG';\n// list of Network headers that are safe to capture\nexport var SAFE_HEADERS = [\n 'access-control-allow-origin',\n 'access-control-allow-credentials',\n 'access-control-expose-headers',\n 'access-control-max-age',\n 'access-control-allow-methods',\n 'access-control-allow-headers',\n 'accept-patch',\n 'accept-ranges',\n 'age',\n 'allow',\n 'alt-svc',\n 'cache-control',\n 'connection',\n 'content-disposition',\n 'content-encoding',\n 'content-language',\n 'content-length',\n 'content-location',\n 'content-md5',\n 'content-range',\n 'content-type',\n 'date',\n 'delta-base',\n 'etag',\n 'expires',\n 'im',\n 'last-modified',\n 'link',\n 'location',\n 'permanent',\n 'p3p',\n 'pragma',\n 'proxy-authenticate',\n 'public-key-pins',\n 'retry-after',\n 'server',\n 'status',\n 'strict-transport-security',\n 'trailer',\n 'transfer-encoding',\n 'tk',\n 'upgrade',\n 'vary',\n 'via',\n 'warning',\n 'www-authenticate',\n 'x-b3-traceid',\n 'x-frame-options',\n];\n// list of Network headers to never capture\nexport var FORBIDDEN_HEADERS = ['authorization', 'cookie', 'set-cookie'];\n//# sourceMappingURL=constants.js.map","/** The status of an event. */\nexport var Status;\n(function (Status) {\n /** The status could not be determined. */\n Status[\"Unknown\"] = \"unknown\";\n /** The event was skipped due to configuration or callbacks. */\n Status[\"Skipped\"] = \"skipped\";\n /** The event was sent successfully. */\n Status[\"Success\"] = \"success\";\n /** A user or device in the payload is currently rate limited and should try again later. */\n Status[\"RateLimit\"] = \"rate_limit\";\n /** The sent payload was too large to be processed. */\n Status[\"PayloadTooLarge\"] = \"payload_too_large\";\n /** The event could not be processed. */\n Status[\"Invalid\"] = \"invalid\";\n /** A server-side error ocurred during submission. */\n Status[\"Failed\"] = \"failed\";\n /** a server or client side error occuring when a request takes too long and is cancelled */\n Status[\"Timeout\"] = \"Timeout\";\n /** NodeJS runtime environment error.. E.g. disconnected from network */\n Status[\"SystemError\"] = \"SystemError\";\n})(Status || (Status = {}));\n//# sourceMappingURL=status.js.map","/* eslint-disable no-restricted-globals */\n/* Only file allowed to access to globalThis, window, self */\nexport var getGlobalScope = function () {\n // This should only be used for integrations with Amplitude that are not running in a browser environment\n // We need to specify the name of the global variable as a string to prevent it from being minified\n var ampIntegrationContextName = 'ampIntegrationContext';\n if (typeof globalThis !== 'undefined' && typeof globalThis[ampIntegrationContextName] !== 'undefined') {\n return globalThis[ampIntegrationContextName];\n }\n if (typeof globalThis !== 'undefined') {\n return globalThis;\n }\n if (typeof window !== 'undefined') {\n return window;\n }\n if (typeof self !== 'undefined') {\n return self;\n }\n if (typeof global !== 'undefined') {\n return global;\n }\n return undefined;\n};\n//# sourceMappingURL=global-scope.js.map","export var LogLevel;\n(function (LogLevel) {\n LogLevel[LogLevel[\"None\"] = 0] = \"None\";\n LogLevel[LogLevel[\"Error\"] = 1] = \"Error\";\n LogLevel[LogLevel[\"Warn\"] = 2] = \"Warn\";\n LogLevel[LogLevel[\"Verbose\"] = 3] = \"Verbose\";\n LogLevel[LogLevel[\"Debug\"] = 4] = \"Debug\";\n})(LogLevel || (LogLevel = {}));\n//# sourceMappingURL=loglevel.js.map","/**\n * Source: [jed's gist's comment]{@link https://gist.github.com/jed/982883?permalink_comment_id=3223002#gistcomment-3223002}.\n * Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,\n * where each x is replaced with a random hexadecimal digit from 0 to f, and\n * y is replaced with a random hexadecimal digit from 8 to b.\n * Used to generate UUIDs for deviceIds.\n * @private\n */\nimport { __read, __spreadArray } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nvar legacyUUID = function (a) {\n return a // if the placeholder was passed, return\n ? // a random number from 0 to 15\n (a ^ // unless b is 8,\n ((Math.random() * // in which case\n 16) >> // a random number from\n (a / 4))) // 8 to 11\n .toString(16) // in hexadecimal\n : // or otherwise a concatenated string:\n (String(1e7) + // 10000000 +\n String(-1e3) + // -1000 +\n String(-4e3) + // -4000 +\n String(-8e3) + // -80000000 +\n String(-1e11)) // -100000000000,\n .replace(\n // replacing\n /[018]/g, // zeroes, ones, and eights with\n UUID);\n};\nvar hex = __spreadArray([], __read(Array(256).keys()), false).map(function (index) { return index.toString(16).padStart(2, '0'); });\nexport var UUID = function (a) {\n var _a;\n var globalScope = getGlobalScope();\n /* istanbul ignore next */\n if (!((_a = globalScope === null || globalScope === void 0 ? void 0 : globalScope.crypto) === null || _a === void 0 ? void 0 : _a.getRandomValues)) {\n // Fallback to legacy UUID generation if crypto is not available\n return legacyUUID(a);\n }\n var r = globalScope.crypto.getRandomValues(new Uint8Array(16));\n r[6] = (r[6] & 0x0f) | 0x40;\n r[8] = (r[8] & 0x3f) | 0x80;\n return __spreadArray([], __read(r.entries()), false).map(function (_a) {\n var _b = __read(_a, 2), index = _b[0], int = _b[1];\n return ([4, 6, 8, 10].includes(index) ? \"-\".concat(hex[int]) : hex[int]);\n }).join('');\n};\n//# sourceMappingURL=uuid.js.map","export var returnWrapper = function (awaitable) { return ({\n promise: awaitable || Promise.resolve(),\n}); };\n//# sourceMappingURL=return-wrapper.js.map","import { LogLevel } from './types/loglevel';\nvar PREFIX = 'Amplitude Logger ';\nvar Logger = /** @class */ (function () {\n function Logger() {\n this.logLevel = LogLevel.None;\n }\n Logger.prototype.disable = function () {\n this.logLevel = LogLevel.None;\n };\n Logger.prototype.enable = function (logLevel) {\n if (logLevel === void 0) { logLevel = LogLevel.Warn; }\n this.logLevel = logLevel;\n };\n Logger.prototype.log = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Verbose) {\n return;\n }\n console.log(\"\".concat(PREFIX, \"[Log]: \").concat(args.join(' ')));\n };\n Logger.prototype.warn = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Warn) {\n return;\n }\n console.warn(\"\".concat(PREFIX, \"[Warn]: \").concat(args.join(' ')));\n };\n Logger.prototype.error = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Error) {\n return;\n }\n console.error(\"\".concat(PREFIX, \"[Error]: \").concat(args.join(' ')));\n };\n Logger.prototype.debug = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Debug) {\n return;\n }\n // console.debug output is hidden by default in chrome\n console.log(\"\".concat(PREFIX, \"[Debug]: \").concat(args.join(' ')));\n };\n return Logger;\n}());\nexport { Logger };\n//# sourceMappingURL=logger.js.map","import { AMPLITUDE_SERVER_URL, AMPLITUDE_BATCH_SERVER_URL, EU_AMPLITUDE_SERVER_URL, EU_AMPLITUDE_BATCH_SERVER_URL, DEFAULT_INSTANCE_NAME, } from './types/constants';\nimport { Logger } from './logger';\nimport { LogLevel } from './types/loglevel';\nexport var getDefaultConfig = function () { return ({\n flushMaxRetries: 12,\n flushQueueSize: 200,\n flushIntervalMillis: 10000,\n instanceName: DEFAULT_INSTANCE_NAME,\n logLevel: LogLevel.Warn,\n loggerProvider: new Logger(),\n offline: false,\n optOut: false,\n serverUrl: AMPLITUDE_SERVER_URL,\n serverZone: 'US',\n useBatch: false,\n}); };\nvar Config = /** @class */ (function () {\n function Config(options) {\n var _a, _b, _c, _d;\n this._optOut = false;\n var defaultConfig = getDefaultConfig();\n this.apiKey = options.apiKey;\n this.flushIntervalMillis = (_a = options.flushIntervalMillis) !== null && _a !== void 0 ? _a : defaultConfig.flushIntervalMillis;\n this.flushMaxRetries = options.flushMaxRetries || defaultConfig.flushMaxRetries;\n this.flushQueueSize = options.flushQueueSize || defaultConfig.flushQueueSize;\n this.instanceName = options.instanceName || defaultConfig.instanceName;\n this.loggerProvider = options.loggerProvider || defaultConfig.loggerProvider;\n this.logLevel = (_b = options.logLevel) !== null && _b !== void 0 ? _b : defaultConfig.logLevel;\n this.minIdLength = options.minIdLength;\n this.plan = options.plan;\n this.ingestionMetadata = options.ingestionMetadata;\n this.offline = options.offline !== undefined ? options.offline : defaultConfig.offline;\n this.optOut = (_c = options.optOut) !== null && _c !== void 0 ? _c : defaultConfig.optOut;\n this.serverUrl = options.serverUrl;\n this.serverZone = options.serverZone || defaultConfig.serverZone;\n this.storageProvider = options.storageProvider;\n this.transportProvider = options.transportProvider;\n this.useBatch = (_d = options.useBatch) !== null && _d !== void 0 ? _d : defaultConfig.useBatch;\n this.loggerProvider.enable(this.logLevel);\n var serverConfig = createServerConfig(options.serverUrl, options.serverZone, options.useBatch);\n this.serverZone = serverConfig.serverZone;\n this.serverUrl = serverConfig.serverUrl;\n }\n Object.defineProperty(Config.prototype, \"optOut\", {\n get: function () {\n return this._optOut;\n },\n set: function (optOut) {\n this._optOut = optOut;\n },\n enumerable: false,\n configurable: true\n });\n return Config;\n}());\nexport { Config };\nexport var getServerUrl = function (serverZone, useBatch) {\n if (serverZone === 'EU') {\n return useBatch ? EU_AMPLITUDE_BATCH_SERVER_URL : EU_AMPLITUDE_SERVER_URL;\n }\n return useBatch ? AMPLITUDE_BATCH_SERVER_URL : AMPLITUDE_SERVER_URL;\n};\nexport var createServerConfig = function (serverUrl, serverZone, useBatch) {\n if (serverUrl === void 0) { serverUrl = ''; }\n if (serverZone === void 0) { serverZone = getDefaultConfig().serverZone; }\n if (useBatch === void 0) { useBatch = getDefaultConfig().useBatch; }\n if (serverUrl) {\n return { serverUrl: serverUrl, serverZone: undefined };\n }\n var _serverZone = ['US', 'EU'].includes(serverZone) ? serverZone : getDefaultConfig().serverZone;\n return {\n serverZone: _serverZone,\n serverUrl: getServerUrl(_serverZone, useBatch),\n };\n};\nvar RequestMetadata = /** @class */ (function () {\n function RequestMetadata() {\n this.sdk = {\n metrics: {\n histogram: {},\n },\n };\n }\n RequestMetadata.prototype.recordHistogram = function (key, value) {\n this.sdk.metrics.histogram[key] = value;\n };\n return RequestMetadata;\n}());\nexport { RequestMetadata };\nvar HistogramOptions = /** @class */ (function () {\n function HistogramOptions() {\n }\n return HistogramOptions;\n}());\n//# sourceMappingURL=config.js.map","import { __assign, __values } from \"tslib\";\nimport { LogLevel } from '../types/loglevel';\nexport var getStacktrace = function (ignoreDepth) {\n if (ignoreDepth === void 0) { ignoreDepth = 0; }\n var trace = new Error().stack || '';\n return trace\n .split('\\n')\n .slice(2 + ignoreDepth)\n .map(function (text) { return text.trim(); });\n};\n// This hook makes sure we always get the latest logger and logLevel.\nexport var getClientLogConfig = function (client) { return function () {\n var _a = __assign({}, client.config), logger = _a.loggerProvider, logLevel = _a.logLevel;\n return {\n logger: logger,\n logLevel: logLevel,\n };\n}; };\n// This is a convenient function to get the attribute from object with string path, similar to lodash '#get'.\nexport var getValueByStringPath = function (obj, path) {\n var e_1, _a;\n path = path.replace(/\\[(\\w+)\\]/g, '.$1'); // convert indexes to properties\n path = path.replace(/^\\./, ''); // strip a leading dot\n try {\n for (var _b = __values(path.split('.')), _c = _b.next(); !_c.done; _c = _b.next()) {\n var attr = _c.value;\n if (attr in obj) {\n obj = obj[attr];\n }\n else {\n return;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (_c && !_c.done && (_a = _b.return)) _a.call(_b);\n }\n finally { if (e_1) throw e_1.error; }\n }\n return obj;\n};\nexport var getClientStates = function (client, paths) { return function () {\n var e_2, _a;\n var res = {};\n try {\n for (var paths_1 = __values(paths), paths_1_1 = paths_1.next(); !paths_1_1.done; paths_1_1 = paths_1.next()) {\n var path = paths_1_1.value;\n res[path] = getValueByStringPath(client, path);\n }\n }\n catch (e_2_1) { e_2 = { error: e_2_1 }; }\n finally {\n try {\n if (paths_1_1 && !paths_1_1.done && (_a = paths_1.return)) _a.call(paths_1);\n }\n finally { if (e_2) throw e_2.error; }\n }\n return res;\n}; };\nexport var debugWrapper = function (fn, fnName, getLogConfig, getStates, fnContext) {\n if (fnContext === void 0) { fnContext = null; }\n return function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n var _a = getLogConfig(), logger = _a.logger, logLevel = _a.logLevel;\n // return early if possible to reduce overhead\n if ((logLevel && logLevel < LogLevel.Debug) || !logLevel || !logger) {\n return fn.apply(fnContext, args);\n }\n var debugContext = {\n type: 'invoke public method',\n name: fnName,\n args: args,\n stacktrace: getStacktrace(1),\n time: {\n start: new Date().toISOString(),\n },\n states: {},\n };\n if (getStates && debugContext.states) {\n debugContext.states.before = getStates();\n }\n var result = fn.apply(fnContext, args);\n if (result && result.promise) {\n // if result is a promise, add the callback\n result.promise.then(function () {\n if (getStates && debugContext.states) {\n debugContext.states.after = getStates();\n }\n if (debugContext.time) {\n debugContext.time.end = new Date().toISOString();\n }\n logger.debug(JSON.stringify(debugContext, null, 2));\n });\n }\n else {\n if (getStates && debugContext.states) {\n debugContext.states.after = getStates();\n }\n if (debugContext.time) {\n debugContext.time.end = new Date().toISOString();\n }\n logger.debug(JSON.stringify(debugContext, null, 2));\n }\n return result;\n };\n};\n//# sourceMappingURL=debug.js.map","var ApplicationContextProviderImpl = /** @class */ (function () {\n function ApplicationContextProviderImpl() {\n }\n ApplicationContextProviderImpl.prototype.getApplicationContext = function () {\n return {\n versionName: this.versionName,\n language: getLanguage(),\n platform: 'Web',\n os: undefined,\n deviceModel: undefined,\n };\n };\n return ApplicationContextProviderImpl;\n}());\nvar getLanguage = function () {\n return ((typeof navigator !== 'undefined' &&\n ((navigator.languages && navigator.languages[0]) ||\n navigator.language)) ||\n '');\n};\n\nvar EventBridgeImpl = /** @class */ (function () {\n function EventBridgeImpl() {\n this.queue = [];\n }\n EventBridgeImpl.prototype.logEvent = function (event) {\n if (!this.receiver) {\n if (this.queue.length < 512) {\n this.queue.push(event);\n }\n }\n else {\n this.receiver(event);\n }\n };\n EventBridgeImpl.prototype.setEventReceiver = function (receiver) {\n this.receiver = receiver;\n if (this.queue.length > 0) {\n this.queue.forEach(function (event) {\n receiver(event);\n });\n this.queue = [];\n }\n };\n return EventBridgeImpl;\n}());\n\n/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\nvar __assign = function () {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n };\n return __assign.apply(this, arguments);\n};\nfunction __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator,\n m = s && o[s],\n i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return {\n value: o && o[i++],\n done: !o\n };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\nfunction __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o),\n r,\n ar = [],\n e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n } catch (error) {\n e = {\n error: error\n };\n } finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n } finally {\n if (e) throw e.error;\n }\n }\n return ar;\n}\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nvar isEqual = function (obj1, obj2) {\n var e_1, _a;\n var primitive = ['string', 'number', 'boolean', 'undefined'];\n var typeA = typeof obj1;\n var typeB = typeof obj2;\n if (typeA !== typeB) {\n return false;\n }\n try {\n for (var primitive_1 = __values(primitive), primitive_1_1 = primitive_1.next(); !primitive_1_1.done; primitive_1_1 = primitive_1.next()) {\n var p = primitive_1_1.value;\n if (p === typeA) {\n return obj1 === obj2;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (primitive_1_1 && !primitive_1_1.done && (_a = primitive_1.return)) _a.call(primitive_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n // check null\n if (obj1 == null && obj2 == null) {\n return true;\n }\n else if (obj1 == null || obj2 == null) {\n return false;\n }\n // if got here - objects\n if (obj1.length !== obj2.length) {\n return false;\n }\n //check if arrays\n var isArrayA = Array.isArray(obj1);\n var isArrayB = Array.isArray(obj2);\n if (isArrayA !== isArrayB) {\n return false;\n }\n if (isArrayA && isArrayB) {\n //arrays\n for (var i = 0; i < obj1.length; i++) {\n if (!isEqual(obj1[i], obj2[i])) {\n return false;\n }\n }\n }\n else {\n //objects\n var sorted1 = Object.keys(obj1).sort();\n var sorted2 = Object.keys(obj2).sort();\n if (!isEqual(sorted1, sorted2)) {\n return false;\n }\n //compare object values\n var result_1 = true;\n Object.keys(obj1).forEach(function (key) {\n if (!isEqual(obj1[key], obj2[key])) {\n result_1 = false;\n }\n });\n return result_1;\n }\n return true;\n};\n\nvar ID_OP_SET = '$set';\nvar ID_OP_UNSET = '$unset';\nvar ID_OP_CLEAR_ALL = '$clearAll';\n// Polyfill for Object.entries\nif (!Object.entries) {\n Object.entries = function (obj) {\n var ownProps = Object.keys(obj);\n var i = ownProps.length;\n var resArray = new Array(i);\n while (i--) {\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n }\n return resArray;\n };\n}\nvar IdentityStoreImpl = /** @class */ (function () {\n function IdentityStoreImpl() {\n this.identity = { userProperties: {} };\n this.listeners = new Set();\n }\n IdentityStoreImpl.prototype.editIdentity = function () {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n var self = this;\n var actingUserProperties = __assign({}, this.identity.userProperties);\n var actingIdentity = __assign(__assign({}, this.identity), { userProperties: actingUserProperties });\n return {\n setUserId: function (userId) {\n actingIdentity.userId = userId;\n return this;\n },\n setDeviceId: function (deviceId) {\n actingIdentity.deviceId = deviceId;\n return this;\n },\n setUserProperties: function (userProperties) {\n actingIdentity.userProperties = userProperties;\n return this;\n },\n setOptOut: function (optOut) {\n actingIdentity.optOut = optOut;\n return this;\n },\n updateUserProperties: function (actions) {\n var e_1, _a, e_2, _b, e_3, _c;\n var actingProperties = actingIdentity.userProperties || {};\n try {\n for (var _d = __values(Object.entries(actions)), _e = _d.next(); !_e.done; _e = _d.next()) {\n var _f = __read(_e.value, 2), action = _f[0], properties = _f[1];\n switch (action) {\n case ID_OP_SET:\n try {\n for (var _g = (e_2 = void 0, __values(Object.entries(properties))), _h = _g.next(); !_h.done; _h = _g.next()) {\n var _j = __read(_h.value, 2), key = _j[0], value = _j[1];\n actingProperties[key] = value;\n }\n }\n catch (e_2_1) { e_2 = { error: e_2_1 }; }\n finally {\n try {\n if (_h && !_h.done && (_b = _g.return)) _b.call(_g);\n }\n finally { if (e_2) throw e_2.error; }\n }\n break;\n case ID_OP_UNSET:\n try {\n for (var _k = (e_3 = void 0, __values(Object.keys(properties))), _l = _k.next(); !_l.done; _l = _k.next()) {\n var key = _l.value;\n delete actingProperties[key];\n }\n }\n catch (e_3_1) { e_3 = { error: e_3_1 }; }\n finally {\n try {\n if (_l && !_l.done && (_c = _k.return)) _c.call(_k);\n }\n finally { if (e_3) throw e_3.error; }\n }\n break;\n case ID_OP_CLEAR_ALL:\n actingProperties = {};\n break;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (_e && !_e.done && (_a = _d.return)) _a.call(_d);\n }\n finally { if (e_1) throw e_1.error; }\n }\n actingIdentity.userProperties = actingProperties;\n return this;\n },\n commit: function () {\n self.setIdentity(actingIdentity);\n return this;\n },\n };\n };\n IdentityStoreImpl.prototype.getIdentity = function () {\n return __assign({}, this.identity);\n };\n IdentityStoreImpl.prototype.setIdentity = function (identity) {\n var originalIdentity = __assign({}, this.identity);\n this.identity = __assign({}, identity);\n if (!isEqual(originalIdentity, this.identity)) {\n this.listeners.forEach(function (listener) {\n listener(identity);\n });\n }\n };\n IdentityStoreImpl.prototype.addIdentityListener = function (listener) {\n this.listeners.add(listener);\n };\n IdentityStoreImpl.prototype.removeIdentityListener = function (listener) {\n this.listeners.delete(listener);\n };\n return IdentityStoreImpl;\n}());\n\nvar safeGlobal = typeof globalThis !== 'undefined'\n ? globalThis\n : typeof global !== 'undefined'\n ? global\n : self;\n\nvar AnalyticsConnector = /** @class */ (function () {\n function AnalyticsConnector() {\n this.identityStore = new IdentityStoreImpl();\n this.eventBridge = new EventBridgeImpl();\n this.applicationContextProvider = new ApplicationContextProviderImpl();\n }\n AnalyticsConnector.getInstance = function (instanceName) {\n if (!safeGlobal['analyticsConnectorInstances']) {\n safeGlobal['analyticsConnectorInstances'] = {};\n }\n if (!safeGlobal['analyticsConnectorInstances'][instanceName]) {\n safeGlobal['analyticsConnectorInstances'][instanceName] =\n new AnalyticsConnector();\n }\n return safeGlobal['analyticsConnectorInstances'][instanceName];\n };\n return AnalyticsConnector;\n}());\n\nexport { AnalyticsConnector };\n","/**\n * @deprecated use ServerZoneType instead\n */\nexport var ServerZone;\n(function (ServerZone) {\n ServerZone[\"US\"] = \"US\";\n ServerZone[\"EU\"] = \"EU\";\n /**\n * Add for session-replay-browser migration from analytics-type v1.x.\n */\n ServerZone[\"STAGING\"] = \"STAGING\";\n})(ServerZone || (ServerZone = {}));\n//# sourceMappingURL=server-zone.js.map","export var generateHashCode = function (str) {\n var hash = 0;\n if (str.length === 0)\n return hash;\n for (var i = 0; i < str.length; i++) {\n var chr = str.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0;\n }\n return hash;\n};\nexport var isTimestampInSample = function (timestamp, sampleRate) {\n var hashNumber = generateHashCode(timestamp.toString());\n var absHash = Math.abs(hashNumber);\n var absHashMultiply = absHash * 31;\n var mod = absHashMultiply % 1000000;\n return mod / 1000000 < sampleRate;\n};\n// TODO(xinyi): replace the temp one in diagnostics client after the fix\n// istanbul ignore next\nexport var isTimestampInSampleTemp = function (timestamp, sampleRate) {\n var hashNumber = generateHashCode(timestamp.toString());\n var absHash = Math.abs(hashNumber);\n var absHashMultiply = absHash * 31;\n var mod = absHashMultiply % 100000;\n return mod / 100000 < sampleRate;\n};\n//# sourceMappingURL=sampling.js.map","import { __awaiter, __generator, __read } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nvar MAX_PERSISTENT_STORAGE_EVENTS_COUNT = 10;\n// Database configuration\nvar DB_VERSION = 1;\n// Table names for different diagnostics types\nexport var TABLE_NAMES = {\n TAGS: 'tags',\n COUNTERS: 'counters',\n HISTOGRAMS: 'histograms',\n EVENTS: 'events',\n INTERNAL: 'internal', // New table for internal storage like flush timestamps\n};\n// Keys for internal storage table\nexport var INTERNAL_KEYS = {\n LAST_FLUSH_TIMESTAMP: 'last_flush_timestamp',\n};\n/**\n * Purpose-specific IndexedDB storage for diagnostics data\n * Provides optimized methods for each type of diagnostics data\n */\nvar DiagnosticsStorage = /** @class */ (function () {\n function DiagnosticsStorage(apiKey, logger) {\n this.dbPromise = null;\n this.logger = logger;\n this.dbName = \"AMP_diagnostics_\".concat(apiKey.substring(0, 10));\n }\n /**\n * Check if IndexedDB is supported in the current environment\n * @returns true if IndexedDB is available, false otherwise\n */\n DiagnosticsStorage.isSupported = function () {\n var _a;\n return ((_a = getGlobalScope()) === null || _a === void 0 ? void 0 : _a.indexedDB) !== undefined;\n };\n DiagnosticsStorage.prototype.getDB = function () {\n return __awaiter(this, void 0, void 0, function () {\n return __generator(this, function (_a) {\n if (!this.dbPromise) {\n this.dbPromise = this.openDB();\n }\n return [2 /*return*/, this.dbPromise];\n });\n });\n };\n DiagnosticsStorage.prototype.openDB = function () {\n var _this = this;\n return new Promise(function (resolve, reject) {\n var request = indexedDB.open(_this.dbName, DB_VERSION);\n request.onerror = function () {\n // Clear dbPromise when it rejects for the first time\n _this.dbPromise = null;\n reject(new Error('Failed to open IndexedDB'));\n };\n request.onsuccess = function () {\n var db = request.result;\n // Clear dbPromise when connection was on but went off later\n db.onclose = function () {\n _this.dbPromise = null;\n _this.logger.debug('DiagnosticsStorage: DB connection closed.');\n };\n db.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: A global database error occurred.', event);\n db.close();\n };\n resolve(db);\n };\n request.onupgradeneeded = function (event) {\n var db = event.target.result;\n _this.createTables(db);\n };\n });\n };\n DiagnosticsStorage.prototype.createTables = function (db) {\n // Create tags table\n if (!db.objectStoreNames.contains(TABLE_NAMES.TAGS)) {\n db.createObjectStore(TABLE_NAMES.TAGS, { keyPath: 'key' });\n }\n // Create counters table\n if (!db.objectStoreNames.contains(TABLE_NAMES.COUNTERS)) {\n db.createObjectStore(TABLE_NAMES.COUNTERS, { keyPath: 'key' });\n }\n // Create histograms table for storing histogram stats (count, min, max, sum)\n if (!db.objectStoreNames.contains(TABLE_NAMES.HISTOGRAMS)) {\n db.createObjectStore(TABLE_NAMES.HISTOGRAMS, {\n keyPath: 'key',\n });\n }\n // Create events table\n if (!db.objectStoreNames.contains(TABLE_NAMES.EVENTS)) {\n var eventsStore = db.createObjectStore(TABLE_NAMES.EVENTS, {\n keyPath: 'id',\n autoIncrement: true,\n });\n // Create index on time for chronological queries\n eventsStore.createIndex('time_idx', 'time', { unique: false });\n }\n // Create internal table for storing internal data like flush timestamps\n if (!db.objectStoreNames.contains(TABLE_NAMES.INTERNAL)) {\n db.createObjectStore(TABLE_NAMES.INTERNAL, { keyPath: 'key' });\n }\n };\n DiagnosticsStorage.prototype.setTags = function (tags) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_1, store_1, error_1;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (Object.entries(tags).length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_1 = db.transaction([TABLE_NAMES.TAGS], 'readwrite');\n store_1 = transaction_1.objectStore(TABLE_NAMES.TAGS);\n return [2 /*return*/, new Promise(function (resolve) {\n var entries = Object.entries(tags);\n transaction_1.oncomplete = function () {\n resolve();\n };\n transaction_1.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set tags', event);\n resolve();\n };\n entries.forEach(function (_a) {\n var _b = __read(_a, 2), key = _b[0], value = _b[1];\n var putRequest = store_1.put({ key: key, value: value });\n putRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set tag', key, value, event);\n };\n });\n })];\n case 2:\n error_1 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to set tags', error_1);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.incrementCounters = function (counters) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_2, store_2, error_2;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (Object.entries(counters).length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_2 = db.transaction([TABLE_NAMES.COUNTERS], 'readwrite');\n store_2 = transaction_2.objectStore(TABLE_NAMES.COUNTERS);\n return [2 /*return*/, new Promise(function (resolve) {\n var entries = Object.entries(counters);\n transaction_2.oncomplete = function () {\n resolve();\n };\n transaction_2.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to increment counters', event);\n resolve();\n };\n // Read existing values and update them\n entries.forEach(function (_a) {\n var _b = __read(_a, 2), key = _b[0], incrementValue = _b[1];\n var getRequest = store_2.get(key);\n getRequest.onsuccess = function () {\n var existingRecord = getRequest.result;\n /* istanbul ignore next */\n var existingValue = existingRecord ? existingRecord.value : 0;\n var putRequest = store_2.put({ key: key, value: existingValue + incrementValue });\n putRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to update counter', key, event);\n };\n };\n getRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to read existing counter', key, event);\n };\n });\n })];\n case 2:\n error_2 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to increment counters', error_2);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.setHistogramStats = function (histogramStats) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_3, store_3, error_3;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (Object.entries(histogramStats).length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_3 = db.transaction([TABLE_NAMES.HISTOGRAMS], 'readwrite');\n store_3 = transaction_3.objectStore(TABLE_NAMES.HISTOGRAMS);\n return [2 /*return*/, new Promise(function (resolve) {\n var entries = Object.entries(histogramStats);\n transaction_3.oncomplete = function () {\n resolve();\n };\n transaction_3.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', event);\n resolve();\n };\n // Read existing values and update them\n entries.forEach(function (_a) {\n var _b = __read(_a, 2), key = _b[0], newStats = _b[1];\n var getRequest = store_3.get(key);\n getRequest.onsuccess = function () {\n var existingRecord = getRequest.result;\n var updatedStats;\n /* istanbul ignore next */\n if (existingRecord) {\n // Accumulate with existing stats\n updatedStats = {\n key: key,\n count: existingRecord.count + newStats.count,\n min: Math.min(existingRecord.min, newStats.min),\n max: Math.max(existingRecord.max, newStats.max),\n sum: existingRecord.sum + newStats.sum,\n };\n }\n else {\n // Create new stats\n updatedStats = {\n key: key,\n count: newStats.count,\n min: newStats.min,\n max: newStats.max,\n sum: newStats.sum,\n };\n }\n var putRequest = store_3.put(updatedStats);\n putRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', key, event);\n };\n };\n getRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to read existing histogram stats', key, event);\n };\n });\n })];\n case 2:\n error_3 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', error_3);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.addEventRecords = function (events) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_4, store_4, error_4;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (events.length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_4 = db.transaction([TABLE_NAMES.EVENTS], 'readwrite');\n store_4 = transaction_4.objectStore(TABLE_NAMES.EVENTS);\n return [2 /*return*/, new Promise(function (resolve) {\n transaction_4.oncomplete = function () {\n resolve();\n };\n /* istanbul ignore next */\n transaction_4.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to add event records', event);\n resolve();\n };\n // First, check how many events are currently stored\n var countRequest = store_4.count();\n countRequest.onsuccess = function () {\n var currentCount = countRequest.result;\n // Calculate how many events we can add\n var availableSlots = Math.max(0, MAX_PERSISTENT_STORAGE_EVENTS_COUNT - currentCount);\n if (availableSlots < events.length) {\n _this.logger.debug(\"DiagnosticsStorage: Only added \".concat(availableSlots, \" of \").concat(events.length, \" events due to storage limit\"));\n }\n // Only add events up to the available slots (take the least recent ones)\n events.slice(0, availableSlots).forEach(function (event) {\n var request = store_4.add(event);\n request.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to add event record', event);\n };\n });\n };\n countRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to count existing events', event);\n };\n })];\n case 2:\n error_4 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to add event records', error_4);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.setInternal = function (key, value) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_5, store_5, error_5;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_5 = db.transaction([TABLE_NAMES.INTERNAL], 'readwrite');\n store_5 = transaction_5.objectStore(TABLE_NAMES.INTERNAL);\n return [2 /*return*/, new Promise(function (resolve, reject) {\n /* istanbul ignore next */\n transaction_5.onabort = function () { return reject(new Error('Failed to set internal value')); };\n var request = store_5.put({ key: key, value: value });\n request.onsuccess = function () { return resolve(); };\n /* istanbul ignore next */\n request.onerror = function () { return reject(new Error('Failed to set internal value')); };\n })];\n case 2:\n error_5 = _a.sent();\n /* istanbul ignore next */\n this.logger.debug('DiagnosticsStorage: Failed to set internal value', error_5);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.getInternal = function (key) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_6, store_6, error_6;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_6 = db.transaction([TABLE_NAMES.INTERNAL], 'readonly');\n store_6 = transaction_6.objectStore(TABLE_NAMES.INTERNAL);\n return [2 /*return*/, new Promise(function (resolve, reject) {\n /* istanbul ignore next */\n transaction_6.onabort = function () { return reject(new Error('Failed to get internal value')); };\n var request = store_6.get(key);\n request.onsuccess = function () { return resolve(request.result); };\n /* istanbul ignore next */\n request.onerror = function () { return reject(new Error('Failed to get internal value')); };\n })];\n case 2:\n error_6 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to get internal value', error_6);\n return [2 /*return*/, undefined];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.getLastFlushTimestamp = function () {\n return __awaiter(this, void 0, void 0, function () {\n var record, error_7;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.getInternal(INTERNAL_KEYS.LAST_FLUSH_TIMESTAMP)];\n case 1:\n record = _a.sent();\n return [2 /*return*/, record ? parseInt(record.value, 10) : undefined];\n case 2:\n error_7 = _a.sent();\n /* istanbul ignore next */\n this.logger.debug('DiagnosticsStorage: Failed to get last flush timestamp', error_7);\n /* istanbul ignore next */\n return [2 /*return*/, undefined];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.setLastFlushTimestamp = function (timestamp) {\n return __awaiter(this, void 0, void 0, function () {\n var error_8;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.setInternal(INTERNAL_KEYS.LAST_FLUSH_TIMESTAMP, timestamp.toString())];\n case 1:\n _a.sent();\n return [3 /*break*/, 3];\n case 2:\n error_8 = _a.sent();\n /* istanbul ignore next */\n this.logger.debug('DiagnosticsStorage: Failed to set last flush timestamp', error_8);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n /* istanbul ignore next */\n DiagnosticsStorage.prototype.clearTable = function (transaction, tableName) {\n return new Promise(function (resolve, reject) {\n var store = transaction.objectStore(tableName);\n var request = store.clear();\n request.onsuccess = function () { return resolve(); };\n request.onerror = function () { return reject(new Error(\"Failed to clear table \".concat(tableName))); };\n });\n };\n /* istanbul ignore next */\n DiagnosticsStorage.prototype.getAllAndClear = function () {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction, _a, tags, counters, histogramStats, events, error_9;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n _b.trys.push([0, 4, , 5]);\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _b.sent();\n transaction = db.transaction([TABLE_NAMES.TAGS, TABLE_NAMES.COUNTERS, TABLE_NAMES.HISTOGRAMS, TABLE_NAMES.EVENTS], 'readwrite');\n return [4 /*yield*/, Promise.all([\n this.getAllFromStore(transaction, TABLE_NAMES.TAGS),\n this.getAllFromStore(transaction, TABLE_NAMES.COUNTERS),\n this.getAllFromStore(transaction, TABLE_NAMES.HISTOGRAMS),\n this.getAllFromStore(transaction, TABLE_NAMES.EVENTS),\n ])];\n case 2:\n _a = __read.apply(void 0, [_b.sent(), 4]), tags = _a[0], counters = _a[1], histogramStats = _a[2], events = _a[3];\n // Clear all data in the same transaction\n return [4 /*yield*/, Promise.all([\n this.clearTable(transaction, TABLE_NAMES.COUNTERS),\n this.clearTable(transaction, TABLE_NAMES.HISTOGRAMS),\n this.clearTable(transaction, TABLE_NAMES.EVENTS),\n ])];\n case 3:\n // Clear all data in the same transaction\n _b.sent();\n return [2 /*return*/, { tags: tags, counters: counters, histogramStats: histogramStats, events: events }];\n case 4:\n error_9 = _b.sent();\n this.logger.debug('DiagnosticsStorage: Failed to get all and clear data', error_9);\n return [2 /*return*/, { tags: [], counters: [], histogramStats: [], events: [] }];\n case 5: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Helper method to get all records from a store within a transaction\n */\n /* istanbul ignore next */\n DiagnosticsStorage.prototype.getAllFromStore = function (transaction, tableName) {\n return new Promise(function (resolve, reject) {\n var store = transaction.objectStore(tableName);\n var request = store.getAll();\n request.onsuccess = function () { return resolve(request.result); };\n request.onerror = function () { return reject(new Error(\"Failed to get all from \".concat(tableName))); };\n });\n };\n return DiagnosticsStorage;\n}());\nexport { DiagnosticsStorage };\n//# sourceMappingURL=diagnostics-storage.js.map","import { __assign, __values } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nexport var GLOBAL_KEY = '__AMPLITUDE_SCRIPT_URL__';\nexport var EVENT_NAME_ERROR_UNCAUGHT = 'sdk.error.uncaught';\nvar getNormalizedScriptUrls = function () {\n var scope = getGlobalScope();\n /* istanbul ignore next */\n if (!scope) {\n return [];\n }\n var value = scope[GLOBAL_KEY];\n if (Array.isArray(value)) {\n return value;\n }\n /* istanbul ignore next - legacy single URL stored as string */\n if (typeof value === 'string') {\n return [value];\n }\n return [];\n};\nvar addNormalizedScriptUrl = function (url) {\n var scope = getGlobalScope();\n /* istanbul ignore next */\n if (!scope) {\n return;\n }\n var urls = getNormalizedScriptUrls();\n if (!urls.includes(url)) {\n urls.push(url);\n scope[GLOBAL_KEY] = urls;\n }\n};\nexport var registerSdkLoaderMetadata = function (metadata) {\n if (metadata.scriptUrl) {\n var normalized = normalizeUrl(metadata.scriptUrl);\n if (normalized) {\n addNormalizedScriptUrl(normalized);\n }\n }\n};\nexport var enableSdkErrorListeners = function (client) {\n var scope = getGlobalScope();\n if (!scope || typeof scope.addEventListener !== 'function') {\n return;\n }\n var handleError = function (event) {\n var error = event.error instanceof Error ? event.error : undefined;\n var stack = error === null || error === void 0 ? void 0 : error.stack;\n var match = detectSdkOrigin({ filename: event.filename, stack: stack });\n if (!match) {\n return;\n }\n capture({\n type: 'error',\n message: event.message,\n stack: stack,\n filename: event.filename,\n errorName: error === null || error === void 0 ? void 0 : error.name,\n metadata: {\n colno: event.colno,\n lineno: event.lineno,\n isTrusted: event.isTrusted,\n matchReason: match,\n },\n });\n };\n var handleRejection = function (event) {\n var _a;\n var error = event.reason instanceof Error ? event.reason : undefined;\n var stack = error === null || error === void 0 ? void 0 : error.stack;\n var filename = extractFilenameFromStack(stack);\n var match = detectSdkOrigin({ filename: filename, stack: stack });\n if (!match) {\n return;\n }\n /* istanbul ignore next */\n capture({\n type: 'unhandledrejection',\n message: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : stringifyReason(event.reason),\n stack: stack,\n filename: filename,\n errorName: error === null || error === void 0 ? void 0 : error.name,\n metadata: {\n isTrusted: event.isTrusted,\n matchReason: match,\n },\n });\n };\n var capture = function (context) {\n client.recordEvent(EVENT_NAME_ERROR_UNCAUGHT, __assign({ type: context.type, message: context.message, filename: context.filename, error_name: context.errorName, stack: context.stack }, context.metadata));\n };\n scope.addEventListener('error', handleError, true);\n scope.addEventListener('unhandledrejection', handleRejection, true);\n};\nvar detectSdkOrigin = function (payload) {\n var e_1, _a;\n var normalizedScriptUrls = getNormalizedScriptUrls();\n if (normalizedScriptUrls.length === 0) {\n return undefined;\n }\n try {\n for (var normalizedScriptUrls_1 = __values(normalizedScriptUrls), normalizedScriptUrls_1_1 = normalizedScriptUrls_1.next(); !normalizedScriptUrls_1_1.done; normalizedScriptUrls_1_1 = normalizedScriptUrls_1.next()) {\n var normalizedScriptUrl = normalizedScriptUrls_1_1.value;\n if (payload.filename && payload.filename.includes(normalizedScriptUrl)) {\n return 'filename';\n }\n if (payload.stack && payload.stack.includes(normalizedScriptUrl)) {\n return 'stack';\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (normalizedScriptUrls_1_1 && !normalizedScriptUrls_1_1.done && (_a = normalizedScriptUrls_1.return)) _a.call(normalizedScriptUrls_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n return undefined;\n};\nvar normalizeUrl = function (value) {\n var _a, _b;\n try {\n /* istanbul ignore next */\n var url = new URL(value, (_b = (_a = getGlobalScope()) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.origin);\n return url.origin + url.pathname;\n }\n catch (_c) {\n return undefined;\n }\n};\nvar extractFilenameFromStack = function (stack) {\n if (!stack) {\n return undefined;\n }\n var match = stack.match(/(https?:\\/\\/\\S+?)(?=[)\\s]|$)/);\n /* istanbul ignore next */\n return match ? match[1] : undefined;\n};\n/* istanbul ignore next */\nvar stringifyReason = function (reason) {\n if (typeof reason === 'string') {\n return reason;\n }\n try {\n return JSON.stringify(reason);\n }\n catch (_a) {\n return '[object Object]';\n }\n};\n//# sourceMappingURL=uncaught-sdk-errors.js.map","import { __assign, __awaiter, __generator, __read, __spreadArray } from \"tslib\";\nimport { DiagnosticsStorage } from './diagnostics-storage';\nimport { getGlobalScope } from '../global-scope';\nimport { isTimestampInSampleTemp } from '../utils/sampling';\nimport { enableSdkErrorListeners } from './uncaught-sdk-errors';\nexport var SAVE_INTERVAL_MS = 1000; // 1 second\nexport var FLUSH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\nexport var DIAGNOSTICS_US_SERVER_URL = 'https://diagnostics.prod.us-west-2.amplitude.com/v1/capture';\nexport var DIAGNOSTICS_EU_SERVER_URL = 'https://diagnostics.prod.eu-central-1.amplitude.com/v1/capture';\n// In-memory storage limits\nexport var MAX_MEMORY_STORAGE_COUNT = 10000; // for tags, counters, histograms separately\nexport var MAX_MEMORY_STORAGE_EVENTS_COUNT = 10;\nvar DiagnosticsClient = /** @class */ (function () {\n function DiagnosticsClient(apiKey, logger, serverZone, options) {\n if (serverZone === void 0) { serverZone = 'US'; }\n // In-memory storages\n this.inMemoryTags = {};\n this.inMemoryCounters = {};\n this.inMemoryHistograms = {};\n this.inMemoryEvents = [];\n // Timer for 1-second persistence\n this.saveTimer = null;\n // Timer for flush interval\n this.flushTimer = null;\n this.apiKey = apiKey;\n this.logger = logger;\n this.serverUrl = serverZone === 'US' ? DIAGNOSTICS_US_SERVER_URL : DIAGNOSTICS_EU_SERVER_URL;\n this.logger.debug('DiagnosticsClient: Initializing with options', JSON.stringify(options, null, 2));\n // Diagnostics is enabled by default with sample rate of 0 (no sampling)\n this.config = __assign({ enabled: true, sampleRate: 0 }, options);\n this.startTimestamp = Date.now();\n this.shouldTrack = isTimestampInSampleTemp(this.startTimestamp, this.config.sampleRate) && this.config.enabled;\n if (DiagnosticsStorage.isSupported()) {\n this.storage = new DiagnosticsStorage(apiKey, logger);\n }\n else {\n this.logger.debug('DiagnosticsClient: IndexedDB is not supported');\n }\n void this.initializeFlushInterval();\n // Track internal diagnostics metrics for sampling\n if (this.shouldTrack) {\n this.increment('sdk.diagnostics.sampled.in.and.enabled');\n enableSdkErrorListeners(this);\n }\n }\n /**\n * Check if storage is available and tracking is enabled\n */\n DiagnosticsClient.prototype.isStorageAndTrackEnabled = function () {\n return Boolean(this.storage) && Boolean(this.shouldTrack);\n };\n DiagnosticsClient.prototype.setTag = function (name, value) {\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (Object.keys(this.inMemoryTags).length >= MAX_MEMORY_STORAGE_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return setTags as reaching memory limit');\n return;\n }\n this.inMemoryTags[name] = value;\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.increment = function (name, size) {\n if (size === void 0) { size = 1; }\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (Object.keys(this.inMemoryCounters).length >= MAX_MEMORY_STORAGE_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return increment as reaching memory limit');\n return;\n }\n this.inMemoryCounters[name] = (this.inMemoryCounters[name] || 0) + size;\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.recordHistogram = function (name, value) {\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (Object.keys(this.inMemoryHistograms).length >= MAX_MEMORY_STORAGE_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return recordHistogram as reaching memory limit');\n return;\n }\n var existing = this.inMemoryHistograms[name];\n if (existing) {\n // Update existing stats incrementally\n existing.count += 1;\n existing.min = Math.min(existing.min, value);\n existing.max = Math.max(existing.max, value);\n existing.sum += value;\n }\n else {\n // Create new stats\n this.inMemoryHistograms[name] = {\n count: 1,\n min: value,\n max: value,\n sum: value,\n };\n }\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.recordEvent = function (name, properties) {\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (this.inMemoryEvents.length >= MAX_MEMORY_STORAGE_EVENTS_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return recordEvent as reaching memory limit');\n return;\n }\n this.inMemoryEvents.push({\n event_name: name,\n time: Date.now(),\n event_properties: properties,\n });\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.startTimersIfNeeded = function () {\n var _this = this;\n if (!this.saveTimer) {\n this.saveTimer = setTimeout(function () {\n _this.saveAllDataToStorage()\n .catch(function (error) {\n _this.logger.debug('DiagnosticsClient: Failed to save all data to storage', error);\n })\n .finally(function () {\n _this.saveTimer = null;\n });\n }, SAVE_INTERVAL_MS);\n }\n if (!this.flushTimer) {\n this.flushTimer = setTimeout(function () {\n _this._flush()\n .catch(function (error) {\n _this.logger.debug('DiagnosticsClient: Failed to flush', error);\n })\n .finally(function () {\n _this.flushTimer = null;\n });\n }, FLUSH_INTERVAL_MS);\n }\n };\n DiagnosticsClient.prototype.saveAllDataToStorage = function () {\n return __awaiter(this, void 0, void 0, function () {\n var tagsToSave, countersToSave, histogramsToSave, eventsToSave;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n if (!this.storage) {\n return [2 /*return*/];\n }\n tagsToSave = __assign({}, this.inMemoryTags);\n countersToSave = __assign({}, this.inMemoryCounters);\n histogramsToSave = __assign({}, this.inMemoryHistograms);\n eventsToSave = __spreadArray([], __read(this.inMemoryEvents), false);\n this.inMemoryEvents = [];\n this.inMemoryTags = {};\n this.inMemoryCounters = {};\n this.inMemoryHistograms = {};\n return [4 /*yield*/, Promise.all([\n this.storage.setTags(tagsToSave),\n this.storage.incrementCounters(countersToSave),\n this.storage.setHistogramStats(histogramsToSave),\n this.storage.addEventRecords(eventsToSave),\n ])];\n case 1:\n _a.sent();\n return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsClient.prototype._flush = function () {\n return __awaiter(this, void 0, void 0, function () {\n var _a, tagRecords, counterRecords, histogramStatsRecords, eventRecords, tags, counters, histogram, events, payload;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n if (!this.storage) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.saveAllDataToStorage()];\n case 1:\n _b.sent();\n this.saveTimer = null;\n this.flushTimer = null;\n return [4 /*yield*/, this.storage.getAllAndClear()];\n case 2:\n _a = _b.sent(), tagRecords = _a.tags, counterRecords = _a.counters, histogramStatsRecords = _a.histogramStats, eventRecords = _a.events;\n // Update the last flush timestamp\n void this.storage.setLastFlushTimestamp(Date.now());\n tags = {};\n tagRecords.forEach(function (record) {\n tags[record.key] = record.value;\n });\n counters = {};\n counterRecords.forEach(function (record) {\n counters[record.key] = record.value;\n });\n histogram = {};\n histogramStatsRecords.forEach(function (stats) {\n histogram[stats.key] = {\n count: stats.count,\n min: stats.min,\n max: stats.max,\n avg: Math.round((stats.sum / stats.count) * 100) / 100, // round the average to 2 decimal places.\n };\n });\n events = eventRecords.map(function (record) { return ({\n event_name: record.event_name,\n time: record.time,\n event_properties: record.event_properties,\n }); });\n // Early return if all data collections are empty\n if (Object.keys(counters).length === 0 && Object.keys(histogram).length === 0 && events.length === 0) {\n return [2 /*return*/];\n }\n payload = {\n tags: tags,\n histogram: histogram,\n counters: counters,\n events: events,\n };\n // Send payload to diagnostics server\n void this.fetch(payload);\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Send diagnostics data to the server\n */\n DiagnosticsClient.prototype.fetch = function (payload) {\n return __awaiter(this, void 0, void 0, function () {\n var response, error_1;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (!getGlobalScope()) {\n throw new Error('DiagnosticsClient: Fetch is not supported');\n }\n return [4 /*yield*/, fetch(this.serverUrl, {\n method: 'POST',\n headers: {\n 'X-ApiKey': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n })];\n case 1:\n response = _a.sent();\n if (!response.ok) {\n this.logger.debug('DiagnosticsClient: Failed to send diagnostics data.');\n return [2 /*return*/];\n }\n this.logger.debug('DiagnosticsClient: Successfully sent diagnostics data');\n return [3 /*break*/, 3];\n case 2:\n error_1 = _a.sent();\n this.logger.debug('DiagnosticsClient: Failed to send diagnostics data. ', error_1);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Initialize flush interval logic.\n * Check if 5 minutes has passed since last flush, if so flush immediately.\n * Otherwise set a timer to flush when the interval is reached.\n */\n DiagnosticsClient.prototype.initializeFlushInterval = function () {\n return __awaiter(this, void 0, void 0, function () {\n var now, lastFlushTimestamp, timeSinceLastFlush;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n if (!this.storage) {\n return [2 /*return*/];\n }\n now = Date.now();\n return [4 /*yield*/, this.storage.getLastFlushTimestamp()];\n case 1:\n lastFlushTimestamp = (_a.sent()) || -1;\n // If last flush timestamp is -1, it means this is a new client\n // Save current timestamp as the initial \"last flush timestamp\"\n // and schedule the flush timer\n if (lastFlushTimestamp === -1) {\n void this.storage.setLastFlushTimestamp(now);\n this._setFlushTimer(FLUSH_INTERVAL_MS);\n return [2 /*return*/];\n }\n timeSinceLastFlush = now - lastFlushTimestamp;\n if (timeSinceLastFlush >= FLUSH_INTERVAL_MS) {\n // More than 5 minutes has passed, flush immediately\n void this._flush();\n return [2 /*return*/];\n }\n else {\n // Set timer for remaining time\n this._setFlushTimer(FLUSH_INTERVAL_MS - timeSinceLastFlush);\n }\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Helper method to set flush timer with consistent error handling\n */\n DiagnosticsClient.prototype._setFlushTimer = function (delay) {\n var _this = this;\n this.flushTimer = setTimeout(function () {\n _this._flush()\n .catch(function (error) {\n _this.logger.debug('DiagnosticsClient: Failed to flush', error);\n })\n .finally(function () {\n _this.flushTimer = null;\n });\n }, delay);\n };\n DiagnosticsClient.prototype._setSampleRate = function (sampleRate) {\n this.logger.debug('DiagnosticsClient: Setting sample rate to', sampleRate);\n this.config.sampleRate = sampleRate;\n this.shouldTrack = isTimestampInSampleTemp(this.startTimestamp, this.config.sampleRate) && this.config.enabled;\n this.logger.debug('DiagnosticsClient: Should track is', this.shouldTrack);\n };\n return DiagnosticsClient;\n}());\nexport { DiagnosticsClient };\n//# sourceMappingURL=diagnostics-client.js.map","import { Status } from '../types/status';\nimport { isSuccessStatusCode } from '../utils/status-code';\nvar BaseTransport = /** @class */ (function () {\n function BaseTransport() {\n }\n BaseTransport.prototype.send = function (_serverUrl, _payload, _enableRequestBodyCompression) {\n return Promise.resolve(null);\n };\n BaseTransport.prototype.buildResponse = function (responseJSON) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;\n if (typeof responseJSON !== 'object') {\n return null;\n }\n var statusCode = responseJSON.code || 0;\n var status = this.buildStatus(statusCode);\n switch (status) {\n case Status.Success:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n eventsIngested: (_a = responseJSON.events_ingested) !== null && _a !== void 0 ? _a : 0,\n payloadSizeBytes: (_b = responseJSON.payload_size_bytes) !== null && _b !== void 0 ? _b : 0,\n serverUploadTime: (_c = responseJSON.server_upload_time) !== null && _c !== void 0 ? _c : 0,\n },\n };\n case Status.Invalid:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n error: (_d = responseJSON.error) !== null && _d !== void 0 ? _d : '',\n missingField: (_e = responseJSON.missing_field) !== null && _e !== void 0 ? _e : '',\n eventsWithInvalidFields: (_f = responseJSON.events_with_invalid_fields) !== null && _f !== void 0 ? _f : {},\n eventsWithMissingFields: (_g = responseJSON.events_with_missing_fields) !== null && _g !== void 0 ? _g : {},\n eventsWithInvalidIdLengths: (_h = responseJSON.events_with_invalid_id_lengths) !== null && _h !== void 0 ? _h : {},\n epsThreshold: (_j = responseJSON.eps_threshold) !== null && _j !== void 0 ? _j : 0,\n exceededDailyQuotaDevices: (_k = responseJSON.exceeded_daily_quota_devices) !== null && _k !== void 0 ? _k : {},\n silencedDevices: (_l = responseJSON.silenced_devices) !== null && _l !== void 0 ? _l : [],\n silencedEvents: (_m = responseJSON.silenced_events) !== null && _m !== void 0 ? _m : [],\n throttledDevices: (_o = responseJSON.throttled_devices) !== null && _o !== void 0 ? _o : {},\n throttledEvents: (_p = responseJSON.throttled_events) !== null && _p !== void 0 ? _p : [],\n },\n };\n case Status.PayloadTooLarge:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n error: (_q = responseJSON.error) !== null && _q !== void 0 ? _q : '',\n },\n };\n case Status.RateLimit:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n error: (_r = responseJSON.error) !== null && _r !== void 0 ? _r : '',\n epsThreshold: (_s = responseJSON.eps_threshold) !== null && _s !== void 0 ? _s : 0,\n throttledDevices: (_t = responseJSON.throttled_devices) !== null && _t !== void 0 ? _t : {},\n throttledUsers: (_u = responseJSON.throttled_users) !== null && _u !== void 0 ? _u : {},\n exceededDailyQuotaDevices: (_v = responseJSON.exceeded_daily_quota_devices) !== null && _v !== void 0 ? _v : {},\n exceededDailyQuotaUsers: (_w = responseJSON.exceeded_daily_quota_users) !== null && _w !== void 0 ? _w : {},\n throttledEvents: (_x = responseJSON.throttled_events) !== null && _x !== void 0 ? _x : [],\n },\n };\n case Status.Timeout:\n default:\n return {\n status: status,\n statusCode: statusCode,\n };\n }\n };\n BaseTransport.prototype.buildStatus = function (code) {\n if (isSuccessStatusCode(code)) {\n return Status.Success;\n }\n if (code === 429) {\n return Status.RateLimit;\n }\n if (code === 413) {\n return Status.PayloadTooLarge;\n }\n if (code === 408) {\n return Status.Timeout;\n }\n if (code >= 400 && code < 500) {\n return Status.Invalid;\n }\n if (code >= 500) {\n return Status.Failed;\n }\n return Status.Unknown;\n };\n return BaseTransport;\n}());\nexport { BaseTransport };\n//# sourceMappingURL=base.js.map","/**\n * Checks if an HTTP status code indicates success (2xx range)\n * @param code - The HTTP status code to check\n * @returns true if the status code is in the 2xx range, false otherwise\n */\nexport function isSuccessStatusCode(code) {\n return code >= 200 && code < 300;\n}\n//# sourceMappingURL=status-code.js.map","import { __assign, __awaiter, __extends, __generator } from \"tslib\";\nimport { BaseTransport } from './base';\nvar FetchTransport = /** @class */ (function (_super) {\n __extends(FetchTransport, _super);\n function FetchTransport(customHeaders) {\n if (customHeaders === void 0) { customHeaders = {}; }\n var _this = _super.call(this) || this;\n _this.customHeaders = customHeaders;\n return _this;\n }\n FetchTransport.prototype.send = function (serverUrl, payload) {\n return __awaiter(this, void 0, void 0, function () {\n var options, response, responseText;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n /* istanbul ignore if */\n if (typeof fetch === 'undefined') {\n throw new Error('FetchTransport is not supported');\n }\n options = {\n headers: __assign({ 'Content-Type': 'application/json', Accept: '*/*' }, this.customHeaders),\n body: JSON.stringify(payload),\n method: 'POST',\n };\n return [4 /*yield*/, fetch(serverUrl, options)];\n case 1:\n response = _a.sent();\n return [4 /*yield*/, response.text()];\n case 2:\n responseText = _a.sent();\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return [2 /*return*/, this.buildResponse(JSON.parse(responseText))];\n }\n catch (_b) {\n return [2 /*return*/, this.buildResponse({ code: response.status })];\n }\n return [2 /*return*/];\n }\n });\n });\n };\n return FetchTransport;\n}(BaseTransport));\nexport { FetchTransport };\n//# sourceMappingURL=fetch.js.map","var RemoteConfigLocalStorage = /** @class */ (function () {\n function RemoteConfigLocalStorage(apiKey, logger) {\n this.key = \"AMP_remote_config_\".concat(apiKey.substring(0, 10));\n this.logger = logger;\n }\n RemoteConfigLocalStorage.prototype.fetchConfig = function () {\n var result = null;\n var failedRemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n try {\n result = localStorage.getItem(this.key);\n }\n catch (error) {\n this.logger.debug('Remote config localstorage failed to access: ', error);\n return Promise.resolve(failedRemoteConfigInfo);\n }\n if (result === null) {\n this.logger.debug('Remote config localstorage gets null because the key does not exist');\n return Promise.resolve(failedRemoteConfigInfo);\n }\n try {\n var remoteConfigInfo = JSON.parse(result);\n this.logger.debug(\"Remote config localstorage parsed successfully: \".concat(JSON.stringify(remoteConfigInfo)));\n return Promise.resolve({\n remoteConfig: remoteConfigInfo.remoteConfig,\n lastFetch: new Date(remoteConfigInfo.lastFetch),\n });\n }\n catch (error) {\n this.logger.debug('Remote config localstorage failed to parse: ', error);\n localStorage.removeItem(this.key);\n return Promise.resolve(failedRemoteConfigInfo);\n }\n };\n RemoteConfigLocalStorage.prototype.setConfig = function (config) {\n try {\n localStorage.setItem(this.key, JSON.stringify(config));\n this.logger.debug('Remote config localstorage set successfully.');\n return Promise.resolve(true);\n }\n catch (error) {\n this.logger.debug('Remote config localstorage failed to set: ', error);\n }\n return Promise.resolve(false);\n };\n return RemoteConfigLocalStorage;\n}());\nexport { RemoteConfigLocalStorage };\n//# sourceMappingURL=remote-config-localstorage.js.map","import { __awaiter, __generator } from \"tslib\";\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\nexport var US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport var EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport var DEFAULT_MAX_RETRIES = 3;\nvar CODE_STATUS = {\n INVALID_API_KEY: 401,\n FORBIDDEN: 403,\n RATE_LIMIT: 429,\n};\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nvar DEFAULT_TIMEOUT = 1000;\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nvar DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\nvar RemoteConfigClient = /** @class */ (function () {\n function RemoteConfigClient(apiKey, logger, serverZone, serverUrl) {\n if (serverZone === void 0) { serverZone = 'US'; }\n // Registered callbackInfos by subscribe().\n this.callbackInfos = [];\n // Track the last successful fetch time for throttling (timestamp in milliseconds).\n this.lastSuccessfulFetch = null;\n // Store the in-flight fetch promise for deduplication.\n this.fetchPromise = null;\n // Used to skip periodic updateConfigs calls when API key is invalid.\n this.isLastFetchInvalidApiKey = false;\n this.apiKey = apiKey;\n this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n this.logger = logger;\n this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n }\n RemoteConfigClient.prototype.subscribe = function (key, deliveryMode, callback) {\n var id = UUID();\n var callbackInfo = {\n id: id,\n key: key,\n deliveryMode: deliveryMode,\n callback: callback,\n };\n this.callbackInfos.push(callbackInfo);\n if (deliveryMode === 'all') {\n void this.subscribeAll(callbackInfo);\n }\n else {\n void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n }\n return id;\n };\n RemoteConfigClient.prototype.unsubscribe = function (id) {\n var index = this.callbackInfos.findIndex(function (callbackInfo) { return callbackInfo.id === id; });\n if (index === -1) {\n this.logger.debug(\"Remote config client unsubscribe failed because callback with id \".concat(id, \" doesn't exist.\"));\n return false;\n }\n this.callbackInfos.splice(index, 1);\n this.logger.debug(\"Remote config client unsubscribe succeeded removing callback with id \".concat(id, \".\"));\n return true;\n };\n RemoteConfigClient.prototype.updateConfigs = function () {\n return __awaiter(this, void 0, void 0, function () {\n var timeSinceLastFetch, result;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n // Check if we need to throttle based on last successful fetch time\n if (this.lastSuccessfulFetch) {\n timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n return [2 /*return*/];\n }\n }\n return [4 /*yield*/, this.getOrCreateFetchPromise()];\n case 1:\n result = _a.sent();\n void this.storage.setConfig(result);\n this.callbackInfos.forEach(function (callbackInfo) {\n _this.sendCallback(callbackInfo, result, 'remote');\n });\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Get the in-flight fetch promise or create a new one.\n * This ensures multiple subscribe calls share the same network request.\n */\n RemoteConfigClient.prototype.getOrCreateFetchPromise = function () {\n var _this = this;\n if (this.fetchPromise) {\n return this.fetchPromise;\n }\n if (this.isLastFetchInvalidApiKey) {\n this.logger.debug('Remote config client skipping fetch: Invalid API key');\n this.fetchPromise = Promise.resolve({\n remoteConfig: null,\n lastFetch: new Date(),\n }).finally(function () {\n _this.fetchPromise = null;\n });\n return this.fetchPromise;\n }\n this.fetchPromise = this.fetch()\n .then(function (result) {\n // Update last successful fetch time if we got a valid config\n if (result.remoteConfig !== null) {\n _this.lastSuccessfulFetch = Date.now();\n }\n return result;\n })\n .finally(function () {\n // Clear the promise after it settles (success or failure)\n _this.fetchPromise = null;\n });\n return this.fetchPromise;\n };\n /**\n * Send remote first. If it's already complete, we can skip the cached response.\n * - if remote is fetched first, no cache fetch.\n * - if cache is fetched first, still fetching remote.\n */\n RemoteConfigClient.prototype.subscribeAll = function (callbackInfo) {\n return __awaiter(this, void 0, void 0, function () {\n var remotePromise, cachePromise, result;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n remotePromise = this.getOrCreateFetchPromise().then(function (result) {\n _this.logger.debug(\"Remote config client subscription all mode fetched from remote: \".concat(JSON.stringify(result)));\n _this.sendCallback(callbackInfo, result, 'remote');\n void _this.storage.setConfig(result);\n });\n cachePromise = this.storage.fetchConfig().then(function (result) {\n return result;\n });\n return [4 /*yield*/, Promise.race([remotePromise, cachePromise])];\n case 1:\n result = _a.sent();\n // If cache is fetched first, wait for remote.\n if (result !== undefined) {\n this.logger.debug(\"Remote config client subscription all mode fetched from cache: \".concat(JSON.stringify(result)));\n // Skip sending callback if cache is empty (first time user).\n if (result.remoteConfig !== null) {\n this.sendCallback(callbackInfo, result, 'cache');\n }\n else {\n this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n }\n }\n return [4 /*yield*/, remotePromise];\n case 2:\n _a.sent();\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Waits for a remote response until the given timeout, then return a cached copy, if available.\n */\n RemoteConfigClient.prototype.subscribeWaitForRemote = function (callbackInfo, timeout) {\n return __awaiter(this, void 0, void 0, function () {\n var timeoutPromise, result, error_1, result;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n timeoutPromise = new Promise(function (_, reject) {\n setTimeout(function () {\n reject('Timeout exceeded');\n }, timeout);\n });\n _a.label = 1;\n case 1:\n _a.trys.push([1, 3, , 5]);\n return [4 /*yield*/, Promise.race([\n this.getOrCreateFetchPromise(),\n timeoutPromise,\n ])];\n case 2:\n result = (_a.sent());\n this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n return [3 /*break*/, 5];\n case 3:\n error_1 = _a.sent();\n this.logger.debug('Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.');\n return [4 /*yield*/, this.storage.fetchConfig()];\n case 4:\n result = _a.sent();\n if (result.remoteConfig !== null) {\n this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n this.sendCallback(callbackInfo, result, 'cache');\n }\n else {\n this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n this.sendCallback(callbackInfo, result, 'remote');\n }\n return [3 /*break*/, 5];\n case 5: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Call the callback with filtered remote config based on key.\n * @param remoteConfigInfo - the whole remote config object without filtering by key.\n */\n RemoteConfigClient.prototype.sendCallback = function (callbackInfo, remoteConfigInfo, source) {\n callbackInfo.lastCallback = new Date();\n var filteredConfig;\n if (callbackInfo.key) {\n // Filter remote config by key.\n // For example, if remote config is {a: {b: {c: 1}}},\n // if key = 'a', filter result is {b: {c: 1}};\n // if key = 'a.b', filter result is {c: 1}\n filteredConfig = callbackInfo.key.split('.').reduce(function (config, key) {\n if (config === null) {\n return config;\n }\n return key in config ? config[key] : null;\n }, remoteConfigInfo.remoteConfig);\n }\n else {\n filteredConfig = remoteConfigInfo.remoteConfig;\n }\n callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n };\n /**\n * Fetch remote config from remote.\n * @param retries - the number of retries. default is 3.\n * @param timeout - the timeout in milliseconds. Default is 1000.\n * This timeout serves two purposes:\n * 1. It determines how long to wait for each remote config fetch request before aborting it.\n * If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n * and the attempt is considered failed (and may be retried if retries remain).\n * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n * Retry behavior by status code:\n * - 401: invalid API key (stop retries and disable future updateConfigs calls).\n * - 429: retry up to max retries.\n * - other 4xx: no retry.\n * - 5xx and network failures: retry up to max retries.\n * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n */\n RemoteConfigClient.prototype.fetch = function (retries, timeout) {\n if (retries === void 0) { retries = DEFAULT_MAX_RETRIES; }\n if (timeout === void 0) { timeout = DEFAULT_TIMEOUT; }\n return __awaiter(this, void 0, void 0, function () {\n var interval, failedRemoteConfigInfo, _loop_1, this_1, attempt, state_1;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n interval = timeout / retries;\n failedRemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n _loop_1 = function (attempt) {\n var shouldRetry, abortController, timeoutId, res, body, remoteConfig, error_2;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n shouldRetry = true;\n abortController = new AbortController();\n timeoutId = setTimeout(function () { return abortController.abort(); }, timeout);\n _b.label = 1;\n case 1:\n _b.trys.push([1, 7, 8, 9]);\n return [4 /*yield*/, fetch(this_1.getUrlParams(), {\n method: 'GET',\n headers: {\n Accept: '*/*',\n },\n signal: abortController.signal,\n })];\n case 2:\n res = _b.sent();\n if (!!res.ok) return [3 /*break*/, 4];\n return [4 /*yield*/, res.text()];\n case 3:\n body = _b.sent();\n this_1.logger.debug(\"Remote config client fetch with retry time \".concat(retries, \" failed with \").concat(res.status, \": \").concat(body));\n if (res.status === CODE_STATUS.INVALID_API_KEY || res.status === CODE_STATUS.FORBIDDEN) {\n this_1.logger.error(\"Remote config client fetch failed with \".concat(res.status, \". Invalid API key; future fetches will be skipped.\"));\n this_1.isLastFetchInvalidApiKey = true;\n shouldRetry = false;\n }\n else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {\n shouldRetry = false;\n }\n return [3 /*break*/, 6];\n case 4: return [4 /*yield*/, res.json()];\n case 5:\n remoteConfig = (_b.sent());\n return [2 /*return*/, { value: {\n remoteConfig: remoteConfig,\n lastFetch: new Date(),\n } }];\n case 6: return [3 /*break*/, 9];\n case 7:\n error_2 = _b.sent();\n // Handle rejects when the request fails, for example, a network error or timeout\n if (error_2 instanceof Error && error_2.name === 'AbortError') {\n this_1.logger.debug(\"Remote config client fetch with retry time \".concat(retries, \" timed out after \").concat(timeout, \"ms\"));\n }\n else {\n this_1.logger.debug(\"Remote config client fetch with retry time \".concat(retries, \" is rejected because: \"), error_2);\n }\n return [3 /*break*/, 9];\n case 8:\n // Clear the timeout since request completed or failed\n clearTimeout(timeoutId);\n return [7 /*endfinally*/];\n case 9:\n if (!shouldRetry) {\n return [2 /*return*/, \"break\"];\n }\n if (!(attempt < retries - 1)) return [3 /*break*/, 11];\n return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, _this.getJitterDelay(interval)); })];\n case 10:\n _b.sent();\n _b.label = 11;\n case 11: return [2 /*return*/];\n }\n });\n };\n this_1 = this;\n attempt = 0;\n _a.label = 1;\n case 1:\n if (!(attempt < retries)) return [3 /*break*/, 4];\n return [5 /*yield**/, _loop_1(attempt)];\n case 2:\n state_1 = _a.sent();\n if (typeof state_1 === \"object\")\n return [2 /*return*/, state_1.value];\n if (state_1 === \"break\")\n return [3 /*break*/, 4];\n _a.label = 3;\n case 3:\n attempt++;\n return [3 /*break*/, 1];\n case 4: return [2 /*return*/, failedRemoteConfigInfo];\n }\n });\n });\n };\n /**\n * Return jitter in the bound of [0,baseDelay) and then floor round.\n */\n RemoteConfigClient.prototype.getJitterDelay = function (baseDelay) {\n return Math.floor(Math.random() * baseDelay);\n };\n RemoteConfigClient.prototype.getUrlParams = function () {\n // URL encode the API key to handle special characters\n var encodedApiKey = encodeURIComponent(this.apiKey);\n var urlParams = new URLSearchParams();\n urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n return \"\".concat(this.serverUrl, \"/\").concat(encodedApiKey, \"?\").concat(urlParams.toString());\n };\n RemoteConfigClient.CONFIG_GROUP = 'browser';\n return RemoteConfigClient;\n}());\nexport { RemoteConfigClient };\n//# sourceMappingURL=remote-config.js.map","// Shared origin constants for Amplitude cross-window communication\nexport var AMPLITUDE_ORIGIN = 'https://app.amplitude.com';\nexport var AMPLITUDE_ORIGIN_EU = 'https://app.eu.amplitude.com';\nexport var AMPLITUDE_ORIGIN_STAGING = 'https://apps.stag2.amplitude.com';\nexport var AMPLITUDE_ORIGINS_MAP = {\n US: AMPLITUDE_ORIGIN,\n EU: AMPLITUDE_ORIGIN_EU,\n STAGING: AMPLITUDE_ORIGIN_STAGING,\n};\n// Background capture script URL (shared between autocapture and session-replay)\nexport var AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL = 'https://cdn.amplitude.com/libs/background-capture-1.0.1.js.gz';\n//# sourceMappingURL=constants.js.map","var _a;\nimport { __awaiter, __generator, __values } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nimport { AMPLITUDE_ORIGIN } from './constants';\nimport { asyncLoadScript, generateUniqueId } from './utils';\n/**\n * Brand key used to identify BaseWindowMessenger instances across bundle boundaries.\n */\nvar MESSENGER_BRAND = '__AMPLITUDE_MESSENGER_INSTANCE__';\n/** Global scope key where the singleton messenger is stored. */\nvar MESSENGER_GLOBAL_KEY = '__AMPLITUDE_MESSENGER__';\n/**\n * BaseWindowMessenger provides generic cross-window communication via postMessage.\n * Singleton access via getOrCreateWindowMessenger() to prevent duplicate instances\n */\nvar BaseWindowMessenger = /** @class */ (function () {\n function BaseWindowMessenger(_b) {\n var _c = _b === void 0 ? {} : _b, _d = _c.origin, origin = _d === void 0 ? AMPLITUDE_ORIGIN : _d;\n /** Brand property for cross-bundle instanceof checks. */\n this[_a] = true;\n this.isSetup = false;\n this.messageHandler = null;\n this.requestCallbacks = {};\n this.actionHandlers = new Map();\n /**\n * Messages received for actions that had no registered handler yet.\n * Drained automatically when the corresponding handler is registered via\n * registerActionHandler(), solving startup race conditions between\n * independently-initialized plugins.\n */\n this.pendingMessages = new Map();\n /**\n * Tracks in-flight and completed script loads by URL.\n * Using a map, this prevents duplicate loads before the first resolves.\n */\n this.scriptLoadPromises = new Map();\n this.endpoint = origin;\n }\n /**\n * Send a message to the parent window (window.opener).\n */\n BaseWindowMessenger.prototype.notify = function (message) {\n var _b, _c, _d, _e;\n (_c = (_b = this.logger) === null || _b === void 0 ? void 0 : _b.debug) === null || _c === void 0 ? void 0 : _c.call(_b, 'Message sent: ', JSON.stringify(message));\n (_e = (_d = window.opener) === null || _d === void 0 ? void 0 : _d.postMessage) === null || _e === void 0 ? void 0 : _e.call(_d, message, this.endpoint);\n };\n /**\n * Send an async request to the parent window with a unique ID.\n * Returns a Promise that resolves when the parent responds.\n */\n BaseWindowMessenger.prototype.sendRequest = function (action, args, options) {\n var _this = this;\n if (options === void 0) { options = { timeout: 15000 }; }\n var id = generateUniqueId();\n var request = { id: id, action: action, args: args };\n var promise = new Promise(function (resolve, reject) {\n _this.requestCallbacks[id] = { resolve: resolve, reject: reject };\n _this.notify(request);\n if (options.timeout > 0) {\n setTimeout(function () {\n reject(new Error(\"\".concat(action, \" timed out (id: \").concat(id, \")\")));\n delete _this.requestCallbacks[id];\n }, options.timeout);\n }\n });\n return promise;\n };\n /**\n * Handle a response to a previous request by resolving its Promise.\n */\n BaseWindowMessenger.prototype.handleResponse = function (response) {\n var _b;\n if (!this.requestCallbacks[response.id]) {\n (_b = this.logger) === null || _b === void 0 ? void 0 : _b.warn(\"No callback found for request id: \".concat(response.id));\n return;\n }\n this.requestCallbacks[response.id].resolve(response.responseData);\n delete this.requestCallbacks[response.id];\n };\n /**\n * Register a handler for a specific action type.\n * Logs a warning if overwriting an existing handler.\n */\n BaseWindowMessenger.prototype.registerActionHandler = function (action, handler) {\n var e_1, _b;\n var _c, _d;\n if (this.actionHandlers.has(action)) {\n (_d = (_c = this.logger) === null || _c === void 0 ? void 0 : _c.warn) === null || _d === void 0 ? void 0 : _d.call(_c, \"Overwriting existing action handler for: \".concat(action));\n }\n this.actionHandlers.set(action, handler);\n // Replay any messages that arrived before this handler was registered\n var queued = this.pendingMessages.get(action);\n if (queued) {\n this.pendingMessages.delete(action);\n try {\n for (var queued_1 = __values(queued), queued_1_1 = queued_1.next(); !queued_1_1.done; queued_1_1 = queued_1.next()) {\n var data = queued_1_1.value;\n handler(data);\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (queued_1_1 && !queued_1_1.done && (_b = queued_1.return)) _b.call(queued_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n }\n };\n /**\n * Load a script once, deduplicating by URL.\n * Safe against concurrent calls — the second call awaits the first's in-flight Promise\n * rather than triggering a duplicate load.\n */\n BaseWindowMessenger.prototype.loadScriptOnce = function (url) {\n return __awaiter(this, void 0, void 0, function () {\n var existing, loadPromise, error_1;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n existing = this.scriptLoadPromises.get(url);\n if (existing) {\n return [2 /*return*/, existing];\n }\n loadPromise = asyncLoadScript(url).then(function () {\n // Resolve to void\n });\n this.scriptLoadPromises.set(url, loadPromise);\n _b.label = 1;\n case 1:\n _b.trys.push([1, 3, , 4]);\n return [4 /*yield*/, loadPromise];\n case 2:\n _b.sent();\n return [3 /*break*/, 4];\n case 3:\n error_1 = _b.sent();\n // Remove failed loads so they can be retried\n this.scriptLoadPromises.delete(url);\n throw error_1;\n case 4: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Set up the message listener. Idempotent — safe to call multiple times.\n * Subclasses should call super.setup() and then register their own action handlers.\n */\n BaseWindowMessenger.prototype.setup = function (_b) {\n var _this = this;\n var _c, _d;\n var _e = _b === void 0 ? {} : _b, logger = _e.logger, endpoint = _e.endpoint;\n if (logger) {\n this.logger = logger;\n }\n // If endpoint is customized, don't override a previously customized endpoint.\n if (endpoint && this.endpoint === AMPLITUDE_ORIGIN) {\n this.endpoint = endpoint;\n }\n // Only attach the message listener once\n if (this.isSetup) {\n return;\n }\n this.isSetup = true;\n (_d = (_c = this.logger) === null || _c === void 0 ? void 0 : _c.debug) === null || _d === void 0 ? void 0 : _d.call(_c, 'Setting up messenger');\n // Attach Event Listener to listen for messages from the parent window\n this.messageHandler = function (event) {\n var _b, _c, _d, _e, _f;\n (_c = (_b = _this.logger) === null || _b === void 0 ? void 0 : _b.debug) === null || _c === void 0 ? void 0 : _c.call(_b, 'Message received: ', JSON.stringify(event));\n // Only accept messages from the specified origin\n if (_this.endpoint !== event.origin) {\n return;\n }\n var eventData = event.data;\n var action = eventData === null || eventData === void 0 ? void 0 : eventData.action;\n // Ignore messages without action\n if (!action) {\n return;\n }\n // If id exists, handle responses to previous requests\n if ('id' in eventData && eventData.id) {\n (_e = (_d = _this.logger) === null || _d === void 0 ? void 0 : _d.debug) === null || _e === void 0 ? void 0 : _e.call(_d, 'Received Response to previous request: ', JSON.stringify(event));\n _this.handleResponse(eventData);\n }\n else {\n if (action === 'ping') {\n _this.notify({ action: 'pong' });\n return;\n }\n // Dispatch to registered action handlers, or buffer for late registration\n var handler = _this.actionHandlers.get(action);\n if (handler) {\n handler(eventData.data);\n }\n else {\n var queue = (_f = _this.pendingMessages.get(action)) !== null && _f !== void 0 ? _f : [];\n queue.push(eventData.data);\n _this.pendingMessages.set(action, queue);\n }\n }\n };\n window.addEventListener('message', this.messageHandler);\n this.notify({ action: 'page-loaded' });\n };\n /**\n * Tear down the messenger: remove the message listener, clear all state.\n */\n BaseWindowMessenger.prototype.destroy = function () {\n if (this.messageHandler) {\n window.removeEventListener('message', this.messageHandler);\n this.messageHandler = null;\n }\n this.isSetup = false;\n this.actionHandlers.clear();\n this.pendingMessages.clear();\n this.requestCallbacks = {};\n this.scriptLoadPromises.clear();\n // Remove from global scope if this is the singleton\n var globalScope = getGlobalScope();\n if ((globalScope === null || globalScope === void 0 ? void 0 : globalScope[MESSENGER_GLOBAL_KEY]) === this) {\n delete globalScope[MESSENGER_GLOBAL_KEY];\n }\n };\n return BaseWindowMessenger;\n}());\n_a = MESSENGER_BRAND;\n/**\n * Type guard: checks whether a value is a BaseWindowMessenger instance.\n */\nfunction isWindowMessenger(value) {\n return (typeof value === 'object' &&\n value !== null &&\n MESSENGER_BRAND in value &&\n value[MESSENGER_BRAND] === true);\n}\n/**\n * Get or create a singleton BaseWindowMessenger instance.\n * Ensures only one messenger (and one message listener) exists per page,\n * preventing duplicate script loads and double notifications.\n *\n * The singleton is stored on globalScope under the same MESSENGER_KEY.\n * The branded property check verifies the stored value is actually a messenger.\n */\nexport function getOrCreateWindowMessenger(options) {\n var globalScope = getGlobalScope();\n var existing = globalScope === null || globalScope === void 0 ? void 0 : globalScope[MESSENGER_GLOBAL_KEY];\n if (isWindowMessenger(existing)) {\n return existing;\n }\n var messenger = new BaseWindowMessenger(options);\n if (globalScope) {\n globalScope[MESSENGER_GLOBAL_KEY] = messenger;\n }\n return messenger;\n}\n//# sourceMappingURL=base-window-messenger.js.map","/* eslint-disable no-restricted-globals */\n/**\n * Dynamically loads an external script by appending a <script> tag to the document head.\n * Deduplicates by checking if a script with the same src already exists.\n */\nexport var asyncLoadScript = function (url) {\n // Dedup: if a script with this src already exists, resolve immediately\n var existing = document.querySelector(\"script[src=\\\"\".concat(CSS.escape(url), \"\\\"]\"));\n if (existing) {\n return Promise.resolve({ status: true });\n }\n return new Promise(function (resolve, reject) {\n var _a;\n try {\n var scriptElement = document.createElement('script');\n scriptElement.type = 'text/javascript';\n scriptElement.async = true;\n scriptElement.src = url;\n scriptElement.addEventListener('load', function () {\n resolve({ status: true });\n }, { once: true });\n scriptElement.addEventListener('error', function () {\n reject({\n status: false,\n message: \"Failed to load the script \".concat(url),\n });\n });\n /* istanbul ignore next */\n (_a = document.head) === null || _a === void 0 ? void 0 : _a.appendChild(scriptElement);\n }\n catch (error) {\n /* istanbul ignore next */\n reject(error);\n }\n });\n};\n/**\n * Generates a simple unique ID for message request/response correlation.\n */\nexport function generateUniqueId() {\n return \"\".concat(Date.now(), \"-\").concat(Math.random().toString(36).substr(2, 9));\n}\n//# sourceMappingURL=utils.js.map","import { AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL } from './constants';\n/**\n * Brand key set on the messenger instance to track whether background capture\n * has been enabled.\n */\nvar BG_CAPTURE_BRAND = '__AMPLITUDE_BACKGROUND_CAPTURE__';\n/**\n * Enable background capture on a messenger instance.\n * Plugins can call this on a shared messenger instance.\n * The first call registers the handlers; subsequent calls are no-ops.\n *\n * @param messenger - The messenger to enable background capture on\n * @param options.scriptUrl - Override the background capture script URL (optional)\n */\nexport function enableBackgroundCapture(messenger, options) {\n var _a;\n // Check the brand on the messenger object itself — works across bundle boundaries\n var branded = messenger;\n if (branded[BG_CAPTURE_BRAND] === true) {\n return;\n }\n branded[BG_CAPTURE_BRAND] = true;\n var scriptUrl = (_a = options === null || options === void 0 ? void 0 : options.scriptUrl) !== null && _a !== void 0 ? _a : AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL;\n var backgroundCaptureInstance = null;\n var onBackgroundCapture = function (type, backgroundCaptureData) {\n var _a, _b;\n if (type === 'background-capture-complete') {\n (_b = (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'Background capture complete');\n messenger.notify({ action: 'background-capture-complete', data: backgroundCaptureData });\n }\n };\n messenger.registerActionHandler('initialize-background-capture', function () {\n var _a, _b;\n (_b = (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'Initializing background capture (external script)');\n var resolvedUrl = new URL(scriptUrl, messenger.endpoint).toString();\n messenger\n .loadScriptOnce(resolvedUrl)\n .then(function () {\n var _a, _b, _c;\n (_b = (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'Background capture script loaded (external)');\n // eslint-disable-next-line\n backgroundCaptureInstance = /* istanbul ignore next -- window is always defined in browser */ (_c = window === null || window === void 0 ? void 0 : window.amplitudeBackgroundCapture) === null || _c === void 0 ? void 0 : _c.call(window, {\n messenger: messenger,\n onBackgroundCapture: onBackgroundCapture,\n });\n messenger.notify({ action: 'background-capture-loaded' });\n })\n .catch(function () {\n var _a;\n (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.warn('Failed to initialize background capture');\n });\n });\n messenger.registerActionHandler('close-background-capture', function () {\n var _a;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n (_a = backgroundCaptureInstance === null || backgroundCaptureInstance === void 0 ? void 0 : backgroundCaptureInstance.close) === null || _a === void 0 ? void 0 : _a.call(backgroundCaptureInstance);\n backgroundCaptureInstance = null;\n });\n}\n//# sourceMappingURL=background-capture.js.map","import { AMPLITUDE_PREFIX, ServerZone } from '@amplitude/analytics-core';\n\nexport const DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';\n\nexport const DEFAULT_SESSION_REPLAY_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay ID`;\nexport const DEFAULT_SESSION_START_EVENT = 'session_start';\nexport const DEFAULT_SESSION_END_EVENT = 'session_end';\nexport const DEFAULT_SAMPLE_RATE = 0;\nexport const DEFAULT_SERVER_ZONE = ServerZone.US;\nexport const DEFAULT_PERFORMANCE_CONFIG = { enabled: true };\nexport const DEFAULT_URL_CHANGE_POLLING_INTERVAL = 1000;\n\nexport const SESSION_REPLAY_DEBUG_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay Debug`;\n\nexport const BLOCK_CLASS = 'amp-block';\nexport const MASK_TEXT_CLASS = 'amp-mask';\nexport const UNMASK_TEXT_CLASS = 'amp-unmask';\nexport const SESSION_REPLAY_SERVER_URL = 'https://api-sr.amplitude.com/sessions/v2/track';\nexport const SESSION_REPLAY_EU_URL = 'https://api-sr.eu.amplitude.com/sessions/v2/track';\nexport const SESSION_REPLAY_STAGING_URL = 'https://api-sr.stag2.amplitude.com/sessions/v2/track';\nexport const STORAGE_PREFIX = `${AMPLITUDE_PREFIX}_replay_unsent`;\n// Raw (uncompressed) UTF-8 byte cap for a single batched events list before the store splits\n// it into its own request. Larger batches mean fewer requests — the primary steady-state lever\n// for request volume — while the time-based flush (flushIntervalConfig) still controls send\n// cadence, so this only decides whether a single high-activity flush gets split into multiple\n// requests. Set to 2 MB: gzipped on the wire that's ~0.2 MB, far under the SR ingest service's\n// 10,000,000-byte decompressed split threshold (nova SessionReplayServletV2 splits batches above\n// it server-side and only 413s a single >10 MB event), and well clear of the ~10-30% wrapper/\n// JSON-escaping overhead. Kept at 2 MB (not higher) so it stays a safe POST body on the\n// no-CompressionStream fallback path (raw == wire there) and keeps per-session memory/IDB\n// buffering modest on low-end devices. A smaller cap (e.g. 700 KB) splits busy-page flushes\n// into several more requests/session and drives SR ingest request-rate throttling.\nexport const MAX_EVENT_LIST_SIZE = 2_000_000;\n// Default raw (uncompressed) UTF-8 byte cap for a single buffered events list when the\n// consumer does not set `maxPersistedEventsSizeBytes`. Set to 6 MB — the value validated in\n// the amp-on-amp canary (appid 187520, session-replay-sdk-perf-config onenav-prod payload):\n// larger batches mean fewer requests and materially less SR ingest request-rate throttling\n// (rc3 0.02% throttle vs prod 1.31.0 2.95%) while staying under the server's 10 MB\n// decompressed split threshold. Kept distinct from MAX_EVENT_LIST_SIZE (2 MB) because that\n// constant is still used to derive MERGE_AFTER_THROTTLE_SOFT_CAP and as a documented per-batch\n// reference; this constant only governs the default buffer cap. Reverses PR #1814's 2 MB default.\nexport const DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES = 6_000_000;\n// 9 MB UTF-8 bytes — just under the server's 10 MB per-event threshold. Compared against the\n// UTF-8 byte length of the serialized event (via Blob/TextEncoder), not the JS string length,\n// so multi-byte payloads (CJK, emoji) are gated correctly.\nexport const MAX_SINGLE_EVENT_SIZE = 9 * 1000000;\n// WAF rejects oversized compressed payloads with a body containing wording like\n// \"Payload exceeds the maximum allowed size of 10MB\". Match loosely so vendor wording\n// tweaks (rule updates, capitalization, etc.) don't silently disable bisect-retry.\nexport const WAF_PAYLOAD_TOO_LARGE_PATTERN = /payload.*exceed/i;\nexport const INTERACTION_MIN_INTERVAL = 30_000; // 30 seconds\nexport const INTERACTION_MAX_INTERVAL = 60_000; // 1 minute\nexport const MIN_INTERVAL = 500; // 500 ms\nexport const MAX_INTERVAL = 10 * 1000; // 10 seconds\n// Default flush-interval bounds applied when the consumer does not pass `flushIntervalConfig`.\n// Set to the values validated in the amp-on-amp canary (session-replay-sdk-perf-config\n// onenav-prod payload, SR-4646): a 1s floor (up from the MIN_INTERVAL 500ms hard floor) reduces\n// request volume on busy pages while the 10s ceiling matches MAX_INTERVAL. MIN_INTERVAL/\n// MAX_INTERVAL remain the absolute clamp bounds and partial-config cross-validation defaults.\nexport const DEFAULT_FLUSH_MIN_INTERVAL_MS = 1000; // 1 second\nexport const DEFAULT_FLUSH_MAX_INTERVAL_MS = 10 * 1000; // 10 seconds\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days\nexport const KB_SIZE = 1024;\nexport const MAX_URL_LENGTH = 1000;\nexport const RETRY_TIMEOUT_MS = 1000;\nexport const MAX_KEEPALIVE_BYTES = 64 * 1024; // browser keepalive budget shared with sendBeacon\n// Per-request send timeout. fetch() has no native timeout, so a single hung request\n// (stuck \"pending\" forever) would otherwise block the serial flush loop indefinitely —\n// head-of-line blocking that stalls every queued batch behind it. We abort after this\n// many ms so each send always settles and the queue keeps draining.\nexport const SEND_TIMEOUT_MS = 10_000;\n\n// Server returns 200 + this header for \"no-retry\" drops (throttle / capture disabled / out-of-range).\n// See projects/sessionreplay/sessionreplay-ingestion/.../SessionReplayError.java.\n// Header value is the numeric error code as a string.\nexport const EVENT_SKIPPED_HEADER = 'X-Session-Replay-Event-Skipped';\nexport const EVENT_SKIP_CODE_THROTTLED = '429';\nexport const EVENT_SKIP_CODE_INVALID_RANGE = '4004';\nexport const EVENT_SKIP_CODE_CAPTURE_DISABLED = '4005';\n// How long to pause the flush schedule after the server signals a throttle.\nexport const THROTTLED_FLUSH_PAUSE_MS = 60_000;\n// Soft UTF-8 byte cap for merging same-session contexts after a throttle pause.\n// Set to 2 * MAX_EVENT_LIST_SIZE so we'll merge at most ~2 max-size sequences (or many\n// small ones) into one POST — fewer requests during recovery without pushing close to\n// the server's 10MB-compressed 413 ceiling. Compared against UTF-8 byte size (via Blob)\n// to match the per-sequence limit's units enforced upstream by base-events-store.\nexport const MERGE_AFTER_THROTTLE_SOFT_CAP = 2 * MAX_EVENT_LIST_SIZE;\n\nexport const CROSS_ORIGIN_IFRAME_MESSAGE_TYPE = 'amplitude-sr-iframe';\n\nexport enum CustomRRwebEvent {\n GET_SR_PROPS = 'get-sr-props',\n DEBUG_INFO = 'debug-info',\n FETCH_REQUEST = 'fetch-request',\n METADATA = 'metadata',\n TARGETING_DECISION = 'targeting-decision',\n /**\n * Emitted once per session, on the first send that passes the min_session_duration_ms\n * gate. Captures how many sends were suppressed before passing and the elapsed time\n * spent below the threshold. Lets backend ingestion diff intended replay count vs\n * actual ingestion so on-call can spot start-time-tracking regressions.\n *\n * Sessions that bounce before crossing the threshold never emit this event by design\n * (the whole payload is suppressed); their absence is the signal.\n */\n REPLAY_GATE_DECISION = 'replay-gate-decision',\n}\n","import { ILogger, LogLevel } from '@amplitude/analytics-core';\n\nexport class SafeLoggerProvider implements ILogger {\n private logger: ILogger;\n\n log: typeof console.log;\n warn: typeof console.warn;\n error: typeof console.error;\n debug: typeof console.debug;\n\n constructor(loggerProvider: ILogger) {\n this.logger = loggerProvider;\n this.log = this.getSafeMethod('log');\n this.warn = this.getSafeMethod('warn');\n this.error = this.getSafeMethod('error');\n this.debug = this.getSafeMethod('debug');\n }\n\n private getSafeMethod<K extends keyof ILogger>(method: K): ILogger[K] {\n if (!this.logger) {\n return (() => {\n // No-op function fallback\n }) as ILogger[K];\n }\n\n const fn = this.logger[method];\n if (typeof fn === 'function') {\n const originalFn = (fn as { __rrweb_original__?: ILogger[K] }).__rrweb_original__ ?? fn;\n return originalFn.bind(this.logger) as ILogger[K];\n }\n\n return (() => {\n // No-op function fallback\n }) as ILogger[K];\n }\n\n enable(logLevel: LogLevel) {\n this.logger.enable(logLevel);\n }\n\n disable() {\n this.logger.disable();\n }\n}\n","import { IConfig, LogLevel, ILogger, IDiagnosticsClient } from '@amplitude/analytics-core';\nimport { StoreType, ConsoleLogLevel } from '../typings/session-replay';\nimport { TargetingFlag } from '@amplitude/targeting';\n\nexport interface SamplingConfig {\n sample_rate: number;\n capture_enabled: boolean;\n min_session_duration_ms?: number;\n}\n\nexport interface InteractionConfig {\n trackEveryNms?: number;\n enabled: boolean; // defaults to false\n batch: boolean; // defaults to false\n /**\n * UGC filter rules.\n */\n ugcFilterRules?: UGCFilterRule[];\n}\n\nexport interface LoggingConfig {\n console: {\n enabled: boolean;\n levels: ConsoleLogLevel[];\n };\n network?: {\n enabled: boolean;\n body?: {\n request?: boolean;\n response?: boolean;\n maxBodySizeBytes?: number;\n };\n };\n}\n\nexport type TargetingConfig = TargetingFlag;\n\nexport type SessionReplayRemoteConfig = {\n sr_sampling_config?: SamplingConfig;\n sr_privacy_config?: PrivacyConfig;\n sr_interaction_config?: InteractionConfig;\n sr_logging_config?: LoggingConfig;\n sr_targeting_config?: TargetingConfig;\n};\n\nexport interface SessionReplayRemoteConfigAPIResponse {\n configs: {\n sessionReplay: SessionReplayRemoteConfig;\n };\n}\n\nexport type MaskLevel =\n | 'light' // only mask a subset of inputs that's deemed sensitive - password, credit card, telephone #, email. These are information we never want to capture.\n | 'medium' // mask all form fields (inputs); page text is captured as-is\n | 'conservative'; // mask all inputs and all texts\n\nexport const DEFAULT_MASK_LEVEL = 'medium';\n\n// err on the side of excluding more\nexport type PrivacyConfig = {\n blockSelector?: string | string[]; // exclude in the UI\n defaultMaskLevel?: MaskLevel;\n maskSelector?: string[];\n unmaskSelector?: string[];\n maskAttributes?: string[]; // HTML attribute names to mask (e.g. [\"placeholder\", \"aria-label\"])\n /**\n * Per-URL overrides for `defaultMaskLevel`. Each entry contains a glob pattern (`match`)\n * and a `maskLevel` to apply when the current page URL matches that pattern.\n * Rules are evaluated in order; the first match wins. Remote rules take precedence\n * over local rules (remote entries are prepended before local entries).\n *\n * @example\n * urlMaskLevels: [\n * { match: 'https://example.com/checkout/*', maskLevel: 'conservative' },\n * { match: 'https://example.com/public/*', maskLevel: 'light' },\n * ]\n */\n urlMaskLevels?: Array<{ match: string; maskLevel: MaskLevel }>;\n};\n\n/**\n * UGC filter rule.\n */\nexport type UGCFilterRule = {\n /**\n * The selector of the UGC element.\n */\n selector: string;\n /**\n * The replacement text for the UGC element.\n */\n replacement: string;\n};\n\nexport interface CrossOriginIframesConfig {\n enabled: boolean;\n /**\n * When true (default), the parent SDK sends start/stop signals to child iframes via\n * postMessage, keeping their recording lifecycle in sync with the parent.\n *\n * **Privacy note:** The child page's rrweb instance performs its own DOM serialization,\n * so the parent's privacy config (mask levels, block selectors) does NOT automatically\n * apply inside the iframe. Privacy settings must be configured independently on the child page.\n *\n * **Third-party iframes:** Cannot capture iframes you don't control (e.g. Stripe, Google\n * Maps) — both parent and child pages must load the SDK with `crossOriginIframes.enabled: true`.\n *\n * Set to `false` to skip coordination and manage the child recording lifecycle yourself.\n * @defaultValue true\n */\n coordinateChildren?: boolean;\n}\n\nexport interface SessionReplayLocalConfig extends IConfig {\n apiKey: string;\n loggerProvider: ILogger;\n /**\n * Optional diagnostics client used to ship SR decision/targeting telemetry to Amplitude's\n * diagnostics backend (independent of whether a replay is recorded). In plugin mode this is\n * forwarded from the analytics SDK's already-initialized client. No-op when absent or when\n * diagnostics is not sampled in. See DiagnosticsClient in @amplitude/analytics-core.\n */\n diagnosticsClient?: IDiagnosticsClient;\n /**\n * Standalone SR only: when no `diagnosticsClient` is provided (i.e. SR is not running as the\n * analytics plugin), opt in to having SR create its own client so TRC/recording diagnostics are\n * still shipped. Ignored when a `diagnosticsClient` is supplied. @defaultValue false\n */\n diagnosticsEnabled?: boolean;\n /**\n * Standalone SR only: sample rate (0..1) for the diagnostics client SR creates when none is\n * provided. A positive value also implies opting in. @defaultValue 0\n */\n diagnosticsSampleRate?: number;\n /**\n * LogLevel.None or LogLevel.Error or LogLevel.Warn or LogLevel.Verbose or LogLevel.Debug.\n * Sets the log level.\n *\n * @defaultValue LogLevel.Warn\n */\n logLevel: LogLevel;\n /**\n * The maximum number of retries allowed for sending replay events.\n * Once this limit is reached, failed events will no longer be sent.\n *\n * @defaultValue 2\n */\n flushMaxRetries: number;\n /**\n * Use this option to control how many sessions to select for replay collection.\n * The number should be a decimal between 0 and 1, for example 0.4, representing\n * the fraction of sessions to have randomly selected for replay collection.\n * Over a large number of sessions, 0.4 would select 40% of those sessions.\n * Sample rates as small as six decimal places (0.000001) are supported.\n *\n * @defaultValue 0\n */\n sampleRate: number;\n privacyConfig?: PrivacyConfig;\n /**\n * Adds additional debug event property to help debug instrumentation issues\n * (such as mismatching apps). Only recommended for debugging initial setup,\n * and not recommended for production.\n */\n debugMode?: boolean;\n /**\n * Specifies the endpoint URL to fetch remote configuration.\n * If provided, it overrides the default server zone configuration.\n */\n configServerUrl?: string;\n /**\n * Specifies the endpoint URL for sending session replay data.\n * If provided, it overrides the default server zone configuration.\n */\n trackServerUrl?: string;\n /**\n * If stylesheets are inlined, the contents of the stylesheet will be stored.\n * During replay, the stored stylesheet will be used instead of attempting to fetch it remotely.\n * This prevents replays from appearing broken due to missing stylesheets.\n * Note: Inlining stylesheets may not work in all cases.\n */\n shouldInlineStylesheet?: boolean;\n version?: SessionReplayVersion;\n /**\n * Performance configuration config. If enabled, we will defer compression\n * to be done during the browser's idle periods.\n */\n performanceConfig?: SessionReplayPerformanceConfig;\n /**\n * Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events\n * when all events cannot be sent during capture. `memory` stores replay events only in memory,\n * meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.\n *\n * @defaultValue 'memory' — reflects the validated amp-on-amp perf config (SR-4646). `memory`\n * drops cross-navigation persistence (unsent events do not survive a full page reload), which\n * is the intended trade-off for lower IDB overhead.\n */\n storeType: StoreType;\n\n /**\n * If true, the SDK will compress replay events using a web worker.\n * This offloads compression to a separate thread, improving performance on the main thread.\n * Set to `false` to keep compression on the main thread.\n *\n * @defaultValue true — reflects the validated amp-on-amp perf config (SR-4646). Was `false`\n * prior to that change.\n */\n useWebWorker?: boolean;\n\n /**\n * Controls transport-layer gzip compression of session replay request bodies.\n * When true (default), the SDK gzip-compresses the JSON request body via the browser's\n * `CompressionStream` API and sets `Content-Encoding: gzip` on the POST. When false,\n * the SDK sends the raw JSON body with no `Content-Encoding` header.\n *\n * Disabling is intended as a debugging / safety opt-out (e.g. for diagnosing\n * server-side decompression issues); it increases egress bytes and is not\n * recommended for production.\n *\n * Note: This is independent of `useWebWorker` / `performanceConfig`, which control\n * per-event rrweb compression that runs before events are queued.\n *\n * @defaultValue true\n */\n enableTransportCompression?: boolean;\n\n /**\n * Milliseconds to wait for a send request before aborting it. `fetch()` has no native\n * timeout, so a request stuck \"pending\" would block the serial flush loop indefinitely;\n * the SDK aborts after this many ms and routes the abort as a retryable failure.\n *\n * Set to `0` (or a negative value) to disable the timeout entirely — note this\n * reintroduces the head-of-line-blocking risk a wedged request can cause, so it is\n * intended only as a diagnostic/experiment opt-out.\n *\n * Tuning this higher is useful when large, slow-but-succeeding uploads are being aborted\n * at the default and counted as failures (which also triggers a retry, inflating request\n * volume / throttle pressure).\n *\n * @defaultValue 10000\n */\n sendTimeoutMs?: number;\n\n userProperties?: { [key: string]: any };\n\n /**\n * If true, applies a background color to blocked elements in the replay.\n * This helps visualize which elements are blocked from being captured.\n */\n applyBackgroundColorToBlockedElements?: boolean;\n /**\n * Enables URL change polling as a fallback for SPA route tracking.\n * When enabled, the SDK will periodically check for URL changes every second\n * in addition to patching the History API. This is useful for edge cases where\n * route changes might bypass the standard History API methods.\n *\n * @defaultValue false\n */\n enableUrlChangePolling?: boolean;\n /**\n * Specifies the interval in milliseconds for URL change polling when enableUrlChangePolling is true.\n * The SDK will check for URL changes at this interval as a fallback for SPA route tracking.\n *\n * @defaultValue 1000\n */\n urlChangePollingInterval?: number;\n /**\n * Whether to capture document title in URL change events.\n * When disabled, the title field will be empty in URL change events.\n *\n * @defaultValue false\n */\n captureDocumentTitle?: boolean;\n interactionConfig?: InteractionConfig;\n /**\n * When true (default), the CSS rules of any `adoptedStyleSheets` on shadow roots and\n * the document are serialized **inline** within the full snapshot. This makes the snapshot\n * self-contained so that shadow DOM styles are replayed correctly even if subsequent\n * incremental `AdoptedStyleSheet` events are dropped in transit.\n *\n * Set to `false` to revert to the legacy behavior where adopted stylesheet rules are\n * emitted as separate incremental events (which may be lost if delivery is unreliable).\n * Only consider opting out if snapshot payload size is a critical concern.\n *\n * @defaultValue true\n */\n captureAdoptedStyleSheets?: boolean;\n /**\n * Enables recording of cross-origin iframes. Both the parent page and each child iframe\n * page must load the Amplitude Session Replay SDK with this option enabled.\n *\n * When enabled, rrweb uses `postMessage` to relay child DOM events to the parent, which\n * merges them into a single unified event stream.\n */\n crossOriginIframes?: CrossOriginIframesConfig;\n /** Interval in ms at which the SDK takes a full DOM snapshot. Disabled by default — periodic snapshots are expensive. Recommended value: 300000 (5 min). */\n fullSnapshotIntervalMs?: number;\n /**\n * Controls how often the SDK splits buffered rrweb events into a sequence and dispatches\n * the resulting batch to the server. The interval starts at `minIntervalMs` and grows by\n * `minIntervalMs` after each split, capped at `maxIntervalMs`. Lowering values increases\n * replay availability latency improvements at the cost of more requests; raising them\n * reduces request volume (and 200+`X-Session-Replay-Event-Skipped` throttling responses)\n * at the cost of slightly delayed replay availability.\n *\n * Defaults to `{ minIntervalMs: 1000, maxIntervalMs: 10_000 }`, reflecting the validated\n * amp-on-amp perf config (SR-4646); the `minIntervalMs` default was `500` prior to that\n * change. Tune up if the server is back-pressuring the SDK on session start.\n */\n flushIntervalConfig?: FlushIntervalConfig;\n /**\n * When true, every rrweb full snapshot is flushed to the server immediately so replays\n * become playable as early as possible. When false (default), full-snapshot sends are\n * deferred to the normal interval/size flush cadence instead. The snapshot is still\n * compressed and buffered immediately either way (ordering and page-exit beacon coverage\n * are preserved); only the eager network send is suppressed. The default-off behavior\n * reduces request volume for pages that produce many full snapshots (e.g. focus-driven or\n * `fullSnapshotIntervalMs` checkouts), especially when many SDK instances run on the same\n * page.\n *\n * @defaultValue false — reflects the validated amp-on-amp perf config (SR-4646). Was `true`\n * prior to that change.\n */\n eagerFullSnapshotSend?: boolean;\n /**\n * When true, the window `focus` listener forces a fresh rrweb full snapshot\n * (`takeFullSnapshot`) every time the page regains focus, so the replay reflects any DOM\n * changes that happened while the tab was backgrounded. When false (default), the on-focus\n * full snapshot is skipped entirely (recording simply continues from the existing stream).\n *\n * On pages with heavy focus churn (e.g. embedded iframes, inline editors that repeatedly\n * steal and return focus) this fires constantly, and when combined with\n * `eagerFullSnapshotSend` each focus produces an immediate network send — the primary\n * driver of focus-driven request storms. The default-off behavior removes the snapshot (and\n * therefore the send) at the cost of slightly staler post-focus frames.\n *\n * @defaultValue false — reflects the validated amp-on-amp perf config (SR-4646). Was `true`\n * prior to that change.\n */\n captureFullSnapshotOnFocus?: boolean;\n /**\n * Raw (uncompressed) UTF-8 byte cap for a single buffered events list before the store\n * splits it into its own request. Larger values produce fewer, larger requests (the primary\n * steady-state lever for request volume); smaller values split sooner. Payloads are gzipped\n * on the wire, so several hundred KB of replay JSON compresses to well under 100 KB.\n *\n * Advanced/debug knob — the default already balances request volume against the server's\n * decompressed-size split threshold. Clamped to a safe range; values outside it are clamped\n * and logged. Defaults to the SDK's internal `DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES`.\n *\n * @defaultValue 6000000 — reflects the validated amp-on-amp perf config (SR-4646). Was\n * `MAX_EVENT_LIST_SIZE` (2000000) prior to that change.\n */\n maxPersistedEventsSizeBytes?: number;\n /**\n * Raw (uncompressed) UTF-8 byte cap for a single rrweb event. Events larger than this are\n * dropped (with a warning) both at capture time and as a pre-send backstop, because the SR\n * ingest service rejects a single event above ~10 MB. Lower this to exercise drop behavior\n * for large full snapshots while debugging.\n *\n * Advanced/debug knob. Clamped to a safe range; values outside it are clamped and logged.\n * Defaults to the SDK's internal `MAX_SINGLE_EVENT_SIZE`.\n *\n * @defaultValue 9000000\n */\n maxSingleEventSizeBytes?: number;\n}\n\nexport interface FlushIntervalConfig {\n /**\n * Lower bound on the rrweb event-split interval in milliseconds. Also the increment\n * added to the interval after each split. Must be > 0; values are clamped to a 100ms floor.\n *\n * @defaultValue 1000 — reflects the validated amp-on-amp perf config (SR-4646). Was `500`\n * prior to that change.\n */\n minIntervalMs?: number;\n /**\n * Upper bound on the rrweb event-split interval in milliseconds. Must be >= `minIntervalMs`.\n *\n * @defaultValue 10000\n */\n maxIntervalMs?: number;\n}\n\nexport interface SessionReplayJoinedConfig extends SessionReplayLocalConfig {\n captureEnabled?: boolean;\n interactionConfig?: InteractionConfig;\n loggingConfig?: LoggingConfig;\n targetingConfig?: TargetingConfig;\n minSessionDurationMs?: number;\n}\n\nexport interface SessionReplayConfigs {\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n remoteConfig: SessionReplayRemoteConfig | undefined;\n}\nexport interface SessionReplayJoinedConfigGenerator {\n generateJoinedConfig: () => Promise<SessionReplayConfigs>;\n}\n\nexport interface SessionReplayMetadata {\n remoteConfig: SessionReplayRemoteConfig | undefined;\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n framework?: {\n name: string;\n version: string;\n };\n sessionId: string | number | undefined;\n hashValue?: number;\n sampleRate: number;\n replaySDKType: string | null;\n replaySDKVersion: string | undefined;\n standaloneSDKType: string;\n standaloneSDKVersion: string | undefined;\n}\n\nexport interface SessionReplayVersion {\n version: string;\n type: SessionReplayType;\n}\n\n/**\n * Configuration options for session replay performance.\n */\nexport interface SessionReplayPerformanceConfig {\n /**\n * If enabled, event compression will be deferred to occur during the browser's idle periods.\n */\n enabled: boolean;\n /**\n * Optional timeout in milliseconds for the `requestIdleCallback` API.\n * If specified, this value will be used to set a maximum time for the browser to wait\n * before executing the deferred compression task, even if the browser is not idle.\n */\n timeout?: number;\n /**\n * If enabled, consecutive mutation events will be merged into a single event before\n * compression, reducing stored event count without changing replay semantics.\n * Defaults to true, reflecting the validated amp-on-amp perf config (SR-4646); set to\n * false to disable merging.\n */\n mergeMutations?: boolean;\n /**\n * Performance configuration for interaction tracking (clicks, scrolls).\n */\n interaction?: InteractionPerformanceConfig;\n}\n\n/**\n * Performance configuration for interaction tracking, specifically for CSS selector generation.\n */\nexport interface InteractionPerformanceConfig {\n /**\n * Maximum time in milliseconds allowed for CSS selector generation.\n * If selector generation takes longer than this, it will throw a timeout error.\n * Default: undefined (no timeout limit)\n */\n timeoutMs?: number;\n /**\n * Maximum number of attempts to optimize/simplify the CSS selector path.\n * Higher values may produce shorter selectors but take longer to compute.\n * Default: 10000\n */\n maxNumberOfTries?: number;\n /**\n * Maximum number of CSS selector combinations to test for uniqueness.\n * If more combinations would be generated, falls back to a simpler strategy.\n * Default: 1000\n */\n threshold?: number;\n}\n\nexport type SessionReplayType = 'standalone' | 'plugin' | 'segment';\n","import { SESSION_REPLAY_EU_URL, SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_STAGING_URL } from '../constants';\n\nexport function getServerUrl(serverZone?: string, trackServerUrl?: string): string {\n if (trackServerUrl) return trackServerUrl;\n if (serverZone === 'STAGING') return SESSION_REPLAY_STAGING_URL;\n if (serverZone === 'EU') return SESSION_REPLAY_EU_URL;\n return SESSION_REPLAY_SERVER_URL;\n}\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { DEFAULT_MASK_LEVEL, MaskLevel, PrivacyConfig, SessionReplayJoinedConfig, UGCFilterRule } from './config/types';\nimport { KB_SIZE, MASK_TEXT_CLASS, UNMASK_TEXT_CLASS } from './constants';\nimport { StorageData } from './typings/session-replay';\nimport { getInputType } from './utils/get-input-type';\nexport { getServerUrl } from './utils/server-url';\n\ntype ChromeStorageEstimate = {\n quota?: number;\n usage?: number;\n usageDetails?: { [key: string]: number };\n};\n\n/**\n * Light: Subset of inputs (sensitive types only — password, hidden, email, tel, cc-*)\n * Medium: All inputs (form fields), text is NOT masked\n * Conservative: All inputs and all texts\n */\nconst isMaskedForLevel = (elementType: 'input' | 'text', level: MaskLevel, element: HTMLElement | null): boolean => {\n switch (level) {\n case 'light': {\n if (elementType !== 'input') {\n return false;\n }\n\n const inputType = element ? getInputType(element) : '';\n /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.\n if (!inputType) {\n return false;\n }\n\n if (['password', 'hidden', 'email', 'tel'].includes(inputType)) {\n return true;\n }\n\n if ((element as HTMLInputElement).autocomplete.startsWith('cc-')) {\n return true;\n }\n\n return false;\n }\n case 'medium':\n return elementType === 'input';\n case 'conservative':\n return true;\n default:\n return isMaskedForLevel(elementType, DEFAULT_MASK_LEVEL, element);\n }\n};\n\n/**\n * Returns the effective mask level for a given URL by checking `urlMaskLevels`\n * (first match wins) and falling back to `defaultMaskLevel`.\n */\nexport const getEffectiveMaskLevel = (url: string | undefined, config: PrivacyConfig): MaskLevel => {\n if (url && config.urlMaskLevels) {\n for (const rule of config.urlMaskLevels) {\n if (globToRegex(rule.match).test(url)) {\n return rule.maskLevel;\n }\n }\n }\n return config.defaultMaskLevel ?? DEFAULT_MASK_LEVEL;\n};\n\n/**\n * Checks if the given element set to be masked by rrweb\n *\n * Priority is:\n * 1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking\n * 2. Use app defaults\n */\nexport const isMasked = (\n elementType: 'input' | 'text',\n config: PrivacyConfig = { defaultMaskLevel: DEFAULT_MASK_LEVEL },\n element: HTMLElement | null,\n currentUrl?: string,\n): boolean => {\n if (element) {\n // Element or parent is explicitly instrumented in code to mask\n if (element.closest('.' + MASK_TEXT_CLASS)) {\n return true;\n }\n\n // Config has override for mask\n const shouldMask = (config.maskSelector ?? []).some((selector) => element.closest(selector));\n if (shouldMask) {\n return true;\n }\n\n // Code or config has override to unmask\n if (element.closest('.' + UNMASK_TEXT_CLASS)) {\n return false;\n }\n\n // Here we are probably sent an element, but we want to match if they have a\n // parent with an unmask selector.\n const shouldUnmask = (config.unmaskSelector ?? []).some((selector) => element.closest(selector));\n if (shouldUnmask) {\n return false;\n }\n }\n\n return isMaskedForLevel(elementType, getEffectiveMaskLevel(currentUrl, config), element);\n};\n\nexport const maskFn =\n (elementType: 'text' | 'input', config?: PrivacyConfig, getCurrentUrl?: () => string) =>\n (text: string, element: HTMLElement | null): string => {\n return isMasked(elementType, config, element, getCurrentUrl?.()) ? text.replace(/[^\\s]/g, '*') : text;\n };\n\nexport const maskAttributeFn = (config?: PrivacyConfig, getCurrentUrl?: () => string) => {\n return (key: string, value: string, element: HTMLElement): string => {\n // Never mask style — rrweb has a separate styleDiff path for attribute mutations\n // that reads directly from the DOM, bypassing maskAttributeFn.\n if (key === 'style') return value;\n\n // Short-circuit: only proceed if this attribute is in the allowlist.\n if (!(config?.maskAttributes ?? []).includes(key)) return value;\n\n // Use 'input' for form elements so that `medium` (which masks inputs but not text)\n // still masks attributes on inputs/selects/textareas. For non-form elements, use\n // 'text' so medium leaves them visible.\n const elementType = ['INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) ? 'input' : 'text';\n return isMasked(elementType, config, element, getCurrentUrl?.()) ? value.replace(/[^\\s]/g, '*') : value;\n };\n};\n\nexport const getCurrentUrl = () => {\n const globalScope = getGlobalScope();\n return globalScope?.location ? globalScope.location.href : '';\n};\n\nexport const generateSessionReplayId = (sessionId: string | number, deviceId: string): string => {\n return `${deviceId}/${sessionId}`;\n};\n\nconst isValidGlobUrl = (globUrl: string): boolean => {\n if (typeof globUrl !== 'string' || globUrl.trim() === '') return false;\n const urlPattern = /^\\/|^https?:\\/\\/[^\\s]+$/;\n if (!urlPattern.test(globUrl)) return false;\n return true;\n};\n\nconst globRegexCache = new Map<string, RegExp>();\n\nconst globToRegex = (glob: string): RegExp => {\n const cached = globRegexCache.get(glob);\n if (cached) return cached;\n\n // Glob → regex conversion. Glob substitution must happen BEFORE regex escaping so that\n // the escaper does not corrupt the glob characters (e.g. turning `/**` into `/\\*\\*`).\n // Placeholder tokens use null bytes, which are illegal in HTTP URLs and therefore can\n // never collide with real pattern content.\n //\n // Substitution order (most-specific first):\n // trailing /** → (/.*)? — path with or without a trailing slash/subpath\n // middle /**/ → /(.*\\/)? — zero-or-more path segments (including zero)\n // bare ** → .* — graceful fallback for ** not adjacent to /\n // single * → .* — any characters (preserves existing behaviour)\n // ? → . — single character wildcard\n const T_TRAILING = '\\x00TRAIL\\x00';\n const T_MIDDLE = '\\x00MID\\x00';\n const T_DSTAR = '\\x00DS\\x00';\n const T_STAR = '\\x00ST\\x00';\n const T_QUEST = '\\x00QU\\x00';\n\n let s = glob;\n s = s.replace(/\\/\\*\\*$/, T_TRAILING); // trailing /**\n s = s.replace(/\\/\\*\\*\\//g, T_MIDDLE); // /**/ in the middle\n s = s.replace(/\\*\\*/g, T_DSTAR); // bare ** (e.g. **.example.com)\n s = s.replace(/\\*/g, T_STAR); // single *\n s = s.replace(/\\?/g, T_QUEST); // ?\n\n // Escape all remaining regex special characters.\n s = s.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Expand tokens into their regex equivalents.\n // Use split/join (not regex) to avoid the no-control-regex lint rule on the token strings.\n s = s.split(T_TRAILING).join('(/.*)?'); // /** → optional /anything\n s = s.split(T_MIDDLE).join('/(.*\\\\/)?'); // /**/ → /zero-or-more-segments/\n s = s.split(T_DSTAR).join('.*'); // bare ** → .*\n s = s.split(T_STAR).join('.*'); // * → .*\n s = s.split(T_QUEST).join('.'); // ? → .\n\n const regex = new RegExp(`^${s}$`);\n globRegexCache.set(glob, regex);\n return regex;\n};\n\nexport const validateUGCFilterRules = (ugcFilterRules: UGCFilterRule[]) => {\n // validate ugcFilterRules\n if (!ugcFilterRules.every((rule) => typeof rule.selector === 'string' && typeof rule.replacement === 'string')) {\n throw new Error('ugcFilterRules must be an array of objects with selector and replacement properties');\n }\n\n // validate ugcFilterRules are valid globs\n if (!ugcFilterRules.every((rule) => isValidGlobUrl(rule.selector))) {\n throw new Error('ugcFilterRules must be an array of objects with valid globs');\n }\n};\n\nexport const getPageUrl = (pageUrl: string, ugcFilterRules: UGCFilterRule[]) => {\n // apply ugcFilterRules, order is important, first rule wins\n for (const rule of ugcFilterRules) {\n const regex = globToRegex(rule.selector);\n\n if (regex.test(pageUrl)) {\n return pageUrl.replace(regex, rule.replacement);\n }\n }\n\n return pageUrl;\n};\n\nexport const getStorageSize = async (): Promise<StorageData> => {\n try {\n const globalScope = getGlobalScope();\n if (globalScope) {\n const { usage, quota, usageDetails }: ChromeStorageEstimate = await globalScope.navigator.storage.estimate();\n const totalStorageSize = usage ? Math.round(usage / KB_SIZE) : 0;\n const percentOfQuota = usage && quota ? Math.round((usage / quota + Number.EPSILON) * 1000) / 1000 : 0;\n return { totalStorageSize, percentOfQuota, usageDetails: JSON.stringify(usageDetails) };\n }\n } catch (e) {\n // swallow\n }\n return { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' };\n};\n\nexport const getDebugConfig = (config: SessionReplayJoinedConfig): SessionReplayJoinedConfig => {\n const debugConfig = {\n ...config,\n };\n const { apiKey } = debugConfig;\n debugConfig.apiKey = `****${apiKey.substring(apiKey.length - 4)}`;\n return debugConfig;\n};\n","export function toLowerCase<T extends string>(str: T): Lowercase<T> {\n return str.toLowerCase() as unknown as Lowercase<T>;\n}\n\n/**\n * Get the type of an input element.\n * This takes care of the case where a password input is changed to a text input.\n * In this case, we continue to consider this of type password, in order to avoid leaking sensitive data\n * where passwords should be masked.\n */\nexport function getInputType(element: HTMLElement): Lowercase<string> | null {\n // when omitting the type of input element(e.g. <input />), the type is treated as text\n const type = (element as HTMLInputElement).type;\n\n return element.hasAttribute('data-rr-is-password')\n ? 'password'\n : type\n ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n toLowerCase(type)\n : null;\n}\n","import {\n Config,\n ILogger,\n Logger,\n FetchTransport,\n LogLevel,\n IDiagnosticsClient,\n DiagnosticsClient,\n} from '@amplitude/analytics-core';\nimport {\n DEFAULT_FLUSH_MAX_INTERVAL_MS,\n DEFAULT_FLUSH_MIN_INTERVAL_MS,\n DEFAULT_PERFORMANCE_CONFIG,\n DEFAULT_SAMPLE_RATE,\n DEFAULT_SERVER_ZONE,\n DEFAULT_URL_CHANGE_POLLING_INTERVAL,\n MAX_INTERVAL,\n MIN_INTERVAL,\n UNMASK_TEXT_CLASS,\n} from '../constants';\nimport { SessionReplayOptions, StoreType } from '../typings/session-replay';\nimport {\n SessionReplayLocalConfig as ISessionReplayLocalConfig,\n CrossOriginIframesConfig,\n FlushIntervalConfig,\n InteractionConfig,\n PrivacyConfig,\n SessionReplayPerformanceConfig,\n SessionReplayVersion,\n} from './types';\nimport { SafeLoggerProvider } from '../logger';\nimport { validateUGCFilterRules } from '../helpers';\n\nexport const getDefaultConfig = () => ({\n flushMaxRetries: 2,\n logLevel: LogLevel.Warn,\n loggerProvider: new Logger(),\n transportProvider: new FetchTransport(),\n});\n\nexport class SessionReplayLocalConfig extends Config implements ISessionReplayLocalConfig {\n apiKey: string;\n sampleRate: number;\n privacyConfig?: PrivacyConfig;\n interactionConfig?: InteractionConfig;\n debugMode?: boolean;\n configServerUrl?: string;\n trackServerUrl?: string;\n shouldInlineStylesheet?: boolean;\n version?: SessionReplayVersion;\n storeType: StoreType;\n performanceConfig?: SessionReplayPerformanceConfig;\n useWebWorker?: boolean;\n enableTransportCompression?: boolean;\n sendTimeoutMs?: number;\n applyBackgroundColorToBlockedElements?: boolean;\n enableUrlChangePolling?: boolean;\n urlChangePollingInterval?: number;\n captureDocumentTitle?: boolean;\n captureAdoptedStyleSheets?: boolean;\n crossOriginIframes?: CrossOriginIframesConfig;\n fullSnapshotIntervalMs?: number;\n flushIntervalConfig?: FlushIntervalConfig;\n eagerFullSnapshotSend?: boolean;\n captureFullSnapshotOnFocus?: boolean;\n maxPersistedEventsSizeBytes?: number;\n maxSingleEventSizeBytes?: number;\n diagnosticsClient?: IDiagnosticsClient;\n diagnosticsEnabled?: boolean;\n diagnosticsSampleRate?: number;\n\n constructor(apiKey: string, options: SessionReplayOptions) {\n const defaultConfig = getDefaultConfig();\n super({\n transportProvider: defaultConfig.transportProvider,\n loggerProvider: new SafeLoggerProvider(options.loggerProvider || defaultConfig.loggerProvider),\n ...options,\n apiKey,\n });\n this.flushMaxRetries =\n options.flushMaxRetries !== undefined && options.flushMaxRetries <= defaultConfig.flushMaxRetries\n ? options.flushMaxRetries\n : defaultConfig.flushMaxRetries;\n\n this.apiKey = apiKey;\n this.sampleRate = options.sampleRate || DEFAULT_SAMPLE_RATE;\n this.serverZone = options.serverZone || DEFAULT_SERVER_ZONE;\n this.configServerUrl = options.configServerUrl;\n this.trackServerUrl = options.trackServerUrl;\n this.shouldInlineStylesheet = options.shouldInlineStylesheet;\n this.version = options.version;\n this.performanceConfig = options.performanceConfig || DEFAULT_PERFORMANCE_CONFIG;\n this.storeType = options.storeType ?? 'memory';\n this.applyBackgroundColorToBlockedElements = options.applyBackgroundColorToBlockedElements ?? false;\n this.enableUrlChangePolling = options.enableUrlChangePolling ?? false;\n this.urlChangePollingInterval = options.urlChangePollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n this.captureDocumentTitle = options.captureDocumentTitle ?? false;\n if (options.fullSnapshotIntervalMs !== undefined) {\n this.fullSnapshotIntervalMs = options.fullSnapshotIntervalMs;\n }\n if (options.eagerFullSnapshotSend !== undefined) {\n this.eagerFullSnapshotSend = options.eagerFullSnapshotSend;\n }\n // Defaults to false per the validated amp-on-amp perf config (SR-4646): the on-focus full\n // snapshot is off unless the consumer explicitly opts in. focusListener honors this by\n // skipping the snapshot whenever the value is not true.\n this.captureFullSnapshotOnFocus = options.captureFullSnapshotOnFocus ?? false;\n if (options.maxPersistedEventsSizeBytes !== undefined) {\n this.maxPersistedEventsSizeBytes = sanitizeByteSize(\n options.maxPersistedEventsSizeBytes,\n MIN_EVENT_BYTE_SIZE,\n MAX_PERSISTED_EVENTS_SIZE_CEILING,\n 'maxPersistedEventsSizeBytes',\n this.loggerProvider,\n );\n }\n if (options.maxSingleEventSizeBytes !== undefined) {\n this.maxSingleEventSizeBytes = sanitizeByteSize(\n options.maxSingleEventSizeBytes,\n MIN_EVENT_BYTE_SIZE,\n MAX_SINGLE_EVENT_SIZE_CEILING,\n 'maxSingleEventSizeBytes',\n this.loggerProvider,\n );\n }\n\n // Auto-include .amp-unmask as a default unmaskSelector entry so it works\n // symmetrically with amp-mask/amp-block without requiring explicit config (SR-2945).\n this.privacyConfig = {\n ...(options.privacyConfig ?? {}),\n unmaskSelector: Array.from(new Set([`.${UNMASK_TEXT_CLASS}`, ...(options.privacyConfig?.unmaskSelector ?? [])])),\n };\n if (options.interactionConfig) {\n this.interactionConfig = options.interactionConfig;\n\n // validate ugcFilterRules, throw error if invalid - throw error at the beginning of the config\n if (this.interactionConfig.ugcFilterRules) {\n validateUGCFilterRules(this.interactionConfig.ugcFilterRules);\n }\n }\n if (options.debugMode) {\n this.debugMode = options.debugMode;\n }\n // Support both new useWebWorker and legacy experimental.useWebWorker for backwards\n // compatibility. Defaults to true per the validated amp-on-amp perf config (SR-4646):\n // compression runs off the main thread unless the consumer explicitly sets either flag\n // to false. The top-level option wins over the legacy experimental one when both are set.\n const legacyOptions = options as { experimental?: { useWebWorker?: boolean } };\n this.useWebWorker = options.useWebWorker ?? legacyOptions.experimental?.useWebWorker ?? true;\n this.enableTransportCompression = options.enableTransportCompression ?? true;\n // Pass through undefined so the track destination applies its SEND_TIMEOUT_MS default;\n // an explicit 0 is preserved (disables the timeout).\n this.sendTimeoutMs = options.sendTimeoutMs;\n this.captureAdoptedStyleSheets = options.captureAdoptedStyleSheets ?? true;\n if (options.crossOriginIframes) {\n this.crossOriginIframes = options.crossOriginIframes;\n }\n if (options.flushIntervalConfig) {\n this.flushIntervalConfig = sanitizeFlushIntervalConfig(options.flushIntervalConfig, this.loggerProvider);\n } else {\n // Default to the validated amp-on-amp perf config (SR-4646). The values are known-valid\n // (min <= max, both above the floor), so no sanitization is required.\n this.flushIntervalConfig = {\n minIntervalMs: DEFAULT_FLUSH_MIN_INTERVAL_MS,\n maxIntervalMs: DEFAULT_FLUSH_MAX_INTERVAL_MS,\n };\n }\n this.diagnosticsEnabled = options.diagnosticsEnabled;\n this.diagnosticsSampleRate = options.diagnosticsSampleRate;\n // Single diagnostics client: in plugin mode the analytics SDK passes its own client in\n // (reused, not duplicated). Standalone SR has no analytics SDK, so create one here — but only\n // when explicitly opted in, to avoid imposing IndexedDB + flush-timer overhead on standalone\n // users who don't want diagnostics.\n this.diagnosticsClient = options.diagnosticsClient ?? this.createStandaloneDiagnosticsClient(apiKey, options);\n }\n\n private createStandaloneDiagnosticsClient(\n apiKey: string,\n options: SessionReplayOptions,\n ): IDiagnosticsClient | undefined {\n const { diagnosticsEnabled, diagnosticsSampleRate } = options;\n const optedIn =\n diagnosticsEnabled === true || (typeof diagnosticsSampleRate === 'number' && diagnosticsSampleRate > 0);\n if (!optedIn) {\n return undefined;\n }\n return new DiagnosticsClient(apiKey, this.loggerProvider, this.serverZone, {\n enabled: diagnosticsEnabled ?? true,\n sampleRate: diagnosticsSampleRate ?? 0,\n });\n }\n}\n\n// 100ms floor avoids degenerate configs (0/negative) that would split on every event.\n// Customers wanting fewer requests should be raising the value, not lowering it; the floor\n// is just a defensive guard against typos and unsigned-int rollovers.\nconst MIN_FLUSH_INTERVAL_FLOOR_MS = 100;\n\n// Shared 1 KB floor for the byte-size overrides — small enough to exercise splitting/drops\n// while debugging, large enough to avoid a 0/negative config that splits on every event.\nconst MIN_EVENT_BYTE_SIZE = 1_000;\n// Batch cap ceiling: stay under the SR ingest service's 10 MB decompressed split threshold\n// (above which the server splits the batch itself) with headroom for the request wrapper.\nconst MAX_PERSISTED_EVENTS_SIZE_CEILING = 8_000_000;\n// Single-event ceiling: the server rejects a single event above ~10 MB, so never allow an\n// override to exceed that.\nconst MAX_SINGLE_EVENT_SIZE_CEILING = 10_000_000;\n\n// Defensive bounds for the byte-size overrides. Non-finite inputs are ignored (fall back to\n// the SDK default); out-of-range values are clamped and logged so a typo can't silently\n// disable splitting or push past the server's limits.\nfunction sanitizeByteSize(\n raw: number,\n min: number,\n max: number,\n name: string,\n loggerProvider: ILogger,\n): number | undefined {\n if (!Number.isFinite(raw)) {\n loggerProvider.warn(`${name} value is not a finite number (got ${String(raw)}); ignoring.`);\n return undefined;\n }\n if (raw < min) {\n loggerProvider.warn(`${name} ${raw} is below floor ${min}; clamping.`);\n return min;\n }\n if (raw > max) {\n loggerProvider.warn(`${name} ${raw} exceeds ceiling ${max}; clamping.`);\n return max;\n }\n return raw;\n}\n\nfunction sanitizeFlushIntervalConfig(raw: FlushIntervalConfig, loggerProvider: ILogger): FlushIntervalConfig {\n const sanitized: FlushIntervalConfig = {};\n if (raw.minIntervalMs !== undefined) {\n if (!Number.isFinite(raw.minIntervalMs) || raw.minIntervalMs < MIN_FLUSH_INTERVAL_FLOOR_MS) {\n loggerProvider.warn(\n `flushIntervalConfig.minIntervalMs ${raw.minIntervalMs} is below floor ${MIN_FLUSH_INTERVAL_FLOOR_MS}ms; clamping.`,\n );\n sanitized.minIntervalMs = MIN_FLUSH_INTERVAL_FLOOR_MS;\n } else {\n sanitized.minIntervalMs = raw.minIntervalMs;\n }\n }\n if (raw.maxIntervalMs !== undefined) {\n // Unlike min, `Infinity` is a meaningful value here: it means \"no upper bound on interval\n // growth\" (Math.min(Infinity, x) === x in BaseEventsStore.shouldSplitEventsList). Reject\n // only NaN and sub-floor values; pass Infinity through.\n if (Number.isNaN(raw.maxIntervalMs) || raw.maxIntervalMs < MIN_FLUSH_INTERVAL_FLOOR_MS) {\n loggerProvider.warn(\n `flushIntervalConfig.maxIntervalMs ${raw.maxIntervalMs} is below floor ${MIN_FLUSH_INTERVAL_FLOOR_MS}ms; clamping.`,\n );\n sanitized.maxIntervalMs = MIN_FLUSH_INTERVAL_FLOOR_MS;\n } else {\n sanitized.maxIntervalMs = raw.maxIntervalMs;\n }\n }\n // Cross-validate against the SDK's effective defaults so that a partial config (only one of\n // {minIntervalMs, maxIntervalMs}) doesn't get silently clamped by the unspecified default.\n // Concrete failure mode without this: customer sets only `minIntervalMs: 30_000`, the store's\n // `maxInterval` falls back to `MAX_INTERVAL = 10_000`, and `shouldSplitEventsList` then\n // caps the effective interval at 10s — silently negating the customer's tune-up.\n // The user-supplied value always wins; we fill in the other side to match.\n if (sanitized.minIntervalMs !== undefined || sanitized.maxIntervalMs !== undefined) {\n const effectiveMin = sanitized.minIntervalMs ?? MIN_INTERVAL;\n const effectiveMax = sanitized.maxIntervalMs ?? MAX_INTERVAL;\n if (effectiveMax < effectiveMin) {\n if (sanitized.maxIntervalMs === undefined) {\n loggerProvider.warn(\n `flushIntervalConfig.minIntervalMs (${effectiveMin}) exceeds the default maxIntervalMs (${MAX_INTERVAL}); raising max to match min.`,\n );\n sanitized.maxIntervalMs = effectiveMin;\n } else if (sanitized.minIntervalMs === undefined) {\n loggerProvider.warn(\n `flushIntervalConfig.maxIntervalMs (${effectiveMax}) is below the default minIntervalMs (${MIN_INTERVAL}); lowering min to match max.`,\n );\n sanitized.minIntervalMs = effectiveMax;\n } else {\n loggerProvider.warn(\n `flushIntervalConfig.maxIntervalMs (${sanitized.maxIntervalMs}) is less than minIntervalMs (${sanitized.minIntervalMs}); raising max to match min.`,\n );\n sanitized.maxIntervalMs = sanitized.minIntervalMs;\n }\n }\n }\n return sanitized;\n}\n","var EventType = /* @__PURE__ */ ((EventType2) => {\n EventType2[EventType2[\"DomContentLoaded\"] = 0] = \"DomContentLoaded\";\n EventType2[EventType2[\"Load\"] = 1] = \"Load\";\n EventType2[EventType2[\"FullSnapshot\"] = 2] = \"FullSnapshot\";\n EventType2[EventType2[\"IncrementalSnapshot\"] = 3] = \"IncrementalSnapshot\";\n EventType2[EventType2[\"Meta\"] = 4] = \"Meta\";\n EventType2[EventType2[\"Custom\"] = 5] = \"Custom\";\n EventType2[EventType2[\"Plugin\"] = 6] = \"Plugin\";\n return EventType2;\n})(EventType || {});\nvar IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {\n IncrementalSource2[IncrementalSource2[\"Mutation\"] = 0] = \"Mutation\";\n IncrementalSource2[IncrementalSource2[\"MouseMove\"] = 1] = \"MouseMove\";\n IncrementalSource2[IncrementalSource2[\"MouseInteraction\"] = 2] = \"MouseInteraction\";\n IncrementalSource2[IncrementalSource2[\"Scroll\"] = 3] = \"Scroll\";\n IncrementalSource2[IncrementalSource2[\"ViewportResize\"] = 4] = \"ViewportResize\";\n IncrementalSource2[IncrementalSource2[\"Input\"] = 5] = \"Input\";\n IncrementalSource2[IncrementalSource2[\"TouchMove\"] = 6] = \"TouchMove\";\n IncrementalSource2[IncrementalSource2[\"MediaInteraction\"] = 7] = \"MediaInteraction\";\n IncrementalSource2[IncrementalSource2[\"StyleSheetRule\"] = 8] = \"StyleSheetRule\";\n IncrementalSource2[IncrementalSource2[\"CanvasMutation\"] = 9] = \"CanvasMutation\";\n IncrementalSource2[IncrementalSource2[\"Font\"] = 10] = \"Font\";\n IncrementalSource2[IncrementalSource2[\"Log\"] = 11] = \"Log\";\n IncrementalSource2[IncrementalSource2[\"Drag\"] = 12] = \"Drag\";\n IncrementalSource2[IncrementalSource2[\"StyleDeclaration\"] = 13] = \"StyleDeclaration\";\n IncrementalSource2[IncrementalSource2[\"Selection\"] = 14] = \"Selection\";\n IncrementalSource2[IncrementalSource2[\"AdoptedStyleSheet\"] = 15] = \"AdoptedStyleSheet\";\n IncrementalSource2[IncrementalSource2[\"CustomElement\"] = 16] = \"CustomElement\";\n return IncrementalSource2;\n})(IncrementalSource || {});\nvar MouseInteractions = /* @__PURE__ */ ((MouseInteractions2) => {\n MouseInteractions2[MouseInteractions2[\"MouseUp\"] = 0] = \"MouseUp\";\n MouseInteractions2[MouseInteractions2[\"MouseDown\"] = 1] = \"MouseDown\";\n MouseInteractions2[MouseInteractions2[\"Click\"] = 2] = \"Click\";\n MouseInteractions2[MouseInteractions2[\"ContextMenu\"] = 3] = \"ContextMenu\";\n MouseInteractions2[MouseInteractions2[\"DblClick\"] = 4] = \"DblClick\";\n MouseInteractions2[MouseInteractions2[\"Focus\"] = 5] = \"Focus\";\n MouseInteractions2[MouseInteractions2[\"Blur\"] = 6] = \"Blur\";\n MouseInteractions2[MouseInteractions2[\"TouchStart\"] = 7] = \"TouchStart\";\n MouseInteractions2[MouseInteractions2[\"TouchMove_Departed\"] = 8] = \"TouchMove_Departed\";\n MouseInteractions2[MouseInteractions2[\"TouchEnd\"] = 9] = \"TouchEnd\";\n MouseInteractions2[MouseInteractions2[\"TouchCancel\"] = 10] = \"TouchCancel\";\n return MouseInteractions2;\n})(MouseInteractions || {});\nvar PointerTypes = /* @__PURE__ */ ((PointerTypes2) => {\n PointerTypes2[PointerTypes2[\"Mouse\"] = 0] = \"Mouse\";\n PointerTypes2[PointerTypes2[\"Pen\"] = 1] = \"Pen\";\n PointerTypes2[PointerTypes2[\"Touch\"] = 2] = \"Touch\";\n return PointerTypes2;\n})(PointerTypes || {});\nvar CanvasContext = /* @__PURE__ */ ((CanvasContext2) => {\n CanvasContext2[CanvasContext2[\"2D\"] = 0] = \"2D\";\n CanvasContext2[CanvasContext2[\"WebGL\"] = 1] = \"WebGL\";\n CanvasContext2[CanvasContext2[\"WebGL2\"] = 2] = \"WebGL2\";\n return CanvasContext2;\n})(CanvasContext || {});\nvar MediaInteractions = /* @__PURE__ */ ((MediaInteractions2) => {\n MediaInteractions2[MediaInteractions2[\"Play\"] = 0] = \"Play\";\n MediaInteractions2[MediaInteractions2[\"Pause\"] = 1] = \"Pause\";\n MediaInteractions2[MediaInteractions2[\"Seeked\"] = 2] = \"Seeked\";\n MediaInteractions2[MediaInteractions2[\"VolumeChange\"] = 3] = \"VolumeChange\";\n MediaInteractions2[MediaInteractions2[\"RateChange\"] = 4] = \"RateChange\";\n return MediaInteractions2;\n})(MediaInteractions || {});\nvar ReplayerEvents = /* @__PURE__ */ ((ReplayerEvents2) => {\n ReplayerEvents2[\"Start\"] = \"start\";\n ReplayerEvents2[\"Pause\"] = \"pause\";\n ReplayerEvents2[\"Resume\"] = \"resume\";\n ReplayerEvents2[\"Resize\"] = \"resize\";\n ReplayerEvents2[\"Finish\"] = \"finish\";\n ReplayerEvents2[\"FullsnapshotRebuilded\"] = \"fullsnapshot-rebuilded\";\n ReplayerEvents2[\"LoadStylesheetStart\"] = \"load-stylesheet-start\";\n ReplayerEvents2[\"LoadStylesheetEnd\"] = \"load-stylesheet-end\";\n ReplayerEvents2[\"SkipStart\"] = \"skip-start\";\n ReplayerEvents2[\"SkipEnd\"] = \"skip-end\";\n ReplayerEvents2[\"MouseInteraction\"] = \"mouse-interaction\";\n ReplayerEvents2[\"EventCast\"] = \"event-cast\";\n ReplayerEvents2[\"CustomEvent\"] = \"custom-event\";\n ReplayerEvents2[\"Flush\"] = \"flush\";\n ReplayerEvents2[\"StateChange\"] = \"state-change\";\n ReplayerEvents2[\"PlayBack\"] = \"play-back\";\n ReplayerEvents2[\"Destroy\"] = \"destroy\";\n ReplayerEvents2[\"SeekStart\"] = \"seek-start\";\n ReplayerEvents2[\"SeekEnd\"] = \"seek-end\";\n return ReplayerEvents2;\n})(ReplayerEvents || {});\nvar NodeType = /* @__PURE__ */ ((NodeType2) => {\n NodeType2[NodeType2[\"Document\"] = 0] = \"Document\";\n NodeType2[NodeType2[\"DocumentType\"] = 1] = \"DocumentType\";\n NodeType2[NodeType2[\"Element\"] = 2] = \"Element\";\n NodeType2[NodeType2[\"Text\"] = 3] = \"Text\";\n NodeType2[NodeType2[\"CDATA\"] = 4] = \"CDATA\";\n NodeType2[NodeType2[\"Comment\"] = 5] = \"Comment\";\n return NodeType2;\n})(NodeType || {});\nexport {\n CanvasContext,\n EventType,\n IncrementalSource,\n MediaInteractions,\n MouseInteractions,\n NodeType,\n PointerTypes,\n ReplayerEvents\n};\n//# sourceMappingURL=rrweb-types.js.map\n","/**\n * Centralized names for Session Replay diagnostics shipped via the analytics DiagnosticsClient.\n *\n * Every name shares SR_DIAGNOSTIC_PREFIX so they group together in DataDog as\n * `sdk.diagnostics.sr.trc.*`. The diagnostics pipeline prepends `sdk.diagnostics.` and appends\n * `.count` to counters / `.{min,max,avg,count}` to histograms; events are forwarded to DataDog\n * Logs keyed by `event_name`. Keep ALL SR diagnostic names here so the prefix stays unified —\n * changing the namespace is then a one-line edit.\n */\nexport const SR_DIAGNOSTIC_PREFIX = 'sr.trc';\n\nconst p = SR_DIAGNOSTIC_PREFIX;\n\nexport const SrDiagnostic = {\n // ── Init (Q1: did init even happen?) ─────────────────────────────────────\n init: `${p}.init`, // counter + event(with props): fires once per init()\n\n // ── Session lifecycle ────────────────────────────────────────────────────\n // SR session id changed (timeout / explicit setSessionId / custom session id). New tabs and\n // page refreshes do NOT change the session id, so this is distinct from a fresh init.\n sessionChanged: `${p}.session.changed`, // event (with from/to)\n\n // ── Remote config fetch (joined-config) ──────────────────────────────────\n configSource: (source: string) => `${p}.config.source.${source}`,\n configHasTargeting: `${p}.config.has_targeting`,\n configNoTargeting: `${p}.config.no_targeting`,\n configFetchFailed: `${p}.config.fetch_failed`,\n configReceived: `${p}.config.received`, // event (with props)\n\n targetingTrigger: `${p}.targeting.trigger`, // event: targeting evaluation triggered\n\n // ── Targeting evaluation (evaluateTargetingAndCapture) ────────────────────\n // Q2 (did eval run?), Q3 (working/failed?), Q4 (missing value?), Q5 (all params).\n evalTrigger: (trigger: string) => `${p}.eval.${trigger}`, // init | urlchange | event\n evalNoConfig: `${p}.eval.no_config`,\n evalMissingPrereq: `${p}.eval.missing_prereq`, // Q4: sessionId/config/deviceId missing\n evalMatch: `${p}.eval.match`,\n evalNoMatch: `${p}.eval.no_match`,\n evalError: `${p}.eval.error`, // Q3: targeting engine threw\n evalStaleDiscarded: `${p}.eval.stale_discarded`,\n evalSkippedAlreadyMatched: `${p}.eval.skipped_already_matched`,\n evalDurationMs: `${p}.eval.duration_ms`, // histogram\n evalEvent: `${p}.eval`, // event (with ALL eval params — Q5)\n evalResult: `${p}.eval.result`, // event: raw engine verdict (variantKey) — why match/no-match\n\n // ── Recording execution (getShouldRecord said yes — did rrweb actually start?) ──\n recordStarted: `${p}.record.started`, // event: capture began (carries the srId the replay uploads under)\n recordNoRecordFn: `${p}.record.no_record_fn`, // counter + event: rrweb import returned nothing\n sendSuppressedMinDuration: `${p}.send.suppressed_min_duration`, // counter: events held back by min_session_duration\n\n // ── Record / no-record gate (getShouldRecord) ────────────────────────────\n gateNoIdentifiers: `${p}.gate.no_identifiers`, // Q4: no config/sessionId at gate time\n gateCaptureDisabled: `${p}.gate.capture_disabled`,\n gateOptOut: `${p}.gate.optout`,\n gateTrcMatch: `${p}.gate.trc_match`,\n gateTrcNoMatch: `${p}.gate.trc_no_match`,\n gateSampleIn: `${p}.gate.sample_in`,\n gateSampleOut: `${p}.gate.sample_out`,\n decision: `${p}.decision`, // event (with props)\n\n // ── SPA URL change (setupUrlChangeListener) ──────────────────────────────\n urlChange: `${p}.url_change`,\n urlChangeEvent: `${p}.url_change`, // event (with props); same name, logs vs metric\n // Was the URL-change listener even wired up? (covers \"the SDK never saw any navigation\"\n // because the listener was never attached — e.g. no targeting config, or no global scope.)\n urlListenerSetup: `${p}.url_listener.setup`, // event: the needsUrlTracking decision + its inputs\n urlListenerAttached: `${p}.url_listener.attached`, // event: subscribeToUrlChanges succeeded (with polling opts)\n urlListenerSkipped: `${p}.url_listener.skipped`, // counter + event: listener NOT attached (with reason)\n} as const;\n","import { ILogger, IRemoteConfigClient, RemoteConfigClient, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport { getDebugConfig } from '../helpers';\nimport { SrDiagnostic } from '../diagnostics';\nimport { SessionReplayOptions } from '../typings/session-replay';\nimport { SessionReplayLocalConfig } from './local-config';\nimport {\n SessionReplayLocalConfig as ISessionReplayLocalConfig,\n PrivacyConfig,\n SessionReplayConfigs,\n SessionReplayJoinedConfig,\n SessionReplayRemoteConfig,\n} from './types';\n\n// Budget for waiting on the remote config response before falling back to the local cache.\n// The inner fetch in analytics-core uses a 1000ms per-attempt AbortController timeout with\n// up to 3 retries — but this outer timeout is the only thing the SR plugin waits on, so\n// only the first attempt can possibly complete in time (attempt 2 starts at ~1000-1333ms\n// after backoff jitter and runs to ~2000-2333ms, well past any reasonable outer budget).\n// 1500ms is set above the 1000ms inner abort to avoid a tie with the inner cutoff and\n// give the first attempt's resolution path room to finish; everything else falls through\n// to the cache fallback. See SR-4234: prefer remote over a stale cache that would\n// otherwise win the synchronous race in 'all' mode.\nconst REMOTE_CONFIG_TIMEOUT_MS = 1500;\n\nexport const removeInvalidSelectorsFromPrivacyConfig = (privacyConfig: PrivacyConfig, loggerProvider: ILogger) => {\n // This allows us to not search the DOM.\n const fragment = document.createDocumentFragment();\n\n const dropInvalidSelectors = (selectors: string[] | string = []): string[] | undefined => {\n if (typeof selectors === 'string') {\n selectors = [selectors];\n }\n selectors = selectors.filter((selector: string) => {\n try {\n fragment.querySelector(selector);\n } catch {\n loggerProvider.warn(`[session-replay-browser] omitting selector \"${selector}\" because it is invalid`);\n return false;\n }\n return true;\n });\n if (selectors.length === 0) {\n return undefined;\n }\n return selectors;\n };\n privacyConfig.blockSelector = dropInvalidSelectors(privacyConfig.blockSelector);\n privacyConfig.maskSelector = dropInvalidSelectors(privacyConfig.maskSelector);\n privacyConfig.unmaskSelector = dropInvalidSelectors(privacyConfig.unmaskSelector);\n return privacyConfig;\n};\nexport class SessionReplayJoinedConfigGenerator {\n private readonly localConfig: ISessionReplayLocalConfig;\n private readonly remoteConfigClient: IRemoteConfigClient;\n // Identity for diagnostics correlation (config fetch is per-session). Sourced from init options.\n private readonly sessionId?: string | number;\n private readonly deviceId?: string;\n\n constructor(\n remoteConfigClient: IRemoteConfigClient,\n localConfig: ISessionReplayLocalConfig,\n identity?: { sessionId?: string | number; deviceId?: string },\n ) {\n this.localConfig = localConfig;\n this.remoteConfigClient = remoteConfigClient;\n this.sessionId = identity?.sessionId;\n this.deviceId = identity?.deviceId;\n }\n\n async generateJoinedConfig(): Promise<SessionReplayConfigs> {\n const config: SessionReplayJoinedConfig = { ...this.localConfig };\n // Special case here as optOut is implemented via getter/setter\n config.optOut = this.localConfig.optOut;\n // We always want captureEnabled to be true, unless there's an override\n // in the remote config.\n config.captureEnabled = true;\n let sessionReplayRemoteConfig: SessionReplayRemoteConfig | undefined;\n\n try {\n // Subscribe with a timeout so the SDK prefers the remote response and only falls back\n // to cache after the budget elapses. 'all' mode would race a synchronous cache read\n // against the network and resolve on whichever fires first — cache always wins, so a\n // stale cache silently overrides the live config (SR-4234).\n await new Promise<void>((resolve, reject) => {\n this.remoteConfigClient.subscribe(\n 'configs.sessionReplay',\n { timeout: REMOTE_CONFIG_TIMEOUT_MS },\n (remoteConfig: RemoteConfig | null, source: Source) => {\n this.localConfig.loggerProvider.debug(\n `Session Replay remote configuration received from ${source}:`,\n JSON.stringify(remoteConfig, null, 2),\n );\n\n if (!remoteConfig) {\n reject(new Error('No remote config received'));\n return;\n }\n\n // remoteConfig is already filtered to 'configs.sessionReplay' namespace\n const namespaceConfig = remoteConfig as SessionReplayRemoteConfig;\n const samplingConfig = namespaceConfig.sr_sampling_config;\n const privacyConfig = namespaceConfig.sr_privacy_config;\n const targetingConfig = namespaceConfig.sr_targeting_config;\n\n // Captured for the sr.trc.config.received diagnostics event below (remote vs cache is\n // the crux of SR-4234 stale-cache reports).\n const samplingForLog = samplingConfig as { capture_enabled?: boolean; sample_rate?: number } | undefined;\n const targetingSegments = (targetingConfig as unknown as { segments?: unknown[] } | undefined)?.segments;\n\n const ugcFilterRules = config.interactionConfig?.ugcFilterRules;\n // This is intentionally forced to only be set through the remote config.\n config.interactionConfig = namespaceConfig.sr_interaction_config;\n if (config.interactionConfig && ugcFilterRules) {\n config.interactionConfig.ugcFilterRules = ugcFilterRules;\n }\n\n // This is intentionally forced to only be set through the remote config.\n config.loggingConfig = namespaceConfig.sr_logging_config;\n\n // Team-visible diagnostics: which SOURCE the config came from (remote vs cache — the\n // crux of SR-4234) and whether targeting was present. Counters aggregate across the\n // customer's sessions; the event carries the full context (source, sample rate,\n // segment count) as queryable log fields. No-op when diagnostics isn't configured.\n try {\n const diagnosticsClient = this.localConfig.diagnosticsClient;\n diagnosticsClient?.increment(SrDiagnostic.configSource(String(source)));\n diagnosticsClient?.increment(\n targetingConfig ? SrDiagnostic.configHasTargeting : SrDiagnostic.configNoTargeting,\n );\n diagnosticsClient?.recordEvent(SrDiagnostic.configReceived, {\n sessionId: this.sessionId,\n deviceId: this.deviceId,\n srId:\n this.deviceId != null && this.sessionId != null ? `${this.deviceId}/${this.sessionId}` : undefined,\n source: String(source),\n hasSampling: !!samplingConfig,\n captureEnabled: samplingForLog?.capture_enabled,\n sampleRate: samplingForLog?.sample_rate,\n hasTargeting: !!targetingConfig,\n targetingSegmentCount: Array.isArray(targetingSegments) ? targetingSegments.length : undefined,\n hasPrivacy: !!privacyConfig,\n });\n // Flush now (vs the client's ~5-min timer). One capture POST per event — higher\n // volume; revisit/gate before production.\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n\n if (samplingConfig || privacyConfig || targetingConfig) {\n sessionReplayRemoteConfig = {};\n if (samplingConfig) {\n sessionReplayRemoteConfig.sr_sampling_config = samplingConfig;\n }\n if (privacyConfig) {\n sessionReplayRemoteConfig.sr_privacy_config = privacyConfig;\n }\n if (targetingConfig) {\n sessionReplayRemoteConfig.sr_targeting_config = targetingConfig;\n }\n }\n\n resolve();\n },\n );\n });\n } catch (error) {\n this.localConfig.loggerProvider.error('Failed to generate joined config: ', error);\n try {\n this.localConfig.diagnosticsClient?.increment(SrDiagnostic.configFetchFailed);\n void this.localConfig.diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n config.captureEnabled = false;\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: undefined,\n };\n }\n\n if (!sessionReplayRemoteConfig) {\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n\n const {\n sr_sampling_config: samplingConfig,\n sr_privacy_config: remotePrivacyConfig,\n sr_targeting_config: targetingConfig,\n } = sessionReplayRemoteConfig;\n if (samplingConfig && Object.keys(samplingConfig).length > 0) {\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) {\n config.captureEnabled = samplingConfig.capture_enabled;\n } else {\n config.captureEnabled = false;\n }\n\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'sample_rate')) {\n config.sampleRate = samplingConfig.sample_rate;\n }\n\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'min_session_duration_ms')) {\n config.minSessionDurationMs = this.sanitizeMinSessionDurationMs(samplingConfig.min_session_duration_ms);\n }\n } else {\n // If config API response was valid (ie 200), but no config returned, assume that\n // customer has not yet set up config, and use sample rate from SDK options,\n // allowing for immediate replay capture\n config.captureEnabled = true;\n this.localConfig.loggerProvider.debug(\n 'Remote config successfully fetched, but no values set for project, Session Replay capture enabled.',\n );\n }\n\n // Remote config join acts somewhat like a left join between the remote and the local\n // config. That is, remote config has precedence over local values as with sampling.\n // However, non conflicting values will be added to the lists.\n // Here's an example to illustrate:\n //\n // Remote config: {'.selector1': 'MASK', '.selector2': 'UNMASK'}\n // Local config: {'.selector1': 'UNMASK', '.selector3': 'MASK'}\n //\n // Resolved config: {'.selector1': 'MASK', '.selector2': 'UNMASK', '.selector3': 'MASK'}\n // config.privacyConfig = {\n // ...(config.privacyConfig ?? {}),\n // ...remotePrivacyConfig,\n // };\n\n if (remotePrivacyConfig) {\n const localPrivacyConfig: PrivacyConfig = config.privacyConfig ?? {};\n\n const joinedPrivacyConfig: Required<PrivacyConfig> & { blockSelector: string[] } = {\n defaultMaskLevel: remotePrivacyConfig.defaultMaskLevel ?? localPrivacyConfig.defaultMaskLevel ?? 'medium',\n blockSelector: [],\n maskSelector: [],\n unmaskSelector: [],\n maskAttributes: [\n ...new Set([...(localPrivacyConfig.maskAttributes ?? []), ...(remotePrivacyConfig.maskAttributes ?? [])]),\n ],\n urlMaskLevels: [...(remotePrivacyConfig.urlMaskLevels ?? []), ...(localPrivacyConfig.urlMaskLevels ?? [])],\n };\n\n const privacyConfigSelectorMap = (privacyConfig: PrivacyConfig): Record<string, 'mask' | 'unmask' | 'block'> => {\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {};\n if (typeof privacyConfig.blockSelector === 'string') {\n privacyConfig.blockSelector = [privacyConfig.blockSelector];\n }\n\n for (const selector of privacyConfig.blockSelector ?? []) {\n selectorMap[selector] = 'block';\n }\n for (const selector of privacyConfig.maskSelector ?? []) {\n selectorMap[selector] = 'mask';\n }\n for (const selector of privacyConfig.unmaskSelector ?? []) {\n selectorMap[selector] = 'unmask';\n }\n return selectorMap;\n };\n\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {\n ...privacyConfigSelectorMap(localPrivacyConfig),\n ...privacyConfigSelectorMap(remotePrivacyConfig),\n };\n\n for (const [selector, selectorType] of Object.entries(selectorMap)) {\n if (selectorType === 'mask') {\n joinedPrivacyConfig.maskSelector.push(selector);\n } else if (selectorType === 'block') {\n joinedPrivacyConfig.blockSelector.push(selector);\n } else if (selectorType === 'unmask') {\n joinedPrivacyConfig.unmaskSelector.push(selector);\n }\n }\n\n config.privacyConfig = removeInvalidSelectorsFromPrivacyConfig(\n joinedPrivacyConfig,\n this.localConfig.loggerProvider,\n );\n }\n\n if (targetingConfig && Object.keys(targetingConfig).length > 0) {\n config.targetingConfig = targetingConfig;\n }\n\n this.localConfig.loggerProvider.debug(\n JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2),\n );\n\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n\n /**\n * Defensive bounds for the remote-supplied min_session_duration_ms. A misconfigured\n * value (e.g. 30_000_000) would silently suppress every replay until the config is\n * pushed again, so we clamp to a sane ceiling and warn on out-of-range inputs.\n * Returns undefined for clearly invalid values so the gate falls back to disabled\n * rather than carrying a NaN through downstream comparisons.\n */\n private sanitizeMinSessionDurationMs(raw: unknown): number | undefined {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) {\n this.localConfig.loggerProvider.warn(\n `min_session_duration_ms remote value is not a finite number (got ${String(raw)}); ignoring.`,\n );\n return undefined;\n }\n if (raw < 0) {\n this.localConfig.loggerProvider.warn(`min_session_duration_ms remote value is negative (${raw}); ignoring.`);\n return undefined;\n }\n if (raw > MAX_MIN_SESSION_DURATION_MS) {\n this.localConfig.loggerProvider.warn(\n `min_session_duration_ms remote value ${raw} exceeds ${MAX_MIN_SESSION_DURATION_MS}ms ceiling; clamping.`,\n );\n return MAX_MIN_SESSION_DURATION_MS;\n }\n return raw;\n }\n}\n\n/**\n * Upper bound for the remote-configured replay min duration. 60 seconds is well above\n * any reasonable bounce threshold; values higher than this are almost certainly typos\n * (e.g. seconds confused for milliseconds, or an extra zero) and would otherwise\n * suppress every replay until the config is corrected.\n */\nexport const MAX_MIN_SESSION_DURATION_MS = 60_000;\n\nexport const createSessionReplayJoinedConfigGenerator = async (apiKey: string, options: SessionReplayOptions) => {\n const localConfig = new SessionReplayLocalConfig(apiKey, options);\n\n const remoteConfigClient = new RemoteConfigClient(\n apiKey,\n localConfig.loggerProvider,\n localConfig.serverZone,\n options.configServerUrl,\n );\n\n return new SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig, {\n sessionId: options.sessionId,\n deviceId: options.deviceId,\n });\n};\n","import { EventType, IncrementalSource } from '@amplitude/rrweb-types';\nimport type { eventWithTime, mutationData, styleOMValue } from '@amplitude/rrweb-types';\n\nfunction isMergeableMutation(event: eventWithTime): boolean {\n if (event.type !== EventType.IncrementalSnapshot) return false;\n const data = event.data as mutationData;\n return data.source === IncrementalSource.Mutation && !data.isAttachIframe;\n}\n\n// In this repo's rrweb, a `style` attribute value is `string | styleOMValue | null`.\n// A `string` (or `null`) is a full replacement/removal; a `styleOMValue` object is a\n// PARTIAL diff that the replayer applies cumulatively (per-property setProperty /\n// removeProperty, where a `false` value means \"delete this property\"). Unlisted\n// properties are never cleared by an object-form write.\ntype StyleValue = string | styleOMValue | null;\n\nfunction isStyleObject(value: StyleValue): value is styleOMValue {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Deep-merges a run of object-form (`styleOMValue`) style diffs into a single\n * object. Later writes win on a per-property basis, exactly mirroring how the\n * rrweb replayer applies object-form styles cumulatively. A `false` value\n * (delete) is preserved so the merged write still removes the property.\n */\nfunction mergeStyleDiffs(diffs: styleOMValue[]): styleOMValue {\n const merged: styleOMValue = {};\n for (const diff of diffs) {\n for (const prop of Object.keys(diff)) {\n merged[prop] = diff[prop];\n }\n }\n return merged;\n}\n\n/**\n * Coalesces `style` attribute mutations within a merged group in a way that is\n * faithful to how the rrweb replayer applies them, so the merged payload stays\n * small without dropping any property that real cumulative replay would keep.\n *\n * Per node id, the surviving `style` writes are computed as follows:\n * - A `string`/`null` style write is a FULL reset: it supersedes every earlier\n * style write for that node. Only the last such reset is kept.\n * - Object-form (`styleOMValue`) writes after the last reset are PARTIAL diffs\n * applied cumulatively; they are deep-merged (later property wins, `false`\n * deletes preserved) into a single object placed at the last write's\n * position. Earlier superseded object writes are dropped.\n * - When all of a node's style writes are object-form, they all merge into one.\n *\n * This means a pure burst of string-form updates collapses to last-write-wins\n * (the common inline-style/opacity ticker case), while object-form partial diffs\n * such as `{color:'red'}` then `{background:'blue'}` are combined into\n * `{color:'red', background:'blue'}` rather than silently losing `color`.\n *\n * Only the `style` key is coalesced. Any other attribute keys on a superseded\n * entry are preserved in place, and non-style entries are left untouched.\n */\nfunction coalesceStyleAttributes(attributes: mutationData['attributes']): mutationData['attributes'] {\n // Per node id, the array indices of attribute mutations carrying a `style` key.\n const styleIndicesById = new Map<number, number[]>();\n attributes.forEach((attr, i) => {\n if (attr.attributes && 'style' in attr.attributes) {\n const list = styleIndicesById.get(attr.id);\n if (list) list.push(i);\n else styleIndicesById.set(attr.id, [i]);\n }\n });\n\n if (styleIndicesById.size === 0) return attributes;\n\n const styleValueAt = (i: number): StyleValue => (attributes[i].attributes as Record<string, StyleValue>).style;\n\n // Per attributes-array index: 'drop' removes the (superseded) style key.\n // mergedStyleByIndex replaces the style value with a deep-merged object.\n // Indices not present in either map keep their style value untouched.\n const dropStyleAt = new Set<number>();\n const mergedStyleByIndex = new Map<number, styleOMValue>();\n\n for (const indices of styleIndicesById.values()) {\n if (indices.length === 1) continue; // single style write — keep as-is\n\n // Position (within `indices`) of the last full-reset string/null write.\n let lastResetPos = -1;\n indices.forEach((idx, pos) => {\n if (!isStyleObject(styleValueAt(idx))) lastResetPos = pos;\n });\n\n // Object-form writes that survive: those after the last reset (or all of\n // them when there is no reset). Everything before the last reset is dropped.\n const survivingObjectIndices: number[] = [];\n indices.forEach((idx, pos) => {\n if (pos === lastResetPos) return; // the surviving full-reset write — keep\n dropStyleAt.add(idx);\n if (pos > lastResetPos) survivingObjectIndices.push(idx);\n });\n\n if (survivingObjectIndices.length > 0) {\n const lastObjectIdx = survivingObjectIndices[survivingObjectIndices.length - 1];\n const merged = mergeStyleDiffs(survivingObjectIndices.map((idx) => styleValueAt(idx) as styleOMValue));\n dropStyleAt.delete(lastObjectIdx);\n mergedStyleByIndex.set(lastObjectIdx, merged);\n }\n }\n\n if (dropStyleAt.size === 0 && mergedStyleByIndex.size === 0) return attributes;\n\n const result: mutationData['attributes'] = [];\n attributes.forEach((attr, i) => {\n const mergedStyle = mergedStyleByIndex.get(i);\n if (mergedStyle !== undefined) {\n result.push({ ...attr, attributes: { ...attr.attributes, style: mergedStyle } });\n return;\n }\n if (!dropStyleAt.has(i)) {\n result.push(attr);\n return;\n }\n // Superseded style write: drop only the `style` key, preserving any other\n // attribute keys. If the entry was style-only, it is dropped entirely.\n const rest = { ...attr.attributes };\n delete rest.style;\n if (Object.keys(rest).length > 0) {\n result.push({ ...attr, attributes: rest });\n }\n });\n\n return result;\n}\n\nfunction mergeGroup(events: eventWithTime[]): eventWithTime {\n const first = events[0];\n\n // Track first/last event index for each node's adds and removes.\n // lastParentById: final parent from most recent add (last-write-wins).\n const firstAddEventIndex = new Map<number, number>();\n const lastAddEventIndex = new Map<number, number>();\n const firstRemoveEventIndex = new Map<number, number>();\n const lastRemoveEventIndex = new Map<number, number>();\n const lastParentById = new Map<number, number>();\n events.forEach((e, i) => {\n const data = e.data as mutationData;\n for (const add of data.adds) {\n if (!firstAddEventIndex.has(add.node.id)) firstAddEventIndex.set(add.node.id, i);\n lastAddEventIndex.set(add.node.id, i);\n lastParentById.set(add.node.id, add.parentId);\n }\n for (const remove of data.removes) {\n if (!firstRemoveEventIndex.has(remove.id)) firstRemoveEventIndex.set(remove.id, i);\n lastRemoveEventIndex.set(remove.id, i);\n }\n });\n\n // Classify nodes that appear in both adds and removes within this window:\n //\n // Pure transient: created here (firstAddIdx < firstRemoveIdx) and ultimately removed\n // (lastAddIdx < lastRemoveIdx). Cancel all adds + all removes.\n //\n // Pre-existing transient: pre-existed in DOM (firstRemoveIdx < firstAddIdx — removed before\n // first add), then re-added, then removed again (lastAddIdx < lastRemoveIdx).\n // The rrweb replayer processes all removes first: the re-add would still\n // execute after both removes, leaving the node present when it should be\n // absent. Fix: cancel the re-add and all post-add removes; keep only the\n // pre-add removes (they represent the legitimate removal from the original\n // location).\n const transientIds = new Set<number>();\n const preExistingTransientIds = new Set<number>();\n\n for (const [id, firstAddIdx] of firstAddEventIndex) {\n const firstRemoveIdx = firstRemoveEventIndex.get(id);\n if (firstRemoveIdx === undefined) continue;\n const lastAddIdx = lastAddEventIndex.get(id)!;\n const lastRemoveIdx = lastRemoveEventIndex.get(id)!;\n if (lastAddIdx >= lastRemoveIdx) continue; // ultimately present — keep as-is\n\n if (firstAddIdx < firstRemoveIdx) {\n transientIds.add(id);\n } else if (firstRemoveIdx < firstAddIdx) {\n // firstRemoveIdx < firstAddIdx: pre-existing node removed, re-added, then removed again\n preExistingTransientIds.add(id);\n }\n // firstAddIdx === firstRemoveIdx: same-event move (remove+add in one rrweb event) followed\n // by a later remove — keep all operations so the move and final removal survive\n }\n\n // Cascade: nodes whose FINAL parent is effectively cancelled (transient or pre-existing-transient)\n // would be orphaned, so treat them as cancelled too.\n // Use lastParentById so a node moved away from a cancelled parent to a live one is not wrongly elided.\n //\n // Three cascade outcomes mirror the main-loop classification:\n // transientIds: no pre-existing removes (node created in window), or no remove/add overlap\n // preExistingTransientIds: nodeFirstRemoveIdx < nodeFirstAddIdx (pre-existing, removed before re-add)\n // cascadeDropAddsOnlyIds: nodeFirstRemoveIdx === nodeFirstAddIdx (same-event move to cancelled parent)\n // → drop adds but preserve removes from non-cancelled parents\n const cascadeDropAddsOnlyIds = new Set<number>();\n if (transientIds.size > 0 || preExistingTransientIds.size > 0) {\n let changed = true;\n while (changed) {\n changed = false;\n for (const [nodeId, parentId] of lastParentById) {\n if (\n !transientIds.has(nodeId) &&\n !preExistingTransientIds.has(nodeId) &&\n !cascadeDropAddsOnlyIds.has(nodeId) &&\n (transientIds.has(parentId) || preExistingTransientIds.has(parentId) || cascadeDropAddsOnlyIds.has(parentId))\n ) {\n const nodeFirstRemoveIdx = firstRemoveEventIndex.get(nodeId);\n const nodeFirstAddIdx = firstAddEventIndex.get(nodeId);\n if (\n nodeFirstRemoveIdx !== undefined &&\n nodeFirstAddIdx !== undefined &&\n nodeFirstRemoveIdx < nodeFirstAddIdx\n ) {\n preExistingTransientIds.add(nodeId);\n } else if (\n nodeFirstRemoveIdx !== undefined &&\n nodeFirstAddIdx !== undefined &&\n nodeFirstRemoveIdx === nodeFirstAddIdx\n ) {\n cascadeDropAddsOnlyIds.add(nodeId);\n } else {\n transientIds.add(nodeId);\n }\n changed = true;\n }\n }\n }\n }\n\n const needsFilter = transientIds.size > 0 || preExistingTransientIds.size > 0 || cascadeDropAddsOnlyIds.size > 0;\n\n // Build filtered removes by iterating per event so we know each remove's event index.\n // Pure transients: drop all removes.\n // Pre-existing transients: drop removes at eventIdx >= firstAddIdx (the cancelled re-add cycle);\n // keep removes at eventIdx < firstAddIdx (legitimate pre-window removal).\n // Cascade drop-adds-only: keep removes from non-cancelled parents; drop removes from cancelled parents\n // (the cancelled parent is never added in the replay, so a remove from it\n // would reference a non-existent node in the replayer).\n const filteredRemoves: mutationData['removes'][0][] = [];\n events.forEach((e, eventIdx) => {\n for (const r of (e.data as mutationData).removes) {\n if (transientIds.has(r.id)) continue;\n if (preExistingTransientIds.has(r.id) && eventIdx >= firstAddEventIndex.get(r.id)!) continue;\n if (\n cascadeDropAddsOnlyIds.has(r.id) &&\n (transientIds.has(r.parentId) ||\n preExistingTransientIds.has(r.parentId) ||\n cascadeDropAddsOnlyIds.has(r.parentId))\n )\n continue;\n filteredRemoves.push(r);\n }\n });\n\n const allAdds = events.flatMap((e) => (e.data as mutationData).adds);\n const allTexts = events.flatMap((e) => (e.data as mutationData).texts);\n const allAttributes = events.flatMap((e) => (e.data as mutationData).attributes);\n\n const mergedAttributes = needsFilter\n ? allAttributes.filter(\n (a) => !transientIds.has(a.id) && !preExistingTransientIds.has(a.id) && !cascadeDropAddsOnlyIds.has(a.id),\n )\n : allAttributes;\n\n const merged: mutationData = {\n source: IncrementalSource.Mutation,\n removes: filteredRemoves,\n adds: needsFilter\n ? allAdds.filter(\n (a) =>\n !transientIds.has(a.node.id) &&\n !preExistingTransientIds.has(a.node.id) &&\n !cascadeDropAddsOnlyIds.has(a.node.id),\n )\n : allAdds,\n texts: needsFilter\n ? allTexts.filter(\n (t) => !transientIds.has(t.id) && !preExistingTransientIds.has(t.id) && !cascadeDropAddsOnlyIds.has(t.id),\n )\n : allTexts,\n attributes: coalesceStyleAttributes(mergedAttributes),\n };\n return { ...first, data: merged } as eventWithTime;\n}\n\n/**\n * Merges consecutive IncrementalSnapshot mutation events into a single event,\n * reducing overall event count without changing replay semantics.\n *\n * isAttachIframe events are never merged — they carry a full iframe document\n * tree and must remain isolated.\n */\nexport function mergeMutationEvents(events: eventWithTime[]): eventWithTime[] {\n if (events.length <= 1) return events;\n\n const result: eventWithTime[] = [];\n let i = 0;\n\n while (i < events.length) {\n if (!isMergeableMutation(events[i])) {\n result.push(events[i]);\n i++;\n continue;\n }\n\n let j = i + 1;\n while (j < events.length && isMergeableMutation(events[j])) {\n j++;\n }\n\n result.push(j > i + 1 ? mergeGroup(events.slice(i, j)) : events[i]);\n i = j;\n }\n\n return result;\n}\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { MAX_SINGLE_EVENT_SIZE } from '../constants';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\nimport { mergeMutationEvents } from './merge-mutation-events';\n\ninterface TaskQueue {\n event: eventWithTime;\n sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n taskQueue: TaskQueue[] = [];\n pendingQueue: TaskQueue[] = [];\n isProcessing = false;\n eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n config: SessionReplayJoinedConfig;\n deviceId: string | undefined;\n canUseIdleCallback: boolean | undefined;\n timeout: number;\n worker?: Worker;\n onFullSnapshotProcessed?: () => void;\n\n constructor(\n eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n config: SessionReplayJoinedConfig,\n deviceId: string | undefined,\n workerScript?: string,\n onFullSnapshotProcessed?: () => void,\n ) {\n const globalScope = getGlobalScope();\n this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n this.eventsManager = eventsManager;\n this.config = config;\n this.deviceId = deviceId;\n this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n if (workerScript) {\n config.loggerProvider.log('Enabling web worker for compression');\n\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n\n worker.onerror = (e) => {\n e.preventDefault();\n config.loggerProvider.error(\n `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n };\n worker.onmessage = (e) => {\n const { compressedEvent, sessionId } = e.data as Record<string, string>;\n this.addCompressedEventToManager(compressedEvent, sessionId);\n };\n\n this.worker = worker;\n } catch (error) {\n config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n }\n }\n }\n\n // Schedule processing during idle time\n public scheduleIdleProcessing(): void {\n if (!this.isProcessing) {\n this.isProcessing = true;\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n }\n }\n\n // Add an event to the task queue if idle callback is supported or compress the event directly\n public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n // maximising the chance it is delivered before the user exits the page.\n if (event.type === RRWebEventType.FullSnapshot) {\n this.config.loggerProvider.debug('Processing full snapshot immediately.');\n // Drain any events still pending in the idle-callback queue first.\n // Those events reference the pre-snapshot DOM and must be sent before\n // the full snapshot; if we let them be processed later they'd arrive at\n // the server after the snapshot and cause \"node not found\" replay errors.\n if (this.taskQueue.length > 0 || this.pendingQueue.length > 0) {\n const allTasks = [...this.taskQueue.splice(0), ...this.mergeMutationTasks(this.pendingQueue.splice(0))];\n for (const task of allTasks) {\n const compressed = this.compressEvent(task.event);\n this.addCompressedEventToManager(compressed, task.sessionId);\n }\n this.isProcessing = false;\n }\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n this.onFullSnapshotProcessed?.();\n return;\n }\n\n if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n this.pendingQueue.push({ event, sessionId });\n this.scheduleIdleProcessing();\n } else {\n this.config.loggerProvider.debug('Processing event without idle callback.');\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // Process the task queue during idle time\n public processQueue(idleDeadline: IdleDeadline): void {\n // Merge newly-arrived pending events and append to the already-merged taskQueue.\n // Keeping them separate prevents re-merging already-merged tasks on subsequent calls,\n // which would corrupt move semantics for nodes that appear in multiple merge passes.\n if (this.pendingQueue.length > 0) {\n this.taskQueue.push(...this.mergeMutationTasks(this.pendingQueue.splice(0)));\n }\n // Process tasks while there's idle time or until the max number of tasks is reached\n while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // If there are still tasks in the queue, schedule the next idle callback\n if (this.taskQueue.length > 0 || this.pendingQueue.length > 0) {\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n } else {\n this.isProcessing = false;\n }\n }\n\n compressEvent = (event: eventWithTime): string => {\n // Serialize with type+timestamp first for streaming parser compatibility.\n // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n // `delay` is an rrweb player field: an optional ms offset applied on top of\n // `timestamp` during replay to smooth out batched/throttled events. Preserve\n // it when present so playback timing is accurate.\n const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n };\n\n private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n // UTF-8 byte size, not JS char count: a 9 M-char string of CJK/emoji can be 18–27 MB\n // on the wire and would otherwise slip past a char-count guard.\n const eventSizeBytes = new Blob([compressedEvent]).size;\n if (eventSizeBytes > (this.config.maxSingleEventSizeBytes ?? MAX_SINGLE_EVENT_SIZE)) {\n this.config.loggerProvider.warn(\n `Session replay event dropped: serialized size ${Math.round(\n eventSizeBytes / 1024,\n )} KB exceeds maximum allowed event size. If this recurs, please open a GitHub issue at https://github.com/amplitude/Amplitude-TypeScript/issues or contact Amplitude support.`,\n );\n return;\n }\n if (this.eventsManager && this.deviceId) {\n this.eventsManager.addEvent({\n event: { type: 'replay', data: compressedEvent },\n sessionId,\n deviceId: this.deviceId,\n });\n }\n };\n\n public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n if (this.worker) {\n // This indirectly compresses the event.\n try {\n this.worker.postMessage({ event, sessionId });\n } catch (err: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (err.name === 'DataCloneError') {\n // fallback: serialize\n this.worker.postMessage(JSON.stringify({ event, sessionId }));\n } else {\n this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n }\n }\n } else {\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n }\n };\n\n /**\n * Synchronously drain all queued events. Called during page unload to prevent\n * data loss from events waiting in the requestIdleCallback queue.\n */\n public flushQueue = () => {\n // Merge any events still in pendingQueue into taskQueue first.\n // Events land in pendingQueue when the idle callback hasn't fired yet;\n // without this step they would be silently lost on page unload.\n if (this.pendingQueue.length > 0) {\n this.taskQueue.push(...this.mergeMutationTasks(this.pendingQueue.splice(0)));\n }\n while (this.taskQueue.length > 0) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n // Bypass the web worker: compress synchronously on the main thread and\n // write directly to the manager. postMessage is async — during page\n // unload the worker response would never arrive and events would be\n // silently dropped. This mirrors the pattern used for full snapshots in\n // enqueueEvent().\n const compressed = this.compressEvent(event);\n this.addCompressedEventToManager(compressed, sessionId);\n }\n }\n this.isProcessing = false;\n };\n\n // Merge consecutive mutation tasks with the same sessionId before processing,\n // reducing the number of events serialized and stored without changing replay semantics.\n // Enabled by default (validated amp-on-amp perf config, SR-4646); only skipped when\n // performanceConfig.mergeMutations is explicitly set to false.\n private mergeMutationTasks(tasks: TaskQueue[]): TaskQueue[] {\n if (this.config.performanceConfig?.mergeMutations === false) return tasks;\n if (tasks.length <= 1) return tasks;\n\n const result: TaskQueue[] = [];\n let i = 0;\n\n while (i < tasks.length) {\n const sessionId = tasks[i].sessionId;\n\n // Find the end of the current session run\n let j = i + 1;\n while (j < tasks.length && tasks[j].sessionId === sessionId) {\n j++;\n }\n\n // Merge consecutive mutations within this session run; non-mutations pass through unchanged\n const merged = mergeMutationEvents(tasks.slice(i, j).map((t) => t.event));\n for (const event of merged) {\n result.push({ event, sessionId });\n }\n\n i = j;\n }\n\n return result;\n }\n\n public terminate = () => {\n this.worker?.terminate();\n };\n}\n","export const UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';\nexport const UNEXPECTED_NETWORK_ERROR_MESSAGE = 'Network error occurred, event batch rejected';\nexport const MAX_RETRIES_EXCEEDED_MESSAGE = 'Session replay event batch rejected due to exceeded retry count';\nexport const STORAGE_FAILURE = 'Failed to store session replay events in IndexedDB';\nexport const MISSING_DEVICE_ID_MESSAGE = 'Session replay event batch not sent due to missing device ID';\nexport const MISSING_API_KEY_MESSAGE = 'Session replay event batch not sent due to missing api key';\nexport const SESSION_KILLED_MESSAGE =\n 'Session replay event batch dropped: server signalled capture disabled or session out of valid range for this session';\n","// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.47.0-sr-trc-debug-log.2';\n","import { BaseTransport, getGlobalScope, ILogger, ServerZone, Status } from '@amplitude/analytics-core';\nimport { getCurrentUrl, getServerUrl } from './helpers';\nimport {\n MAX_RETRIES_EXCEEDED_MESSAGE,\n MISSING_API_KEY_MESSAGE,\n MISSING_DEVICE_ID_MESSAGE,\n SESSION_KILLED_MESSAGE,\n UNEXPECTED_ERROR_MESSAGE,\n UNEXPECTED_NETWORK_ERROR_MESSAGE,\n} from './messages';\nimport {\n SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination,\n SessionReplayDestination,\n SessionReplayDestinationContext,\n} from './typings/session-replay';\nimport { VERSION } from './version';\nimport {\n MAX_URL_LENGTH,\n KB_SIZE,\n MAX_KEEPALIVE_BYTES,\n WAF_PAYLOAD_TOO_LARGE_PATTERN,\n EVENT_SKIPPED_HEADER,\n EVENT_SKIP_CODE_THROTTLED,\n EVENT_SKIP_CODE_INVALID_RANGE,\n EVENT_SKIP_CODE_CAPTURE_DISABLED,\n THROTTLED_FLUSH_PAUSE_MS,\n MERGE_AFTER_THROTTLE_SOFT_CAP,\n SEND_TIMEOUT_MS,\n} from './constants';\nimport { gzipJson } from './utils/gzip';\n\ninterface WorkerCompleteMessage {\n type: 'complete';\n id: string;\n err?: string;\n // null when the response was a clean 200 (no skip header), undefined when the\n // request did not produce a 200, otherwise the server's skip-code string.\n skipCode?: string | null;\n}\ninterface WorkerLogMessage {\n type: 'log' | 'warn';\n id: string;\n message: string;\n}\ninterface WorkerPayloadTooLargeMessage {\n type: 'payload_too_large';\n id: string;\n isWaf: boolean;\n}\ntype WorkerMessage = WorkerCompleteMessage | WorkerLogMessage | WorkerPayloadTooLargeMessage;\n\nexport type PayloadBatcher = ({ version, events }: { version: number; events: string[] }) => {\n version: number;\n events: unknown[];\n};\n\n// Bounded so a long-lived SDK instance can't accumulate kill records indefinitely;\n// sessions are time-bounded in practice, this cap is just a defensive ceiling.\nconst MAX_KILLED_SESSIONS = 256;\n\n// Defensive ceiling on retained timed-out worker requests (see timedOutWorkerRequests).\n// In normal operation each entry is removed when the worker's late message arrives; this\n// cap only guards the pathological case of a wedged worker that never replies at all.\nconst MAX_TIMED_OUT_WORKER_REQUESTS = 256;\n\nexport class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {\n loggerProvider: ILogger;\n storageKey = '';\n trackServerUrl?: string;\n retryTimeout = 1000;\n // Defaults to true (gzip enabled) so existing call sites that don't pass the flag\n // retain pre-flag behavior. The local-config layer also defaults to true; this\n // belt-and-braces default protects direct constructor callers (e.g. tests).\n private enableTransportCompression: boolean;\n // Milliseconds before an in-flight send is aborted; <= 0 disables the abort/timeout.\n // Defaults to SEND_TIMEOUT_MS. Configurable so large slow-but-succeeding uploads aren't\n // killed (and retried) at an over-aggressive default. See config.sendTimeoutMs.\n private sendTimeoutMs: number;\n private scheduled: ReturnType<typeof setTimeout> | null = null;\n payloadBatcher: PayloadBatcher;\n queue: SessionReplayDestinationContext[] = [];\n private worker?: Worker;\n private sendIdCounter = 0;\n private pendingWorkerRequests = new Map<\n string,\n { context: SessionReplayDestinationContext; resolve: () => void; timeout?: ReturnType<typeof setTimeout> }\n >();\n // Requests the main thread stopped awaiting after SEND_TIMEOUT_MS (so the serial flush\n // loop could proceed) but whose worker may still be retrying in the background. We keep\n // the context — bounded, like killedSessions — so a *late* worker complete/payload_too_large\n // can still run completeRequest and settle the store record. Without this the late message\n // is dropped (its id is gone from pendingWorkerRequests), so a successful late delivery would\n // leave the IDB/memory record behind for sendStoredEvents to re-upload as duplicate replay data.\n private timedOutWorkerRequests = new Map<string, SessionReplayDestinationContext>();\n // Server back-pressure state, fed by the X-Session-Replay-Event-Skipped header on 200s.\n // The server uses this header (instead of 4xx) to signal a deliberate no-retry drop so SDKs\n // don't retry-storm. We honor it here by slowing or stopping our flush schedule.\n private flushPauseUntilMs = 0;\n // Set when schedule() defers a flush because we're inside a throttle pause; consumed by\n // flush() to merge same-session contexts before sending. Throttling is enforced by request\n // count, so collapsing N queued batches into one POST directly reduces throttle pressure.\n private mergeOnNextFlush = false;\n // Set by markCoalesceNextFlush() before the page-load backlog is enqueued; consumed by\n // flush() to coalesce the drained persisted sequences. Distinct from\n // mergeOnNextFlush so the drain isn't conflated with a throttle pause for logging.\n private coalesceNextFlush = false;\n // Gates the merge log to once per throttle pause window — mirroring the throttle log's\n // transition-only gating — so a sustained throttle scenario doesn't spam logs every cycle.\n private mergeLogFiredThisPause = false;\n private killedSessions = new Set<string | number>();\n\n constructor({\n trackServerUrl,\n loggerProvider,\n payloadBatcher,\n workerScript,\n enableTransportCompression,\n sendTimeoutMs,\n }: {\n trackServerUrl?: string;\n loggerProvider: ILogger;\n payloadBatcher?: PayloadBatcher;\n workerScript?: string;\n enableTransportCompression?: boolean;\n sendTimeoutMs?: number;\n }) {\n this.loggerProvider = loggerProvider;\n this.payloadBatcher = payloadBatcher ? payloadBatcher : (payload) => payload;\n this.trackServerUrl = trackServerUrl;\n this.enableTransportCompression = enableTransportCompression ?? true;\n this.sendTimeoutMs = sendTimeoutMs ?? SEND_TIMEOUT_MS;\n\n if (workerScript) {\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n worker.onerror = (e) => {\n e.preventDefault();\n loggerProvider.error(\n `Track destination worker failed, falling back to main-thread sending: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n // Resolve pending promises so flush() doesn't hang. Do NOT call completeRequest\n // here — the events were never delivered, so onComplete must not fire and the\n // IDB/memory store entries must remain intact for recovery by sendStoredEvents.\n for (const [, pending] of this.pendingWorkerRequests) {\n // Cancel the per-request timeout — onerror already settles every pending\n // promise, so leaving the timer armed would fire a spurious timeout warn later.\n if (pending.timeout) clearTimeout(pending.timeout);\n loggerProvider.warn(`Session replay event send failed due to worker crash: ${e.message}`);\n pending.resolve();\n }\n this.pendingWorkerRequests.clear();\n // The worker is gone, so no late completion can arrive for timed-out requests either.\n // Drop the retained contexts to free memory; their store records stay intact (we never\n // completeRequest here) so sendStoredEvents can recover them on next init.\n this.timedOutWorkerRequests.clear();\n };\n worker.onmessage = (e: MessageEvent<WorkerMessage>) => {\n const msg = e.data;\n if (msg.type === 'log') {\n loggerProvider.log(msg.message);\n } else if (msg.type === 'warn') {\n loggerProvider.warn(msg.message);\n } else if (msg.type === 'payload_too_large') {\n const pending = this.pendingWorkerRequests.get(msg.id);\n if (pending) {\n if (pending.timeout) clearTimeout(pending.timeout);\n this.handlePayloadTooLargeResponse(pending.context, msg.isWaf);\n pending.resolve();\n this.pendingWorkerRequests.delete(msg.id);\n } else {\n // Late message for a request the main thread already timed out: the worker still\n // determined the payload was too large, so split-and-retry off the original record.\n const timedOut = this.timedOutWorkerRequests.get(msg.id);\n if (timedOut) {\n this.timedOutWorkerRequests.delete(msg.id);\n this.handlePayloadTooLargeResponse(timedOut, msg.isWaf);\n }\n }\n } else if (msg.type === 'complete') {\n const pending = this.pendingWorkerRequests.get(msg.id);\n if (pending) {\n if (pending.timeout) clearTimeout(pending.timeout);\n if (msg.skipCode !== undefined) {\n this.applyServerDirective(pending.context.sessionId, msg.skipCode);\n }\n this.completeRequest({ context: pending.context });\n pending.resolve();\n this.pendingWorkerRequests.delete(msg.id);\n } else {\n // Late completion for a request the main thread already timed out. The worker's\n // actual outcome (delivered, or retries exhausted) is authoritative, so settle the\n // store record by it rather than leaving it behind for sendStoredEvents to re-upload.\n const timedOut = this.timedOutWorkerRequests.get(msg.id);\n if (timedOut) {\n this.timedOutWorkerRequests.delete(msg.id);\n if (msg.skipCode !== undefined) {\n this.applyServerDirective(timedOut.sessionId, msg.skipCode);\n }\n this.completeRequest({ context: timedOut });\n }\n }\n }\n };\n this.worker = worker;\n } catch (error) {\n loggerProvider.error('Failed to create track destination worker, falling back to main-thread sending:', error);\n }\n }\n }\n\n sendEventsList(destinationData: SessionReplayDestination) {\n this.addToQueue({\n ...destinationData,\n attempts: 0,\n timeout: 0,\n });\n }\n\n /**\n * Marks the next scheduled flush to coalesce its queued contexts by destination identity.\n * Callers use this immediately before enqueuing the page-load backlog drain (many persisted\n * sequences replayed back-to-back on init via sendStoredEvents). Because those enqueues are\n * synchronous and the flush is deferred to the next tick via schedule(0), the whole backlog\n * lands in the queue before the flag is consumed — collapsing N small POSTs into far fewer\n * and avoiding the request flood observed on page load. Steady-state live capture\n * never sets this flag, so its sending behavior is unchanged.\n *\n * Schedules a flush so the flag is always consumed by the next flush, even when every\n * backlog sequence is dropped before reaching the queue (e.g. all events oversized) and no\n * enqueue schedules one itself. Otherwise the flag would stick and a later unrelated live\n * flush could coalesce live batches as if they were a page-load drain.\n */\n markCoalesceNextFlush() {\n this.coalesceNextFlush = true;\n this.schedule(0);\n }\n\n /**\n * Sends events via navigator.sendBeacon on page exit.\n * Beacon payloads are sent as uncompressed JSON because sendBeacon does not support\n * Content-Encoding, and small incremental batches don't benefit much from compression.\n * The full snapshot has already been sent eagerly via fetch, so the beacon only needs\n * to cover the remaining incremental events since the last fetch flush.\n */\n sendBeacon({\n events,\n sessionId,\n deviceId,\n apiKey,\n serverZone,\n }: {\n events: string[];\n sessionId: string | number;\n deviceId: string;\n apiKey: string;\n serverZone?: keyof typeof ServerZone;\n }) {\n const MAX_BEACON_BYTES = 64 * 1024;\n const byteLength = (s: string) => new Blob([s]).size;\n let trimmedEvents = events;\n let payload = JSON.stringify({ version: 2, events: trimmedEvents });\n if (byteLength(payload) > MAX_BEACON_BYTES) {\n // Binary search for the largest prefix that fits within the beacon size limit.\n // Uses Blob.size to get the UTF-8 byte count, which is what sendBeacon measures.\n let lo = 0;\n let hi = trimmedEvents.length;\n while (lo < hi) {\n const mid = Math.floor((lo + hi + 1) / 2);\n if (byteLength(JSON.stringify({ version: 2, events: trimmedEvents.slice(0, mid) })) <= MAX_BEACON_BYTES) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n trimmedEvents = trimmedEvents.slice(0, lo);\n payload = JSON.stringify({ version: 2, events: trimmedEvents });\n this.loggerProvider.warn(\n `sendBeacon payload exceeded 64 KB limit, trimmed from ${events.length} to ${trimmedEvents.length} events`,\n );\n }\n if (trimmedEvents.length === 0) {\n return;\n }\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: String(sessionId),\n type: 'replay',\n api_key: apiKey,\n });\n const serverUrl = `${getServerUrl(serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n const globalScope = getGlobalScope();\n try {\n // Wrap in a Blob to set Content-Type: application/json; a plain string would\n // cause the browser to send Content-Type: text/plain, which the server rejects.\n const payloadBlob = new Blob([payload], { type: 'application/json' });\n const sent = globalScope?.navigator?.sendBeacon?.(serverUrl, payloadBlob);\n if (sent === false) {\n this.loggerProvider.warn('sendBeacon failed to queue session replay payload');\n }\n } catch {\n // Best effort — no fallback on page exit.\n }\n }\n\n addToQueue(...list: SessionReplayDestinationContext[]) {\n const tryable = list.filter((context) => {\n if (this.killedSessions.has(context.sessionId)) {\n // Server has signaled capture_disabled or session_in_invalid_range for this session;\n // drop the batch (and clean up its IDB record via onComplete) instead of POSTing.\n this.completeRequest({\n context,\n err: SESSION_KILLED_MESSAGE,\n });\n return false;\n }\n if (context.attempts < (context.flushMaxRetries || 0)) {\n context.attempts += 1;\n return true;\n }\n this.completeRequest({\n context,\n err: MAX_RETRIES_EXCEEDED_MESSAGE,\n });\n return false;\n });\n tryable.forEach((context) => {\n this.queue = this.queue.concat(context);\n this.schedule(0);\n });\n }\n\n schedule(timeout: number) {\n if (this.scheduled) return;\n // If the server signaled throttling on a recent 200, defer the next flush until the\n // pause window ends. This lets us keep batching events without retry-storming the server.\n const pauseRemaining = this.flushPauseUntilMs - Date.now();\n const isPaused = pauseRemaining > 0;\n const effectiveTimeout = pauseRemaining > timeout ? pauseRemaining : timeout;\n if (isPaused) {\n // Mark the upcoming flush for merge: contexts piling up during the pause should\n // be coalesced into one POST per (session, device, api, type, ...) group.\n this.mergeOnNextFlush = true;\n }\n this.scheduled = setTimeout(() => {\n void this.flush(true).then(() => {\n if (this.queue.length > 0) {\n this.schedule(timeout);\n }\n });\n }, effectiveTimeout);\n }\n\n async flush(useRetry = false) {\n let list = this.queue;\n this.queue = [];\n\n if (this.scheduled) {\n clearTimeout(this.scheduled);\n this.scheduled = null;\n }\n\n if (this.mergeOnNextFlush) {\n this.mergeOnNextFlush = false;\n // A throttle merge already coalesces by identity; clear the drain flag too so the\n // same backlog isn't passed through a redundant second merge on a later flush.\n this.coalesceNextFlush = false;\n list = this.mergeQueueAfterThrottle(list);\n } else if (this.coalesceNextFlush) {\n this.coalesceNextFlush = false;\n list = this.mergeDrainBacklog(list);\n }\n\n for (const context of list) {\n await this.send(context, useRetry);\n }\n }\n\n /**\n * Post-throttle release path: coalesce the queued contexts, then log once per pause window.\n * Delegates the actual merging to the shared coalesceByIdentity helper so the drain path\n * (mergeDrainBacklog) and this path stay byte-for-byte identical in how they merge.\n */\n private mergeQueueAfterThrottle(list: SessionReplayDestinationContext[]): SessionReplayDestinationContext[] {\n const merged = this.coalesceByIdentity(list);\n if (merged.length < list.length && !this.mergeLogFiredThisPause) {\n this.mergeLogFiredThisPause = true;\n this.loggerProvider.log(\n `Session replay throttle pause ended; merged ${list.length} queued batches into ${merged.length} request(s)`,\n );\n }\n return merged;\n }\n\n /**\n * Page-load backlog drain path: on init the SDK replays every persisted sequence\n * from a prior session via sendStoredEvents. Enqueued back-to-back they would flush as N\n * separate POSTs — a request flood on page load that feeds volume spikes and throttling.\n * Reuses the exact same identity-grouped merge as the post-throttle path so the backlog\n * collapses into far fewer requests, with onComplete fanned out so each source IDB record\n * is still cleaned up exactly once on success.\n */\n private mergeDrainBacklog(list: SessionReplayDestinationContext[]): SessionReplayDestinationContext[] {\n const merged = this.coalesceByIdentity(list);\n if (merged.length < list.length) {\n this.loggerProvider.log(\n `Session replay coalesced ${list.length} persisted page-load backlog batches into ${merged.length} request(s)`,\n );\n }\n return merged;\n }\n\n /**\n * Coalesces queued contexts that share the same destination identity into fewer requests.\n * Identity covers everything that affects the request URL, routing, or per-request semantics\n * — splitting on any difference keeps each merged POST indistinguishable from the source\n * contexts it replaced.\n *\n * Greedy concat with a soft byte-length cap (`MERGE_AFTER_THROTTLE_SOFT_CAP`) keeps merged\n * payloads well under the 413 ceiling; on the rare oversized merge, the existing\n * split-and-retry path still bisects safely.\n *\n * The merged context's `onComplete` fans out to every source context's callback so each\n * underlying IDB sequence record is cleaned up exactly once on success.\n */\n private coalesceByIdentity(list: SessionReplayDestinationContext[]): SessionReplayDestinationContext[] {\n if (list.length <= 1) return list;\n\n const groups = new Map<string, SessionReplayDestinationContext[]>();\n for (const ctx of list) {\n // Anything that can change the URL, headers, or backend routing must split groups.\n const key = [\n ctx.sessionId,\n ctx.deviceId ?? '',\n ctx.apiKey ?? '',\n ctx.type,\n ctx.serverZone ?? '',\n ctx.sampleRate,\n ctx.version?.type ?? '',\n ctx.version?.version ?? '',\n ].join('|');\n const arr = groups.get(key);\n if (arr) arr.push(ctx);\n else groups.set(key, [ctx]);\n }\n\n const merged: SessionReplayDestinationContext[] = [];\n for (const group of groups.values()) {\n if (group.length === 1) {\n merged.push(group[0]);\n continue;\n }\n let current: SessionReplayDestinationContext | null = null;\n let currentBytes = 0;\n const flushCurrent = () => {\n if (current) merged.push(current);\n current = null;\n currentBytes = 0;\n };\n for (const ctx of group) {\n // UTF-8 byte size, matching how the events store enforces MAX_EVENT_LIST_SIZE\n // (see base-events-store.ts:getStringSize). Using char length would let a CJK/\n // emoji-heavy payload sneak past the cap.\n const ctxBytes = ctx.events.reduce((sum, e) => sum + new Blob([e]).size, 0);\n if (current === null) {\n // Reset attempts to 0 on the merged context so the post-throttle delivery gets a\n // full retry budget. The throttle pause has already absorbed back-pressure; the\n // alternative (Math.max of source attempts) would collapse N source budgets into\n // one and end-of-life all N IDB records on a single retry exhaustion.\n current = { ...ctx, events: [...ctx.events], attempts: 0 };\n currentBytes = ctxBytes;\n continue;\n }\n if (currentBytes + ctxBytes > MERGE_AFTER_THROTTLE_SOFT_CAP) {\n flushCurrent();\n current = { ...ctx, events: [...ctx.events], attempts: 0 };\n currentBytes = ctxBytes;\n continue;\n }\n const prevOnComplete = current.onComplete;\n const ctxOnComplete = ctx.onComplete;\n current.events = current.events.concat(ctx.events);\n currentBytes += ctxBytes;\n current.onComplete = async () => {\n // allSettled (not all): an underlying store cleanup failure in one shouldn't\n // block the other, and the merged onComplete is invoked fire-and-forget via\n // `void context.onComplete()` — a rejection from `Promise.all` would surface\n // as an unhandled rejection. Errors stay encapsulated in the source callbacks.\n await Promise.allSettled([prevOnComplete(), ctxOnComplete()]);\n };\n }\n flushCurrent();\n }\n\n return merged;\n }\n\n async send(context: SessionReplayDestinationContext, useRetry = true) {\n // A kill directive can arrive between flush() snapshotting the queue and us reaching\n // each context. Re-check before hitting the network so we don't waste POSTs on a\n // session the server has already told us to stop sending for.\n if (this.killedSessions.has(context.sessionId)) {\n return this.completeRequest({ context, err: SESSION_KILLED_MESSAGE });\n }\n const apiKey = context.apiKey;\n if (!apiKey) {\n return this.completeRequest({ context, err: MISSING_API_KEY_MESSAGE });\n }\n const deviceId = context.deviceId;\n if (!deviceId) {\n return this.completeRequest({ context, err: MISSING_DEVICE_ID_MESSAGE });\n }\n\n const payload = this.payloadBatcher({\n version: 1,\n events: context.events,\n });\n\n if (payload.events.length === 0) {\n this.completeRequest({ context });\n return;\n }\n\n const { worker } = this;\n if (worker) {\n return this.sendViaWorker(worker, context, payload, useRetry);\n }\n\n return this.sendOnMainThread(apiKey, deviceId, context, payload, useRetry);\n }\n\n private async sendViaWorker(\n worker: Worker,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const id = `${++this.sendIdCounter}`;\n return new Promise<void>((resolve) => {\n // The worker only resolves this promise when it posts back complete/payload_too_large.\n // If the worker's own fetch hangs, no message ever arrives, so this promise — and the\n // serial flush loop awaiting it — would hang forever while pendingWorkerRequests grows\n // unbounded. On timeout we resolve so flush() proceeds, but deliberately do NOT call\n // completeRequest: like the worker-crash path above, the events were never confirmed\n // delivered, so onComplete must not fire and the IDB/memory store must stay intact for\n // recovery by sendStoredEvents.\n // sendTimeoutMs <= 0 disables the wait timer entirely: we then rely solely on the\n // worker's own complete/payload_too_large message to settle. This reintroduces the\n // hang risk this timer guards against, so it is an explicit experiment opt-out.\n const timeout =\n this.sendTimeoutMs > 0\n ? setTimeout(() => {\n const pending = this.pendingWorkerRequests.get(id);\n if (!pending) return;\n this.pendingWorkerRequests.delete(id);\n // Retain the context so a *late* worker complete/payload_too_large can still settle the\n // store record (see timedOutWorkerRequests). Without this, a worker that ultimately\n // delivers after we stopped awaiting would leave the record behind → duplicate upload.\n this.rememberTimedOutRequest(id, pending.context);\n this.loggerProvider.warn(\n `Session replay worker send timed out after ${this.sendTimeoutMs}ms; leaving events for retry`,\n );\n pending.resolve();\n }, this.sendTimeoutMs)\n : undefined;\n this.pendingWorkerRequests.set(id, { context, resolve, timeout });\n worker.postMessage({\n type: 'send',\n id,\n payload,\n useRetry,\n context: {\n apiKey: context.apiKey,\n deviceId: context.deviceId,\n sessionId: context.sessionId,\n events: context.events,\n eventType: context.type,\n flushMaxRetries: context.flushMaxRetries ?? 0,\n sampleRate: context.sampleRate,\n serverZone: context.serverZone,\n trackServerUrl: this.trackServerUrl,\n version: context.version,\n currentUrl: getCurrentUrl(),\n sdkVersion: VERSION,\n enableTransportCompression: this.enableTransportCompression,\n sendTimeoutMs: this.sendTimeoutMs,\n },\n });\n });\n }\n\n private rememberTimedOutRequest(id: string, context: SessionReplayDestinationContext) {\n this.timedOutWorkerRequests.set(id, context);\n // Bound memory: a wedged worker that never replies must not let this grow without limit.\n // Map preserves insertion order, so deleting the first key evicts the oldest entry.\n if (this.timedOutWorkerRequests.size > MAX_TIMED_OUT_WORKER_REQUESTS) {\n for (const oldest of this.timedOutWorkerRequests.keys()) {\n this.timedOutWorkerRequests.delete(oldest);\n break;\n }\n }\n }\n\n private async sendOnMainThread(\n apiKey: string,\n deviceId: string,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const url = getCurrentUrl();\n const version = VERSION;\n const sampleRate = context.sampleRate;\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: `${context.sessionId}`,\n type: `${context.type}`,\n });\n const sessionReplayLibrary = `${context.version?.type ?? 'standalone'}/${context.version?.version ?? version}`;\n\n try {\n const payloadJson = JSON.stringify(payload);\n // Only await gzip when (a) the customer hasn't opted out and (b) CompressionStream\n // is actually available; skipping the await entirely preserves the synchronous\n // fast-path for browsers/environments (e.g. Jest) that don't support it, keeping\n // retry-timing tests unaffected.\n const globalScope = getGlobalScope();\n const gzipped =\n this.enableTransportCompression && globalScope && 'CompressionStream' in globalScope\n ? await gzipJson(payloadJson, globalScope)\n : null;\n const payloadSize = gzipped ? gzipped.byteLength : new Blob([payloadJson]).size;\n // fetch() has no native timeout. A request stuck \"pending\" forever would block the\n // serial flush loop indefinitely (head-of-line blocking), so we abort it after\n // SEND_TIMEOUT_MS. The abort surfaces as an AbortError in the catch below, where it's\n // routed as a retryable network failure when useRetry is true.\n const controller = new AbortController();\n const options: RequestInit = {\n headers: {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n Authorization: `Bearer ${apiKey}`,\n 'X-Client-Version': version,\n 'X-Client-Library': sessionReplayLibrary,\n 'X-Client-Url': url.substring(0, MAX_URL_LENGTH), // limit url length to 1000 characters to avoid ELB 400 error\n 'X-Client-Sample-Rate': `${sampleRate}`,\n 'X-Sampling-Hash-Alg': 'xxhash32',\n ...(gzipped ? { 'Content-Encoding': 'gzip' } : {}),\n },\n body: (gzipped ?? payloadJson) as BodyInit,\n method: 'POST',\n // keepalive lets the request survive page navigation, preventing 499 (client-closed) errors.\n // Must stay under the browser's 64 KB keepalive budget; large payloads skip it.\n keepalive: payloadSize <= MAX_KEEPALIVE_BYTES,\n signal: controller.signal,\n };\n\n const serverUrl = `${getServerUrl(context.serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n // Final defensive guard: never POST a zero-event payload. Upper layers (events-manager\n // oversize filter, send()'s post-batcher check, store-layer filters) should already\n // have caught this — but SR-4284 fleet logs show ~416 empty-body 400s/24h slipping\n // through somehow, so a cheap belt-and-braces check immediately before fetch prevents\n // any future regression from re-introducing the same server rejection.\n if (payload.events.length === 0) {\n this.completeRequest({ context });\n return;\n }\n // sendTimeoutMs <= 0 disables the abort: the request can then hang indefinitely\n // (head-of-line blocking the serial flush). Explicit experiment opt-out only.\n const sendTimeout =\n this.sendTimeoutMs > 0\n ? setTimeout(() => {\n controller.abort();\n }, this.sendTimeoutMs)\n : undefined;\n let res: Response;\n try {\n res = await fetch(serverUrl, options);\n } finally {\n // Clear on success and on error alike so a settled request never leaves an armed\n // timer that would abort a later reused controller or fire a stray callback.\n if (sendTimeout) clearTimeout(sendTimeout);\n }\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE });\n return;\n }\n if (res.status >= 200 && res.status < 300) {\n const skipCode = res.headers?.get?.(EVENT_SKIPPED_HEADER) ?? null;\n this.applyServerDirective(context.sessionId, skipCode);\n }\n if (!useRetry) {\n let responseBody = '';\n try {\n responseBody = JSON.stringify(res.body, null, 2);\n } catch {\n // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n }\n this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n } else {\n let responseBody = '';\n if (res.status === 413) {\n try {\n responseBody = await res.text();\n } catch {\n // best effort\n }\n }\n await this.handleReponse(res.status, context, responseBody);\n }\n } catch (e) {\n // A send timeout aborts the fetch, which rejects with an AbortError. Treat that as a\n // transient network failure and route it through the same retry budget/backoff as a\n // 5xx (so a single stalled request doesn't permanently drop the batch) when retries\n // are enabled. completeRequest fires onComplete exactly once via either branch\n // (handleOtherResponse only completes on retry exhaustion), so onComplete can't fire\n // twice. Non-abort errors keep the original complete-with-error behavior.\n // Browsers reject an aborted fetch with a DOMException named 'AbortError', which is NOT an\n // Error instance — an `instanceof Error` check would misroute every send-timeout abort to\n // the fatal completeRequest path, defeating the retry. Match on the name across any thrown\n // object (DOMException or Error) instead.\n const isAbort = !!e && typeof e === 'object' && (e as { name?: unknown }).name === 'AbortError';\n if (isAbort && useRetry) {\n await this.handleOtherResponse(context);\n } else {\n this.completeRequest({ context, err: e as string });\n }\n }\n }\n\n async handleReponse(status: number, context: SessionReplayDestinationContext, responseBody = '') {\n const parsedStatus = new BaseTransport().buildStatus(status);\n switch (parsedStatus) {\n case Status.Success:\n this.handleSuccessResponse(context);\n break;\n case Status.Failed:\n case Status.Timeout: // 408: server timed out waiting for request, data not received\n case Status.RateLimit: // 429: retry with existing backoff rather than silently dropping\n await this.handleOtherResponse(context);\n break;\n case Status.PayloadTooLarge:\n this.handlePayloadTooLargeResponse(context, WAF_PAYLOAD_TOO_LARGE_PATTERN.test(responseBody));\n break;\n default:\n // 499 (client closed connection / upstream dropped) is also retryable\n if (status === 499) {\n await this.handleOtherResponse(context);\n break;\n }\n this.completeRequest({ context, err: UNEXPECTED_NETWORK_ERROR_MESSAGE });\n }\n }\n\n handlePayloadTooLargeResponse(context: SessionReplayDestinationContext, isWaf: boolean): void {\n const source = isWaf ? 'WAF (compressed payload too large)' : 'server (event too large)';\n const totalSizeKB = Math.round(context.events.reduce((sum, e) => sum + e.length, 0) / KB_SIZE);\n\n if (!isWaf) {\n this.completeRequest({\n context,\n err: `Session replay event batch dropped: ${source} rejected payload (${context.events.length} events, ${totalSizeKB} KB) — not retrying non-WAF 413`,\n });\n return;\n }\n\n if (context.events.length === 1) {\n this.completeRequest({\n context,\n err: `Session replay event dropped: single event (${totalSizeKB} KB, 1 event) rejected by ${source} — cannot split further`,\n });\n return;\n }\n\n this.loggerProvider.warn(\n `Session replay event batch rejected by ${source} (${context.events.length} events, ${totalSizeKB} KB total) — splitting and retrying`,\n );\n\n // Clean up the original IDB record, then re-enqueue both halves as new in-memory batches.\n // For a merged-on-throttle context (mergeQueueAfterThrottle), this onComplete is the\n // fanned-out callback covering N source IDB records — they'll all be cleaned up here.\n // Halves get noop onCompletes, so a page-close between this cleanup and a half delivery\n // means up to N source sequences are lost. The merge soft cap (1.4MB chars) is well under\n // the 10MB compressed 413 ceiling, so a 413 on a merged context is exceedingly rare in\n // practice; the alternative — deferring source cleanup until both halves complete — would\n // significantly complicate the retry path for marginal benefit.\n void context.onComplete();\n const noop = (): Promise<void> => Promise.resolve();\n const mid = Math.floor(context.events.length / 2);\n this.sendEventsList({ ...context, events: context.events.slice(0, mid), onComplete: noop });\n this.sendEventsList({ ...context, events: context.events.slice(mid), onComplete: noop });\n }\n\n handleSuccessResponse(context: SessionReplayDestinationContext) {\n const sizeOfEventsList = Math.round(new Blob(context.events).size / KB_SIZE);\n this.completeRequest({\n context,\n success: `Session replay event batch tracked successfully for session id ${context.sessionId}, size of events: ${sizeOfEventsList} KB`,\n });\n }\n\n async handleOtherResponse(context: SessionReplayDestinationContext) {\n const delay = Math.random() * context.attempts * this.retryTimeout;\n context.attempts++;\n if (context.attempts > (context.flushMaxRetries || 0)) {\n this.completeRequest({ context, err: MAX_RETRIES_EXCEEDED_MESSAGE });\n return;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n await this.send(context, true);\n }\n\n completeRequest({\n context,\n err,\n success,\n }: {\n context: SessionReplayDestinationContext;\n err?: string;\n success?: string;\n }) {\n void context.onComplete();\n if (err) {\n this.loggerProvider.warn(err);\n } else if (success) {\n this.loggerProvider.log(success);\n }\n }\n\n /**\n * Applies the server's back-pressure signal carried on a 200 response.\n *\n * - `EVENT_SKIP_CODE_THROTTLED` (server-side rate limit): pause the flush schedule\n * for `THROTTLED_FLUSH_PAUSE_MS` so we keep batching events instead of retry-storming.\n * - `EVENT_SKIP_CODE_CAPTURE_DISABLED` / `EVENT_SKIP_CODE_INVALID_RANGE`: hard kill\n * switch for this session — drop the queued contexts and stop accepting new ones.\n * New sessions are unaffected.\n * - `null` (clean 200, no header): clear any throttle pause; subsequent flushes resume\n * on the normal cadence.\n */\n private applyServerDirective(sessionId: string | number, skipCode: string | null) {\n if (skipCode === null) {\n this.flushPauseUntilMs = 0;\n this.mergeLogFiredThisPause = false;\n return;\n }\n if (skipCode === EVENT_SKIP_CODE_THROTTLED) {\n const wasInPause = this.flushPauseUntilMs > Date.now();\n this.flushPauseUntilMs = Date.now() + THROTTLED_FLUSH_PAUSE_MS;\n // Log only on pause-state transitions — a throttled server may reply to many\n // batches per minute, and one log per batch would flood the console.\n if (!wasInPause) {\n this.loggerProvider.log(\n `Session replay throttled by server; pausing flush schedule for ${THROTTLED_FLUSH_PAUSE_MS / 1000}s`,\n );\n }\n return;\n }\n if (skipCode === EVENT_SKIP_CODE_CAPTURE_DISABLED || skipCode === EVENT_SKIP_CODE_INVALID_RANGE) {\n this.killSession(sessionId, skipCode);\n }\n // Unknown skip codes are ignored — the server may add new ones, and our default\n // behavior (treat as a normal 200) preserves throughput rather than penalizing the\n // session for a code we don't recognize.\n }\n\n private killSession(sessionId: string | number, skipCode: string) {\n if (this.killedSessions.has(sessionId)) return;\n this.killedSessions.add(sessionId);\n // Set preserves insertion order, so deleting the first key evicts the oldest entry.\n if (this.killedSessions.size > MAX_KILLED_SESSIONS) {\n for (const oldest of this.killedSessions) {\n this.killedSessions.delete(oldest);\n break;\n }\n }\n this.loggerProvider.log(\n `Session replay capture stopped for session ${sessionId} by server directive ${skipCode}; remaining events will be dropped`,\n );\n // Drain any queued contexts for this session so their IDB records get cleaned up\n // via onComplete, instead of sitting in the queue waiting for a flush we'll never make.\n const remaining: SessionReplayDestinationContext[] = [];\n for (const queued of this.queue) {\n if (queued.sessionId === sessionId) {\n this.completeRequest({ context: queued, err: SESSION_KILLED_MESSAGE });\n } else {\n remaining.push(queued);\n }\n }\n this.queue = remaining;\n }\n}\n","/**\n * Gzip-compresses a JSON string using the CompressionStream API.\n * The `scope` parameter must be the global object (window or self) that\n * owns the CompressionStream constructor. The caller is responsible for\n * verifying that CompressionStream exists on that scope before calling.\n * Returns null if compression fails for any reason.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function gzipJson(jsonStr: string, scope: any): Promise<Uint8Array | null> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n const CS = scope.CompressionStream as typeof CompressionStream;\n const stream = new CS('gzip');\n const writer = stream.writable.getWriter();\n const reader = stream.readable.getReader();\n\n // Read concurrently with write+close. CompressionStream applies back-pressure:\n // close() blocks until all compressed output is consumed, so the reader must\n // run in parallel or close() will deadlock waiting for the readable side to drain.\n const chunks: Uint8Array[] = [];\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const readPromise: Promise<void> = (async () => {\n for (;;) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { done, value } = await reader.read();\n if (done) break;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n chunks.push(value);\n }\n })();\n\n await writer.write(new TextEncoder().encode(jsonStr));\n await writer.close();\n await readPromise;\n\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n } catch {\n return null;\n }\n}\n","import { ILogger } from '@amplitude/analytics-core';\nimport { DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES, MAX_INTERVAL, MIN_INTERVAL } from '../constants';\nimport { Events, EventsStore, SendingSequencesReturn } from '../typings/session-replay';\n\nexport type InstanceArgs = {\n loggerProvider: ILogger;\n minInterval?: number;\n maxInterval?: number;\n maxPersistedEventsSize?: number;\n};\n\nexport abstract class BaseEventsStore<KeyType> implements EventsStore<KeyType> {\n protected readonly loggerProvider: ILogger;\n private minInterval = MIN_INTERVAL;\n private maxInterval = MAX_INTERVAL;\n private maxPersistedEventsSize = DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES;\n // Assigned in the constructor after `minInterval` is overridden by `args`. Class-field\n // initializers run before the constructor body, so initializing here would freeze\n // `interval` at the class-field default (500ms) — defeating any caller-supplied minInterval\n // for the very first split.\n private interval!: number;\n private _timeAtLastSplit = Date.now(); // Initialize this so we have a point of comparison when events are recorded\n\n public get timeAtLastSplit() {\n return this._timeAtLastSplit;\n }\n\n constructor(args: InstanceArgs) {\n this.loggerProvider = args.loggerProvider;\n this.minInterval = args.minInterval ?? this.minInterval;\n this.maxInterval = args.maxInterval ?? this.maxInterval;\n this.maxPersistedEventsSize = args.maxPersistedEventsSize ?? this.maxPersistedEventsSize;\n this.interval = this.minInterval;\n }\n\n abstract addEventToCurrentSequence(\n sessionId: string | number,\n event: string,\n ): Promise<SendingSequencesReturn<KeyType> | undefined>;\n abstract getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>;\n abstract storeCurrentSequence(sessionId: number): Promise<SendingSequencesReturn<KeyType> | undefined>;\n abstract storeSendingEvents(sessionId: string | number, events: Events): Promise<KeyType | undefined>;\n abstract cleanUpSessionEventsStore(sessionId: number, sequenceId: KeyType): Promise<void>;\n\n /**\n * Returns the UTF-8 byte size of a string without buffer allocation, matching the\n * actual wire byte count for non-ASCII content (Base64 image data, emoji, etc.).\n */\n private getStringSize(str: string): number {\n let bytes = 0;\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code <= 0x7f) {\n bytes++;\n } else if (code <= 0x7ff) {\n bytes += 2;\n } else if (code >= 0xd800 && code <= 0xdbff) {\n // High surrogate — check for a valid low surrogate before consuming the pair.\n const next = i + 1 < str.length ? str.charCodeAt(i + 1) : NaN;\n if (next >= 0xdc00 && next <= 0xdfff) {\n // Valid surrogate pair → encodes a code point above U+FFFF (4 UTF-8 bytes).\n bytes += 4;\n i++;\n } else {\n // Orphaned high surrogate — treated as a replacement character (3 UTF-8 bytes).\n bytes += 3;\n }\n } else if (code >= 0xdc00 && code <= 0xdfff) {\n // Orphaned low surrogate — treated as a replacement character (3 UTF-8 bytes).\n bytes += 3;\n } else {\n // Other BMP character (U+0800–U+FFFF, excluding surrogates): 3 UTF-8 bytes.\n bytes += 3;\n }\n }\n return bytes;\n }\n\n /**\n * Calculates the total UTF-8 byte size of events array\n * Accounts for JSON serialization overhead when sent to backend\n */\n private getEventsArraySize(events: Events): number {\n let totalSize = 0;\n for (const event of events) {\n totalSize += this.getStringSize(event);\n }\n\n // Approximate overhead from the array portion of the JSON payload:\n // - Array brackets: [] = 2 bytes\n // - Commas between events: events.length - 1 bytes\n // - Double quotes wrapping each event string: events.length * 2 bytes\n // Note: does not include the outer { version, events } wrapper (~22 bytes) or\n // per-event JSON-escaping of \" and \\ characters; the 2 MB MAX_EVENT_LIST_SIZE cap\n // stays well under the server's 10 MB decompressed split threshold even with those.\n const overhead = 2 + Math.max(0, events.length - 1) + events.length * 2;\n\n return totalSize + overhead;\n }\n\n /**\n * Determines whether to send the events list to the backend and start a new\n * empty events list, based on the size of the list as well as the last time sent\n * @param nextEventString\n * @returns boolean\n */\n shouldSplitEventsList = (events: Events, nextEventString: string): boolean => {\n const sizeOfNextEvent = this.getStringSize(nextEventString);\n const sizeOfEventsList = this.getEventsArraySize(events);\n\n // Check size constraint first (most likely to trigger)\n if (sizeOfEventsList + sizeOfNextEvent >= this.maxPersistedEventsSize) {\n return true;\n }\n if (Date.now() - this.timeAtLastSplit > this.interval && events.length) {\n this.interval = Math.min(this.maxInterval, this.interval + this.minInterval);\n this._timeAtLastSplit = Date.now();\n return true;\n }\n return false;\n };\n}\n","import { ILogger } from '@amplitude/analytics-core';\n\n/**\n * IndexedDB can surface transient AbortErrors (internal cancellations,\n * cleanup) that are not actionable by customers. We downgrade these from\n * warn → debug to avoid triggering Sentry alerts in customer projects.\n * Duck-types on name rather than instanceof DOMException because the idb\n * wrapper library and test environments may surface plain Error objects.\n */\nconst isAbortError = (e: unknown): boolean =>\n typeof e === 'object' && e !== null && (e as { name?: string }).name === 'AbortError';\n\n/**\n * Logs an IDB error at the appropriate level: debug for transient\n * AbortErrors (to avoid customer Sentry noise), warn for everything else.\n */\nexport const logIdbError = (logger: ILogger, message: string, error?: unknown) => {\n if (isAbortError(error)) {\n logger.debug(message);\n } else {\n logger.warn(message);\n }\n};\n","import { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { STORAGE_FAILURE } from '../messages';\nimport { EventType, Events, SendingSequencesReturn } from '../typings/session-replay';\nimport { BaseEventsStore, InstanceArgs as BaseInstanceArgs } from './base-events-store';\nimport { logIdbError } from '../utils/is-abort-error';\n\n// crypto.randomUUID() requires a secure context (https). Fall back to a\n// Math.random-based UUID for http origins or older browsers — tab IDs don't\n// need to be cryptographically secure, just unique within a session.\nexport function generateUUID(): string {\n try {\n return crypto.randomUUID();\n } catch {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n });\n }\n}\n\nexport const currentSequenceKey = 'sessionCurrentSequence';\nexport const sequencesToSendKey = 'sequencesToSend';\nexport const remoteConfigKey = 'remoteConfig';\n\n// Timeout for openDB at init. IDB openDB can hang forever when another tab\n// holds an open connection during a version upgrade, or when the DB is in a\n// \"closing\" state (documented Chrome behaviour). When that happens we want\n// SessionReplayEventsIDBStore.new() to bail out so the caller can fall back\n// to the in-memory store.\nexport const OPEN_DB_TIMEOUT_MS = 2000;\n\n// Timeout for per-operation tx.done settlement. Mid-recording a readwrite\n// transaction can stall (storage pressure in some browsers stalls instead of\n// throwing); without a timeout, recordFailure() is never called and the\n// memory fallback never triggers. The transaction may still settle later;\n// the timedOut flag prevents double-counting alongside errorLogged.\nexport const TX_DONE_TIMEOUT_MS = 5000;\n\n/**\n * Race a promise against a timeout. Resolves/rejects with the original\n * promise's value when it settles first; rejects with a timeout error if\n * `ms` elapses first. Either way the timer is cleared so we don't leak\n * pending setTimeouts.\n */\nexport function withTimeout<T>(promise: Promise<T>, ms: number, message = 'IDB operation timed out'): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`${message} after ${ms}ms`)), ms);\n promise.then(\n (v) => {\n clearTimeout(timer);\n resolve(v);\n },\n (e) => {\n clearTimeout(timer);\n reject(e);\n },\n );\n });\n}\n\n/**\n * Arms a watchdog that fires `onTimeout` only if `tx.done` hasn't settled\n * within `ms`. A \"soft cancel\" returned to the caller suppresses the timeout\n * if the synchronous operation body completes without exception — important\n * because in test environments fake timers can fire ahead of tx.done's commit\n * microtask. Production behaviour is preserved: a genuinely stalled\n * transaction (no commit, no error, individual op promises never resolved)\n * cannot reach the soft-cancel call and the timeout fires as designed.\n *\n * Soft-cancel is only invoked once the awaits inside the operation's outer\n * try block have all returned — i.e. the IDB driver acknowledged each\n * individual put/get. If the driver accepts a put but the underlying\n * transaction silently fails to commit (the production stall scenario),\n * tx.done still hasn't settled, and recordFailure must NOT have been\n * suppressed. The fix for that scenario in production is the tx.done.catch\n * handler attached separately by callers, which catches the eventual abort.\n *\n * The soft-cancel pattern only suppresses the timeout for the \"all puts\n * resolved successfully\" case — a case where tx.done is overwhelmingly\n * likely to settle imminently in production. If it doesn't, callers can\n * still detect the failure on the NEXT operation (which will fail to open\n * a transaction or hit the same pressure), because all three methods use\n * readwrite transactions on the same two stores, which IDB serializes:\n * if T1's tx.done never settles, T2 is blocked waiting for T1 to commit or\n * abort — T2's put/get requests never resolve, T2 never reaches its\n * soft-cancel, and T2's watchdog fires, calling recordFailure().\n */\nfunction armTxDoneTimeout(txDone: Promise<unknown>, ms: number, onTimeout: () => void): () => void {\n const timer = setTimeout(onTimeout, ms);\n // Belt-and-braces: clear the timer when tx.done settles, even though the\n // primary cancel path is the caller's success-path cancel(). This covers\n // the case where tx.done settles with no caller cancellation (shouldn't\n // happen in current code paths, but cheap insurance).\n txDone.then(\n () => clearTimeout(timer),\n () => clearTimeout(timer),\n );\n return () => clearTimeout(timer);\n}\n\nexport interface SessionReplayDB extends DBSchema {\n sessionCurrentSequence: {\n key: number;\n value: Omit<SendingSequencesReturn<number>, 'sequenceId'> & { tabId?: string };\n };\n sequencesToSend: {\n key: number;\n value: Omit<SendingSequencesReturn<number>, 'sequenceId'> & { tabId?: string };\n indexes: { sessionId: string | number };\n };\n}\n\nexport const defineObjectStores = (db: IDBPDatabase<SessionReplayDB>) => {\n let sequencesStore;\n let currentSequenceStore;\n if (!db.objectStoreNames.contains(currentSequenceKey)) {\n currentSequenceStore = db.createObjectStore(currentSequenceKey, {\n keyPath: 'sessionId',\n });\n }\n if (!db.objectStoreNames.contains(sequencesToSendKey)) {\n sequencesStore = db.createObjectStore(sequencesToSendKey, {\n keyPath: 'sequenceId',\n autoIncrement: true,\n });\n sequencesStore.createIndex('sessionId', 'sessionId');\n }\n return {\n sequencesStore,\n currentSequenceStore,\n };\n};\n\nexport const createStore = async (dbName: string) => {\n // Wrap openDB with a timeout so a hung connection (foreign tab holding an\n // open handle during version upgrade, or \"closing\" DB) doesn't block the\n // SDK from initialising. On timeout this rejects, which propagates up to\n // SessionReplayEventsIDBStore.new()'s catch block, returning undefined and\n // triggering the memory fallback.\n return await withTimeout(\n openDB<SessionReplayDB>(dbName, 1, {\n upgrade: defineObjectStores,\n }),\n OPEN_DB_TIMEOUT_MS,\n 'IDB openDB timed out',\n );\n};\n\ntype InstanceArgs = {\n apiKey: string;\n db: IDBPDatabase<SessionReplayDB>;\n tabId: string;\n onPersistentFailure?: () => void;\n consecutiveFailureThreshold?: number;\n} & BaseInstanceArgs;\n\nexport class SessionReplayEventsIDBStore extends BaseEventsStore<number> {\n private readonly db: IDBPDatabase<SessionReplayDB>;\n private readonly tabId: string;\n private readonly onPersistentFailure?: () => void;\n private readonly consecutiveFailureThreshold: number;\n private consecutiveFailures = 0;\n private hasTriggeredFallback = false;\n private emptyFilteredCount = 0;\n\n // Sampled (1 in 100) debug log so we can observe whether the store-layer guards\n // are catching empty-batch cases that would otherwise hit the empty-body 400 path\n // on the server. Logged at debug, not warn — this is operational telemetry for\n // post-deploy verification, not a customer-actionable warning. Per-store-instance\n // counter (rather than Math.random) keeps the first hit deterministic for tests.\n private maybeLogEmptyFiltered(source: string) {\n if (this.emptyFilteredCount++ % 100 === 0) {\n this.loggerProvider.debug(`Filtered empty session replay sequence at ${source} (idb store)`);\n }\n }\n\n constructor(args: InstanceArgs) {\n super(args);\n this.db = args.db;\n this.tabId = args.tabId;\n this.onPersistentFailure = args.onPersistentFailure;\n // Default threshold of 1: fall back to memory immediately on the first IDB failure.\n // Session replay correctness is far more important than persistence, and IDB errors\n // are typically the symptom of a deeper problem (storage pressure, locked DB, broken\n // browser implementation) that won't recover within a single session. Memory store\n // is always safe — fall back early.\n this.consecutiveFailureThreshold = args.consecutiveFailureThreshold ?? 1;\n }\n\n private recordFailure() {\n this.consecutiveFailures++;\n if (!this.hasTriggeredFallback && this.consecutiveFailures >= this.consecutiveFailureThreshold) {\n this.hasTriggeredFallback = true;\n this.onPersistentFailure?.();\n }\n }\n\n private recordSuccess() {\n this.consecutiveFailures = 0;\n }\n\n static async new(\n type: EventType,\n args: Omit<InstanceArgs, 'db' | 'tabId'> & { tabId?: string },\n ): Promise<SessionReplayEventsIDBStore | undefined> {\n try {\n const dbSuffix = type === 'replay' ? '' : `_${type}`;\n const dbName = `${args.apiKey.substring(0, 10)}_amp_session_replay_events${dbSuffix}`;\n const db = await createStore(dbName);\n // Generate a fresh in-memory UUID per store instance. sessionStorage is\n // intentionally avoided: standalone session-replay customers (without the\n // analytics-browser SDK) would be exposed to a new storage surface they\n // did not consent to, and persistence across page reloads is not needed —\n // completed sequences in sequencesToSend are flushed by any tab/instance.\n const tabId = args.tabId ?? generateUUID();\n return new SessionReplayEventsIDBStore({\n ...args,\n db,\n tabId,\n });\n } catch (e) {\n logIdbError(args.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n }\n return;\n }\n\n async getCurrentSequenceEvents(sessionId?: number) {\n if (sessionId) {\n const record = await this.db.get('sessionCurrentSequence', sessionId);\n if (!record) {\n return undefined;\n }\n // Only return our own tab's record (or legacy untagged records).\n if (record.tabId && record.tabId !== this.tabId) {\n return undefined;\n }\n const { tabId: _tabId, ...rest } = record;\n return [rest];\n }\n\n const allEvents = [];\n for (const record of await this.db.getAll('sessionCurrentSequence')) {\n if (record.tabId && record.tabId !== this.tabId) {\n continue;\n }\n const { tabId: _tabId, ...rest } = record;\n allEvents.push(rest);\n }\n\n return allEvents;\n }\n\n getSequencesToSend = async (): Promise<SendingSequencesReturn<number>[] | undefined> => {\n let errorLogged = false;\n let timedOut = false;\n try {\n const sequences: SendingSequencesReturn<number>[] = [];\n // readwrite mode so we can prune stale empty rows in-place. Without that,\n // older-SDK-persisted events:[] rows sit in IDB indefinitely and re-fire the\n // sampled log on every flush cycle, creating Datadog noise indistinguishable\n // from active bug occurrences.\n const tx = this.db.transaction('sequencesToSend', 'readwrite');\n // Attach a catch handler immediately so tx.done rejections (e.g. AbortError after\n // cursor traversal completes) are always handled without blocking the return path.\n // The errorLogged / timedOut flags prevent double-logging and double-recording\n // when the outer catch (or the timeout race) already fired for the same abort.\n tx.done.catch((e: unknown) => {\n if (!errorLogged && !timedOut) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n });\n // Arm a watchdog so a stalled transaction (no error, no commit, e.g.\n // storage pressure on some browsers) still trips the failure counter.\n // The watchdog fires only when tx.done genuinely never settles AND the\n // operation's success path didn't run; if tx.done rejects (abort), the\n // tx.done.catch handler above is the sole recorder of failure.\n const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n if (!errorLogged && !timedOut) {\n timedOut = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n this.recordFailure();\n }\n });\n let cursor = await tx.store.openCursor();\n while (cursor) {\n const { sessionId, events } = cursor.value;\n // Skip empty persisted records. These can come from older SDK builds that\n // wrote zero-event sequences via addEventToCurrentSequence's split path\n // (when a single oversized event triggered a split with empty buffer);\n // flushing them produces empty-body POSTs the server rejects with 400.\n // Delete them in-place so they don't re-fire the sampled log on every\n // subsequent flush — by construction (this fix) we never write empty rows\n // anymore, so any empty row is unambiguously stale.\n if (events.length === 0) {\n this.maybeLogEmptyFiltered('getSequencesToSend');\n await cursor.delete();\n } else {\n // Return all completed sequences regardless of tabId. Filtering by tab\n // would cause event loss on page reload: a new store instance gets a\n // fresh in-memory UUID and would never see sequences written by the\n // previous instance. Completed sequences are safe to flush by any\n // tab/instance; the server deduplicates, and cleanUpSessionEventsStore\n // on an already-deleted key is a no-op.\n sequences.push({\n events,\n sequenceId: cursor.key,\n sessionId,\n });\n }\n cursor = await cursor.continue();\n }\n\n this.recordSuccess();\n cancelTimeout();\n return sequences;\n } catch (e) {\n if (!timedOut) {\n errorLogged = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n }\n return undefined;\n };\n\n storeCurrentSequence = async (sessionId: number) => {\n let errorLogged = false;\n let timedOut = false;\n try {\n // Wrap the read of sessionCurrentSequence and the writes to sequencesToSend +\n // sessionCurrentSequence in a single readwrite transaction so the three operations\n // commit or roll back atomically. Without this, a concurrent addEventToCurrentSequence\n // call could interleave and either lose the events being promoted or duplicate them\n // (storeCurrentSequence reads N events, addEvent appends an N+1th, storeCurrentSequence\n // writes only the first N back to sequencesToSend, then resets the slot — losing N+1).\n const tx = this.db.transaction([currentSequenceKey, sequencesToSendKey], 'readwrite');\n tx.done.catch((e: unknown) => {\n if (!errorLogged && !timedOut) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n });\n // Stalled-transaction protection: see armTxDoneTimeout in getSequencesToSend.\n const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n if (!errorLogged && !timedOut) {\n timedOut = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n this.recordFailure();\n }\n });\n\n const currentSequenceData = await tx.objectStore(currentSequenceKey).get(sessionId);\n // Skip promotion if the slot is empty or owned by another tab — let the owning\n // tab promote its own events on its next addEventToCurrentSequence/storeCurrentSequence\n // call (via Bug 1's foreign-tab promotion path).\n // Don't call recordSuccess() here: no write was performed, so this is not\n // evidence the storage layer is healthy — leave the failure counter unchanged.\n if (!currentSequenceData || (currentSequenceData.tabId && currentSequenceData.tabId !== this.tabId)) {\n cancelTimeout();\n return undefined;\n }\n\n // Skip empty sequences — no point writing a zero-event row to sequencesToSend\n // (would later POST as an empty body and 400 on the server).\n if (currentSequenceData.events.length === 0) {\n this.maybeLogEmptyFiltered('storeCurrentSequence');\n cancelTimeout();\n return undefined;\n }\n\n const sequenceId = await tx.objectStore(sequencesToSendKey).put({\n sessionId,\n events: currentSequenceData.events,\n tabId: this.tabId,\n });\n\n await tx.objectStore(currentSequenceKey).put({\n sessionId,\n events: [],\n tabId: this.tabId,\n });\n\n this.recordSuccess();\n cancelTimeout();\n const { tabId: _tabId, ...rest } = currentSequenceData;\n return {\n ...rest,\n sessionId,\n sequenceId,\n };\n } catch (e) {\n if (!timedOut) {\n errorLogged = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n }\n return undefined;\n };\n\n addEventToCurrentSequence = async (sessionId: number, event: string) => {\n let errorLogged = false;\n let timedOut = false;\n try {\n // Always open a readwrite transaction over both stores so that the read and\n // any subsequent write are atomic. IDB serializes readwrite transactions on\n // overlapping stores, so concurrent fire-and-forget callers (events-manager\n // does not await this method) are queued by the engine rather than interleaving\n // — eliminating the TOCTOU race that a narrow-read + separate-write approach\n // would introduce on the split path.\n const tx = this.db.transaction([currentSequenceKey, sequencesToSendKey], 'readwrite');\n // Attach a catch handler immediately so tx.done rejections (e.g. AbortError after\n // put succeeds but before auto-commit) are always handled without blocking.\n // The errorLogged / timedOut flags prevent double-logging when the outer catch\n // (or the timeout) already fired for the same transaction.\n tx.done.catch((e: unknown) => {\n if (!errorLogged && !timedOut) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n });\n // Stalled-transaction protection: see armTxDoneTimeout in getSequencesToSend.\n const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n if (!errorLogged && !timedOut) {\n timedOut = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n this.recordFailure();\n }\n });\n const sequenceEvents = await tx.objectStore(currentSequenceKey).get(sessionId);\n\n // Foreign-tab record path: another tab owns the current-sequence slot for this\n // sessionId. Don't silently overwrite — that would drop the foreign tab's\n // in-progress events. Promote them to sequencesToSend (tabId kept for forensics)\n // before claiming the slot for ourselves. getSequencesToSend no longer filters\n // by tabId, so either tab may flush the promoted sequence; server deduplicates.\n if (sequenceEvents?.tabId && sequenceEvents.tabId !== this.tabId) {\n if (sequenceEvents.events.length > 0) {\n await tx.objectStore(sequencesToSendKey).put({\n sessionId,\n events: sequenceEvents.events,\n tabId: sequenceEvents.tabId,\n });\n }\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n // ownedSequence is either undefined (no record yet) or this tab's record.\n const ownedSequence = sequenceEvents;\n\n if (!ownedSequence) {\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n if (!this.shouldSplitEventsList(ownedSequence.events, event)) {\n await tx\n .objectStore(currentSequenceKey)\n .put({ sessionId, events: ownedSequence.events.concat(event), tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n // Split path: reset sessionCurrentSequence and write the old events to\n // sequencesToSend atomically within the same transaction.\n const eventsToSend = ownedSequence.events;\n\n // shouldSplitEventsList can return true with an empty buffer when a single\n // incoming event is larger than MAX_EVENT_LIST_SIZE (2 MB) — the size-constraint\n // branch fires regardless of current length. Don't write a zero-event row to\n // sequencesToSend (which would later POST as an empty body, the SR-4284 root\n // cause); just claim the slot for the new event without finalizing anything.\n // This is the *primary* root-cause filter site: warn here so post-deploy\n // Datadog can confirm the new SDK is actually preventing the bug at its source\n // (vs. only seeing leftover-state hits at the get/storeCurrentSequence layers).\n if (eventsToSend.length === 0) {\n this.maybeLogEmptyFiltered('addEventToCurrentSequence');\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n const sequenceId = await tx.objectStore(sequencesToSendKey).put({\n sessionId,\n events: eventsToSend,\n tabId: this.tabId,\n });\n\n this.recordSuccess();\n cancelTimeout();\n return {\n events: eventsToSend,\n sessionId,\n sequenceId,\n };\n } catch (e) {\n if (!timedOut) {\n errorLogged = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n }\n return undefined;\n };\n\n storeSendingEvents = async (sessionId: number, events: Events) => {\n try {\n const sequenceId = await this.db.put<'sequencesToSend'>(sequencesToSendKey, {\n sessionId: sessionId,\n events: events,\n tabId: this.tabId,\n });\n this.recordSuccess();\n return sequenceId;\n } catch (e) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n return undefined;\n };\n\n cleanUpSessionEventsStore = async (_sessionId: number, sequenceId?: number) => {\n if (!sequenceId) {\n return;\n }\n try {\n await this.db.delete<'sequencesToSend'>(sequencesToSendKey, sequenceId);\n this.recordSuccess();\n } catch (e) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n };\n}\n","import { Events, SendingSequencesReturn } from '../typings/session-replay';\nimport { BaseEventsStore } from './base-events-store';\n\nexport class InMemoryEventsStore extends BaseEventsStore<number> {\n private finalizedSequences: Record<number, { sessionId: string | number; events: string[] }> = {};\n private sequences: Record<string | number, string[]> = {};\n private sequenceId = 0;\n private emptyFilteredCount = 0;\n\n private resetCurrentSequence(sessionId: string | number) {\n this.sequences[sessionId] = [];\n }\n\n private addSequence(sessionId: string | number): SendingSequencesReturn<number> {\n const sequenceId = this.sequenceId++;\n const events = [...this.sequences[sessionId]];\n this.finalizedSequences[sequenceId] = { sessionId, events };\n this.resetCurrentSequence(sessionId);\n return { sequenceId, events, sessionId };\n }\n\n // Sampled (1 in 100) debug log so we can observe whether the store-layer guards\n // are actually catching cases that would otherwise hit the empty-body 400 path on\n // the server. Logged at debug, not warn — this is operational telemetry for\n // post-deploy verification, not a customer-actionable warning. Per-store-instance\n // counter rather than Math.random keeps the first hit deterministic for tests.\n private maybeLogEmptyFiltered(source: string) {\n if (this.emptyFilteredCount++ % 100 === 0) {\n this.loggerProvider.debug(`Filtered empty session replay sequence at ${source} (in-memory store)`);\n }\n }\n\n async getSequencesToSend(): Promise<SendingSequencesReturn<number>[] | undefined> {\n const result: SendingSequencesReturn<number>[] = [];\n for (const [sequenceId, { sessionId, events }] of Object.entries(this.finalizedSequences)) {\n if (events.length === 0) {\n // Prune in-place for consistency with the IDB store: by construction we\n // never write empty sequences anymore, so any empty entry is unambiguously\n // stale residue. Without the delete, every subsequent getSequencesToSend\n // would re-iterate the empty entry and re-fire the sampled log, producing\n // repeated noise that's indistinguishable from active bug occurrences.\n this.maybeLogEmptyFiltered('getSequencesToSend');\n delete this.finalizedSequences[Number(sequenceId)];\n continue;\n }\n result.push({ sequenceId: Number(sequenceId), sessionId, events });\n }\n return result;\n }\n\n async storeCurrentSequence(sessionId: string | number): Promise<SendingSequencesReturn<number> | undefined> {\n const buffered = this.sequences[sessionId];\n if (!buffered) {\n return undefined;\n }\n if (buffered.length === 0) {\n // Slot exists but is empty (e.g. drained by a prior storeCurrentSequence then\n // re-flushed before any new event landed). Don't finalize a zero-event row.\n this.maybeLogEmptyFiltered('storeCurrentSequence');\n return undefined;\n }\n return this.addSequence(sessionId);\n }\n\n async addEventToCurrentSequence(\n sessionId: number,\n event: string,\n ): Promise<SendingSequencesReturn<number> | undefined> {\n if (!this.sequences[sessionId]) {\n this.resetCurrentSequence(sessionId);\n }\n\n let sequenceReturn: SendingSequencesReturn<number> | undefined;\n // shouldSplitEventsList can return true with an empty buffer when a single\n // incoming event is larger than MAX_EVENT_LIST_SIZE (2 MB) — the size-constraint\n // branch fires regardless of current length. Don't finalize a zero-event sequence\n // (the SR-4284 root cause); just hold the incoming event in the buffer.\n // shouldSplitEventsList's time-elapsed branch only fires when events.length > 0\n // (see base-events-store.ts), so calling it on an empty buffer has no side effects.\n if (this.shouldSplitEventsList(this.sequences[sessionId], event)) {\n if (this.sequences[sessionId].length === 0) {\n this.maybeLogEmptyFiltered('addEventToCurrentSequence');\n } else {\n sequenceReturn = this.addSequence(sessionId);\n }\n }\n\n this.sequences[sessionId].push(event);\n\n return sequenceReturn;\n }\n\n async storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined> {\n this.finalizedSequences[this.sequenceId] = { sessionId, events };\n\n return this.sequenceId++;\n }\n\n async cleanUpSessionEventsStore(_sessionId: number, sequenceId?: number): Promise<void> {\n if (sequenceId !== undefined) {\n delete this.finalizedSequences[sequenceId];\n }\n }\n}\n","import {\n SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n EventsStore,\n EventType,\n StoreType,\n} from '../typings/session-replay';\n\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { MAX_SINGLE_EVENT_SIZE } from '../constants';\nimport { getStorageSize } from '../helpers';\nimport { PayloadBatcher, SessionReplayTrackDestination } from '../track-destination';\nimport { SessionReplayEventsIDBStore } from './events-idb-store';\nimport { InMemoryEventsStore } from './events-memory-store';\n\nexport type EventsManagerWithBeacon<Type extends EventType> = AmplitudeSessionReplayEventsManager<Type, string> & {\n /**\n * Returns current pending events (since last flush) for synchronous access on page exit.\n * Used to populate a sendBeacon payload when the page is unloading.\n */\n getBeaconEvents(): string[];\n /**\n * Drops all pending beacon events. Used when the session is decided to be below\n * the min duration threshold so its events don't leak into a later session's beacon.\n */\n dropPendingBeaconEvents(): void;\n trackDestination: SessionReplayTrackDestination;\n};\n\nexport const createEventsManager = async <Type extends EventType>({\n config,\n minInterval,\n maxInterval,\n maxPersistedEventsSize,\n type,\n payloadBatcher,\n storeType,\n trackDestinationWorkerScript,\n shouldSend,\n}: {\n config: SessionReplayJoinedConfig;\n type: Type;\n minInterval?: number;\n maxInterval?: number;\n maxPersistedEventsSize?: number;\n payloadBatcher?: PayloadBatcher;\n storeType: StoreType;\n trackDestinationWorkerScript?: string;\n shouldSend?: () => boolean;\n}): Promise<EventsManagerWithBeacon<Type>> => {\n // Configurable per-single-event drop cap (defaults to MAX_SINGLE_EVENT_SIZE); enforced both\n // here as a pre-send backstop and at capture time in EventCompressor.\n const maxSingleEventSize = config.maxSingleEventSizeBytes ?? MAX_SINGLE_EVENT_SIZE;\n const trackDestination = new SessionReplayTrackDestination({\n ...config,\n loggerProvider: config.loggerProvider,\n payloadBatcher,\n workerScript: trackDestinationWorkerScript,\n });\n\n const getMemoryStore = (): EventsStore<number> => {\n return new InMemoryEventsStore({\n loggerProvider: config.loggerProvider,\n maxInterval,\n minInterval,\n maxPersistedEventsSize,\n });\n };\n\n let lastKnownDeviceId: string | undefined;\n let usingIdbStore = false;\n let store!: EventsStore<number>;\n\n const switchToMemoryStore = async () => {\n if (!usingIdbStore) return;\n usingIdbStore = false;\n config.loggerProvider.warn('IDB store is experiencing repeated failures; falling back to in-memory event store.');\n const sequences = lastKnownDeviceId ? await store.getSequencesToSend() : undefined;\n store = getMemoryStore();\n if (sequences && lastKnownDeviceId) {\n const deviceId = lastKnownDeviceId;\n sequences.forEach((seq) => {\n sendEventsList({ sequenceId: seq.sequenceId, events: seq.events, sessionId: seq.sessionId, deviceId });\n });\n }\n };\n\n const getIdbStoreOrFallback = async (): Promise<EventsStore<number>> => {\n const idb = await SessionReplayEventsIDBStore.new(type, {\n loggerProvider: config.loggerProvider,\n minInterval,\n maxInterval,\n maxPersistedEventsSize,\n apiKey: config.apiKey,\n onPersistentFailure: () => {\n void switchToMemoryStore();\n },\n });\n if (!idb) {\n config.loggerProvider.log('Failed to initialize idb store, falling back to memory store.');\n return getMemoryStore();\n }\n usingIdbStore = true;\n return idb;\n };\n\n store = storeType === 'idb' ? await getIdbStoreOrFallback() : getMemoryStore();\n\n // Beacon buffer: a sliding window of pending (unsent) event strings for synchronous\n // access on page exit. Uses an absolute index counter to correctly handle concurrent\n // async flushes without losing events added between the flush call and its resolution.\n const beaconBuffer: string[] = [];\n let beaconWindowStart = 0; // absolute index of the first element in beaconBuffer\n\n const advanceBeaconWindow = (upToAbsoluteIdx: number) => {\n if (upToAbsoluteIdx <= beaconWindowStart) return;\n const trimCount = Math.min(upToAbsoluteIdx - beaconWindowStart, beaconBuffer.length);\n if (trimCount > 0) {\n beaconBuffer.splice(0, trimCount);\n beaconWindowStart = upToAbsoluteIdx;\n }\n };\n\n /**\n * Immediately sends events to the track destination.\n */\n const sendEventsList = ({\n events: rawEvents,\n sessionId,\n deviceId,\n sequenceId,\n }: {\n events: string[];\n sessionId: string | number;\n deviceId: string;\n sequenceId?: number;\n }) => {\n // Backstop for events that entered IDB before the per-event size guard in\n // addCompressedEventToManager (e.g. stored by a previous SDK version or via\n // storeCurrentSequence/sendStoredEvents which bypass the capture-time check).\n // Compare UTF-8 byte size, not JS char count, to match the server-side limit.\n const sizedEvents = rawEvents.map((e) => ({ event: e, bytes: new Blob([e]).size }));\n const oversized = sizedEvents.filter((s) => s.bytes > maxSingleEventSize);\n if (oversized.length > 0) {\n config.loggerProvider.warn(\n `Dropping ${oversized.length} oversized event(s) from session replay sequence before send. Sizes: ${oversized\n .map((s) => `${Math.round(s.bytes / 1024)} KB`)\n .join(\n ', ',\n )}. If this recurs, please open a GitHub issue at https://github.com/amplitude/Amplitude-TypeScript/issues or contact Amplitude support.`,\n );\n }\n const events =\n oversized.length > 0 ? sizedEvents.filter((s) => s.bytes <= maxSingleEventSize).map((s) => s.event) : rawEvents;\n if (events.length === 0) {\n store.cleanUpSessionEventsStore(sessionId, sequenceId).catch((e) => {\n config.loggerProvider.warn('Failed to clean up session replay events store:', e);\n });\n return;\n }\n\n if (config.debugMode) {\n getStorageSize()\n .then(({ totalStorageSize, percentOfQuota, usageDetails }) => {\n config.loggerProvider.debug(\n `Total storage size: ${totalStorageSize} KB, percentage of quota: ${percentOfQuota}%, usage details: ${usageDetails}`,\n );\n })\n .catch(() => {\n // swallow error\n });\n }\n\n trackDestination.sendEventsList({\n events: events,\n sessionId: sessionId,\n flushMaxRetries: config.flushMaxRetries,\n apiKey: config.apiKey,\n deviceId: deviceId,\n sampleRate: config.sampleRate,\n serverZone: config.serverZone,\n version: config.version,\n type,\n onComplete: async () => {\n await store.cleanUpSessionEventsStore(sessionId, sequenceId);\n return;\n },\n });\n };\n\n const sendCurrentSequenceEvents = ({ sessionId, deviceId }: { sessionId: number; deviceId: string }) => {\n lastKnownDeviceId = deviceId;\n // Evaluate shouldSend synchronously before the async store read. asyncSetSessionId\n // updates sessionStartTime immediately after calling sendEvents(), so by the time\n // storeCurrentSequence resolves the start time would reflect the new session and\n // the elapsed check would compute ~0ms, silently dropping the previous session's events.\n if (shouldSend && !shouldSend()) return;\n // Snapshot the absolute end-index before the async store read so that any events\n // pushed after this point are NOT considered sent and remain in the beacon buffer.\n const snapshotAbsIdx = beaconWindowStart + beaconBuffer.length;\n store\n .storeCurrentSequence(sessionId)\n .then((currentSequence) => {\n if (currentSequence) {\n advanceBeaconWindow(snapshotAbsIdx);\n sendEventsList({\n sequenceId: currentSequence.sequenceId,\n events: currentSequence.events,\n sessionId: currentSequence.sessionId,\n deviceId,\n });\n }\n })\n .catch((e) => {\n config.loggerProvider.warn('Failed to get current sequence of session replay events for session:', e);\n });\n };\n\n const sendStoredEvents = async ({ deviceId }: { deviceId: string }) => {\n lastKnownDeviceId = deviceId;\n const sequencesToSend = await store.getSequencesToSend();\n if (!sequencesToSend?.length) {\n return;\n }\n config.loggerProvider.log(`Draining ${sequencesToSend.length} stored sequence(s) from previous session.`);\n // These persisted sequences are about to be enqueued back-to-back. Without\n // coalescing they flush as N separate POSTs — a request flood on page load. Mark the\n // imminent flush to merge same-identity batches (the enqueues below are synchronous, so\n // the whole backlog lands in the queue before the deferred flush consumes the flag). Skip\n // the single-sequence case where there's nothing to merge.\n if (sequencesToSend.length > 1) {\n trackDestination.markCoalesceNextFlush();\n }\n sequencesToSend.forEach((sequence) => {\n sendEventsList({\n sequenceId: sequence.sequenceId,\n events: sequence.events,\n sessionId: sequence.sessionId,\n deviceId,\n });\n });\n };\n\n const addEvent = ({\n event,\n sessionId,\n deviceId,\n }: {\n event: { type: Type; data: string };\n sessionId: number;\n deviceId: string;\n }) => {\n lastKnownDeviceId = deviceId;\n // Capture shouldSend synchronously before the async store write, for the same\n // reason as sendCurrentSequenceEvents: asyncSetSessionId updates sessionStartTime\n // synchronously, so evaluating inside the .then() would use the new session's\n // start time and compute ~0ms elapsed, silently dropping a valid batch.\n const canSend = !shouldSend || shouldSend();\n // Record the absolute index of this event in the beacon buffer before the async\n // store operation. If a batch split occurs, we advance the window up to (but not\n // including) this event so that it starts the next pending window.\n const absIdx = beaconWindowStart + beaconBuffer.length;\n beaconBuffer.push(event.data);\n store\n .addEventToCurrentSequence(sessionId, event.data)\n .then((sequenceToSend) => {\n if (sequenceToSend) {\n if (!canSend) {\n // The split atomically moved events to sequencesToSend; without cleanup\n // they would be unconditionally replayed on next page load via\n // sendStoredEvents, bypassing the min session duration gate. The split\n // batch must also be dropped from the beacon buffer so it isn't sent\n // via sendBeacon on page unload (potentially attributed to a later session).\n store.cleanUpSessionEventsStore(sequenceToSend.sessionId, sequenceToSend.sequenceId).catch((e) => {\n config.loggerProvider.warn('Failed to clean up dropped session replay sequence:', e);\n });\n advanceBeaconWindow(absIdx);\n return;\n }\n // Events before absIdx belong to the split batch being sent; advance window.\n advanceBeaconWindow(absIdx);\n sendEventsList({\n sequenceId: sequenceToSend.sequenceId,\n events: sequenceToSend.events,\n sessionId: sequenceToSend.sessionId,\n deviceId,\n });\n }\n })\n .catch((e) => {\n config.loggerProvider.warn('Failed to add event to session replay capture:', e);\n });\n };\n\n async function flush(useRetry = false) {\n return trackDestination.flush(useRetry);\n }\n\n const getBeaconEvents = (): string[] => [...beaconBuffer];\n\n const dropPendingBeaconEvents = () => {\n advanceBeaconWindow(beaconWindowStart + beaconBuffer.length);\n };\n\n return {\n sendCurrentSequenceEvents,\n addEvent,\n sendStoredEvents,\n flush,\n getBeaconEvents,\n dropPendingBeaconEvents,\n trackDestination,\n };\n};\n","import {\n SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n EventsManagerWithType,\n} from '../typings/session-replay';\n\n/**\n * \"Registers\" events managers internally. When an event is added this class routes the event to the correct\n * manager. For all send or flush methods this will invoke the event for all registered managers.\n */\nexport class MultiEventManager<EventType, EventDataType>\n implements AmplitudeSessionReplayEventsManager<EventType, EventDataType>\n{\n private managers: Map<EventType, AmplitudeSessionReplayEventsManager<EventType, EventDataType>>;\n\n constructor(...managers: EventsManagerWithType<EventType, EventDataType>[]) {\n const managersMap = new Map<EventType, AmplitudeSessionReplayEventsManager<EventType, EventDataType>>();\n managers.forEach((t) => {\n managersMap.set(t.name, t.manager);\n });\n this.managers = managersMap;\n }\n\n async sendStoredEvents(opts: { deviceId: string }): Promise<void> {\n const promises: Promise<void>[] = [];\n this.managers.forEach((manager) => {\n promises.push(manager.sendStoredEvents(opts));\n });\n await Promise.all(promises);\n }\n\n addEvent({\n sessionId,\n event,\n deviceId,\n }: {\n sessionId: number;\n event: { type: EventType; data: EventDataType };\n deviceId: string;\n }): void {\n this.managers.get(event.type)?.addEvent({ sessionId, event, deviceId });\n }\n\n sendCurrentSequenceEvents({ sessionId, deviceId }: { sessionId: number; deviceId: string }): void {\n this.managers.forEach((manager) => {\n manager.sendCurrentSequenceEvents({ sessionId, deviceId });\n });\n }\n\n async flush(useRetry?: boolean | undefined): Promise<void> {\n const promises: Promise<void>[] = [];\n this.managers.forEach((manager) => {\n promises.push(manager.flush(useRetry));\n });\n await Promise.all(promises);\n }\n}\n","/* istanbul ignore file */\n\n// DO NOT EDIT (unless you know what you're doing)\n// Taken directly from git@github.com:antonmedv/finder.git@77d33158440dfffee4a300d2975b43a5283004ab\n\n/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */\n/* eslint-disable prefer-const */\n\n// License: MIT\n// Author: Anton Medvedev <anton@medv.io>\n// Source: https://github.com/antonmedv/finder\n\ntype Knot = {\n name: string;\n penalty: number;\n level?: number;\n};\n\ntype Path = Knot[];\n\nexport type Options = {\n root: Element;\n idName: (name: string) => boolean;\n className: (name: string) => boolean;\n tagName: (name: string) => boolean;\n attr: (name: string, value: string) => boolean;\n seedMinLength: number;\n optimizedMinLength: number;\n threshold: number;\n maxNumberOfTries: number;\n timeoutMs: number | undefined;\n};\n\nlet config: Options;\nlet rootDocument: Document | Element;\nlet start: Date;\n\nexport function finder(input: Element, options?: Partial<Options>): string {\n start = new Date();\n if (input.nodeType !== Node.ELEMENT_NODE) {\n throw new Error(`Can't generate CSS selector for non-element node type.`);\n }\n if ('html' === input.tagName.toLowerCase()) {\n return 'html';\n }\n const defaults: Options = {\n root: document.body,\n idName: (_name: string) => true,\n className: (_name: string) => true,\n tagName: (_name: string) => true,\n attr: (_name: string, _value: string) => false,\n seedMinLength: 1,\n optimizedMinLength: 2,\n threshold: 1000,\n maxNumberOfTries: 10000,\n timeoutMs: undefined,\n };\n\n config = { ...defaults, ...options };\n rootDocument = findRootDocument(config.root, defaults);\n\n let path = bottomUpSearch(input, 'all', () =>\n bottomUpSearch(input, 'two', () => bottomUpSearch(input, 'one', () => bottomUpSearch(input, 'none'))),\n );\n\n if (path) {\n const optimized = sort(optimize(path, input));\n if (optimized.length > 0) {\n path = optimized[0];\n }\n return selector(path);\n } else {\n throw new Error(`Selector was not found.`);\n }\n}\n\nfunction findRootDocument(rootNode: Element | Document, defaults: Options) {\n if (rootNode.nodeType === Node.DOCUMENT_NODE) {\n return rootNode;\n }\n if (rootNode === defaults.root) {\n return rootNode.ownerDocument as Document;\n }\n return rootNode;\n}\n\nfunction bottomUpSearch(\n input: Element,\n limit: 'all' | 'two' | 'one' | 'none',\n fallback?: () => Path | null,\n): Path | null {\n let path: Path | null = null;\n let stack: Knot[][] = [];\n let current: Element | null = input;\n let i = 0;\n while (current) {\n const elapsedTime = new Date().getTime() - start.getTime();\n if (config.timeoutMs !== undefined && elapsedTime > config.timeoutMs) {\n throw new Error(`Timeout: Can't find a unique selector after ${elapsedTime}ms`);\n }\n let level: Knot[] = maybe(id(current)) ||\n maybe(...attr(current)) ||\n maybe(...classNames(current)) ||\n maybe(tagName(current)) || [any()];\n const nth = index(current);\n if (limit == 'all') {\n if (nth) {\n level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n }\n } else if (limit == 'two') {\n level = level.slice(0, 1);\n if (nth) {\n level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n }\n } else if (limit == 'one') {\n const [node] = (level = level.slice(0, 1));\n if (nth && dispensableNth(node)) {\n level = [nthChild(node, nth)];\n }\n } else if (limit == 'none') {\n level = [any()];\n if (nth) {\n level = [nthChild(level[0], nth)];\n }\n }\n for (let node of level) {\n node.level = i;\n }\n stack.push(level);\n if (stack.length >= config.seedMinLength) {\n path = findUniquePath(stack, fallback);\n if (path) {\n break;\n }\n }\n current = current.parentElement;\n i++;\n }\n if (!path) {\n path = findUniquePath(stack, fallback);\n }\n if (!path && fallback) {\n return fallback();\n }\n return path;\n}\n\nfunction findUniquePath(stack: Knot[][], fallback?: () => Path | null): Path | null {\n const paths = sort(combinations(stack));\n if (paths.length > config.threshold) {\n return fallback ? fallback() : null;\n }\n for (let candidate of paths) {\n if (unique(candidate)) {\n return candidate;\n }\n }\n return null;\n}\n\nfunction selector(path: Path): string {\n let node = path[0];\n let query = node.name;\n for (let i = 1; i < path.length; i++) {\n const level = path[i].level || 0;\n if (node.level === level - 1) {\n query = `${path[i].name} > ${query}`;\n } else {\n query = `${path[i].name} ${query}`;\n }\n node = path[i];\n }\n return query;\n}\n\nfunction penalty(path: Path): number {\n return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);\n}\n\nfunction unique(path: Path) {\n const css = selector(path);\n switch (rootDocument.querySelectorAll(css).length) {\n case 0:\n throw new Error(`Can't select any node with this selector: ${css}`);\n case 1:\n return true;\n default:\n return false;\n }\n}\n\nfunction id(input: Element): Knot | null {\n const elementId = input.getAttribute('id');\n if (elementId && config.idName(elementId)) {\n return {\n name: '#' + CSS.escape(elementId),\n penalty: 0,\n };\n }\n return null;\n}\n\nfunction attr(input: Element): Knot[] {\n const attrs = Array.from(input.attributes).filter((attr) => config.attr(attr.name, attr.value));\n return attrs.map(\n (attr): Knot => ({\n name: `[${CSS.escape(attr.name)}=\"${CSS.escape(attr.value)}\"]`,\n penalty: 0.5,\n }),\n );\n}\n\nfunction classNames(input: Element): Knot[] {\n const names = Array.from(input.classList).filter(config.className);\n return names.map(\n (name): Knot => ({\n name: '.' + CSS.escape(name),\n penalty: 1,\n }),\n );\n}\n\nfunction tagName(input: Element): Knot | null {\n const name = input.tagName.toLowerCase();\n if (config.tagName(name)) {\n return {\n name,\n penalty: 2,\n };\n }\n return null;\n}\n\nfunction any(): Knot {\n return {\n name: '*',\n penalty: 3,\n };\n}\n\nfunction index(input: Element): number | null {\n const parent = input.parentNode;\n if (!parent) {\n return null;\n }\n let child = parent.firstChild;\n if (!child) {\n return null;\n }\n let i = 0;\n while (child) {\n if (child.nodeType === Node.ELEMENT_NODE) {\n i++;\n }\n if (child === input) {\n break;\n }\n child = child.nextSibling;\n }\n return i;\n}\n\nfunction nthChild(node: Knot, i: number): Knot {\n return {\n name: node.name + `:nth-child(${i})`,\n penalty: node.penalty + 1,\n };\n}\n\nfunction dispensableNth(node: Knot) {\n return node.name !== 'html' && !node.name.startsWith('#');\n}\n\nfunction maybe(...level: (Knot | null)[]): Knot[] | null {\n const list = level.filter(notEmpty);\n if (list.length > 0) {\n return list;\n }\n return null;\n}\n\nfunction notEmpty<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined;\n}\n\nfunction* combinations(stack: Knot[][], path: Knot[] = []): Generator<Knot[]> {\n if (stack.length > 0) {\n for (let node of stack[0]) {\n yield* combinations(stack.slice(1, stack.length), path.concat(node));\n }\n } else {\n yield path;\n }\n}\n\nfunction sort(paths: Iterable<Path>): Path[] {\n return [...paths].sort((a, b) => penalty(a) - penalty(b));\n}\n\ntype Scope = {\n counter: number;\n visited: Map<string, boolean>;\n};\n\nfunction* optimize(\n path: Path,\n input: Element,\n scope: Scope = {\n counter: 0,\n visited: new Map<string, boolean>(),\n },\n): Generator<Knot[]> {\n if (path.length > 2 && path.length > config.optimizedMinLength) {\n for (let i = 1; i < path.length - 1; i++) {\n if (scope.counter > config.maxNumberOfTries) {\n return; // Okay At least I tried!\n }\n scope.counter += 1;\n const newPath = [...path];\n newPath.splice(i, 1);\n const newPathKey = selector(newPath);\n if (scope.visited.has(newPathKey)) {\n return;\n }\n if (unique(newPath) && same(newPath, input)) {\n yield newPath;\n scope.visited.set(newPathKey, true);\n yield* optimize(newPath, input, scope);\n }\n }\n }\n}\n\nfunction same(path: Path, input: Element) {\n return rootDocument.querySelector(selector(path)) === input;\n}\n","import type { mouseInteractionCallBack } from '@amplitude/rrweb-types';\nimport { MouseInteractions } from '@amplitude/rrweb-types';\nimport { Mirror } from '../utils/rrweb';\nimport { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager } from '../typings/session-replay';\nimport { PayloadBatcher } from '../track-destination';\nimport { finder, Options as FinderOptions } from '../libs/finder';\nimport { getGlobalScope, ILogger } from '@amplitude/analytics-core';\nimport { UGCFilterRule, InteractionPerformanceConfig } from '../config/types';\nimport { getPageUrl } from '../helpers';\nimport { ScrollWatcher } from './scroll';\n\n// exported for testing\nexport type ClickEvent = {\n timestamp: number;\n x: number;\n y: number;\n viewportWidth: number;\n viewportHeight: number;\n pageUrl: string;\n selector?: string;\n type: 'click';\n};\n\n// exported for testing\nexport type ClickEventWithCount = ClickEvent & { count: number };\n\ntype Context = {\n sessionId: string | number;\n deviceIdFn: () => string | undefined;\n eventsManager: AmplitudeSessionReplayEventsManager<'interaction', string>;\n mirror: Mirror;\n ugcFilterRules: UGCFilterRule[];\n performanceOptions?: InteractionPerformanceConfig;\n};\n\nconst HOUR_IN_MILLISECONDS = 3_600_000;\n\nexport const clickNonBatcher: PayloadBatcher = ({ version, events }) => {\n const clickEvents: ClickEvent[] = [];\n events.forEach((evt: string) => {\n const record = JSON.parse(evt) as Record<string, unknown>;\n record.count = 1;\n if (record.type === 'click') {\n clickEvents.push(record as ClickEvent);\n }\n });\n return { version, events: clickEvents };\n};\n\nexport const clickBatcher: PayloadBatcher = ({ version, events }) => {\n const clickEvents: ClickEvent[] = [];\n events.forEach((evt: string) => {\n const record = JSON.parse(evt) as Record<string, unknown>;\n if (record.type === 'click') {\n clickEvents.push(record as ClickEvent);\n }\n });\n\n const reduced = clickEvents.reduce<Record<string, ClickEventWithCount>>((prev, curr) => {\n const { x, y, selector, timestamp } = curr;\n\n // round down to nearest hour.\n const hour = timestamp - (timestamp % HOUR_IN_MILLISECONDS);\n\n const k = `${x}:${y}:${selector ?? ''}:${hour}`;\n if (!prev[k]) {\n prev[k] = { ...curr, timestamp: hour, count: 1 };\n } else {\n prev[k].count += 1;\n }\n return prev;\n }, {});\n\n return { version, events: Object.values(reduced) };\n};\n\nexport class ClickHandler {\n private readonly logger: ILogger;\n private readonly scrollWatcher: ScrollWatcher;\n\n constructor(logger: ILogger, scrollWatcher: ScrollWatcher) {\n this.logger = logger;\n this.scrollWatcher = scrollWatcher;\n }\n\n createHook: (context: Context) => mouseInteractionCallBack = ({\n eventsManager,\n sessionId,\n deviceIdFn,\n mirror,\n ugcFilterRules,\n performanceOptions,\n }) => {\n return (e) => {\n if (e.type !== MouseInteractions.Click) {\n return;\n }\n\n const globalScope = getGlobalScope();\n if (!globalScope) {\n return;\n }\n\n const { location, innerHeight, innerWidth } = globalScope;\n // it only makes sense to send events if a pageUrl exists\n if (!location) {\n return;\n }\n\n const { x, y } = e;\n if (x === undefined || y === undefined) {\n return;\n }\n\n const node = mirror.getNode(e.id);\n let selector;\n if (node) {\n try {\n selector = finder(\n node as Element,\n performanceOptions as Pick<FinderOptions, 'timeoutMs' | 'maxNumberOfTries' | 'threshold'>,\n );\n } catch (err) {\n this.logger.debug('error resolving selector from finder');\n }\n }\n\n const pageUrl = getPageUrl(location.href, ugcFilterRules);\n\n const event: ClickEvent = {\n x: x + this.scrollWatcher.currentScrollX,\n y: y + this.scrollWatcher.currentScrollY,\n selector,\n\n viewportHeight: innerHeight,\n viewportWidth: innerWidth,\n pageUrl,\n timestamp: Date.now(),\n type: 'click',\n };\n const deviceId = deviceIdFn();\n if (deviceId) {\n eventsManager.addEvent({ sessionId, event: { type: 'interaction', data: JSON.stringify(event) }, deviceId });\n }\n };\n };\n}\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport type { eventWithTime, scrollCallback } from '@amplitude/rrweb-types';\n\n// These functions are not exposed in rrweb package, so we will define it here to use\n// Ignoring this function since this is copied from rrweb\nexport function getViewportHeight(): number {\n const globalScope = getGlobalScope();\n return globalScope?.innerHeight || (document.documentElement && document.documentElement.clientHeight) || 0;\n}\n\nexport function getViewportWidth(): number {\n const globalScope = getGlobalScope();\n return globalScope?.innerWidth || (document.documentElement && document.documentElement.clientWidth) || 0;\n}\n\nexport type Mirror = {\n getNode: (id: number) => Node | null;\n};\n\nexport type RecordFunction = {\n (options: {\n emit: (event: eventWithTime) => void;\n inlineStylesheet?: boolean;\n hooks?: {\n mouseInteraction?: any;\n scroll?: scrollCallback;\n };\n maskAllInputs?: boolean;\n maskTextClass?: string;\n blockClass?: string;\n blockSelector?: string;\n maskInputFn?: (text: string, element: HTMLElement | null) => string;\n maskTextFn?: (text: string, element: HTMLElement | null) => string;\n maskAttributeFn?: (key: string, value: string, element: HTMLElement) => string;\n maskTextSelector?: string;\n checkoutEveryNms?: number;\n recordCanvas?: boolean;\n slimDOMOptions?: {\n script?: boolean;\n comment?: boolean;\n headFavicon?: boolean;\n headWhitespace?: boolean;\n headMetaDescKeywords?: boolean;\n headMetaSocial?: boolean;\n headMetaRobots?: boolean;\n headMetaHttpEquiv?: boolean;\n headMetaAuthorship?: boolean;\n headMetaVerification?: boolean;\n };\n errorHandler?: (error: unknown) => boolean;\n plugins?: any[];\n applyBackgroundColorToBlockedElements?: boolean;\n /**\n * When true (default), adoptedStyleSheets CSS rules are serialized inline in the full snapshot\n * rather than emitted as separate incremental events that can be dropped in transit.\n * Set to false to revert to the legacy incremental-event path if snapshot size is a concern.\n */\n captureAdoptedStyleSheets?: boolean;\n recordCrossOriginIframes?: boolean;\n }): (() => void) | undefined;\n addCustomEvent: (eventName: string, eventData: any) => void;\n takeFullSnapshot: (isCheckout?: boolean) => void;\n mirror: Mirror;\n};\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from './config/types';\nimport { SessionReplayDestinationSessionMetadata } from './typings/session-replay';\nimport { getServerUrl } from './helpers';\n\ntype BeaconSendFn<T> = (pageUrl: string, payload: T) => boolean;\n\n/**\n * For very small payloads it's preferable to use the [Beacon API](https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API).\n * While it doesn't provide 100% guarantees on sends, it greatly helps with overall reliability and page load performance. As\n * the Beacon API has a potential to fail due to size constraints we want to fall back to XHR if need be. This is mostly to\n * be used with 'pagehide' or 'beforeunload' events.\n *\n * Note there are only 3 CORS safelisted Content-Types you can send:\n *\n * - application/x-www-form-urlencoded\n * - multipart/form-data\n * - text/plain\n *\n * If we do not send one of these, some browsers like Chrome may not send this at all. Also we incur the overhead of a preflight\n * request. In our case we will add no additional content-type header. If you are trying to ping a server that requires this\n * header, you may want to use the regular fetch API or a different mechanism.\n */\nexport class BeaconTransport<T> {\n private sendBeacon: BeaconSendFn<T>;\n private sendXhr: BeaconSendFn<T>;\n private readonly basePageUrl: string;\n private readonly context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>;\n private readonly apiKey: string;\n\n constructor(context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>, config: SessionReplayJoinedConfig) {\n const globalScope = getGlobalScope();\n if (globalScope && globalScope.navigator && typeof globalScope.navigator.sendBeacon === 'function') {\n this.sendBeacon = (pageUrl, payload) => {\n try {\n if (globalScope.navigator.sendBeacon(pageUrl, JSON.stringify(payload))) {\n return true;\n }\n } catch (e) {\n // not logging error, since it would be hard to view and just adds overhead.\n }\n return false;\n };\n } else {\n this.sendBeacon = () => false;\n }\n\n this.sendXhr = (pageUrl, payload) => {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', pageUrl, true);\n xhr.setRequestHeader('Accept', '*/*');\n xhr.send(JSON.stringify(payload));\n return true;\n };\n\n this.basePageUrl = getServerUrl(config.serverZone, config.trackServerUrl);\n this.apiKey = config.apiKey;\n this.context = context;\n }\n\n send(deviceId: string, payload: T) {\n const { sessionId, type } = this.context;\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: String(sessionId),\n type: String(type),\n api_key: this.apiKey,\n });\n\n const pageUrl = `${this.basePageUrl}?${urlParams.toString()}`;\n\n // ideally send using the beacon API, but there is a chance it may fail, possibly due to a payload\n // size limit. in this case, try best effort to send using xhr.\n this.sendBeacon(pageUrl, payload) || this.sendXhr(pageUrl, payload);\n }\n}\n","import { getViewportHeight, getViewportWidth } from '../utils/rrweb';\nimport type { scrollCallback, scrollPosition } from '@amplitude/rrweb-types';\nimport { BeaconTransport } from '../beacon-transport';\nimport { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayDestinationSessionMetadata } from '../typings/session-replay';\nimport { getPageUrl } from '../helpers';\n\nexport type ScrollEvent = {\n timestamp: number; // Timestamp the event occurred\n maxScrollX: number; // Max window scroll X on a page\n maxScrollY: number; // Max window scroll Y on a page\n maxScrollHeight: number; // Max window scroll Y + window height on a page\n maxScrollWidth: number; // Max window scroll X + window width on a page\n viewportWidth: number;\n viewportHeight: number;\n pageUrl: string;\n type: 'scroll';\n};\n\nexport type ScrollEventPayload = { version: number; events: ScrollEvent[] };\n\n/**\n * This is intended to watch and update max scroll activity when loaded for a particular page.\n * A new instance should be created if the page URL changes, since by default it does not reset\n * it's max scroll state. It is intended to send very few and very small events utilizing the\n * Beacon API.\n * @see {@link BeaconTransport} for more details on Beacon API usage.\n */\nexport class ScrollWatcher {\n private timestamp = Date.now();\n private _currentScrollX: number;\n private _currentScrollY: number;\n private _maxScrollX: number;\n private _maxScrollY: number;\n private _maxScrollWidth: number;\n private _maxScrollHeight: number;\n private readonly transport: BeaconTransport<ScrollEventPayload>;\n private readonly config: Pick<SessionReplayJoinedConfig, 'loggerProvider' | 'interactionConfig'>;\n\n static default(\n context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>,\n config: SessionReplayJoinedConfig,\n ): ScrollWatcher {\n return new ScrollWatcher(new BeaconTransport<ScrollEventPayload>(context, config), config);\n }\n\n constructor(\n transport: BeaconTransport<ScrollEventPayload>,\n config: Pick<SessionReplayJoinedConfig, 'loggerProvider' | 'interactionConfig'>,\n ) {\n this._maxScrollX = 0;\n this._maxScrollY = 0;\n this._currentScrollX = 0;\n this._currentScrollY = 0;\n this._maxScrollWidth = getViewportWidth();\n this._maxScrollHeight = getViewportHeight();\n this.config = config;\n\n this.transport = transport;\n }\n\n public get maxScrollX(): number {\n return this._maxScrollX;\n }\n\n public get maxScrollY(): number {\n return this._maxScrollY;\n }\n\n public get maxScrollWidth(): number {\n return this._maxScrollWidth;\n }\n\n public get maxScrollHeight(): number {\n return this._maxScrollHeight;\n }\n\n public get currentScrollX(): number {\n return this._currentScrollX;\n }\n\n public get currentScrollY(): number {\n return this._currentScrollY;\n }\n\n update(e: scrollPosition) {\n const now = Date.now();\n this._currentScrollX = e.x;\n this._currentScrollY = e.y;\n if (e.x > this._maxScrollX) {\n const width = getViewportWidth();\n this._maxScrollX = e.x;\n const maxScrollWidth = e.x + width;\n if (maxScrollWidth > this._maxScrollWidth) {\n this._maxScrollWidth = maxScrollWidth;\n }\n this.timestamp = now;\n }\n\n if (e.y > this._maxScrollY) {\n const height = getViewportHeight();\n this._maxScrollY = e.y;\n const maxScrollHeight = e.y + height;\n if (maxScrollHeight > this._maxScrollHeight) {\n this._maxScrollHeight = maxScrollHeight;\n }\n this.timestamp = now;\n }\n }\n\n hook: scrollCallback = (e: scrollPosition) => {\n this.update(e);\n };\n\n send: (deviceIdFn: () => string | undefined) => (_: PageTransitionEvent | Event) => void = (deviceIdFn) => (_) => {\n const deviceId = deviceIdFn();\n const globalScope = getGlobalScope();\n if (globalScope && deviceId) {\n // Capture the true final scroll position directly from the window.\n // rrweb's scroll observer throttles callbacks to 100ms using setTimeout,\n // so the most recent scroll position may not have been delivered to the hook yet.\n const scrollX = globalScope.scrollX ?? 0;\n const scrollY = globalScope.scrollY ?? 0;\n if (scrollX > 0 || scrollY > 0) {\n // id is required by the scrollPosition type but is not used by update() —\n // only x and y are read. 1 is the conventional rrweb mirror ID for the document node.\n this.update({ id: 1, x: scrollX, y: scrollY });\n }\n this.transport.send(deviceId, {\n version: 1,\n events: [\n {\n maxScrollX: this._maxScrollX,\n maxScrollY: this._maxScrollY,\n maxScrollWidth: this._maxScrollWidth,\n maxScrollHeight: this._maxScrollHeight,\n\n viewportHeight: getViewportHeight(),\n viewportWidth: getViewportWidth(),\n pageUrl: getPageUrl(globalScope.location.href, this.config.interactionConfig?.ugcFilterRules ?? []),\n timestamp: this.timestamp,\n type: 'scroll',\n },\n ],\n });\n }\n };\n}\n","import { generateSessionReplayId } from './helpers';\nimport { SessionIdentifiers as ISessionIdentifiers } from './typings/session-replay';\n\nexport class SessionIdentifiers implements ISessionIdentifiers {\n deviceId?: string;\n sessionId?: string | number;\n sessionReplayId?: string;\n\n constructor({ sessionId, deviceId }: { sessionId?: string | number; deviceId?: string }) {\n this.deviceId = deviceId;\n this.sessionId = sessionId;\n\n if (sessionId && deviceId) {\n this.sessionReplayId = generateSessionReplayId(sessionId, deviceId);\n }\n }\n}\n","import { getGlobalScope, ILogger } from '@amplitude/analytics-core';\n\n/**\n * Persists the wall-clock time at which a session's replay first began capturing,\n * keyed by sessionId. The persisted value drives the `min_session_duration_ms` gate:\n * we measure elapsed *replay* time, not just current page-load time, so a session that\n * is paused and resumed (or that crosses a page navigation) is still gated correctly.\n *\n * All storage access is wrapped in try/catch — when localStorage is unavailable (Safari\n * private mode, quota exceeded, sandboxed iframe) callers fall back to `Date.now()` so\n * the gate degrades gracefully instead of throwing.\n */\n\nconst KEY_PREFIX = 'AMP_SR_START_';\nconst APIKEY_FINGERPRINT_LEN = 10;\n\n/**\n * TTL beyond which a stored start time is treated as stale and pruned on next init.\n * 24 hours covers the longest realistic single-session duration in Amplitude (default\n * inactivity timeout is 30 minutes; some configs extend sessions across resumes).\n */\nexport const REPLAY_START_TIME_TTL_MS = 24 * 60 * 60 * 1000;\n\nconst buildKeyPrefix = (apiKey: string) => `${KEY_PREFIX}${apiKey.substring(0, APIKEY_FINGERPRINT_LEN)}_`;\nconst buildKey = (apiKey: string, sessionId: string | number) => `${buildKeyPrefix(apiKey)}${sessionId}`;\n\nconst getLocalStorage = (): Storage | undefined => {\n try {\n const scope = getGlobalScope() as { localStorage?: Storage } | undefined;\n return scope?.localStorage;\n } catch {\n // Accessing localStorage can throw in some sandboxed contexts.\n return undefined;\n }\n};\n\n/**\n * Returns the persisted replay start time for this sessionId if one exists and is fresh,\n * otherwise writes `now` and returns it. Returns undefined only if storage is unavailable\n * — callers should fall back to a transient `Date.now()` in that case.\n */\nexport const getOrInitReplayStartTime = (\n apiKey: string,\n sessionId: string | number,\n now: number,\n logger?: ILogger,\n): number | undefined => {\n const storage = getLocalStorage();\n if (!storage) return undefined;\n const key = buildKey(apiKey, sessionId);\n try {\n const raw = storage.getItem(key);\n if (raw !== null) {\n const parsed = Number(raw);\n // Treat NaN, non-finite, future-dated, and stale entries as missing.\n if (Number.isFinite(parsed) && parsed > 0 && parsed <= now && now - parsed < REPLAY_START_TIME_TTL_MS) {\n return parsed;\n }\n }\n storage.setItem(key, String(now));\n return now;\n } catch (e) {\n logger?.debug(`Failed to read/write replay start time from storage: ${String(e)}`);\n return undefined;\n }\n};\n\nexport const setReplayStartTime = (\n apiKey: string,\n sessionId: string | number,\n startTime: number,\n logger?: ILogger,\n): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.setItem(buildKey(apiKey, sessionId), String(startTime));\n } catch (e) {\n logger?.debug(`Failed to write replay start time to storage: ${String(e)}`);\n }\n};\n\nexport const removeReplayStartTime = (apiKey: string, sessionId: string | number, logger?: ILogger): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.removeItem(buildKey(apiKey, sessionId));\n } catch (e) {\n logger?.debug(`Failed to remove replay start time from storage: ${String(e)}`);\n }\n};\n\n/**\n * Drops stored start times older than {@link REPLAY_START_TIME_TTL_MS}. Cheap best-effort\n * sweep called on init — keeps localStorage from accumulating dead entries when sessions\n * end without a clean transition (browser close, crash). Scoped to this API key's keys\n * so multi-tenant pages don't churn through each other's entries.\n */\nexport const pruneStaleReplayStartTimes = (apiKey: string, now: number, logger?: ILogger): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n const prefix = buildKeyPrefix(apiKey);\n try {\n // Collect first; localStorage indices shift as we remove.\n const stale: string[] = [];\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (!key || !key.startsWith(prefix)) continue;\n const raw = storage.getItem(key);\n if (raw === null) continue;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0 || now - parsed >= REPLAY_START_TIME_TTL_MS) {\n stale.push(key);\n }\n }\n for (const key of stale) {\n storage.removeItem(key);\n }\n } catch (e) {\n logger?.debug(`Failed to prune stale replay start times: ${String(e)}`);\n }\n};\n","import { Logger as ILogger } from '@amplitude/analytics-types';\nimport { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { logIdbError } from '../utils/is-abort-error';\n\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 2; // 2 days\n\nexport interface SessionReplayTargetingDB extends DBSchema {\n sessionTargetingMatch: {\n key: string;\n value: {\n sessionId: string;\n targetingMatch: boolean;\n lastUpdated: number;\n };\n };\n}\n\nexport class TargetingIDBStore {\n dbs: { [apiKey: string]: IDBPDatabase<SessionReplayTargetingDB> } = {};\n\n createStore = async (dbName: string) => {\n return await openDB<SessionReplayTargetingDB>(dbName, 1, {\n upgrade: (db: IDBPDatabase<SessionReplayTargetingDB>) => {\n if (!db.objectStoreNames.contains('sessionTargetingMatch')) {\n db.createObjectStore('sessionTargetingMatch', {\n keyPath: 'sessionId',\n });\n }\n },\n });\n };\n\n openOrCreateDB = async (apiKey: string) => {\n if (this.dbs && this.dbs[apiKey]) {\n return this.dbs[apiKey];\n }\n const dbName = `${apiKey.substring(0, 10)}_amp_session_replay_targeting`;\n const db = await this.createStore(dbName);\n this.dbs[apiKey] = db;\n return db;\n };\n\n getTargetingMatchForSession = async ({\n loggerProvider,\n apiKey,\n sessionId,\n }: {\n loggerProvider: ILogger;\n apiKey: string;\n sessionId: string | number;\n }) => {\n try {\n const db = await this.openOrCreateDB(apiKey);\n const sessionIdStr = String(sessionId);\n const targetingMatchForSession = await db.get<'sessionTargetingMatch'>('sessionTargetingMatch', sessionIdStr);\n\n return targetingMatchForSession?.targetingMatch;\n } catch (e) {\n logIdbError(loggerProvider, `Failed to get targeting match for session id ${sessionId}: ${e as string}`, e);\n }\n return undefined;\n };\n\n storeTargetingMatchForSession = async ({\n loggerProvider,\n apiKey,\n sessionId,\n targetingMatch,\n }: {\n loggerProvider: ILogger;\n apiKey: string;\n sessionId: string | number;\n targetingMatch: boolean;\n }) => {\n try {\n const db = await this.openOrCreateDB(apiKey);\n const sessionIdStr = String(sessionId);\n const targetingMatchForSession = await db.put<'sessionTargetingMatch'>('sessionTargetingMatch', {\n targetingMatch,\n sessionId: sessionIdStr,\n lastUpdated: Date.now(),\n });\n\n return targetingMatchForSession;\n } catch (e) {\n logIdbError(loggerProvider, `Failed to store targeting match for session id ${sessionId}: ${e as string}`, e);\n }\n return undefined;\n };\n\n clearStoreOfOldSessions = async ({\n loggerProvider,\n apiKey,\n currentSessionId,\n }: {\n loggerProvider: ILogger;\n apiKey: string;\n currentSessionId: string | number;\n }) => {\n try {\n const db = await this.openOrCreateDB(apiKey);\n const currentSessionIdStr = String(currentSessionId);\n const tx = db.transaction<'sessionTargetingMatch', 'readwrite'>('sessionTargetingMatch', 'readwrite');\n const allTargetingMatchObjs = await tx.store.getAll();\n for (let i = 0; i < allTargetingMatchObjs.length; i++) {\n const targetingMatchObj = allTargetingMatchObjs[i];\n const amountOfTimeSinceSession = Date.now() - targetingMatchObj.lastUpdated;\n if (targetingMatchObj.sessionId !== currentSessionIdStr && amountOfTimeSinceSession > MAX_IDB_STORAGE_LENGTH) {\n await tx.store.delete(targetingMatchObj.sessionId);\n }\n }\n await tx.done;\n } catch (e) {\n logIdbError(loggerProvider, `Failed to clear old targeting matches for sessions: ${e as string}`, e);\n }\n };\n}\nexport const targetingIDBStore = new TargetingIDBStore();\n","// Pure JS xxHash32 implementation based on the official specification:\n// https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md\nconst PRIME32_1 = 0x9e3779b1;\nconst PRIME32_2 = 0x85ebca77;\nconst PRIME32_3 = 0xc2b2ae3d;\nconst PRIME32_4 = 0x27d4eb2f;\nconst PRIME32_5 = 0x165667b1;\n\nfunction rotl32(x: number, r: number): number {\n return ((x << r) | (x >>> (32 - r))) >>> 0;\n}\n\nfunction round(acc: number, input: number): number {\n acc = (acc + Math.imul(input, PRIME32_2)) >>> 0;\n acc = rotl32(acc, 13);\n acc = Math.imul(acc, PRIME32_1) >>> 0;\n return acc;\n}\n\nfunction readU32(bytes: Uint8Array, offset: number): number {\n return (bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)) >>> 0;\n}\n\nfunction toUTF8Bytes(str: string): Uint8Array {\n const bytes: number[] = [];\n for (let i = 0; i < str.length; i++) {\n let c = str.charCodeAt(i);\n if (c >= 0xd800 && c <= 0xdbff && i + 1 < str.length) {\n const next = str.charCodeAt(i + 1);\n if (next >= 0xdc00 && next <= 0xdfff) {\n c = ((c - 0xd800) << 10) + (next - 0xdc00) + 0x10000;\n i++;\n }\n }\n if (c < 0x80) {\n bytes.push(c);\n } else if (c < 0x800) {\n bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f));\n } else if (c < 0x10000) {\n bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));\n } else {\n bytes.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));\n }\n }\n return new Uint8Array(bytes);\n}\n\nexport function xxHash32(input: string, seed = 0): number {\n const bytes = toUTF8Bytes(input);\n const len = bytes.length;\n let h32: number;\n let offset = 0;\n\n if (len >= 16) {\n let v1 = (seed + PRIME32_1 + PRIME32_2) >>> 0;\n let v2 = (seed + PRIME32_2) >>> 0;\n let v3 = seed >>> 0;\n let v4 = (seed - PRIME32_1) >>> 0;\n\n while (offset <= len - 16) {\n v1 = round(v1, readU32(bytes, offset));\n offset += 4;\n v2 = round(v2, readU32(bytes, offset));\n offset += 4;\n v3 = round(v3, readU32(bytes, offset));\n offset += 4;\n v4 = round(v4, readU32(bytes, offset));\n offset += 4;\n }\n\n h32 = (rotl32(v1, 1) + rotl32(v2, 7) + rotl32(v3, 12) + rotl32(v4, 18)) >>> 0;\n } else {\n h32 = (seed + PRIME32_5) >>> 0;\n }\n\n h32 = (h32 + len) >>> 0;\n\n while (offset <= len - 4) {\n h32 = (h32 + Math.imul(readU32(bytes, offset), PRIME32_3)) >>> 0;\n h32 = Math.imul(rotl32(h32, 17), PRIME32_4) >>> 0;\n offset += 4;\n }\n\n while (offset < len) {\n h32 = (h32 + Math.imul(bytes[offset], PRIME32_5)) >>> 0;\n h32 = Math.imul(rotl32(h32, 11), PRIME32_1) >>> 0;\n offset++;\n }\n\n h32 ^= h32 >>> 15;\n h32 = Math.imul(h32, PRIME32_2) >>> 0;\n h32 ^= h32 >>> 13;\n h32 = Math.imul(h32, PRIME32_3) >>> 0;\n h32 ^= h32 >>> 16;\n\n return h32 >>> 0;\n}\n\nexport function isSessionInSample(sessionId: string | number, sampleRate: number): boolean {\n const hash = xxHash32(sessionId.toString());\n const mod = hash % 1_000_000;\n return mod / 1_000_000 < sampleRate;\n}\n","import { getPageUrl } from '../helpers';\nimport { UGCFilterRule } from '../config/types';\nimport { DEFAULT_URL_CHANGE_POLLING_INTERVAL } from '../constants';\nimport { RecordPlugin } from '@amplitude/rrweb-types';\n\n/**\n * Event emitted when URL changes are detected by the plugin\n * Contains the current page URL, title, and viewport dimensions\n */\nexport interface URLChangeEvent {\n /** The current page URL (may be filtered if UGC rules are applied) */\n href: string;\n /** The current page title */\n title: string;\n /** Viewport height in pixels */\n viewportHeight: number;\n /** Viewport width in pixels */\n viewportWidth: number;\n /** The type of URL change event */\n type: string;\n}\n\n/**\n * Configuration options for the URL tracking plugin\n */\nexport interface URLTrackingPluginOptions {\n /** Rules for filtering sensitive URLs (User Generated Content) */\n ugcFilterRules?: UGCFilterRule[];\n /** Whether to use polling instead of history API events for URL detection */\n enablePolling?: boolean;\n /** Interval in milliseconds for polling URL changes (default: 1000ms) */\n pollingInterval?: number;\n /** Whether to capture document title in URL change events (default: false) */\n captureDocumentTitle?: boolean;\n}\n\n/** Options for subscribeToUrlChanges (polling vs history + hash) */\nexport interface SubscribeToUrlChangesOptions {\n /** Use polling instead of history/popstate/hashchange (e.g. when history is unreliable) */\n enablePolling?: boolean;\n /** Polling interval in ms when enablePolling is true (default: 1000) */\n pollingInterval?: number;\n /**\n * Optional debug logger, called once per poll tick (only on the polling path). Lets the SDK\n * confirm in the browser console that the interval is actually firing — useful when verifying\n * that enableUrlChangePolling took effect for an SPA that bypasses the History API.\n */\n log?: (message: string) => void;\n}\n\n/** Patch detection marker to prevent double-patching */\nconst PATCH_MARKER = '__amplitude_url_tracking_patched__';\n\ntype PatchableHistoryMethod<T extends (...args: any[]) => any> = T & { [PATCH_MARKER]?: boolean };\n\ninterface UrlChangeSubscriptionState {\n callbacks: Set<(href: string) => void>;\n onPopStateOrHashChange: () => void;\n notify: () => void;\n listenersAttached: boolean;\n}\n\n/** Per-globalScope subscription state; persists to avoid wrapper stacking across re-subscribe cycles */\nconst urlChangeSubscriptionsByScope = new WeakMap<Window, UrlChangeSubscriptionState>();\n\n/**\n * Single helper for URL change detection. Supports:\n * - History API (pushState/replaceState) + popstate + hashchange (shared patch per scope)\n * - Optional polling (setInterval on location.href)\n *\n * Used by session-replay targeting (re-evaluate on URL change) and the URL tracking plugin\n * (emit rrweb events). Call the returned function to unsubscribe.\n *\n * @param globalScope - window (or equivalent); no-op if undefined\n * @param onUrlChange - called when the URL changes, with the new href\n * @param options - optional polling (default: event-based only)\n * @returns cleanup function to remove this subscription\n */\nexport function subscribeToUrlChanges(\n globalScope: Window | undefined,\n onUrlChange: (href: string) => void,\n options: SubscribeToUrlChangesOptions = {},\n): () => void {\n if (!globalScope?.location) {\n return (): void => {\n return;\n };\n }\n\n const { enablePolling = false, pollingInterval = DEFAULT_URL_CHANGE_POLLING_INTERVAL, log } = options;\n\n if (enablePolling) {\n const getHref = (): string => globalScope.location.href ?? '';\n let lastHref = getHref();\n const id = globalScope.setInterval(() => {\n const href = getHref();\n // Logged every tick (not just on change) so we can confirm the polling loop is alive.\n log?.(`URL polling tick (href=${href}, changed=${String(href !== lastHref)}).`);\n if (href === lastHref) {\n return;\n }\n lastHref = href;\n onUrlChange(href);\n }, pollingInterval);\n return (): void => {\n if (id != null) {\n globalScope.clearInterval(id);\n }\n };\n }\n\n let subscriptionState = urlChangeSubscriptionsByScope.get(globalScope);\n if (!subscriptionState) {\n let lastHref: string | undefined = undefined;\n const callbacks = new Set<(href: string) => void>();\n\n const getHref = (): string => globalScope.location.href ?? '';\n\n const notify = (): void => {\n const href = getHref();\n if (lastHref !== undefined && href === lastHref) return;\n lastHref = href;\n callbacks.forEach((c) => c(href));\n };\n\n /**\n * Creates a patched version of history methods (pushState/replaceState)\n * that calls the original method and then emits a URL change event.\n */\n const createHistoryMethodPatch = <T extends typeof history.pushState | typeof history.replaceState>(\n originalMethod: T,\n ) => {\n const patchedMethod = function (this: History, ...args: Parameters<T>) {\n const result = originalMethod.apply(this, args);\n // Read from location.href after history call so we always notify with resolved absolute URL.\n notify();\n return result;\n } as PatchableHistoryMethod<T>;\n\n patchedMethod[PATCH_MARKER] = true;\n return patchedMethod;\n };\n\n const history = globalScope.history;\n if (history?.pushState) {\n const pushState = Reflect.get(history, 'pushState') as PatchableHistoryMethod<History['pushState']>;\n if (!pushState[PATCH_MARKER]) {\n history.pushState = createHistoryMethodPatch(pushState);\n }\n }\n if (history?.replaceState) {\n const replaceState = Reflect.get(history, 'replaceState') as PatchableHistoryMethod<History['replaceState']>;\n if (!replaceState[PATCH_MARKER]) {\n history.replaceState = createHistoryMethodPatch(replaceState);\n }\n }\n\n subscriptionState = {\n callbacks,\n notify,\n onPopStateOrHashChange: () => notify(),\n listenersAttached: false,\n };\n urlChangeSubscriptionsByScope.set(globalScope, subscriptionState);\n }\n\n const state = subscriptionState;\n if (!state.listenersAttached) {\n globalScope.addEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.addEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = true;\n }\n\n state.callbacks.add(onUrlChange);\n return (): void => {\n state.callbacks.delete(onUrlChange);\n if (state.callbacks.size === 0) {\n // Do not restore history methods: we are not aware of patches applied by other scripts.\n if (state.listenersAttached) {\n globalScope.removeEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.removeEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = false;\n }\n }\n };\n}\n\n/**\n * Creates a URL tracking plugin for rrweb record function\n *\n * This plugin monitors URL changes in the browser and emits events when the URL changes.\n * It supports three tracking modes:\n * 1. Polling (if explicitly enabled) - periodically checks for URL changes\n * 2. History API + Hash routing (default) - patches pushState/replaceState, listens to popstate and hashchange\n * 3. Hash routing only (fallback) - listens to hashchange events when History API is unavailable\n *\n * The plugin handles edge cases gracefully:\n * - Missing or null location objects\n * - Undefined, null, or empty location.href values\n * - Temporal dead zone issues with variable declarations\n * - Consistent URL normalization across all code paths\n *\n * @param options Configuration options for URL tracking\n * @returns RecordPlugin instance that can be used with rrweb\n */\nexport function createUrlTrackingPlugin(\n options: URLTrackingPluginOptions = {},\n): RecordPlugin<URLTrackingPluginOptions> {\n return {\n name: 'amplitude/url-tracking@1',\n observer(cb, globalScope, pluginOptions?: URLTrackingPluginOptions) {\n // Merge options with plugin-level options taking precedence over constructor options\n const config = { ...options, ...pluginOptions };\n const ugcFilterRules = config.ugcFilterRules || [];\n const enablePolling = config.enablePolling ?? false;\n const pollingInterval = config.pollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n const captureDocumentTitle = config.captureDocumentTitle ?? false;\n\n // Early return if no global scope is available\n if (!globalScope) {\n return () => {\n // No cleanup needed if no global scope available\n };\n }\n\n // Track the last URL to prevent duplicate events\n // Initialize to undefined to ensure first call always emits an event\n let lastTrackedUrl: string | undefined = undefined;\n\n // Helper functions\n /**\n * Gets the current URL with proper normalization\n * Handles edge cases where location.href might be undefined, null, or empty\n * Ensures consistent behavior across all code paths\n * @returns Normalized URL string (empty string if location unavailable)\n */\n const getCurrentUrl = (): string => {\n if (!globalScope.location) return '';\n return globalScope.location.href || '';\n };\n\n /**\n * Creates a URL change event with current page information\n * Applies UGC filtering if rules are configured\n * Uses getCurrentUrl() for consistent URL normalization\n * @returns URLChangeEvent with current page state\n */\n const createUrlChangeEvent = (): URLChangeEvent => {\n const { innerHeight, innerWidth, document } = globalScope;\n const currentUrl = getCurrentUrl();\n let currentTitle = '';\n if (captureDocumentTitle) {\n currentTitle = document?.title || '';\n }\n\n // Apply UGC filtering if rules are provided, otherwise use original URL\n const filteredUrl = ugcFilterRules.length > 0 ? getPageUrl(currentUrl, ugcFilterRules) : currentUrl;\n\n return {\n href: filteredUrl,\n title: currentTitle,\n viewportHeight: innerHeight,\n viewportWidth: innerWidth,\n type: 'url-change-event',\n };\n };\n\n /**\n * Emits a URL change event if the URL has actually changed\n * Always emits on first call (when lastTrackedUrl is undefined)\n */\n const emitUrlChange = (): void => {\n const currentUrl = getCurrentUrl();\n if (lastTrackedUrl === undefined || currentUrl !== lastTrackedUrl) {\n lastTrackedUrl = currentUrl;\n const event = createUrlChangeEvent();\n cb(event);\n }\n };\n\n // Single helper: history + popstate + hashchange, or polling when enabled\n const unsubscribe = subscribeToUrlChanges(\n globalScope as Window,\n () => emitUrlChange(),\n enablePolling ? { enablePolling: true, pollingInterval } : {},\n );\n emitUrlChange();\n\n return (): void => unsubscribe();\n },\n options,\n };\n}\n\n/**\n * Default URL tracking plugin instance with default options\n * Can be used directly without custom configuration\n */\nexport const urlTrackingPlugin = createUrlTrackingPlugin();\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { CROSS_ORIGIN_IFRAME_MESSAGE_TYPE } from './constants';\n\nexport function isInIframe(): boolean {\n try {\n const globalScope = getGlobalScope() as Window | undefined;\n if (!globalScope) {\n return false;\n }\n return globalScope.parent !== globalScope;\n } catch {\n // SecurityError accessing window.parent in some sandboxed environments\n return true;\n }\n}\n\ntype IframeMessage = { type: typeof CROSS_ORIGIN_IFRAME_MESSAGE_TYPE; action: 'start' | 'stop' };\n\n/**\n * Manages the parent side of cross-origin iframe recording coordination.\n *\n * When the parent starts recording, it sends a start signal to all current child\n * iframes and watches for dynamically added iframes via MutationObserver. When the\n * parent stops, it sends a stop signal.\n */\nexport class CrossOriginIframeCoordinator {\n private mutationObserver: MutationObserver | undefined;\n // Tracks pending load listeners for dynamically added iframes so stop() can cancel them.\n private pendingLoadListeners = new Map<HTMLIFrameElement, () => void>();\n\n start() {\n this.mutationObserver?.disconnect(); // guard against double-start\n const globalScope = getGlobalScope();\n if (!globalScope) {\n return;\n }\n this.sendToAllIframes({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n this.mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of Array.from(mutation.addedNodes)) {\n if (node instanceof HTMLIFrameElement) {\n // Send the start signal after the child page has loaded, not at insertion\n // time. At insertion the contentWindow is still about:blank; the message\n // sent there is discarded when the iframe navigates to its src, and the\n // child SDK never receives it.\n this.sendToIframeAfterLoad(node);\n } else if (node instanceof Element) {\n // A container element (e.g. a React-rendered div) may already have\n // iframe descendants when it is inserted. These iframes do NOT appear\n // in addedNodes — only the container does. Query the subtree so we\n // don't miss them.\n node.querySelectorAll<HTMLIFrameElement>('iframe').forEach((iframe) => {\n this.sendToIframeAfterLoad(iframe);\n });\n }\n }\n for (const node of Array.from(mutation.removedNodes)) {\n if (node instanceof HTMLIFrameElement) {\n const listener = this.pendingLoadListeners.get(node);\n if (listener) {\n node.removeEventListener('load', listener);\n this.pendingLoadListeners.delete(node);\n }\n }\n }\n }\n });\n this.mutationObserver.observe(document.documentElement, { childList: true, subtree: true });\n }\n\n stop() {\n this.mutationObserver?.disconnect();\n this.mutationObserver = undefined;\n // Cancel any start signals that were waiting for a pending iframe load.\n this.pendingLoadListeners.forEach((listener, iframe) => {\n iframe.removeEventListener('load', listener);\n });\n this.pendingLoadListeners.clear();\n this.sendToAllIframes({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' });\n }\n\n private sendToIframeAfterLoad(iframe: HTMLIFrameElement) {\n const sendStart = () => {\n this.pendingLoadListeners.delete(iframe);\n this.sendToIframe(iframe, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n };\n this.pendingLoadListeners.set(iframe, sendStart);\n iframe.addEventListener('load', sendStart, { once: true });\n }\n\n private sendToAllIframes(message: IframeMessage) {\n const iframes = document.querySelectorAll<HTMLIFrameElement>('iframe');\n iframes.forEach((iframe) => this.sendToIframe(iframe, message));\n }\n\n private sendToIframe(iframe: HTMLIFrameElement, message: IframeMessage) {\n try {\n iframe.contentWindow?.postMessage(message, '*');\n } catch {\n // Cross-origin postMessage can throw in some sandboxed environments; ignore.\n }\n }\n}\n\n/**\n * Listens for start/stop signals from the parent page and invokes the provided\n * callbacks. Only messages from `window.parent` are accepted.\n *\n * Returns a cleanup function that removes the message listener.\n */\nexport function listenForParentSignals(callbacks: { onStart: () => void; onStop: () => void }): () => void {\n const globalScope = getGlobalScope() as Window | undefined;\n if (!globalScope) {\n return () => undefined;\n }\n\n const parentFrame = globalScope.parent;\n\n function handler(event: MessageEvent) {\n // Only accept messages from the direct parent frame.\n if (event.source !== parentFrame) {\n return;\n }\n const data = event.data as Partial<IframeMessage>;\n if (data?.type !== CROSS_ORIGIN_IFRAME_MESSAGE_TYPE) {\n return;\n }\n if (data.action === 'start') {\n callbacks.onStart();\n } else if (data.action === 'stop') {\n callbacks.onStop();\n }\n }\n\n globalScope.addEventListener('message', handler);\n return () => globalScope.removeEventListener('message', handler);\n}\n","import {\n getAnalyticsConnector,\n getGlobalScope,\n ILogger,\n Logger,\n LogLevel,\n returnWrapper,\n SpecialEventType,\n generateHashCode,\n getOrCreateWindowMessenger,\n enableBackgroundCapture,\n AMPLITUDE_ORIGINS_MAP,\n} from '@amplitude/analytics-core';\n\n// Import only specific types to avoid pulling in the entire rrweb-types package\nimport { eventWithTime, EventType as RRWebEventType, scrollCallback } from '@amplitude/rrweb-types';\nimport { createSessionReplayJoinedConfigGenerator } from './config/joined-config';\nimport {\n LoggingConfig,\n SessionReplayJoinedConfig,\n SessionReplayJoinedConfigGenerator,\n SessionReplayLocalConfig,\n SessionReplayMetadata,\n SessionReplayRemoteConfig,\n} from './config/types';\nimport {\n BLOCK_CLASS,\n CustomRRwebEvent,\n DEFAULT_SESSION_REPLAY_PROPERTY,\n INTERACTION_MAX_INTERVAL,\n INTERACTION_MIN_INTERVAL,\n MASK_TEXT_CLASS,\n SESSION_REPLAY_DEBUG_PROPERTY,\n SESSION_REPLAY_EU_URL,\n SESSION_REPLAY_SERVER_URL,\n SESSION_REPLAY_STAGING_URL,\n} from './constants';\nimport {\n getServerUrl,\n getDebugConfig,\n getEffectiveMaskLevel,\n getPageUrl,\n getStorageSize,\n getCurrentUrl,\n maskFn,\n maskAttributeFn,\n} from './helpers';\nimport { EventCompressor } from './events/event-compressor';\nimport { createEventsManager, EventsManagerWithBeacon } from './events/events-manager';\nimport { MultiEventManager } from './events/multi-manager';\nimport { clickBatcher, ClickHandler, clickNonBatcher } from './hooks/click';\nimport { ScrollWatcher } from './hooks/scroll';\nimport { SessionIdentifiers } from './identifiers';\nimport { SafeLoggerProvider } from './logger';\nimport {\n getOrInitReplayStartTime,\n pruneStaleReplayStartTimes,\n removeReplayStartTime,\n setReplayStartTime,\n} from './replay-start-time-store';\nimport { evaluateTargetingAndStore } from './targeting/targeting-manager';\nimport { SrDiagnostic } from './diagnostics';\nimport {\n AmplitudeSessionReplay,\n SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n DebugInfo,\n EventsManagerWithType,\n EventType,\n SessionIdentifiers as ISessionIdentifiers,\n SessionReplayOptions,\n SessionReplayTargetingInput,\n} from './typings/session-replay';\nimport { isSessionInSample } from './sampling';\nimport { VERSION } from './version';\n\n// Import only the type for NetworkRequestEvent to keep type safety\nimport type { NetworkObservers, NetworkRequestEvent } from './observers';\nimport { createUrlTrackingPlugin, subscribeToUrlChanges } from './plugins/url-tracking-plugin';\nimport type { RecordFunction } from './utils/rrweb';\nimport { isInIframe, CrossOriginIframeCoordinator, listenForParentSignals } from './cross-origin-iframes';\n\ntype PageLeaveFn = (e: PageTransitionEvent | Event) => void;\n\nexport class SessionReplay implements AmplitudeSessionReplay {\n name = '@amplitude/session-replay-browser';\n config: SessionReplayJoinedConfig | undefined;\n joinedConfigGenerator: SessionReplayJoinedConfigGenerator | undefined;\n identifiers: ISessionIdentifiers | undefined;\n eventsManager?: AmplitudeSessionReplayEventsManager<'replay' | 'interaction', string>;\n loggerProvider: ILogger;\n recordCancelCallback: ReturnType<RecordFunction> | null = null;\n eventCount = 0;\n eventCompressor: EventCompressor | undefined;\n sessionTargetingMatch = false;\n private lastTargetingParams?: SessionReplayTargetingInput;\n private lastShouldRecordDecision?: boolean;\n // Session for which the one-per-session TRC diagnostic event was already emitted. The\n // diagnostics client caps in-memory events, so per-call signals go through counters and only\n // a single rich snapshot event is recorded per session.\n private trcDiagnosticSessionId: string | number | undefined = undefined;\n\n // Public on purpose. `pageLeaveFns` is iterated by `pageLeaveListener`,\n // `rrwebEventManager` is dereferenced in `asyncSetSessionId` to drop the beacon buffer\n // at a session boundary, and `sessionStartTime` drives `isBelowMinSessionDuration()`.\n // Tests also stub/inspect these — privatizing them would break both production callers\n // and the gate's test coverage.\n pageLeaveFns: PageLeaveFn[] = [];\n sessionStartTime: number | undefined;\n rrwebEventManager: EventsManagerWithBeacon<'replay'> | undefined;\n /**\n * Count of sendEvents() calls suppressed by the min-session-duration gate for the\n * current session. Drives the REPLAY_GATE_DECISION rrweb event on first send-after-pass.\n */\n private suppressedSendCount = 0;\n /** True once REPLAY_GATE_DECISION has been emitted for the current session. */\n private hasEmittedGateDecision = false;\n private scrollHook?: scrollCallback;\n private clickHandler?: ClickHandler;\n private networkObservers?: NetworkObservers;\n private metadata: SessionReplayMetadata | undefined;\n\n // Cache the dynamically imported record function\n private recordFunction: RecordFunction | null = null;\n private recordEventsInFlight = false;\n private pendingEmitEvents: Array<{ event: eventWithTime; sessionId: string | number }> = [];\n\n /** Current page URL, kept in sync with SPA navigations for URL-based masking */\n private currentPageUrl = '';\n\n private recordEventsPendingShouldLogMetadata: boolean | null = null;\n\n /** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */\n private urlChangeCleanup: (() => void) | null = null;\n private crossOriginIframeCoordinator: CrossOriginIframeCoordinator | null = null;\n private crossOriginParentSignalCleanup: (() => void) | null = null;\n /** Monotonic counter to ignore stale URL-change targeting results */\n private latestUrlChangeTargetingEvaluationId = 0;\n\n constructor() {\n this.loggerProvider = new SafeLoggerProvider(new Logger());\n }\n\n init(apiKey: string, options: SessionReplayOptions) {\n return returnWrapper(this._init(apiKey, options));\n }\n\n private teardownEventListeners = (teardown: boolean) => {\n const globalScope = getGlobalScope();\n if (globalScope) {\n globalScope.removeEventListener('blur', this.blurListener);\n globalScope.removeEventListener('focus', this.focusListener);\n !teardown && globalScope.addEventListener('blur', this.blurListener);\n !teardown && globalScope.addEventListener('focus', this.focusListener);\n // prefer pagehide to unload events, this is the standard going forward. it is not\n // 100% reliable, but is bfcache-compatible.\n if (globalScope.self && 'onpagehide' in globalScope.self) {\n globalScope.removeEventListener('pagehide', this.pageLeaveListener);\n !teardown && globalScope.addEventListener('pagehide', this.pageLeaveListener);\n } else {\n // this has performance implications, but is the only way we can reliably send events\n // in browser that don't support pagehide.\n globalScope.removeEventListener('beforeunload', this.pageLeaveListener);\n !teardown && globalScope.addEventListener('beforeunload', this.pageLeaveListener);\n }\n }\n };\n\n /**\n * Subscribes to SPA URL changes via the URL tracking plugin. Always keeps\n * `currentPageUrl` in sync (needed for URL-based masking). When a targeting\n * config is present it also re-evaluates targeting on every navigation.\n */\n private setupUrlChangeListener(): void {\n // If init() runs multiple times, remove the previous URL-change subscription first\n // so we don't leak callbacks and trigger duplicate targeting evaluations.\n this.urlChangeCleanup?.();\n\n const globalScope = getGlobalScope() as Window | undefined;\n if (!globalScope?.location) {\n // No window/location (SSR, worker, or pre-render) — the listener can't attach, so TRC will\n // never re-evaluate on navigation. Surface it rather than failing silently.\n this.incrementDiagnostic(SrDiagnostic.urlListenerSkipped);\n this.recordDiagnosticEvent(SrDiagnostic.urlListenerSkipped, { reason: 'no_global_scope' });\n this.loggerProvider.debug('URL-change listener not attached: no global scope/location.');\n return;\n }\n\n const hasTargeting = !!this.config?.targetingConfig;\n\n const onUrlChange = (href: string): void => {\n this.currentPageUrl = href;\n\n // Team-visible signal that an SPA navigation was detected at all (covers the \"is the SDK\n // even seeing route changes in this framework?\" question — counter + a log with the href\n // and whether it triggered a targeting re-eval).\n this.incrementDiagnostic(SrDiagnostic.urlChange);\n this.recordDiagnosticEvent(SrDiagnostic.urlChangeEvent, {\n href,\n hasTargeting,\n alreadyMatched: this.sessionTargetingMatch,\n });\n\n if (hasTargeting) {\n const evaluationId = ++this.latestUrlChangeTargetingEvaluationId;\n void this.evaluateTargetingAndCapture(\n {\n userProperties: {},\n event: undefined,\n page: { url: href },\n },\n false,\n false,\n true,\n );\n this.loggerProvider.debug(`Queued URL-change targeting re-evaluation #${evaluationId} for ${href}.`);\n }\n };\n // Pass the polling options so targeting re-evaluation also respects `enableUrlChangePolling`.\n // Without this, the targeting listener only sees history.pushState/replaceState + popstate +\n // hashchange — so SPA navigations that bypass the history API never re-evaluate TRC and\n // recording never starts on the new URL (enableUrlChangePolling previously only affected the\n // rrweb URL-tracking plugin, which runs only once recording is already active).\n const enablePolling = this.config?.enableUrlChangePolling ?? false;\n const unsubscribe = subscribeToUrlChanges(globalScope, onUrlChange, {\n enablePolling,\n pollingInterval: this.config?.urlChangePollingInterval,\n // Mirror each poll tick to the console (Debug level) so we can confirm polling is firing.\n log: this.loggerProvider.debug.bind(this.loggerProvider),\n });\n // Confirm the listener is actually live, and under what settings — if recording never starts on\n // navigation, this tells us whether the listener existed and whether polling (the fallback for\n // SPAs that bypass the History API) was on.\n this.recordDiagnosticEvent(SrDiagnostic.urlListenerAttached, {\n hasTargeting,\n enablePolling,\n pollingInterval: this.config?.urlChangePollingInterval,\n });\n this.loggerProvider.debug(`URL-change listener attached (polling: ${String(enablePolling)}).`);\n\n this.urlChangeCleanup = (): void => {\n unsubscribe();\n this.urlChangeCleanup = null;\n };\n }\n\n /**\n * Single source of truth for the min_session_duration_ms gate. Returns true when the\n * current session has not yet reached the configured threshold (and we have both a\n * configured value and a recorded start time). Returns false when there's no\n * threshold, no recorded start time, or the threshold has been met — i.e. it\n * answers \"should this batch be suppressed?\".\n *\n * Centralizing the check means future changes (clock-skew tolerance, switching to\n * performance.now(), etc.) are one-line edits.\n */\n private isBelowMinSessionDuration(): boolean {\n const minSessionDurationMs = this.config?.minSessionDurationMs;\n if (minSessionDurationMs === undefined || this.sessionStartTime === undefined) {\n return false;\n }\n return Date.now() - this.sessionStartTime < minSessionDurationMs;\n }\n\n private getCurrentPageForTargeting(): SessionReplayTargetingInput['page'] {\n const currentUrl = getGlobalScope()?.location?.href;\n return currentUrl != null ? { url: currentUrl } : undefined;\n }\n\n /**\n * Best-effort navigation type from the Navigation Timing API: 'reload' | 'navigate' |\n * 'back_forward' | 'prerender'. Surfaced in the init diagnostic so a page refresh ('reload')\n * is distinguishable from a fresh load ('navigate') — neither changes the session id, so this\n * is the only way to tell them apart. Returns undefined when the API is unavailable.\n */\n private getNavigationType(): string | undefined {\n try {\n const globalScope = getGlobalScope();\n const performance = globalScope && globalScope.performance;\n if (!performance || typeof performance.getEntriesByType !== 'function') {\n return undefined;\n }\n const navEntries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[];\n return navEntries.length > 0 ? navEntries[0].type : undefined;\n } catch {\n return undefined;\n }\n }\n\n protected async _init(apiKey: string, options: SessionReplayOptions) {\n // Re-init should always tear down any previous URL-change subscription, even when the\n // next config has no targeting config and we don't subscribe again.\n this.urlChangeCleanup?.();\n\n this.loggerProvider = new SafeLoggerProvider(options.loggerProvider || new Logger());\n Object.prototype.hasOwnProperty.call(options, 'logLevel') &&\n this.loggerProvider.enable(options.logLevel as LogLevel);\n this.currentPageUrl = getCurrentUrl();\n this.identifiers = new SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId });\n // Persist replay start time per sessionId so the min_session_duration_ms gate\n // measures replay duration (survives page reloads within a session) rather than\n // page-load duration. Storage failures fall back to a transient Date.now().\n const now = Date.now();\n pruneStaleReplayStartTimes(apiKey, now, this.loggerProvider);\n this.sessionStartTime =\n options.sessionId !== undefined\n ? getOrInitReplayStartTime(apiKey, options.sessionId, now, this.loggerProvider) ?? now\n : now;\n this.joinedConfigGenerator = await createSessionReplayJoinedConfigGenerator(apiKey, options);\n const { joinedConfig, localConfig, remoteConfig } = await this.joinedConfigGenerator.generateJoinedConfig();\n this.config = joinedConfig;\n\n this.setMetadata(\n options.sessionId,\n joinedConfig,\n localConfig,\n remoteConfig,\n options.version?.version,\n VERSION,\n options.version?.type,\n );\n\n this.pageLeaveFns = [];\n\n if (options.sessionId && this.config.interactionConfig?.enabled) {\n const scrollWatcher = ScrollWatcher.default(\n {\n sessionId: options.sessionId,\n type: 'interaction',\n },\n this.config,\n );\n this.pageLeaveFns = [scrollWatcher.send(this.getDeviceId.bind(this)).bind(scrollWatcher)];\n this.scrollHook = scrollWatcher.hook.bind(scrollWatcher);\n this.clickHandler = new ClickHandler(this.loggerProvider, scrollWatcher);\n }\n\n const managers: EventsManagerWithType<EventType, string>[] = [];\n let { storeType } = this.config;\n if (storeType === 'idb' && !getGlobalScope()?.indexedDB) {\n storeType = 'memory';\n this.loggerProvider.warn('Could not use preferred indexedDB storage, reverting to in memory option.');\n }\n this.loggerProvider.log(`Using ${storeType} for event storage.`);\n let compressionWorkerScript: string | undefined;\n let trackDestinationWorkerScript: string | undefined;\n const globalScope = getGlobalScope();\n if (this.config.useWebWorker && globalScope && globalScope.Worker) {\n const { compressionScript, trackDestinationScript } = await import('./worker');\n compressionWorkerScript = compressionScript;\n trackDestinationWorkerScript = trackDestinationScript;\n }\n\n let rrwebEventManager: EventsManagerWithBeacon<'replay'> | undefined;\n try {\n rrwebEventManager = await createEventsManager<'replay'>({\n config: this.config,\n type: 'replay',\n minInterval: this.config.flushIntervalConfig?.minIntervalMs,\n maxInterval: this.config.flushIntervalConfig?.maxIntervalMs,\n maxPersistedEventsSize: this.config.maxPersistedEventsSizeBytes,\n storeType,\n trackDestinationWorkerScript,\n shouldSend: () => !this.isBelowMinSessionDuration(),\n });\n this.rrwebEventManager = rrwebEventManager;\n managers.push({ name: 'replay', manager: rrwebEventManager });\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(`Error occurred while creating replay events manager: ${typedError.toString()}`);\n }\n\n if (this.config.interactionConfig?.enabled) {\n const payloadBatcher = this.config.interactionConfig.batch ? clickBatcher : clickNonBatcher;\n try {\n const interactionEventManager = await createEventsManager<'interaction'>({\n config: this.config,\n type: 'interaction',\n minInterval: this.config.interactionConfig.trackEveryNms ?? INTERACTION_MIN_INTERVAL,\n maxInterval: INTERACTION_MAX_INTERVAL,\n maxPersistedEventsSize: this.config.maxPersistedEventsSizeBytes,\n payloadBatcher,\n storeType,\n trackDestinationWorkerScript,\n });\n managers.push({ name: 'interaction', manager: interactionEventManager });\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(`Error occurred while creating interaction events manager: ${typedError.toString()}`);\n }\n }\n\n this.eventsManager = new MultiEventManager<'replay' | 'interaction', string>(...managers);\n // To prevent too many threads.\n if (this.eventCompressor) {\n this.eventCompressor.terminate();\n }\n\n // Eager full-snapshot send is tunable. When `eagerFullSnapshotSend` is true, every full\n // snapshot triggers an immediate flush so replays are playable as early as possible (the\n // SR-3115 contract). Leaving it unset (default) keeps the snapshot compressed and buffered\n // immediately (ordering + beacon coverage on page exit preserved) but defers the network\n // send to the normal interval/size cadence — this avoids the focus/checkout-driven request\n // storm that eager per-snapshot sends create when many SDK instances run on the same page.\n // The default flipped to disabled per the validated amp-on-amp perf config (SR-4646).\n const onFullSnapshotProcessed = this.config.eagerFullSnapshotSend === true ? () => this.sendEvents() : undefined;\n this.eventCompressor = new EventCompressor(\n this.eventsManager,\n this.config,\n this.getDeviceId(),\n compressionWorkerScript,\n onFullSnapshotProcessed,\n );\n\n // Flush any events that arrived while eventCompressor was not yet ready\n // (e.g. a concurrent setSessionId() call that raced _init()'s async setup).\n if (this.pendingEmitEvents.length > 0) {\n const pending = this.pendingEmitEvents.splice(0);\n for (const { event, sessionId } of pending) {\n this.eventCompressor.enqueueEvent(event, sessionId);\n }\n }\n\n // Register beacon fallback for page exit. sendBeacon survives page unload\n // and delivers any incremental events that haven't been flushed via fetch yet.\n //\n // Known cross-session race: if asyncSetSessionId fired and its async\n // storeCurrentSequence hasn't resolved before unload, the beacon buffer can still\n // hold previous-session events. The gate below reads the *new* session's\n // sessionStartTime, so legitimately-sendable old-session events get suppressed.\n // Follow-up: track start time per buffered batch instead of globally.\n this.pageLeaveFns = [\n ...this.pageLeaveFns,\n () => {\n if (!this.config || !this.identifiers?.sessionId || !rrwebEventManager) return;\n const events = rrwebEventManager.getBeaconEvents();\n if (!events.length) return;\n const deviceId = this.getDeviceId();\n if (!deviceId) return;\n if (this.isBelowMinSessionDuration()) return;\n rrwebEventManager.trackDestination.sendBeacon({\n events,\n sessionId: this.identifiers.sessionId,\n deviceId,\n apiKey: this.config.apiKey,\n serverZone: this.config.serverZone,\n });\n },\n ];\n\n await this.initializeNetworkObservers();\n\n // Enable background capture when this page is opened by the Amplitude app\n // (window.opener exists). Uses the shared messenger singleton so that if\n // autocapture is also loaded, both share a single messenger and script load.\n if (getGlobalScope()?.opener) {\n const messenger = getOrCreateWindowMessenger();\n enableBackgroundCapture(messenger);\n messenger.setup({\n logger: this.loggerProvider,\n ...(this.config.serverZone && { endpoint: AMPLITUDE_ORIGINS_MAP[this.config.serverZone] }),\n });\n }\n\n this.loggerProvider.log('Installing @amplitude/session-replay-browser.');\n\n this.teardownEventListeners(false);\n\n // Q1 \"did init happen?\": its presence in DataDog proves init() ran to completion for this\n // session; the props show whether the prerequisites (session/device id, config) were present.\n this.incrementDiagnostic(SrDiagnostic.init);\n this.recordDiagnosticEvent(SrDiagnostic.init, {\n // sessionId is always stamped by recordDiagnosticEvent, so no separate hasSessionId here.\n hasDeviceId: !!this.getDeviceId(),\n captureEnabled: this.config.captureEnabled,\n hasTargetingConfig: !!this.config.targetingConfig,\n sampleRate: this.config.sampleRate,\n optOut: this.shouldOptOut(),\n currentUrl: this.getCurrentPageForTargeting()?.url,\n // 'reload' tells a page refresh apart from a fresh load ('navigate') or back/forward\n // ('back_forward'). New tabs and refreshes keep the same session id, so this is the only\n // way to distinguish a refresh from a brand-new init within a session.\n navigationType: this.getNavigationType(),\n });\n\n await this.evaluateTargetingAndCapture(\n { userProperties: options.userProperties, page: this.getCurrentPageForTargeting() },\n true,\n );\n\n const needsUrlTracking = this.config.targetingConfig || (this.config.privacyConfig?.urlMaskLevels?.length ?? 0) > 0;\n // Record whether we even attempt to wire up the URL-change listener, and the inputs behind that\n // decision. If `needsUrlTracking` is false the listener is never attached, so SPA navigations are\n // invisible to TRC — this is the first thing to check when \"TRC is on but never re-evaluates\".\n this.recordDiagnosticEvent(SrDiagnostic.urlListenerSetup, {\n needsUrlTracking: !!needsUrlTracking,\n hasTargetingConfig: !!this.config.targetingConfig,\n urlMaskLevels: this.config.privacyConfig?.urlMaskLevels?.length ?? 0,\n // config always defaults this to a boolean (see local-config), so no `?? false` needed here.\n enableUrlChangePolling: this.config.enableUrlChangePolling,\n urlChangePollingInterval: this.config.urlChangePollingInterval,\n });\n this.loggerProvider.debug(`URL-change listener needed: ${String(!!needsUrlTracking)}.`);\n if (needsUrlTracking) {\n this.setupUrlChangeListener();\n }\n }\n\n setSessionId(sessionId: string | number, deviceId?: string) {\n return returnWrapper(this.asyncSetSessionId(sessionId, deviceId));\n }\n\n async asyncSetSessionId(\n sessionId: string | number,\n deviceId?: string,\n options?: { userProperties?: { [key: string]: any } },\n ) {\n const previousSessionId = this.identifiers?.sessionId;\n const currentDeviceId = this.getDeviceId();\n // Standalone SDK callers may poll setSessionId with a stable bucket id (e.g. hour-aligned\n // timestamps) and only need a no-op when the bucket hasn't rolled. Without this guard,\n // the rest of asyncSetSessionId still runs: sendEvents, targeting reset, config refetch,\n // and recordEvents (stop + restart rrweb). Proceed when deviceId changes or\n // non-empty userProperties are passed so targeting can re-evaluate on Identify.\n if (\n previousSessionId !== undefined &&\n previousSessionId === sessionId &&\n (deviceId === undefined || deviceId === currentDeviceId) &&\n (options?.userProperties === undefined || Object.keys(options.userProperties).length === 0)\n ) {\n return;\n }\n\n // Invalidate any in-flight URL-change re-evaluations from the previous session.\n this.latestUrlChangeTargetingEvaluationId++;\n this.sessionTargetingMatch = false;\n this.lastShouldRecordDecision = undefined; // Reset targeting decision for new session\n if (previousSessionId) {\n this.sendEvents(previousSessionId);\n }\n\n const isSessionChange = previousSessionId !== sessionId;\n\n // A real session transition (not the first set): recording stops/restarts and targeting is\n // re-evaluated here, so session churn (timeout, multi-tab custom ids, explicit setSessionId)\n // is a prime suspect for \"sometimes records, sometimes not\". recordDiagnosticEvent ships to\n // DataDog AND mirrors to loggerProvider.debug. New tabs / refreshes keep the same id and won't\n // hit this — use the init diagnostic's navigationType for those.\n if (isSessionChange && previousSessionId !== undefined) {\n this.recordDiagnosticEvent(SrDiagnostic.sessionChanged, {\n from: previousSessionId,\n to: sessionId,\n deviceIdChanged: deviceId !== undefined && deviceId !== currentDeviceId,\n });\n }\n\n // Drop any beacon-buffered events from the previous session BEFORE installing the\n // new identifiers / start time. Otherwise the page-leave beacon path could attribute\n // old-session events to the new session id, and the gate (using the new start time)\n // would compute the wrong elapsed duration. Skip on a redundant same-sessionId call —\n // the buffer belongs to the *continuing* session and should ship via beacon as normal.\n if (isSessionChange) {\n this.rrwebEventManager?.dropPendingBeaconEvents();\n }\n\n const deviceIdForReplayId = deviceId || this.getDeviceId();\n this.identifiers = new SessionIdentifiers({\n sessionId: sessionId,\n deviceId: deviceIdForReplayId,\n });\n\n // Gate state and persisted start time only get reset on an actual session boundary.\n // A redundant setSessionId(currentId) call would otherwise overwrite both the in-memory\n // and stored start time with a fresh Date.now() — restarting the gate clock for what is\n // supposed to be a continuing session.\n if (isSessionChange) {\n this.sessionStartTime = Date.now();\n this.suppressedSendCount = 0;\n this.hasEmittedGateDecision = false;\n if (this.config?.apiKey) {\n setReplayStartTime(this.config.apiKey, sessionId, this.sessionStartTime, this.loggerProvider);\n if (previousSessionId !== undefined) {\n removeReplayStartTime(this.config.apiKey, previousSessionId, this.loggerProvider);\n }\n }\n }\n\n // If there is no previous session id, SDK is being initialized for the first time,\n // and config was just fetched in initialization, so no need to fetch it a second time\n if (this.joinedConfigGenerator && previousSessionId) {\n const { joinedConfig } = await this.joinedConfigGenerator.generateJoinedConfig();\n this.config = joinedConfig;\n }\n\n if (this.config?.targetingConfig) {\n await this.evaluateTargetingAndCapture(\n { userProperties: options?.userProperties, page: this.getCurrentPageForTargeting() },\n false,\n true,\n );\n } else {\n await this.recordEvents();\n }\n }\n\n getSessionReplayProperties() {\n const config = this.config;\n const identifiers = this.identifiers;\n if (!config || !identifiers) {\n this.loggerProvider.warn('Session replay init has not been called, cannot get session replay properties.');\n return {};\n }\n\n const shouldRecord = this.getShouldRecord();\n let eventProperties: { [key: string]: string | null } = {};\n\n if (shouldRecord) {\n eventProperties = {\n [DEFAULT_SESSION_REPLAY_PROPERTY]: identifiers.sessionReplayId ? identifiers.sessionReplayId : null,\n };\n if (config.debugMode) {\n eventProperties[SESSION_REPLAY_DEBUG_PROPERTY] = JSON.stringify({\n appHash: generateHashCode(config.apiKey).toString(),\n });\n }\n }\n\n void this.addCustomRRWebEvent(\n CustomRRwebEvent.GET_SR_PROPS,\n {\n shouldRecord,\n eventProperties: eventProperties,\n },\n this.eventCount === 10,\n );\n if (this.eventCount === 10) {\n this.eventCount = 0;\n }\n this.eventCount++;\n\n return eventProperties;\n }\n\n blurListener = () => {\n this.sendEvents();\n };\n\n focusListener = () => {\n if (this.recordCancelCallback && this.recordFunction) {\n // Recording is already active. The on-focus full snapshot is tunable: when\n // `captureFullSnapshotOnFocus` is false we skip it entirely so high focus-churn pages\n // don't generate a full snapshot (and, with eager send, a network request) per focus.\n if (this.config?.captureFullSnapshotOnFocus === false) {\n return;\n }\n try {\n this.recordFunction.takeFullSnapshot(true);\n } catch (error) {\n this.loggerProvider.warn('Failed to take full snapshot on focus:', error);\n }\n } else if (!this.recordEventsInFlight) {\n void this.recordEvents(false);\n }\n };\n\n /**\n * This is an instance member so that if init is called multiple times\n * it doesn't add another listener to the page leave event. This is to\n * prevent duplicate listener actions from firing.\n */\n private pageLeaveListener = (e: PageTransitionEvent | Event) => {\n // Synchronously drain any events still queued in the requestIdleCallback\n // pipeline so they are available to send before the page unloads.\n this.eventCompressor?.flushQueue();\n this.sendEvents();\n this.pageLeaveFns.forEach((fn) => {\n fn(e);\n });\n };\n\n evaluateTargetingAndCapture = async (\n targetingParams: SessionReplayTargetingInput,\n isInit = false,\n forceRestart = false,\n forceTargetingReevaluation = false,\n ) => {\n // What triggered this evaluation (init vs SPA URL change vs analytics event) — shows in\n // DataDog how often re-evaluation actually runs.\n this.incrementDiagnostic(\n SrDiagnostic.evalTrigger(isInit ? 'init' : forceTargetingReevaluation ? 'urlchange' : 'event'),\n );\n\n if (!this.identifiers || !this.identifiers.sessionId || !this.config) {\n // Q4: eval can't run because a prerequisite is missing — record exactly which one.\n this.incrementDiagnostic(SrDiagnostic.evalMissingPrereq);\n this.recordDiagnosticEvent(SrDiagnostic.evalMissingPrereq, {\n hasIdentifiers: !!this.identifiers,\n hasSessionId: !!this.identifiers?.sessionId,\n hasConfig: !!this.config,\n hasDeviceId: !!this.getDeviceId(),\n });\n if (this.identifiers && !this.identifiers.sessionId) {\n this.loggerProvider.log('Session ID has not been set yet, cannot evaluate targeting for Session Replay.');\n } else {\n this.loggerProvider.warn('Session replay init has not been called, cannot evaluate targeting.');\n }\n return;\n }\n\n // Handle cases where there's no targeting config\n if (!this.config.targetingConfig) {\n this.incrementDiagnostic(SrDiagnostic.evalNoConfig);\n if (isInit) {\n this.loggerProvider.log('Targeting config has not been set yet, cannot evaluate targeting.');\n } else {\n this.loggerProvider.log('No targeting config set, skipping initialization/recording for event.');\n return;\n }\n }\n\n // Store targeting parameters for use in getShouldRecord\n this.lastTargetingParams = targetingParams;\n\n // Re-evaluate only until we get the first match in this session.\n // Once matched, keep recording for the rest of the session.\n const targetingConfig = this.config.targetingConfig;\n const shouldReEvaluate = targetingConfig && !this.sessionTargetingMatch;\n if (shouldReEvaluate) {\n // Capture URL-change evaluation id so out-of-order async completions can be discarded.\n const urlChangeEvaluationId = forceTargetingReevaluation ? this.latestUrlChangeTargetingEvaluationId : undefined;\n let eventForTargeting = targetingParams.event;\n if (\n eventForTargeting &&\n Object.values(SpecialEventType).includes(eventForTargeting.event_type as SpecialEventType)\n ) {\n eventForTargeting = undefined;\n }\n\n const pageUrl = targetingParams.page?.url ?? getGlobalScope()?.location?.href ?? '';\n const pageForTargeting = targetingParams.page ?? (pageUrl !== '' ? { url: pageUrl } : undefined);\n\n // Record the targeting trigger event\n this.recordDiagnosticEvent(SrDiagnostic.targetingTrigger, {\n sessionId: this.identifiers.sessionId,\n deviceId: this.getDeviceId(),\n targetingConfig: this.config.targetingConfig,\n targetingParams: {\n userProperties: targetingParams.userProperties,\n event: eventForTargeting,\n page: pageForTargeting,\n },\n });\n\n const evalStart = Date.now();\n const targetingMatch = await evaluateTargetingAndStore({\n sessionId: this.identifiers.sessionId,\n targetingConfig,\n loggerProvider: this.loggerProvider,\n apiKey: this.config.apiKey,\n targetingParams: {\n userProperties: targetingParams.userProperties,\n event: eventForTargeting,\n page: pageForTargeting,\n },\n urlChange: forceTargetingReevaluation,\n diagnosticsClient: this.config.diagnosticsClient,\n deviceId: this.getDeviceId(),\n });\n const evalDurationMs = Date.now() - evalStart;\n const trigger = isInit ? 'init' : forceTargetingReevaluation ? 'urlchange' : 'event';\n // Evaluation latency — surfaces the slow-network residual gap (SR-4234) in DataDog as\n // sdk.diagnostics.sr.trc.eval.duration_ms.{avg,max,...}.\n this.recordDiagnosticHistogram(SrDiagnostic.evalDurationMs, evalDurationMs);\n\n if (\n forceTargetingReevaluation &&\n urlChangeEvaluationId !== undefined &&\n urlChangeEvaluationId !== this.latestUrlChangeTargetingEvaluationId\n ) {\n this.incrementDiagnostic(SrDiagnostic.evalStaleDiscarded);\n this.recordDiagnosticEvent(SrDiagnostic.evalStaleDiscarded, {\n sessionId: this.identifiers.sessionId,\n pageUrl: pageForTargeting?.url,\n evaluationId: urlChangeEvaluationId,\n latestEvaluationId: this.latestUrlChangeTargetingEvaluationId,\n evalDurationMs,\n });\n this.loggerProvider.debug(\n `Ignoring stale URL-change targeting result #${urlChangeEvaluationId}; latest is #${this.latestUrlChangeTargetingEvaluationId}.`,\n );\n return;\n }\n // Per-evaluation outcome (distinct from the per-session sr.gate.* gate counters).\n this.incrementDiagnostic(targetingMatch ? SrDiagnostic.evalMatch : SrDiagnostic.evalNoMatch);\n // Keep targeting match monotonic within a session: once true, always true.\n // This avoids races where an older in-flight evaluation resolves false after\n // a newer evaluation already resolved true.\n this.sessionTargetingMatch = this.sessionTargetingMatch || targetingMatch;\n // Q5: record ALL evaluation params (→ DataDog Logs) so a single evaluation can be fully\n // reconstructed by URL, identifiers, inputs, outcome, trigger and latency. userProperties\n // values are intentionally reduced to keys to avoid logging PII.\n this.recordDiagnosticEvent(SrDiagnostic.evalEvent, {\n // sessionId + deviceId are stamped by recordDiagnosticEvent.\n trigger,\n matched: targetingMatch,\n sessionTargetingMatch: this.sessionTargetingMatch,\n pageUrl: pageForTargeting?.url,\n hasDeviceId: !!this.getDeviceId(),\n hasEvent: !!eventForTargeting,\n eventType: eventForTargeting?.event_type,\n userPropertyKeys: targetingParams.userProperties ? Object.keys(targetingParams.userProperties) : [],\n evalDurationMs,\n });\n\n this.loggerProvider.debug(\n JSON.stringify(\n {\n name: 'targeted replay capture config',\n sessionTargetingMatch: this.sessionTargetingMatch,\n event: eventForTargeting,\n targetingParams: targetingParams,\n },\n null,\n 2,\n ),\n );\n } else if (targetingConfig && this.sessionTargetingMatch) {\n // Already matched earlier this session — recording continues without re-evaluation.\n this.incrementDiagnostic(SrDiagnostic.evalSkippedAlreadyMatched);\n }\n\n if (isInit) {\n void this.initialize(true);\n } else if (forceRestart || !this.recordCancelCallback) {\n this.loggerProvider.log('Recording events for session due to forceRestart or no ongoing recording.');\n await this.recordEvents();\n }\n };\n\n sendEvents(sessionId?: string | number) {\n const sessionIdToSend = sessionId || this.identifiers?.sessionId;\n const deviceId = this.getDeviceId();\n if (this.eventsManager && sessionIdToSend && deviceId) {\n if (this.isBelowMinSessionDuration()) {\n // Safe to dereference: isBelowMinSessionDuration() only returns true when both\n // this.config and this.sessionStartTime are defined.\n const startTime = this.sessionStartTime as number;\n const minMs = (this.config as SessionReplayJoinedConfig).minSessionDurationMs as number;\n this.loggerProvider.log(\n `Session ${sessionIdToSend} not sent: duration ${Date.now() - startTime}ms is below minimum ${minMs}ms.`,\n );\n // We deliberately do NOT clear the beacon buffer here. Blur/visibility-change\n // can call sendEvents() mid-session; if the session later crosses the threshold\n // those buffered events are legitimately sendable via beacon on page exit.\n // Cross-session leak is prevented in asyncSetSessionId, which drops the buffer\n // at the session transition. The page-leave path also gates independently.\n this.suppressedSendCount++;\n // gap #1: recording but events held back by min_session_duration — another \"recording yet\n // no replay in Amplitude\" cause.\n this.incrementDiagnostic(SrDiagnostic.sendSuppressedMinDuration);\n return;\n }\n // On the first send-after-pass for the session, emit a custom rrweb event so the\n // payload itself carries the gate verdict. Lets backend ingestion diff intended\n // vs actual replay counts to spot start-time-tracking regressions.\n //\n // Gate on recording being active too: addCustomRRWebEvent is a no-op when\n // recordCancelCallback/recordFunction aren't set yet (e.g. a blur-listener-fired\n // sendEvents reaches us before _recordEvents() activates on a reloaded long-lived\n // session). Tripping hasEmittedGateDecision unconditionally would lose the signal\n // for that session's first real send.\n if (\n !this.hasEmittedGateDecision &&\n this.config?.minSessionDurationMs !== undefined &&\n this.recordCancelCallback &&\n this.recordFunction\n ) {\n this.hasEmittedGateDecision = true;\n const elapsedMs = this.sessionStartTime !== undefined ? Date.now() - this.sessionStartTime : undefined;\n void this.addCustomRRWebEvent(\n CustomRRwebEvent.REPLAY_GATE_DECISION,\n {\n sessionId: sessionIdToSend,\n suppressedSendCount: this.suppressedSendCount,\n elapsedMs,\n minSessionDurationMs: this.config.minSessionDurationMs,\n },\n false,\n );\n }\n this.eventsManager.sendCurrentSequenceEvents({ sessionId: sessionIdToSend, deviceId });\n }\n }\n\n async initialize(shouldSendStoredEvents = false) {\n if (!this.identifiers?.sessionId) {\n this.loggerProvider.log(`Session is not being recorded due to lack of session id.`);\n return Promise.resolve();\n }\n\n const deviceId = this.getDeviceId();\n if (!deviceId) {\n this.loggerProvider.log(`Session is not being recorded due to lack of device id.`);\n return Promise.resolve();\n }\n this.eventsManager && shouldSendStoredEvents && void this.eventsManager.sendStoredEvents({ deviceId });\n\n return this.recordEvents();\n }\n\n shouldOptOut() {\n let identityStoreOptOut: boolean | undefined;\n if (this.config?.instanceName) {\n const identityStore = getAnalyticsConnector(this.config.instanceName).identityStore;\n identityStoreOptOut = identityStore.getIdentity().optOut;\n }\n\n return identityStoreOptOut !== undefined ? identityStoreOptOut : this.config?.optOut;\n }\n\n /**\n * Increment a diagnostics counter so the team can see the distribution of recording decisions\n * across a customer's sessions (e.g. lots of sr.gate.trc_no_match => rule isn't matching).\n * Ships via the analytics SDK's DiagnosticsClient. No-op when there's no client or diagnostics\n * isn't sampled in; never throws — diagnostics must never interfere with recording.\n */\n private incrementDiagnostic(counter: string) {\n try {\n // Mirror to the console (Debug level) so the full set of diagnostics is visible in the\n // browser, not only in DataDog — helps debugging when a customer can't share a repro env.\n this.loggerProvider.debug(`[SR diagnostics] ${counter}`);\n this.config?.diagnosticsClient?.increment(counter);\n } catch {\n // swallow — diagnostics is best-effort\n }\n }\n\n /**\n * Record a diagnostics histogram value (min/max/avg/count in DataDog). Same best-effort, never-\n * throws contract as incrementDiagnostic. Use for latencies/sizes, not per-call counts.\n */\n private recordDiagnosticHistogram(name: string, value: number) {\n try {\n // Mirror to the console (Debug level) — see incrementDiagnostic.\n this.loggerProvider.debug(`[SR diagnostics] ${name}=${value}`);\n // The only caller runs inside evaluateTargetingAndCapture's `this.config` guard, so the\n // `config == null` arm of this optional chain is unreachable here (kept as defensive parity\n // with recordDiagnosticEvent). The diagnosticsClient-absent arm IS exercised by no-client tests.\n /* istanbul ignore next */\n this.config?.diagnosticsClient?.recordHistogram(name, value);\n } catch {\n // swallow — diagnostics is best-effort\n }\n }\n\n /**\n * Record a diagnostics EVENT with properties. Events are forwarded to DataDog Logs, so the\n * properties become queryable fields (e.g. @matched, @pageUrl). Use sparingly vs counters: the\n * client caps in-memory events (~10 per save interval), so this is for context-rich signals at\n * meaningful decision points, not per-call tallies. Best-effort, never throws.\n */\n private recordDiagnosticEvent(name: string, properties: { [key: string]: unknown }) {\n try {\n const sessionId = this.identifiers?.sessionId;\n const deviceId = this.getDeviceId();\n // Always stamp sessionId, deviceId and srId so every diagnostics event (→ DataDog Logs) can\n // be correlated to a single session/device — and to the actual replay, since the Session\n // Replay ID is `${deviceId}/${sessionId}`. Caller props override if they pass their own.\n const enriched = {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n ...properties,\n };\n // Mirror to the console (Debug level) so the full event + props are visible in the browser,\n // not only in DataDog — see incrementDiagnostic.\n this.loggerProvider.debug(`[SR diagnostics] ${name} ${JSON.stringify(enriched)}`);\n this.config?.diagnosticsClient?.recordEvent(name, enriched);\n // Flush immediately so the event ships now rather than on the client's ~5-min timer (and so\n // short sessions that never reach the timer aren't lost). NOTE: this sends one capture POST\n // per event — higher request volume; revisit/gate before production.\n void this.config?.diagnosticsClient?._flush?.();\n } catch {\n // swallow — diagnostics is best-effort\n }\n }\n\n /**\n * Emit a single rich TRC decision snapshot per session to diagnostics — surfaced even when\n * nothing records (the exact case customers can't reproduce locally).\n */\n private recordTrcDecisionDiagnostic(shouldRecord: boolean) {\n const config = this.config;\n // Every caller is past getShouldRecord's `!this.identifiers`/`!this.config` guard, so both are\n // defined here; the `?.` arms below are unreachable defensive narrowing and excluded from\n // coverage. The reachable guards (no diagnosticsClient, undefined/duplicate sessionId) are tested.\n /* istanbul ignore next */\n if (!config) {\n return;\n }\n /* istanbul ignore next */\n const sessionId = this.identifiers?.sessionId;\n // Once past this guard, config.diagnosticsClient is truthy, so the fields below read config\n // directly rather than re-asserting with `?.` on every access.\n if (!config.diagnosticsClient || sessionId === undefined || sessionId === this.trcDiagnosticSessionId) {\n return;\n }\n this.trcDiagnosticSessionId = sessionId;\n // Goes through recordDiagnosticEvent so it carries sessionId + deviceId like every other event.\n this.recordDiagnosticEvent(SrDiagnostic.decision, {\n shouldRecord,\n captureEnabled: config.captureEnabled,\n hasTargetingConfig: !!config.targetingConfig,\n sessionTargetingMatch: this.sessionTargetingMatch,\n sampleRate: config.sampleRate,\n pageUrl: this.getCurrentPageForTargeting()?.url,\n sdkVersion: VERSION,\n });\n }\n\n getShouldRecord() {\n if (!this.identifiers || !this.config || !this.identifiers.sessionId) {\n this.loggerProvider.warn(`Session is not being recorded due to lack of config, please call sessionReplay.init.`);\n this.incrementDiagnostic(SrDiagnostic.gateNoIdentifiers);\n return false;\n }\n\n if (!this.config.captureEnabled) {\n this.loggerProvider.log(\n `Session ${this.identifiers.sessionId} not being captured due to capture being disabled for project or because the remote config could not be fetched.`,\n );\n this.incrementDiagnostic(SrDiagnostic.gateCaptureDisabled);\n this.recordTrcDecisionDiagnostic(false);\n return false;\n }\n\n if (this.shouldOptOut()) {\n this.loggerProvider.log(`Opting session ${this.identifiers.sessionId} out of recording due to optOut config.`);\n this.incrementDiagnostic(SrDiagnostic.gateOptOut);\n this.recordTrcDecisionDiagnostic(false);\n return false;\n }\n\n let shouldRecord = false;\n let message = '';\n let matched = false;\n\n // If targetingConfig exists, we'll use the sessionTargetingMatch to determine whether to record\n // Otherwise, we'll evaluate the session against the overall sample rate\n if (this.config.targetingConfig) {\n if (!this.sessionTargetingMatch) {\n message = `Not capturing replays for session ${this.identifiers.sessionId} due to not matching targeting conditions.`;\n this.loggerProvider.log(message);\n shouldRecord = false;\n matched = false;\n this.incrementDiagnostic(SrDiagnostic.gateTrcNoMatch);\n } else {\n message = `Capturing replays for session ${this.identifiers.sessionId} due to matching targeting conditions.`;\n this.loggerProvider.log(message);\n shouldRecord = true;\n matched = true;\n this.incrementDiagnostic(SrDiagnostic.gateTrcMatch);\n }\n } else {\n const isInSample = isSessionInSample(this.identifiers.sessionId, this.config.sampleRate);\n if (!isInSample) {\n message = `Opting session ${this.identifiers.sessionId} out of recording due to sample rate.`;\n this.loggerProvider.log(message);\n shouldRecord = false;\n matched = false;\n this.incrementDiagnostic(SrDiagnostic.gateSampleOut);\n } else {\n shouldRecord = true;\n matched = true;\n this.incrementDiagnostic(SrDiagnostic.gateSampleIn);\n }\n }\n\n // Only send custom rrweb event for targeting decision when the decision changes\n if (this.lastShouldRecordDecision !== shouldRecord && this.config.targetingConfig) {\n void this.addCustomRRWebEvent(CustomRRwebEvent.TARGETING_DECISION, {\n message,\n sessionId: this.identifiers.sessionId,\n matched,\n targetingParams: this.lastTargetingParams,\n });\n this.lastShouldRecordDecision = shouldRecord;\n }\n\n this.recordTrcDecisionDiagnostic(shouldRecord);\n\n return shouldRecord;\n }\n\n getBlockSelectors(): string | string[] | undefined {\n // For some reason, this defaults to empty array ([]) if undefined in the compiled script.\n // Empty arrays cause errors when being evaluated in Safari.\n // Force the selector to be undefined if it's an empty array.\n const blockSelector = this.config?.privacyConfig?.blockSelector ?? [];\n if (blockSelector.length === 0) {\n return undefined;\n }\n return blockSelector;\n }\n\n getMaskTextSelectors(): string | undefined {\n const privacyConfig = this.config?.privacyConfig;\n const effectiveLevel = privacyConfig ? getEffectiveMaskLevel(this.currentPageUrl, privacyConfig) : undefined;\n\n if (effectiveLevel === 'conservative') {\n return '*';\n }\n\n // If any urlMaskLevels rule uses 'conservative', always route all text nodes\n // through maskTextFn so the dynamic URL getter can decide at call time.\n // Without this, rrweb's static maskTextSelector would miss text nodes when\n // the user navigates from a non-conservative page to a conservative one.\n if (privacyConfig?.urlMaskLevels?.some((rule) => rule.maskLevel === 'conservative')) {\n return '*';\n }\n\n // If defaultMaskLevel is 'conservative' and URL rules exist, always route text through\n // maskTextFn — a page matching no rule falls back to the conservative default, and\n // rrweb must be set up at start to call maskTextFn for those text nodes.\n const urlMaskLevels = privacyConfig?.urlMaskLevels;\n if (privacyConfig?.defaultMaskLevel === 'conservative' && urlMaskLevels && urlMaskLevels.length > 0) {\n return '*';\n }\n\n const maskSelector = privacyConfig?.maskSelector;\n if (!maskSelector) {\n return;\n }\n\n return maskSelector as unknown as string;\n }\n\n async getRecordingPlugins(loggingConfig: LoggingConfig | undefined) {\n const plugins = [];\n\n // Add URL tracking plugin\n try {\n const urlTrackingPlugin = createUrlTrackingPlugin({\n ugcFilterRules: this.config?.interactionConfig?.ugcFilterRules || [],\n enablePolling: this.config?.enableUrlChangePolling || false,\n pollingInterval: this.config?.urlChangePollingInterval,\n captureDocumentTitle: this.config?.captureDocumentTitle,\n });\n\n plugins.push(urlTrackingPlugin);\n } catch (error) {\n this.loggerProvider.warn('Failed to create URL tracking plugin:', error);\n }\n\n // Default plugin settings -\n // {\n // level: ['info', 'log', 'warn', 'error'],\n // lengthThreshold: 10000,\n // stringifyOptions: {\n // stringLengthLimit: undefined,\n // numOfKeysLimit: 50,\n // depthOfLimit: 4,\n // },\n // logger: window.console,\n // }\n if (loggingConfig?.console?.enabled) {\n try {\n // Dynamic import keeps console plugin separate and only loads when needed\n const { getRecordConsolePlugin } = await import('@amplitude/rrweb-plugin-console-record');\n plugins.push(getRecordConsolePlugin({ level: loggingConfig.console.levels }));\n } catch (error) {\n this.loggerProvider.warn('Failed to load console plugin:', error);\n }\n }\n\n return plugins.length > 0 ? plugins : undefined;\n }\n\n private async getRecordFunction(): Promise<RecordFunction | null> {\n if (this.recordFunction) {\n return this.recordFunction;\n }\n\n try {\n const { record } = await import('@amplitude/rrweb-record');\n this.recordFunction = record;\n return record;\n } catch (error) {\n this.loggerProvider.warn('Failed to load rrweb-record module:', error);\n return null;\n }\n }\n\n async recordEvents(shouldLogMetadata = true) {\n if (this.recordEventsInFlight) {\n this.recordEventsPendingShouldLogMetadata = shouldLogMetadata;\n return;\n }\n this.recordEventsInFlight = true;\n try {\n await this._recordEvents(shouldLogMetadata);\n while (this.recordEventsPendingShouldLogMetadata !== null) {\n const pendingArgs = this.recordEventsPendingShouldLogMetadata;\n this.recordEventsPendingShouldLogMetadata = null;\n await this._recordEvents(pendingArgs);\n }\n } finally {\n this.recordEventsInFlight = false;\n this.recordEventsPendingShouldLogMetadata = null;\n }\n }\n\n private async _recordEvents(shouldLogMetadata = true) {\n const config = this.config;\n const shouldRecord = this.getShouldRecord();\n const sessionId = this.identifiers?.sessionId;\n if (!shouldRecord || !sessionId || !config) {\n return;\n }\n this.stopRecordingEvents();\n\n const recordFunction = await this.getRecordFunction();\n\n // May be undefined if cannot import rrweb-record\n if (!recordFunction) {\n // gap #1: gate said record, but rrweb couldn't load → no replay despite shouldRecord=true.\n this.incrementDiagnostic(SrDiagnostic.recordNoRecordFn);\n this.recordDiagnosticEvent(SrDiagnostic.recordNoRecordFn, {});\n return;\n }\n\n await this.initializeNetworkObservers();\n\n const networkLoggingConfig = config.loggingConfig?.network;\n const trackUrl = getServerUrl(config.serverZone, config.trackServerUrl);\n const ignoredUrls = [SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_EU_URL, SESSION_REPLAY_STAGING_URL, trackUrl];\n this.networkObservers?.start((event: NetworkRequestEvent) => {\n if (ignoredUrls.some((url) => event.url.startsWith(url))) return;\n void this.addCustomRRWebEvent(CustomRRwebEvent.FETCH_REQUEST, event);\n }, networkLoggingConfig);\n const { interactionConfig, loggingConfig } = config;\n\n const hooks = interactionConfig?.enabled\n ? {\n mouseInteraction:\n this.eventsManager &&\n this.clickHandler?.createHook({\n eventsManager: this.eventsManager,\n sessionId,\n deviceIdFn: this.getDeviceId.bind(this),\n mirror: recordFunction.mirror,\n ugcFilterRules: interactionConfig.ugcFilterRules ?? [],\n performanceOptions: config.performanceConfig?.interaction,\n }),\n scroll: this.scrollHook,\n }\n : {};\n\n const ugcFilterRules =\n interactionConfig?.enabled && interactionConfig.ugcFilterRules ? interactionConfig.ugcFilterRules : [];\n\n this.loggerProvider.log(`Session Replay capture beginning for ${sessionId}.`);\n // gap #1: rrweb is actually starting. Closes the \"gate said yes but no replay\" blind spot,\n // and its srId is the id the replay uploads under (compare with analytics events to catch the\n // device-id mismatch that breaks stitching).\n this.incrementDiagnostic(SrDiagnostic.recordStarted);\n this.recordDiagnosticEvent(SrDiagnostic.recordStarted, {});\n\n try {\n const crossOriginIframesEnabled = !!config.crossOriginIframes?.enabled;\n const coordinateChildren = config.crossOriginIframes?.coordinateChildren !== false;\n const childMode = crossOriginIframesEnabled && isInIframe();\n\n if (childMode && coordinateChildren) {\n // Child mode: don't self-start; wait for a start signal from the parent.\n // (The previous listener, if any, was already removed by stopRecordingEvents above.)\n this.crossOriginParentSignalCleanup = listenForParentSignals({\n onStart: () => this._recordEventsInChildMode(recordFunction, sessionId, config, hooks),\n onStop: () => {\n try {\n // Only cancel the rrweb recording — do NOT call stopRecordingEvents() here,\n // which would clear crossOriginParentSignalCleanup and make the child deaf\n // to subsequent start/stop cycles from the parent.\n this.recordCancelCallback && this.recordCancelCallback();\n this.recordCancelCallback = null;\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(\n `Error occurred while stopping child iframe replay capture: ${typedError.toString()}`,\n );\n }\n },\n });\n return;\n }\n\n this.recordCancelCallback = recordFunction({\n ...this.buildRRWebRecordOptions(\n config,\n hooks,\n (event: eventWithTime) => {\n if (this.shouldOptOut()) {\n this.loggerProvider.log(`Opting session ${sessionId} out of recording due to optOut config.`);\n this.stopRecordingEvents();\n this.sendEvents();\n return;\n }\n\n if (event.type === RRWebEventType.Meta) {\n event.data.href = getPageUrl(event.data.href, ugcFilterRules);\n }\n\n if (this.eventCompressor) {\n // Schedule processing during idle time if the browser supports requestIdleCallback\n this.eventCompressor.enqueueEvent(event, sessionId);\n } else {\n // eventCompressor is not yet ready (concurrent call racing _init()).\n // Buffer the event so it can be flushed once the compressor is initialized.\n this.pendingEmitEvents.push({ event, sessionId });\n }\n },\n 'Error while capturing replay: ',\n ),\n plugins: await this.getRecordingPlugins(loggingConfig),\n recordCrossOriginIframes: crossOriginIframesEnabled,\n });\n\n if (crossOriginIframesEnabled && !childMode && coordinateChildren) {\n if (!this.crossOriginIframeCoordinator) {\n this.crossOriginIframeCoordinator = new CrossOriginIframeCoordinator();\n }\n this.crossOriginIframeCoordinator.start();\n }\n\n void this.addCustomRRWebEvent(CustomRRwebEvent.DEBUG_INFO);\n if (shouldLogMetadata) {\n void this.addCustomRRWebEvent(CustomRRwebEvent.METADATA, this.metadata);\n }\n } catch (error) {\n this.loggerProvider.warn('Failed to initialize session replay:', error);\n }\n }\n\n private buildRRWebRecordOptions(\n config: SessionReplayJoinedConfig,\n hooks: { mouseInteraction?: any; scroll?: scrollCallback },\n emit: (event: eventWithTime) => void,\n errorLogPrefix: string,\n ): Parameters<RecordFunction>[0] {\n const { privacyConfig } = config;\n return {\n emit,\n inlineStylesheet: config.shouldInlineStylesheet,\n hooks,\n maskAllInputs: true,\n maskTextClass: MASK_TEXT_CLASS,\n blockClass: BLOCK_CLASS,\n blockSelector: this.getBlockSelectors() as string | undefined,\n applyBackgroundColorToBlockedElements: config.applyBackgroundColorToBlockedElements,\n maskInputFn: maskFn('input', privacyConfig, () => this.currentPageUrl),\n maskTextFn: maskFn('text', privacyConfig, () => this.currentPageUrl),\n maskAttributeFn: maskAttributeFn(privacyConfig, () => this.currentPageUrl),\n maskTextSelector: this.getMaskTextSelectors(),\n ...(config.fullSnapshotIntervalMs !== undefined && { checkoutEveryNms: config.fullSnapshotIntervalMs }),\n recordCanvas: false,\n captureAdoptedStyleSheets: config.captureAdoptedStyleSheets,\n // Strip nodes that are never rendered by the rrweb replay player.\n // None of these affect visual fidelity; omitting them reduces snapshot size.\n slimDOMOptions: {\n script: true,\n comment: true,\n headFavicon: true,\n headWhitespace: true,\n headMetaDescKeywords: true,\n headMetaSocial: true,\n headMetaRobots: true,\n headMetaHttpEquiv: true,\n headMetaAuthorship: true,\n headMetaVerification: true,\n },\n errorHandler: (error: unknown) => {\n const typedError = error as Error & { _external_?: boolean };\n // styled-components relies on this error being thrown and bubbled up, rrweb is otherwise suppressing it\n if (typedError.message.includes('insertRule') && typedError.message.includes('CSSStyleSheet')) {\n throw typedError;\n }\n // rrweb monkey-patches window functions like CSSStyleSheet.insertRule; errors from external callers\n // (e.g. styled-components) must be re-thrown so they aren't silently swallowed.\n if (typedError._external_) {\n throw typedError;\n }\n this.loggerProvider.warn(errorLogPrefix, typedError.toString());\n // Return true so that we don't clutter user's consoles with internal rrweb errors\n return true;\n },\n };\n }\n\n private _recordEventsInChildMode(\n recordFunction: RecordFunction,\n sessionId: string | number,\n config: SessionReplayJoinedConfig,\n hooks: { mouseInteraction?: any; scroll?: scrollCallback },\n ) {\n // In child mode, rrweb detects window.parent !== window and routes events via\n // postMessage to the parent instead of calling emit. The emit callback is unused.\n // Note: recording plugins (URL tracking, console capture) are intentionally omitted\n // here — the child's events are merged into the parent stream, so URL changes inside\n // the iframe should not be recorded as parent page-view events.\n try {\n // Stop only the previous rrweb recording. Do NOT call stopRecordingEvents() here:\n // that would clear crossOriginParentSignalCleanup — the very listener that invoked\n // this method — making the child permanently deaf to subsequent stop/start cycles.\n this.recordCancelCallback && this.recordCancelCallback();\n this.recordCancelCallback = null;\n this.recordCancelCallback = recordFunction({\n ...this.buildRRWebRecordOptions(\n config,\n hooks,\n () => {\n // no-op: child events are forwarded to parent via postMessage by rrweb\n },\n 'Error while capturing replay (child iframe): ',\n ),\n recordCrossOriginIframes: true, // child mode is only entered when crossOriginIframes.enabled is true\n });\n this.loggerProvider.log(`Session Replay child iframe capture beginning for session ${sessionId}.`);\n } catch (error) {\n this.loggerProvider.warn('Failed to initialize session replay in child iframe mode:', error);\n }\n }\n\n addCustomRRWebEvent = async (\n eventName: CustomRRwebEvent,\n eventData: { [key: string]: any } = {},\n addStorageInfo = true,\n ) => {\n try {\n let debugInfo: DebugInfo | undefined = undefined;\n const config = this.config;\n // Only add debug info for non-metadata events\n if (config && eventName !== CustomRRwebEvent.METADATA) {\n debugInfo = {\n config: getDebugConfig(config),\n version: VERSION,\n };\n if (addStorageInfo) {\n const storageSizeData = await getStorageSize();\n debugInfo = {\n ...storageSizeData,\n ...debugInfo,\n };\n }\n }\n // Check first to ensure we are recording\n if (this.recordCancelCallback && this.recordFunction) {\n this.recordFunction.addCustomEvent(eventName, {\n ...eventData,\n ...debugInfo,\n });\n } else {\n this.loggerProvider.debug(\n `Not able to add custom replay capture event ${eventName} due to no ongoing recording.`,\n );\n }\n } catch (e) {\n this.loggerProvider.debug('Error while adding custom replay capture event: ', e);\n }\n };\n\n stopRecordingEvents = () => {\n try {\n this.loggerProvider.log('Session Replay capture stopping.');\n this.recordCancelCallback && this.recordCancelCallback();\n this.recordCancelCallback = null;\n this.networkObservers?.stop();\n this.crossOriginIframeCoordinator?.stop();\n this.crossOriginIframeCoordinator = null;\n // Remove the child-mode parent signal listener so a later mode change\n // (e.g. crossOriginIframes disabled) does not leave a stale listener.\n this.crossOriginParentSignalCleanup?.();\n this.crossOriginParentSignalCleanup = null;\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(`Error occurred while stopping replay capture: ${typedError.toString()}`);\n }\n };\n\n getDeviceId() {\n return this.identifiers?.deviceId;\n }\n\n getSessionId() {\n return this.identifiers?.sessionId;\n }\n\n async flush(useRetry = false) {\n // Intentionally not gated on min_session_duration_ms. flush() forwards payloads\n // already queued in trackDestination, and every code path that queues into it —\n // sendCurrentSequenceEvents, addEvent's batch-split path, sendStoredEvents reading\n // sequencesToSend from IDB — has already passed the gate at the time of queuing.\n // A duplicate gate here would be unreachable.\n return this.eventsManager?.flush(useRetry);\n }\n\n shutdown() {\n this.urlChangeCleanup?.();\n this.crossOriginParentSignalCleanup?.();\n this.crossOriginParentSignalCleanup = null;\n this.teardownEventListeners(true);\n this.stopRecordingEvents();\n this.sendEvents();\n }\n\n private mapSDKType(sdkType: string | undefined) {\n if (sdkType === 'plugin') {\n return '@amplitude/plugin-session-replay-browser';\n }\n\n if (sdkType === 'segment') {\n return '@amplitude/segment-session-replay-plugin';\n }\n\n return null;\n }\n\n private setMetadata(\n sessionId: string | number | undefined,\n joinedConfig: SessionReplayJoinedConfig,\n localConfig: SessionReplayLocalConfig,\n remoteConfig: SessionReplayRemoteConfig | undefined,\n replaySDKVersion: string | undefined,\n standaloneSDKVersion: string | undefined,\n sdkType: string | undefined,\n ) {\n const hashValue = sessionId?.toString() ? generateHashCode(sessionId.toString()) : undefined;\n\n this.metadata = {\n joinedConfig,\n localConfig,\n remoteConfig,\n sessionId,\n hashValue,\n sampleRate: joinedConfig.sampleRate,\n replaySDKType: this.mapSDKType(sdkType),\n replaySDKVersion,\n standaloneSDKType: '@amplitude/session-replay-browser',\n standaloneSDKVersion,\n };\n }\n\n private async initializeNetworkObservers(): Promise<void> {\n if (this.config?.loggingConfig?.network?.enabled && !this.networkObservers) {\n try {\n const { NetworkObservers: NetworkObserversClass } = await import('./observers');\n this.networkObservers = new NetworkObserversClass();\n } catch (error) {\n this.loggerProvider.warn('Failed to import or instantiate NetworkObservers:', error);\n }\n }\n }\n}\n","import type { TargetingParameters } from '@amplitude/targeting';\nimport { TargetingConfig } from '../config/types';\nimport { Logger } from '@amplitude/analytics-types';\nimport { IDiagnosticsClient } from '@amplitude/analytics-core';\nimport { SessionReplayTargetingInput } from '../typings/session-replay';\nimport { targetingIDBStore } from './targeting-idb-store';\nimport { SrDiagnostic } from '../diagnostics';\n\nexport const evaluateTargetingAndStore = async ({\n sessionId,\n targetingConfig,\n loggerProvider,\n apiKey,\n targetingParams,\n urlChange = false,\n diagnosticsClient,\n deviceId,\n}: {\n sessionId: string | number;\n targetingConfig: TargetingConfig;\n loggerProvider: Logger;\n apiKey: string;\n targetingParams?: SessionReplayTargetingInput;\n urlChange?: boolean;\n diagnosticsClient?: IDiagnosticsClient;\n deviceId?: string;\n}) => {\n await targetingIDBStore.clearStoreOfOldSessions({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n currentSessionId: sessionId,\n });\n\n const idbTargetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n sessionId: sessionId,\n });\n\n // Skip IDB cache when re-evaluating with a new page (e.g. URL change); otherwise we'd never\n // re-evaluate and would keep returning true after navigating to a non-matching page.\n if (idbTargetingMatch === true && !urlChange) {\n return true;\n }\n\n // If the targeting config is undefined or an empty object,\n // assume the response was valid but no conditions were set,\n // so all users match targeting\n let sessionTargetingMatch = true;\n try {\n // Dynamic import of the targeting package\n const { evaluateTargeting: evaluateTargetingPackage } = await import('@amplitude/targeting');\n\n const params: TargetingParameters = {\n ...targetingParams,\n flag: targetingConfig,\n sessionId: typeof sessionId === 'string' ? parseInt(sessionId, 10) : sessionId,\n apiKey: apiKey,\n loggerProvider: loggerProvider,\n };\n diagnosticsClient?.recordEvent(SrDiagnostic.targetingTrigger, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n matched: sessionTargetingMatch,\n targetingConfig: targetingConfig,\n });\n const targetingResult = await evaluateTargetingPackage(params);\n if (targetingResult && targetingResult.sr_targeting_config) {\n sessionTargetingMatch = targetingResult.sr_targeting_config.key === 'on';\n }\n // gap #2: the raw engine verdict. variantKey 'on' => matched; 'off'/undefined => not.\n // Pair with the eval event's pageUrl to tell \"URL condition didn't match\" from \"URL matched\n // but the segment bucket (capture %) didn't allocate this session\".\n try {\n diagnosticsClient?.recordEvent(SrDiagnostic.evalResult, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n variantKey: targetingResult?.sr_targeting_config?.key ?? null,\n matched: sessionTargetingMatch,\n targetingConfig: targetingConfig,\n });\n // Flush now so the verdict ships immediately (vs the client's ~5-min timer). One capture\n // POST per event — higher volume; revisit/gate before production.\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n\n void targetingIDBStore.storeTargetingMatchForSession({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n sessionId: sessionId,\n targetingMatch: sessionTargetingMatch,\n });\n } catch (err: unknown) {\n const knownError = err as Error;\n // Q3 \"is the TRC failing?\": the targeting engine threw — record it so the team sees TRC\n // errors in DataDog (this exception is otherwise swallowed). Best-effort, never re-throws.\n try {\n diagnosticsClient?.increment(SrDiagnostic.evalError);\n diagnosticsClient?.recordEvent(SrDiagnostic.evalError, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n message: knownError.message,\n });\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n loggerProvider.warn(knownError.message);\n }\n return sessionTargetingMatch;\n};\n","import { AnalyticsConnector } from '@amplitude/analytics-connector';\nimport { DEFAULT_INSTANCE_NAME } from './types/constants';\nexport var getAnalyticsConnector = function (instanceName) {\n if (instanceName === void 0) { instanceName = DEFAULT_INSTANCE_NAME; }\n return AnalyticsConnector.getInstance(instanceName);\n};\nexport var setConnectorUserId = function (userId, instanceName) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n getAnalyticsConnector(instanceName).identityStore.editIdentity().setUserId(userId).commit();\n};\nexport var setConnectorDeviceId = function (deviceId, instanceName) {\n getAnalyticsConnector(instanceName).identityStore.editIdentity().setDeviceId(deviceId).commit();\n};\n//# sourceMappingURL=analytics-connector.js.map","import { debugWrapper, LogConfig } from '@amplitude/analytics-core';\nimport { getDefaultConfig } from './config/local-config';\nimport { SessionReplay } from './session-replay';\nimport { AmplitudeSessionReplay } from './typings/session-replay';\n\nexport const getLogConfig = (sessionReplay: SessionReplay) => (): LogConfig => {\n const { config } = sessionReplay;\n const { loggerProvider: logger, logLevel } = config || getDefaultConfig();\n return {\n logger,\n logLevel,\n };\n};\n\nconst createInstance: () => AmplitudeSessionReplay = () => {\n const sessionReplay = new SessionReplay();\n return {\n init: debugWrapper(sessionReplay.init.bind(sessionReplay), 'init', getLogConfig(sessionReplay)),\n evaluateTargetingAndCapture: debugWrapper(\n sessionReplay.evaluateTargetingAndCapture.bind(sessionReplay),\n 'evaluateTargetingAndRecord',\n getLogConfig(sessionReplay),\n ),\n setSessionId: debugWrapper(\n sessionReplay.setSessionId.bind(sessionReplay),\n 'setSessionId',\n getLogConfig(sessionReplay),\n ),\n getSessionId: debugWrapper(\n sessionReplay.getSessionId.bind(sessionReplay),\n 'getSessionId',\n getLogConfig(sessionReplay),\n ),\n getSessionReplayProperties: debugWrapper(\n sessionReplay.getSessionReplayProperties.bind(sessionReplay),\n 'getSessionReplayProperties',\n getLogConfig(sessionReplay),\n ),\n flush: debugWrapper(sessionReplay.flush.bind(sessionReplay), 'flush', getLogConfig(sessionReplay)),\n shutdown: debugWrapper(sessionReplay.shutdown.bind(sessionReplay), 'shutdown', getLogConfig(sessionReplay)),\n };\n};\n\nexport default createInstance();\n","import sessionReplay from './session-replay-factory';\nexport const {\n init,\n setSessionId,\n getSessionId,\n getSessionReplayProperties,\n flush,\n shutdown,\n evaluateTargetingAndCapture,\n} = sessionReplay;\nexport { SessionReplayOptions, StoreType } from './typings/session-replay';\nexport { SafeLoggerProvider } from './logger';\nexport { AmplitudeSessionReplay } from './typings/session-replay';\n"],"names":["IdentifyOperation","SpecialEventType","Status","DEFAULT_INSTANCE_NAME","AMPLITUDE_SERVER_URL","LogLevel","getGlobalScope","ampIntegrationContextName","globalThis","window","self","global","hex","__spreadArray","__read","Array","keys","map","index","toString","padStart","UUID","a","_a","globalScope","crypto","getRandomValues","Math","random","String","replace","legacyUUID","r","Uint8Array","entries","_b","int","includes","concat","join","returnWrapper","awaitable","promise","Promise","resolve","PREFIX","Logger","this","logLevel","None","prototype","disable","enable","Warn","log","args","_i","arguments","length","Verbose","console","warn","error","Error","debug","Debug","getDefaultConfig","flushMaxRetries","flushQueueSize","flushIntervalMillis","instanceName","loggerProvider","offline","optOut","serverUrl","serverZone","useBatch","Config","options","_c","_d","_optOut","defaultConfig","apiKey","minIdLength","plan","ingestionMetadata","undefined","storageProvider","transportProvider","serverConfig","createServerConfig","Object","defineProperty","get","set","enumerable","configurable","getServerUrl","_serverZone","debugWrapper","fn","fnName","getLogConfig","getStates","fnContext","logger","apply","ignoreDepth","debugContext","type","name","stacktrace","stack","split","slice","text","trim","time","start","Date","toISOString","states","before","result","then","after","end","JSON","stringify","ApplicationContextProviderImpl","getApplicationContext","versionName","language","getLanguage","platform","os","deviceModel","navigator","languages","EventBridgeImpl","queue","logEvent","event","receiver","push","setEventReceiver","forEach","__assign","assign","t","s","i","n","p","hasOwnProperty","call","__values","o","Symbol","iterator","m","next","value","done","TypeError","e","ar","SuppressedError","isEqual","obj1","obj2","e_1","typeA","primitive_1","primitive_1_1","e_1_1","return","isArrayA","isArray","isArrayB","sorted1","sort","sorted2","result_1","key","obj","ownProps","resArray","ServerZone","IdentityStoreImpl","identity","userProperties","listeners","Set","editIdentity","actingUserProperties","actingIdentity","setUserId","userId","setDeviceId","deviceId","setUserProperties","setOptOut","updateUserProperties","actions","e_2","e_3","actingProperties","_e","_f","action","properties","_g","_h","_j","e_2_1","_k","_l","e_3_1","commit","setIdentity","getIdentity","originalIdentity","listener","addIdentityListener","add","removeIdentityListener","delete","safeGlobal","AnalyticsConnector","identityStore","eventBridge","applicationContextProvider","getInstance","generateHashCode","str","hash","charCodeAt","isTimestampInSampleTemp","timestamp","sampleRate","hashNumber","abs","TABLE_NAMES","INTERNAL_KEYS","DiagnosticsStorage","dbPromise","dbName","substring","isSupported","indexedDB","getDB","__awaiter","__generator","openDB","_this","reject","request","open","onerror","onsuccess","db","onclose","close","onupgradeneeded","target","createTables","objectStoreNames","contains","createObjectStore","keyPath","autoIncrement","createIndex","unique","setTags","tags","transaction_1","store_1","error_1","label","trys","sent","transaction","objectStore","oncomplete","onabort","put","incrementCounters","counters","transaction_2","store_2","error_2","incrementValue","getRequest","existingRecord","existingValue","setHistogramStats","histogramStats","transaction_3","store_3","error_3","newStats","updatedStats","count","min","max","sum","addEventRecords","events","transaction_4","store_4","error_4","countRequest","currentCount","availableSlots","setInternal","transaction_5","store_5","error_5","getInternal","transaction_6","store_6","error_6","getLastFlushTimestamp","record","error_7","parseInt","setLastFlushTimestamp","error_8","clearTable","tableName","clear","getAllAndClear","error_9","all","getAllFromStore","getAll","detectSdkOrigin","payload","normalizedScriptUrls","scope","getNormalizedScriptUrls","normalizedScriptUrls_1","normalizedScriptUrls_1_1","normalizedScriptUrl","filename","extractFilenameFromStack","match","stringifyReason","reason","FLUSH_INTERVAL_MS","MAX_MEMORY_STORAGE_COUNT","DiagnosticsClient","inMemoryTags","inMemoryCounters","inMemoryHistograms","inMemoryEvents","saveTimer","flushTimer","config","enabled","startTimestamp","now","shouldTrack","storage","initializeFlushInterval","increment","client","addEventListener","capture","context","recordEvent","message","error_name","errorName","metadata","colno","lineno","isTrusted","matchReason","enableSdkErrorListeners","isStorageAndTrackEnabled","Boolean","setTag","startTimersIfNeeded","size","recordHistogram","existing","event_name","event_properties","setTimeout","saveAllDataToStorage","catch","finally","_flush","tagsToSave","countersToSave","histogramsToSave","eventsToSave","tagRecords","counterRecords","histogramStatsRecords","eventRecords","histogram","stats","avg","round","fetch","method","headers","body","ok","lastFlushTimestamp","timeSinceLastFlush","_setFlushTimer","delay","_setSampleRate","BaseTransport","send","_serverUrl","_payload","_enableRequestBodyCompression","buildResponse","responseJSON","_m","_o","_p","_q","_r","_s","_t","_u","_v","_w","_x","statusCode","code","status","buildStatus","Success","eventsIngested","events_ingested","payloadSizeBytes","payload_size_bytes","serverUploadTime","server_upload_time","Invalid","missingField","missing_field","eventsWithInvalidFields","events_with_invalid_fields","eventsWithMissingFields","events_with_missing_fields","eventsWithInvalidIdLengths","events_with_invalid_id_lengths","epsThreshold","eps_threshold","exceededDailyQuotaDevices","exceeded_daily_quota_devices","silencedDevices","silenced_devices","silencedEvents","silenced_events","throttledDevices","throttled_devices","throttledEvents","throttled_events","PayloadTooLarge","RateLimit","throttledUsers","throttled_users","exceededDailyQuotaUsers","exceeded_daily_quota_users","Timeout","isSuccessStatusCode","Failed","Unknown","FetchTransport","_super","customHeaders","__extends","response","responseText","Accept","parse","RemoteConfigLocalStorage","fetchConfig","failedRemoteConfigInfo","remoteConfig","lastFetch","localStorage","getItem","remoteConfigInfo","removeItem","setConfig","setItem","CODE_STATUS","RemoteConfigClient","callbackInfos","lastSuccessfulFetch","fetchPromise","isLastFetchInvalidApiKey","subscribe","deliveryMode","callback","id","callbackInfo","subscribeAll","subscribeWaitForRemote","timeout","unsubscribe","findIndex","splice","updateConfigs","getOrCreateFetchPromise","sendCallback","remotePromise","cachePromise","race","timeoutPromise","_","source","filteredConfig","lastCallback","reduce","retries","interval","_loop_1","this_1","attempt","state_1","shouldRetry","abortController","timeoutId","res","AbortController","abort","getUrlParams","signal","json","clearTimeout","getJitterDelay","baseDelay","floor","encodedApiKey","encodeURIComponent","urlParams","URLSearchParams","append","CONFIG_GROUP","AMPLITUDE_ORIGIN","AMPLITUDE_ORIGINS_MAP","US","EU","STAGING","MESSENGER_BRAND","MESSENGER_GLOBAL_KEY","BaseWindowMessenger","origin","isSetup","messageHandler","requestCallbacks","actionHandlers","Map","pendingMessages","scriptLoadPromises","endpoint","notify","opener","postMessage","sendRequest","substr","handleResponse","responseData","registerActionHandler","handler","has","queued","queued_1","queued_1_1","loadScriptOnce","url","loadPromise","document","querySelector","CSS","escape","scriptElement","createElement","async","src","once","head","appendChild","asyncLoadScript","setup","eventData","data","destroy","removeEventListener","getOrCreateWindowMessenger","messenger","BG_CAPTURE_BRAND","DEFAULT_EVENT_PROPERTY_PREFIX","DEFAULT_SESSION_REPLAY_PROPERTY","DEFAULT_SERVER_ZONE","DEFAULT_PERFORMANCE_CONFIG","DEFAULT_URL_CHANGE_POLLING_INTERVAL","SESSION_REPLAY_DEBUG_PROPERTY","MASK_TEXT_CLASS","UNMASK_TEXT_CLASS","SESSION_REPLAY_SERVER_URL","SESSION_REPLAY_EU_URL","SESSION_REPLAY_STAGING_URL","MAX_SINGLE_EVENT_SIZE","WAF_PAYLOAD_TOO_LARGE_PATTERN","MIN_INTERVAL","MAX_INTERVAL","KB_SIZE","CROSS_ORIGIN_IFRAME_MESSAGE_TYPE","CustomRRwebEvent","SafeLoggerProvider","constructor","getSafeMethod","__rrweb_original__","bind","DEFAULT_MASK_LEVEL","trackServerUrl","isMaskedForLevel","elementType","level","element","inputType","hasAttribute","toLowerCase","getInputType","autocomplete","startsWith","getEffectiveMaskLevel","urlMaskLevels","rule","globToRegex","test","maskLevel","defaultMaskLevel","isMasked","currentUrl","closest","shouldMask","maskSelector","some","selector","shouldUnmask","unmaskSelector","maskFn","getCurrentUrl","maskAttributeFn","maskAttributes","tagName","location","href","globRegexCache","glob","cached","T_TRAILING","T_MIDDLE","T_DSTAR","T_STAR","T_QUEST","regex","RegExp","getPageUrl","pageUrl","ugcFilterRules","replacement","getStorageSize","usage","quota","usageDetails","estimate","totalStorageSize","percentOfQuota","Number","EPSILON","getDebugConfig","debugConfig","SessionReplayLocalConfig","super","configServerUrl","shouldInlineStylesheet","version","performanceConfig","storeType","applyBackgroundColorToBlockedElements","enableUrlChangePolling","urlChangePollingInterval","captureDocumentTitle","fullSnapshotIntervalMs","eagerFullSnapshotSend","captureFullSnapshotOnFocus","maxPersistedEventsSizeBytes","sanitizeByteSize","MIN_EVENT_BYTE_SIZE","MAX_PERSISTED_EVENTS_SIZE_CEILING","maxSingleEventSizeBytes","MAX_SINGLE_EVENT_SIZE_CEILING","privacyConfig","from","interactionConfig","every","isValidGlobUrl","globUrl","validateUGCFilterRules","debugMode","legacyOptions","useWebWorker","experimental","enableTransportCompression","sendTimeoutMs","captureAdoptedStyleSheets","crossOriginIframes","flushIntervalConfig","raw","sanitized","minIntervalMs","isFinite","MIN_FLUSH_INTERVAL_FLOOR_MS","maxIntervalMs","isNaN","effectiveMin","effectiveMax","sanitizeFlushIntervalConfig","diagnosticsEnabled","diagnosticsSampleRate","diagnosticsClient","createStandaloneDiagnosticsClient","EventType","EventType2","IncrementalSource","IncrementalSource2","MouseInteractions","MouseInteractions2","SrDiagnostic","init","sessionChanged","configSource","configHasTargeting","configNoTargeting","configFetchFailed","configReceived","targetingTrigger","evalTrigger","trigger","evalNoConfig","evalMissingPrereq","evalMatch","evalNoMatch","evalError","evalStaleDiscarded","evalSkippedAlreadyMatched","evalDurationMs","evalEvent","evalResult","recordStarted","recordNoRecordFn","sendSuppressedMinDuration","gateNoIdentifiers","gateCaptureDisabled","gateOptOut","gateTrcMatch","gateTrcNoMatch","gateSampleIn","gateSampleOut","decision","urlChange","urlChangeEvent","urlListenerSetup","urlListenerAttached","urlListenerSkipped","SessionReplayJoinedConfigGenerator","remoteConfigClient","localConfig","sessionId","generateJoinedConfig","sessionReplayRemoteConfig","captureEnabled","namespaceConfig","samplingConfig","sr_sampling_config","sr_privacy_config","targetingConfig","sr_targeting_config","samplingForLog","targetingSegments","segments","sr_interaction_config","loggingConfig","sr_logging_config","srId","hasSampling","capture_enabled","sample_rate","hasTargeting","targetingSegmentCount","hasPrivacy","joinedConfig","remotePrivacyConfig","minSessionDurationMs","sanitizeMinSessionDurationMs","min_session_duration_ms","localPrivacyConfig","joinedPrivacyConfig","blockSelector","privacyConfigSelectorMap","selectorMap","selectorType","fragment","createDocumentFragment","dropInvalidSelectors","selectors","filter","removeInvalidSelectorsFromPrivacyConfig","MAX_MIN_SESSION_DURATION_MS","isMergeableMutation","IncrementalSnapshot","Mutation","isAttachIframe","mergeStyleDiffs","diffs","merged","diff","prop","coalesceStyleAttributes","attributes","styleIndicesById","attr","list","styleValueAt","style","dropStyleAt","mergedStyleByIndex","indices","values","lastResetPos","idx","pos","survivingObjectIndices","lastObjectIdx","mergedStyle","rest","mergeGroup","first","firstAddEventIndex","lastAddEventIndex","firstRemoveEventIndex","lastRemoveEventIndex","lastParentById","adds","node","parentId","remove","removes","transientIds","preExistingTransientIds","firstAddIdx","firstRemoveIdx","cascadeDropAddsOnlyIds","changed","nodeId","nodeFirstRemoveIdx","nodeFirstAddIdx","needsFilter","filteredRemoves","eventIdx","allAdds","flatMap","allTexts","texts","allAttributes","mergedAttributes","mergeMutationEvents","j","EventCompressor","eventsManager","workerScript","onFullSnapshotProcessed","taskQueue","pendingQueue","isProcessing","compressEvent","addCompressedEventToManager","compressedEvent","eventSizeBytes","Blob","addEvent","addCompressedEvent","worker","err","flushQueue","mergeMutationTasks","task","shift","compressed","terminate","canUseIdleCallback","blob","blobUrl","URL","createObjectURL","Worker","preventDefault","onmessage","scheduleIdleProcessing","requestIdleCallback","idleDeadline","processQueue","enqueueEvent","RRWebEventType","FullSnapshot","allTasks","timeRemaining","didTimeout","tasks","mergeMutations","MAX_RETRIES_EXCEEDED_MESSAGE","STORAGE_FAILURE","SESSION_KILLED_MESSAGE","VERSION","SessionReplayTrackDestination","payloadBatcher","storageKey","retryTimeout","scheduled","sendIdCounter","pendingWorkerRequests","timedOutWorkerRequests","flushPauseUntilMs","mergeOnNextFlush","coalesceNextFlush","mergeLogFiredThisPause","killedSessions","pending","msg","handlePayloadTooLargeResponse","isWaf","timedOut","skipCode","applyServerDirective","completeRequest","sendEventsList","destinationData","addToQueue","attempts","markCoalesceNextFlush","schedule","sendBeacon","byteLength","trimmedEvents","lo","hi","mid","device_id","session_id","api_key","payloadBlob","pauseRemaining","effectiveTimeout","flush","useRetry","mergeQueueAfterThrottle","mergeDrainBacklog","coalesceByIdentity","groups","ctx","arr","group","current","currentBytes","flushCurrent","ctxBytes","prevOnComplete","onComplete","ctxOnComplete","allSettled","sendViaWorker","sendOnMainThread","rememberTimedOutRequest","eventType","sdkVersion","oldest","sessionReplayLibrary","payloadJson","gzipped","jsonStr","stream","CS","CompressionStream","writer","writable","getWriter","reader","readable","getReader","chunks","readPromise","read","write","TextEncoder","encode","totalLength","c","offset","chunk","gzipJson","payloadSize","controller","Authorization","keepalive","sendTimeout","responseBody","handleReponse","success","handleOtherResponse","handleSuccessResponse","totalSizeKB","noop","sizeOfEventsList","wasInPause","killSession","remaining","BaseEventsStore","timeAtLastSplit","_timeAtLastSplit","minInterval","maxInterval","maxPersistedEventsSize","shouldSplitEventsList","nextEventString","sizeOfNextEvent","getStringSize","getEventsArraySize","bytes","NaN","totalSize","logIdbError","currentSequenceKey","sequencesToSendKey","TX_DONE_TIMEOUT_MS","armTxDoneTimeout","txDone","ms","onTimeout","timer","defineObjectStores","sequencesStore","currentSequenceStore","createStore","v","withTimeout","upgrade","SessionReplayEventsIDBStore","maybeLogEmptyFiltered","emptyFilteredCount","consecutiveFailures","hasTriggeredFallback","getSequencesToSend","errorLogged","sequences","tx","recordFailure","cancelTimeout","cursor","store","openCursor","sequenceId","continue","recordSuccess","storeCurrentSequence","currentSequenceData","tabId","_tabId","__rest","addEventToCurrentSequence","sequenceEvents","ownedSequence","eventsToSend","storeSendingEvents","cleanUpSessionEventsStore","_sessionId","onPersistentFailure","consecutiveFailureThreshold","dbSuffix","randomUUID","generateUUID","getCurrentSequenceEvents","allEvents","InMemoryEventsStore","finalizedSequences","resetCurrentSequence","addSequence","buffered","sequenceReturn","createEventsManager","trackDestinationWorkerScript","shouldSend","maxSingleEventSize","trackDestination","getMemoryStore","lastKnownDeviceId","usingIdbStore","idb","new","seq","beaconBuffer","beaconWindowStart","advanceBeaconWindow","upToAbsoluteIdx","trimCount","rawEvents","sizedEvents","oversized","sendCurrentSequenceEvents","snapshotAbsIdx","currentSequence","canSend","absIdx","sequenceToSend","sendStoredEvents","sequencesToSend","sequence","getBeaconEvents","dropPendingBeaconEvents","MultiEventManager","managers","managersMap","manager","opts","promises","rootDocument","finder","input","nodeType","Node","ELEMENT_NODE","defaults","root","idName","_name","className","_value","seedMinLength","optimizedMinLength","threshold","maxNumberOfTries","timeoutMs","rootNode","DOCUMENT_NODE","ownerDocument","findRootDocument","path","bottomUpSearch","optimized","optimize","limit","fallback","elapsedTime","getTime","maybe","classNames","any","nth","dispensableNth","nthChild","findUniquePath","parentElement","paths","combinations","candidate","query","penalty","acc","css","querySelectorAll","elementId","getAttribute","attrs","classList","parent","parentNode","child","firstChild","nextSibling","notEmpty","b","counter","visited","newPath","newPathKey","same","clickNonBatcher","clickEvents","evt","clickBatcher","reduced","prev","curr","x","y","hour","k","ClickHandler","scrollWatcher","createHook","deviceIdFn","mirror","performanceOptions","Click","innerHeight","innerWidth","getNode","currentScrollX","currentScrollY","viewportHeight","viewportWidth","getViewportHeight","documentElement","clientHeight","getViewportWidth","clientWidth","BeaconTransport","sendXhr","xhr","XMLHttpRequest","setRequestHeader","basePageUrl","ScrollWatcher","transport","hook","update","scrollX","scrollY","maxScrollX","_maxScrollX","maxScrollY","_maxScrollY","maxScrollWidth","_maxScrollWidth","maxScrollHeight","_maxScrollHeight","_currentScrollX","_currentScrollY","width","height","SessionIdentifiers","sessionReplayId","generateSessionReplayId","REPLAY_START_TIME_TTL_MS","buildKeyPrefix","buildKey","getLocalStorage","targetingIDBStore","dbs","openOrCreateDB","getTargetingMatchForSession","sessionIdStr","targetingMatchForSession","targetingMatch","storeTargetingMatchForSession","lastUpdated","clearStoreOfOldSessions","currentSessionId","currentSessionIdStr","allTargetingMatchObjs","targetingMatchObj","amountOfTimeSinceSession","PRIME32_1","PRIME32_2","PRIME32_3","PRIME32_5","rotl32","imul","readU32","xxHash32","seed","toUTF8Bytes","len","h32","v1","v2","v3","v4","PATCH_MARKER","urlChangeSubscriptionsByScope","WeakMap","subscribeToUrlChanges","onUrlChange","enablePolling","pollingInterval","getHref","lastHref","setInterval","clearInterval","subscriptionState","callbacks","createHistoryMethodPatch","originalMethod","patchedMethod","history","pushState","Reflect","replaceState","onPopStateOrHashChange","listenersAttached","state","createUrlTrackingPlugin","observer","cb","pluginOptions","lastTrackedUrl","emitUrlChange","currentTitle","title","createUrlChangeEvent","CrossOriginIframeCoordinator","pendingLoadListeners","mutationObserver","disconnect","sendToAllIframes","MutationObserver","mutations","mutation","addedNodes","HTMLIFrameElement","sendToIframeAfterLoad","Element","iframe","removedNodes","observe","childList","subtree","stop","sendStart","sendToIframe","contentWindow","SessionReplay","recordCancelCallback","eventCount","sessionTargetingMatch","trcDiagnosticSessionId","pageLeaveFns","suppressedSendCount","hasEmittedGateDecision","recordFunction","recordEventsInFlight","pendingEmitEvents","currentPageUrl","recordEventsPendingShouldLogMetadata","urlChangeCleanup","crossOriginIframeCoordinator","crossOriginParentSignalCleanup","latestUrlChangeTargetingEvaluationId","teardownEventListeners","teardown","blurListener","focusListener","pageLeaveListener","sendEvents","takeFullSnapshot","recordEvents","eventCompressor","evaluateTargetingAndCapture","targetingParams","isInit","forceRestart","forceTargetingReevaluation","incrementDiagnostic","identifiers","recordDiagnosticEvent","hasIdentifiers","hasSessionId","hasConfig","hasDeviceId","getDeviceId","lastTargetingParams","urlChangeEvaluationId","eventForTargeting","event_type","page","pageForTargeting","evalStart","evaluateTargeting","evaluateTargetingPackage","import","params","flag","matched","targetingResult","variantKey","knownError","evaluateTargetingAndStore","recordDiagnosticHistogram","evaluationId","latestEvaluationId","hasEvent","userPropertyKeys","initialize","addCustomRRWebEvent","eventName","addStorageInfo","debugInfo","METADATA","storageSizeData","addCustomEvent","stopRecordingEvents","networkObservers","typedError","_init","setupUrlChangeListener","alreadyMatched","isBelowMinSessionDuration","sessionStartTime","getCurrentPageForTargeting","getNavigationType","performance","getEntriesByType","navEntries","prefix","stale","parsed","pruneStaleReplayStartTimes","getOrInitReplayStartTime","joinedConfigGenerator","createSessionReplayJoinedConfigGenerator","setMetadata","default","scrollHook","clickHandler","compressionWorkerScript","compressionScript","trackDestinationScript","rrwebEventManager","batch","interactionEventManager","trackEveryNms","initializeNetworkObservers","branded","scriptUrl","backgroundCaptureInstance","onBackgroundCapture","backgroundCaptureData","resolvedUrl","amplitudeBackgroundCapture","enableBackgroundCapture","hasTargetingConfig","shouldOptOut","navigationType","needsUrlTracking","setSessionId","asyncSetSessionId","previousSessionId","currentDeviceId","lastShouldRecordDecision","isSessionChange","to","deviceIdChanged","deviceIdForReplayId","startTime","setReplayStartTime","removeReplayStartTime","getSessionReplayProperties","shouldRecord","getShouldRecord","eventProperties","appHash","GET_SR_PROPS","sessionIdToSend","minMs","elapsedMs","REPLAY_GATE_DECISION","shouldSendStoredEvents","identityStoreOptOut","enriched","recordTrcDecisionDiagnostic","TARGETING_DECISION","getBlockSelectors","getMaskTextSelectors","getRecordingPlugins","plugins","urlTrackingPlugin","getRecordConsolePlugin","levels","getRecordFunction","shouldLogMetadata","_recordEvents","pendingArgs","networkLoggingConfig","network","trackUrl","ignoredUrls","FETCH_REQUEST","hooks","mouseInteraction","interaction","scroll","crossOriginIframesEnabled","coordinateChildren","childMode","isInIframe","parentFrame","onStart","onStop","listenForParentSignals","_recordEventsInChildMode","buildRRWebRecordOptions","Meta","recordCrossOriginIframes","DEBUG_INFO","emit","errorLogPrefix","inlineStylesheet","maskAllInputs","maskTextClass","blockClass","maskInputFn","maskTextFn","maskTextSelector","checkoutEveryNms","recordCanvas","slimDOMOptions","script","comment","headFavicon","headWhitespace","headMetaDescKeywords","headMetaSocial","headMetaRobots","headMetaHttpEquiv","headMetaAuthorship","headMetaVerification","errorHandler","_external_","getSessionId","shutdown","mapSDKType","sdkType","replaySDKVersion","standaloneSDKVersion","hashValue","replaySDKType","standaloneSDKType","NetworkObservers","NetworkObserversClass","sessionReplay","createInstance"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-min.js","sources":["../../../analytics-core/lib/esm/types/event/event.js","../../../analytics-core/lib/esm/types/constants.js","../../../analytics-core/lib/esm/types/status.js","../../../analytics-core/lib/esm/global-scope.js","../../../analytics-core/lib/esm/types/loglevel.js","../../../analytics-core/lib/esm/utils/uuid.js","../../../analytics-core/lib/esm/utils/return-wrapper.js","../../../analytics-core/lib/esm/logger.js","../../../analytics-core/lib/esm/config.js","../../../analytics-core/lib/esm/utils/debug.js","../../../../node_modules/.pnpm/@amplitude+analytics-connector@1.6.4/node_modules/@amplitude/analytics-connector/dist/analytics-connector.esm.js","../../../analytics-core/lib/esm/types/server-zone.js","../../../analytics-core/lib/esm/utils/sampling.js","../../../analytics-core/lib/esm/diagnostics/diagnostics-storage.js","../../../analytics-core/lib/esm/diagnostics/uncaught-sdk-errors.js","../../../analytics-core/lib/esm/diagnostics/diagnostics-client.js","../../../analytics-core/lib/esm/transports/base.js","../../../analytics-core/lib/esm/utils/status-code.js","../../../analytics-core/lib/esm/transports/fetch.js","../../../analytics-core/lib/esm/remote-config/remote-config-localstorage.js","../../../analytics-core/lib/esm/remote-config/remote-config.js","../../../analytics-core/lib/esm/messenger/constants.js","../../../analytics-core/lib/esm/messenger/base-window-messenger.js","../../../analytics-core/lib/esm/messenger/utils.js","../../../analytics-core/lib/esm/messenger/background-capture.js","../../../src/constants.ts","../../../src/logger.ts","../../../src/config/types.ts","../../../src/utils/server-url.ts","../../../src/helpers.ts","../../../src/utils/get-input-type.ts","../../../src/config/local-config.ts","../../../../node_modules/.pnpm/@amplitude+rrweb-types@2.0.0-alpha.40/node_modules/@amplitude/rrweb-types/dist/rrweb-types.js","../../../src/diagnostics.ts","../../../src/config/joined-config.ts","../../../src/events/merge-mutation-events.ts","../../../src/events/event-compressor.ts","../../../src/messages.ts","../../../src/version.ts","../../../src/track-destination.ts","../../../src/utils/gzip.ts","../../../src/events/base-events-store.ts","../../../src/utils/is-abort-error.ts","../../../src/events/events-idb-store.ts","../../../src/events/events-memory-store.ts","../../../src/events/events-manager.ts","../../../src/events/multi-manager.ts","../../../src/libs/finder.ts","../../../src/hooks/click.ts","../../../src/utils/rrweb.ts","../../../src/beacon-transport.ts","../../../src/hooks/scroll.ts","../../../src/identifiers.ts","../../../src/replay-start-time-store.ts","../../../src/targeting/targeting-idb-store.ts","../../../src/sampling.ts","../../../src/plugins/url-tracking-plugin.ts","../../../src/cross-origin-iframes.ts","../../../src/session-replay.ts","../../../src/targeting/targeting-manager.ts","../../../analytics-core/lib/esm/analytics-connector.js","../../../src/session-replay-factory.ts","../../../src/index.ts"],"sourcesContent":["export var IdentifyOperation;\n(function (IdentifyOperation) {\n // Base Operations to set values\n IdentifyOperation[\"SET\"] = \"$set\";\n IdentifyOperation[\"SET_ONCE\"] = \"$setOnce\";\n // Operations around modifying existing values\n IdentifyOperation[\"ADD\"] = \"$add\";\n IdentifyOperation[\"APPEND\"] = \"$append\";\n IdentifyOperation[\"PREPEND\"] = \"$prepend\";\n IdentifyOperation[\"REMOVE\"] = \"$remove\";\n // Operations around appending values *if* they aren't present\n IdentifyOperation[\"PREINSERT\"] = \"$preInsert\";\n IdentifyOperation[\"POSTINSERT\"] = \"$postInsert\";\n // Operations around removing properties/values\n IdentifyOperation[\"UNSET\"] = \"$unset\";\n IdentifyOperation[\"CLEAR_ALL\"] = \"$clearAll\";\n})(IdentifyOperation || (IdentifyOperation = {}));\n/**\n * Strings that have special meaning when used as an event's type\n * and have different specifications.\n */\nexport var SpecialEventType;\n(function (SpecialEventType) {\n SpecialEventType[\"IDENTIFY\"] = \"$identify\";\n SpecialEventType[\"GROUP_IDENTIFY\"] = \"$groupidentify\";\n SpecialEventType[\"REVENUE\"] = \"revenue_amount\";\n})(SpecialEventType || (SpecialEventType = {}));\n//# sourceMappingURL=event.js.map","export var UNSET_VALUE = '-';\nexport var AMPLITUDE_PREFIX = 'AMP';\nexport var STORAGE_PREFIX = \"\".concat(AMPLITUDE_PREFIX, \"_unsent\");\nexport var DEFAULT_INSTANCE_NAME = '$default_instance';\nexport var AMPLITUDE_SERVER_URL = 'https://api2.amplitude.com/2/httpapi';\nexport var EU_AMPLITUDE_SERVER_URL = 'https://api.eu.amplitude.com/2/httpapi';\nexport var AMPLITUDE_BATCH_SERVER_URL = 'https://api2.amplitude.com/batch';\nexport var EU_AMPLITUDE_BATCH_SERVER_URL = 'https://api.eu.amplitude.com/batch';\n// Campaign constants\nexport var UTM_CAMPAIGN = 'utm_campaign';\nexport var UTM_CONTENT = 'utm_content';\nexport var UTM_ID = 'utm_id';\nexport var UTM_MEDIUM = 'utm_medium';\nexport var UTM_SOURCE = 'utm_source';\nexport var UTM_TERM = 'utm_term';\nexport var DCLID = 'dclid';\nexport var FBCLID = 'fbclid';\nexport var GBRAID = 'gbraid';\nexport var GCLID = 'gclid';\nexport var KO_CLICK_ID = 'ko_click_id';\nexport var LI_FAT_ID = 'li_fat_id';\nexport var MSCLKID = 'msclkid';\nexport var RDT_CID = 'rdt_cid';\nexport var TTCLID = 'ttclid';\nexport var TWCLID = 'twclid';\nexport var WBRAID = 'wbraid';\nexport var EMPTY_VALUE = 'EMPTY';\nexport var BASE_CAMPAIGN = {\n utm_campaign: undefined,\n utm_content: undefined,\n utm_id: undefined,\n utm_medium: undefined,\n utm_source: undefined,\n utm_term: undefined,\n referrer: undefined,\n referring_domain: undefined,\n dclid: undefined,\n gbraid: undefined,\n gclid: undefined,\n fbclid: undefined,\n ko_click_id: undefined,\n li_fat_id: undefined,\n msclkid: undefined,\n rdt_cid: undefined,\n ttclid: undefined,\n twclid: undefined,\n wbraid: undefined,\n};\nexport var MKTG = 'MKTG';\n// list of Network headers that are safe to capture\nexport var SAFE_HEADERS = [\n 'access-control-allow-origin',\n 'access-control-allow-credentials',\n 'access-control-expose-headers',\n 'access-control-max-age',\n 'access-control-allow-methods',\n 'access-control-allow-headers',\n 'accept-patch',\n 'accept-ranges',\n 'age',\n 'allow',\n 'alt-svc',\n 'cache-control',\n 'connection',\n 'content-disposition',\n 'content-encoding',\n 'content-language',\n 'content-length',\n 'content-location',\n 'content-md5',\n 'content-range',\n 'content-type',\n 'date',\n 'delta-base',\n 'etag',\n 'expires',\n 'im',\n 'last-modified',\n 'link',\n 'location',\n 'permanent',\n 'p3p',\n 'pragma',\n 'proxy-authenticate',\n 'public-key-pins',\n 'retry-after',\n 'server',\n 'status',\n 'strict-transport-security',\n 'trailer',\n 'transfer-encoding',\n 'tk',\n 'upgrade',\n 'vary',\n 'via',\n 'warning',\n 'www-authenticate',\n 'x-b3-traceid',\n 'x-frame-options',\n];\n// list of Network headers to never capture\nexport var FORBIDDEN_HEADERS = ['authorization', 'cookie', 'set-cookie'];\n//# sourceMappingURL=constants.js.map","/** The status of an event. */\nexport var Status;\n(function (Status) {\n /** The status could not be determined. */\n Status[\"Unknown\"] = \"unknown\";\n /** The event was skipped due to configuration or callbacks. */\n Status[\"Skipped\"] = \"skipped\";\n /** The event was sent successfully. */\n Status[\"Success\"] = \"success\";\n /** A user or device in the payload is currently rate limited and should try again later. */\n Status[\"RateLimit\"] = \"rate_limit\";\n /** The sent payload was too large to be processed. */\n Status[\"PayloadTooLarge\"] = \"payload_too_large\";\n /** The event could not be processed. */\n Status[\"Invalid\"] = \"invalid\";\n /** A server-side error ocurred during submission. */\n Status[\"Failed\"] = \"failed\";\n /** a server or client side error occuring when a request takes too long and is cancelled */\n Status[\"Timeout\"] = \"Timeout\";\n /** NodeJS runtime environment error.. E.g. disconnected from network */\n Status[\"SystemError\"] = \"SystemError\";\n})(Status || (Status = {}));\n//# sourceMappingURL=status.js.map","/* eslint-disable no-restricted-globals */\n/* Only file allowed to access to globalThis, window, self */\nexport var getGlobalScope = function () {\n // This should only be used for integrations with Amplitude that are not running in a browser environment\n // We need to specify the name of the global variable as a string to prevent it from being minified\n var ampIntegrationContextName = 'ampIntegrationContext';\n if (typeof globalThis !== 'undefined' && typeof globalThis[ampIntegrationContextName] !== 'undefined') {\n return globalThis[ampIntegrationContextName];\n }\n if (typeof globalThis !== 'undefined') {\n return globalThis;\n }\n if (typeof window !== 'undefined') {\n return window;\n }\n if (typeof self !== 'undefined') {\n return self;\n }\n if (typeof global !== 'undefined') {\n return global;\n }\n return undefined;\n};\n//# sourceMappingURL=global-scope.js.map","export var LogLevel;\n(function (LogLevel) {\n LogLevel[LogLevel[\"None\"] = 0] = \"None\";\n LogLevel[LogLevel[\"Error\"] = 1] = \"Error\";\n LogLevel[LogLevel[\"Warn\"] = 2] = \"Warn\";\n LogLevel[LogLevel[\"Verbose\"] = 3] = \"Verbose\";\n LogLevel[LogLevel[\"Debug\"] = 4] = \"Debug\";\n})(LogLevel || (LogLevel = {}));\n//# sourceMappingURL=loglevel.js.map","/**\n * Source: [jed's gist's comment]{@link https://gist.github.com/jed/982883?permalink_comment_id=3223002#gistcomment-3223002}.\n * Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,\n * where each x is replaced with a random hexadecimal digit from 0 to f, and\n * y is replaced with a random hexadecimal digit from 8 to b.\n * Used to generate UUIDs for deviceIds.\n * @private\n */\nimport { __read, __spreadArray } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nvar legacyUUID = function (a) {\n return a // if the placeholder was passed, return\n ? // a random number from 0 to 15\n (a ^ // unless b is 8,\n ((Math.random() * // in which case\n 16) >> // a random number from\n (a / 4))) // 8 to 11\n .toString(16) // in hexadecimal\n : // or otherwise a concatenated string:\n (String(1e7) + // 10000000 +\n String(-1e3) + // -1000 +\n String(-4e3) + // -4000 +\n String(-8e3) + // -80000000 +\n String(-1e11)) // -100000000000,\n .replace(\n // replacing\n /[018]/g, // zeroes, ones, and eights with\n UUID);\n};\nvar hex = __spreadArray([], __read(Array(256).keys()), false).map(function (index) { return index.toString(16).padStart(2, '0'); });\nexport var UUID = function (a) {\n var _a;\n var globalScope = getGlobalScope();\n /* istanbul ignore next */\n if (!((_a = globalScope === null || globalScope === void 0 ? void 0 : globalScope.crypto) === null || _a === void 0 ? void 0 : _a.getRandomValues)) {\n // Fallback to legacy UUID generation if crypto is not available\n return legacyUUID(a);\n }\n var r = globalScope.crypto.getRandomValues(new Uint8Array(16));\n r[6] = (r[6] & 0x0f) | 0x40;\n r[8] = (r[8] & 0x3f) | 0x80;\n return __spreadArray([], __read(r.entries()), false).map(function (_a) {\n var _b = __read(_a, 2), index = _b[0], int = _b[1];\n return ([4, 6, 8, 10].includes(index) ? \"-\".concat(hex[int]) : hex[int]);\n }).join('');\n};\n//# sourceMappingURL=uuid.js.map","export var returnWrapper = function (awaitable) { return ({\n promise: awaitable || Promise.resolve(),\n}); };\n//# sourceMappingURL=return-wrapper.js.map","import { LogLevel } from './types/loglevel';\nvar PREFIX = 'Amplitude Logger ';\nvar Logger = /** @class */ (function () {\n function Logger() {\n this.logLevel = LogLevel.None;\n }\n Logger.prototype.disable = function () {\n this.logLevel = LogLevel.None;\n };\n Logger.prototype.enable = function (logLevel) {\n if (logLevel === void 0) { logLevel = LogLevel.Warn; }\n this.logLevel = logLevel;\n };\n Logger.prototype.log = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Verbose) {\n return;\n }\n console.log(\"\".concat(PREFIX, \"[Log]: \").concat(args.join(' ')));\n };\n Logger.prototype.warn = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Warn) {\n return;\n }\n console.warn(\"\".concat(PREFIX, \"[Warn]: \").concat(args.join(' ')));\n };\n Logger.prototype.error = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Error) {\n return;\n }\n console.error(\"\".concat(PREFIX, \"[Error]: \").concat(args.join(' ')));\n };\n Logger.prototype.debug = function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n if (this.logLevel < LogLevel.Debug) {\n return;\n }\n // console.debug output is hidden by default in chrome\n console.log(\"\".concat(PREFIX, \"[Debug]: \").concat(args.join(' ')));\n };\n return Logger;\n}());\nexport { Logger };\n//# sourceMappingURL=logger.js.map","import { AMPLITUDE_SERVER_URL, AMPLITUDE_BATCH_SERVER_URL, EU_AMPLITUDE_SERVER_URL, EU_AMPLITUDE_BATCH_SERVER_URL, DEFAULT_INSTANCE_NAME, } from './types/constants';\nimport { Logger } from './logger';\nimport { LogLevel } from './types/loglevel';\nexport var getDefaultConfig = function () { return ({\n flushMaxRetries: 12,\n flushQueueSize: 200,\n flushIntervalMillis: 10000,\n instanceName: DEFAULT_INSTANCE_NAME,\n logLevel: LogLevel.Warn,\n loggerProvider: new Logger(),\n offline: false,\n optOut: false,\n serverUrl: AMPLITUDE_SERVER_URL,\n serverZone: 'US',\n useBatch: false,\n}); };\nvar Config = /** @class */ (function () {\n function Config(options) {\n var _a, _b, _c, _d;\n this._optOut = false;\n var defaultConfig = getDefaultConfig();\n this.apiKey = options.apiKey;\n this.flushIntervalMillis = (_a = options.flushIntervalMillis) !== null && _a !== void 0 ? _a : defaultConfig.flushIntervalMillis;\n this.flushMaxRetries = options.flushMaxRetries || defaultConfig.flushMaxRetries;\n this.flushQueueSize = options.flushQueueSize || defaultConfig.flushQueueSize;\n this.instanceName = options.instanceName || defaultConfig.instanceName;\n this.loggerProvider = options.loggerProvider || defaultConfig.loggerProvider;\n this.logLevel = (_b = options.logLevel) !== null && _b !== void 0 ? _b : defaultConfig.logLevel;\n this.minIdLength = options.minIdLength;\n this.plan = options.plan;\n this.ingestionMetadata = options.ingestionMetadata;\n this.offline = options.offline !== undefined ? options.offline : defaultConfig.offline;\n this.optOut = (_c = options.optOut) !== null && _c !== void 0 ? _c : defaultConfig.optOut;\n this.serverUrl = options.serverUrl;\n this.serverZone = options.serverZone || defaultConfig.serverZone;\n this.storageProvider = options.storageProvider;\n this.transportProvider = options.transportProvider;\n this.useBatch = (_d = options.useBatch) !== null && _d !== void 0 ? _d : defaultConfig.useBatch;\n this.loggerProvider.enable(this.logLevel);\n var serverConfig = createServerConfig(options.serverUrl, options.serverZone, options.useBatch);\n this.serverZone = serverConfig.serverZone;\n this.serverUrl = serverConfig.serverUrl;\n }\n Object.defineProperty(Config.prototype, \"optOut\", {\n get: function () {\n return this._optOut;\n },\n set: function (optOut) {\n this._optOut = optOut;\n },\n enumerable: false,\n configurable: true\n });\n return Config;\n}());\nexport { Config };\nexport var getServerUrl = function (serverZone, useBatch) {\n if (serverZone === 'EU') {\n return useBatch ? EU_AMPLITUDE_BATCH_SERVER_URL : EU_AMPLITUDE_SERVER_URL;\n }\n return useBatch ? AMPLITUDE_BATCH_SERVER_URL : AMPLITUDE_SERVER_URL;\n};\nexport var createServerConfig = function (serverUrl, serverZone, useBatch) {\n if (serverUrl === void 0) { serverUrl = ''; }\n if (serverZone === void 0) { serverZone = getDefaultConfig().serverZone; }\n if (useBatch === void 0) { useBatch = getDefaultConfig().useBatch; }\n if (serverUrl) {\n return { serverUrl: serverUrl, serverZone: undefined };\n }\n var _serverZone = ['US', 'EU'].includes(serverZone) ? serverZone : getDefaultConfig().serverZone;\n return {\n serverZone: _serverZone,\n serverUrl: getServerUrl(_serverZone, useBatch),\n };\n};\nvar RequestMetadata = /** @class */ (function () {\n function RequestMetadata() {\n this.sdk = {\n metrics: {\n histogram: {},\n },\n };\n }\n RequestMetadata.prototype.recordHistogram = function (key, value) {\n this.sdk.metrics.histogram[key] = value;\n };\n return RequestMetadata;\n}());\nexport { RequestMetadata };\nvar HistogramOptions = /** @class */ (function () {\n function HistogramOptions() {\n }\n return HistogramOptions;\n}());\n//# sourceMappingURL=config.js.map","import { __assign, __values } from \"tslib\";\nimport { LogLevel } from '../types/loglevel';\nexport var getStacktrace = function (ignoreDepth) {\n if (ignoreDepth === void 0) { ignoreDepth = 0; }\n var trace = new Error().stack || '';\n return trace\n .split('\\n')\n .slice(2 + ignoreDepth)\n .map(function (text) { return text.trim(); });\n};\n// This hook makes sure we always get the latest logger and logLevel.\nexport var getClientLogConfig = function (client) { return function () {\n var _a = __assign({}, client.config), logger = _a.loggerProvider, logLevel = _a.logLevel;\n return {\n logger: logger,\n logLevel: logLevel,\n };\n}; };\n// This is a convenient function to get the attribute from object with string path, similar to lodash '#get'.\nexport var getValueByStringPath = function (obj, path) {\n var e_1, _a;\n path = path.replace(/\\[(\\w+)\\]/g, '.$1'); // convert indexes to properties\n path = path.replace(/^\\./, ''); // strip a leading dot\n try {\n for (var _b = __values(path.split('.')), _c = _b.next(); !_c.done; _c = _b.next()) {\n var attr = _c.value;\n if (attr in obj) {\n obj = obj[attr];\n }\n else {\n return;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (_c && !_c.done && (_a = _b.return)) _a.call(_b);\n }\n finally { if (e_1) throw e_1.error; }\n }\n return obj;\n};\nexport var getClientStates = function (client, paths) { return function () {\n var e_2, _a;\n var res = {};\n try {\n for (var paths_1 = __values(paths), paths_1_1 = paths_1.next(); !paths_1_1.done; paths_1_1 = paths_1.next()) {\n var path = paths_1_1.value;\n res[path] = getValueByStringPath(client, path);\n }\n }\n catch (e_2_1) { e_2 = { error: e_2_1 }; }\n finally {\n try {\n if (paths_1_1 && !paths_1_1.done && (_a = paths_1.return)) _a.call(paths_1);\n }\n finally { if (e_2) throw e_2.error; }\n }\n return res;\n}; };\nexport var debugWrapper = function (fn, fnName, getLogConfig, getStates, fnContext) {\n if (fnContext === void 0) { fnContext = null; }\n return function () {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n var _a = getLogConfig(), logger = _a.logger, logLevel = _a.logLevel;\n // return early if possible to reduce overhead\n if ((logLevel && logLevel < LogLevel.Debug) || !logLevel || !logger) {\n return fn.apply(fnContext, args);\n }\n var debugContext = {\n type: 'invoke public method',\n name: fnName,\n args: args,\n stacktrace: getStacktrace(1),\n time: {\n start: new Date().toISOString(),\n },\n states: {},\n };\n if (getStates && debugContext.states) {\n debugContext.states.before = getStates();\n }\n var result = fn.apply(fnContext, args);\n if (result && result.promise) {\n // if result is a promise, add the callback\n result.promise.then(function () {\n if (getStates && debugContext.states) {\n debugContext.states.after = getStates();\n }\n if (debugContext.time) {\n debugContext.time.end = new Date().toISOString();\n }\n logger.debug(JSON.stringify(debugContext, null, 2));\n });\n }\n else {\n if (getStates && debugContext.states) {\n debugContext.states.after = getStates();\n }\n if (debugContext.time) {\n debugContext.time.end = new Date().toISOString();\n }\n logger.debug(JSON.stringify(debugContext, null, 2));\n }\n return result;\n };\n};\n//# sourceMappingURL=debug.js.map","var ApplicationContextProviderImpl = /** @class */ (function () {\n function ApplicationContextProviderImpl() {\n }\n ApplicationContextProviderImpl.prototype.getApplicationContext = function () {\n return {\n versionName: this.versionName,\n language: getLanguage(),\n platform: 'Web',\n os: undefined,\n deviceModel: undefined,\n };\n };\n return ApplicationContextProviderImpl;\n}());\nvar getLanguage = function () {\n return ((typeof navigator !== 'undefined' &&\n ((navigator.languages && navigator.languages[0]) ||\n navigator.language)) ||\n '');\n};\n\nvar EventBridgeImpl = /** @class */ (function () {\n function EventBridgeImpl() {\n this.queue = [];\n }\n EventBridgeImpl.prototype.logEvent = function (event) {\n if (!this.receiver) {\n if (this.queue.length < 512) {\n this.queue.push(event);\n }\n }\n else {\n this.receiver(event);\n }\n };\n EventBridgeImpl.prototype.setEventReceiver = function (receiver) {\n this.receiver = receiver;\n if (this.queue.length > 0) {\n this.queue.forEach(function (event) {\n receiver(event);\n });\n this.queue = [];\n }\n };\n return EventBridgeImpl;\n}());\n\n/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\nvar __assign = function () {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n };\n return __assign.apply(this, arguments);\n};\nfunction __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator,\n m = s && o[s],\n i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return {\n value: o && o[i++],\n done: !o\n };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\nfunction __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o),\n r,\n ar = [],\n e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n } catch (error) {\n e = {\n error: error\n };\n } finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n } finally {\n if (e) throw e.error;\n }\n }\n return ar;\n}\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nvar isEqual = function (obj1, obj2) {\n var e_1, _a;\n var primitive = ['string', 'number', 'boolean', 'undefined'];\n var typeA = typeof obj1;\n var typeB = typeof obj2;\n if (typeA !== typeB) {\n return false;\n }\n try {\n for (var primitive_1 = __values(primitive), primitive_1_1 = primitive_1.next(); !primitive_1_1.done; primitive_1_1 = primitive_1.next()) {\n var p = primitive_1_1.value;\n if (p === typeA) {\n return obj1 === obj2;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (primitive_1_1 && !primitive_1_1.done && (_a = primitive_1.return)) _a.call(primitive_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n // check null\n if (obj1 == null && obj2 == null) {\n return true;\n }\n else if (obj1 == null || obj2 == null) {\n return false;\n }\n // if got here - objects\n if (obj1.length !== obj2.length) {\n return false;\n }\n //check if arrays\n var isArrayA = Array.isArray(obj1);\n var isArrayB = Array.isArray(obj2);\n if (isArrayA !== isArrayB) {\n return false;\n }\n if (isArrayA && isArrayB) {\n //arrays\n for (var i = 0; i < obj1.length; i++) {\n if (!isEqual(obj1[i], obj2[i])) {\n return false;\n }\n }\n }\n else {\n //objects\n var sorted1 = Object.keys(obj1).sort();\n var sorted2 = Object.keys(obj2).sort();\n if (!isEqual(sorted1, sorted2)) {\n return false;\n }\n //compare object values\n var result_1 = true;\n Object.keys(obj1).forEach(function (key) {\n if (!isEqual(obj1[key], obj2[key])) {\n result_1 = false;\n }\n });\n return result_1;\n }\n return true;\n};\n\nvar ID_OP_SET = '$set';\nvar ID_OP_UNSET = '$unset';\nvar ID_OP_CLEAR_ALL = '$clearAll';\n// Polyfill for Object.entries\nif (!Object.entries) {\n Object.entries = function (obj) {\n var ownProps = Object.keys(obj);\n var i = ownProps.length;\n var resArray = new Array(i);\n while (i--) {\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n }\n return resArray;\n };\n}\nvar IdentityStoreImpl = /** @class */ (function () {\n function IdentityStoreImpl() {\n this.identity = { userProperties: {} };\n this.listeners = new Set();\n }\n IdentityStoreImpl.prototype.editIdentity = function () {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n var self = this;\n var actingUserProperties = __assign({}, this.identity.userProperties);\n var actingIdentity = __assign(__assign({}, this.identity), { userProperties: actingUserProperties });\n return {\n setUserId: function (userId) {\n actingIdentity.userId = userId;\n return this;\n },\n setDeviceId: function (deviceId) {\n actingIdentity.deviceId = deviceId;\n return this;\n },\n setUserProperties: function (userProperties) {\n actingIdentity.userProperties = userProperties;\n return this;\n },\n setOptOut: function (optOut) {\n actingIdentity.optOut = optOut;\n return this;\n },\n updateUserProperties: function (actions) {\n var e_1, _a, e_2, _b, e_3, _c;\n var actingProperties = actingIdentity.userProperties || {};\n try {\n for (var _d = __values(Object.entries(actions)), _e = _d.next(); !_e.done; _e = _d.next()) {\n var _f = __read(_e.value, 2), action = _f[0], properties = _f[1];\n switch (action) {\n case ID_OP_SET:\n try {\n for (var _g = (e_2 = void 0, __values(Object.entries(properties))), _h = _g.next(); !_h.done; _h = _g.next()) {\n var _j = __read(_h.value, 2), key = _j[0], value = _j[1];\n actingProperties[key] = value;\n }\n }\n catch (e_2_1) { e_2 = { error: e_2_1 }; }\n finally {\n try {\n if (_h && !_h.done && (_b = _g.return)) _b.call(_g);\n }\n finally { if (e_2) throw e_2.error; }\n }\n break;\n case ID_OP_UNSET:\n try {\n for (var _k = (e_3 = void 0, __values(Object.keys(properties))), _l = _k.next(); !_l.done; _l = _k.next()) {\n var key = _l.value;\n delete actingProperties[key];\n }\n }\n catch (e_3_1) { e_3 = { error: e_3_1 }; }\n finally {\n try {\n if (_l && !_l.done && (_c = _k.return)) _c.call(_k);\n }\n finally { if (e_3) throw e_3.error; }\n }\n break;\n case ID_OP_CLEAR_ALL:\n actingProperties = {};\n break;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (_e && !_e.done && (_a = _d.return)) _a.call(_d);\n }\n finally { if (e_1) throw e_1.error; }\n }\n actingIdentity.userProperties = actingProperties;\n return this;\n },\n commit: function () {\n self.setIdentity(actingIdentity);\n return this;\n },\n };\n };\n IdentityStoreImpl.prototype.getIdentity = function () {\n return __assign({}, this.identity);\n };\n IdentityStoreImpl.prototype.setIdentity = function (identity) {\n var originalIdentity = __assign({}, this.identity);\n this.identity = __assign({}, identity);\n if (!isEqual(originalIdentity, this.identity)) {\n this.listeners.forEach(function (listener) {\n listener(identity);\n });\n }\n };\n IdentityStoreImpl.prototype.addIdentityListener = function (listener) {\n this.listeners.add(listener);\n };\n IdentityStoreImpl.prototype.removeIdentityListener = function (listener) {\n this.listeners.delete(listener);\n };\n return IdentityStoreImpl;\n}());\n\nvar safeGlobal = typeof globalThis !== 'undefined'\n ? globalThis\n : typeof global !== 'undefined'\n ? global\n : self;\n\nvar AnalyticsConnector = /** @class */ (function () {\n function AnalyticsConnector() {\n this.identityStore = new IdentityStoreImpl();\n this.eventBridge = new EventBridgeImpl();\n this.applicationContextProvider = new ApplicationContextProviderImpl();\n }\n AnalyticsConnector.getInstance = function (instanceName) {\n if (!safeGlobal['analyticsConnectorInstances']) {\n safeGlobal['analyticsConnectorInstances'] = {};\n }\n if (!safeGlobal['analyticsConnectorInstances'][instanceName]) {\n safeGlobal['analyticsConnectorInstances'][instanceName] =\n new AnalyticsConnector();\n }\n return safeGlobal['analyticsConnectorInstances'][instanceName];\n };\n return AnalyticsConnector;\n}());\n\nexport { AnalyticsConnector };\n","/**\n * @deprecated use ServerZoneType instead\n */\nexport var ServerZone;\n(function (ServerZone) {\n ServerZone[\"US\"] = \"US\";\n ServerZone[\"EU\"] = \"EU\";\n /**\n * Add for session-replay-browser migration from analytics-type v1.x.\n */\n ServerZone[\"STAGING\"] = \"STAGING\";\n})(ServerZone || (ServerZone = {}));\n//# sourceMappingURL=server-zone.js.map","export var generateHashCode = function (str) {\n var hash = 0;\n if (str.length === 0)\n return hash;\n for (var i = 0; i < str.length; i++) {\n var chr = str.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0;\n }\n return hash;\n};\nexport var isTimestampInSample = function (timestamp, sampleRate) {\n var hashNumber = generateHashCode(timestamp.toString());\n var absHash = Math.abs(hashNumber);\n var absHashMultiply = absHash * 31;\n var mod = absHashMultiply % 1000000;\n return mod / 1000000 < sampleRate;\n};\n// TODO(xinyi): replace the temp one in diagnostics client after the fix\n// istanbul ignore next\nexport var isTimestampInSampleTemp = function (timestamp, sampleRate) {\n var hashNumber = generateHashCode(timestamp.toString());\n var absHash = Math.abs(hashNumber);\n var absHashMultiply = absHash * 31;\n var mod = absHashMultiply % 100000;\n return mod / 100000 < sampleRate;\n};\n//# sourceMappingURL=sampling.js.map","import { __awaiter, __generator, __read } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nvar MAX_PERSISTENT_STORAGE_EVENTS_COUNT = 10;\n// Database configuration\nvar DB_VERSION = 1;\n// Table names for different diagnostics types\nexport var TABLE_NAMES = {\n TAGS: 'tags',\n COUNTERS: 'counters',\n HISTOGRAMS: 'histograms',\n EVENTS: 'events',\n INTERNAL: 'internal', // New table for internal storage like flush timestamps\n};\n// Keys for internal storage table\nexport var INTERNAL_KEYS = {\n LAST_FLUSH_TIMESTAMP: 'last_flush_timestamp',\n};\n/**\n * Purpose-specific IndexedDB storage for diagnostics data\n * Provides optimized methods for each type of diagnostics data\n */\nvar DiagnosticsStorage = /** @class */ (function () {\n function DiagnosticsStorage(apiKey, logger) {\n this.dbPromise = null;\n this.logger = logger;\n this.dbName = \"AMP_diagnostics_\".concat(apiKey.substring(0, 10));\n }\n /**\n * Check if IndexedDB is supported in the current environment\n * @returns true if IndexedDB is available, false otherwise\n */\n DiagnosticsStorage.isSupported = function () {\n var _a;\n return ((_a = getGlobalScope()) === null || _a === void 0 ? void 0 : _a.indexedDB) !== undefined;\n };\n DiagnosticsStorage.prototype.getDB = function () {\n return __awaiter(this, void 0, void 0, function () {\n return __generator(this, function (_a) {\n if (!this.dbPromise) {\n this.dbPromise = this.openDB();\n }\n return [2 /*return*/, this.dbPromise];\n });\n });\n };\n DiagnosticsStorage.prototype.openDB = function () {\n var _this = this;\n return new Promise(function (resolve, reject) {\n var request = indexedDB.open(_this.dbName, DB_VERSION);\n request.onerror = function () {\n // Clear dbPromise when it rejects for the first time\n _this.dbPromise = null;\n reject(new Error('Failed to open IndexedDB'));\n };\n request.onsuccess = function () {\n var db = request.result;\n // Clear dbPromise when connection was on but went off later\n db.onclose = function () {\n _this.dbPromise = null;\n _this.logger.debug('DiagnosticsStorage: DB connection closed.');\n };\n db.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: A global database error occurred.', event);\n db.close();\n };\n resolve(db);\n };\n request.onupgradeneeded = function (event) {\n var db = event.target.result;\n _this.createTables(db);\n };\n });\n };\n DiagnosticsStorage.prototype.createTables = function (db) {\n // Create tags table\n if (!db.objectStoreNames.contains(TABLE_NAMES.TAGS)) {\n db.createObjectStore(TABLE_NAMES.TAGS, { keyPath: 'key' });\n }\n // Create counters table\n if (!db.objectStoreNames.contains(TABLE_NAMES.COUNTERS)) {\n db.createObjectStore(TABLE_NAMES.COUNTERS, { keyPath: 'key' });\n }\n // Create histograms table for storing histogram stats (count, min, max, sum)\n if (!db.objectStoreNames.contains(TABLE_NAMES.HISTOGRAMS)) {\n db.createObjectStore(TABLE_NAMES.HISTOGRAMS, {\n keyPath: 'key',\n });\n }\n // Create events table\n if (!db.objectStoreNames.contains(TABLE_NAMES.EVENTS)) {\n var eventsStore = db.createObjectStore(TABLE_NAMES.EVENTS, {\n keyPath: 'id',\n autoIncrement: true,\n });\n // Create index on time for chronological queries\n eventsStore.createIndex('time_idx', 'time', { unique: false });\n }\n // Create internal table for storing internal data like flush timestamps\n if (!db.objectStoreNames.contains(TABLE_NAMES.INTERNAL)) {\n db.createObjectStore(TABLE_NAMES.INTERNAL, { keyPath: 'key' });\n }\n };\n DiagnosticsStorage.prototype.setTags = function (tags) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_1, store_1, error_1;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (Object.entries(tags).length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_1 = db.transaction([TABLE_NAMES.TAGS], 'readwrite');\n store_1 = transaction_1.objectStore(TABLE_NAMES.TAGS);\n return [2 /*return*/, new Promise(function (resolve) {\n var entries = Object.entries(tags);\n transaction_1.oncomplete = function () {\n resolve();\n };\n transaction_1.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set tags', event);\n resolve();\n };\n entries.forEach(function (_a) {\n var _b = __read(_a, 2), key = _b[0], value = _b[1];\n var putRequest = store_1.put({ key: key, value: value });\n putRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set tag', key, value, event);\n };\n });\n })];\n case 2:\n error_1 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to set tags', error_1);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.incrementCounters = function (counters) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_2, store_2, error_2;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (Object.entries(counters).length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_2 = db.transaction([TABLE_NAMES.COUNTERS], 'readwrite');\n store_2 = transaction_2.objectStore(TABLE_NAMES.COUNTERS);\n return [2 /*return*/, new Promise(function (resolve) {\n var entries = Object.entries(counters);\n transaction_2.oncomplete = function () {\n resolve();\n };\n transaction_2.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to increment counters', event);\n resolve();\n };\n // Read existing values and update them\n entries.forEach(function (_a) {\n var _b = __read(_a, 2), key = _b[0], incrementValue = _b[1];\n var getRequest = store_2.get(key);\n getRequest.onsuccess = function () {\n var existingRecord = getRequest.result;\n /* istanbul ignore next */\n var existingValue = existingRecord ? existingRecord.value : 0;\n var putRequest = store_2.put({ key: key, value: existingValue + incrementValue });\n putRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to update counter', key, event);\n };\n };\n getRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to read existing counter', key, event);\n };\n });\n })];\n case 2:\n error_2 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to increment counters', error_2);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.setHistogramStats = function (histogramStats) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_3, store_3, error_3;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (Object.entries(histogramStats).length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_3 = db.transaction([TABLE_NAMES.HISTOGRAMS], 'readwrite');\n store_3 = transaction_3.objectStore(TABLE_NAMES.HISTOGRAMS);\n return [2 /*return*/, new Promise(function (resolve) {\n var entries = Object.entries(histogramStats);\n transaction_3.oncomplete = function () {\n resolve();\n };\n transaction_3.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', event);\n resolve();\n };\n // Read existing values and update them\n entries.forEach(function (_a) {\n var _b = __read(_a, 2), key = _b[0], newStats = _b[1];\n var getRequest = store_3.get(key);\n getRequest.onsuccess = function () {\n var existingRecord = getRequest.result;\n var updatedStats;\n /* istanbul ignore next */\n if (existingRecord) {\n // Accumulate with existing stats\n updatedStats = {\n key: key,\n count: existingRecord.count + newStats.count,\n min: Math.min(existingRecord.min, newStats.min),\n max: Math.max(existingRecord.max, newStats.max),\n sum: existingRecord.sum + newStats.sum,\n };\n }\n else {\n // Create new stats\n updatedStats = {\n key: key,\n count: newStats.count,\n min: newStats.min,\n max: newStats.max,\n sum: newStats.sum,\n };\n }\n var putRequest = store_3.put(updatedStats);\n putRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', key, event);\n };\n };\n getRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to read existing histogram stats', key, event);\n };\n });\n })];\n case 2:\n error_3 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', error_3);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.addEventRecords = function (events) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_4, store_4, error_4;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (events.length === 0) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_4 = db.transaction([TABLE_NAMES.EVENTS], 'readwrite');\n store_4 = transaction_4.objectStore(TABLE_NAMES.EVENTS);\n return [2 /*return*/, new Promise(function (resolve) {\n transaction_4.oncomplete = function () {\n resolve();\n };\n /* istanbul ignore next */\n transaction_4.onabort = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to add event records', event);\n resolve();\n };\n // First, check how many events are currently stored\n var countRequest = store_4.count();\n countRequest.onsuccess = function () {\n var currentCount = countRequest.result;\n // Calculate how many events we can add\n var availableSlots = Math.max(0, MAX_PERSISTENT_STORAGE_EVENTS_COUNT - currentCount);\n if (availableSlots < events.length) {\n _this.logger.debug(\"DiagnosticsStorage: Only added \".concat(availableSlots, \" of \").concat(events.length, \" events due to storage limit\"));\n }\n // Only add events up to the available slots (take the least recent ones)\n events.slice(0, availableSlots).forEach(function (event) {\n var request = store_4.add(event);\n request.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to add event record', event);\n };\n });\n };\n countRequest.onerror = function (event) {\n _this.logger.debug('DiagnosticsStorage: Failed to count existing events', event);\n };\n })];\n case 2:\n error_4 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to add event records', error_4);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.setInternal = function (key, value) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_5, store_5, error_5;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_5 = db.transaction([TABLE_NAMES.INTERNAL], 'readwrite');\n store_5 = transaction_5.objectStore(TABLE_NAMES.INTERNAL);\n return [2 /*return*/, new Promise(function (resolve, reject) {\n /* istanbul ignore next */\n transaction_5.onabort = function () { return reject(new Error('Failed to set internal value')); };\n var request = store_5.put({ key: key, value: value });\n request.onsuccess = function () { return resolve(); };\n /* istanbul ignore next */\n request.onerror = function () { return reject(new Error('Failed to set internal value')); };\n })];\n case 2:\n error_5 = _a.sent();\n /* istanbul ignore next */\n this.logger.debug('DiagnosticsStorage: Failed to set internal value', error_5);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.getInternal = function (key) {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction_6, store_6, error_6;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _a.sent();\n transaction_6 = db.transaction([TABLE_NAMES.INTERNAL], 'readonly');\n store_6 = transaction_6.objectStore(TABLE_NAMES.INTERNAL);\n return [2 /*return*/, new Promise(function (resolve, reject) {\n /* istanbul ignore next */\n transaction_6.onabort = function () { return reject(new Error('Failed to get internal value')); };\n var request = store_6.get(key);\n request.onsuccess = function () { return resolve(request.result); };\n /* istanbul ignore next */\n request.onerror = function () { return reject(new Error('Failed to get internal value')); };\n })];\n case 2:\n error_6 = _a.sent();\n this.logger.debug('DiagnosticsStorage: Failed to get internal value', error_6);\n return [2 /*return*/, undefined];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.getLastFlushTimestamp = function () {\n return __awaiter(this, void 0, void 0, function () {\n var record, error_7;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.getInternal(INTERNAL_KEYS.LAST_FLUSH_TIMESTAMP)];\n case 1:\n record = _a.sent();\n return [2 /*return*/, record ? parseInt(record.value, 10) : undefined];\n case 2:\n error_7 = _a.sent();\n /* istanbul ignore next */\n this.logger.debug('DiagnosticsStorage: Failed to get last flush timestamp', error_7);\n /* istanbul ignore next */\n return [2 /*return*/, undefined];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsStorage.prototype.setLastFlushTimestamp = function (timestamp) {\n return __awaiter(this, void 0, void 0, function () {\n var error_8;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n return [4 /*yield*/, this.setInternal(INTERNAL_KEYS.LAST_FLUSH_TIMESTAMP, timestamp.toString())];\n case 1:\n _a.sent();\n return [3 /*break*/, 3];\n case 2:\n error_8 = _a.sent();\n /* istanbul ignore next */\n this.logger.debug('DiagnosticsStorage: Failed to set last flush timestamp', error_8);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n /* istanbul ignore next */\n DiagnosticsStorage.prototype.clearTable = function (transaction, tableName) {\n return new Promise(function (resolve, reject) {\n var store = transaction.objectStore(tableName);\n var request = store.clear();\n request.onsuccess = function () { return resolve(); };\n request.onerror = function () { return reject(new Error(\"Failed to clear table \".concat(tableName))); };\n });\n };\n /* istanbul ignore next */\n DiagnosticsStorage.prototype.getAllAndClear = function () {\n return __awaiter(this, void 0, void 0, function () {\n var db, transaction, _a, tags, counters, histogramStats, events, error_9;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n _b.trys.push([0, 4, , 5]);\n return [4 /*yield*/, this.getDB()];\n case 1:\n db = _b.sent();\n transaction = db.transaction([TABLE_NAMES.TAGS, TABLE_NAMES.COUNTERS, TABLE_NAMES.HISTOGRAMS, TABLE_NAMES.EVENTS], 'readwrite');\n return [4 /*yield*/, Promise.all([\n this.getAllFromStore(transaction, TABLE_NAMES.TAGS),\n this.getAllFromStore(transaction, TABLE_NAMES.COUNTERS),\n this.getAllFromStore(transaction, TABLE_NAMES.HISTOGRAMS),\n this.getAllFromStore(transaction, TABLE_NAMES.EVENTS),\n ])];\n case 2:\n _a = __read.apply(void 0, [_b.sent(), 4]), tags = _a[0], counters = _a[1], histogramStats = _a[2], events = _a[3];\n // Clear all data in the same transaction\n return [4 /*yield*/, Promise.all([\n this.clearTable(transaction, TABLE_NAMES.COUNTERS),\n this.clearTable(transaction, TABLE_NAMES.HISTOGRAMS),\n this.clearTable(transaction, TABLE_NAMES.EVENTS),\n ])];\n case 3:\n // Clear all data in the same transaction\n _b.sent();\n return [2 /*return*/, { tags: tags, counters: counters, histogramStats: histogramStats, events: events }];\n case 4:\n error_9 = _b.sent();\n this.logger.debug('DiagnosticsStorage: Failed to get all and clear data', error_9);\n return [2 /*return*/, { tags: [], counters: [], histogramStats: [], events: [] }];\n case 5: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Helper method to get all records from a store within a transaction\n */\n /* istanbul ignore next */\n DiagnosticsStorage.prototype.getAllFromStore = function (transaction, tableName) {\n return new Promise(function (resolve, reject) {\n var store = transaction.objectStore(tableName);\n var request = store.getAll();\n request.onsuccess = function () { return resolve(request.result); };\n request.onerror = function () { return reject(new Error(\"Failed to get all from \".concat(tableName))); };\n });\n };\n return DiagnosticsStorage;\n}());\nexport { DiagnosticsStorage };\n//# sourceMappingURL=diagnostics-storage.js.map","import { __assign, __values } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nexport var GLOBAL_KEY = '__AMPLITUDE_SCRIPT_URL__';\nexport var EVENT_NAME_ERROR_UNCAUGHT = 'sdk.error.uncaught';\nvar getNormalizedScriptUrls = function () {\n var scope = getGlobalScope();\n /* istanbul ignore next */\n if (!scope) {\n return [];\n }\n var value = scope[GLOBAL_KEY];\n if (Array.isArray(value)) {\n return value;\n }\n /* istanbul ignore next - legacy single URL stored as string */\n if (typeof value === 'string') {\n return [value];\n }\n return [];\n};\nvar addNormalizedScriptUrl = function (url) {\n var scope = getGlobalScope();\n /* istanbul ignore next */\n if (!scope) {\n return;\n }\n var urls = getNormalizedScriptUrls();\n if (!urls.includes(url)) {\n urls.push(url);\n scope[GLOBAL_KEY] = urls;\n }\n};\nexport var registerSdkLoaderMetadata = function (metadata) {\n if (metadata.scriptUrl) {\n var normalized = normalizeUrl(metadata.scriptUrl);\n if (normalized) {\n addNormalizedScriptUrl(normalized);\n }\n }\n};\nexport var enableSdkErrorListeners = function (client) {\n var scope = getGlobalScope();\n if (!scope || typeof scope.addEventListener !== 'function') {\n return;\n }\n var handleError = function (event) {\n var error = event.error instanceof Error ? event.error : undefined;\n var stack = error === null || error === void 0 ? void 0 : error.stack;\n var match = detectSdkOrigin({ filename: event.filename, stack: stack });\n if (!match) {\n return;\n }\n capture({\n type: 'error',\n message: event.message,\n stack: stack,\n filename: event.filename,\n errorName: error === null || error === void 0 ? void 0 : error.name,\n metadata: {\n colno: event.colno,\n lineno: event.lineno,\n isTrusted: event.isTrusted,\n matchReason: match,\n },\n });\n };\n var handleRejection = function (event) {\n var _a;\n var error = event.reason instanceof Error ? event.reason : undefined;\n var stack = error === null || error === void 0 ? void 0 : error.stack;\n var filename = extractFilenameFromStack(stack);\n var match = detectSdkOrigin({ filename: filename, stack: stack });\n if (!match) {\n return;\n }\n /* istanbul ignore next */\n capture({\n type: 'unhandledrejection',\n message: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : stringifyReason(event.reason),\n stack: stack,\n filename: filename,\n errorName: error === null || error === void 0 ? void 0 : error.name,\n metadata: {\n isTrusted: event.isTrusted,\n matchReason: match,\n },\n });\n };\n var capture = function (context) {\n client.recordEvent(EVENT_NAME_ERROR_UNCAUGHT, __assign({ type: context.type, message: context.message, filename: context.filename, error_name: context.errorName, stack: context.stack }, context.metadata));\n };\n scope.addEventListener('error', handleError, true);\n scope.addEventListener('unhandledrejection', handleRejection, true);\n};\nvar detectSdkOrigin = function (payload) {\n var e_1, _a;\n var normalizedScriptUrls = getNormalizedScriptUrls();\n if (normalizedScriptUrls.length === 0) {\n return undefined;\n }\n try {\n for (var normalizedScriptUrls_1 = __values(normalizedScriptUrls), normalizedScriptUrls_1_1 = normalizedScriptUrls_1.next(); !normalizedScriptUrls_1_1.done; normalizedScriptUrls_1_1 = normalizedScriptUrls_1.next()) {\n var normalizedScriptUrl = normalizedScriptUrls_1_1.value;\n if (payload.filename && payload.filename.includes(normalizedScriptUrl)) {\n return 'filename';\n }\n if (payload.stack && payload.stack.includes(normalizedScriptUrl)) {\n return 'stack';\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (normalizedScriptUrls_1_1 && !normalizedScriptUrls_1_1.done && (_a = normalizedScriptUrls_1.return)) _a.call(normalizedScriptUrls_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n return undefined;\n};\nvar normalizeUrl = function (value) {\n var _a, _b;\n try {\n /* istanbul ignore next */\n var url = new URL(value, (_b = (_a = getGlobalScope()) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.origin);\n return url.origin + url.pathname;\n }\n catch (_c) {\n return undefined;\n }\n};\nvar extractFilenameFromStack = function (stack) {\n if (!stack) {\n return undefined;\n }\n var match = stack.match(/(https?:\\/\\/\\S+?)(?=[)\\s]|$)/);\n /* istanbul ignore next */\n return match ? match[1] : undefined;\n};\n/* istanbul ignore next */\nvar stringifyReason = function (reason) {\n if (typeof reason === 'string') {\n return reason;\n }\n try {\n return JSON.stringify(reason);\n }\n catch (_a) {\n return '[object Object]';\n }\n};\n//# sourceMappingURL=uncaught-sdk-errors.js.map","import { __assign, __awaiter, __generator, __read, __spreadArray } from \"tslib\";\nimport { DiagnosticsStorage } from './diagnostics-storage';\nimport { getGlobalScope } from '../global-scope';\nimport { isTimestampInSampleTemp } from '../utils/sampling';\nimport { enableSdkErrorListeners } from './uncaught-sdk-errors';\nexport var SAVE_INTERVAL_MS = 1000; // 1 second\nexport var FLUSH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\nexport var DIAGNOSTICS_US_SERVER_URL = 'https://diagnostics.prod.us-west-2.amplitude.com/v1/capture';\nexport var DIAGNOSTICS_EU_SERVER_URL = 'https://diagnostics.prod.eu-central-1.amplitude.com/v1/capture';\n// In-memory storage limits\nexport var MAX_MEMORY_STORAGE_COUNT = 10000; // for tags, counters, histograms separately\nexport var MAX_MEMORY_STORAGE_EVENTS_COUNT = 10;\nvar DiagnosticsClient = /** @class */ (function () {\n function DiagnosticsClient(apiKey, logger, serverZone, options) {\n if (serverZone === void 0) { serverZone = 'US'; }\n // In-memory storages\n this.inMemoryTags = {};\n this.inMemoryCounters = {};\n this.inMemoryHistograms = {};\n this.inMemoryEvents = [];\n // Timer for 1-second persistence\n this.saveTimer = null;\n // Timer for flush interval\n this.flushTimer = null;\n this.apiKey = apiKey;\n this.logger = logger;\n this.serverUrl = serverZone === 'US' ? DIAGNOSTICS_US_SERVER_URL : DIAGNOSTICS_EU_SERVER_URL;\n this.logger.debug('DiagnosticsClient: Initializing with options', JSON.stringify(options, null, 2));\n // Diagnostics is enabled by default with sample rate of 0 (no sampling)\n this.config = __assign({ enabled: true, sampleRate: 0 }, options);\n this.startTimestamp = Date.now();\n this.shouldTrack = isTimestampInSampleTemp(this.startTimestamp, this.config.sampleRate) && this.config.enabled;\n if (DiagnosticsStorage.isSupported()) {\n this.storage = new DiagnosticsStorage(apiKey, logger);\n }\n else {\n this.logger.debug('DiagnosticsClient: IndexedDB is not supported');\n }\n void this.initializeFlushInterval();\n // Track internal diagnostics metrics for sampling\n if (this.shouldTrack) {\n this.increment('sdk.diagnostics.sampled.in.and.enabled');\n enableSdkErrorListeners(this);\n }\n }\n /**\n * Check if storage is available and tracking is enabled\n */\n DiagnosticsClient.prototype.isStorageAndTrackEnabled = function () {\n return Boolean(this.storage) && Boolean(this.shouldTrack);\n };\n DiagnosticsClient.prototype.setTag = function (name, value) {\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (Object.keys(this.inMemoryTags).length >= MAX_MEMORY_STORAGE_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return setTags as reaching memory limit');\n return;\n }\n this.inMemoryTags[name] = value;\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.increment = function (name, size) {\n if (size === void 0) { size = 1; }\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (Object.keys(this.inMemoryCounters).length >= MAX_MEMORY_STORAGE_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return increment as reaching memory limit');\n return;\n }\n this.inMemoryCounters[name] = (this.inMemoryCounters[name] || 0) + size;\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.recordHistogram = function (name, value) {\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (Object.keys(this.inMemoryHistograms).length >= MAX_MEMORY_STORAGE_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return recordHistogram as reaching memory limit');\n return;\n }\n var existing = this.inMemoryHistograms[name];\n if (existing) {\n // Update existing stats incrementally\n existing.count += 1;\n existing.min = Math.min(existing.min, value);\n existing.max = Math.max(existing.max, value);\n existing.sum += value;\n }\n else {\n // Create new stats\n this.inMemoryHistograms[name] = {\n count: 1,\n min: value,\n max: value,\n sum: value,\n };\n }\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.recordEvent = function (name, properties) {\n if (!this.isStorageAndTrackEnabled()) {\n return;\n }\n if (this.inMemoryEvents.length >= MAX_MEMORY_STORAGE_EVENTS_COUNT) {\n this.logger.debug('DiagnosticsClient: Early return recordEvent as reaching memory limit');\n return;\n }\n this.inMemoryEvents.push({\n event_name: name,\n time: Date.now(),\n event_properties: properties,\n });\n this.startTimersIfNeeded();\n };\n DiagnosticsClient.prototype.startTimersIfNeeded = function () {\n var _this = this;\n if (!this.saveTimer) {\n this.saveTimer = setTimeout(function () {\n _this.saveAllDataToStorage()\n .catch(function (error) {\n _this.logger.debug('DiagnosticsClient: Failed to save all data to storage', error);\n })\n .finally(function () {\n _this.saveTimer = null;\n });\n }, SAVE_INTERVAL_MS);\n }\n if (!this.flushTimer) {\n this.flushTimer = setTimeout(function () {\n _this._flush()\n .catch(function (error) {\n _this.logger.debug('DiagnosticsClient: Failed to flush', error);\n })\n .finally(function () {\n _this.flushTimer = null;\n });\n }, FLUSH_INTERVAL_MS);\n }\n };\n DiagnosticsClient.prototype.saveAllDataToStorage = function () {\n return __awaiter(this, void 0, void 0, function () {\n var tagsToSave, countersToSave, histogramsToSave, eventsToSave;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n if (!this.storage) {\n return [2 /*return*/];\n }\n tagsToSave = __assign({}, this.inMemoryTags);\n countersToSave = __assign({}, this.inMemoryCounters);\n histogramsToSave = __assign({}, this.inMemoryHistograms);\n eventsToSave = __spreadArray([], __read(this.inMemoryEvents), false);\n this.inMemoryEvents = [];\n this.inMemoryTags = {};\n this.inMemoryCounters = {};\n this.inMemoryHistograms = {};\n return [4 /*yield*/, Promise.all([\n this.storage.setTags(tagsToSave),\n this.storage.incrementCounters(countersToSave),\n this.storage.setHistogramStats(histogramsToSave),\n this.storage.addEventRecords(eventsToSave),\n ])];\n case 1:\n _a.sent();\n return [2 /*return*/];\n }\n });\n });\n };\n DiagnosticsClient.prototype._flush = function () {\n return __awaiter(this, void 0, void 0, function () {\n var _a, tagRecords, counterRecords, histogramStatsRecords, eventRecords, tags, counters, histogram, events, payload;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n if (!this.storage) {\n return [2 /*return*/];\n }\n return [4 /*yield*/, this.saveAllDataToStorage()];\n case 1:\n _b.sent();\n this.saveTimer = null;\n this.flushTimer = null;\n return [4 /*yield*/, this.storage.getAllAndClear()];\n case 2:\n _a = _b.sent(), tagRecords = _a.tags, counterRecords = _a.counters, histogramStatsRecords = _a.histogramStats, eventRecords = _a.events;\n // Update the last flush timestamp\n void this.storage.setLastFlushTimestamp(Date.now());\n tags = {};\n tagRecords.forEach(function (record) {\n tags[record.key] = record.value;\n });\n counters = {};\n counterRecords.forEach(function (record) {\n counters[record.key] = record.value;\n });\n histogram = {};\n histogramStatsRecords.forEach(function (stats) {\n histogram[stats.key] = {\n count: stats.count,\n min: stats.min,\n max: stats.max,\n avg: Math.round((stats.sum / stats.count) * 100) / 100, // round the average to 2 decimal places.\n };\n });\n events = eventRecords.map(function (record) { return ({\n event_name: record.event_name,\n time: record.time,\n event_properties: record.event_properties,\n }); });\n // Early return if all data collections are empty\n if (Object.keys(counters).length === 0 && Object.keys(histogram).length === 0 && events.length === 0) {\n return [2 /*return*/];\n }\n payload = {\n tags: tags,\n histogram: histogram,\n counters: counters,\n events: events,\n };\n // Send payload to diagnostics server\n void this.fetch(payload);\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Send diagnostics data to the server\n */\n DiagnosticsClient.prototype.fetch = function (payload) {\n return __awaiter(this, void 0, void 0, function () {\n var response, error_1;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n _a.trys.push([0, 2, , 3]);\n if (!getGlobalScope()) {\n throw new Error('DiagnosticsClient: Fetch is not supported');\n }\n return [4 /*yield*/, fetch(this.serverUrl, {\n method: 'POST',\n headers: {\n 'X-ApiKey': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n })];\n case 1:\n response = _a.sent();\n if (!response.ok) {\n this.logger.debug('DiagnosticsClient: Failed to send diagnostics data.');\n return [2 /*return*/];\n }\n this.logger.debug('DiagnosticsClient: Successfully sent diagnostics data');\n return [3 /*break*/, 3];\n case 2:\n error_1 = _a.sent();\n this.logger.debug('DiagnosticsClient: Failed to send diagnostics data. ', error_1);\n return [3 /*break*/, 3];\n case 3: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Initialize flush interval logic.\n * Check if 5 minutes has passed since last flush, if so flush immediately.\n * Otherwise set a timer to flush when the interval is reached.\n */\n DiagnosticsClient.prototype.initializeFlushInterval = function () {\n return __awaiter(this, void 0, void 0, function () {\n var now, lastFlushTimestamp, timeSinceLastFlush;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n if (!this.storage) {\n return [2 /*return*/];\n }\n now = Date.now();\n return [4 /*yield*/, this.storage.getLastFlushTimestamp()];\n case 1:\n lastFlushTimestamp = (_a.sent()) || -1;\n // If last flush timestamp is -1, it means this is a new client\n // Save current timestamp as the initial \"last flush timestamp\"\n // and schedule the flush timer\n if (lastFlushTimestamp === -1) {\n void this.storage.setLastFlushTimestamp(now);\n this._setFlushTimer(FLUSH_INTERVAL_MS);\n return [2 /*return*/];\n }\n timeSinceLastFlush = now - lastFlushTimestamp;\n if (timeSinceLastFlush >= FLUSH_INTERVAL_MS) {\n // More than 5 minutes has passed, flush immediately\n void this._flush();\n return [2 /*return*/];\n }\n else {\n // Set timer for remaining time\n this._setFlushTimer(FLUSH_INTERVAL_MS - timeSinceLastFlush);\n }\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Helper method to set flush timer with consistent error handling\n */\n DiagnosticsClient.prototype._setFlushTimer = function (delay) {\n var _this = this;\n this.flushTimer = setTimeout(function () {\n _this._flush()\n .catch(function (error) {\n _this.logger.debug('DiagnosticsClient: Failed to flush', error);\n })\n .finally(function () {\n _this.flushTimer = null;\n });\n }, delay);\n };\n DiagnosticsClient.prototype._setSampleRate = function (sampleRate) {\n this.logger.debug('DiagnosticsClient: Setting sample rate to', sampleRate);\n this.config.sampleRate = sampleRate;\n this.shouldTrack = isTimestampInSampleTemp(this.startTimestamp, this.config.sampleRate) && this.config.enabled;\n this.logger.debug('DiagnosticsClient: Should track is', this.shouldTrack);\n };\n return DiagnosticsClient;\n}());\nexport { DiagnosticsClient };\n//# sourceMappingURL=diagnostics-client.js.map","import { Status } from '../types/status';\nimport { isSuccessStatusCode } from '../utils/status-code';\nvar BaseTransport = /** @class */ (function () {\n function BaseTransport() {\n }\n BaseTransport.prototype.send = function (_serverUrl, _payload, _enableRequestBodyCompression) {\n return Promise.resolve(null);\n };\n BaseTransport.prototype.buildResponse = function (responseJSON) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;\n if (typeof responseJSON !== 'object') {\n return null;\n }\n var statusCode = responseJSON.code || 0;\n var status = this.buildStatus(statusCode);\n switch (status) {\n case Status.Success:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n eventsIngested: (_a = responseJSON.events_ingested) !== null && _a !== void 0 ? _a : 0,\n payloadSizeBytes: (_b = responseJSON.payload_size_bytes) !== null && _b !== void 0 ? _b : 0,\n serverUploadTime: (_c = responseJSON.server_upload_time) !== null && _c !== void 0 ? _c : 0,\n },\n };\n case Status.Invalid:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n error: (_d = responseJSON.error) !== null && _d !== void 0 ? _d : '',\n missingField: (_e = responseJSON.missing_field) !== null && _e !== void 0 ? _e : '',\n eventsWithInvalidFields: (_f = responseJSON.events_with_invalid_fields) !== null && _f !== void 0 ? _f : {},\n eventsWithMissingFields: (_g = responseJSON.events_with_missing_fields) !== null && _g !== void 0 ? _g : {},\n eventsWithInvalidIdLengths: (_h = responseJSON.events_with_invalid_id_lengths) !== null && _h !== void 0 ? _h : {},\n epsThreshold: (_j = responseJSON.eps_threshold) !== null && _j !== void 0 ? _j : 0,\n exceededDailyQuotaDevices: (_k = responseJSON.exceeded_daily_quota_devices) !== null && _k !== void 0 ? _k : {},\n silencedDevices: (_l = responseJSON.silenced_devices) !== null && _l !== void 0 ? _l : [],\n silencedEvents: (_m = responseJSON.silenced_events) !== null && _m !== void 0 ? _m : [],\n throttledDevices: (_o = responseJSON.throttled_devices) !== null && _o !== void 0 ? _o : {},\n throttledEvents: (_p = responseJSON.throttled_events) !== null && _p !== void 0 ? _p : [],\n },\n };\n case Status.PayloadTooLarge:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n error: (_q = responseJSON.error) !== null && _q !== void 0 ? _q : '',\n },\n };\n case Status.RateLimit:\n return {\n status: status,\n statusCode: statusCode,\n body: {\n error: (_r = responseJSON.error) !== null && _r !== void 0 ? _r : '',\n epsThreshold: (_s = responseJSON.eps_threshold) !== null && _s !== void 0 ? _s : 0,\n throttledDevices: (_t = responseJSON.throttled_devices) !== null && _t !== void 0 ? _t : {},\n throttledUsers: (_u = responseJSON.throttled_users) !== null && _u !== void 0 ? _u : {},\n exceededDailyQuotaDevices: (_v = responseJSON.exceeded_daily_quota_devices) !== null && _v !== void 0 ? _v : {},\n exceededDailyQuotaUsers: (_w = responseJSON.exceeded_daily_quota_users) !== null && _w !== void 0 ? _w : {},\n throttledEvents: (_x = responseJSON.throttled_events) !== null && _x !== void 0 ? _x : [],\n },\n };\n case Status.Timeout:\n default:\n return {\n status: status,\n statusCode: statusCode,\n };\n }\n };\n BaseTransport.prototype.buildStatus = function (code) {\n if (isSuccessStatusCode(code)) {\n return Status.Success;\n }\n if (code === 429) {\n return Status.RateLimit;\n }\n if (code === 413) {\n return Status.PayloadTooLarge;\n }\n if (code === 408) {\n return Status.Timeout;\n }\n if (code >= 400 && code < 500) {\n return Status.Invalid;\n }\n if (code >= 500) {\n return Status.Failed;\n }\n return Status.Unknown;\n };\n return BaseTransport;\n}());\nexport { BaseTransport };\n//# sourceMappingURL=base.js.map","/**\n * Checks if an HTTP status code indicates success (2xx range)\n * @param code - The HTTP status code to check\n * @returns true if the status code is in the 2xx range, false otherwise\n */\nexport function isSuccessStatusCode(code) {\n return code >= 200 && code < 300;\n}\n//# sourceMappingURL=status-code.js.map","import { __assign, __awaiter, __extends, __generator } from \"tslib\";\nimport { BaseTransport } from './base';\nvar FetchTransport = /** @class */ (function (_super) {\n __extends(FetchTransport, _super);\n function FetchTransport(customHeaders) {\n if (customHeaders === void 0) { customHeaders = {}; }\n var _this = _super.call(this) || this;\n _this.customHeaders = customHeaders;\n return _this;\n }\n FetchTransport.prototype.send = function (serverUrl, payload) {\n return __awaiter(this, void 0, void 0, function () {\n var options, response, responseText;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n /* istanbul ignore if */\n if (typeof fetch === 'undefined') {\n throw new Error('FetchTransport is not supported');\n }\n options = {\n headers: __assign({ 'Content-Type': 'application/json', Accept: '*/*' }, this.customHeaders),\n body: JSON.stringify(payload),\n method: 'POST',\n };\n return [4 /*yield*/, fetch(serverUrl, options)];\n case 1:\n response = _a.sent();\n return [4 /*yield*/, response.text()];\n case 2:\n responseText = _a.sent();\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return [2 /*return*/, this.buildResponse(JSON.parse(responseText))];\n }\n catch (_b) {\n return [2 /*return*/, this.buildResponse({ code: response.status })];\n }\n return [2 /*return*/];\n }\n });\n });\n };\n return FetchTransport;\n}(BaseTransport));\nexport { FetchTransport };\n//# sourceMappingURL=fetch.js.map","var RemoteConfigLocalStorage = /** @class */ (function () {\n function RemoteConfigLocalStorage(apiKey, logger) {\n this.key = \"AMP_remote_config_\".concat(apiKey.substring(0, 10));\n this.logger = logger;\n }\n RemoteConfigLocalStorage.prototype.fetchConfig = function () {\n var result = null;\n var failedRemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n try {\n result = localStorage.getItem(this.key);\n }\n catch (error) {\n this.logger.debug('Remote config localstorage failed to access: ', error);\n return Promise.resolve(failedRemoteConfigInfo);\n }\n if (result === null) {\n this.logger.debug('Remote config localstorage gets null because the key does not exist');\n return Promise.resolve(failedRemoteConfigInfo);\n }\n try {\n var remoteConfigInfo = JSON.parse(result);\n this.logger.debug(\"Remote config localstorage parsed successfully: \".concat(JSON.stringify(remoteConfigInfo)));\n return Promise.resolve({\n remoteConfig: remoteConfigInfo.remoteConfig,\n lastFetch: new Date(remoteConfigInfo.lastFetch),\n });\n }\n catch (error) {\n this.logger.debug('Remote config localstorage failed to parse: ', error);\n localStorage.removeItem(this.key);\n return Promise.resolve(failedRemoteConfigInfo);\n }\n };\n RemoteConfigLocalStorage.prototype.setConfig = function (config) {\n try {\n localStorage.setItem(this.key, JSON.stringify(config));\n this.logger.debug('Remote config localstorage set successfully.');\n return Promise.resolve(true);\n }\n catch (error) {\n this.logger.debug('Remote config localstorage failed to set: ', error);\n }\n return Promise.resolve(false);\n };\n return RemoteConfigLocalStorage;\n}());\nexport { RemoteConfigLocalStorage };\n//# sourceMappingURL=remote-config-localstorage.js.map","import { __awaiter, __generator } from \"tslib\";\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\nexport var US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport var EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport var DEFAULT_MAX_RETRIES = 3;\nvar CODE_STATUS = {\n INVALID_API_KEY: 401,\n FORBIDDEN: 403,\n RATE_LIMIT: 429,\n};\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nvar DEFAULT_TIMEOUT = 1000;\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nvar DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\nvar RemoteConfigClient = /** @class */ (function () {\n function RemoteConfigClient(apiKey, logger, serverZone, serverUrl) {\n if (serverZone === void 0) { serverZone = 'US'; }\n // Registered callbackInfos by subscribe().\n this.callbackInfos = [];\n // Track the last successful fetch time for throttling (timestamp in milliseconds).\n this.lastSuccessfulFetch = null;\n // Store the in-flight fetch promise for deduplication.\n this.fetchPromise = null;\n // Used to skip periodic updateConfigs calls when API key is invalid.\n this.isLastFetchInvalidApiKey = false;\n this.apiKey = apiKey;\n this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n this.logger = logger;\n this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n }\n RemoteConfigClient.prototype.subscribe = function (key, deliveryMode, callback) {\n var id = UUID();\n var callbackInfo = {\n id: id,\n key: key,\n deliveryMode: deliveryMode,\n callback: callback,\n };\n this.callbackInfos.push(callbackInfo);\n if (deliveryMode === 'all') {\n void this.subscribeAll(callbackInfo);\n }\n else {\n void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n }\n return id;\n };\n RemoteConfigClient.prototype.unsubscribe = function (id) {\n var index = this.callbackInfos.findIndex(function (callbackInfo) { return callbackInfo.id === id; });\n if (index === -1) {\n this.logger.debug(\"Remote config client unsubscribe failed because callback with id \".concat(id, \" doesn't exist.\"));\n return false;\n }\n this.callbackInfos.splice(index, 1);\n this.logger.debug(\"Remote config client unsubscribe succeeded removing callback with id \".concat(id, \".\"));\n return true;\n };\n RemoteConfigClient.prototype.updateConfigs = function () {\n return __awaiter(this, void 0, void 0, function () {\n var timeSinceLastFetch, result;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n // Check if we need to throttle based on last successful fetch time\n if (this.lastSuccessfulFetch) {\n timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n return [2 /*return*/];\n }\n }\n return [4 /*yield*/, this.getOrCreateFetchPromise()];\n case 1:\n result = _a.sent();\n void this.storage.setConfig(result);\n this.callbackInfos.forEach(function (callbackInfo) {\n _this.sendCallback(callbackInfo, result, 'remote');\n });\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Get the in-flight fetch promise or create a new one.\n * This ensures multiple subscribe calls share the same network request.\n */\n RemoteConfigClient.prototype.getOrCreateFetchPromise = function () {\n var _this = this;\n if (this.fetchPromise) {\n return this.fetchPromise;\n }\n if (this.isLastFetchInvalidApiKey) {\n this.logger.debug('Remote config client skipping fetch: Invalid API key');\n this.fetchPromise = Promise.resolve({\n remoteConfig: null,\n lastFetch: new Date(),\n }).finally(function () {\n _this.fetchPromise = null;\n });\n return this.fetchPromise;\n }\n this.fetchPromise = this.fetch()\n .then(function (result) {\n // Update last successful fetch time if we got a valid config\n if (result.remoteConfig !== null) {\n _this.lastSuccessfulFetch = Date.now();\n }\n return result;\n })\n .finally(function () {\n // Clear the promise after it settles (success or failure)\n _this.fetchPromise = null;\n });\n return this.fetchPromise;\n };\n /**\n * Send remote first. If it's already complete, we can skip the cached response.\n * - if remote is fetched first, no cache fetch.\n * - if cache is fetched first, still fetching remote.\n */\n RemoteConfigClient.prototype.subscribeAll = function (callbackInfo) {\n return __awaiter(this, void 0, void 0, function () {\n var remotePromise, cachePromise, result;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n remotePromise = this.getOrCreateFetchPromise().then(function (result) {\n _this.logger.debug(\"Remote config client subscription all mode fetched from remote: \".concat(JSON.stringify(result)));\n _this.sendCallback(callbackInfo, result, 'remote');\n void _this.storage.setConfig(result);\n });\n cachePromise = this.storage.fetchConfig().then(function (result) {\n return result;\n });\n return [4 /*yield*/, Promise.race([remotePromise, cachePromise])];\n case 1:\n result = _a.sent();\n // If cache is fetched first, wait for remote.\n if (result !== undefined) {\n this.logger.debug(\"Remote config client subscription all mode fetched from cache: \".concat(JSON.stringify(result)));\n // Skip sending callback if cache is empty (first time user).\n if (result.remoteConfig !== null) {\n this.sendCallback(callbackInfo, result, 'cache');\n }\n else {\n this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n }\n }\n return [4 /*yield*/, remotePromise];\n case 2:\n _a.sent();\n return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Waits for a remote response until the given timeout, then return a cached copy, if available.\n */\n RemoteConfigClient.prototype.subscribeWaitForRemote = function (callbackInfo, timeout) {\n return __awaiter(this, void 0, void 0, function () {\n var timeoutPromise, result, error_1, result;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n timeoutPromise = new Promise(function (_, reject) {\n setTimeout(function () {\n reject('Timeout exceeded');\n }, timeout);\n });\n _a.label = 1;\n case 1:\n _a.trys.push([1, 3, , 5]);\n return [4 /*yield*/, Promise.race([\n this.getOrCreateFetchPromise(),\n timeoutPromise,\n ])];\n case 2:\n result = (_a.sent());\n this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n this.sendCallback(callbackInfo, result, 'remote');\n void this.storage.setConfig(result);\n return [3 /*break*/, 5];\n case 3:\n error_1 = _a.sent();\n this.logger.debug('Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.');\n return [4 /*yield*/, this.storage.fetchConfig()];\n case 4:\n result = _a.sent();\n if (result.remoteConfig !== null) {\n this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n this.sendCallback(callbackInfo, result, 'cache');\n }\n else {\n this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n this.sendCallback(callbackInfo, result, 'remote');\n }\n return [3 /*break*/, 5];\n case 5: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Call the callback with filtered remote config based on key.\n * @param remoteConfigInfo - the whole remote config object without filtering by key.\n */\n RemoteConfigClient.prototype.sendCallback = function (callbackInfo, remoteConfigInfo, source) {\n callbackInfo.lastCallback = new Date();\n var filteredConfig;\n if (callbackInfo.key) {\n // Filter remote config by key.\n // For example, if remote config is {a: {b: {c: 1}}},\n // if key = 'a', filter result is {b: {c: 1}};\n // if key = 'a.b', filter result is {c: 1}\n filteredConfig = callbackInfo.key.split('.').reduce(function (config, key) {\n if (config === null) {\n return config;\n }\n return key in config ? config[key] : null;\n }, remoteConfigInfo.remoteConfig);\n }\n else {\n filteredConfig = remoteConfigInfo.remoteConfig;\n }\n callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n };\n /**\n * Fetch remote config from remote.\n * @param retries - the number of retries. default is 3.\n * @param timeout - the timeout in milliseconds. Default is 1000.\n * This timeout serves two purposes:\n * 1. It determines how long to wait for each remote config fetch request before aborting it.\n * If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n * and the attempt is considered failed (and may be retried if retries remain).\n * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n * so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n * Retry behavior by status code:\n * - 401: invalid API key (stop retries and disable future updateConfigs calls).\n * - 429: retry up to max retries.\n * - other 4xx: no retry.\n * - 5xx and network failures: retry up to max retries.\n * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n */\n RemoteConfigClient.prototype.fetch = function (retries, timeout) {\n if (retries === void 0) { retries = DEFAULT_MAX_RETRIES; }\n if (timeout === void 0) { timeout = DEFAULT_TIMEOUT; }\n return __awaiter(this, void 0, void 0, function () {\n var interval, failedRemoteConfigInfo, _loop_1, this_1, attempt, state_1;\n var _this = this;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0:\n interval = timeout / retries;\n failedRemoteConfigInfo = {\n remoteConfig: null,\n lastFetch: new Date(),\n };\n _loop_1 = function (attempt) {\n var shouldRetry, abortController, timeoutId, res, body, remoteConfig, error_2;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n shouldRetry = true;\n abortController = new AbortController();\n timeoutId = setTimeout(function () { return abortController.abort(); }, timeout);\n _b.label = 1;\n case 1:\n _b.trys.push([1, 7, 8, 9]);\n return [4 /*yield*/, fetch(this_1.getUrlParams(), {\n method: 'GET',\n headers: {\n Accept: '*/*',\n },\n signal: abortController.signal,\n })];\n case 2:\n res = _b.sent();\n if (!!res.ok) return [3 /*break*/, 4];\n return [4 /*yield*/, res.text()];\n case 3:\n body = _b.sent();\n this_1.logger.debug(\"Remote config client fetch with retry time \".concat(retries, \" failed with \").concat(res.status, \": \").concat(body));\n if (res.status === CODE_STATUS.INVALID_API_KEY || res.status === CODE_STATUS.FORBIDDEN) {\n this_1.logger.error(\"Remote config client fetch failed with \".concat(res.status, \". Invalid API key; future fetches will be skipped.\"));\n this_1.isLastFetchInvalidApiKey = true;\n shouldRetry = false;\n }\n else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {\n shouldRetry = false;\n }\n return [3 /*break*/, 6];\n case 4: return [4 /*yield*/, res.json()];\n case 5:\n remoteConfig = (_b.sent());\n return [2 /*return*/, { value: {\n remoteConfig: remoteConfig,\n lastFetch: new Date(),\n } }];\n case 6: return [3 /*break*/, 9];\n case 7:\n error_2 = _b.sent();\n // Handle rejects when the request fails, for example, a network error or timeout\n if (error_2 instanceof Error && error_2.name === 'AbortError') {\n this_1.logger.debug(\"Remote config client fetch with retry time \".concat(retries, \" timed out after \").concat(timeout, \"ms\"));\n }\n else {\n this_1.logger.debug(\"Remote config client fetch with retry time \".concat(retries, \" is rejected because: \"), error_2);\n }\n return [3 /*break*/, 9];\n case 8:\n // Clear the timeout since request completed or failed\n clearTimeout(timeoutId);\n return [7 /*endfinally*/];\n case 9:\n if (!shouldRetry) {\n return [2 /*return*/, \"break\"];\n }\n if (!(attempt < retries - 1)) return [3 /*break*/, 11];\n return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, _this.getJitterDelay(interval)); })];\n case 10:\n _b.sent();\n _b.label = 11;\n case 11: return [2 /*return*/];\n }\n });\n };\n this_1 = this;\n attempt = 0;\n _a.label = 1;\n case 1:\n if (!(attempt < retries)) return [3 /*break*/, 4];\n return [5 /*yield**/, _loop_1(attempt)];\n case 2:\n state_1 = _a.sent();\n if (typeof state_1 === \"object\")\n return [2 /*return*/, state_1.value];\n if (state_1 === \"break\")\n return [3 /*break*/, 4];\n _a.label = 3;\n case 3:\n attempt++;\n return [3 /*break*/, 1];\n case 4: return [2 /*return*/, failedRemoteConfigInfo];\n }\n });\n });\n };\n /**\n * Return jitter in the bound of [0,baseDelay) and then floor round.\n */\n RemoteConfigClient.prototype.getJitterDelay = function (baseDelay) {\n return Math.floor(Math.random() * baseDelay);\n };\n RemoteConfigClient.prototype.getUrlParams = function () {\n // URL encode the API key to handle special characters\n var encodedApiKey = encodeURIComponent(this.apiKey);\n var urlParams = new URLSearchParams();\n urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n return \"\".concat(this.serverUrl, \"/\").concat(encodedApiKey, \"?\").concat(urlParams.toString());\n };\n RemoteConfigClient.CONFIG_GROUP = 'browser';\n return RemoteConfigClient;\n}());\nexport { RemoteConfigClient };\n//# sourceMappingURL=remote-config.js.map","// Shared origin constants for Amplitude cross-window communication\nexport var AMPLITUDE_ORIGIN = 'https://app.amplitude.com';\nexport var AMPLITUDE_ORIGIN_EU = 'https://app.eu.amplitude.com';\nexport var AMPLITUDE_ORIGIN_STAGING = 'https://apps.stag2.amplitude.com';\nexport var AMPLITUDE_ORIGINS_MAP = {\n US: AMPLITUDE_ORIGIN,\n EU: AMPLITUDE_ORIGIN_EU,\n STAGING: AMPLITUDE_ORIGIN_STAGING,\n};\n// Background capture script URL (shared between autocapture and session-replay)\nexport var AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL = 'https://cdn.amplitude.com/libs/background-capture-1.0.1.js.gz';\n//# sourceMappingURL=constants.js.map","var _a;\nimport { __awaiter, __generator, __values } from \"tslib\";\nimport { getGlobalScope } from '../global-scope';\nimport { AMPLITUDE_ORIGIN } from './constants';\nimport { asyncLoadScript, generateUniqueId } from './utils';\n/**\n * Brand key used to identify BaseWindowMessenger instances across bundle boundaries.\n */\nvar MESSENGER_BRAND = '__AMPLITUDE_MESSENGER_INSTANCE__';\n/** Global scope key where the singleton messenger is stored. */\nvar MESSENGER_GLOBAL_KEY = '__AMPLITUDE_MESSENGER__';\n/**\n * BaseWindowMessenger provides generic cross-window communication via postMessage.\n * Singleton access via getOrCreateWindowMessenger() to prevent duplicate instances\n */\nvar BaseWindowMessenger = /** @class */ (function () {\n function BaseWindowMessenger(_b) {\n var _c = _b === void 0 ? {} : _b, _d = _c.origin, origin = _d === void 0 ? AMPLITUDE_ORIGIN : _d;\n /** Brand property for cross-bundle instanceof checks. */\n this[_a] = true;\n this.isSetup = false;\n this.messageHandler = null;\n this.requestCallbacks = {};\n this.actionHandlers = new Map();\n /**\n * Messages received for actions that had no registered handler yet.\n * Drained automatically when the corresponding handler is registered via\n * registerActionHandler(), solving startup race conditions between\n * independently-initialized plugins.\n */\n this.pendingMessages = new Map();\n /**\n * Tracks in-flight and completed script loads by URL.\n * Using a map, this prevents duplicate loads before the first resolves.\n */\n this.scriptLoadPromises = new Map();\n this.endpoint = origin;\n }\n /**\n * Send a message to the parent window (window.opener).\n */\n BaseWindowMessenger.prototype.notify = function (message) {\n var _b, _c, _d, _e;\n (_c = (_b = this.logger) === null || _b === void 0 ? void 0 : _b.debug) === null || _c === void 0 ? void 0 : _c.call(_b, 'Message sent: ', JSON.stringify(message));\n (_e = (_d = window.opener) === null || _d === void 0 ? void 0 : _d.postMessage) === null || _e === void 0 ? void 0 : _e.call(_d, message, this.endpoint);\n };\n /**\n * Send an async request to the parent window with a unique ID.\n * Returns a Promise that resolves when the parent responds.\n */\n BaseWindowMessenger.prototype.sendRequest = function (action, args, options) {\n var _this = this;\n if (options === void 0) { options = { timeout: 15000 }; }\n var id = generateUniqueId();\n var request = { id: id, action: action, args: args };\n var promise = new Promise(function (resolve, reject) {\n _this.requestCallbacks[id] = { resolve: resolve, reject: reject };\n _this.notify(request);\n if (options.timeout > 0) {\n setTimeout(function () {\n reject(new Error(\"\".concat(action, \" timed out (id: \").concat(id, \")\")));\n delete _this.requestCallbacks[id];\n }, options.timeout);\n }\n });\n return promise;\n };\n /**\n * Handle a response to a previous request by resolving its Promise.\n */\n BaseWindowMessenger.prototype.handleResponse = function (response) {\n var _b;\n if (!this.requestCallbacks[response.id]) {\n (_b = this.logger) === null || _b === void 0 ? void 0 : _b.warn(\"No callback found for request id: \".concat(response.id));\n return;\n }\n this.requestCallbacks[response.id].resolve(response.responseData);\n delete this.requestCallbacks[response.id];\n };\n /**\n * Register a handler for a specific action type.\n * Logs a warning if overwriting an existing handler.\n */\n BaseWindowMessenger.prototype.registerActionHandler = function (action, handler) {\n var e_1, _b;\n var _c, _d;\n if (this.actionHandlers.has(action)) {\n (_d = (_c = this.logger) === null || _c === void 0 ? void 0 : _c.warn) === null || _d === void 0 ? void 0 : _d.call(_c, \"Overwriting existing action handler for: \".concat(action));\n }\n this.actionHandlers.set(action, handler);\n // Replay any messages that arrived before this handler was registered\n var queued = this.pendingMessages.get(action);\n if (queued) {\n this.pendingMessages.delete(action);\n try {\n for (var queued_1 = __values(queued), queued_1_1 = queued_1.next(); !queued_1_1.done; queued_1_1 = queued_1.next()) {\n var data = queued_1_1.value;\n handler(data);\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (queued_1_1 && !queued_1_1.done && (_b = queued_1.return)) _b.call(queued_1);\n }\n finally { if (e_1) throw e_1.error; }\n }\n }\n };\n /**\n * Load a script once, deduplicating by URL.\n * Safe against concurrent calls — the second call awaits the first's in-flight Promise\n * rather than triggering a duplicate load.\n */\n BaseWindowMessenger.prototype.loadScriptOnce = function (url) {\n return __awaiter(this, void 0, void 0, function () {\n var existing, loadPromise, error_1;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0:\n existing = this.scriptLoadPromises.get(url);\n if (existing) {\n return [2 /*return*/, existing];\n }\n loadPromise = asyncLoadScript(url).then(function () {\n // Resolve to void\n });\n this.scriptLoadPromises.set(url, loadPromise);\n _b.label = 1;\n case 1:\n _b.trys.push([1, 3, , 4]);\n return [4 /*yield*/, loadPromise];\n case 2:\n _b.sent();\n return [3 /*break*/, 4];\n case 3:\n error_1 = _b.sent();\n // Remove failed loads so they can be retried\n this.scriptLoadPromises.delete(url);\n throw error_1;\n case 4: return [2 /*return*/];\n }\n });\n });\n };\n /**\n * Set up the message listener. Idempotent — safe to call multiple times.\n * Subclasses should call super.setup() and then register their own action handlers.\n */\n BaseWindowMessenger.prototype.setup = function (_b) {\n var _this = this;\n var _c, _d;\n var _e = _b === void 0 ? {} : _b, logger = _e.logger, endpoint = _e.endpoint;\n if (logger) {\n this.logger = logger;\n }\n // If endpoint is customized, don't override a previously customized endpoint.\n if (endpoint && this.endpoint === AMPLITUDE_ORIGIN) {\n this.endpoint = endpoint;\n }\n // Only attach the message listener once\n if (this.isSetup) {\n return;\n }\n this.isSetup = true;\n (_d = (_c = this.logger) === null || _c === void 0 ? void 0 : _c.debug) === null || _d === void 0 ? void 0 : _d.call(_c, 'Setting up messenger');\n // Attach Event Listener to listen for messages from the parent window\n this.messageHandler = function (event) {\n var _b, _c, _d, _e, _f;\n (_c = (_b = _this.logger) === null || _b === void 0 ? void 0 : _b.debug) === null || _c === void 0 ? void 0 : _c.call(_b, 'Message received: ', JSON.stringify(event));\n // Only accept messages from the specified origin\n if (_this.endpoint !== event.origin) {\n return;\n }\n var eventData = event.data;\n var action = eventData === null || eventData === void 0 ? void 0 : eventData.action;\n // Ignore messages without action\n if (!action) {\n return;\n }\n // If id exists, handle responses to previous requests\n if ('id' in eventData && eventData.id) {\n (_e = (_d = _this.logger) === null || _d === void 0 ? void 0 : _d.debug) === null || _e === void 0 ? void 0 : _e.call(_d, 'Received Response to previous request: ', JSON.stringify(event));\n _this.handleResponse(eventData);\n }\n else {\n if (action === 'ping') {\n _this.notify({ action: 'pong' });\n return;\n }\n // Dispatch to registered action handlers, or buffer for late registration\n var handler = _this.actionHandlers.get(action);\n if (handler) {\n handler(eventData.data);\n }\n else {\n var queue = (_f = _this.pendingMessages.get(action)) !== null && _f !== void 0 ? _f : [];\n queue.push(eventData.data);\n _this.pendingMessages.set(action, queue);\n }\n }\n };\n window.addEventListener('message', this.messageHandler);\n this.notify({ action: 'page-loaded' });\n };\n /**\n * Tear down the messenger: remove the message listener, clear all state.\n */\n BaseWindowMessenger.prototype.destroy = function () {\n if (this.messageHandler) {\n window.removeEventListener('message', this.messageHandler);\n this.messageHandler = null;\n }\n this.isSetup = false;\n this.actionHandlers.clear();\n this.pendingMessages.clear();\n this.requestCallbacks = {};\n this.scriptLoadPromises.clear();\n // Remove from global scope if this is the singleton\n var globalScope = getGlobalScope();\n if ((globalScope === null || globalScope === void 0 ? void 0 : globalScope[MESSENGER_GLOBAL_KEY]) === this) {\n delete globalScope[MESSENGER_GLOBAL_KEY];\n }\n };\n return BaseWindowMessenger;\n}());\n_a = MESSENGER_BRAND;\n/**\n * Type guard: checks whether a value is a BaseWindowMessenger instance.\n */\nfunction isWindowMessenger(value) {\n return (typeof value === 'object' &&\n value !== null &&\n MESSENGER_BRAND in value &&\n value[MESSENGER_BRAND] === true);\n}\n/**\n * Get or create a singleton BaseWindowMessenger instance.\n * Ensures only one messenger (and one message listener) exists per page,\n * preventing duplicate script loads and double notifications.\n *\n * The singleton is stored on globalScope under the same MESSENGER_KEY.\n * The branded property check verifies the stored value is actually a messenger.\n */\nexport function getOrCreateWindowMessenger(options) {\n var globalScope = getGlobalScope();\n var existing = globalScope === null || globalScope === void 0 ? void 0 : globalScope[MESSENGER_GLOBAL_KEY];\n if (isWindowMessenger(existing)) {\n return existing;\n }\n var messenger = new BaseWindowMessenger(options);\n if (globalScope) {\n globalScope[MESSENGER_GLOBAL_KEY] = messenger;\n }\n return messenger;\n}\n//# sourceMappingURL=base-window-messenger.js.map","/* eslint-disable no-restricted-globals */\n/**\n * Dynamically loads an external script by appending a <script> tag to the document head.\n * Deduplicates by checking if a script with the same src already exists.\n */\nexport var asyncLoadScript = function (url) {\n // Dedup: if a script with this src already exists, resolve immediately\n var existing = document.querySelector(\"script[src=\\\"\".concat(CSS.escape(url), \"\\\"]\"));\n if (existing) {\n return Promise.resolve({ status: true });\n }\n return new Promise(function (resolve, reject) {\n var _a;\n try {\n var scriptElement = document.createElement('script');\n scriptElement.type = 'text/javascript';\n scriptElement.async = true;\n scriptElement.src = url;\n scriptElement.addEventListener('load', function () {\n resolve({ status: true });\n }, { once: true });\n scriptElement.addEventListener('error', function () {\n reject({\n status: false,\n message: \"Failed to load the script \".concat(url),\n });\n });\n /* istanbul ignore next */\n (_a = document.head) === null || _a === void 0 ? void 0 : _a.appendChild(scriptElement);\n }\n catch (error) {\n /* istanbul ignore next */\n reject(error);\n }\n });\n};\n/**\n * Generates a simple unique ID for message request/response correlation.\n */\nexport function generateUniqueId() {\n return \"\".concat(Date.now(), \"-\").concat(Math.random().toString(36).substr(2, 9));\n}\n//# sourceMappingURL=utils.js.map","import { AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL } from './constants';\n/**\n * Brand key set on the messenger instance to track whether background capture\n * has been enabled.\n */\nvar BG_CAPTURE_BRAND = '__AMPLITUDE_BACKGROUND_CAPTURE__';\n/**\n * Enable background capture on a messenger instance.\n * Plugins can call this on a shared messenger instance.\n * The first call registers the handlers; subsequent calls are no-ops.\n *\n * @param messenger - The messenger to enable background capture on\n * @param options.scriptUrl - Override the background capture script URL (optional)\n */\nexport function enableBackgroundCapture(messenger, options) {\n var _a;\n // Check the brand on the messenger object itself — works across bundle boundaries\n var branded = messenger;\n if (branded[BG_CAPTURE_BRAND] === true) {\n return;\n }\n branded[BG_CAPTURE_BRAND] = true;\n var scriptUrl = (_a = options === null || options === void 0 ? void 0 : options.scriptUrl) !== null && _a !== void 0 ? _a : AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL;\n var backgroundCaptureInstance = null;\n var onBackgroundCapture = function (type, backgroundCaptureData) {\n var _a, _b;\n if (type === 'background-capture-complete') {\n (_b = (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'Background capture complete');\n messenger.notify({ action: 'background-capture-complete', data: backgroundCaptureData });\n }\n };\n messenger.registerActionHandler('initialize-background-capture', function () {\n var _a, _b;\n (_b = (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'Initializing background capture (external script)');\n var resolvedUrl = new URL(scriptUrl, messenger.endpoint).toString();\n messenger\n .loadScriptOnce(resolvedUrl)\n .then(function () {\n var _a, _b, _c;\n (_b = (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'Background capture script loaded (external)');\n // eslint-disable-next-line\n backgroundCaptureInstance = /* istanbul ignore next -- window is always defined in browser */ (_c = window === null || window === void 0 ? void 0 : window.amplitudeBackgroundCapture) === null || _c === void 0 ? void 0 : _c.call(window, {\n messenger: messenger,\n onBackgroundCapture: onBackgroundCapture,\n });\n messenger.notify({ action: 'background-capture-loaded' });\n })\n .catch(function () {\n var _a;\n (_a = messenger.logger) === null || _a === void 0 ? void 0 : _a.warn('Failed to initialize background capture');\n });\n });\n messenger.registerActionHandler('close-background-capture', function () {\n var _a;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n (_a = backgroundCaptureInstance === null || backgroundCaptureInstance === void 0 ? void 0 : backgroundCaptureInstance.close) === null || _a === void 0 ? void 0 : _a.call(backgroundCaptureInstance);\n backgroundCaptureInstance = null;\n });\n}\n//# sourceMappingURL=background-capture.js.map","import { AMPLITUDE_PREFIX, ServerZone } from '@amplitude/analytics-core';\n\nexport const DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';\n\nexport const DEFAULT_SESSION_REPLAY_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay ID`;\nexport const DEFAULT_SESSION_START_EVENT = 'session_start';\nexport const DEFAULT_SESSION_END_EVENT = 'session_end';\nexport const DEFAULT_SAMPLE_RATE = 0;\nexport const DEFAULT_SERVER_ZONE = ServerZone.US;\nexport const DEFAULT_PERFORMANCE_CONFIG = { enabled: true };\nexport const DEFAULT_URL_CHANGE_POLLING_INTERVAL = 1000;\n\nexport const SESSION_REPLAY_DEBUG_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay Debug`;\n\nexport const BLOCK_CLASS = 'amp-block';\nexport const MASK_TEXT_CLASS = 'amp-mask';\nexport const UNMASK_TEXT_CLASS = 'amp-unmask';\nexport const SESSION_REPLAY_SERVER_URL = 'https://api-sr.amplitude.com/sessions/v2/track';\nexport const SESSION_REPLAY_EU_URL = 'https://api-sr.eu.amplitude.com/sessions/v2/track';\nexport const SESSION_REPLAY_STAGING_URL = 'https://api-sr.stag2.amplitude.com/sessions/v2/track';\nexport const STORAGE_PREFIX = `${AMPLITUDE_PREFIX}_replay_unsent`;\n// Raw (uncompressed) UTF-8 byte cap for a single batched events list before the store splits\n// it into its own request. Larger batches mean fewer requests — the primary steady-state lever\n// for request volume — while the time-based flush (flushIntervalConfig) still controls send\n// cadence, so this only decides whether a single high-activity flush gets split into multiple\n// requests. Set to 2 MB: gzipped on the wire that's ~0.2 MB, far under the SR ingest service's\n// 10,000,000-byte decompressed split threshold (nova SessionReplayServletV2 splits batches above\n// it server-side and only 413s a single >10 MB event), and well clear of the ~10-30% wrapper/\n// JSON-escaping overhead. Kept at 2 MB (not higher) so it stays a safe POST body on the\n// no-CompressionStream fallback path (raw == wire there) and keeps per-session memory/IDB\n// buffering modest on low-end devices. A smaller cap (e.g. 700 KB) splits busy-page flushes\n// into several more requests/session and drives SR ingest request-rate throttling.\nexport const MAX_EVENT_LIST_SIZE = 2_000_000;\n// Default raw (uncompressed) UTF-8 byte cap for a single buffered events list when the\n// consumer does not set `maxPersistedEventsSizeBytes`. Set to 6 MB — the value validated in\n// the amp-on-amp canary (appid 187520, session-replay-sdk-perf-config onenav-prod payload):\n// larger batches mean fewer requests and materially less SR ingest request-rate throttling\n// (rc3 0.02% throttle vs prod 1.31.0 2.95%) while staying under the server's 10 MB\n// decompressed split threshold. Kept distinct from MAX_EVENT_LIST_SIZE (2 MB) because that\n// constant is still used to derive MERGE_AFTER_THROTTLE_SOFT_CAP and as a documented per-batch\n// reference; this constant only governs the default buffer cap. Reverses PR #1814's 2 MB default.\nexport const DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES = 6_000_000;\n// 9 MB UTF-8 bytes — just under the server's 10 MB per-event threshold. Compared against the\n// UTF-8 byte length of the serialized event (via Blob/TextEncoder), not the JS string length,\n// so multi-byte payloads (CJK, emoji) are gated correctly.\nexport const MAX_SINGLE_EVENT_SIZE = 9 * 1000000;\n// WAF rejects oversized compressed payloads with a body containing wording like\n// \"Payload exceeds the maximum allowed size of 10MB\". Match loosely so vendor wording\n// tweaks (rule updates, capitalization, etc.) don't silently disable bisect-retry.\nexport const WAF_PAYLOAD_TOO_LARGE_PATTERN = /payload.*exceed/i;\nexport const INTERACTION_MIN_INTERVAL = 30_000; // 30 seconds\nexport const INTERACTION_MAX_INTERVAL = 60_000; // 1 minute\nexport const MIN_INTERVAL = 500; // 500 ms\nexport const MAX_INTERVAL = 10 * 1000; // 10 seconds\n// Default flush-interval bounds applied when the consumer does not pass `flushIntervalConfig`.\n// Set to the values validated in the amp-on-amp canary (session-replay-sdk-perf-config\n// onenav-prod payload, SR-4646): a 1s floor (up from the MIN_INTERVAL 500ms hard floor) reduces\n// request volume on busy pages while the 10s ceiling matches MAX_INTERVAL. MIN_INTERVAL/\n// MAX_INTERVAL remain the absolute clamp bounds and partial-config cross-validation defaults.\nexport const DEFAULT_FLUSH_MIN_INTERVAL_MS = 1000; // 1 second\nexport const DEFAULT_FLUSH_MAX_INTERVAL_MS = 10 * 1000; // 10 seconds\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days\nexport const KB_SIZE = 1024;\nexport const MAX_URL_LENGTH = 1000;\nexport const RETRY_TIMEOUT_MS = 1000;\nexport const MAX_KEEPALIVE_BYTES = 64 * 1024; // browser keepalive budget shared with sendBeacon\n// Per-request send timeout. fetch() has no native timeout, so a single hung request\n// (stuck \"pending\" forever) would otherwise block the serial flush loop indefinitely —\n// head-of-line blocking that stalls every queued batch behind it. We abort after this\n// many ms so each send always settles and the queue keeps draining.\nexport const SEND_TIMEOUT_MS = 10_000;\n\n// Server returns 200 + this header for \"no-retry\" drops (throttle / capture disabled / out-of-range).\n// See projects/sessionreplay/sessionreplay-ingestion/.../SessionReplayError.java.\n// Header value is the numeric error code as a string.\nexport const EVENT_SKIPPED_HEADER = 'X-Session-Replay-Event-Skipped';\nexport const EVENT_SKIP_CODE_THROTTLED = '429';\nexport const EVENT_SKIP_CODE_INVALID_RANGE = '4004';\nexport const EVENT_SKIP_CODE_CAPTURE_DISABLED = '4005';\n// How long to pause the flush schedule after the server signals a throttle.\nexport const THROTTLED_FLUSH_PAUSE_MS = 60_000;\n// Soft UTF-8 byte cap for merging same-session contexts after a throttle pause.\n// Set to 2 * MAX_EVENT_LIST_SIZE so we'll merge at most ~2 max-size sequences (or many\n// small ones) into one POST — fewer requests during recovery without pushing close to\n// the server's 10MB-compressed 413 ceiling. Compared against UTF-8 byte size (via Blob)\n// to match the per-sequence limit's units enforced upstream by base-events-store.\nexport const MERGE_AFTER_THROTTLE_SOFT_CAP = 2 * MAX_EVENT_LIST_SIZE;\n\nexport const CROSS_ORIGIN_IFRAME_MESSAGE_TYPE = 'amplitude-sr-iframe';\n\nexport enum CustomRRwebEvent {\n GET_SR_PROPS = 'get-sr-props',\n DEBUG_INFO = 'debug-info',\n FETCH_REQUEST = 'fetch-request',\n METADATA = 'metadata',\n TARGETING_DECISION = 'targeting-decision',\n /**\n * Emitted once per session, on the first send that passes the min_session_duration_ms\n * gate. Captures how many sends were suppressed before passing and the elapsed time\n * spent below the threshold. Lets backend ingestion diff intended replay count vs\n * actual ingestion so on-call can spot start-time-tracking regressions.\n *\n * Sessions that bounce before crossing the threshold never emit this event by design\n * (the whole payload is suppressed); their absence is the signal.\n */\n REPLAY_GATE_DECISION = 'replay-gate-decision',\n}\n","import { ILogger, LogLevel } from '@amplitude/analytics-core';\n\nexport class SafeLoggerProvider implements ILogger {\n private logger: ILogger;\n\n log: typeof console.log;\n warn: typeof console.warn;\n error: typeof console.error;\n debug: typeof console.debug;\n\n constructor(loggerProvider: ILogger) {\n this.logger = loggerProvider;\n this.log = this.getSafeMethod('log');\n this.warn = this.getSafeMethod('warn');\n this.error = this.getSafeMethod('error');\n this.debug = this.getSafeMethod('debug');\n }\n\n private getSafeMethod<K extends keyof ILogger>(method: K): ILogger[K] {\n if (!this.logger) {\n return (() => {\n // No-op function fallback\n }) as ILogger[K];\n }\n\n const fn = this.logger[method];\n if (typeof fn === 'function') {\n const originalFn = (fn as { __rrweb_original__?: ILogger[K] }).__rrweb_original__ ?? fn;\n return originalFn.bind(this.logger) as ILogger[K];\n }\n\n return (() => {\n // No-op function fallback\n }) as ILogger[K];\n }\n\n enable(logLevel: LogLevel) {\n this.logger.enable(logLevel);\n }\n\n disable() {\n this.logger.disable();\n }\n}\n","import { IConfig, LogLevel, ILogger, IDiagnosticsClient } from '@amplitude/analytics-core';\nimport { StoreType, ConsoleLogLevel } from '../typings/session-replay';\nimport { TargetingFlag } from '@amplitude/targeting';\n\nexport interface SamplingConfig {\n sample_rate: number;\n capture_enabled: boolean;\n min_session_duration_ms?: number;\n}\n\nexport interface InteractionConfig {\n trackEveryNms?: number;\n enabled: boolean; // defaults to false\n batch: boolean; // defaults to false\n /**\n * UGC filter rules.\n */\n ugcFilterRules?: UGCFilterRule[];\n}\n\nexport interface LoggingConfig {\n console: {\n enabled: boolean;\n levels: ConsoleLogLevel[];\n };\n network?: {\n enabled: boolean;\n body?: {\n request?: boolean;\n response?: boolean;\n maxBodySizeBytes?: number;\n };\n };\n}\n\nexport type TargetingConfig = TargetingFlag;\n\nexport type SessionReplayRemoteConfig = {\n sr_sampling_config?: SamplingConfig;\n sr_privacy_config?: PrivacyConfig;\n sr_interaction_config?: InteractionConfig;\n sr_logging_config?: LoggingConfig;\n sr_targeting_config?: TargetingConfig;\n};\n\nexport interface SessionReplayRemoteConfigAPIResponse {\n configs: {\n sessionReplay: SessionReplayRemoteConfig;\n };\n}\n\nexport type MaskLevel =\n | 'light' // only mask a subset of inputs that's deemed sensitive - password, credit card, telephone #, email. These are information we never want to capture.\n | 'medium' // mask all form fields (inputs); page text is captured as-is\n | 'conservative'; // mask all inputs and all texts\n\nexport const DEFAULT_MASK_LEVEL = 'medium';\n\n// err on the side of excluding more\nexport type PrivacyConfig = {\n blockSelector?: string | string[]; // exclude in the UI\n defaultMaskLevel?: MaskLevel;\n maskSelector?: string[];\n unmaskSelector?: string[];\n maskAttributes?: string[]; // HTML attribute names to mask (e.g. [\"placeholder\", \"aria-label\"])\n /**\n * Per-URL overrides for `defaultMaskLevel`. Each entry contains a glob pattern (`match`)\n * and a `maskLevel` to apply when the current page URL matches that pattern.\n * Rules are evaluated in order; the first match wins. Remote rules take precedence\n * over local rules (remote entries are prepended before local entries).\n *\n * @example\n * urlMaskLevels: [\n * { match: 'https://example.com/checkout/*', maskLevel: 'conservative' },\n * { match: 'https://example.com/public/*', maskLevel: 'light' },\n * ]\n */\n urlMaskLevels?: Array<{ match: string; maskLevel: MaskLevel }>;\n};\n\n/**\n * UGC filter rule.\n */\nexport type UGCFilterRule = {\n /**\n * The selector of the UGC element.\n */\n selector: string;\n /**\n * The replacement text for the UGC element.\n */\n replacement: string;\n};\n\nexport interface CrossOriginIframesConfig {\n enabled: boolean;\n /**\n * When true (default), the parent SDK sends start/stop signals to child iframes via\n * postMessage, keeping their recording lifecycle in sync with the parent.\n *\n * **Privacy note:** The child page's rrweb instance performs its own DOM serialization,\n * so the parent's privacy config (mask levels, block selectors) does NOT automatically\n * apply inside the iframe. Privacy settings must be configured independently on the child page.\n *\n * **Third-party iframes:** Cannot capture iframes you don't control (e.g. Stripe, Google\n * Maps) — both parent and child pages must load the SDK with `crossOriginIframes.enabled: true`.\n *\n * Set to `false` to skip coordination and manage the child recording lifecycle yourself.\n * @defaultValue true\n */\n coordinateChildren?: boolean;\n}\n\nexport interface SessionReplayLocalConfig extends IConfig {\n apiKey: string;\n loggerProvider: ILogger;\n /**\n * Optional diagnostics client used to ship SR decision/targeting telemetry to Amplitude's\n * diagnostics backend (independent of whether a replay is recorded). In plugin mode this is\n * forwarded from the analytics SDK's already-initialized client. No-op when absent or when\n * diagnostics is not sampled in. See DiagnosticsClient in @amplitude/analytics-core.\n */\n diagnosticsClient?: IDiagnosticsClient;\n /**\n * Standalone SR only: when no `diagnosticsClient` is provided (i.e. SR is not running as the\n * analytics plugin), opt in to having SR create its own client so TRC/recording diagnostics are\n * still shipped. Ignored when a `diagnosticsClient` is supplied. @defaultValue false\n */\n diagnosticsEnabled?: boolean;\n /**\n * Standalone SR only: sample rate (0..1) for the diagnostics client SR creates when none is\n * provided. A positive value also implies opting in. @defaultValue 0\n */\n diagnosticsSampleRate?: number;\n /**\n * LogLevel.None or LogLevel.Error or LogLevel.Warn or LogLevel.Verbose or LogLevel.Debug.\n * Sets the log level.\n *\n * @defaultValue LogLevel.Warn\n */\n logLevel: LogLevel;\n /**\n * The maximum number of retries allowed for sending replay events.\n * Once this limit is reached, failed events will no longer be sent.\n *\n * @defaultValue 2\n */\n flushMaxRetries: number;\n /**\n * Use this option to control how many sessions to select for replay collection.\n * The number should be a decimal between 0 and 1, for example 0.4, representing\n * the fraction of sessions to have randomly selected for replay collection.\n * Over a large number of sessions, 0.4 would select 40% of those sessions.\n * Sample rates as small as six decimal places (0.000001) are supported.\n *\n * @defaultValue 0\n */\n sampleRate: number;\n privacyConfig?: PrivacyConfig;\n /**\n * Adds additional debug event property to help debug instrumentation issues\n * (such as mismatching apps). Only recommended for debugging initial setup,\n * and not recommended for production.\n */\n debugMode?: boolean;\n /**\n * Specifies the endpoint URL to fetch remote configuration.\n * If provided, it overrides the default server zone configuration.\n */\n configServerUrl?: string;\n /**\n * Specifies the endpoint URL for sending session replay data.\n * If provided, it overrides the default server zone configuration.\n */\n trackServerUrl?: string;\n /**\n * If stylesheets are inlined, the contents of the stylesheet will be stored.\n * During replay, the stored stylesheet will be used instead of attempting to fetch it remotely.\n * This prevents replays from appearing broken due to missing stylesheets.\n * Note: Inlining stylesheets may not work in all cases.\n */\n shouldInlineStylesheet?: boolean;\n version?: SessionReplayVersion;\n /**\n * Performance configuration config. If enabled, we will defer compression\n * to be done during the browser's idle periods.\n */\n performanceConfig?: SessionReplayPerformanceConfig;\n /**\n * Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events\n * when all events cannot be sent during capture. `memory` stores replay events only in memory,\n * meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.\n *\n * @defaultValue 'memory' — reflects the validated amp-on-amp perf config (SR-4646). `memory`\n * drops cross-navigation persistence (unsent events do not survive a full page reload), which\n * is the intended trade-off for lower IDB overhead.\n */\n storeType: StoreType;\n\n /**\n * If true, the SDK will compress replay events using a web worker.\n * This offloads compression to a separate thread, improving performance on the main thread.\n * Set to `false` to keep compression on the main thread.\n *\n * @defaultValue true — reflects the validated amp-on-amp perf config (SR-4646). Was `false`\n * prior to that change.\n */\n useWebWorker?: boolean;\n\n /**\n * Controls transport-layer gzip compression of session replay request bodies.\n * When true (default), the SDK gzip-compresses the JSON request body via the browser's\n * `CompressionStream` API and sets `Content-Encoding: gzip` on the POST. When false,\n * the SDK sends the raw JSON body with no `Content-Encoding` header.\n *\n * Disabling is intended as a debugging / safety opt-out (e.g. for diagnosing\n * server-side decompression issues); it increases egress bytes and is not\n * recommended for production.\n *\n * Note: This is independent of `useWebWorker` / `performanceConfig`, which control\n * per-event rrweb compression that runs before events are queued.\n *\n * @defaultValue true\n */\n enableTransportCompression?: boolean;\n\n /**\n * Milliseconds to wait for a send request before aborting it. `fetch()` has no native\n * timeout, so a request stuck \"pending\" would block the serial flush loop indefinitely;\n * the SDK aborts after this many ms and routes the abort as a retryable failure.\n *\n * Set to `0` (or a negative value) to disable the timeout entirely — note this\n * reintroduces the head-of-line-blocking risk a wedged request can cause, so it is\n * intended only as a diagnostic/experiment opt-out.\n *\n * Tuning this higher is useful when large, slow-but-succeeding uploads are being aborted\n * at the default and counted as failures (which also triggers a retry, inflating request\n * volume / throttle pressure).\n *\n * @defaultValue 10000\n */\n sendTimeoutMs?: number;\n\n userProperties?: { [key: string]: any };\n\n /**\n * If true, applies a background color to blocked elements in the replay.\n * This helps visualize which elements are blocked from being captured.\n */\n applyBackgroundColorToBlockedElements?: boolean;\n /**\n * Enables URL change polling as a fallback for SPA route tracking.\n * When enabled, the SDK will periodically check for URL changes every second\n * in addition to patching the History API. This is useful for edge cases where\n * route changes might bypass the standard History API methods.\n *\n * @defaultValue false\n */\n enableUrlChangePolling?: boolean;\n /**\n * Specifies the interval in milliseconds for URL change polling when enableUrlChangePolling is true.\n * The SDK will check for URL changes at this interval as a fallback for SPA route tracking.\n *\n * @defaultValue 1000\n */\n urlChangePollingInterval?: number;\n /**\n * Whether to capture document title in URL change events.\n * When disabled, the title field will be empty in URL change events.\n *\n * @defaultValue false\n */\n captureDocumentTitle?: boolean;\n interactionConfig?: InteractionConfig;\n /**\n * When true (default), the CSS rules of any `adoptedStyleSheets` on shadow roots and\n * the document are serialized **inline** within the full snapshot. This makes the snapshot\n * self-contained so that shadow DOM styles are replayed correctly even if subsequent\n * incremental `AdoptedStyleSheet` events are dropped in transit.\n *\n * Set to `false` to revert to the legacy behavior where adopted stylesheet rules are\n * emitted as separate incremental events (which may be lost if delivery is unreliable).\n * Only consider opting out if snapshot payload size is a critical concern.\n *\n * @defaultValue true\n */\n captureAdoptedStyleSheets?: boolean;\n /**\n * Enables recording of cross-origin iframes. Both the parent page and each child iframe\n * page must load the Amplitude Session Replay SDK with this option enabled.\n *\n * When enabled, rrweb uses `postMessage` to relay child DOM events to the parent, which\n * merges them into a single unified event stream.\n */\n crossOriginIframes?: CrossOriginIframesConfig;\n /** Interval in ms at which the SDK takes a full DOM snapshot. Disabled by default — periodic snapshots are expensive. Recommended value: 300000 (5 min). */\n fullSnapshotIntervalMs?: number;\n /**\n * Controls how often the SDK splits buffered rrweb events into a sequence and dispatches\n * the resulting batch to the server. The interval starts at `minIntervalMs` and grows by\n * `minIntervalMs` after each split, capped at `maxIntervalMs`. Lowering values increases\n * replay availability latency improvements at the cost of more requests; raising them\n * reduces request volume (and 200+`X-Session-Replay-Event-Skipped` throttling responses)\n * at the cost of slightly delayed replay availability.\n *\n * Defaults to `{ minIntervalMs: 1000, maxIntervalMs: 10_000 }`, reflecting the validated\n * amp-on-amp perf config (SR-4646); the `minIntervalMs` default was `500` prior to that\n * change. Tune up if the server is back-pressuring the SDK on session start.\n */\n flushIntervalConfig?: FlushIntervalConfig;\n /**\n * When true, every rrweb full snapshot is flushed to the server immediately so replays\n * become playable as early as possible. When false (default), full-snapshot sends are\n * deferred to the normal interval/size flush cadence instead. The snapshot is still\n * compressed and buffered immediately either way (ordering and page-exit beacon coverage\n * are preserved); only the eager network send is suppressed. The default-off behavior\n * reduces request volume for pages that produce many full snapshots (e.g. focus-driven or\n * `fullSnapshotIntervalMs` checkouts), especially when many SDK instances run on the same\n * page.\n *\n * @defaultValue false — reflects the validated amp-on-amp perf config (SR-4646). Was `true`\n * prior to that change.\n */\n eagerFullSnapshotSend?: boolean;\n /**\n * When true, the window `focus` listener forces a fresh rrweb full snapshot\n * (`takeFullSnapshot`) every time the page regains focus, so the replay reflects any DOM\n * changes that happened while the tab was backgrounded. When false (default), the on-focus\n * full snapshot is skipped entirely (recording simply continues from the existing stream).\n *\n * On pages with heavy focus churn (e.g. embedded iframes, inline editors that repeatedly\n * steal and return focus) this fires constantly, and when combined with\n * `eagerFullSnapshotSend` each focus produces an immediate network send — the primary\n * driver of focus-driven request storms. The default-off behavior removes the snapshot (and\n * therefore the send) at the cost of slightly staler post-focus frames.\n *\n * @defaultValue false — reflects the validated amp-on-amp perf config (SR-4646). Was `true`\n * prior to that change.\n */\n captureFullSnapshotOnFocus?: boolean;\n /**\n * Raw (uncompressed) UTF-8 byte cap for a single buffered events list before the store\n * splits it into its own request. Larger values produce fewer, larger requests (the primary\n * steady-state lever for request volume); smaller values split sooner. Payloads are gzipped\n * on the wire, so several hundred KB of replay JSON compresses to well under 100 KB.\n *\n * Advanced/debug knob — the default already balances request volume against the server's\n * decompressed-size split threshold. Clamped to a safe range; values outside it are clamped\n * and logged. Defaults to the SDK's internal `DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES`.\n *\n * @defaultValue 6000000 — reflects the validated amp-on-amp perf config (SR-4646). Was\n * `MAX_EVENT_LIST_SIZE` (2000000) prior to that change.\n */\n maxPersistedEventsSizeBytes?: number;\n /**\n * Raw (uncompressed) UTF-8 byte cap for a single rrweb event. Events larger than this are\n * dropped (with a warning) both at capture time and as a pre-send backstop, because the SR\n * ingest service rejects a single event above ~10 MB. Lower this to exercise drop behavior\n * for large full snapshots while debugging.\n *\n * Advanced/debug knob. Clamped to a safe range; values outside it are clamped and logged.\n * Defaults to the SDK's internal `MAX_SINGLE_EVENT_SIZE`.\n *\n * @defaultValue 9000000\n */\n maxSingleEventSizeBytes?: number;\n}\n\nexport interface FlushIntervalConfig {\n /**\n * Lower bound on the rrweb event-split interval in milliseconds. Also the increment\n * added to the interval after each split. Must be > 0; values are clamped to a 100ms floor.\n *\n * @defaultValue 1000 — reflects the validated amp-on-amp perf config (SR-4646). Was `500`\n * prior to that change.\n */\n minIntervalMs?: number;\n /**\n * Upper bound on the rrweb event-split interval in milliseconds. Must be >= `minIntervalMs`.\n *\n * @defaultValue 10000\n */\n maxIntervalMs?: number;\n}\n\nexport interface SessionReplayJoinedConfig extends SessionReplayLocalConfig {\n captureEnabled?: boolean;\n interactionConfig?: InteractionConfig;\n loggingConfig?: LoggingConfig;\n targetingConfig?: TargetingConfig;\n minSessionDurationMs?: number;\n}\n\nexport interface SessionReplayConfigs {\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n remoteConfig: SessionReplayRemoteConfig | undefined;\n}\nexport interface SessionReplayJoinedConfigGenerator {\n generateJoinedConfig: () => Promise<SessionReplayConfigs>;\n}\n\nexport interface SessionReplayMetadata {\n remoteConfig: SessionReplayRemoteConfig | undefined;\n localConfig: SessionReplayLocalConfig;\n joinedConfig: SessionReplayJoinedConfig;\n framework?: {\n name: string;\n version: string;\n };\n sessionId: string | number | undefined;\n hashValue?: number;\n sampleRate: number;\n replaySDKType: string | null;\n replaySDKVersion: string | undefined;\n standaloneSDKType: string;\n standaloneSDKVersion: string | undefined;\n}\n\nexport interface SessionReplayVersion {\n version: string;\n type: SessionReplayType;\n}\n\n/**\n * Configuration options for session replay performance.\n */\nexport interface SessionReplayPerformanceConfig {\n /**\n * If enabled, event compression will be deferred to occur during the browser's idle periods.\n */\n enabled: boolean;\n /**\n * Optional timeout in milliseconds for the `requestIdleCallback` API.\n * If specified, this value will be used to set a maximum time for the browser to wait\n * before executing the deferred compression task, even if the browser is not idle.\n */\n timeout?: number;\n /**\n * If enabled, consecutive mutation events will be merged into a single event before\n * compression, reducing stored event count without changing replay semantics.\n * Defaults to true, reflecting the validated amp-on-amp perf config (SR-4646); set to\n * false to disable merging.\n */\n mergeMutations?: boolean;\n /**\n * Performance configuration for interaction tracking (clicks, scrolls).\n */\n interaction?: InteractionPerformanceConfig;\n}\n\n/**\n * Performance configuration for interaction tracking, specifically for CSS selector generation.\n */\nexport interface InteractionPerformanceConfig {\n /**\n * Maximum time in milliseconds allowed for CSS selector generation.\n * If selector generation takes longer than this, it will throw a timeout error.\n * Default: undefined (no timeout limit)\n */\n timeoutMs?: number;\n /**\n * Maximum number of attempts to optimize/simplify the CSS selector path.\n * Higher values may produce shorter selectors but take longer to compute.\n * Default: 10000\n */\n maxNumberOfTries?: number;\n /**\n * Maximum number of CSS selector combinations to test for uniqueness.\n * If more combinations would be generated, falls back to a simpler strategy.\n * Default: 1000\n */\n threshold?: number;\n}\n\nexport type SessionReplayType = 'standalone' | 'plugin' | 'segment';\n","import { SESSION_REPLAY_EU_URL, SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_STAGING_URL } from '../constants';\n\nexport function getServerUrl(serverZone?: string, trackServerUrl?: string): string {\n if (trackServerUrl) return trackServerUrl;\n if (serverZone === 'STAGING') return SESSION_REPLAY_STAGING_URL;\n if (serverZone === 'EU') return SESSION_REPLAY_EU_URL;\n return SESSION_REPLAY_SERVER_URL;\n}\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { DEFAULT_MASK_LEVEL, MaskLevel, PrivacyConfig, SessionReplayJoinedConfig, UGCFilterRule } from './config/types';\nimport { KB_SIZE, MASK_TEXT_CLASS, UNMASK_TEXT_CLASS } from './constants';\nimport { StorageData } from './typings/session-replay';\nimport { getInputType } from './utils/get-input-type';\nexport { getServerUrl } from './utils/server-url';\n\ntype ChromeStorageEstimate = {\n quota?: number;\n usage?: number;\n usageDetails?: { [key: string]: number };\n};\n\n/**\n * Light: Subset of inputs (sensitive types only — password, hidden, email, tel, cc-*)\n * Medium: All inputs (form fields), text is NOT masked\n * Conservative: All inputs and all texts\n */\nconst isMaskedForLevel = (elementType: 'input' | 'text', level: MaskLevel, element: HTMLElement | null): boolean => {\n switch (level) {\n case 'light': {\n if (elementType !== 'input') {\n return false;\n }\n\n const inputType = element ? getInputType(element) : '';\n /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.\n if (!inputType) {\n return false;\n }\n\n if (['password', 'hidden', 'email', 'tel'].includes(inputType)) {\n return true;\n }\n\n if ((element as HTMLInputElement).autocomplete.startsWith('cc-')) {\n return true;\n }\n\n return false;\n }\n case 'medium':\n return elementType === 'input';\n case 'conservative':\n return true;\n default:\n return isMaskedForLevel(elementType, DEFAULT_MASK_LEVEL, element);\n }\n};\n\n/**\n * Returns the effective mask level for a given URL by checking `urlMaskLevels`\n * (first match wins) and falling back to `defaultMaskLevel`.\n */\nexport const getEffectiveMaskLevel = (url: string | undefined, config: PrivacyConfig): MaskLevel => {\n if (url && config.urlMaskLevels) {\n for (const rule of config.urlMaskLevels) {\n if (globToRegex(rule.match).test(url)) {\n return rule.maskLevel;\n }\n }\n }\n return config.defaultMaskLevel ?? DEFAULT_MASK_LEVEL;\n};\n\n/**\n * Checks if the given element set to be masked by rrweb\n *\n * Priority is:\n * 1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking\n * 2. Use app defaults\n */\nexport const isMasked = (\n elementType: 'input' | 'text',\n config: PrivacyConfig = { defaultMaskLevel: DEFAULT_MASK_LEVEL },\n element: HTMLElement | null,\n currentUrl?: string,\n): boolean => {\n if (element) {\n // Element or parent is explicitly instrumented in code to mask\n if (element.closest('.' + MASK_TEXT_CLASS)) {\n return true;\n }\n\n // Config has override for mask\n const shouldMask = (config.maskSelector ?? []).some((selector) => element.closest(selector));\n if (shouldMask) {\n return true;\n }\n\n // Code or config has override to unmask\n if (element.closest('.' + UNMASK_TEXT_CLASS)) {\n return false;\n }\n\n // Here we are probably sent an element, but we want to match if they have a\n // parent with an unmask selector.\n const shouldUnmask = (config.unmaskSelector ?? []).some((selector) => element.closest(selector));\n if (shouldUnmask) {\n return false;\n }\n }\n\n return isMaskedForLevel(elementType, getEffectiveMaskLevel(currentUrl, config), element);\n};\n\nexport const maskFn =\n (elementType: 'text' | 'input', config?: PrivacyConfig, getCurrentUrl?: () => string) =>\n (text: string, element: HTMLElement | null): string => {\n return isMasked(elementType, config, element, getCurrentUrl?.()) ? text.replace(/[^\\s]/g, '*') : text;\n };\n\nexport const maskAttributeFn = (config?: PrivacyConfig, getCurrentUrl?: () => string) => {\n return (key: string, value: string, element: HTMLElement): string => {\n // Never mask style — rrweb has a separate styleDiff path for attribute mutations\n // that reads directly from the DOM, bypassing maskAttributeFn.\n if (key === 'style') return value;\n\n // Short-circuit: only proceed if this attribute is in the allowlist.\n if (!(config?.maskAttributes ?? []).includes(key)) return value;\n\n // Use 'input' for form elements so that `medium` (which masks inputs but not text)\n // still masks attributes on inputs/selects/textareas. For non-form elements, use\n // 'text' so medium leaves them visible.\n const elementType = ['INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) ? 'input' : 'text';\n return isMasked(elementType, config, element, getCurrentUrl?.()) ? value.replace(/[^\\s]/g, '*') : value;\n };\n};\n\nexport const getCurrentUrl = () => {\n const globalScope = getGlobalScope();\n return globalScope?.location ? globalScope.location.href : '';\n};\n\nexport const generateSessionReplayId = (sessionId: string | number, deviceId: string): string => {\n return `${deviceId}/${sessionId}`;\n};\n\nconst isValidGlobUrl = (globUrl: string): boolean => {\n if (typeof globUrl !== 'string' || globUrl.trim() === '') return false;\n const urlPattern = /^\\/|^https?:\\/\\/[^\\s]+$/;\n if (!urlPattern.test(globUrl)) return false;\n return true;\n};\n\nconst globRegexCache = new Map<string, RegExp>();\n\nconst globToRegex = (glob: string): RegExp => {\n const cached = globRegexCache.get(glob);\n if (cached) return cached;\n\n // Glob → regex conversion. Glob substitution must happen BEFORE regex escaping so that\n // the escaper does not corrupt the glob characters (e.g. turning `/**` into `/\\*\\*`).\n // Placeholder tokens use null bytes, which are illegal in HTTP URLs and therefore can\n // never collide with real pattern content.\n //\n // Substitution order (most-specific first):\n // trailing /** → (/.*)? — path with or without a trailing slash/subpath\n // middle /**/ → /(.*\\/)? — zero-or-more path segments (including zero)\n // bare ** → .* — graceful fallback for ** not adjacent to /\n // single * → .* — any characters (preserves existing behaviour)\n // ? → . — single character wildcard\n const T_TRAILING = '\\x00TRAIL\\x00';\n const T_MIDDLE = '\\x00MID\\x00';\n const T_DSTAR = '\\x00DS\\x00';\n const T_STAR = '\\x00ST\\x00';\n const T_QUEST = '\\x00QU\\x00';\n\n let s = glob;\n s = s.replace(/\\/\\*\\*$/, T_TRAILING); // trailing /**\n s = s.replace(/\\/\\*\\*\\//g, T_MIDDLE); // /**/ in the middle\n s = s.replace(/\\*\\*/g, T_DSTAR); // bare ** (e.g. **.example.com)\n s = s.replace(/\\*/g, T_STAR); // single *\n s = s.replace(/\\?/g, T_QUEST); // ?\n\n // Escape all remaining regex special characters.\n s = s.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Expand tokens into their regex equivalents.\n // Use split/join (not regex) to avoid the no-control-regex lint rule on the token strings.\n s = s.split(T_TRAILING).join('(/.*)?'); // /** → optional /anything\n s = s.split(T_MIDDLE).join('/(.*\\\\/)?'); // /**/ → /zero-or-more-segments/\n s = s.split(T_DSTAR).join('.*'); // bare ** → .*\n s = s.split(T_STAR).join('.*'); // * → .*\n s = s.split(T_QUEST).join('.'); // ? → .\n\n const regex = new RegExp(`^${s}$`);\n globRegexCache.set(glob, regex);\n return regex;\n};\n\nexport const validateUGCFilterRules = (ugcFilterRules: UGCFilterRule[]) => {\n // validate ugcFilterRules\n if (!ugcFilterRules.every((rule) => typeof rule.selector === 'string' && typeof rule.replacement === 'string')) {\n throw new Error('ugcFilterRules must be an array of objects with selector and replacement properties');\n }\n\n // validate ugcFilterRules are valid globs\n if (!ugcFilterRules.every((rule) => isValidGlobUrl(rule.selector))) {\n throw new Error('ugcFilterRules must be an array of objects with valid globs');\n }\n};\n\nexport const getPageUrl = (pageUrl: string, ugcFilterRules: UGCFilterRule[]) => {\n // apply ugcFilterRules, order is important, first rule wins\n for (const rule of ugcFilterRules) {\n const regex = globToRegex(rule.selector);\n\n if (regex.test(pageUrl)) {\n return pageUrl.replace(regex, rule.replacement);\n }\n }\n\n return pageUrl;\n};\n\nexport const getStorageSize = async (): Promise<StorageData> => {\n try {\n const globalScope = getGlobalScope();\n if (globalScope) {\n const { usage, quota, usageDetails }: ChromeStorageEstimate = await globalScope.navigator.storage.estimate();\n const totalStorageSize = usage ? Math.round(usage / KB_SIZE) : 0;\n const percentOfQuota = usage && quota ? Math.round((usage / quota + Number.EPSILON) * 1000) / 1000 : 0;\n return { totalStorageSize, percentOfQuota, usageDetails: JSON.stringify(usageDetails) };\n }\n } catch (e) {\n // swallow\n }\n return { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' };\n};\n\nexport const getDebugConfig = (config: SessionReplayJoinedConfig): SessionReplayJoinedConfig => {\n const debugConfig = {\n ...config,\n };\n const { apiKey } = debugConfig;\n debugConfig.apiKey = `****${apiKey.substring(apiKey.length - 4)}`;\n return debugConfig;\n};\n","export function toLowerCase<T extends string>(str: T): Lowercase<T> {\n return str.toLowerCase() as unknown as Lowercase<T>;\n}\n\n/**\n * Get the type of an input element.\n * This takes care of the case where a password input is changed to a text input.\n * In this case, we continue to consider this of type password, in order to avoid leaking sensitive data\n * where passwords should be masked.\n */\nexport function getInputType(element: HTMLElement): Lowercase<string> | null {\n // when omitting the type of input element(e.g. <input />), the type is treated as text\n const type = (element as HTMLInputElement).type;\n\n return element.hasAttribute('data-rr-is-password')\n ? 'password'\n : type\n ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n toLowerCase(type)\n : null;\n}\n","import {\n Config,\n ILogger,\n Logger,\n FetchTransport,\n LogLevel,\n IDiagnosticsClient,\n DiagnosticsClient,\n} from '@amplitude/analytics-core';\nimport {\n DEFAULT_FLUSH_MAX_INTERVAL_MS,\n DEFAULT_FLUSH_MIN_INTERVAL_MS,\n DEFAULT_PERFORMANCE_CONFIG,\n DEFAULT_SAMPLE_RATE,\n DEFAULT_SERVER_ZONE,\n DEFAULT_URL_CHANGE_POLLING_INTERVAL,\n MAX_INTERVAL,\n MIN_INTERVAL,\n UNMASK_TEXT_CLASS,\n} from '../constants';\nimport { SessionReplayOptions, StoreType } from '../typings/session-replay';\nimport {\n SessionReplayLocalConfig as ISessionReplayLocalConfig,\n CrossOriginIframesConfig,\n FlushIntervalConfig,\n InteractionConfig,\n PrivacyConfig,\n SessionReplayPerformanceConfig,\n SessionReplayVersion,\n} from './types';\nimport { SafeLoggerProvider } from '../logger';\nimport { validateUGCFilterRules } from '../helpers';\n\nexport const getDefaultConfig = () => ({\n flushMaxRetries: 2,\n logLevel: LogLevel.Warn,\n loggerProvider: new Logger(),\n transportProvider: new FetchTransport(),\n});\n\nexport class SessionReplayLocalConfig extends Config implements ISessionReplayLocalConfig {\n apiKey: string;\n sampleRate: number;\n privacyConfig?: PrivacyConfig;\n interactionConfig?: InteractionConfig;\n debugMode?: boolean;\n configServerUrl?: string;\n trackServerUrl?: string;\n shouldInlineStylesheet?: boolean;\n version?: SessionReplayVersion;\n storeType: StoreType;\n performanceConfig?: SessionReplayPerformanceConfig;\n useWebWorker?: boolean;\n enableTransportCompression?: boolean;\n sendTimeoutMs?: number;\n applyBackgroundColorToBlockedElements?: boolean;\n enableUrlChangePolling?: boolean;\n urlChangePollingInterval?: number;\n captureDocumentTitle?: boolean;\n captureAdoptedStyleSheets?: boolean;\n crossOriginIframes?: CrossOriginIframesConfig;\n fullSnapshotIntervalMs?: number;\n flushIntervalConfig?: FlushIntervalConfig;\n eagerFullSnapshotSend?: boolean;\n captureFullSnapshotOnFocus?: boolean;\n maxPersistedEventsSizeBytes?: number;\n maxSingleEventSizeBytes?: number;\n diagnosticsClient?: IDiagnosticsClient;\n diagnosticsEnabled?: boolean;\n diagnosticsSampleRate?: number;\n\n constructor(apiKey: string, options: SessionReplayOptions) {\n const defaultConfig = getDefaultConfig();\n super({\n transportProvider: defaultConfig.transportProvider,\n loggerProvider: new SafeLoggerProvider(options.loggerProvider || defaultConfig.loggerProvider),\n ...options,\n apiKey,\n });\n this.flushMaxRetries =\n options.flushMaxRetries !== undefined && options.flushMaxRetries <= defaultConfig.flushMaxRetries\n ? options.flushMaxRetries\n : defaultConfig.flushMaxRetries;\n\n this.apiKey = apiKey;\n this.sampleRate = options.sampleRate || DEFAULT_SAMPLE_RATE;\n this.serverZone = options.serverZone || DEFAULT_SERVER_ZONE;\n this.configServerUrl = options.configServerUrl;\n this.trackServerUrl = options.trackServerUrl;\n this.shouldInlineStylesheet = options.shouldInlineStylesheet;\n this.version = options.version;\n this.performanceConfig = options.performanceConfig || DEFAULT_PERFORMANCE_CONFIG;\n this.storeType = options.storeType ?? 'memory';\n this.applyBackgroundColorToBlockedElements = options.applyBackgroundColorToBlockedElements ?? false;\n this.enableUrlChangePolling = options.enableUrlChangePolling ?? false;\n this.urlChangePollingInterval = options.urlChangePollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n this.captureDocumentTitle = options.captureDocumentTitle ?? false;\n if (options.fullSnapshotIntervalMs !== undefined) {\n this.fullSnapshotIntervalMs = options.fullSnapshotIntervalMs;\n }\n if (options.eagerFullSnapshotSend !== undefined) {\n this.eagerFullSnapshotSend = options.eagerFullSnapshotSend;\n }\n // Defaults to false per the validated amp-on-amp perf config (SR-4646): the on-focus full\n // snapshot is off unless the consumer explicitly opts in. focusListener honors this by\n // skipping the snapshot whenever the value is not true.\n this.captureFullSnapshotOnFocus = options.captureFullSnapshotOnFocus ?? false;\n if (options.maxPersistedEventsSizeBytes !== undefined) {\n this.maxPersistedEventsSizeBytes = sanitizeByteSize(\n options.maxPersistedEventsSizeBytes,\n MIN_EVENT_BYTE_SIZE,\n MAX_PERSISTED_EVENTS_SIZE_CEILING,\n 'maxPersistedEventsSizeBytes',\n this.loggerProvider,\n );\n }\n if (options.maxSingleEventSizeBytes !== undefined) {\n this.maxSingleEventSizeBytes = sanitizeByteSize(\n options.maxSingleEventSizeBytes,\n MIN_EVENT_BYTE_SIZE,\n MAX_SINGLE_EVENT_SIZE_CEILING,\n 'maxSingleEventSizeBytes',\n this.loggerProvider,\n );\n }\n\n // Auto-include .amp-unmask as a default unmaskSelector entry so it works\n // symmetrically with amp-mask/amp-block without requiring explicit config (SR-2945).\n this.privacyConfig = {\n ...(options.privacyConfig ?? {}),\n unmaskSelector: Array.from(new Set([`.${UNMASK_TEXT_CLASS}`, ...(options.privacyConfig?.unmaskSelector ?? [])])),\n };\n if (options.interactionConfig) {\n this.interactionConfig = options.interactionConfig;\n\n // validate ugcFilterRules, throw error if invalid - throw error at the beginning of the config\n if (this.interactionConfig.ugcFilterRules) {\n validateUGCFilterRules(this.interactionConfig.ugcFilterRules);\n }\n }\n if (options.debugMode) {\n this.debugMode = options.debugMode;\n }\n // Support both new useWebWorker and legacy experimental.useWebWorker for backwards\n // compatibility. Defaults to true per the validated amp-on-amp perf config (SR-4646):\n // compression runs off the main thread unless the consumer explicitly sets either flag\n // to false. The top-level option wins over the legacy experimental one when both are set.\n const legacyOptions = options as { experimental?: { useWebWorker?: boolean } };\n this.useWebWorker = options.useWebWorker ?? legacyOptions.experimental?.useWebWorker ?? true;\n this.enableTransportCompression = options.enableTransportCompression ?? true;\n // Pass through undefined so the track destination applies its SEND_TIMEOUT_MS default;\n // an explicit 0 is preserved (disables the timeout).\n this.sendTimeoutMs = options.sendTimeoutMs;\n this.captureAdoptedStyleSheets = options.captureAdoptedStyleSheets ?? true;\n if (options.crossOriginIframes) {\n this.crossOriginIframes = options.crossOriginIframes;\n }\n if (options.flushIntervalConfig) {\n this.flushIntervalConfig = sanitizeFlushIntervalConfig(options.flushIntervalConfig, this.loggerProvider);\n } else {\n // Default to the validated amp-on-amp perf config (SR-4646). The values are known-valid\n // (min <= max, both above the floor), so no sanitization is required.\n this.flushIntervalConfig = {\n minIntervalMs: DEFAULT_FLUSH_MIN_INTERVAL_MS,\n maxIntervalMs: DEFAULT_FLUSH_MAX_INTERVAL_MS,\n };\n }\n this.diagnosticsEnabled = options.diagnosticsEnabled;\n this.diagnosticsSampleRate = options.diagnosticsSampleRate;\n // Single diagnostics client: in plugin mode the analytics SDK passes its own client in\n // (reused, not duplicated). Standalone SR has no analytics SDK, so create one here — but only\n // when explicitly opted in, to avoid imposing IndexedDB + flush-timer overhead on standalone\n // users who don't want diagnostics.\n this.diagnosticsClient = options.diagnosticsClient ?? this.createStandaloneDiagnosticsClient(apiKey, options);\n }\n\n private createStandaloneDiagnosticsClient(\n apiKey: string,\n options: SessionReplayOptions,\n ): IDiagnosticsClient | undefined {\n const { diagnosticsEnabled, diagnosticsSampleRate } = options;\n const optedIn =\n diagnosticsEnabled === true || (typeof diagnosticsSampleRate === 'number' && diagnosticsSampleRate > 0);\n if (!optedIn) {\n return undefined;\n }\n return new DiagnosticsClient(apiKey, this.loggerProvider, this.serverZone, {\n enabled: diagnosticsEnabled ?? true,\n sampleRate: diagnosticsSampleRate ?? 0,\n });\n }\n}\n\n// 100ms floor avoids degenerate configs (0/negative) that would split on every event.\n// Customers wanting fewer requests should be raising the value, not lowering it; the floor\n// is just a defensive guard against typos and unsigned-int rollovers.\nconst MIN_FLUSH_INTERVAL_FLOOR_MS = 100;\n\n// Shared 1 KB floor for the byte-size overrides — small enough to exercise splitting/drops\n// while debugging, large enough to avoid a 0/negative config that splits on every event.\nconst MIN_EVENT_BYTE_SIZE = 1_000;\n// Batch cap ceiling: stay under the SR ingest service's 10 MB decompressed split threshold\n// (above which the server splits the batch itself) with headroom for the request wrapper.\nconst MAX_PERSISTED_EVENTS_SIZE_CEILING = 8_000_000;\n// Single-event ceiling: the server rejects a single event above ~10 MB, so never allow an\n// override to exceed that.\nconst MAX_SINGLE_EVENT_SIZE_CEILING = 10_000_000;\n\n// Defensive bounds for the byte-size overrides. Non-finite inputs are ignored (fall back to\n// the SDK default); out-of-range values are clamped and logged so a typo can't silently\n// disable splitting or push past the server's limits.\nfunction sanitizeByteSize(\n raw: number,\n min: number,\n max: number,\n name: string,\n loggerProvider: ILogger,\n): number | undefined {\n if (!Number.isFinite(raw)) {\n loggerProvider.warn(`${name} value is not a finite number (got ${String(raw)}); ignoring.`);\n return undefined;\n }\n if (raw < min) {\n loggerProvider.warn(`${name} ${raw} is below floor ${min}; clamping.`);\n return min;\n }\n if (raw > max) {\n loggerProvider.warn(`${name} ${raw} exceeds ceiling ${max}; clamping.`);\n return max;\n }\n return raw;\n}\n\nfunction sanitizeFlushIntervalConfig(raw: FlushIntervalConfig, loggerProvider: ILogger): FlushIntervalConfig {\n const sanitized: FlushIntervalConfig = {};\n if (raw.minIntervalMs !== undefined) {\n if (!Number.isFinite(raw.minIntervalMs) || raw.minIntervalMs < MIN_FLUSH_INTERVAL_FLOOR_MS) {\n loggerProvider.warn(\n `flushIntervalConfig.minIntervalMs ${raw.minIntervalMs} is below floor ${MIN_FLUSH_INTERVAL_FLOOR_MS}ms; clamping.`,\n );\n sanitized.minIntervalMs = MIN_FLUSH_INTERVAL_FLOOR_MS;\n } else {\n sanitized.minIntervalMs = raw.minIntervalMs;\n }\n }\n if (raw.maxIntervalMs !== undefined) {\n // Unlike min, `Infinity` is a meaningful value here: it means \"no upper bound on interval\n // growth\" (Math.min(Infinity, x) === x in BaseEventsStore.shouldSplitEventsList). Reject\n // only NaN and sub-floor values; pass Infinity through.\n if (Number.isNaN(raw.maxIntervalMs) || raw.maxIntervalMs < MIN_FLUSH_INTERVAL_FLOOR_MS) {\n loggerProvider.warn(\n `flushIntervalConfig.maxIntervalMs ${raw.maxIntervalMs} is below floor ${MIN_FLUSH_INTERVAL_FLOOR_MS}ms; clamping.`,\n );\n sanitized.maxIntervalMs = MIN_FLUSH_INTERVAL_FLOOR_MS;\n } else {\n sanitized.maxIntervalMs = raw.maxIntervalMs;\n }\n }\n // Cross-validate against the SDK's effective defaults so that a partial config (only one of\n // {minIntervalMs, maxIntervalMs}) doesn't get silently clamped by the unspecified default.\n // Concrete failure mode without this: customer sets only `minIntervalMs: 30_000`, the store's\n // `maxInterval` falls back to `MAX_INTERVAL = 10_000`, and `shouldSplitEventsList` then\n // caps the effective interval at 10s — silently negating the customer's tune-up.\n // The user-supplied value always wins; we fill in the other side to match.\n if (sanitized.minIntervalMs !== undefined || sanitized.maxIntervalMs !== undefined) {\n const effectiveMin = sanitized.minIntervalMs ?? MIN_INTERVAL;\n const effectiveMax = sanitized.maxIntervalMs ?? MAX_INTERVAL;\n if (effectiveMax < effectiveMin) {\n if (sanitized.maxIntervalMs === undefined) {\n loggerProvider.warn(\n `flushIntervalConfig.minIntervalMs (${effectiveMin}) exceeds the default maxIntervalMs (${MAX_INTERVAL}); raising max to match min.`,\n );\n sanitized.maxIntervalMs = effectiveMin;\n } else if (sanitized.minIntervalMs === undefined) {\n loggerProvider.warn(\n `flushIntervalConfig.maxIntervalMs (${effectiveMax}) is below the default minIntervalMs (${MIN_INTERVAL}); lowering min to match max.`,\n );\n sanitized.minIntervalMs = effectiveMax;\n } else {\n loggerProvider.warn(\n `flushIntervalConfig.maxIntervalMs (${sanitized.maxIntervalMs}) is less than minIntervalMs (${sanitized.minIntervalMs}); raising max to match min.`,\n );\n sanitized.maxIntervalMs = sanitized.minIntervalMs;\n }\n }\n }\n return sanitized;\n}\n","var EventType = /* @__PURE__ */ ((EventType2) => {\n EventType2[EventType2[\"DomContentLoaded\"] = 0] = \"DomContentLoaded\";\n EventType2[EventType2[\"Load\"] = 1] = \"Load\";\n EventType2[EventType2[\"FullSnapshot\"] = 2] = \"FullSnapshot\";\n EventType2[EventType2[\"IncrementalSnapshot\"] = 3] = \"IncrementalSnapshot\";\n EventType2[EventType2[\"Meta\"] = 4] = \"Meta\";\n EventType2[EventType2[\"Custom\"] = 5] = \"Custom\";\n EventType2[EventType2[\"Plugin\"] = 6] = \"Plugin\";\n return EventType2;\n})(EventType || {});\nvar IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {\n IncrementalSource2[IncrementalSource2[\"Mutation\"] = 0] = \"Mutation\";\n IncrementalSource2[IncrementalSource2[\"MouseMove\"] = 1] = \"MouseMove\";\n IncrementalSource2[IncrementalSource2[\"MouseInteraction\"] = 2] = \"MouseInteraction\";\n IncrementalSource2[IncrementalSource2[\"Scroll\"] = 3] = \"Scroll\";\n IncrementalSource2[IncrementalSource2[\"ViewportResize\"] = 4] = \"ViewportResize\";\n IncrementalSource2[IncrementalSource2[\"Input\"] = 5] = \"Input\";\n IncrementalSource2[IncrementalSource2[\"TouchMove\"] = 6] = \"TouchMove\";\n IncrementalSource2[IncrementalSource2[\"MediaInteraction\"] = 7] = \"MediaInteraction\";\n IncrementalSource2[IncrementalSource2[\"StyleSheetRule\"] = 8] = \"StyleSheetRule\";\n IncrementalSource2[IncrementalSource2[\"CanvasMutation\"] = 9] = \"CanvasMutation\";\n IncrementalSource2[IncrementalSource2[\"Font\"] = 10] = \"Font\";\n IncrementalSource2[IncrementalSource2[\"Log\"] = 11] = \"Log\";\n IncrementalSource2[IncrementalSource2[\"Drag\"] = 12] = \"Drag\";\n IncrementalSource2[IncrementalSource2[\"StyleDeclaration\"] = 13] = \"StyleDeclaration\";\n IncrementalSource2[IncrementalSource2[\"Selection\"] = 14] = \"Selection\";\n IncrementalSource2[IncrementalSource2[\"AdoptedStyleSheet\"] = 15] = \"AdoptedStyleSheet\";\n IncrementalSource2[IncrementalSource2[\"CustomElement\"] = 16] = \"CustomElement\";\n return IncrementalSource2;\n})(IncrementalSource || {});\nvar MouseInteractions = /* @__PURE__ */ ((MouseInteractions2) => {\n MouseInteractions2[MouseInteractions2[\"MouseUp\"] = 0] = \"MouseUp\";\n MouseInteractions2[MouseInteractions2[\"MouseDown\"] = 1] = \"MouseDown\";\n MouseInteractions2[MouseInteractions2[\"Click\"] = 2] = \"Click\";\n MouseInteractions2[MouseInteractions2[\"ContextMenu\"] = 3] = \"ContextMenu\";\n MouseInteractions2[MouseInteractions2[\"DblClick\"] = 4] = \"DblClick\";\n MouseInteractions2[MouseInteractions2[\"Focus\"] = 5] = \"Focus\";\n MouseInteractions2[MouseInteractions2[\"Blur\"] = 6] = \"Blur\";\n MouseInteractions2[MouseInteractions2[\"TouchStart\"] = 7] = \"TouchStart\";\n MouseInteractions2[MouseInteractions2[\"TouchMove_Departed\"] = 8] = \"TouchMove_Departed\";\n MouseInteractions2[MouseInteractions2[\"TouchEnd\"] = 9] = \"TouchEnd\";\n MouseInteractions2[MouseInteractions2[\"TouchCancel\"] = 10] = \"TouchCancel\";\n return MouseInteractions2;\n})(MouseInteractions || {});\nvar PointerTypes = /* @__PURE__ */ ((PointerTypes2) => {\n PointerTypes2[PointerTypes2[\"Mouse\"] = 0] = \"Mouse\";\n PointerTypes2[PointerTypes2[\"Pen\"] = 1] = \"Pen\";\n PointerTypes2[PointerTypes2[\"Touch\"] = 2] = \"Touch\";\n return PointerTypes2;\n})(PointerTypes || {});\nvar CanvasContext = /* @__PURE__ */ ((CanvasContext2) => {\n CanvasContext2[CanvasContext2[\"2D\"] = 0] = \"2D\";\n CanvasContext2[CanvasContext2[\"WebGL\"] = 1] = \"WebGL\";\n CanvasContext2[CanvasContext2[\"WebGL2\"] = 2] = \"WebGL2\";\n return CanvasContext2;\n})(CanvasContext || {});\nvar MediaInteractions = /* @__PURE__ */ ((MediaInteractions2) => {\n MediaInteractions2[MediaInteractions2[\"Play\"] = 0] = \"Play\";\n MediaInteractions2[MediaInteractions2[\"Pause\"] = 1] = \"Pause\";\n MediaInteractions2[MediaInteractions2[\"Seeked\"] = 2] = \"Seeked\";\n MediaInteractions2[MediaInteractions2[\"VolumeChange\"] = 3] = \"VolumeChange\";\n MediaInteractions2[MediaInteractions2[\"RateChange\"] = 4] = \"RateChange\";\n return MediaInteractions2;\n})(MediaInteractions || {});\nvar ReplayerEvents = /* @__PURE__ */ ((ReplayerEvents2) => {\n ReplayerEvents2[\"Start\"] = \"start\";\n ReplayerEvents2[\"Pause\"] = \"pause\";\n ReplayerEvents2[\"Resume\"] = \"resume\";\n ReplayerEvents2[\"Resize\"] = \"resize\";\n ReplayerEvents2[\"Finish\"] = \"finish\";\n ReplayerEvents2[\"FullsnapshotRebuilded\"] = \"fullsnapshot-rebuilded\";\n ReplayerEvents2[\"LoadStylesheetStart\"] = \"load-stylesheet-start\";\n ReplayerEvents2[\"LoadStylesheetEnd\"] = \"load-stylesheet-end\";\n ReplayerEvents2[\"SkipStart\"] = \"skip-start\";\n ReplayerEvents2[\"SkipEnd\"] = \"skip-end\";\n ReplayerEvents2[\"MouseInteraction\"] = \"mouse-interaction\";\n ReplayerEvents2[\"EventCast\"] = \"event-cast\";\n ReplayerEvents2[\"CustomEvent\"] = \"custom-event\";\n ReplayerEvents2[\"Flush\"] = \"flush\";\n ReplayerEvents2[\"StateChange\"] = \"state-change\";\n ReplayerEvents2[\"PlayBack\"] = \"play-back\";\n ReplayerEvents2[\"Destroy\"] = \"destroy\";\n ReplayerEvents2[\"SeekStart\"] = \"seek-start\";\n ReplayerEvents2[\"SeekEnd\"] = \"seek-end\";\n return ReplayerEvents2;\n})(ReplayerEvents || {});\nvar NodeType = /* @__PURE__ */ ((NodeType2) => {\n NodeType2[NodeType2[\"Document\"] = 0] = \"Document\";\n NodeType2[NodeType2[\"DocumentType\"] = 1] = \"DocumentType\";\n NodeType2[NodeType2[\"Element\"] = 2] = \"Element\";\n NodeType2[NodeType2[\"Text\"] = 3] = \"Text\";\n NodeType2[NodeType2[\"CDATA\"] = 4] = \"CDATA\";\n NodeType2[NodeType2[\"Comment\"] = 5] = \"Comment\";\n return NodeType2;\n})(NodeType || {});\nexport {\n CanvasContext,\n EventType,\n IncrementalSource,\n MediaInteractions,\n MouseInteractions,\n NodeType,\n PointerTypes,\n ReplayerEvents\n};\n//# sourceMappingURL=rrweb-types.js.map\n","/**\n * Centralized names for Session Replay diagnostics shipped via the analytics DiagnosticsClient.\n *\n * Every name shares SR_DIAGNOSTIC_PREFIX so they group together in DataDog as\n * `sdk.diagnostics.sr.trc.*`. The diagnostics pipeline prepends `sdk.diagnostics.` and appends\n * `.count` to counters / `.{min,max,avg,count}` to histograms; events are forwarded to DataDog\n * Logs keyed by `event_name`. Keep ALL SR diagnostic names here so the prefix stays unified —\n * changing the namespace is then a one-line edit.\n */\nexport const SR_DIAGNOSTIC_PREFIX = 'sr.trc';\n\nconst p = SR_DIAGNOSTIC_PREFIX;\n\nexport const SrDiagnostic = {\n // ── Init (Q1: did init even happen?) ─────────────────────────────────────\n init: `${p}.init`, // counter + event(with props): fires once per init()\n\n // ── Session lifecycle ────────────────────────────────────────────────────\n // SR session id changed (timeout / explicit setSessionId / custom session id). New tabs and\n // page refreshes do NOT change the session id, so this is distinct from a fresh init.\n sessionChanged: `${p}.session.changed`, // event (with from/to)\n\n // ── Remote config fetch (joined-config) ──────────────────────────────────\n configSource: (source: string) => `${p}.config.source.${source}`,\n configHasTargeting: `${p}.config.has_targeting`,\n configNoTargeting: `${p}.config.no_targeting`,\n configFetchFailed: `${p}.config.fetch_failed`,\n configReceived: `${p}.config.received`, // event (with props)\n\n targetingTrigger: `${p}.targeting.trigger`, // event: targeting evaluation triggered\n\n // ── Targeting evaluation (evaluateTargetingAndCapture) ────────────────────\n // Q2 (did eval run?), Q3 (working/failed?), Q4 (missing value?), Q5 (all params).\n evalTrigger: (trigger: string) => `${p}.eval.${trigger}`, // init | urlchange | event\n evalNoConfig: `${p}.eval.no_config`,\n evalMissingPrereq: `${p}.eval.missing_prereq`, // Q4: sessionId/config/deviceId missing\n evalMatch: `${p}.eval.match`,\n evalNoMatch: `${p}.eval.no_match`,\n evalError: `${p}.eval.error`, // Q3: targeting engine threw\n evalStaleDiscarded: `${p}.eval.stale_discarded`,\n evalSkippedAlreadyMatched: `${p}.eval.skipped_already_matched`,\n evalDurationMs: `${p}.eval.duration_ms`, // histogram\n evalEvent: `${p}.eval`, // event (with ALL eval params — Q5)\n evalResult: `${p}.eval.result`, // event: raw engine verdict (variantKey) — why match/no-match\n\n // ── Recording execution (getShouldRecord said yes — did rrweb actually start?) ──\n recordStarted: `${p}.record.started`, // event: capture began (carries the srId the replay uploads under)\n recordNoRecordFn: `${p}.record.no_record_fn`, // counter + event: rrweb import returned nothing\n sendSuppressedMinDuration: `${p}.send.suppressed_min_duration`, // counter: events held back by min_session_duration\n\n // ── Record / no-record gate (getShouldRecord) ────────────────────────────\n gateNoIdentifiers: `${p}.gate.no_identifiers`, // Q4: no config/sessionId at gate time\n gateCaptureDisabled: `${p}.gate.capture_disabled`,\n gateOptOut: `${p}.gate.optout`,\n gateTrcMatch: `${p}.gate.trc_match`,\n gateTrcNoMatch: `${p}.gate.trc_no_match`,\n gateSampleIn: `${p}.gate.sample_in`,\n gateSampleOut: `${p}.gate.sample_out`,\n decision: `${p}.decision`, // event (with props)\n\n // ── SPA URL change (setupUrlChangeListener) ──────────────────────────────\n urlChange: `${p}.url_change`,\n urlChangeEvent: `${p}.url_change`, // event (with props); same name, logs vs metric\n // Was the URL-change listener even wired up? (covers \"the SDK never saw any navigation\"\n // because the listener was never attached — e.g. no targeting config, or no global scope.)\n urlListenerSetup: `${p}.url_listener.setup`, // event: the needsUrlTracking decision + its inputs\n urlListenerAttached: `${p}.url_listener.attached`, // event: subscribeToUrlChanges succeeded (with polling opts)\n urlListenerSkipped: `${p}.url_listener.skipped`, // counter + event: listener NOT attached (with reason)\n // Proof the polling loop actually FIRES (not just that it was scheduled by url_listener.attached).\n urlPollTick: `${p}.url_poll.tick`, // counter: incremented every poll tick (aggregated metric, cheap)\n urlPollFirstTick: `${p}.url_poll.first_tick`, // event: once per session on the first tick (carries href)\n} as const;\n","import { ILogger, IRemoteConfigClient, RemoteConfigClient, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport { getDebugConfig } from '../helpers';\nimport { SrDiagnostic } from '../diagnostics';\nimport { SessionReplayOptions } from '../typings/session-replay';\nimport { SessionReplayLocalConfig } from './local-config';\nimport {\n SessionReplayLocalConfig as ISessionReplayLocalConfig,\n PrivacyConfig,\n SessionReplayConfigs,\n SessionReplayJoinedConfig,\n SessionReplayRemoteConfig,\n} from './types';\n\n// Budget for waiting on the remote config response before falling back to the local cache.\n// The inner fetch in analytics-core uses a 1000ms per-attempt AbortController timeout with\n// up to 3 retries — but this outer timeout is the only thing the SR plugin waits on, so\n// only the first attempt can possibly complete in time (attempt 2 starts at ~1000-1333ms\n// after backoff jitter and runs to ~2000-2333ms, well past any reasonable outer budget).\n// 1500ms is set above the 1000ms inner abort to avoid a tie with the inner cutoff and\n// give the first attempt's resolution path room to finish; everything else falls through\n// to the cache fallback. See SR-4234: prefer remote over a stale cache that would\n// otherwise win the synchronous race in 'all' mode.\nconst REMOTE_CONFIG_TIMEOUT_MS = 1500;\n\nexport const removeInvalidSelectorsFromPrivacyConfig = (privacyConfig: PrivacyConfig, loggerProvider: ILogger) => {\n // This allows us to not search the DOM.\n const fragment = document.createDocumentFragment();\n\n const dropInvalidSelectors = (selectors: string[] | string = []): string[] | undefined => {\n if (typeof selectors === 'string') {\n selectors = [selectors];\n }\n selectors = selectors.filter((selector: string) => {\n try {\n fragment.querySelector(selector);\n } catch {\n loggerProvider.warn(`[session-replay-browser] omitting selector \"${selector}\" because it is invalid`);\n return false;\n }\n return true;\n });\n if (selectors.length === 0) {\n return undefined;\n }\n return selectors;\n };\n privacyConfig.blockSelector = dropInvalidSelectors(privacyConfig.blockSelector);\n privacyConfig.maskSelector = dropInvalidSelectors(privacyConfig.maskSelector);\n privacyConfig.unmaskSelector = dropInvalidSelectors(privacyConfig.unmaskSelector);\n return privacyConfig;\n};\nexport class SessionReplayJoinedConfigGenerator {\n private readonly localConfig: ISessionReplayLocalConfig;\n private readonly remoteConfigClient: IRemoteConfigClient;\n // Identity for diagnostics correlation (config fetch is per-session). Sourced from init options.\n private readonly sessionId?: string | number;\n private readonly deviceId?: string;\n\n constructor(\n remoteConfigClient: IRemoteConfigClient,\n localConfig: ISessionReplayLocalConfig,\n identity?: { sessionId?: string | number; deviceId?: string },\n ) {\n this.localConfig = localConfig;\n this.remoteConfigClient = remoteConfigClient;\n this.sessionId = identity?.sessionId;\n this.deviceId = identity?.deviceId;\n }\n\n async generateJoinedConfig(): Promise<SessionReplayConfigs> {\n const config: SessionReplayJoinedConfig = { ...this.localConfig };\n // Special case here as optOut is implemented via getter/setter\n config.optOut = this.localConfig.optOut;\n // We always want captureEnabled to be true, unless there's an override\n // in the remote config.\n config.captureEnabled = true;\n let sessionReplayRemoteConfig: SessionReplayRemoteConfig | undefined;\n\n try {\n // Subscribe with a timeout so the SDK prefers the remote response and only falls back\n // to cache after the budget elapses. 'all' mode would race a synchronous cache read\n // against the network and resolve on whichever fires first — cache always wins, so a\n // stale cache silently overrides the live config (SR-4234).\n await new Promise<void>((resolve, reject) => {\n this.remoteConfigClient.subscribe(\n 'configs.sessionReplay',\n { timeout: REMOTE_CONFIG_TIMEOUT_MS },\n (remoteConfig: RemoteConfig | null, source: Source) => {\n this.localConfig.loggerProvider.debug(\n `Session Replay remote configuration received from ${source}:`,\n JSON.stringify(remoteConfig, null, 2),\n );\n\n if (!remoteConfig) {\n reject(new Error('No remote config received'));\n return;\n }\n\n // remoteConfig is already filtered to 'configs.sessionReplay' namespace\n const namespaceConfig = remoteConfig as SessionReplayRemoteConfig;\n const samplingConfig = namespaceConfig.sr_sampling_config;\n const privacyConfig = namespaceConfig.sr_privacy_config;\n const targetingConfig = namespaceConfig.sr_targeting_config;\n\n // Captured for the sr.trc.config.received diagnostics event below (remote vs cache is\n // the crux of SR-4234 stale-cache reports).\n const samplingForLog = samplingConfig as { capture_enabled?: boolean; sample_rate?: number } | undefined;\n const targetingSegments = (targetingConfig as unknown as { segments?: unknown[] } | undefined)?.segments;\n\n const ugcFilterRules = config.interactionConfig?.ugcFilterRules;\n // This is intentionally forced to only be set through the remote config.\n config.interactionConfig = namespaceConfig.sr_interaction_config;\n if (config.interactionConfig && ugcFilterRules) {\n config.interactionConfig.ugcFilterRules = ugcFilterRules;\n }\n\n // This is intentionally forced to only be set through the remote config.\n config.loggingConfig = namespaceConfig.sr_logging_config;\n\n // Team-visible diagnostics: which SOURCE the config came from (remote vs cache — the\n // crux of SR-4234) and whether targeting was present. Counters aggregate across the\n // customer's sessions; the event carries the full context (source, sample rate,\n // segment count) as queryable log fields. No-op when diagnostics isn't configured.\n try {\n const diagnosticsClient = this.localConfig.diagnosticsClient;\n diagnosticsClient?.increment(SrDiagnostic.configSource(String(source)));\n diagnosticsClient?.increment(\n targetingConfig ? SrDiagnostic.configHasTargeting : SrDiagnostic.configNoTargeting,\n );\n diagnosticsClient?.recordEvent(SrDiagnostic.configReceived, {\n sessionId: this.sessionId,\n deviceId: this.deviceId,\n srId:\n this.deviceId != null && this.sessionId != null ? `${this.deviceId}/${this.sessionId}` : undefined,\n source: String(source),\n hasSampling: !!samplingConfig,\n captureEnabled: samplingForLog?.capture_enabled,\n sampleRate: samplingForLog?.sample_rate,\n hasTargeting: !!targetingConfig,\n targetingSegmentCount: Array.isArray(targetingSegments) ? targetingSegments.length : undefined,\n hasPrivacy: !!privacyConfig,\n });\n // Flush now (vs the client's ~5-min timer). One capture POST per event — higher\n // volume; revisit/gate before production.\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n\n if (samplingConfig || privacyConfig || targetingConfig) {\n sessionReplayRemoteConfig = {};\n if (samplingConfig) {\n sessionReplayRemoteConfig.sr_sampling_config = samplingConfig;\n }\n if (privacyConfig) {\n sessionReplayRemoteConfig.sr_privacy_config = privacyConfig;\n }\n if (targetingConfig) {\n sessionReplayRemoteConfig.sr_targeting_config = targetingConfig;\n }\n }\n\n resolve();\n },\n );\n });\n } catch (error) {\n this.localConfig.loggerProvider.error('Failed to generate joined config: ', error);\n try {\n this.localConfig.diagnosticsClient?.increment(SrDiagnostic.configFetchFailed);\n void this.localConfig.diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n config.captureEnabled = false;\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: undefined,\n };\n }\n\n if (!sessionReplayRemoteConfig) {\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n\n const {\n sr_sampling_config: samplingConfig,\n sr_privacy_config: remotePrivacyConfig,\n sr_targeting_config: targetingConfig,\n } = sessionReplayRemoteConfig;\n if (samplingConfig && Object.keys(samplingConfig).length > 0) {\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) {\n config.captureEnabled = samplingConfig.capture_enabled;\n } else {\n config.captureEnabled = false;\n }\n\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'sample_rate')) {\n config.sampleRate = samplingConfig.sample_rate;\n }\n\n if (Object.prototype.hasOwnProperty.call(samplingConfig, 'min_session_duration_ms')) {\n config.minSessionDurationMs = this.sanitizeMinSessionDurationMs(samplingConfig.min_session_duration_ms);\n }\n } else {\n // If config API response was valid (ie 200), but no config returned, assume that\n // customer has not yet set up config, and use sample rate from SDK options,\n // allowing for immediate replay capture\n config.captureEnabled = true;\n this.localConfig.loggerProvider.debug(\n 'Remote config successfully fetched, but no values set for project, Session Replay capture enabled.',\n );\n }\n\n // Remote config join acts somewhat like a left join between the remote and the local\n // config. That is, remote config has precedence over local values as with sampling.\n // However, non conflicting values will be added to the lists.\n // Here's an example to illustrate:\n //\n // Remote config: {'.selector1': 'MASK', '.selector2': 'UNMASK'}\n // Local config: {'.selector1': 'UNMASK', '.selector3': 'MASK'}\n //\n // Resolved config: {'.selector1': 'MASK', '.selector2': 'UNMASK', '.selector3': 'MASK'}\n // config.privacyConfig = {\n // ...(config.privacyConfig ?? {}),\n // ...remotePrivacyConfig,\n // };\n\n if (remotePrivacyConfig) {\n const localPrivacyConfig: PrivacyConfig = config.privacyConfig ?? {};\n\n const joinedPrivacyConfig: Required<PrivacyConfig> & { blockSelector: string[] } = {\n defaultMaskLevel: remotePrivacyConfig.defaultMaskLevel ?? localPrivacyConfig.defaultMaskLevel ?? 'medium',\n blockSelector: [],\n maskSelector: [],\n unmaskSelector: [],\n maskAttributes: [\n ...new Set([...(localPrivacyConfig.maskAttributes ?? []), ...(remotePrivacyConfig.maskAttributes ?? [])]),\n ],\n urlMaskLevels: [...(remotePrivacyConfig.urlMaskLevels ?? []), ...(localPrivacyConfig.urlMaskLevels ?? [])],\n };\n\n const privacyConfigSelectorMap = (privacyConfig: PrivacyConfig): Record<string, 'mask' | 'unmask' | 'block'> => {\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {};\n if (typeof privacyConfig.blockSelector === 'string') {\n privacyConfig.blockSelector = [privacyConfig.blockSelector];\n }\n\n for (const selector of privacyConfig.blockSelector ?? []) {\n selectorMap[selector] = 'block';\n }\n for (const selector of privacyConfig.maskSelector ?? []) {\n selectorMap[selector] = 'mask';\n }\n for (const selector of privacyConfig.unmaskSelector ?? []) {\n selectorMap[selector] = 'unmask';\n }\n return selectorMap;\n };\n\n const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {\n ...privacyConfigSelectorMap(localPrivacyConfig),\n ...privacyConfigSelectorMap(remotePrivacyConfig),\n };\n\n for (const [selector, selectorType] of Object.entries(selectorMap)) {\n if (selectorType === 'mask') {\n joinedPrivacyConfig.maskSelector.push(selector);\n } else if (selectorType === 'block') {\n joinedPrivacyConfig.blockSelector.push(selector);\n } else if (selectorType === 'unmask') {\n joinedPrivacyConfig.unmaskSelector.push(selector);\n }\n }\n\n config.privacyConfig = removeInvalidSelectorsFromPrivacyConfig(\n joinedPrivacyConfig,\n this.localConfig.loggerProvider,\n );\n }\n\n if (targetingConfig && Object.keys(targetingConfig).length > 0) {\n config.targetingConfig = targetingConfig;\n }\n\n this.localConfig.loggerProvider.debug(\n JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2),\n );\n\n return {\n localConfig: this.localConfig,\n joinedConfig: config,\n remoteConfig: sessionReplayRemoteConfig,\n };\n }\n\n /**\n * Defensive bounds for the remote-supplied min_session_duration_ms. A misconfigured\n * value (e.g. 30_000_000) would silently suppress every replay until the config is\n * pushed again, so we clamp to a sane ceiling and warn on out-of-range inputs.\n * Returns undefined for clearly invalid values so the gate falls back to disabled\n * rather than carrying a NaN through downstream comparisons.\n */\n private sanitizeMinSessionDurationMs(raw: unknown): number | undefined {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) {\n this.localConfig.loggerProvider.warn(\n `min_session_duration_ms remote value is not a finite number (got ${String(raw)}); ignoring.`,\n );\n return undefined;\n }\n if (raw < 0) {\n this.localConfig.loggerProvider.warn(`min_session_duration_ms remote value is negative (${raw}); ignoring.`);\n return undefined;\n }\n if (raw > MAX_MIN_SESSION_DURATION_MS) {\n this.localConfig.loggerProvider.warn(\n `min_session_duration_ms remote value ${raw} exceeds ${MAX_MIN_SESSION_DURATION_MS}ms ceiling; clamping.`,\n );\n return MAX_MIN_SESSION_DURATION_MS;\n }\n return raw;\n }\n}\n\n/**\n * Upper bound for the remote-configured replay min duration. 60 seconds is well above\n * any reasonable bounce threshold; values higher than this are almost certainly typos\n * (e.g. seconds confused for milliseconds, or an extra zero) and would otherwise\n * suppress every replay until the config is corrected.\n */\nexport const MAX_MIN_SESSION_DURATION_MS = 60_000;\n\nexport const createSessionReplayJoinedConfigGenerator = async (apiKey: string, options: SessionReplayOptions) => {\n const localConfig = new SessionReplayLocalConfig(apiKey, options);\n\n const remoteConfigClient = new RemoteConfigClient(\n apiKey,\n localConfig.loggerProvider,\n localConfig.serverZone,\n options.configServerUrl,\n );\n\n return new SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig, {\n sessionId: options.sessionId,\n deviceId: options.deviceId,\n });\n};\n","import { EventType, IncrementalSource } from '@amplitude/rrweb-types';\nimport type { eventWithTime, mutationData, styleOMValue } from '@amplitude/rrweb-types';\n\nfunction isMergeableMutation(event: eventWithTime): boolean {\n if (event.type !== EventType.IncrementalSnapshot) return false;\n const data = event.data as mutationData;\n return data.source === IncrementalSource.Mutation && !data.isAttachIframe;\n}\n\n// In this repo's rrweb, a `style` attribute value is `string | styleOMValue | null`.\n// A `string` (or `null`) is a full replacement/removal; a `styleOMValue` object is a\n// PARTIAL diff that the replayer applies cumulatively (per-property setProperty /\n// removeProperty, where a `false` value means \"delete this property\"). Unlisted\n// properties are never cleared by an object-form write.\ntype StyleValue = string | styleOMValue | null;\n\nfunction isStyleObject(value: StyleValue): value is styleOMValue {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Deep-merges a run of object-form (`styleOMValue`) style diffs into a single\n * object. Later writes win on a per-property basis, exactly mirroring how the\n * rrweb replayer applies object-form styles cumulatively. A `false` value\n * (delete) is preserved so the merged write still removes the property.\n */\nfunction mergeStyleDiffs(diffs: styleOMValue[]): styleOMValue {\n const merged: styleOMValue = {};\n for (const diff of diffs) {\n for (const prop of Object.keys(diff)) {\n merged[prop] = diff[prop];\n }\n }\n return merged;\n}\n\n/**\n * Coalesces `style` attribute mutations within a merged group in a way that is\n * faithful to how the rrweb replayer applies them, so the merged payload stays\n * small without dropping any property that real cumulative replay would keep.\n *\n * Per node id, the surviving `style` writes are computed as follows:\n * - A `string`/`null` style write is a FULL reset: it supersedes every earlier\n * style write for that node. Only the last such reset is kept.\n * - Object-form (`styleOMValue`) writes after the last reset are PARTIAL diffs\n * applied cumulatively; they are deep-merged (later property wins, `false`\n * deletes preserved) into a single object placed at the last write's\n * position. Earlier superseded object writes are dropped.\n * - When all of a node's style writes are object-form, they all merge into one.\n *\n * This means a pure burst of string-form updates collapses to last-write-wins\n * (the common inline-style/opacity ticker case), while object-form partial diffs\n * such as `{color:'red'}` then `{background:'blue'}` are combined into\n * `{color:'red', background:'blue'}` rather than silently losing `color`.\n *\n * Only the `style` key is coalesced. Any other attribute keys on a superseded\n * entry are preserved in place, and non-style entries are left untouched.\n */\nfunction coalesceStyleAttributes(attributes: mutationData['attributes']): mutationData['attributes'] {\n // Per node id, the array indices of attribute mutations carrying a `style` key.\n const styleIndicesById = new Map<number, number[]>();\n attributes.forEach((attr, i) => {\n if (attr.attributes && 'style' in attr.attributes) {\n const list = styleIndicesById.get(attr.id);\n if (list) list.push(i);\n else styleIndicesById.set(attr.id, [i]);\n }\n });\n\n if (styleIndicesById.size === 0) return attributes;\n\n const styleValueAt = (i: number): StyleValue => (attributes[i].attributes as Record<string, StyleValue>).style;\n\n // Per attributes-array index: 'drop' removes the (superseded) style key.\n // mergedStyleByIndex replaces the style value with a deep-merged object.\n // Indices not present in either map keep their style value untouched.\n const dropStyleAt = new Set<number>();\n const mergedStyleByIndex = new Map<number, styleOMValue>();\n\n for (const indices of styleIndicesById.values()) {\n if (indices.length === 1) continue; // single style write — keep as-is\n\n // Position (within `indices`) of the last full-reset string/null write.\n let lastResetPos = -1;\n indices.forEach((idx, pos) => {\n if (!isStyleObject(styleValueAt(idx))) lastResetPos = pos;\n });\n\n // Object-form writes that survive: those after the last reset (or all of\n // them when there is no reset). Everything before the last reset is dropped.\n const survivingObjectIndices: number[] = [];\n indices.forEach((idx, pos) => {\n if (pos === lastResetPos) return; // the surviving full-reset write — keep\n dropStyleAt.add(idx);\n if (pos > lastResetPos) survivingObjectIndices.push(idx);\n });\n\n if (survivingObjectIndices.length > 0) {\n const lastObjectIdx = survivingObjectIndices[survivingObjectIndices.length - 1];\n const merged = mergeStyleDiffs(survivingObjectIndices.map((idx) => styleValueAt(idx) as styleOMValue));\n dropStyleAt.delete(lastObjectIdx);\n mergedStyleByIndex.set(lastObjectIdx, merged);\n }\n }\n\n if (dropStyleAt.size === 0 && mergedStyleByIndex.size === 0) return attributes;\n\n const result: mutationData['attributes'] = [];\n attributes.forEach((attr, i) => {\n const mergedStyle = mergedStyleByIndex.get(i);\n if (mergedStyle !== undefined) {\n result.push({ ...attr, attributes: { ...attr.attributes, style: mergedStyle } });\n return;\n }\n if (!dropStyleAt.has(i)) {\n result.push(attr);\n return;\n }\n // Superseded style write: drop only the `style` key, preserving any other\n // attribute keys. If the entry was style-only, it is dropped entirely.\n const rest = { ...attr.attributes };\n delete rest.style;\n if (Object.keys(rest).length > 0) {\n result.push({ ...attr, attributes: rest });\n }\n });\n\n return result;\n}\n\nfunction mergeGroup(events: eventWithTime[]): eventWithTime {\n const first = events[0];\n\n // Track first/last event index for each node's adds and removes.\n // lastParentById: final parent from most recent add (last-write-wins).\n const firstAddEventIndex = new Map<number, number>();\n const lastAddEventIndex = new Map<number, number>();\n const firstRemoveEventIndex = new Map<number, number>();\n const lastRemoveEventIndex = new Map<number, number>();\n const lastParentById = new Map<number, number>();\n events.forEach((e, i) => {\n const data = e.data as mutationData;\n for (const add of data.adds) {\n if (!firstAddEventIndex.has(add.node.id)) firstAddEventIndex.set(add.node.id, i);\n lastAddEventIndex.set(add.node.id, i);\n lastParentById.set(add.node.id, add.parentId);\n }\n for (const remove of data.removes) {\n if (!firstRemoveEventIndex.has(remove.id)) firstRemoveEventIndex.set(remove.id, i);\n lastRemoveEventIndex.set(remove.id, i);\n }\n });\n\n // Classify nodes that appear in both adds and removes within this window:\n //\n // Pure transient: created here (firstAddIdx < firstRemoveIdx) and ultimately removed\n // (lastAddIdx < lastRemoveIdx). Cancel all adds + all removes.\n //\n // Pre-existing transient: pre-existed in DOM (firstRemoveIdx < firstAddIdx — removed before\n // first add), then re-added, then removed again (lastAddIdx < lastRemoveIdx).\n // The rrweb replayer processes all removes first: the re-add would still\n // execute after both removes, leaving the node present when it should be\n // absent. Fix: cancel the re-add and all post-add removes; keep only the\n // pre-add removes (they represent the legitimate removal from the original\n // location).\n const transientIds = new Set<number>();\n const preExistingTransientIds = new Set<number>();\n\n for (const [id, firstAddIdx] of firstAddEventIndex) {\n const firstRemoveIdx = firstRemoveEventIndex.get(id);\n if (firstRemoveIdx === undefined) continue;\n const lastAddIdx = lastAddEventIndex.get(id)!;\n const lastRemoveIdx = lastRemoveEventIndex.get(id)!;\n if (lastAddIdx >= lastRemoveIdx) continue; // ultimately present — keep as-is\n\n if (firstAddIdx < firstRemoveIdx) {\n transientIds.add(id);\n } else if (firstRemoveIdx < firstAddIdx) {\n // firstRemoveIdx < firstAddIdx: pre-existing node removed, re-added, then removed again\n preExistingTransientIds.add(id);\n }\n // firstAddIdx === firstRemoveIdx: same-event move (remove+add in one rrweb event) followed\n // by a later remove — keep all operations so the move and final removal survive\n }\n\n // Cascade: nodes whose FINAL parent is effectively cancelled (transient or pre-existing-transient)\n // would be orphaned, so treat them as cancelled too.\n // Use lastParentById so a node moved away from a cancelled parent to a live one is not wrongly elided.\n //\n // Three cascade outcomes mirror the main-loop classification:\n // transientIds: no pre-existing removes (node created in window), or no remove/add overlap\n // preExistingTransientIds: nodeFirstRemoveIdx < nodeFirstAddIdx (pre-existing, removed before re-add)\n // cascadeDropAddsOnlyIds: nodeFirstRemoveIdx === nodeFirstAddIdx (same-event move to cancelled parent)\n // → drop adds but preserve removes from non-cancelled parents\n const cascadeDropAddsOnlyIds = new Set<number>();\n if (transientIds.size > 0 || preExistingTransientIds.size > 0) {\n let changed = true;\n while (changed) {\n changed = false;\n for (const [nodeId, parentId] of lastParentById) {\n if (\n !transientIds.has(nodeId) &&\n !preExistingTransientIds.has(nodeId) &&\n !cascadeDropAddsOnlyIds.has(nodeId) &&\n (transientIds.has(parentId) || preExistingTransientIds.has(parentId) || cascadeDropAddsOnlyIds.has(parentId))\n ) {\n const nodeFirstRemoveIdx = firstRemoveEventIndex.get(nodeId);\n const nodeFirstAddIdx = firstAddEventIndex.get(nodeId);\n if (\n nodeFirstRemoveIdx !== undefined &&\n nodeFirstAddIdx !== undefined &&\n nodeFirstRemoveIdx < nodeFirstAddIdx\n ) {\n preExistingTransientIds.add(nodeId);\n } else if (\n nodeFirstRemoveIdx !== undefined &&\n nodeFirstAddIdx !== undefined &&\n nodeFirstRemoveIdx === nodeFirstAddIdx\n ) {\n cascadeDropAddsOnlyIds.add(nodeId);\n } else {\n transientIds.add(nodeId);\n }\n changed = true;\n }\n }\n }\n }\n\n const needsFilter = transientIds.size > 0 || preExistingTransientIds.size > 0 || cascadeDropAddsOnlyIds.size > 0;\n\n // Build filtered removes by iterating per event so we know each remove's event index.\n // Pure transients: drop all removes.\n // Pre-existing transients: drop removes at eventIdx >= firstAddIdx (the cancelled re-add cycle);\n // keep removes at eventIdx < firstAddIdx (legitimate pre-window removal).\n // Cascade drop-adds-only: keep removes from non-cancelled parents; drop removes from cancelled parents\n // (the cancelled parent is never added in the replay, so a remove from it\n // would reference a non-existent node in the replayer).\n const filteredRemoves: mutationData['removes'][0][] = [];\n events.forEach((e, eventIdx) => {\n for (const r of (e.data as mutationData).removes) {\n if (transientIds.has(r.id)) continue;\n if (preExistingTransientIds.has(r.id) && eventIdx >= firstAddEventIndex.get(r.id)!) continue;\n if (\n cascadeDropAddsOnlyIds.has(r.id) &&\n (transientIds.has(r.parentId) ||\n preExistingTransientIds.has(r.parentId) ||\n cascadeDropAddsOnlyIds.has(r.parentId))\n )\n continue;\n filteredRemoves.push(r);\n }\n });\n\n const allAdds = events.flatMap((e) => (e.data as mutationData).adds);\n const allTexts = events.flatMap((e) => (e.data as mutationData).texts);\n const allAttributes = events.flatMap((e) => (e.data as mutationData).attributes);\n\n const mergedAttributes = needsFilter\n ? allAttributes.filter(\n (a) => !transientIds.has(a.id) && !preExistingTransientIds.has(a.id) && !cascadeDropAddsOnlyIds.has(a.id),\n )\n : allAttributes;\n\n const merged: mutationData = {\n source: IncrementalSource.Mutation,\n removes: filteredRemoves,\n adds: needsFilter\n ? allAdds.filter(\n (a) =>\n !transientIds.has(a.node.id) &&\n !preExistingTransientIds.has(a.node.id) &&\n !cascadeDropAddsOnlyIds.has(a.node.id),\n )\n : allAdds,\n texts: needsFilter\n ? allTexts.filter(\n (t) => !transientIds.has(t.id) && !preExistingTransientIds.has(t.id) && !cascadeDropAddsOnlyIds.has(t.id),\n )\n : allTexts,\n attributes: coalesceStyleAttributes(mergedAttributes),\n };\n return { ...first, data: merged } as eventWithTime;\n}\n\n/**\n * Merges consecutive IncrementalSnapshot mutation events into a single event,\n * reducing overall event count without changing replay semantics.\n *\n * isAttachIframe events are never merged — they carry a full iframe document\n * tree and must remain isolated.\n */\nexport function mergeMutationEvents(events: eventWithTime[]): eventWithTime[] {\n if (events.length <= 1) return events;\n\n const result: eventWithTime[] = [];\n let i = 0;\n\n while (i < events.length) {\n if (!isMergeableMutation(events[i])) {\n result.push(events[i]);\n i++;\n continue;\n }\n\n let j = i + 1;\n while (j < events.length && isMergeableMutation(events[j])) {\n j++;\n }\n\n result.push(j > i + 1 ? mergeGroup(events.slice(i, j)) : events[i]);\n i = j;\n }\n\n return result;\n}\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { MAX_SINGLE_EVENT_SIZE } from '../constants';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\nimport { mergeMutationEvents } from './merge-mutation-events';\n\ninterface TaskQueue {\n event: eventWithTime;\n sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n taskQueue: TaskQueue[] = [];\n pendingQueue: TaskQueue[] = [];\n isProcessing = false;\n eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n config: SessionReplayJoinedConfig;\n deviceId: string | undefined;\n canUseIdleCallback: boolean | undefined;\n timeout: number;\n worker?: Worker;\n onFullSnapshotProcessed?: () => void;\n\n constructor(\n eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n config: SessionReplayJoinedConfig,\n deviceId: string | undefined,\n workerScript?: string,\n onFullSnapshotProcessed?: () => void,\n ) {\n const globalScope = getGlobalScope();\n this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n this.eventsManager = eventsManager;\n this.config = config;\n this.deviceId = deviceId;\n this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n if (workerScript) {\n config.loggerProvider.log('Enabling web worker for compression');\n\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n\n worker.onerror = (e) => {\n e.preventDefault();\n config.loggerProvider.error(\n `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n };\n worker.onmessage = (e) => {\n const { compressedEvent, sessionId } = e.data as Record<string, string>;\n this.addCompressedEventToManager(compressedEvent, sessionId);\n };\n\n this.worker = worker;\n } catch (error) {\n config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n }\n }\n }\n\n // Schedule processing during idle time\n public scheduleIdleProcessing(): void {\n if (!this.isProcessing) {\n this.isProcessing = true;\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n }\n }\n\n // Add an event to the task queue if idle callback is supported or compress the event directly\n public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n // maximising the chance it is delivered before the user exits the page.\n if (event.type === RRWebEventType.FullSnapshot) {\n this.config.loggerProvider.debug('Processing full snapshot immediately.');\n // Drain any events still pending in the idle-callback queue first.\n // Those events reference the pre-snapshot DOM and must be sent before\n // the full snapshot; if we let them be processed later they'd arrive at\n // the server after the snapshot and cause \"node not found\" replay errors.\n if (this.taskQueue.length > 0 || this.pendingQueue.length > 0) {\n const allTasks = [...this.taskQueue.splice(0), ...this.mergeMutationTasks(this.pendingQueue.splice(0))];\n for (const task of allTasks) {\n const compressed = this.compressEvent(task.event);\n this.addCompressedEventToManager(compressed, task.sessionId);\n }\n this.isProcessing = false;\n }\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n this.onFullSnapshotProcessed?.();\n return;\n }\n\n if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n this.pendingQueue.push({ event, sessionId });\n this.scheduleIdleProcessing();\n } else {\n this.config.loggerProvider.debug('Processing event without idle callback.');\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // Process the task queue during idle time\n public processQueue(idleDeadline: IdleDeadline): void {\n // Merge newly-arrived pending events and append to the already-merged taskQueue.\n // Keeping them separate prevents re-merging already-merged tasks on subsequent calls,\n // which would corrupt move semantics for nodes that appear in multiple merge passes.\n if (this.pendingQueue.length > 0) {\n this.taskQueue.push(...this.mergeMutationTasks(this.pendingQueue.splice(0)));\n }\n // Process tasks while there's idle time or until the max number of tasks is reached\n while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n this.addCompressedEvent(event, sessionId);\n }\n }\n\n // If there are still tasks in the queue, schedule the next idle callback\n if (this.taskQueue.length > 0 || this.pendingQueue.length > 0) {\n requestIdleCallback(\n (idleDeadline) => {\n this.processQueue(idleDeadline);\n },\n { timeout: this.timeout },\n );\n } else {\n this.isProcessing = false;\n }\n }\n\n compressEvent = (event: eventWithTime): string => {\n // Serialize with type+timestamp first for streaming parser compatibility.\n // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n // `delay` is an rrweb player field: an optional ms offset applied on top of\n // `timestamp` during replay to smooth out batched/throttled events. Preserve\n // it when present so playback timing is accurate.\n const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n };\n\n private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n // UTF-8 byte size, not JS char count: a 9 M-char string of CJK/emoji can be 18–27 MB\n // on the wire and would otherwise slip past a char-count guard.\n const eventSizeBytes = new Blob([compressedEvent]).size;\n if (eventSizeBytes > (this.config.maxSingleEventSizeBytes ?? MAX_SINGLE_EVENT_SIZE)) {\n this.config.loggerProvider.warn(\n `Session replay event dropped: serialized size ${Math.round(\n eventSizeBytes / 1024,\n )} KB exceeds maximum allowed event size. If this recurs, please open a GitHub issue at https://github.com/amplitude/Amplitude-TypeScript/issues or contact Amplitude support.`,\n );\n return;\n }\n if (this.eventsManager && this.deviceId) {\n this.eventsManager.addEvent({\n event: { type: 'replay', data: compressedEvent },\n sessionId,\n deviceId: this.deviceId,\n });\n }\n };\n\n public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n if (this.worker) {\n // This indirectly compresses the event.\n try {\n this.worker.postMessage({ event, sessionId });\n } catch (err: any) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (err.name === 'DataCloneError') {\n // fallback: serialize\n this.worker.postMessage(JSON.stringify({ event, sessionId }));\n } else {\n this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n }\n }\n } else {\n const compressedEvent = this.compressEvent(event);\n this.addCompressedEventToManager(compressedEvent, sessionId);\n }\n };\n\n /**\n * Synchronously drain all queued events. Called during page unload to prevent\n * data loss from events waiting in the requestIdleCallback queue.\n */\n public flushQueue = () => {\n // Merge any events still in pendingQueue into taskQueue first.\n // Events land in pendingQueue when the idle callback hasn't fired yet;\n // without this step they would be silently lost on page unload.\n if (this.pendingQueue.length > 0) {\n this.taskQueue.push(...this.mergeMutationTasks(this.pendingQueue.splice(0)));\n }\n while (this.taskQueue.length > 0) {\n const task = this.taskQueue.shift();\n if (task) {\n const { event, sessionId } = task;\n // Bypass the web worker: compress synchronously on the main thread and\n // write directly to the manager. postMessage is async — during page\n // unload the worker response would never arrive and events would be\n // silently dropped. This mirrors the pattern used for full snapshots in\n // enqueueEvent().\n const compressed = this.compressEvent(event);\n this.addCompressedEventToManager(compressed, sessionId);\n }\n }\n this.isProcessing = false;\n };\n\n // Merge consecutive mutation tasks with the same sessionId before processing,\n // reducing the number of events serialized and stored without changing replay semantics.\n // Enabled by default (validated amp-on-amp perf config, SR-4646); only skipped when\n // performanceConfig.mergeMutations is explicitly set to false.\n private mergeMutationTasks(tasks: TaskQueue[]): TaskQueue[] {\n if (this.config.performanceConfig?.mergeMutations === false) return tasks;\n if (tasks.length <= 1) return tasks;\n\n const result: TaskQueue[] = [];\n let i = 0;\n\n while (i < tasks.length) {\n const sessionId = tasks[i].sessionId;\n\n // Find the end of the current session run\n let j = i + 1;\n while (j < tasks.length && tasks[j].sessionId === sessionId) {\n j++;\n }\n\n // Merge consecutive mutations within this session run; non-mutations pass through unchanged\n const merged = mergeMutationEvents(tasks.slice(i, j).map((t) => t.event));\n for (const event of merged) {\n result.push({ event, sessionId });\n }\n\n i = j;\n }\n\n return result;\n }\n\n public terminate = () => {\n this.worker?.terminate();\n };\n}\n","export const UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';\nexport const UNEXPECTED_NETWORK_ERROR_MESSAGE = 'Network error occurred, event batch rejected';\nexport const MAX_RETRIES_EXCEEDED_MESSAGE = 'Session replay event batch rejected due to exceeded retry count';\nexport const STORAGE_FAILURE = 'Failed to store session replay events in IndexedDB';\nexport const MISSING_DEVICE_ID_MESSAGE = 'Session replay event batch not sent due to missing device ID';\nexport const MISSING_API_KEY_MESSAGE = 'Session replay event batch not sent due to missing api key';\nexport const SESSION_KILLED_MESSAGE =\n 'Session replay event batch dropped: server signalled capture disabled or session out of valid range for this session';\n","// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.47.0-sr-trc-debug-log.3';\n","import { BaseTransport, getGlobalScope, ILogger, ServerZone, Status } from '@amplitude/analytics-core';\nimport { getCurrentUrl, getServerUrl } from './helpers';\nimport {\n MAX_RETRIES_EXCEEDED_MESSAGE,\n MISSING_API_KEY_MESSAGE,\n MISSING_DEVICE_ID_MESSAGE,\n SESSION_KILLED_MESSAGE,\n UNEXPECTED_ERROR_MESSAGE,\n UNEXPECTED_NETWORK_ERROR_MESSAGE,\n} from './messages';\nimport {\n SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination,\n SessionReplayDestination,\n SessionReplayDestinationContext,\n} from './typings/session-replay';\nimport { VERSION } from './version';\nimport {\n MAX_URL_LENGTH,\n KB_SIZE,\n MAX_KEEPALIVE_BYTES,\n WAF_PAYLOAD_TOO_LARGE_PATTERN,\n EVENT_SKIPPED_HEADER,\n EVENT_SKIP_CODE_THROTTLED,\n EVENT_SKIP_CODE_INVALID_RANGE,\n EVENT_SKIP_CODE_CAPTURE_DISABLED,\n THROTTLED_FLUSH_PAUSE_MS,\n MERGE_AFTER_THROTTLE_SOFT_CAP,\n SEND_TIMEOUT_MS,\n} from './constants';\nimport { gzipJson } from './utils/gzip';\n\ninterface WorkerCompleteMessage {\n type: 'complete';\n id: string;\n err?: string;\n // null when the response was a clean 200 (no skip header), undefined when the\n // request did not produce a 200, otherwise the server's skip-code string.\n skipCode?: string | null;\n}\ninterface WorkerLogMessage {\n type: 'log' | 'warn';\n id: string;\n message: string;\n}\ninterface WorkerPayloadTooLargeMessage {\n type: 'payload_too_large';\n id: string;\n isWaf: boolean;\n}\ntype WorkerMessage = WorkerCompleteMessage | WorkerLogMessage | WorkerPayloadTooLargeMessage;\n\nexport type PayloadBatcher = ({ version, events }: { version: number; events: string[] }) => {\n version: number;\n events: unknown[];\n};\n\n// Bounded so a long-lived SDK instance can't accumulate kill records indefinitely;\n// sessions are time-bounded in practice, this cap is just a defensive ceiling.\nconst MAX_KILLED_SESSIONS = 256;\n\n// Defensive ceiling on retained timed-out worker requests (see timedOutWorkerRequests).\n// In normal operation each entry is removed when the worker's late message arrives; this\n// cap only guards the pathological case of a wedged worker that never replies at all.\nconst MAX_TIMED_OUT_WORKER_REQUESTS = 256;\n\nexport class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {\n loggerProvider: ILogger;\n storageKey = '';\n trackServerUrl?: string;\n retryTimeout = 1000;\n // Defaults to true (gzip enabled) so existing call sites that don't pass the flag\n // retain pre-flag behavior. The local-config layer also defaults to true; this\n // belt-and-braces default protects direct constructor callers (e.g. tests).\n private enableTransportCompression: boolean;\n // Milliseconds before an in-flight send is aborted; <= 0 disables the abort/timeout.\n // Defaults to SEND_TIMEOUT_MS. Configurable so large slow-but-succeeding uploads aren't\n // killed (and retried) at an over-aggressive default. See config.sendTimeoutMs.\n private sendTimeoutMs: number;\n private scheduled: ReturnType<typeof setTimeout> | null = null;\n payloadBatcher: PayloadBatcher;\n queue: SessionReplayDestinationContext[] = [];\n private worker?: Worker;\n private sendIdCounter = 0;\n private pendingWorkerRequests = new Map<\n string,\n { context: SessionReplayDestinationContext; resolve: () => void; timeout?: ReturnType<typeof setTimeout> }\n >();\n // Requests the main thread stopped awaiting after SEND_TIMEOUT_MS (so the serial flush\n // loop could proceed) but whose worker may still be retrying in the background. We keep\n // the context — bounded, like killedSessions — so a *late* worker complete/payload_too_large\n // can still run completeRequest and settle the store record. Without this the late message\n // is dropped (its id is gone from pendingWorkerRequests), so a successful late delivery would\n // leave the IDB/memory record behind for sendStoredEvents to re-upload as duplicate replay data.\n private timedOutWorkerRequests = new Map<string, SessionReplayDestinationContext>();\n // Server back-pressure state, fed by the X-Session-Replay-Event-Skipped header on 200s.\n // The server uses this header (instead of 4xx) to signal a deliberate no-retry drop so SDKs\n // don't retry-storm. We honor it here by slowing or stopping our flush schedule.\n private flushPauseUntilMs = 0;\n // Set when schedule() defers a flush because we're inside a throttle pause; consumed by\n // flush() to merge same-session contexts before sending. Throttling is enforced by request\n // count, so collapsing N queued batches into one POST directly reduces throttle pressure.\n private mergeOnNextFlush = false;\n // Set by markCoalesceNextFlush() before the page-load backlog is enqueued; consumed by\n // flush() to coalesce the drained persisted sequences. Distinct from\n // mergeOnNextFlush so the drain isn't conflated with a throttle pause for logging.\n private coalesceNextFlush = false;\n // Gates the merge log to once per throttle pause window — mirroring the throttle log's\n // transition-only gating — so a sustained throttle scenario doesn't spam logs every cycle.\n private mergeLogFiredThisPause = false;\n private killedSessions = new Set<string | number>();\n\n constructor({\n trackServerUrl,\n loggerProvider,\n payloadBatcher,\n workerScript,\n enableTransportCompression,\n sendTimeoutMs,\n }: {\n trackServerUrl?: string;\n loggerProvider: ILogger;\n payloadBatcher?: PayloadBatcher;\n workerScript?: string;\n enableTransportCompression?: boolean;\n sendTimeoutMs?: number;\n }) {\n this.loggerProvider = loggerProvider;\n this.payloadBatcher = payloadBatcher ? payloadBatcher : (payload) => payload;\n this.trackServerUrl = trackServerUrl;\n this.enableTransportCompression = enableTransportCompression ?? true;\n this.sendTimeoutMs = sendTimeoutMs ?? SEND_TIMEOUT_MS;\n\n if (workerScript) {\n try {\n const blob = new Blob([workerScript], { type: 'application/javascript' });\n const blobUrl = URL.createObjectURL(blob);\n const worker = new Worker(blobUrl);\n worker.onerror = (e) => {\n e.preventDefault();\n loggerProvider.error(\n `Track destination worker failed, falling back to main-thread sending: ${e.message} (${e.filename}:${e.lineno})`,\n );\n worker.terminate();\n this.worker = undefined;\n // Resolve pending promises so flush() doesn't hang. Do NOT call completeRequest\n // here — the events were never delivered, so onComplete must not fire and the\n // IDB/memory store entries must remain intact for recovery by sendStoredEvents.\n for (const [, pending] of this.pendingWorkerRequests) {\n // Cancel the per-request timeout — onerror already settles every pending\n // promise, so leaving the timer armed would fire a spurious timeout warn later.\n if (pending.timeout) clearTimeout(pending.timeout);\n loggerProvider.warn(`Session replay event send failed due to worker crash: ${e.message}`);\n pending.resolve();\n }\n this.pendingWorkerRequests.clear();\n // The worker is gone, so no late completion can arrive for timed-out requests either.\n // Drop the retained contexts to free memory; their store records stay intact (we never\n // completeRequest here) so sendStoredEvents can recover them on next init.\n this.timedOutWorkerRequests.clear();\n };\n worker.onmessage = (e: MessageEvent<WorkerMessage>) => {\n const msg = e.data;\n if (msg.type === 'log') {\n loggerProvider.log(msg.message);\n } else if (msg.type === 'warn') {\n loggerProvider.warn(msg.message);\n } else if (msg.type === 'payload_too_large') {\n const pending = this.pendingWorkerRequests.get(msg.id);\n if (pending) {\n if (pending.timeout) clearTimeout(pending.timeout);\n this.handlePayloadTooLargeResponse(pending.context, msg.isWaf);\n pending.resolve();\n this.pendingWorkerRequests.delete(msg.id);\n } else {\n // Late message for a request the main thread already timed out: the worker still\n // determined the payload was too large, so split-and-retry off the original record.\n const timedOut = this.timedOutWorkerRequests.get(msg.id);\n if (timedOut) {\n this.timedOutWorkerRequests.delete(msg.id);\n this.handlePayloadTooLargeResponse(timedOut, msg.isWaf);\n }\n }\n } else if (msg.type === 'complete') {\n const pending = this.pendingWorkerRequests.get(msg.id);\n if (pending) {\n if (pending.timeout) clearTimeout(pending.timeout);\n if (msg.skipCode !== undefined) {\n this.applyServerDirective(pending.context.sessionId, msg.skipCode);\n }\n this.completeRequest({ context: pending.context });\n pending.resolve();\n this.pendingWorkerRequests.delete(msg.id);\n } else {\n // Late completion for a request the main thread already timed out. The worker's\n // actual outcome (delivered, or retries exhausted) is authoritative, so settle the\n // store record by it rather than leaving it behind for sendStoredEvents to re-upload.\n const timedOut = this.timedOutWorkerRequests.get(msg.id);\n if (timedOut) {\n this.timedOutWorkerRequests.delete(msg.id);\n if (msg.skipCode !== undefined) {\n this.applyServerDirective(timedOut.sessionId, msg.skipCode);\n }\n this.completeRequest({ context: timedOut });\n }\n }\n }\n };\n this.worker = worker;\n } catch (error) {\n loggerProvider.error('Failed to create track destination worker, falling back to main-thread sending:', error);\n }\n }\n }\n\n sendEventsList(destinationData: SessionReplayDestination) {\n this.addToQueue({\n ...destinationData,\n attempts: 0,\n timeout: 0,\n });\n }\n\n /**\n * Marks the next scheduled flush to coalesce its queued contexts by destination identity.\n * Callers use this immediately before enqueuing the page-load backlog drain (many persisted\n * sequences replayed back-to-back on init via sendStoredEvents). Because those enqueues are\n * synchronous and the flush is deferred to the next tick via schedule(0), the whole backlog\n * lands in the queue before the flag is consumed — collapsing N small POSTs into far fewer\n * and avoiding the request flood observed on page load. Steady-state live capture\n * never sets this flag, so its sending behavior is unchanged.\n *\n * Schedules a flush so the flag is always consumed by the next flush, even when every\n * backlog sequence is dropped before reaching the queue (e.g. all events oversized) and no\n * enqueue schedules one itself. Otherwise the flag would stick and a later unrelated live\n * flush could coalesce live batches as if they were a page-load drain.\n */\n markCoalesceNextFlush() {\n this.coalesceNextFlush = true;\n this.schedule(0);\n }\n\n /**\n * Sends events via navigator.sendBeacon on page exit.\n * Beacon payloads are sent as uncompressed JSON because sendBeacon does not support\n * Content-Encoding, and small incremental batches don't benefit much from compression.\n * The full snapshot has already been sent eagerly via fetch, so the beacon only needs\n * to cover the remaining incremental events since the last fetch flush.\n */\n sendBeacon({\n events,\n sessionId,\n deviceId,\n apiKey,\n serverZone,\n }: {\n events: string[];\n sessionId: string | number;\n deviceId: string;\n apiKey: string;\n serverZone?: keyof typeof ServerZone;\n }) {\n const MAX_BEACON_BYTES = 64 * 1024;\n const byteLength = (s: string) => new Blob([s]).size;\n let trimmedEvents = events;\n let payload = JSON.stringify({ version: 2, events: trimmedEvents });\n if (byteLength(payload) > MAX_BEACON_BYTES) {\n // Binary search for the largest prefix that fits within the beacon size limit.\n // Uses Blob.size to get the UTF-8 byte count, which is what sendBeacon measures.\n let lo = 0;\n let hi = trimmedEvents.length;\n while (lo < hi) {\n const mid = Math.floor((lo + hi + 1) / 2);\n if (byteLength(JSON.stringify({ version: 2, events: trimmedEvents.slice(0, mid) })) <= MAX_BEACON_BYTES) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n trimmedEvents = trimmedEvents.slice(0, lo);\n payload = JSON.stringify({ version: 2, events: trimmedEvents });\n this.loggerProvider.warn(\n `sendBeacon payload exceeded 64 KB limit, trimmed from ${events.length} to ${trimmedEvents.length} events`,\n );\n }\n if (trimmedEvents.length === 0) {\n return;\n }\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: String(sessionId),\n type: 'replay',\n api_key: apiKey,\n });\n const serverUrl = `${getServerUrl(serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n const globalScope = getGlobalScope();\n try {\n // Wrap in a Blob to set Content-Type: application/json; a plain string would\n // cause the browser to send Content-Type: text/plain, which the server rejects.\n const payloadBlob = new Blob([payload], { type: 'application/json' });\n const sent = globalScope?.navigator?.sendBeacon?.(serverUrl, payloadBlob);\n if (sent === false) {\n this.loggerProvider.warn('sendBeacon failed to queue session replay payload');\n }\n } catch {\n // Best effort — no fallback on page exit.\n }\n }\n\n addToQueue(...list: SessionReplayDestinationContext[]) {\n const tryable = list.filter((context) => {\n if (this.killedSessions.has(context.sessionId)) {\n // Server has signaled capture_disabled or session_in_invalid_range for this session;\n // drop the batch (and clean up its IDB record via onComplete) instead of POSTing.\n this.completeRequest({\n context,\n err: SESSION_KILLED_MESSAGE,\n });\n return false;\n }\n if (context.attempts < (context.flushMaxRetries || 0)) {\n context.attempts += 1;\n return true;\n }\n this.completeRequest({\n context,\n err: MAX_RETRIES_EXCEEDED_MESSAGE,\n });\n return false;\n });\n tryable.forEach((context) => {\n this.queue = this.queue.concat(context);\n this.schedule(0);\n });\n }\n\n schedule(timeout: number) {\n if (this.scheduled) return;\n // If the server signaled throttling on a recent 200, defer the next flush until the\n // pause window ends. This lets us keep batching events without retry-storming the server.\n const pauseRemaining = this.flushPauseUntilMs - Date.now();\n const isPaused = pauseRemaining > 0;\n const effectiveTimeout = pauseRemaining > timeout ? pauseRemaining : timeout;\n if (isPaused) {\n // Mark the upcoming flush for merge: contexts piling up during the pause should\n // be coalesced into one POST per (session, device, api, type, ...) group.\n this.mergeOnNextFlush = true;\n }\n this.scheduled = setTimeout(() => {\n void this.flush(true).then(() => {\n if (this.queue.length > 0) {\n this.schedule(timeout);\n }\n });\n }, effectiveTimeout);\n }\n\n async flush(useRetry = false) {\n let list = this.queue;\n this.queue = [];\n\n if (this.scheduled) {\n clearTimeout(this.scheduled);\n this.scheduled = null;\n }\n\n if (this.mergeOnNextFlush) {\n this.mergeOnNextFlush = false;\n // A throttle merge already coalesces by identity; clear the drain flag too so the\n // same backlog isn't passed through a redundant second merge on a later flush.\n this.coalesceNextFlush = false;\n list = this.mergeQueueAfterThrottle(list);\n } else if (this.coalesceNextFlush) {\n this.coalesceNextFlush = false;\n list = this.mergeDrainBacklog(list);\n }\n\n for (const context of list) {\n await this.send(context, useRetry);\n }\n }\n\n /**\n * Post-throttle release path: coalesce the queued contexts, then log once per pause window.\n * Delegates the actual merging to the shared coalesceByIdentity helper so the drain path\n * (mergeDrainBacklog) and this path stay byte-for-byte identical in how they merge.\n */\n private mergeQueueAfterThrottle(list: SessionReplayDestinationContext[]): SessionReplayDestinationContext[] {\n const merged = this.coalesceByIdentity(list);\n if (merged.length < list.length && !this.mergeLogFiredThisPause) {\n this.mergeLogFiredThisPause = true;\n this.loggerProvider.log(\n `Session replay throttle pause ended; merged ${list.length} queued batches into ${merged.length} request(s)`,\n );\n }\n return merged;\n }\n\n /**\n * Page-load backlog drain path: on init the SDK replays every persisted sequence\n * from a prior session via sendStoredEvents. Enqueued back-to-back they would flush as N\n * separate POSTs — a request flood on page load that feeds volume spikes and throttling.\n * Reuses the exact same identity-grouped merge as the post-throttle path so the backlog\n * collapses into far fewer requests, with onComplete fanned out so each source IDB record\n * is still cleaned up exactly once on success.\n */\n private mergeDrainBacklog(list: SessionReplayDestinationContext[]): SessionReplayDestinationContext[] {\n const merged = this.coalesceByIdentity(list);\n if (merged.length < list.length) {\n this.loggerProvider.log(\n `Session replay coalesced ${list.length} persisted page-load backlog batches into ${merged.length} request(s)`,\n );\n }\n return merged;\n }\n\n /**\n * Coalesces queued contexts that share the same destination identity into fewer requests.\n * Identity covers everything that affects the request URL, routing, or per-request semantics\n * — splitting on any difference keeps each merged POST indistinguishable from the source\n * contexts it replaced.\n *\n * Greedy concat with a soft byte-length cap (`MERGE_AFTER_THROTTLE_SOFT_CAP`) keeps merged\n * payloads well under the 413 ceiling; on the rare oversized merge, the existing\n * split-and-retry path still bisects safely.\n *\n * The merged context's `onComplete` fans out to every source context's callback so each\n * underlying IDB sequence record is cleaned up exactly once on success.\n */\n private coalesceByIdentity(list: SessionReplayDestinationContext[]): SessionReplayDestinationContext[] {\n if (list.length <= 1) return list;\n\n const groups = new Map<string, SessionReplayDestinationContext[]>();\n for (const ctx of list) {\n // Anything that can change the URL, headers, or backend routing must split groups.\n const key = [\n ctx.sessionId,\n ctx.deviceId ?? '',\n ctx.apiKey ?? '',\n ctx.type,\n ctx.serverZone ?? '',\n ctx.sampleRate,\n ctx.version?.type ?? '',\n ctx.version?.version ?? '',\n ].join('|');\n const arr = groups.get(key);\n if (arr) arr.push(ctx);\n else groups.set(key, [ctx]);\n }\n\n const merged: SessionReplayDestinationContext[] = [];\n for (const group of groups.values()) {\n if (group.length === 1) {\n merged.push(group[0]);\n continue;\n }\n let current: SessionReplayDestinationContext | null = null;\n let currentBytes = 0;\n const flushCurrent = () => {\n if (current) merged.push(current);\n current = null;\n currentBytes = 0;\n };\n for (const ctx of group) {\n // UTF-8 byte size, matching how the events store enforces MAX_EVENT_LIST_SIZE\n // (see base-events-store.ts:getStringSize). Using char length would let a CJK/\n // emoji-heavy payload sneak past the cap.\n const ctxBytes = ctx.events.reduce((sum, e) => sum + new Blob([e]).size, 0);\n if (current === null) {\n // Reset attempts to 0 on the merged context so the post-throttle delivery gets a\n // full retry budget. The throttle pause has already absorbed back-pressure; the\n // alternative (Math.max of source attempts) would collapse N source budgets into\n // one and end-of-life all N IDB records on a single retry exhaustion.\n current = { ...ctx, events: [...ctx.events], attempts: 0 };\n currentBytes = ctxBytes;\n continue;\n }\n if (currentBytes + ctxBytes > MERGE_AFTER_THROTTLE_SOFT_CAP) {\n flushCurrent();\n current = { ...ctx, events: [...ctx.events], attempts: 0 };\n currentBytes = ctxBytes;\n continue;\n }\n const prevOnComplete = current.onComplete;\n const ctxOnComplete = ctx.onComplete;\n current.events = current.events.concat(ctx.events);\n currentBytes += ctxBytes;\n current.onComplete = async () => {\n // allSettled (not all): an underlying store cleanup failure in one shouldn't\n // block the other, and the merged onComplete is invoked fire-and-forget via\n // `void context.onComplete()` — a rejection from `Promise.all` would surface\n // as an unhandled rejection. Errors stay encapsulated in the source callbacks.\n await Promise.allSettled([prevOnComplete(), ctxOnComplete()]);\n };\n }\n flushCurrent();\n }\n\n return merged;\n }\n\n async send(context: SessionReplayDestinationContext, useRetry = true) {\n // A kill directive can arrive between flush() snapshotting the queue and us reaching\n // each context. Re-check before hitting the network so we don't waste POSTs on a\n // session the server has already told us to stop sending for.\n if (this.killedSessions.has(context.sessionId)) {\n return this.completeRequest({ context, err: SESSION_KILLED_MESSAGE });\n }\n const apiKey = context.apiKey;\n if (!apiKey) {\n return this.completeRequest({ context, err: MISSING_API_KEY_MESSAGE });\n }\n const deviceId = context.deviceId;\n if (!deviceId) {\n return this.completeRequest({ context, err: MISSING_DEVICE_ID_MESSAGE });\n }\n\n const payload = this.payloadBatcher({\n version: 1,\n events: context.events,\n });\n\n if (payload.events.length === 0) {\n this.completeRequest({ context });\n return;\n }\n\n const { worker } = this;\n if (worker) {\n return this.sendViaWorker(worker, context, payload, useRetry);\n }\n\n return this.sendOnMainThread(apiKey, deviceId, context, payload, useRetry);\n }\n\n private async sendViaWorker(\n worker: Worker,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const id = `${++this.sendIdCounter}`;\n return new Promise<void>((resolve) => {\n // The worker only resolves this promise when it posts back complete/payload_too_large.\n // If the worker's own fetch hangs, no message ever arrives, so this promise — and the\n // serial flush loop awaiting it — would hang forever while pendingWorkerRequests grows\n // unbounded. On timeout we resolve so flush() proceeds, but deliberately do NOT call\n // completeRequest: like the worker-crash path above, the events were never confirmed\n // delivered, so onComplete must not fire and the IDB/memory store must stay intact for\n // recovery by sendStoredEvents.\n // sendTimeoutMs <= 0 disables the wait timer entirely: we then rely solely on the\n // worker's own complete/payload_too_large message to settle. This reintroduces the\n // hang risk this timer guards against, so it is an explicit experiment opt-out.\n const timeout =\n this.sendTimeoutMs > 0\n ? setTimeout(() => {\n const pending = this.pendingWorkerRequests.get(id);\n if (!pending) return;\n this.pendingWorkerRequests.delete(id);\n // Retain the context so a *late* worker complete/payload_too_large can still settle the\n // store record (see timedOutWorkerRequests). Without this, a worker that ultimately\n // delivers after we stopped awaiting would leave the record behind → duplicate upload.\n this.rememberTimedOutRequest(id, pending.context);\n this.loggerProvider.warn(\n `Session replay worker send timed out after ${this.sendTimeoutMs}ms; leaving events for retry`,\n );\n pending.resolve();\n }, this.sendTimeoutMs)\n : undefined;\n this.pendingWorkerRequests.set(id, { context, resolve, timeout });\n worker.postMessage({\n type: 'send',\n id,\n payload,\n useRetry,\n context: {\n apiKey: context.apiKey,\n deviceId: context.deviceId,\n sessionId: context.sessionId,\n events: context.events,\n eventType: context.type,\n flushMaxRetries: context.flushMaxRetries ?? 0,\n sampleRate: context.sampleRate,\n serverZone: context.serverZone,\n trackServerUrl: this.trackServerUrl,\n version: context.version,\n currentUrl: getCurrentUrl(),\n sdkVersion: VERSION,\n enableTransportCompression: this.enableTransportCompression,\n sendTimeoutMs: this.sendTimeoutMs,\n },\n });\n });\n }\n\n private rememberTimedOutRequest(id: string, context: SessionReplayDestinationContext) {\n this.timedOutWorkerRequests.set(id, context);\n // Bound memory: a wedged worker that never replies must not let this grow without limit.\n // Map preserves insertion order, so deleting the first key evicts the oldest entry.\n if (this.timedOutWorkerRequests.size > MAX_TIMED_OUT_WORKER_REQUESTS) {\n for (const oldest of this.timedOutWorkerRequests.keys()) {\n this.timedOutWorkerRequests.delete(oldest);\n break;\n }\n }\n }\n\n private async sendOnMainThread(\n apiKey: string,\n deviceId: string,\n context: SessionReplayDestinationContext,\n payload: { version: number; events: unknown[] },\n useRetry: boolean,\n ): Promise<void> {\n const url = getCurrentUrl();\n const version = VERSION;\n const sampleRate = context.sampleRate;\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: `${context.sessionId}`,\n type: `${context.type}`,\n });\n const sessionReplayLibrary = `${context.version?.type ?? 'standalone'}/${context.version?.version ?? version}`;\n\n try {\n const payloadJson = JSON.stringify(payload);\n // Only await gzip when (a) the customer hasn't opted out and (b) CompressionStream\n // is actually available; skipping the await entirely preserves the synchronous\n // fast-path for browsers/environments (e.g. Jest) that don't support it, keeping\n // retry-timing tests unaffected.\n const globalScope = getGlobalScope();\n const gzipped =\n this.enableTransportCompression && globalScope && 'CompressionStream' in globalScope\n ? await gzipJson(payloadJson, globalScope)\n : null;\n const payloadSize = gzipped ? gzipped.byteLength : new Blob([payloadJson]).size;\n // fetch() has no native timeout. A request stuck \"pending\" forever would block the\n // serial flush loop indefinitely (head-of-line blocking), so we abort it after\n // SEND_TIMEOUT_MS. The abort surfaces as an AbortError in the catch below, where it's\n // routed as a retryable network failure when useRetry is true.\n const controller = new AbortController();\n const options: RequestInit = {\n headers: {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n Authorization: `Bearer ${apiKey}`,\n 'X-Client-Version': version,\n 'X-Client-Library': sessionReplayLibrary,\n 'X-Client-Url': url.substring(0, MAX_URL_LENGTH), // limit url length to 1000 characters to avoid ELB 400 error\n 'X-Client-Sample-Rate': `${sampleRate}`,\n 'X-Sampling-Hash-Alg': 'xxhash32',\n ...(gzipped ? { 'Content-Encoding': 'gzip' } : {}),\n },\n body: (gzipped ?? payloadJson) as BodyInit,\n method: 'POST',\n // keepalive lets the request survive page navigation, preventing 499 (client-closed) errors.\n // Must stay under the browser's 64 KB keepalive budget; large payloads skip it.\n keepalive: payloadSize <= MAX_KEEPALIVE_BYTES,\n signal: controller.signal,\n };\n\n const serverUrl = `${getServerUrl(context.serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n // Final defensive guard: never POST a zero-event payload. Upper layers (events-manager\n // oversize filter, send()'s post-batcher check, store-layer filters) should already\n // have caught this — but SR-4284 fleet logs show ~416 empty-body 400s/24h slipping\n // through somehow, so a cheap belt-and-braces check immediately before fetch prevents\n // any future regression from re-introducing the same server rejection.\n if (payload.events.length === 0) {\n this.completeRequest({ context });\n return;\n }\n // sendTimeoutMs <= 0 disables the abort: the request can then hang indefinitely\n // (head-of-line blocking the serial flush). Explicit experiment opt-out only.\n const sendTimeout =\n this.sendTimeoutMs > 0\n ? setTimeout(() => {\n controller.abort();\n }, this.sendTimeoutMs)\n : undefined;\n let res: Response;\n try {\n res = await fetch(serverUrl, options);\n } finally {\n // Clear on success and on error alike so a settled request never leaves an armed\n // timer that would abort a later reused controller or fire a stray callback.\n if (sendTimeout) clearTimeout(sendTimeout);\n }\n if (res === null) {\n this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE });\n return;\n }\n if (res.status >= 200 && res.status < 300) {\n const skipCode = res.headers?.get?.(EVENT_SKIPPED_HEADER) ?? null;\n this.applyServerDirective(context.sessionId, skipCode);\n }\n if (!useRetry) {\n let responseBody = '';\n try {\n responseBody = JSON.stringify(res.body, null, 2);\n } catch {\n // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n }\n this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n } else {\n let responseBody = '';\n if (res.status === 413) {\n try {\n responseBody = await res.text();\n } catch {\n // best effort\n }\n }\n await this.handleReponse(res.status, context, responseBody);\n }\n } catch (e) {\n // A send timeout aborts the fetch, which rejects with an AbortError. Treat that as a\n // transient network failure and route it through the same retry budget/backoff as a\n // 5xx (so a single stalled request doesn't permanently drop the batch) when retries\n // are enabled. completeRequest fires onComplete exactly once via either branch\n // (handleOtherResponse only completes on retry exhaustion), so onComplete can't fire\n // twice. Non-abort errors keep the original complete-with-error behavior.\n // Browsers reject an aborted fetch with a DOMException named 'AbortError', which is NOT an\n // Error instance — an `instanceof Error` check would misroute every send-timeout abort to\n // the fatal completeRequest path, defeating the retry. Match on the name across any thrown\n // object (DOMException or Error) instead.\n const isAbort = !!e && typeof e === 'object' && (e as { name?: unknown }).name === 'AbortError';\n if (isAbort && useRetry) {\n await this.handleOtherResponse(context);\n } else {\n this.completeRequest({ context, err: e as string });\n }\n }\n }\n\n async handleReponse(status: number, context: SessionReplayDestinationContext, responseBody = '') {\n const parsedStatus = new BaseTransport().buildStatus(status);\n switch (parsedStatus) {\n case Status.Success:\n this.handleSuccessResponse(context);\n break;\n case Status.Failed:\n case Status.Timeout: // 408: server timed out waiting for request, data not received\n case Status.RateLimit: // 429: retry with existing backoff rather than silently dropping\n await this.handleOtherResponse(context);\n break;\n case Status.PayloadTooLarge:\n this.handlePayloadTooLargeResponse(context, WAF_PAYLOAD_TOO_LARGE_PATTERN.test(responseBody));\n break;\n default:\n // 499 (client closed connection / upstream dropped) is also retryable\n if (status === 499) {\n await this.handleOtherResponse(context);\n break;\n }\n this.completeRequest({ context, err: UNEXPECTED_NETWORK_ERROR_MESSAGE });\n }\n }\n\n handlePayloadTooLargeResponse(context: SessionReplayDestinationContext, isWaf: boolean): void {\n const source = isWaf ? 'WAF (compressed payload too large)' : 'server (event too large)';\n const totalSizeKB = Math.round(context.events.reduce((sum, e) => sum + e.length, 0) / KB_SIZE);\n\n if (!isWaf) {\n this.completeRequest({\n context,\n err: `Session replay event batch dropped: ${source} rejected payload (${context.events.length} events, ${totalSizeKB} KB) — not retrying non-WAF 413`,\n });\n return;\n }\n\n if (context.events.length === 1) {\n this.completeRequest({\n context,\n err: `Session replay event dropped: single event (${totalSizeKB} KB, 1 event) rejected by ${source} — cannot split further`,\n });\n return;\n }\n\n this.loggerProvider.warn(\n `Session replay event batch rejected by ${source} (${context.events.length} events, ${totalSizeKB} KB total) — splitting and retrying`,\n );\n\n // Clean up the original IDB record, then re-enqueue both halves as new in-memory batches.\n // For a merged-on-throttle context (mergeQueueAfterThrottle), this onComplete is the\n // fanned-out callback covering N source IDB records — they'll all be cleaned up here.\n // Halves get noop onCompletes, so a page-close between this cleanup and a half delivery\n // means up to N source sequences are lost. The merge soft cap (1.4MB chars) is well under\n // the 10MB compressed 413 ceiling, so a 413 on a merged context is exceedingly rare in\n // practice; the alternative — deferring source cleanup until both halves complete — would\n // significantly complicate the retry path for marginal benefit.\n void context.onComplete();\n const noop = (): Promise<void> => Promise.resolve();\n const mid = Math.floor(context.events.length / 2);\n this.sendEventsList({ ...context, events: context.events.slice(0, mid), onComplete: noop });\n this.sendEventsList({ ...context, events: context.events.slice(mid), onComplete: noop });\n }\n\n handleSuccessResponse(context: SessionReplayDestinationContext) {\n const sizeOfEventsList = Math.round(new Blob(context.events).size / KB_SIZE);\n this.completeRequest({\n context,\n success: `Session replay event batch tracked successfully for session id ${context.sessionId}, size of events: ${sizeOfEventsList} KB`,\n });\n }\n\n async handleOtherResponse(context: SessionReplayDestinationContext) {\n const delay = Math.random() * context.attempts * this.retryTimeout;\n context.attempts++;\n if (context.attempts > (context.flushMaxRetries || 0)) {\n this.completeRequest({ context, err: MAX_RETRIES_EXCEEDED_MESSAGE });\n return;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n await this.send(context, true);\n }\n\n completeRequest({\n context,\n err,\n success,\n }: {\n context: SessionReplayDestinationContext;\n err?: string;\n success?: string;\n }) {\n void context.onComplete();\n if (err) {\n this.loggerProvider.warn(err);\n } else if (success) {\n this.loggerProvider.log(success);\n }\n }\n\n /**\n * Applies the server's back-pressure signal carried on a 200 response.\n *\n * - `EVENT_SKIP_CODE_THROTTLED` (server-side rate limit): pause the flush schedule\n * for `THROTTLED_FLUSH_PAUSE_MS` so we keep batching events instead of retry-storming.\n * - `EVENT_SKIP_CODE_CAPTURE_DISABLED` / `EVENT_SKIP_CODE_INVALID_RANGE`: hard kill\n * switch for this session — drop the queued contexts and stop accepting new ones.\n * New sessions are unaffected.\n * - `null` (clean 200, no header): clear any throttle pause; subsequent flushes resume\n * on the normal cadence.\n */\n private applyServerDirective(sessionId: string | number, skipCode: string | null) {\n if (skipCode === null) {\n this.flushPauseUntilMs = 0;\n this.mergeLogFiredThisPause = false;\n return;\n }\n if (skipCode === EVENT_SKIP_CODE_THROTTLED) {\n const wasInPause = this.flushPauseUntilMs > Date.now();\n this.flushPauseUntilMs = Date.now() + THROTTLED_FLUSH_PAUSE_MS;\n // Log only on pause-state transitions — a throttled server may reply to many\n // batches per minute, and one log per batch would flood the console.\n if (!wasInPause) {\n this.loggerProvider.log(\n `Session replay throttled by server; pausing flush schedule for ${THROTTLED_FLUSH_PAUSE_MS / 1000}s`,\n );\n }\n return;\n }\n if (skipCode === EVENT_SKIP_CODE_CAPTURE_DISABLED || skipCode === EVENT_SKIP_CODE_INVALID_RANGE) {\n this.killSession(sessionId, skipCode);\n }\n // Unknown skip codes are ignored — the server may add new ones, and our default\n // behavior (treat as a normal 200) preserves throughput rather than penalizing the\n // session for a code we don't recognize.\n }\n\n private killSession(sessionId: string | number, skipCode: string) {\n if (this.killedSessions.has(sessionId)) return;\n this.killedSessions.add(sessionId);\n // Set preserves insertion order, so deleting the first key evicts the oldest entry.\n if (this.killedSessions.size > MAX_KILLED_SESSIONS) {\n for (const oldest of this.killedSessions) {\n this.killedSessions.delete(oldest);\n break;\n }\n }\n this.loggerProvider.log(\n `Session replay capture stopped for session ${sessionId} by server directive ${skipCode}; remaining events will be dropped`,\n );\n // Drain any queued contexts for this session so their IDB records get cleaned up\n // via onComplete, instead of sitting in the queue waiting for a flush we'll never make.\n const remaining: SessionReplayDestinationContext[] = [];\n for (const queued of this.queue) {\n if (queued.sessionId === sessionId) {\n this.completeRequest({ context: queued, err: SESSION_KILLED_MESSAGE });\n } else {\n remaining.push(queued);\n }\n }\n this.queue = remaining;\n }\n}\n","/**\n * Gzip-compresses a JSON string using the CompressionStream API.\n * The `scope` parameter must be the global object (window or self) that\n * owns the CompressionStream constructor. The caller is responsible for\n * verifying that CompressionStream exists on that scope before calling.\n * Returns null if compression fails for any reason.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function gzipJson(jsonStr: string, scope: any): Promise<Uint8Array | null> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n const CS = scope.CompressionStream as typeof CompressionStream;\n const stream = new CS('gzip');\n const writer = stream.writable.getWriter();\n const reader = stream.readable.getReader();\n\n // Read concurrently with write+close. CompressionStream applies back-pressure:\n // close() blocks until all compressed output is consumed, so the reader must\n // run in parallel or close() will deadlock waiting for the readable side to drain.\n const chunks: Uint8Array[] = [];\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const readPromise: Promise<void> = (async () => {\n for (;;) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { done, value } = await reader.read();\n if (done) break;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n chunks.push(value);\n }\n })();\n\n await writer.write(new TextEncoder().encode(jsonStr));\n await writer.close();\n await readPromise;\n\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n } catch {\n return null;\n }\n}\n","import { ILogger } from '@amplitude/analytics-core';\nimport { DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES, MAX_INTERVAL, MIN_INTERVAL } from '../constants';\nimport { Events, EventsStore, SendingSequencesReturn } from '../typings/session-replay';\n\nexport type InstanceArgs = {\n loggerProvider: ILogger;\n minInterval?: number;\n maxInterval?: number;\n maxPersistedEventsSize?: number;\n};\n\nexport abstract class BaseEventsStore<KeyType> implements EventsStore<KeyType> {\n protected readonly loggerProvider: ILogger;\n private minInterval = MIN_INTERVAL;\n private maxInterval = MAX_INTERVAL;\n private maxPersistedEventsSize = DEFAULT_MAX_PERSISTED_EVENTS_SIZE_BYTES;\n // Assigned in the constructor after `minInterval` is overridden by `args`. Class-field\n // initializers run before the constructor body, so initializing here would freeze\n // `interval` at the class-field default (500ms) — defeating any caller-supplied minInterval\n // for the very first split.\n private interval!: number;\n private _timeAtLastSplit = Date.now(); // Initialize this so we have a point of comparison when events are recorded\n\n public get timeAtLastSplit() {\n return this._timeAtLastSplit;\n }\n\n constructor(args: InstanceArgs) {\n this.loggerProvider = args.loggerProvider;\n this.minInterval = args.minInterval ?? this.minInterval;\n this.maxInterval = args.maxInterval ?? this.maxInterval;\n this.maxPersistedEventsSize = args.maxPersistedEventsSize ?? this.maxPersistedEventsSize;\n this.interval = this.minInterval;\n }\n\n abstract addEventToCurrentSequence(\n sessionId: string | number,\n event: string,\n ): Promise<SendingSequencesReturn<KeyType> | undefined>;\n abstract getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>;\n abstract storeCurrentSequence(sessionId: number): Promise<SendingSequencesReturn<KeyType> | undefined>;\n abstract storeSendingEvents(sessionId: string | number, events: Events): Promise<KeyType | undefined>;\n abstract cleanUpSessionEventsStore(sessionId: number, sequenceId: KeyType): Promise<void>;\n\n /**\n * Returns the UTF-8 byte size of a string without buffer allocation, matching the\n * actual wire byte count for non-ASCII content (Base64 image data, emoji, etc.).\n */\n private getStringSize(str: string): number {\n let bytes = 0;\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code <= 0x7f) {\n bytes++;\n } else if (code <= 0x7ff) {\n bytes += 2;\n } else if (code >= 0xd800 && code <= 0xdbff) {\n // High surrogate — check for a valid low surrogate before consuming the pair.\n const next = i + 1 < str.length ? str.charCodeAt(i + 1) : NaN;\n if (next >= 0xdc00 && next <= 0xdfff) {\n // Valid surrogate pair → encodes a code point above U+FFFF (4 UTF-8 bytes).\n bytes += 4;\n i++;\n } else {\n // Orphaned high surrogate — treated as a replacement character (3 UTF-8 bytes).\n bytes += 3;\n }\n } else if (code >= 0xdc00 && code <= 0xdfff) {\n // Orphaned low surrogate — treated as a replacement character (3 UTF-8 bytes).\n bytes += 3;\n } else {\n // Other BMP character (U+0800–U+FFFF, excluding surrogates): 3 UTF-8 bytes.\n bytes += 3;\n }\n }\n return bytes;\n }\n\n /**\n * Calculates the total UTF-8 byte size of events array\n * Accounts for JSON serialization overhead when sent to backend\n */\n private getEventsArraySize(events: Events): number {\n let totalSize = 0;\n for (const event of events) {\n totalSize += this.getStringSize(event);\n }\n\n // Approximate overhead from the array portion of the JSON payload:\n // - Array brackets: [] = 2 bytes\n // - Commas between events: events.length - 1 bytes\n // - Double quotes wrapping each event string: events.length * 2 bytes\n // Note: does not include the outer { version, events } wrapper (~22 bytes) or\n // per-event JSON-escaping of \" and \\ characters; the 2 MB MAX_EVENT_LIST_SIZE cap\n // stays well under the server's 10 MB decompressed split threshold even with those.\n const overhead = 2 + Math.max(0, events.length - 1) + events.length * 2;\n\n return totalSize + overhead;\n }\n\n /**\n * Determines whether to send the events list to the backend and start a new\n * empty events list, based on the size of the list as well as the last time sent\n * @param nextEventString\n * @returns boolean\n */\n shouldSplitEventsList = (events: Events, nextEventString: string): boolean => {\n const sizeOfNextEvent = this.getStringSize(nextEventString);\n const sizeOfEventsList = this.getEventsArraySize(events);\n\n // Check size constraint first (most likely to trigger)\n if (sizeOfEventsList + sizeOfNextEvent >= this.maxPersistedEventsSize) {\n return true;\n }\n if (Date.now() - this.timeAtLastSplit > this.interval && events.length) {\n this.interval = Math.min(this.maxInterval, this.interval + this.minInterval);\n this._timeAtLastSplit = Date.now();\n return true;\n }\n return false;\n };\n}\n","import { ILogger } from '@amplitude/analytics-core';\n\n/**\n * IndexedDB can surface transient AbortErrors (internal cancellations,\n * cleanup) that are not actionable by customers. We downgrade these from\n * warn → debug to avoid triggering Sentry alerts in customer projects.\n * Duck-types on name rather than instanceof DOMException because the idb\n * wrapper library and test environments may surface plain Error objects.\n */\nconst isAbortError = (e: unknown): boolean =>\n typeof e === 'object' && e !== null && (e as { name?: string }).name === 'AbortError';\n\n/**\n * Logs an IDB error at the appropriate level: debug for transient\n * AbortErrors (to avoid customer Sentry noise), warn for everything else.\n */\nexport const logIdbError = (logger: ILogger, message: string, error?: unknown) => {\n if (isAbortError(error)) {\n logger.debug(message);\n } else {\n logger.warn(message);\n }\n};\n","import { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { STORAGE_FAILURE } from '../messages';\nimport { EventType, Events, SendingSequencesReturn } from '../typings/session-replay';\nimport { BaseEventsStore, InstanceArgs as BaseInstanceArgs } from './base-events-store';\nimport { logIdbError } from '../utils/is-abort-error';\n\n// crypto.randomUUID() requires a secure context (https). Fall back to a\n// Math.random-based UUID for http origins or older browsers — tab IDs don't\n// need to be cryptographically secure, just unique within a session.\nexport function generateUUID(): string {\n try {\n return crypto.randomUUID();\n } catch {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n });\n }\n}\n\nexport const currentSequenceKey = 'sessionCurrentSequence';\nexport const sequencesToSendKey = 'sequencesToSend';\nexport const remoteConfigKey = 'remoteConfig';\n\n// Timeout for openDB at init. IDB openDB can hang forever when another tab\n// holds an open connection during a version upgrade, or when the DB is in a\n// \"closing\" state (documented Chrome behaviour). When that happens we want\n// SessionReplayEventsIDBStore.new() to bail out so the caller can fall back\n// to the in-memory store.\nexport const OPEN_DB_TIMEOUT_MS = 2000;\n\n// Timeout for per-operation tx.done settlement. Mid-recording a readwrite\n// transaction can stall (storage pressure in some browsers stalls instead of\n// throwing); without a timeout, recordFailure() is never called and the\n// memory fallback never triggers. The transaction may still settle later;\n// the timedOut flag prevents double-counting alongside errorLogged.\nexport const TX_DONE_TIMEOUT_MS = 5000;\n\n/**\n * Race a promise against a timeout. Resolves/rejects with the original\n * promise's value when it settles first; rejects with a timeout error if\n * `ms` elapses first. Either way the timer is cleared so we don't leak\n * pending setTimeouts.\n */\nexport function withTimeout<T>(promise: Promise<T>, ms: number, message = 'IDB operation timed out'): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`${message} after ${ms}ms`)), ms);\n promise.then(\n (v) => {\n clearTimeout(timer);\n resolve(v);\n },\n (e) => {\n clearTimeout(timer);\n reject(e);\n },\n );\n });\n}\n\n/**\n * Arms a watchdog that fires `onTimeout` only if `tx.done` hasn't settled\n * within `ms`. A \"soft cancel\" returned to the caller suppresses the timeout\n * if the synchronous operation body completes without exception — important\n * because in test environments fake timers can fire ahead of tx.done's commit\n * microtask. Production behaviour is preserved: a genuinely stalled\n * transaction (no commit, no error, individual op promises never resolved)\n * cannot reach the soft-cancel call and the timeout fires as designed.\n *\n * Soft-cancel is only invoked once the awaits inside the operation's outer\n * try block have all returned — i.e. the IDB driver acknowledged each\n * individual put/get. If the driver accepts a put but the underlying\n * transaction silently fails to commit (the production stall scenario),\n * tx.done still hasn't settled, and recordFailure must NOT have been\n * suppressed. The fix for that scenario in production is the tx.done.catch\n * handler attached separately by callers, which catches the eventual abort.\n *\n * The soft-cancel pattern only suppresses the timeout for the \"all puts\n * resolved successfully\" case — a case where tx.done is overwhelmingly\n * likely to settle imminently in production. If it doesn't, callers can\n * still detect the failure on the NEXT operation (which will fail to open\n * a transaction or hit the same pressure), because all three methods use\n * readwrite transactions on the same two stores, which IDB serializes:\n * if T1's tx.done never settles, T2 is blocked waiting for T1 to commit or\n * abort — T2's put/get requests never resolve, T2 never reaches its\n * soft-cancel, and T2's watchdog fires, calling recordFailure().\n */\nfunction armTxDoneTimeout(txDone: Promise<unknown>, ms: number, onTimeout: () => void): () => void {\n const timer = setTimeout(onTimeout, ms);\n // Belt-and-braces: clear the timer when tx.done settles, even though the\n // primary cancel path is the caller's success-path cancel(). This covers\n // the case where tx.done settles with no caller cancellation (shouldn't\n // happen in current code paths, but cheap insurance).\n txDone.then(\n () => clearTimeout(timer),\n () => clearTimeout(timer),\n );\n return () => clearTimeout(timer);\n}\n\nexport interface SessionReplayDB extends DBSchema {\n sessionCurrentSequence: {\n key: number;\n value: Omit<SendingSequencesReturn<number>, 'sequenceId'> & { tabId?: string };\n };\n sequencesToSend: {\n key: number;\n value: Omit<SendingSequencesReturn<number>, 'sequenceId'> & { tabId?: string };\n indexes: { sessionId: string | number };\n };\n}\n\nexport const defineObjectStores = (db: IDBPDatabase<SessionReplayDB>) => {\n let sequencesStore;\n let currentSequenceStore;\n if (!db.objectStoreNames.contains(currentSequenceKey)) {\n currentSequenceStore = db.createObjectStore(currentSequenceKey, {\n keyPath: 'sessionId',\n });\n }\n if (!db.objectStoreNames.contains(sequencesToSendKey)) {\n sequencesStore = db.createObjectStore(sequencesToSendKey, {\n keyPath: 'sequenceId',\n autoIncrement: true,\n });\n sequencesStore.createIndex('sessionId', 'sessionId');\n }\n return {\n sequencesStore,\n currentSequenceStore,\n };\n};\n\nexport const createStore = async (dbName: string) => {\n // Wrap openDB with a timeout so a hung connection (foreign tab holding an\n // open handle during version upgrade, or \"closing\" DB) doesn't block the\n // SDK from initialising. On timeout this rejects, which propagates up to\n // SessionReplayEventsIDBStore.new()'s catch block, returning undefined and\n // triggering the memory fallback.\n return await withTimeout(\n openDB<SessionReplayDB>(dbName, 1, {\n upgrade: defineObjectStores,\n }),\n OPEN_DB_TIMEOUT_MS,\n 'IDB openDB timed out',\n );\n};\n\ntype InstanceArgs = {\n apiKey: string;\n db: IDBPDatabase<SessionReplayDB>;\n tabId: string;\n onPersistentFailure?: () => void;\n consecutiveFailureThreshold?: number;\n} & BaseInstanceArgs;\n\nexport class SessionReplayEventsIDBStore extends BaseEventsStore<number> {\n private readonly db: IDBPDatabase<SessionReplayDB>;\n private readonly tabId: string;\n private readonly onPersistentFailure?: () => void;\n private readonly consecutiveFailureThreshold: number;\n private consecutiveFailures = 0;\n private hasTriggeredFallback = false;\n private emptyFilteredCount = 0;\n\n // Sampled (1 in 100) debug log so we can observe whether the store-layer guards\n // are catching empty-batch cases that would otherwise hit the empty-body 400 path\n // on the server. Logged at debug, not warn — this is operational telemetry for\n // post-deploy verification, not a customer-actionable warning. Per-store-instance\n // counter (rather than Math.random) keeps the first hit deterministic for tests.\n private maybeLogEmptyFiltered(source: string) {\n if (this.emptyFilteredCount++ % 100 === 0) {\n this.loggerProvider.debug(`Filtered empty session replay sequence at ${source} (idb store)`);\n }\n }\n\n constructor(args: InstanceArgs) {\n super(args);\n this.db = args.db;\n this.tabId = args.tabId;\n this.onPersistentFailure = args.onPersistentFailure;\n // Default threshold of 1: fall back to memory immediately on the first IDB failure.\n // Session replay correctness is far more important than persistence, and IDB errors\n // are typically the symptom of a deeper problem (storage pressure, locked DB, broken\n // browser implementation) that won't recover within a single session. Memory store\n // is always safe — fall back early.\n this.consecutiveFailureThreshold = args.consecutiveFailureThreshold ?? 1;\n }\n\n private recordFailure() {\n this.consecutiveFailures++;\n if (!this.hasTriggeredFallback && this.consecutiveFailures >= this.consecutiveFailureThreshold) {\n this.hasTriggeredFallback = true;\n this.onPersistentFailure?.();\n }\n }\n\n private recordSuccess() {\n this.consecutiveFailures = 0;\n }\n\n static async new(\n type: EventType,\n args: Omit<InstanceArgs, 'db' | 'tabId'> & { tabId?: string },\n ): Promise<SessionReplayEventsIDBStore | undefined> {\n try {\n const dbSuffix = type === 'replay' ? '' : `_${type}`;\n const dbName = `${args.apiKey.substring(0, 10)}_amp_session_replay_events${dbSuffix}`;\n const db = await createStore(dbName);\n // Generate a fresh in-memory UUID per store instance. sessionStorage is\n // intentionally avoided: standalone session-replay customers (without the\n // analytics-browser SDK) would be exposed to a new storage surface they\n // did not consent to, and persistence across page reloads is not needed —\n // completed sequences in sequencesToSend are flushed by any tab/instance.\n const tabId = args.tabId ?? generateUUID();\n return new SessionReplayEventsIDBStore({\n ...args,\n db,\n tabId,\n });\n } catch (e) {\n logIdbError(args.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n }\n return;\n }\n\n async getCurrentSequenceEvents(sessionId?: number) {\n if (sessionId) {\n const record = await this.db.get('sessionCurrentSequence', sessionId);\n if (!record) {\n return undefined;\n }\n // Only return our own tab's record (or legacy untagged records).\n if (record.tabId && record.tabId !== this.tabId) {\n return undefined;\n }\n const { tabId: _tabId, ...rest } = record;\n return [rest];\n }\n\n const allEvents = [];\n for (const record of await this.db.getAll('sessionCurrentSequence')) {\n if (record.tabId && record.tabId !== this.tabId) {\n continue;\n }\n const { tabId: _tabId, ...rest } = record;\n allEvents.push(rest);\n }\n\n return allEvents;\n }\n\n getSequencesToSend = async (): Promise<SendingSequencesReturn<number>[] | undefined> => {\n let errorLogged = false;\n let timedOut = false;\n try {\n const sequences: SendingSequencesReturn<number>[] = [];\n // readwrite mode so we can prune stale empty rows in-place. Without that,\n // older-SDK-persisted events:[] rows sit in IDB indefinitely and re-fire the\n // sampled log on every flush cycle, creating Datadog noise indistinguishable\n // from active bug occurrences.\n const tx = this.db.transaction('sequencesToSend', 'readwrite');\n // Attach a catch handler immediately so tx.done rejections (e.g. AbortError after\n // cursor traversal completes) are always handled without blocking the return path.\n // The errorLogged / timedOut flags prevent double-logging and double-recording\n // when the outer catch (or the timeout race) already fired for the same abort.\n tx.done.catch((e: unknown) => {\n if (!errorLogged && !timedOut) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n });\n // Arm a watchdog so a stalled transaction (no error, no commit, e.g.\n // storage pressure on some browsers) still trips the failure counter.\n // The watchdog fires only when tx.done genuinely never settles AND the\n // operation's success path didn't run; if tx.done rejects (abort), the\n // tx.done.catch handler above is the sole recorder of failure.\n const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n if (!errorLogged && !timedOut) {\n timedOut = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n this.recordFailure();\n }\n });\n let cursor = await tx.store.openCursor();\n while (cursor) {\n const { sessionId, events } = cursor.value;\n // Skip empty persisted records. These can come from older SDK builds that\n // wrote zero-event sequences via addEventToCurrentSequence's split path\n // (when a single oversized event triggered a split with empty buffer);\n // flushing them produces empty-body POSTs the server rejects with 400.\n // Delete them in-place so they don't re-fire the sampled log on every\n // subsequent flush — by construction (this fix) we never write empty rows\n // anymore, so any empty row is unambiguously stale.\n if (events.length === 0) {\n this.maybeLogEmptyFiltered('getSequencesToSend');\n await cursor.delete();\n } else {\n // Return all completed sequences regardless of tabId. Filtering by tab\n // would cause event loss on page reload: a new store instance gets a\n // fresh in-memory UUID and would never see sequences written by the\n // previous instance. Completed sequences are safe to flush by any\n // tab/instance; the server deduplicates, and cleanUpSessionEventsStore\n // on an already-deleted key is a no-op.\n sequences.push({\n events,\n sequenceId: cursor.key,\n sessionId,\n });\n }\n cursor = await cursor.continue();\n }\n\n this.recordSuccess();\n cancelTimeout();\n return sequences;\n } catch (e) {\n if (!timedOut) {\n errorLogged = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n }\n return undefined;\n };\n\n storeCurrentSequence = async (sessionId: number) => {\n let errorLogged = false;\n let timedOut = false;\n try {\n // Wrap the read of sessionCurrentSequence and the writes to sequencesToSend +\n // sessionCurrentSequence in a single readwrite transaction so the three operations\n // commit or roll back atomically. Without this, a concurrent addEventToCurrentSequence\n // call could interleave and either lose the events being promoted or duplicate them\n // (storeCurrentSequence reads N events, addEvent appends an N+1th, storeCurrentSequence\n // writes only the first N back to sequencesToSend, then resets the slot — losing N+1).\n const tx = this.db.transaction([currentSequenceKey, sequencesToSendKey], 'readwrite');\n tx.done.catch((e: unknown) => {\n if (!errorLogged && !timedOut) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n });\n // Stalled-transaction protection: see armTxDoneTimeout in getSequencesToSend.\n const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n if (!errorLogged && !timedOut) {\n timedOut = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n this.recordFailure();\n }\n });\n\n const currentSequenceData = await tx.objectStore(currentSequenceKey).get(sessionId);\n // Skip promotion if the slot is empty or owned by another tab — let the owning\n // tab promote its own events on its next addEventToCurrentSequence/storeCurrentSequence\n // call (via Bug 1's foreign-tab promotion path).\n // Don't call recordSuccess() here: no write was performed, so this is not\n // evidence the storage layer is healthy — leave the failure counter unchanged.\n if (!currentSequenceData || (currentSequenceData.tabId && currentSequenceData.tabId !== this.tabId)) {\n cancelTimeout();\n return undefined;\n }\n\n // Skip empty sequences — no point writing a zero-event row to sequencesToSend\n // (would later POST as an empty body and 400 on the server).\n if (currentSequenceData.events.length === 0) {\n this.maybeLogEmptyFiltered('storeCurrentSequence');\n cancelTimeout();\n return undefined;\n }\n\n const sequenceId = await tx.objectStore(sequencesToSendKey).put({\n sessionId,\n events: currentSequenceData.events,\n tabId: this.tabId,\n });\n\n await tx.objectStore(currentSequenceKey).put({\n sessionId,\n events: [],\n tabId: this.tabId,\n });\n\n this.recordSuccess();\n cancelTimeout();\n const { tabId: _tabId, ...rest } = currentSequenceData;\n return {\n ...rest,\n sessionId,\n sequenceId,\n };\n } catch (e) {\n if (!timedOut) {\n errorLogged = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n }\n return undefined;\n };\n\n addEventToCurrentSequence = async (sessionId: number, event: string) => {\n let errorLogged = false;\n let timedOut = false;\n try {\n // Always open a readwrite transaction over both stores so that the read and\n // any subsequent write are atomic. IDB serializes readwrite transactions on\n // overlapping stores, so concurrent fire-and-forget callers (events-manager\n // does not await this method) are queued by the engine rather than interleaving\n // — eliminating the TOCTOU race that a narrow-read + separate-write approach\n // would introduce on the split path.\n const tx = this.db.transaction([currentSequenceKey, sequencesToSendKey], 'readwrite');\n // Attach a catch handler immediately so tx.done rejections (e.g. AbortError after\n // put succeeds but before auto-commit) are always handled without blocking.\n // The errorLogged / timedOut flags prevent double-logging when the outer catch\n // (or the timeout) already fired for the same transaction.\n tx.done.catch((e: unknown) => {\n if (!errorLogged && !timedOut) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n });\n // Stalled-transaction protection: see armTxDoneTimeout in getSequencesToSend.\n const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n if (!errorLogged && !timedOut) {\n timedOut = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n this.recordFailure();\n }\n });\n const sequenceEvents = await tx.objectStore(currentSequenceKey).get(sessionId);\n\n // Foreign-tab record path: another tab owns the current-sequence slot for this\n // sessionId. Don't silently overwrite — that would drop the foreign tab's\n // in-progress events. Promote them to sequencesToSend (tabId kept for forensics)\n // before claiming the slot for ourselves. getSequencesToSend no longer filters\n // by tabId, so either tab may flush the promoted sequence; server deduplicates.\n if (sequenceEvents?.tabId && sequenceEvents.tabId !== this.tabId) {\n if (sequenceEvents.events.length > 0) {\n await tx.objectStore(sequencesToSendKey).put({\n sessionId,\n events: sequenceEvents.events,\n tabId: sequenceEvents.tabId,\n });\n }\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n // ownedSequence is either undefined (no record yet) or this tab's record.\n const ownedSequence = sequenceEvents;\n\n if (!ownedSequence) {\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n if (!this.shouldSplitEventsList(ownedSequence.events, event)) {\n await tx\n .objectStore(currentSequenceKey)\n .put({ sessionId, events: ownedSequence.events.concat(event), tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n // Split path: reset sessionCurrentSequence and write the old events to\n // sequencesToSend atomically within the same transaction.\n const eventsToSend = ownedSequence.events;\n\n // shouldSplitEventsList can return true with an empty buffer when a single\n // incoming event is larger than MAX_EVENT_LIST_SIZE (2 MB) — the size-constraint\n // branch fires regardless of current length. Don't write a zero-event row to\n // sequencesToSend (which would later POST as an empty body, the SR-4284 root\n // cause); just claim the slot for the new event without finalizing anything.\n // This is the *primary* root-cause filter site: warn here so post-deploy\n // Datadog can confirm the new SDK is actually preventing the bug at its source\n // (vs. only seeing leftover-state hits at the get/storeCurrentSequence layers).\n if (eventsToSend.length === 0) {\n this.maybeLogEmptyFiltered('addEventToCurrentSequence');\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n this.recordSuccess();\n cancelTimeout();\n return undefined;\n }\n\n await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n const sequenceId = await tx.objectStore(sequencesToSendKey).put({\n sessionId,\n events: eventsToSend,\n tabId: this.tabId,\n });\n\n this.recordSuccess();\n cancelTimeout();\n return {\n events: eventsToSend,\n sessionId,\n sequenceId,\n };\n } catch (e) {\n if (!timedOut) {\n errorLogged = true;\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n }\n return undefined;\n };\n\n storeSendingEvents = async (sessionId: number, events: Events) => {\n try {\n const sequenceId = await this.db.put<'sequencesToSend'>(sequencesToSendKey, {\n sessionId: sessionId,\n events: events,\n tabId: this.tabId,\n });\n this.recordSuccess();\n return sequenceId;\n } catch (e) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n return undefined;\n };\n\n cleanUpSessionEventsStore = async (_sessionId: number, sequenceId?: number) => {\n if (!sequenceId) {\n return;\n }\n try {\n await this.db.delete<'sequencesToSend'>(sequencesToSendKey, sequenceId);\n this.recordSuccess();\n } catch (e) {\n logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n this.recordFailure();\n }\n };\n}\n","import { Events, SendingSequencesReturn } from '../typings/session-replay';\nimport { BaseEventsStore } from './base-events-store';\n\nexport class InMemoryEventsStore extends BaseEventsStore<number> {\n private finalizedSequences: Record<number, { sessionId: string | number; events: string[] }> = {};\n private sequences: Record<string | number, string[]> = {};\n private sequenceId = 0;\n private emptyFilteredCount = 0;\n\n private resetCurrentSequence(sessionId: string | number) {\n this.sequences[sessionId] = [];\n }\n\n private addSequence(sessionId: string | number): SendingSequencesReturn<number> {\n const sequenceId = this.sequenceId++;\n const events = [...this.sequences[sessionId]];\n this.finalizedSequences[sequenceId] = { sessionId, events };\n this.resetCurrentSequence(sessionId);\n return { sequenceId, events, sessionId };\n }\n\n // Sampled (1 in 100) debug log so we can observe whether the store-layer guards\n // are actually catching cases that would otherwise hit the empty-body 400 path on\n // the server. Logged at debug, not warn — this is operational telemetry for\n // post-deploy verification, not a customer-actionable warning. Per-store-instance\n // counter rather than Math.random keeps the first hit deterministic for tests.\n private maybeLogEmptyFiltered(source: string) {\n if (this.emptyFilteredCount++ % 100 === 0) {\n this.loggerProvider.debug(`Filtered empty session replay sequence at ${source} (in-memory store)`);\n }\n }\n\n async getSequencesToSend(): Promise<SendingSequencesReturn<number>[] | undefined> {\n const result: SendingSequencesReturn<number>[] = [];\n for (const [sequenceId, { sessionId, events }] of Object.entries(this.finalizedSequences)) {\n if (events.length === 0) {\n // Prune in-place for consistency with the IDB store: by construction we\n // never write empty sequences anymore, so any empty entry is unambiguously\n // stale residue. Without the delete, every subsequent getSequencesToSend\n // would re-iterate the empty entry and re-fire the sampled log, producing\n // repeated noise that's indistinguishable from active bug occurrences.\n this.maybeLogEmptyFiltered('getSequencesToSend');\n delete this.finalizedSequences[Number(sequenceId)];\n continue;\n }\n result.push({ sequenceId: Number(sequenceId), sessionId, events });\n }\n return result;\n }\n\n async storeCurrentSequence(sessionId: string | number): Promise<SendingSequencesReturn<number> | undefined> {\n const buffered = this.sequences[sessionId];\n if (!buffered) {\n return undefined;\n }\n if (buffered.length === 0) {\n // Slot exists but is empty (e.g. drained by a prior storeCurrentSequence then\n // re-flushed before any new event landed). Don't finalize a zero-event row.\n this.maybeLogEmptyFiltered('storeCurrentSequence');\n return undefined;\n }\n return this.addSequence(sessionId);\n }\n\n async addEventToCurrentSequence(\n sessionId: number,\n event: string,\n ): Promise<SendingSequencesReturn<number> | undefined> {\n if (!this.sequences[sessionId]) {\n this.resetCurrentSequence(sessionId);\n }\n\n let sequenceReturn: SendingSequencesReturn<number> | undefined;\n // shouldSplitEventsList can return true with an empty buffer when a single\n // incoming event is larger than MAX_EVENT_LIST_SIZE (2 MB) — the size-constraint\n // branch fires regardless of current length. Don't finalize a zero-event sequence\n // (the SR-4284 root cause); just hold the incoming event in the buffer.\n // shouldSplitEventsList's time-elapsed branch only fires when events.length > 0\n // (see base-events-store.ts), so calling it on an empty buffer has no side effects.\n if (this.shouldSplitEventsList(this.sequences[sessionId], event)) {\n if (this.sequences[sessionId].length === 0) {\n this.maybeLogEmptyFiltered('addEventToCurrentSequence');\n } else {\n sequenceReturn = this.addSequence(sessionId);\n }\n }\n\n this.sequences[sessionId].push(event);\n\n return sequenceReturn;\n }\n\n async storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined> {\n this.finalizedSequences[this.sequenceId] = { sessionId, events };\n\n return this.sequenceId++;\n }\n\n async cleanUpSessionEventsStore(_sessionId: number, sequenceId?: number): Promise<void> {\n if (sequenceId !== undefined) {\n delete this.finalizedSequences[sequenceId];\n }\n }\n}\n","import {\n SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n EventsStore,\n EventType,\n StoreType,\n} from '../typings/session-replay';\n\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { MAX_SINGLE_EVENT_SIZE } from '../constants';\nimport { getStorageSize } from '../helpers';\nimport { PayloadBatcher, SessionReplayTrackDestination } from '../track-destination';\nimport { SessionReplayEventsIDBStore } from './events-idb-store';\nimport { InMemoryEventsStore } from './events-memory-store';\n\nexport type EventsManagerWithBeacon<Type extends EventType> = AmplitudeSessionReplayEventsManager<Type, string> & {\n /**\n * Returns current pending events (since last flush) for synchronous access on page exit.\n * Used to populate a sendBeacon payload when the page is unloading.\n */\n getBeaconEvents(): string[];\n /**\n * Drops all pending beacon events. Used when the session is decided to be below\n * the min duration threshold so its events don't leak into a later session's beacon.\n */\n dropPendingBeaconEvents(): void;\n trackDestination: SessionReplayTrackDestination;\n};\n\nexport const createEventsManager = async <Type extends EventType>({\n config,\n minInterval,\n maxInterval,\n maxPersistedEventsSize,\n type,\n payloadBatcher,\n storeType,\n trackDestinationWorkerScript,\n shouldSend,\n}: {\n config: SessionReplayJoinedConfig;\n type: Type;\n minInterval?: number;\n maxInterval?: number;\n maxPersistedEventsSize?: number;\n payloadBatcher?: PayloadBatcher;\n storeType: StoreType;\n trackDestinationWorkerScript?: string;\n shouldSend?: () => boolean;\n}): Promise<EventsManagerWithBeacon<Type>> => {\n // Configurable per-single-event drop cap (defaults to MAX_SINGLE_EVENT_SIZE); enforced both\n // here as a pre-send backstop and at capture time in EventCompressor.\n const maxSingleEventSize = config.maxSingleEventSizeBytes ?? MAX_SINGLE_EVENT_SIZE;\n const trackDestination = new SessionReplayTrackDestination({\n ...config,\n loggerProvider: config.loggerProvider,\n payloadBatcher,\n workerScript: trackDestinationWorkerScript,\n });\n\n const getMemoryStore = (): EventsStore<number> => {\n return new InMemoryEventsStore({\n loggerProvider: config.loggerProvider,\n maxInterval,\n minInterval,\n maxPersistedEventsSize,\n });\n };\n\n let lastKnownDeviceId: string | undefined;\n let usingIdbStore = false;\n let store!: EventsStore<number>;\n\n const switchToMemoryStore = async () => {\n if (!usingIdbStore) return;\n usingIdbStore = false;\n config.loggerProvider.warn('IDB store is experiencing repeated failures; falling back to in-memory event store.');\n const sequences = lastKnownDeviceId ? await store.getSequencesToSend() : undefined;\n store = getMemoryStore();\n if (sequences && lastKnownDeviceId) {\n const deviceId = lastKnownDeviceId;\n sequences.forEach((seq) => {\n sendEventsList({ sequenceId: seq.sequenceId, events: seq.events, sessionId: seq.sessionId, deviceId });\n });\n }\n };\n\n const getIdbStoreOrFallback = async (): Promise<EventsStore<number>> => {\n const idb = await SessionReplayEventsIDBStore.new(type, {\n loggerProvider: config.loggerProvider,\n minInterval,\n maxInterval,\n maxPersistedEventsSize,\n apiKey: config.apiKey,\n onPersistentFailure: () => {\n void switchToMemoryStore();\n },\n });\n if (!idb) {\n config.loggerProvider.log('Failed to initialize idb store, falling back to memory store.');\n return getMemoryStore();\n }\n usingIdbStore = true;\n return idb;\n };\n\n store = storeType === 'idb' ? await getIdbStoreOrFallback() : getMemoryStore();\n\n // Beacon buffer: a sliding window of pending (unsent) event strings for synchronous\n // access on page exit. Uses an absolute index counter to correctly handle concurrent\n // async flushes without losing events added between the flush call and its resolution.\n const beaconBuffer: string[] = [];\n let beaconWindowStart = 0; // absolute index of the first element in beaconBuffer\n\n const advanceBeaconWindow = (upToAbsoluteIdx: number) => {\n if (upToAbsoluteIdx <= beaconWindowStart) return;\n const trimCount = Math.min(upToAbsoluteIdx - beaconWindowStart, beaconBuffer.length);\n if (trimCount > 0) {\n beaconBuffer.splice(0, trimCount);\n beaconWindowStart = upToAbsoluteIdx;\n }\n };\n\n /**\n * Immediately sends events to the track destination.\n */\n const sendEventsList = ({\n events: rawEvents,\n sessionId,\n deviceId,\n sequenceId,\n }: {\n events: string[];\n sessionId: string | number;\n deviceId: string;\n sequenceId?: number;\n }) => {\n // Backstop for events that entered IDB before the per-event size guard in\n // addCompressedEventToManager (e.g. stored by a previous SDK version or via\n // storeCurrentSequence/sendStoredEvents which bypass the capture-time check).\n // Compare UTF-8 byte size, not JS char count, to match the server-side limit.\n const sizedEvents = rawEvents.map((e) => ({ event: e, bytes: new Blob([e]).size }));\n const oversized = sizedEvents.filter((s) => s.bytes > maxSingleEventSize);\n if (oversized.length > 0) {\n config.loggerProvider.warn(\n `Dropping ${oversized.length} oversized event(s) from session replay sequence before send. Sizes: ${oversized\n .map((s) => `${Math.round(s.bytes / 1024)} KB`)\n .join(\n ', ',\n )}. If this recurs, please open a GitHub issue at https://github.com/amplitude/Amplitude-TypeScript/issues or contact Amplitude support.`,\n );\n }\n const events =\n oversized.length > 0 ? sizedEvents.filter((s) => s.bytes <= maxSingleEventSize).map((s) => s.event) : rawEvents;\n if (events.length === 0) {\n store.cleanUpSessionEventsStore(sessionId, sequenceId).catch((e) => {\n config.loggerProvider.warn('Failed to clean up session replay events store:', e);\n });\n return;\n }\n\n if (config.debugMode) {\n getStorageSize()\n .then(({ totalStorageSize, percentOfQuota, usageDetails }) => {\n config.loggerProvider.debug(\n `Total storage size: ${totalStorageSize} KB, percentage of quota: ${percentOfQuota}%, usage details: ${usageDetails}`,\n );\n })\n .catch(() => {\n // swallow error\n });\n }\n\n trackDestination.sendEventsList({\n events: events,\n sessionId: sessionId,\n flushMaxRetries: config.flushMaxRetries,\n apiKey: config.apiKey,\n deviceId: deviceId,\n sampleRate: config.sampleRate,\n serverZone: config.serverZone,\n version: config.version,\n type,\n onComplete: async () => {\n await store.cleanUpSessionEventsStore(sessionId, sequenceId);\n return;\n },\n });\n };\n\n const sendCurrentSequenceEvents = ({ sessionId, deviceId }: { sessionId: number; deviceId: string }) => {\n lastKnownDeviceId = deviceId;\n // Evaluate shouldSend synchronously before the async store read. asyncSetSessionId\n // updates sessionStartTime immediately after calling sendEvents(), so by the time\n // storeCurrentSequence resolves the start time would reflect the new session and\n // the elapsed check would compute ~0ms, silently dropping the previous session's events.\n if (shouldSend && !shouldSend()) return;\n // Snapshot the absolute end-index before the async store read so that any events\n // pushed after this point are NOT considered sent and remain in the beacon buffer.\n const snapshotAbsIdx = beaconWindowStart + beaconBuffer.length;\n store\n .storeCurrentSequence(sessionId)\n .then((currentSequence) => {\n if (currentSequence) {\n advanceBeaconWindow(snapshotAbsIdx);\n sendEventsList({\n sequenceId: currentSequence.sequenceId,\n events: currentSequence.events,\n sessionId: currentSequence.sessionId,\n deviceId,\n });\n }\n })\n .catch((e) => {\n config.loggerProvider.warn('Failed to get current sequence of session replay events for session:', e);\n });\n };\n\n const sendStoredEvents = async ({ deviceId }: { deviceId: string }) => {\n lastKnownDeviceId = deviceId;\n const sequencesToSend = await store.getSequencesToSend();\n if (!sequencesToSend?.length) {\n return;\n }\n config.loggerProvider.log(`Draining ${sequencesToSend.length} stored sequence(s) from previous session.`);\n // These persisted sequences are about to be enqueued back-to-back. Without\n // coalescing they flush as N separate POSTs — a request flood on page load. Mark the\n // imminent flush to merge same-identity batches (the enqueues below are synchronous, so\n // the whole backlog lands in the queue before the deferred flush consumes the flag). Skip\n // the single-sequence case where there's nothing to merge.\n if (sequencesToSend.length > 1) {\n trackDestination.markCoalesceNextFlush();\n }\n sequencesToSend.forEach((sequence) => {\n sendEventsList({\n sequenceId: sequence.sequenceId,\n events: sequence.events,\n sessionId: sequence.sessionId,\n deviceId,\n });\n });\n };\n\n const addEvent = ({\n event,\n sessionId,\n deviceId,\n }: {\n event: { type: Type; data: string };\n sessionId: number;\n deviceId: string;\n }) => {\n lastKnownDeviceId = deviceId;\n // Capture shouldSend synchronously before the async store write, for the same\n // reason as sendCurrentSequenceEvents: asyncSetSessionId updates sessionStartTime\n // synchronously, so evaluating inside the .then() would use the new session's\n // start time and compute ~0ms elapsed, silently dropping a valid batch.\n const canSend = !shouldSend || shouldSend();\n // Record the absolute index of this event in the beacon buffer before the async\n // store operation. If a batch split occurs, we advance the window up to (but not\n // including) this event so that it starts the next pending window.\n const absIdx = beaconWindowStart + beaconBuffer.length;\n beaconBuffer.push(event.data);\n store\n .addEventToCurrentSequence(sessionId, event.data)\n .then((sequenceToSend) => {\n if (sequenceToSend) {\n if (!canSend) {\n // The split atomically moved events to sequencesToSend; without cleanup\n // they would be unconditionally replayed on next page load via\n // sendStoredEvents, bypassing the min session duration gate. The split\n // batch must also be dropped from the beacon buffer so it isn't sent\n // via sendBeacon on page unload (potentially attributed to a later session).\n store.cleanUpSessionEventsStore(sequenceToSend.sessionId, sequenceToSend.sequenceId).catch((e) => {\n config.loggerProvider.warn('Failed to clean up dropped session replay sequence:', e);\n });\n advanceBeaconWindow(absIdx);\n return;\n }\n // Events before absIdx belong to the split batch being sent; advance window.\n advanceBeaconWindow(absIdx);\n sendEventsList({\n sequenceId: sequenceToSend.sequenceId,\n events: sequenceToSend.events,\n sessionId: sequenceToSend.sessionId,\n deviceId,\n });\n }\n })\n .catch((e) => {\n config.loggerProvider.warn('Failed to add event to session replay capture:', e);\n });\n };\n\n async function flush(useRetry = false) {\n return trackDestination.flush(useRetry);\n }\n\n const getBeaconEvents = (): string[] => [...beaconBuffer];\n\n const dropPendingBeaconEvents = () => {\n advanceBeaconWindow(beaconWindowStart + beaconBuffer.length);\n };\n\n return {\n sendCurrentSequenceEvents,\n addEvent,\n sendStoredEvents,\n flush,\n getBeaconEvents,\n dropPendingBeaconEvents,\n trackDestination,\n };\n};\n","import {\n SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n EventsManagerWithType,\n} from '../typings/session-replay';\n\n/**\n * \"Registers\" events managers internally. When an event is added this class routes the event to the correct\n * manager. For all send or flush methods this will invoke the event for all registered managers.\n */\nexport class MultiEventManager<EventType, EventDataType>\n implements AmplitudeSessionReplayEventsManager<EventType, EventDataType>\n{\n private managers: Map<EventType, AmplitudeSessionReplayEventsManager<EventType, EventDataType>>;\n\n constructor(...managers: EventsManagerWithType<EventType, EventDataType>[]) {\n const managersMap = new Map<EventType, AmplitudeSessionReplayEventsManager<EventType, EventDataType>>();\n managers.forEach((t) => {\n managersMap.set(t.name, t.manager);\n });\n this.managers = managersMap;\n }\n\n async sendStoredEvents(opts: { deviceId: string }): Promise<void> {\n const promises: Promise<void>[] = [];\n this.managers.forEach((manager) => {\n promises.push(manager.sendStoredEvents(opts));\n });\n await Promise.all(promises);\n }\n\n addEvent({\n sessionId,\n event,\n deviceId,\n }: {\n sessionId: number;\n event: { type: EventType; data: EventDataType };\n deviceId: string;\n }): void {\n this.managers.get(event.type)?.addEvent({ sessionId, event, deviceId });\n }\n\n sendCurrentSequenceEvents({ sessionId, deviceId }: { sessionId: number; deviceId: string }): void {\n this.managers.forEach((manager) => {\n manager.sendCurrentSequenceEvents({ sessionId, deviceId });\n });\n }\n\n async flush(useRetry?: boolean | undefined): Promise<void> {\n const promises: Promise<void>[] = [];\n this.managers.forEach((manager) => {\n promises.push(manager.flush(useRetry));\n });\n await Promise.all(promises);\n }\n}\n","/* istanbul ignore file */\n\n// DO NOT EDIT (unless you know what you're doing)\n// Taken directly from git@github.com:antonmedv/finder.git@77d33158440dfffee4a300d2975b43a5283004ab\n\n/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */\n/* eslint-disable prefer-const */\n\n// License: MIT\n// Author: Anton Medvedev <anton@medv.io>\n// Source: https://github.com/antonmedv/finder\n\ntype Knot = {\n name: string;\n penalty: number;\n level?: number;\n};\n\ntype Path = Knot[];\n\nexport type Options = {\n root: Element;\n idName: (name: string) => boolean;\n className: (name: string) => boolean;\n tagName: (name: string) => boolean;\n attr: (name: string, value: string) => boolean;\n seedMinLength: number;\n optimizedMinLength: number;\n threshold: number;\n maxNumberOfTries: number;\n timeoutMs: number | undefined;\n};\n\nlet config: Options;\nlet rootDocument: Document | Element;\nlet start: Date;\n\nexport function finder(input: Element, options?: Partial<Options>): string {\n start = new Date();\n if (input.nodeType !== Node.ELEMENT_NODE) {\n throw new Error(`Can't generate CSS selector for non-element node type.`);\n }\n if ('html' === input.tagName.toLowerCase()) {\n return 'html';\n }\n const defaults: Options = {\n root: document.body,\n idName: (_name: string) => true,\n className: (_name: string) => true,\n tagName: (_name: string) => true,\n attr: (_name: string, _value: string) => false,\n seedMinLength: 1,\n optimizedMinLength: 2,\n threshold: 1000,\n maxNumberOfTries: 10000,\n timeoutMs: undefined,\n };\n\n config = { ...defaults, ...options };\n rootDocument = findRootDocument(config.root, defaults);\n\n let path = bottomUpSearch(input, 'all', () =>\n bottomUpSearch(input, 'two', () => bottomUpSearch(input, 'one', () => bottomUpSearch(input, 'none'))),\n );\n\n if (path) {\n const optimized = sort(optimize(path, input));\n if (optimized.length > 0) {\n path = optimized[0];\n }\n return selector(path);\n } else {\n throw new Error(`Selector was not found.`);\n }\n}\n\nfunction findRootDocument(rootNode: Element | Document, defaults: Options) {\n if (rootNode.nodeType === Node.DOCUMENT_NODE) {\n return rootNode;\n }\n if (rootNode === defaults.root) {\n return rootNode.ownerDocument as Document;\n }\n return rootNode;\n}\n\nfunction bottomUpSearch(\n input: Element,\n limit: 'all' | 'two' | 'one' | 'none',\n fallback?: () => Path | null,\n): Path | null {\n let path: Path | null = null;\n let stack: Knot[][] = [];\n let current: Element | null = input;\n let i = 0;\n while (current) {\n const elapsedTime = new Date().getTime() - start.getTime();\n if (config.timeoutMs !== undefined && elapsedTime > config.timeoutMs) {\n throw new Error(`Timeout: Can't find a unique selector after ${elapsedTime}ms`);\n }\n let level: Knot[] = maybe(id(current)) ||\n maybe(...attr(current)) ||\n maybe(...classNames(current)) ||\n maybe(tagName(current)) || [any()];\n const nth = index(current);\n if (limit == 'all') {\n if (nth) {\n level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n }\n } else if (limit == 'two') {\n level = level.slice(0, 1);\n if (nth) {\n level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n }\n } else if (limit == 'one') {\n const [node] = (level = level.slice(0, 1));\n if (nth && dispensableNth(node)) {\n level = [nthChild(node, nth)];\n }\n } else if (limit == 'none') {\n level = [any()];\n if (nth) {\n level = [nthChild(level[0], nth)];\n }\n }\n for (let node of level) {\n node.level = i;\n }\n stack.push(level);\n if (stack.length >= config.seedMinLength) {\n path = findUniquePath(stack, fallback);\n if (path) {\n break;\n }\n }\n current = current.parentElement;\n i++;\n }\n if (!path) {\n path = findUniquePath(stack, fallback);\n }\n if (!path && fallback) {\n return fallback();\n }\n return path;\n}\n\nfunction findUniquePath(stack: Knot[][], fallback?: () => Path | null): Path | null {\n const paths = sort(combinations(stack));\n if (paths.length > config.threshold) {\n return fallback ? fallback() : null;\n }\n for (let candidate of paths) {\n if (unique(candidate)) {\n return candidate;\n }\n }\n return null;\n}\n\nfunction selector(path: Path): string {\n let node = path[0];\n let query = node.name;\n for (let i = 1; i < path.length; i++) {\n const level = path[i].level || 0;\n if (node.level === level - 1) {\n query = `${path[i].name} > ${query}`;\n } else {\n query = `${path[i].name} ${query}`;\n }\n node = path[i];\n }\n return query;\n}\n\nfunction penalty(path: Path): number {\n return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);\n}\n\nfunction unique(path: Path) {\n const css = selector(path);\n switch (rootDocument.querySelectorAll(css).length) {\n case 0:\n throw new Error(`Can't select any node with this selector: ${css}`);\n case 1:\n return true;\n default:\n return false;\n }\n}\n\nfunction id(input: Element): Knot | null {\n const elementId = input.getAttribute('id');\n if (elementId && config.idName(elementId)) {\n return {\n name: '#' + CSS.escape(elementId),\n penalty: 0,\n };\n }\n return null;\n}\n\nfunction attr(input: Element): Knot[] {\n const attrs = Array.from(input.attributes).filter((attr) => config.attr(attr.name, attr.value));\n return attrs.map(\n (attr): Knot => ({\n name: `[${CSS.escape(attr.name)}=\"${CSS.escape(attr.value)}\"]`,\n penalty: 0.5,\n }),\n );\n}\n\nfunction classNames(input: Element): Knot[] {\n const names = Array.from(input.classList).filter(config.className);\n return names.map(\n (name): Knot => ({\n name: '.' + CSS.escape(name),\n penalty: 1,\n }),\n );\n}\n\nfunction tagName(input: Element): Knot | null {\n const name = input.tagName.toLowerCase();\n if (config.tagName(name)) {\n return {\n name,\n penalty: 2,\n };\n }\n return null;\n}\n\nfunction any(): Knot {\n return {\n name: '*',\n penalty: 3,\n };\n}\n\nfunction index(input: Element): number | null {\n const parent = input.parentNode;\n if (!parent) {\n return null;\n }\n let child = parent.firstChild;\n if (!child) {\n return null;\n }\n let i = 0;\n while (child) {\n if (child.nodeType === Node.ELEMENT_NODE) {\n i++;\n }\n if (child === input) {\n break;\n }\n child = child.nextSibling;\n }\n return i;\n}\n\nfunction nthChild(node: Knot, i: number): Knot {\n return {\n name: node.name + `:nth-child(${i})`,\n penalty: node.penalty + 1,\n };\n}\n\nfunction dispensableNth(node: Knot) {\n return node.name !== 'html' && !node.name.startsWith('#');\n}\n\nfunction maybe(...level: (Knot | null)[]): Knot[] | null {\n const list = level.filter(notEmpty);\n if (list.length > 0) {\n return list;\n }\n return null;\n}\n\nfunction notEmpty<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined;\n}\n\nfunction* combinations(stack: Knot[][], path: Knot[] = []): Generator<Knot[]> {\n if (stack.length > 0) {\n for (let node of stack[0]) {\n yield* combinations(stack.slice(1, stack.length), path.concat(node));\n }\n } else {\n yield path;\n }\n}\n\nfunction sort(paths: Iterable<Path>): Path[] {\n return [...paths].sort((a, b) => penalty(a) - penalty(b));\n}\n\ntype Scope = {\n counter: number;\n visited: Map<string, boolean>;\n};\n\nfunction* optimize(\n path: Path,\n input: Element,\n scope: Scope = {\n counter: 0,\n visited: new Map<string, boolean>(),\n },\n): Generator<Knot[]> {\n if (path.length > 2 && path.length > config.optimizedMinLength) {\n for (let i = 1; i < path.length - 1; i++) {\n if (scope.counter > config.maxNumberOfTries) {\n return; // Okay At least I tried!\n }\n scope.counter += 1;\n const newPath = [...path];\n newPath.splice(i, 1);\n const newPathKey = selector(newPath);\n if (scope.visited.has(newPathKey)) {\n return;\n }\n if (unique(newPath) && same(newPath, input)) {\n yield newPath;\n scope.visited.set(newPathKey, true);\n yield* optimize(newPath, input, scope);\n }\n }\n }\n}\n\nfunction same(path: Path, input: Element) {\n return rootDocument.querySelector(selector(path)) === input;\n}\n","import type { mouseInteractionCallBack } from '@amplitude/rrweb-types';\nimport { MouseInteractions } from '@amplitude/rrweb-types';\nimport { Mirror } from '../utils/rrweb';\nimport { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager } from '../typings/session-replay';\nimport { PayloadBatcher } from '../track-destination';\nimport { finder, Options as FinderOptions } from '../libs/finder';\nimport { getGlobalScope, ILogger } from '@amplitude/analytics-core';\nimport { UGCFilterRule, InteractionPerformanceConfig } from '../config/types';\nimport { getPageUrl } from '../helpers';\nimport { ScrollWatcher } from './scroll';\n\n// exported for testing\nexport type ClickEvent = {\n timestamp: number;\n x: number;\n y: number;\n viewportWidth: number;\n viewportHeight: number;\n pageUrl: string;\n selector?: string;\n type: 'click';\n};\n\n// exported for testing\nexport type ClickEventWithCount = ClickEvent & { count: number };\n\ntype Context = {\n sessionId: string | number;\n deviceIdFn: () => string | undefined;\n eventsManager: AmplitudeSessionReplayEventsManager<'interaction', string>;\n mirror: Mirror;\n ugcFilterRules: UGCFilterRule[];\n performanceOptions?: InteractionPerformanceConfig;\n};\n\nconst HOUR_IN_MILLISECONDS = 3_600_000;\n\nexport const clickNonBatcher: PayloadBatcher = ({ version, events }) => {\n const clickEvents: ClickEvent[] = [];\n events.forEach((evt: string) => {\n const record = JSON.parse(evt) as Record<string, unknown>;\n record.count = 1;\n if (record.type === 'click') {\n clickEvents.push(record as ClickEvent);\n }\n });\n return { version, events: clickEvents };\n};\n\nexport const clickBatcher: PayloadBatcher = ({ version, events }) => {\n const clickEvents: ClickEvent[] = [];\n events.forEach((evt: string) => {\n const record = JSON.parse(evt) as Record<string, unknown>;\n if (record.type === 'click') {\n clickEvents.push(record as ClickEvent);\n }\n });\n\n const reduced = clickEvents.reduce<Record<string, ClickEventWithCount>>((prev, curr) => {\n const { x, y, selector, timestamp } = curr;\n\n // round down to nearest hour.\n const hour = timestamp - (timestamp % HOUR_IN_MILLISECONDS);\n\n const k = `${x}:${y}:${selector ?? ''}:${hour}`;\n if (!prev[k]) {\n prev[k] = { ...curr, timestamp: hour, count: 1 };\n } else {\n prev[k].count += 1;\n }\n return prev;\n }, {});\n\n return { version, events: Object.values(reduced) };\n};\n\nexport class ClickHandler {\n private readonly logger: ILogger;\n private readonly scrollWatcher: ScrollWatcher;\n\n constructor(logger: ILogger, scrollWatcher: ScrollWatcher) {\n this.logger = logger;\n this.scrollWatcher = scrollWatcher;\n }\n\n createHook: (context: Context) => mouseInteractionCallBack = ({\n eventsManager,\n sessionId,\n deviceIdFn,\n mirror,\n ugcFilterRules,\n performanceOptions,\n }) => {\n return (e) => {\n if (e.type !== MouseInteractions.Click) {\n return;\n }\n\n const globalScope = getGlobalScope();\n if (!globalScope) {\n return;\n }\n\n const { location, innerHeight, innerWidth } = globalScope;\n // it only makes sense to send events if a pageUrl exists\n if (!location) {\n return;\n }\n\n const { x, y } = e;\n if (x === undefined || y === undefined) {\n return;\n }\n\n const node = mirror.getNode(e.id);\n let selector;\n if (node) {\n try {\n selector = finder(\n node as Element,\n performanceOptions as Pick<FinderOptions, 'timeoutMs' | 'maxNumberOfTries' | 'threshold'>,\n );\n } catch (err) {\n this.logger.debug('error resolving selector from finder');\n }\n }\n\n const pageUrl = getPageUrl(location.href, ugcFilterRules);\n\n const event: ClickEvent = {\n x: x + this.scrollWatcher.currentScrollX,\n y: y + this.scrollWatcher.currentScrollY,\n selector,\n\n viewportHeight: innerHeight,\n viewportWidth: innerWidth,\n pageUrl,\n timestamp: Date.now(),\n type: 'click',\n };\n const deviceId = deviceIdFn();\n if (deviceId) {\n eventsManager.addEvent({ sessionId, event: { type: 'interaction', data: JSON.stringify(event) }, deviceId });\n }\n };\n };\n}\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport type { eventWithTime, scrollCallback } from '@amplitude/rrweb-types';\n\n// These functions are not exposed in rrweb package, so we will define it here to use\n// Ignoring this function since this is copied from rrweb\nexport function getViewportHeight(): number {\n const globalScope = getGlobalScope();\n return globalScope?.innerHeight || (document.documentElement && document.documentElement.clientHeight) || 0;\n}\n\nexport function getViewportWidth(): number {\n const globalScope = getGlobalScope();\n return globalScope?.innerWidth || (document.documentElement && document.documentElement.clientWidth) || 0;\n}\n\nexport type Mirror = {\n getNode: (id: number) => Node | null;\n};\n\nexport type RecordFunction = {\n (options: {\n emit: (event: eventWithTime) => void;\n inlineStylesheet?: boolean;\n hooks?: {\n mouseInteraction?: any;\n scroll?: scrollCallback;\n };\n maskAllInputs?: boolean;\n maskTextClass?: string;\n blockClass?: string;\n blockSelector?: string;\n maskInputFn?: (text: string, element: HTMLElement | null) => string;\n maskTextFn?: (text: string, element: HTMLElement | null) => string;\n maskAttributeFn?: (key: string, value: string, element: HTMLElement) => string;\n maskTextSelector?: string;\n checkoutEveryNms?: number;\n recordCanvas?: boolean;\n slimDOMOptions?: {\n script?: boolean;\n comment?: boolean;\n headFavicon?: boolean;\n headWhitespace?: boolean;\n headMetaDescKeywords?: boolean;\n headMetaSocial?: boolean;\n headMetaRobots?: boolean;\n headMetaHttpEquiv?: boolean;\n headMetaAuthorship?: boolean;\n headMetaVerification?: boolean;\n };\n errorHandler?: (error: unknown) => boolean;\n plugins?: any[];\n applyBackgroundColorToBlockedElements?: boolean;\n /**\n * When true (default), adoptedStyleSheets CSS rules are serialized inline in the full snapshot\n * rather than emitted as separate incremental events that can be dropped in transit.\n * Set to false to revert to the legacy incremental-event path if snapshot size is a concern.\n */\n captureAdoptedStyleSheets?: boolean;\n recordCrossOriginIframes?: boolean;\n }): (() => void) | undefined;\n addCustomEvent: (eventName: string, eventData: any) => void;\n takeFullSnapshot: (isCheckout?: boolean) => void;\n mirror: Mirror;\n};\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from './config/types';\nimport { SessionReplayDestinationSessionMetadata } from './typings/session-replay';\nimport { getServerUrl } from './helpers';\n\ntype BeaconSendFn<T> = (pageUrl: string, payload: T) => boolean;\n\n/**\n * For very small payloads it's preferable to use the [Beacon API](https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API).\n * While it doesn't provide 100% guarantees on sends, it greatly helps with overall reliability and page load performance. As\n * the Beacon API has a potential to fail due to size constraints we want to fall back to XHR if need be. This is mostly to\n * be used with 'pagehide' or 'beforeunload' events.\n *\n * Note there are only 3 CORS safelisted Content-Types you can send:\n *\n * - application/x-www-form-urlencoded\n * - multipart/form-data\n * - text/plain\n *\n * If we do not send one of these, some browsers like Chrome may not send this at all. Also we incur the overhead of a preflight\n * request. In our case we will add no additional content-type header. If you are trying to ping a server that requires this\n * header, you may want to use the regular fetch API or a different mechanism.\n */\nexport class BeaconTransport<T> {\n private sendBeacon: BeaconSendFn<T>;\n private sendXhr: BeaconSendFn<T>;\n private readonly basePageUrl: string;\n private readonly context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>;\n private readonly apiKey: string;\n\n constructor(context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>, config: SessionReplayJoinedConfig) {\n const globalScope = getGlobalScope();\n if (globalScope && globalScope.navigator && typeof globalScope.navigator.sendBeacon === 'function') {\n this.sendBeacon = (pageUrl, payload) => {\n try {\n if (globalScope.navigator.sendBeacon(pageUrl, JSON.stringify(payload))) {\n return true;\n }\n } catch (e) {\n // not logging error, since it would be hard to view and just adds overhead.\n }\n return false;\n };\n } else {\n this.sendBeacon = () => false;\n }\n\n this.sendXhr = (pageUrl, payload) => {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', pageUrl, true);\n xhr.setRequestHeader('Accept', '*/*');\n xhr.send(JSON.stringify(payload));\n return true;\n };\n\n this.basePageUrl = getServerUrl(config.serverZone, config.trackServerUrl);\n this.apiKey = config.apiKey;\n this.context = context;\n }\n\n send(deviceId: string, payload: T) {\n const { sessionId, type } = this.context;\n const urlParams = new URLSearchParams({\n device_id: deviceId,\n session_id: String(sessionId),\n type: String(type),\n api_key: this.apiKey,\n });\n\n const pageUrl = `${this.basePageUrl}?${urlParams.toString()}`;\n\n // ideally send using the beacon API, but there is a chance it may fail, possibly due to a payload\n // size limit. in this case, try best effort to send using xhr.\n this.sendBeacon(pageUrl, payload) || this.sendXhr(pageUrl, payload);\n }\n}\n","import { getViewportHeight, getViewportWidth } from '../utils/rrweb';\nimport type { scrollCallback, scrollPosition } from '@amplitude/rrweb-types';\nimport { BeaconTransport } from '../beacon-transport';\nimport { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayDestinationSessionMetadata } from '../typings/session-replay';\nimport { getPageUrl } from '../helpers';\n\nexport type ScrollEvent = {\n timestamp: number; // Timestamp the event occurred\n maxScrollX: number; // Max window scroll X on a page\n maxScrollY: number; // Max window scroll Y on a page\n maxScrollHeight: number; // Max window scroll Y + window height on a page\n maxScrollWidth: number; // Max window scroll X + window width on a page\n viewportWidth: number;\n viewportHeight: number;\n pageUrl: string;\n type: 'scroll';\n};\n\nexport type ScrollEventPayload = { version: number; events: ScrollEvent[] };\n\n/**\n * This is intended to watch and update max scroll activity when loaded for a particular page.\n * A new instance should be created if the page URL changes, since by default it does not reset\n * it's max scroll state. It is intended to send very few and very small events utilizing the\n * Beacon API.\n * @see {@link BeaconTransport} for more details on Beacon API usage.\n */\nexport class ScrollWatcher {\n private timestamp = Date.now();\n private _currentScrollX: number;\n private _currentScrollY: number;\n private _maxScrollX: number;\n private _maxScrollY: number;\n private _maxScrollWidth: number;\n private _maxScrollHeight: number;\n private readonly transport: BeaconTransport<ScrollEventPayload>;\n private readonly config: Pick<SessionReplayJoinedConfig, 'loggerProvider' | 'interactionConfig'>;\n\n static default(\n context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>,\n config: SessionReplayJoinedConfig,\n ): ScrollWatcher {\n return new ScrollWatcher(new BeaconTransport<ScrollEventPayload>(context, config), config);\n }\n\n constructor(\n transport: BeaconTransport<ScrollEventPayload>,\n config: Pick<SessionReplayJoinedConfig, 'loggerProvider' | 'interactionConfig'>,\n ) {\n this._maxScrollX = 0;\n this._maxScrollY = 0;\n this._currentScrollX = 0;\n this._currentScrollY = 0;\n this._maxScrollWidth = getViewportWidth();\n this._maxScrollHeight = getViewportHeight();\n this.config = config;\n\n this.transport = transport;\n }\n\n public get maxScrollX(): number {\n return this._maxScrollX;\n }\n\n public get maxScrollY(): number {\n return this._maxScrollY;\n }\n\n public get maxScrollWidth(): number {\n return this._maxScrollWidth;\n }\n\n public get maxScrollHeight(): number {\n return this._maxScrollHeight;\n }\n\n public get currentScrollX(): number {\n return this._currentScrollX;\n }\n\n public get currentScrollY(): number {\n return this._currentScrollY;\n }\n\n update(e: scrollPosition) {\n const now = Date.now();\n this._currentScrollX = e.x;\n this._currentScrollY = e.y;\n if (e.x > this._maxScrollX) {\n const width = getViewportWidth();\n this._maxScrollX = e.x;\n const maxScrollWidth = e.x + width;\n if (maxScrollWidth > this._maxScrollWidth) {\n this._maxScrollWidth = maxScrollWidth;\n }\n this.timestamp = now;\n }\n\n if (e.y > this._maxScrollY) {\n const height = getViewportHeight();\n this._maxScrollY = e.y;\n const maxScrollHeight = e.y + height;\n if (maxScrollHeight > this._maxScrollHeight) {\n this._maxScrollHeight = maxScrollHeight;\n }\n this.timestamp = now;\n }\n }\n\n hook: scrollCallback = (e: scrollPosition) => {\n this.update(e);\n };\n\n send: (deviceIdFn: () => string | undefined) => (_: PageTransitionEvent | Event) => void = (deviceIdFn) => (_) => {\n const deviceId = deviceIdFn();\n const globalScope = getGlobalScope();\n if (globalScope && deviceId) {\n // Capture the true final scroll position directly from the window.\n // rrweb's scroll observer throttles callbacks to 100ms using setTimeout,\n // so the most recent scroll position may not have been delivered to the hook yet.\n const scrollX = globalScope.scrollX ?? 0;\n const scrollY = globalScope.scrollY ?? 0;\n if (scrollX > 0 || scrollY > 0) {\n // id is required by the scrollPosition type but is not used by update() —\n // only x and y are read. 1 is the conventional rrweb mirror ID for the document node.\n this.update({ id: 1, x: scrollX, y: scrollY });\n }\n this.transport.send(deviceId, {\n version: 1,\n events: [\n {\n maxScrollX: this._maxScrollX,\n maxScrollY: this._maxScrollY,\n maxScrollWidth: this._maxScrollWidth,\n maxScrollHeight: this._maxScrollHeight,\n\n viewportHeight: getViewportHeight(),\n viewportWidth: getViewportWidth(),\n pageUrl: getPageUrl(globalScope.location.href, this.config.interactionConfig?.ugcFilterRules ?? []),\n timestamp: this.timestamp,\n type: 'scroll',\n },\n ],\n });\n }\n };\n}\n","import { generateSessionReplayId } from './helpers';\nimport { SessionIdentifiers as ISessionIdentifiers } from './typings/session-replay';\n\nexport class SessionIdentifiers implements ISessionIdentifiers {\n deviceId?: string;\n sessionId?: string | number;\n sessionReplayId?: string;\n\n constructor({ sessionId, deviceId }: { sessionId?: string | number; deviceId?: string }) {\n this.deviceId = deviceId;\n this.sessionId = sessionId;\n\n if (sessionId && deviceId) {\n this.sessionReplayId = generateSessionReplayId(sessionId, deviceId);\n }\n }\n}\n","import { getGlobalScope, ILogger } from '@amplitude/analytics-core';\n\n/**\n * Persists the wall-clock time at which a session's replay first began capturing,\n * keyed by sessionId. The persisted value drives the `min_session_duration_ms` gate:\n * we measure elapsed *replay* time, not just current page-load time, so a session that\n * is paused and resumed (or that crosses a page navigation) is still gated correctly.\n *\n * All storage access is wrapped in try/catch — when localStorage is unavailable (Safari\n * private mode, quota exceeded, sandboxed iframe) callers fall back to `Date.now()` so\n * the gate degrades gracefully instead of throwing.\n */\n\nconst KEY_PREFIX = 'AMP_SR_START_';\nconst APIKEY_FINGERPRINT_LEN = 10;\n\n/**\n * TTL beyond which a stored start time is treated as stale and pruned on next init.\n * 24 hours covers the longest realistic single-session duration in Amplitude (default\n * inactivity timeout is 30 minutes; some configs extend sessions across resumes).\n */\nexport const REPLAY_START_TIME_TTL_MS = 24 * 60 * 60 * 1000;\n\nconst buildKeyPrefix = (apiKey: string) => `${KEY_PREFIX}${apiKey.substring(0, APIKEY_FINGERPRINT_LEN)}_`;\nconst buildKey = (apiKey: string, sessionId: string | number) => `${buildKeyPrefix(apiKey)}${sessionId}`;\n\nconst getLocalStorage = (): Storage | undefined => {\n try {\n const scope = getGlobalScope() as { localStorage?: Storage } | undefined;\n return scope?.localStorage;\n } catch {\n // Accessing localStorage can throw in some sandboxed contexts.\n return undefined;\n }\n};\n\n/**\n * Returns the persisted replay start time for this sessionId if one exists and is fresh,\n * otherwise writes `now` and returns it. Returns undefined only if storage is unavailable\n * — callers should fall back to a transient `Date.now()` in that case.\n */\nexport const getOrInitReplayStartTime = (\n apiKey: string,\n sessionId: string | number,\n now: number,\n logger?: ILogger,\n): number | undefined => {\n const storage = getLocalStorage();\n if (!storage) return undefined;\n const key = buildKey(apiKey, sessionId);\n try {\n const raw = storage.getItem(key);\n if (raw !== null) {\n const parsed = Number(raw);\n // Treat NaN, non-finite, future-dated, and stale entries as missing.\n if (Number.isFinite(parsed) && parsed > 0 && parsed <= now && now - parsed < REPLAY_START_TIME_TTL_MS) {\n return parsed;\n }\n }\n storage.setItem(key, String(now));\n return now;\n } catch (e) {\n logger?.debug(`Failed to read/write replay start time from storage: ${String(e)}`);\n return undefined;\n }\n};\n\nexport const setReplayStartTime = (\n apiKey: string,\n sessionId: string | number,\n startTime: number,\n logger?: ILogger,\n): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.setItem(buildKey(apiKey, sessionId), String(startTime));\n } catch (e) {\n logger?.debug(`Failed to write replay start time to storage: ${String(e)}`);\n }\n};\n\nexport const removeReplayStartTime = (apiKey: string, sessionId: string | number, logger?: ILogger): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n try {\n storage.removeItem(buildKey(apiKey, sessionId));\n } catch (e) {\n logger?.debug(`Failed to remove replay start time from storage: ${String(e)}`);\n }\n};\n\n/**\n * Drops stored start times older than {@link REPLAY_START_TIME_TTL_MS}. Cheap best-effort\n * sweep called on init — keeps localStorage from accumulating dead entries when sessions\n * end without a clean transition (browser close, crash). Scoped to this API key's keys\n * so multi-tenant pages don't churn through each other's entries.\n */\nexport const pruneStaleReplayStartTimes = (apiKey: string, now: number, logger?: ILogger): void => {\n const storage = getLocalStorage();\n if (!storage) return;\n const prefix = buildKeyPrefix(apiKey);\n try {\n // Collect first; localStorage indices shift as we remove.\n const stale: string[] = [];\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (!key || !key.startsWith(prefix)) continue;\n const raw = storage.getItem(key);\n if (raw === null) continue;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0 || now - parsed >= REPLAY_START_TIME_TTL_MS) {\n stale.push(key);\n }\n }\n for (const key of stale) {\n storage.removeItem(key);\n }\n } catch (e) {\n logger?.debug(`Failed to prune stale replay start times: ${String(e)}`);\n }\n};\n","import { Logger as ILogger } from '@amplitude/analytics-types';\nimport { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { logIdbError } from '../utils/is-abort-error';\n\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 2; // 2 days\n\nexport interface SessionReplayTargetingDB extends DBSchema {\n sessionTargetingMatch: {\n key: string;\n value: {\n sessionId: string;\n targetingMatch: boolean;\n lastUpdated: number;\n };\n };\n}\n\nexport class TargetingIDBStore {\n dbs: { [apiKey: string]: IDBPDatabase<SessionReplayTargetingDB> } = {};\n\n createStore = async (dbName: string) => {\n return await openDB<SessionReplayTargetingDB>(dbName, 1, {\n upgrade: (db: IDBPDatabase<SessionReplayTargetingDB>) => {\n if (!db.objectStoreNames.contains('sessionTargetingMatch')) {\n db.createObjectStore('sessionTargetingMatch', {\n keyPath: 'sessionId',\n });\n }\n },\n });\n };\n\n openOrCreateDB = async (apiKey: string) => {\n if (this.dbs && this.dbs[apiKey]) {\n return this.dbs[apiKey];\n }\n const dbName = `${apiKey.substring(0, 10)}_amp_session_replay_targeting`;\n const db = await this.createStore(dbName);\n this.dbs[apiKey] = db;\n return db;\n };\n\n getTargetingMatchForSession = async ({\n loggerProvider,\n apiKey,\n sessionId,\n }: {\n loggerProvider: ILogger;\n apiKey: string;\n sessionId: string | number;\n }) => {\n try {\n const db = await this.openOrCreateDB(apiKey);\n const sessionIdStr = String(sessionId);\n const targetingMatchForSession = await db.get<'sessionTargetingMatch'>('sessionTargetingMatch', sessionIdStr);\n\n return targetingMatchForSession?.targetingMatch;\n } catch (e) {\n logIdbError(loggerProvider, `Failed to get targeting match for session id ${sessionId}: ${e as string}`, e);\n }\n return undefined;\n };\n\n storeTargetingMatchForSession = async ({\n loggerProvider,\n apiKey,\n sessionId,\n targetingMatch,\n }: {\n loggerProvider: ILogger;\n apiKey: string;\n sessionId: string | number;\n targetingMatch: boolean;\n }) => {\n try {\n const db = await this.openOrCreateDB(apiKey);\n const sessionIdStr = String(sessionId);\n const targetingMatchForSession = await db.put<'sessionTargetingMatch'>('sessionTargetingMatch', {\n targetingMatch,\n sessionId: sessionIdStr,\n lastUpdated: Date.now(),\n });\n\n return targetingMatchForSession;\n } catch (e) {\n logIdbError(loggerProvider, `Failed to store targeting match for session id ${sessionId}: ${e as string}`, e);\n }\n return undefined;\n };\n\n clearStoreOfOldSessions = async ({\n loggerProvider,\n apiKey,\n currentSessionId,\n }: {\n loggerProvider: ILogger;\n apiKey: string;\n currentSessionId: string | number;\n }) => {\n try {\n const db = await this.openOrCreateDB(apiKey);\n const currentSessionIdStr = String(currentSessionId);\n const tx = db.transaction<'sessionTargetingMatch', 'readwrite'>('sessionTargetingMatch', 'readwrite');\n const allTargetingMatchObjs = await tx.store.getAll();\n for (let i = 0; i < allTargetingMatchObjs.length; i++) {\n const targetingMatchObj = allTargetingMatchObjs[i];\n const amountOfTimeSinceSession = Date.now() - targetingMatchObj.lastUpdated;\n if (targetingMatchObj.sessionId !== currentSessionIdStr && amountOfTimeSinceSession > MAX_IDB_STORAGE_LENGTH) {\n await tx.store.delete(targetingMatchObj.sessionId);\n }\n }\n await tx.done;\n } catch (e) {\n logIdbError(loggerProvider, `Failed to clear old targeting matches for sessions: ${e as string}`, e);\n }\n };\n}\nexport const targetingIDBStore = new TargetingIDBStore();\n","// Pure JS xxHash32 implementation based on the official specification:\n// https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md\nconst PRIME32_1 = 0x9e3779b1;\nconst PRIME32_2 = 0x85ebca77;\nconst PRIME32_3 = 0xc2b2ae3d;\nconst PRIME32_4 = 0x27d4eb2f;\nconst PRIME32_5 = 0x165667b1;\n\nfunction rotl32(x: number, r: number): number {\n return ((x << r) | (x >>> (32 - r))) >>> 0;\n}\n\nfunction round(acc: number, input: number): number {\n acc = (acc + Math.imul(input, PRIME32_2)) >>> 0;\n acc = rotl32(acc, 13);\n acc = Math.imul(acc, PRIME32_1) >>> 0;\n return acc;\n}\n\nfunction readU32(bytes: Uint8Array, offset: number): number {\n return (bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)) >>> 0;\n}\n\nfunction toUTF8Bytes(str: string): Uint8Array {\n const bytes: number[] = [];\n for (let i = 0; i < str.length; i++) {\n let c = str.charCodeAt(i);\n if (c >= 0xd800 && c <= 0xdbff && i + 1 < str.length) {\n const next = str.charCodeAt(i + 1);\n if (next >= 0xdc00 && next <= 0xdfff) {\n c = ((c - 0xd800) << 10) + (next - 0xdc00) + 0x10000;\n i++;\n }\n }\n if (c < 0x80) {\n bytes.push(c);\n } else if (c < 0x800) {\n bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f));\n } else if (c < 0x10000) {\n bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));\n } else {\n bytes.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));\n }\n }\n return new Uint8Array(bytes);\n}\n\nexport function xxHash32(input: string, seed = 0): number {\n const bytes = toUTF8Bytes(input);\n const len = bytes.length;\n let h32: number;\n let offset = 0;\n\n if (len >= 16) {\n let v1 = (seed + PRIME32_1 + PRIME32_2) >>> 0;\n let v2 = (seed + PRIME32_2) >>> 0;\n let v3 = seed >>> 0;\n let v4 = (seed - PRIME32_1) >>> 0;\n\n while (offset <= len - 16) {\n v1 = round(v1, readU32(bytes, offset));\n offset += 4;\n v2 = round(v2, readU32(bytes, offset));\n offset += 4;\n v3 = round(v3, readU32(bytes, offset));\n offset += 4;\n v4 = round(v4, readU32(bytes, offset));\n offset += 4;\n }\n\n h32 = (rotl32(v1, 1) + rotl32(v2, 7) + rotl32(v3, 12) + rotl32(v4, 18)) >>> 0;\n } else {\n h32 = (seed + PRIME32_5) >>> 0;\n }\n\n h32 = (h32 + len) >>> 0;\n\n while (offset <= len - 4) {\n h32 = (h32 + Math.imul(readU32(bytes, offset), PRIME32_3)) >>> 0;\n h32 = Math.imul(rotl32(h32, 17), PRIME32_4) >>> 0;\n offset += 4;\n }\n\n while (offset < len) {\n h32 = (h32 + Math.imul(bytes[offset], PRIME32_5)) >>> 0;\n h32 = Math.imul(rotl32(h32, 11), PRIME32_1) >>> 0;\n offset++;\n }\n\n h32 ^= h32 >>> 15;\n h32 = Math.imul(h32, PRIME32_2) >>> 0;\n h32 ^= h32 >>> 13;\n h32 = Math.imul(h32, PRIME32_3) >>> 0;\n h32 ^= h32 >>> 16;\n\n return h32 >>> 0;\n}\n\nexport function isSessionInSample(sessionId: string | number, sampleRate: number): boolean {\n const hash = xxHash32(sessionId.toString());\n const mod = hash % 1_000_000;\n return mod / 1_000_000 < sampleRate;\n}\n","import { getPageUrl } from '../helpers';\nimport { UGCFilterRule } from '../config/types';\nimport { DEFAULT_URL_CHANGE_POLLING_INTERVAL } from '../constants';\nimport { RecordPlugin } from '@amplitude/rrweb-types';\n\n/**\n * Event emitted when URL changes are detected by the plugin\n * Contains the current page URL, title, and viewport dimensions\n */\nexport interface URLChangeEvent {\n /** The current page URL (may be filtered if UGC rules are applied) */\n href: string;\n /** The current page title */\n title: string;\n /** Viewport height in pixels */\n viewportHeight: number;\n /** Viewport width in pixels */\n viewportWidth: number;\n /** The type of URL change event */\n type: string;\n}\n\n/**\n * Configuration options for the URL tracking plugin\n */\nexport interface URLTrackingPluginOptions {\n /** Rules for filtering sensitive URLs (User Generated Content) */\n ugcFilterRules?: UGCFilterRule[];\n /** Whether to use polling instead of history API events for URL detection */\n enablePolling?: boolean;\n /** Interval in milliseconds for polling URL changes (default: 1000ms) */\n pollingInterval?: number;\n /** Whether to capture document title in URL change events (default: false) */\n captureDocumentTitle?: boolean;\n}\n\n/** Options for subscribeToUrlChanges (polling vs history + hash) */\nexport interface SubscribeToUrlChangesOptions {\n /** Use polling instead of history/popstate/hashchange (e.g. when history is unreliable) */\n enablePolling?: boolean;\n /** Polling interval in ms when enablePolling is true (default: 1000) */\n pollingInterval?: number;\n /**\n * Optional debug logger, called once per poll tick (only on the polling path). Lets the SDK\n * confirm in the browser console that the interval is actually firing — useful when verifying\n * that enableUrlChangePolling took effect for an SPA that bypasses the History API.\n */\n log?: (message: string) => void;\n /**\n * Optional per-tick hook (polling path only), called every interval with the current href and\n * whether it changed since the last tick. The SDK uses this to emit a diagnostics signal proving\n * the polling loop actually fired (vs only being scheduled). Kept separate from `log` so the SDK\n * can throttle/aggregate what it ships.\n */\n onPoll?: (href: string, changed: boolean) => void;\n}\n\n/** Patch detection marker to prevent double-patching */\nconst PATCH_MARKER = '__amplitude_url_tracking_patched__';\n\ntype PatchableHistoryMethod<T extends (...args: any[]) => any> = T & { [PATCH_MARKER]?: boolean };\n\ninterface UrlChangeSubscriptionState {\n callbacks: Set<(href: string) => void>;\n onPopStateOrHashChange: () => void;\n notify: () => void;\n listenersAttached: boolean;\n}\n\n/** Per-globalScope subscription state; persists to avoid wrapper stacking across re-subscribe cycles */\nconst urlChangeSubscriptionsByScope = new WeakMap<Window, UrlChangeSubscriptionState>();\n\n/**\n * Single helper for URL change detection. Supports:\n * - History API (pushState/replaceState) + popstate + hashchange (shared patch per scope)\n * - Optional polling (setInterval on location.href)\n *\n * Used by session-replay targeting (re-evaluate on URL change) and the URL tracking plugin\n * (emit rrweb events). Call the returned function to unsubscribe.\n *\n * @param globalScope - window (or equivalent); no-op if undefined\n * @param onUrlChange - called when the URL changes, with the new href\n * @param options - optional polling (default: event-based only)\n * @returns cleanup function to remove this subscription\n */\nexport function subscribeToUrlChanges(\n globalScope: Window | undefined,\n onUrlChange: (href: string) => void,\n options: SubscribeToUrlChangesOptions = {},\n): () => void {\n if (!globalScope?.location) {\n return (): void => {\n return;\n };\n }\n\n const { enablePolling = false, pollingInterval = DEFAULT_URL_CHANGE_POLLING_INTERVAL, log, onPoll } = options;\n\n if (enablePolling) {\n const getHref = (): string => globalScope.location.href ?? '';\n let lastHref = getHref();\n const id = globalScope.setInterval(() => {\n const href = getHref();\n const changed = href !== lastHref;\n // Logged every tick (not just on change) so we can confirm the polling loop is alive.\n log?.(`URL polling tick (href=${href}, changed=${String(changed)}).`);\n onPoll?.(href, changed);\n if (!changed) {\n return;\n }\n lastHref = href;\n onUrlChange(href);\n }, pollingInterval);\n return (): void => {\n if (id != null) {\n globalScope.clearInterval(id);\n }\n };\n }\n\n let subscriptionState = urlChangeSubscriptionsByScope.get(globalScope);\n if (!subscriptionState) {\n let lastHref: string | undefined = undefined;\n const callbacks = new Set<(href: string) => void>();\n\n const getHref = (): string => globalScope.location.href ?? '';\n\n const notify = (): void => {\n const href = getHref();\n if (lastHref !== undefined && href === lastHref) return;\n lastHref = href;\n callbacks.forEach((c) => c(href));\n };\n\n /**\n * Creates a patched version of history methods (pushState/replaceState)\n * that calls the original method and then emits a URL change event.\n */\n const createHistoryMethodPatch = <T extends typeof history.pushState | typeof history.replaceState>(\n originalMethod: T,\n ) => {\n const patchedMethod = function (this: History, ...args: Parameters<T>) {\n const result = originalMethod.apply(this, args);\n // Read from location.href after history call so we always notify with resolved absolute URL.\n notify();\n return result;\n } as PatchableHistoryMethod<T>;\n\n patchedMethod[PATCH_MARKER] = true;\n return patchedMethod;\n };\n\n const history = globalScope.history;\n if (history?.pushState) {\n const pushState = Reflect.get(history, 'pushState') as PatchableHistoryMethod<History['pushState']>;\n if (!pushState[PATCH_MARKER]) {\n history.pushState = createHistoryMethodPatch(pushState);\n }\n }\n if (history?.replaceState) {\n const replaceState = Reflect.get(history, 'replaceState') as PatchableHistoryMethod<History['replaceState']>;\n if (!replaceState[PATCH_MARKER]) {\n history.replaceState = createHistoryMethodPatch(replaceState);\n }\n }\n\n subscriptionState = {\n callbacks,\n notify,\n onPopStateOrHashChange: () => notify(),\n listenersAttached: false,\n };\n urlChangeSubscriptionsByScope.set(globalScope, subscriptionState);\n }\n\n const state = subscriptionState;\n if (!state.listenersAttached) {\n globalScope.addEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.addEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = true;\n }\n\n state.callbacks.add(onUrlChange);\n return (): void => {\n state.callbacks.delete(onUrlChange);\n if (state.callbacks.size === 0) {\n // Do not restore history methods: we are not aware of patches applied by other scripts.\n if (state.listenersAttached) {\n globalScope.removeEventListener('popstate', state.onPopStateOrHashChange);\n globalScope.removeEventListener('hashchange', state.onPopStateOrHashChange);\n state.listenersAttached = false;\n }\n }\n };\n}\n\n/**\n * Creates a URL tracking plugin for rrweb record function\n *\n * This plugin monitors URL changes in the browser and emits events when the URL changes.\n * It supports three tracking modes:\n * 1. Polling (if explicitly enabled) - periodically checks for URL changes\n * 2. History API + Hash routing (default) - patches pushState/replaceState, listens to popstate and hashchange\n * 3. Hash routing only (fallback) - listens to hashchange events when History API is unavailable\n *\n * The plugin handles edge cases gracefully:\n * - Missing or null location objects\n * - Undefined, null, or empty location.href values\n * - Temporal dead zone issues with variable declarations\n * - Consistent URL normalization across all code paths\n *\n * @param options Configuration options for URL tracking\n * @returns RecordPlugin instance that can be used with rrweb\n */\nexport function createUrlTrackingPlugin(\n options: URLTrackingPluginOptions = {},\n): RecordPlugin<URLTrackingPluginOptions> {\n return {\n name: 'amplitude/url-tracking@1',\n observer(cb, globalScope, pluginOptions?: URLTrackingPluginOptions) {\n // Merge options with plugin-level options taking precedence over constructor options\n const config = { ...options, ...pluginOptions };\n const ugcFilterRules = config.ugcFilterRules || [];\n const enablePolling = config.enablePolling ?? false;\n const pollingInterval = config.pollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n const captureDocumentTitle = config.captureDocumentTitle ?? false;\n\n // Early return if no global scope is available\n if (!globalScope) {\n return () => {\n // No cleanup needed if no global scope available\n };\n }\n\n // Track the last URL to prevent duplicate events\n // Initialize to undefined to ensure first call always emits an event\n let lastTrackedUrl: string | undefined = undefined;\n\n // Helper functions\n /**\n * Gets the current URL with proper normalization\n * Handles edge cases where location.href might be undefined, null, or empty\n * Ensures consistent behavior across all code paths\n * @returns Normalized URL string (empty string if location unavailable)\n */\n const getCurrentUrl = (): string => {\n if (!globalScope.location) return '';\n return globalScope.location.href || '';\n };\n\n /**\n * Creates a URL change event with current page information\n * Applies UGC filtering if rules are configured\n * Uses getCurrentUrl() for consistent URL normalization\n * @returns URLChangeEvent with current page state\n */\n const createUrlChangeEvent = (): URLChangeEvent => {\n const { innerHeight, innerWidth, document } = globalScope;\n const currentUrl = getCurrentUrl();\n let currentTitle = '';\n if (captureDocumentTitle) {\n currentTitle = document?.title || '';\n }\n\n // Apply UGC filtering if rules are provided, otherwise use original URL\n const filteredUrl = ugcFilterRules.length > 0 ? getPageUrl(currentUrl, ugcFilterRules) : currentUrl;\n\n return {\n href: filteredUrl,\n title: currentTitle,\n viewportHeight: innerHeight,\n viewportWidth: innerWidth,\n type: 'url-change-event',\n };\n };\n\n /**\n * Emits a URL change event if the URL has actually changed\n * Always emits on first call (when lastTrackedUrl is undefined)\n */\n const emitUrlChange = (): void => {\n const currentUrl = getCurrentUrl();\n if (lastTrackedUrl === undefined || currentUrl !== lastTrackedUrl) {\n lastTrackedUrl = currentUrl;\n const event = createUrlChangeEvent();\n cb(event);\n }\n };\n\n // Single helper: history + popstate + hashchange, or polling when enabled\n const unsubscribe = subscribeToUrlChanges(\n globalScope as Window,\n () => emitUrlChange(),\n enablePolling ? { enablePolling: true, pollingInterval } : {},\n );\n emitUrlChange();\n\n return (): void => unsubscribe();\n },\n options,\n };\n}\n\n/**\n * Default URL tracking plugin instance with default options\n * Can be used directly without custom configuration\n */\nexport const urlTrackingPlugin = createUrlTrackingPlugin();\n","import { getGlobalScope } from '@amplitude/analytics-core';\nimport { CROSS_ORIGIN_IFRAME_MESSAGE_TYPE } from './constants';\n\nexport function isInIframe(): boolean {\n try {\n const globalScope = getGlobalScope() as Window | undefined;\n if (!globalScope) {\n return false;\n }\n return globalScope.parent !== globalScope;\n } catch {\n // SecurityError accessing window.parent in some sandboxed environments\n return true;\n }\n}\n\ntype IframeMessage = { type: typeof CROSS_ORIGIN_IFRAME_MESSAGE_TYPE; action: 'start' | 'stop' };\n\n/**\n * Manages the parent side of cross-origin iframe recording coordination.\n *\n * When the parent starts recording, it sends a start signal to all current child\n * iframes and watches for dynamically added iframes via MutationObserver. When the\n * parent stops, it sends a stop signal.\n */\nexport class CrossOriginIframeCoordinator {\n private mutationObserver: MutationObserver | undefined;\n // Tracks pending load listeners for dynamically added iframes so stop() can cancel them.\n private pendingLoadListeners = new Map<HTMLIFrameElement, () => void>();\n\n start() {\n this.mutationObserver?.disconnect(); // guard against double-start\n const globalScope = getGlobalScope();\n if (!globalScope) {\n return;\n }\n this.sendToAllIframes({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n this.mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of Array.from(mutation.addedNodes)) {\n if (node instanceof HTMLIFrameElement) {\n // Send the start signal after the child page has loaded, not at insertion\n // time. At insertion the contentWindow is still about:blank; the message\n // sent there is discarded when the iframe navigates to its src, and the\n // child SDK never receives it.\n this.sendToIframeAfterLoad(node);\n } else if (node instanceof Element) {\n // A container element (e.g. a React-rendered div) may already have\n // iframe descendants when it is inserted. These iframes do NOT appear\n // in addedNodes — only the container does. Query the subtree so we\n // don't miss them.\n node.querySelectorAll<HTMLIFrameElement>('iframe').forEach((iframe) => {\n this.sendToIframeAfterLoad(iframe);\n });\n }\n }\n for (const node of Array.from(mutation.removedNodes)) {\n if (node instanceof HTMLIFrameElement) {\n const listener = this.pendingLoadListeners.get(node);\n if (listener) {\n node.removeEventListener('load', listener);\n this.pendingLoadListeners.delete(node);\n }\n }\n }\n }\n });\n this.mutationObserver.observe(document.documentElement, { childList: true, subtree: true });\n }\n\n stop() {\n this.mutationObserver?.disconnect();\n this.mutationObserver = undefined;\n // Cancel any start signals that were waiting for a pending iframe load.\n this.pendingLoadListeners.forEach((listener, iframe) => {\n iframe.removeEventListener('load', listener);\n });\n this.pendingLoadListeners.clear();\n this.sendToAllIframes({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' });\n }\n\n private sendToIframeAfterLoad(iframe: HTMLIFrameElement) {\n const sendStart = () => {\n this.pendingLoadListeners.delete(iframe);\n this.sendToIframe(iframe, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n };\n this.pendingLoadListeners.set(iframe, sendStart);\n iframe.addEventListener('load', sendStart, { once: true });\n }\n\n private sendToAllIframes(message: IframeMessage) {\n const iframes = document.querySelectorAll<HTMLIFrameElement>('iframe');\n iframes.forEach((iframe) => this.sendToIframe(iframe, message));\n }\n\n private sendToIframe(iframe: HTMLIFrameElement, message: IframeMessage) {\n try {\n iframe.contentWindow?.postMessage(message, '*');\n } catch {\n // Cross-origin postMessage can throw in some sandboxed environments; ignore.\n }\n }\n}\n\n/**\n * Listens for start/stop signals from the parent page and invokes the provided\n * callbacks. Only messages from `window.parent` are accepted.\n *\n * Returns a cleanup function that removes the message listener.\n */\nexport function listenForParentSignals(callbacks: { onStart: () => void; onStop: () => void }): () => void {\n const globalScope = getGlobalScope() as Window | undefined;\n if (!globalScope) {\n return () => undefined;\n }\n\n const parentFrame = globalScope.parent;\n\n function handler(event: MessageEvent) {\n // Only accept messages from the direct parent frame.\n if (event.source !== parentFrame) {\n return;\n }\n const data = event.data as Partial<IframeMessage>;\n if (data?.type !== CROSS_ORIGIN_IFRAME_MESSAGE_TYPE) {\n return;\n }\n if (data.action === 'start') {\n callbacks.onStart();\n } else if (data.action === 'stop') {\n callbacks.onStop();\n }\n }\n\n globalScope.addEventListener('message', handler);\n return () => globalScope.removeEventListener('message', handler);\n}\n","import {\n getAnalyticsConnector,\n getGlobalScope,\n ILogger,\n Logger,\n LogLevel,\n returnWrapper,\n SpecialEventType,\n generateHashCode,\n getOrCreateWindowMessenger,\n enableBackgroundCapture,\n AMPLITUDE_ORIGINS_MAP,\n} from '@amplitude/analytics-core';\n\n// Import only specific types to avoid pulling in the entire rrweb-types package\nimport { eventWithTime, EventType as RRWebEventType, scrollCallback } from '@amplitude/rrweb-types';\nimport { createSessionReplayJoinedConfigGenerator } from './config/joined-config';\nimport {\n LoggingConfig,\n SessionReplayJoinedConfig,\n SessionReplayJoinedConfigGenerator,\n SessionReplayLocalConfig,\n SessionReplayMetadata,\n SessionReplayRemoteConfig,\n} from './config/types';\nimport {\n BLOCK_CLASS,\n CustomRRwebEvent,\n DEFAULT_SESSION_REPLAY_PROPERTY,\n INTERACTION_MAX_INTERVAL,\n INTERACTION_MIN_INTERVAL,\n MASK_TEXT_CLASS,\n SESSION_REPLAY_DEBUG_PROPERTY,\n SESSION_REPLAY_EU_URL,\n SESSION_REPLAY_SERVER_URL,\n SESSION_REPLAY_STAGING_URL,\n} from './constants';\nimport {\n getServerUrl,\n getDebugConfig,\n getEffectiveMaskLevel,\n getPageUrl,\n getStorageSize,\n getCurrentUrl,\n maskFn,\n maskAttributeFn,\n} from './helpers';\nimport { EventCompressor } from './events/event-compressor';\nimport { createEventsManager, EventsManagerWithBeacon } from './events/events-manager';\nimport { MultiEventManager } from './events/multi-manager';\nimport { clickBatcher, ClickHandler, clickNonBatcher } from './hooks/click';\nimport { ScrollWatcher } from './hooks/scroll';\nimport { SessionIdentifiers } from './identifiers';\nimport { SafeLoggerProvider } from './logger';\nimport {\n getOrInitReplayStartTime,\n pruneStaleReplayStartTimes,\n removeReplayStartTime,\n setReplayStartTime,\n} from './replay-start-time-store';\nimport { evaluateTargetingAndStore } from './targeting/targeting-manager';\nimport { SrDiagnostic } from './diagnostics';\nimport {\n AmplitudeSessionReplay,\n SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n DebugInfo,\n EventsManagerWithType,\n EventType,\n SessionIdentifiers as ISessionIdentifiers,\n SessionReplayOptions,\n SessionReplayTargetingInput,\n} from './typings/session-replay';\nimport { isSessionInSample } from './sampling';\nimport { VERSION } from './version';\n\n// Import only the type for NetworkRequestEvent to keep type safety\nimport type { NetworkObservers, NetworkRequestEvent } from './observers';\nimport { createUrlTrackingPlugin, subscribeToUrlChanges } from './plugins/url-tracking-plugin';\nimport type { RecordFunction } from './utils/rrweb';\nimport { isInIframe, CrossOriginIframeCoordinator, listenForParentSignals } from './cross-origin-iframes';\n\ntype PageLeaveFn = (e: PageTransitionEvent | Event) => void;\n\nexport class SessionReplay implements AmplitudeSessionReplay {\n name = '@amplitude/session-replay-browser';\n config: SessionReplayJoinedConfig | undefined;\n joinedConfigGenerator: SessionReplayJoinedConfigGenerator | undefined;\n identifiers: ISessionIdentifiers | undefined;\n eventsManager?: AmplitudeSessionReplayEventsManager<'replay' | 'interaction', string>;\n loggerProvider: ILogger;\n recordCancelCallback: ReturnType<RecordFunction> | null = null;\n eventCount = 0;\n eventCompressor: EventCompressor | undefined;\n sessionTargetingMatch = false;\n private lastTargetingParams?: SessionReplayTargetingInput;\n private lastShouldRecordDecision?: boolean;\n // Session for which the one-per-session TRC diagnostic event was already emitted. The\n // diagnostics client caps in-memory events, so per-call signals go through counters and only\n // a single rich snapshot event is recorded per session.\n private trcDiagnosticSessionId: string | number | undefined = undefined;\n\n // Public on purpose. `pageLeaveFns` is iterated by `pageLeaveListener`,\n // `rrwebEventManager` is dereferenced in `asyncSetSessionId` to drop the beacon buffer\n // at a session boundary, and `sessionStartTime` drives `isBelowMinSessionDuration()`.\n // Tests also stub/inspect these — privatizing them would break both production callers\n // and the gate's test coverage.\n pageLeaveFns: PageLeaveFn[] = [];\n sessionStartTime: number | undefined;\n rrwebEventManager: EventsManagerWithBeacon<'replay'> | undefined;\n /**\n * Count of sendEvents() calls suppressed by the min-session-duration gate for the\n * current session. Drives the REPLAY_GATE_DECISION rrweb event on first send-after-pass.\n */\n private suppressedSendCount = 0;\n /** True once REPLAY_GATE_DECISION has been emitted for the current session. */\n private hasEmittedGateDecision = false;\n private scrollHook?: scrollCallback;\n private clickHandler?: ClickHandler;\n private networkObservers?: NetworkObservers;\n private metadata: SessionReplayMetadata | undefined;\n\n // Cache the dynamically imported record function\n private recordFunction: RecordFunction | null = null;\n private recordEventsInFlight = false;\n private pendingEmitEvents: Array<{ event: eventWithTime; sessionId: string | number }> = [];\n\n /** Current page URL, kept in sync with SPA navigations for URL-based masking */\n private currentPageUrl = '';\n\n private recordEventsPendingShouldLogMetadata: boolean | null = null;\n\n /** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */\n private urlChangeCleanup: (() => void) | null = null;\n // Ensures the url_poll.first_tick diagnostic event is emitted at most once per listener setup\n // (the per-tick counter still increments every tick; only the rich event is one-shot).\n private urlPollFirstTickRecorded = false;\n private crossOriginIframeCoordinator: CrossOriginIframeCoordinator | null = null;\n private crossOriginParentSignalCleanup: (() => void) | null = null;\n /** Monotonic counter to ignore stale URL-change targeting results */\n private latestUrlChangeTargetingEvaluationId = 0;\n\n constructor() {\n this.loggerProvider = new SafeLoggerProvider(new Logger());\n }\n\n init(apiKey: string, options: SessionReplayOptions) {\n return returnWrapper(this._init(apiKey, options));\n }\n\n private teardownEventListeners = (teardown: boolean) => {\n const globalScope = getGlobalScope();\n if (globalScope) {\n globalScope.removeEventListener('blur', this.blurListener);\n globalScope.removeEventListener('focus', this.focusListener);\n !teardown && globalScope.addEventListener('blur', this.blurListener);\n !teardown && globalScope.addEventListener('focus', this.focusListener);\n // prefer pagehide to unload events, this is the standard going forward. it is not\n // 100% reliable, but is bfcache-compatible.\n if (globalScope.self && 'onpagehide' in globalScope.self) {\n globalScope.removeEventListener('pagehide', this.pageLeaveListener);\n !teardown && globalScope.addEventListener('pagehide', this.pageLeaveListener);\n } else {\n // this has performance implications, but is the only way we can reliably send events\n // in browser that don't support pagehide.\n globalScope.removeEventListener('beforeunload', this.pageLeaveListener);\n !teardown && globalScope.addEventListener('beforeunload', this.pageLeaveListener);\n }\n }\n };\n\n /**\n * Subscribes to SPA URL changes via the URL tracking plugin. Always keeps\n * `currentPageUrl` in sync (needed for URL-based masking). When a targeting\n * config is present it also re-evaluates targeting on every navigation.\n */\n private setupUrlChangeListener(): void {\n // If init() runs multiple times, remove the previous URL-change subscription first\n // so we don't leak callbacks and trigger duplicate targeting evaluations.\n this.urlChangeCleanup?.();\n\n const globalScope = getGlobalScope() as Window | undefined;\n if (!globalScope?.location) {\n // No window/location (SSR, worker, or pre-render) — the listener can't attach, so TRC will\n // never re-evaluate on navigation. Surface it rather than failing silently.\n this.incrementDiagnostic(SrDiagnostic.urlListenerSkipped);\n this.recordDiagnosticEvent(SrDiagnostic.urlListenerSkipped, { reason: 'no_global_scope' });\n this.loggerProvider.debug('URL-change listener not attached: no global scope/location.');\n return;\n }\n\n const hasTargeting = !!this.config?.targetingConfig;\n\n const onUrlChange = (href: string): void => {\n this.currentPageUrl = href;\n\n // Team-visible signal that an SPA navigation was detected at all (covers the \"is the SDK\n // even seeing route changes in this framework?\" question — counter + a log with the href\n // and whether it triggered a targeting re-eval).\n this.incrementDiagnostic(SrDiagnostic.urlChange);\n this.recordDiagnosticEvent(SrDiagnostic.urlChangeEvent, {\n href,\n hasTargeting,\n alreadyMatched: this.sessionTargetingMatch,\n });\n\n if (hasTargeting) {\n const evaluationId = ++this.latestUrlChangeTargetingEvaluationId;\n void this.evaluateTargetingAndCapture(\n {\n userProperties: {},\n event: undefined,\n page: { url: href },\n },\n false,\n false,\n true,\n );\n this.loggerProvider.debug(`Queued URL-change targeting re-evaluation #${evaluationId} for ${href}.`);\n }\n };\n // Pass the polling options so targeting re-evaluation also respects `enableUrlChangePolling`.\n // Without this, the targeting listener only sees history.pushState/replaceState + popstate +\n // hashchange — so SPA navigations that bypass the history API never re-evaluate TRC and\n // recording never starts on the new URL (enableUrlChangePolling previously only affected the\n // rrweb URL-tracking plugin, which runs only once recording is already active).\n const enablePolling = this.config?.enableUrlChangePolling ?? false;\n this.urlPollFirstTickRecorded = false;\n const unsubscribe = subscribeToUrlChanges(globalScope, onUrlChange, {\n enablePolling,\n pollingInterval: this.config?.urlChangePollingInterval,\n // Mirror each poll tick to the console (Debug level) so we can confirm polling is firing.\n log: this.loggerProvider.debug.bind(this.loggerProvider),\n // Prove in DataDog that polling actually FIRES (not just that it was scheduled). Per-tick is a\n // cheap aggregated counter; the rich event is emitted once (with href) to avoid flooding the\n // diagnostics endpoint with one capture POST per second.\n onPoll: (href: string, changed: boolean): void => {\n this.incrementDiagnostic(SrDiagnostic.urlPollTick);\n if (!this.urlPollFirstTickRecorded) {\n this.urlPollFirstTickRecorded = true;\n // pollingInterval is already on url_listener.attached, so it's omitted here.\n this.recordDiagnosticEvent(SrDiagnostic.urlPollFirstTick, { href, changed });\n }\n },\n });\n // Confirm the listener is actually live, and under what settings — if recording never starts on\n // navigation, this tells us whether the listener existed and whether polling (the fallback for\n // SPAs that bypass the History API) was on.\n this.recordDiagnosticEvent(SrDiagnostic.urlListenerAttached, {\n hasTargeting,\n enablePolling,\n pollingInterval: this.config?.urlChangePollingInterval,\n });\n this.loggerProvider.debug(`URL-change listener attached (polling: ${String(enablePolling)}).`);\n\n this.urlChangeCleanup = (): void => {\n unsubscribe();\n this.urlChangeCleanup = null;\n };\n }\n\n /**\n * Single source of truth for the min_session_duration_ms gate. Returns true when the\n * current session has not yet reached the configured threshold (and we have both a\n * configured value and a recorded start time). Returns false when there's no\n * threshold, no recorded start time, or the threshold has been met — i.e. it\n * answers \"should this batch be suppressed?\".\n *\n * Centralizing the check means future changes (clock-skew tolerance, switching to\n * performance.now(), etc.) are one-line edits.\n */\n private isBelowMinSessionDuration(): boolean {\n const minSessionDurationMs = this.config?.minSessionDurationMs;\n if (minSessionDurationMs === undefined || this.sessionStartTime === undefined) {\n return false;\n }\n return Date.now() - this.sessionStartTime < minSessionDurationMs;\n }\n\n private getCurrentPageForTargeting(): SessionReplayTargetingInput['page'] {\n const currentUrl = getGlobalScope()?.location?.href;\n return currentUrl != null ? { url: currentUrl } : undefined;\n }\n\n /**\n * Best-effort navigation type from the Navigation Timing API: 'reload' | 'navigate' |\n * 'back_forward' | 'prerender'. Surfaced in the init diagnostic so a page refresh ('reload')\n * is distinguishable from a fresh load ('navigate') — neither changes the session id, so this\n * is the only way to tell them apart. Returns undefined when the API is unavailable.\n */\n private getNavigationType(): string | undefined {\n try {\n const globalScope = getGlobalScope();\n const performance = globalScope && globalScope.performance;\n if (!performance || typeof performance.getEntriesByType !== 'function') {\n return undefined;\n }\n const navEntries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[];\n return navEntries.length > 0 ? navEntries[0].type : undefined;\n } catch {\n return undefined;\n }\n }\n\n protected async _init(apiKey: string, options: SessionReplayOptions) {\n // Re-init should always tear down any previous URL-change subscription, even when the\n // next config has no targeting config and we don't subscribe again.\n this.urlChangeCleanup?.();\n\n this.loggerProvider = new SafeLoggerProvider(options.loggerProvider || new Logger());\n Object.prototype.hasOwnProperty.call(options, 'logLevel') &&\n this.loggerProvider.enable(options.logLevel as LogLevel);\n this.currentPageUrl = getCurrentUrl();\n this.identifiers = new SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId });\n // Persist replay start time per sessionId so the min_session_duration_ms gate\n // measures replay duration (survives page reloads within a session) rather than\n // page-load duration. Storage failures fall back to a transient Date.now().\n const now = Date.now();\n pruneStaleReplayStartTimes(apiKey, now, this.loggerProvider);\n this.sessionStartTime =\n options.sessionId !== undefined\n ? getOrInitReplayStartTime(apiKey, options.sessionId, now, this.loggerProvider) ?? now\n : now;\n this.joinedConfigGenerator = await createSessionReplayJoinedConfigGenerator(apiKey, options);\n const { joinedConfig, localConfig, remoteConfig } = await this.joinedConfigGenerator.generateJoinedConfig();\n this.config = joinedConfig;\n\n this.setMetadata(\n options.sessionId,\n joinedConfig,\n localConfig,\n remoteConfig,\n options.version?.version,\n VERSION,\n options.version?.type,\n );\n\n this.pageLeaveFns = [];\n\n if (options.sessionId && this.config.interactionConfig?.enabled) {\n const scrollWatcher = ScrollWatcher.default(\n {\n sessionId: options.sessionId,\n type: 'interaction',\n },\n this.config,\n );\n this.pageLeaveFns = [scrollWatcher.send(this.getDeviceId.bind(this)).bind(scrollWatcher)];\n this.scrollHook = scrollWatcher.hook.bind(scrollWatcher);\n this.clickHandler = new ClickHandler(this.loggerProvider, scrollWatcher);\n }\n\n const managers: EventsManagerWithType<EventType, string>[] = [];\n let { storeType } = this.config;\n if (storeType === 'idb' && !getGlobalScope()?.indexedDB) {\n storeType = 'memory';\n this.loggerProvider.warn('Could not use preferred indexedDB storage, reverting to in memory option.');\n }\n this.loggerProvider.log(`Using ${storeType} for event storage.`);\n let compressionWorkerScript: string | undefined;\n let trackDestinationWorkerScript: string | undefined;\n const globalScope = getGlobalScope();\n if (this.config.useWebWorker && globalScope && globalScope.Worker) {\n const { compressionScript, trackDestinationScript } = await import('./worker');\n compressionWorkerScript = compressionScript;\n trackDestinationWorkerScript = trackDestinationScript;\n }\n\n let rrwebEventManager: EventsManagerWithBeacon<'replay'> | undefined;\n try {\n rrwebEventManager = await createEventsManager<'replay'>({\n config: this.config,\n type: 'replay',\n minInterval: this.config.flushIntervalConfig?.minIntervalMs,\n maxInterval: this.config.flushIntervalConfig?.maxIntervalMs,\n maxPersistedEventsSize: this.config.maxPersistedEventsSizeBytes,\n storeType,\n trackDestinationWorkerScript,\n shouldSend: () => !this.isBelowMinSessionDuration(),\n });\n this.rrwebEventManager = rrwebEventManager;\n managers.push({ name: 'replay', manager: rrwebEventManager });\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(`Error occurred while creating replay events manager: ${typedError.toString()}`);\n }\n\n if (this.config.interactionConfig?.enabled) {\n const payloadBatcher = this.config.interactionConfig.batch ? clickBatcher : clickNonBatcher;\n try {\n const interactionEventManager = await createEventsManager<'interaction'>({\n config: this.config,\n type: 'interaction',\n minInterval: this.config.interactionConfig.trackEveryNms ?? INTERACTION_MIN_INTERVAL,\n maxInterval: INTERACTION_MAX_INTERVAL,\n maxPersistedEventsSize: this.config.maxPersistedEventsSizeBytes,\n payloadBatcher,\n storeType,\n trackDestinationWorkerScript,\n });\n managers.push({ name: 'interaction', manager: interactionEventManager });\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(`Error occurred while creating interaction events manager: ${typedError.toString()}`);\n }\n }\n\n this.eventsManager = new MultiEventManager<'replay' | 'interaction', string>(...managers);\n // To prevent too many threads.\n if (this.eventCompressor) {\n this.eventCompressor.terminate();\n }\n\n // Eager full-snapshot send is tunable. When `eagerFullSnapshotSend` is true, every full\n // snapshot triggers an immediate flush so replays are playable as early as possible (the\n // SR-3115 contract). Leaving it unset (default) keeps the snapshot compressed and buffered\n // immediately (ordering + beacon coverage on page exit preserved) but defers the network\n // send to the normal interval/size cadence — this avoids the focus/checkout-driven request\n // storm that eager per-snapshot sends create when many SDK instances run on the same page.\n // The default flipped to disabled per the validated amp-on-amp perf config (SR-4646).\n const onFullSnapshotProcessed = this.config.eagerFullSnapshotSend === true ? () => this.sendEvents() : undefined;\n this.eventCompressor = new EventCompressor(\n this.eventsManager,\n this.config,\n this.getDeviceId(),\n compressionWorkerScript,\n onFullSnapshotProcessed,\n );\n\n // Flush any events that arrived while eventCompressor was not yet ready\n // (e.g. a concurrent setSessionId() call that raced _init()'s async setup).\n if (this.pendingEmitEvents.length > 0) {\n const pending = this.pendingEmitEvents.splice(0);\n for (const { event, sessionId } of pending) {\n this.eventCompressor.enqueueEvent(event, sessionId);\n }\n }\n\n // Register beacon fallback for page exit. sendBeacon survives page unload\n // and delivers any incremental events that haven't been flushed via fetch yet.\n //\n // Known cross-session race: if asyncSetSessionId fired and its async\n // storeCurrentSequence hasn't resolved before unload, the beacon buffer can still\n // hold previous-session events. The gate below reads the *new* session's\n // sessionStartTime, so legitimately-sendable old-session events get suppressed.\n // Follow-up: track start time per buffered batch instead of globally.\n this.pageLeaveFns = [\n ...this.pageLeaveFns,\n () => {\n if (!this.config || !this.identifiers?.sessionId || !rrwebEventManager) return;\n const events = rrwebEventManager.getBeaconEvents();\n if (!events.length) return;\n const deviceId = this.getDeviceId();\n if (!deviceId) return;\n if (this.isBelowMinSessionDuration()) return;\n rrwebEventManager.trackDestination.sendBeacon({\n events,\n sessionId: this.identifiers.sessionId,\n deviceId,\n apiKey: this.config.apiKey,\n serverZone: this.config.serverZone,\n });\n },\n ];\n\n await this.initializeNetworkObservers();\n\n // Enable background capture when this page is opened by the Amplitude app\n // (window.opener exists). Uses the shared messenger singleton so that if\n // autocapture is also loaded, both share a single messenger and script load.\n if (getGlobalScope()?.opener) {\n const messenger = getOrCreateWindowMessenger();\n enableBackgroundCapture(messenger);\n messenger.setup({\n logger: this.loggerProvider,\n ...(this.config.serverZone && { endpoint: AMPLITUDE_ORIGINS_MAP[this.config.serverZone] }),\n });\n }\n\n this.loggerProvider.log('Installing @amplitude/session-replay-browser.');\n\n this.teardownEventListeners(false);\n\n // Q1 \"did init happen?\": its presence in DataDog proves init() ran to completion for this\n // session; the props show whether the prerequisites (session/device id, config) were present.\n this.incrementDiagnostic(SrDiagnostic.init);\n this.recordDiagnosticEvent(SrDiagnostic.init, {\n // sessionId is always stamped by recordDiagnosticEvent, so no separate hasSessionId here.\n hasDeviceId: !!this.getDeviceId(),\n captureEnabled: this.config.captureEnabled,\n hasTargetingConfig: !!this.config.targetingConfig,\n sampleRate: this.config.sampleRate,\n optOut: this.shouldOptOut(),\n currentUrl: this.getCurrentPageForTargeting()?.url,\n // 'reload' tells a page refresh apart from a fresh load ('navigate') or back/forward\n // ('back_forward'). New tabs and refreshes keep the same session id, so this is the only\n // way to distinguish a refresh from a brand-new init within a session.\n navigationType: this.getNavigationType(),\n });\n\n await this.evaluateTargetingAndCapture(\n { userProperties: options.userProperties, page: this.getCurrentPageForTargeting() },\n true,\n );\n\n const needsUrlTracking = this.config.targetingConfig || (this.config.privacyConfig?.urlMaskLevels?.length ?? 0) > 0;\n // Record whether we even attempt to wire up the URL-change listener, and the inputs behind that\n // decision. If `needsUrlTracking` is false the listener is never attached, so SPA navigations are\n // invisible to TRC — this is the first thing to check when \"TRC is on but never re-evaluates\".\n this.recordDiagnosticEvent(SrDiagnostic.urlListenerSetup, {\n needsUrlTracking: !!needsUrlTracking,\n hasTargetingConfig: !!this.config.targetingConfig,\n urlMaskLevels: this.config.privacyConfig?.urlMaskLevels?.length ?? 0,\n // config always defaults this to a boolean (see local-config), so no `?? false` needed here.\n enableUrlChangePolling: this.config.enableUrlChangePolling,\n urlChangePollingInterval: this.config.urlChangePollingInterval,\n });\n this.loggerProvider.debug(`URL-change listener needed: ${String(!!needsUrlTracking)}.`);\n if (needsUrlTracking) {\n this.setupUrlChangeListener();\n }\n }\n\n setSessionId(sessionId: string | number, deviceId?: string) {\n return returnWrapper(this.asyncSetSessionId(sessionId, deviceId));\n }\n\n async asyncSetSessionId(\n sessionId: string | number,\n deviceId?: string,\n options?: { userProperties?: { [key: string]: any } },\n ) {\n const previousSessionId = this.identifiers?.sessionId;\n const currentDeviceId = this.getDeviceId();\n // Standalone SDK callers may poll setSessionId with a stable bucket id (e.g. hour-aligned\n // timestamps) and only need a no-op when the bucket hasn't rolled. Without this guard,\n // the rest of asyncSetSessionId still runs: sendEvents, targeting reset, config refetch,\n // and recordEvents (stop + restart rrweb). Proceed when deviceId changes or\n // non-empty userProperties are passed so targeting can re-evaluate on Identify.\n if (\n previousSessionId !== undefined &&\n previousSessionId === sessionId &&\n (deviceId === undefined || deviceId === currentDeviceId) &&\n (options?.userProperties === undefined || Object.keys(options.userProperties).length === 0)\n ) {\n return;\n }\n\n // Invalidate any in-flight URL-change re-evaluations from the previous session.\n this.latestUrlChangeTargetingEvaluationId++;\n this.sessionTargetingMatch = false;\n this.lastShouldRecordDecision = undefined; // Reset targeting decision for new session\n if (previousSessionId) {\n this.sendEvents(previousSessionId);\n }\n\n const isSessionChange = previousSessionId !== sessionId;\n\n // A real session transition (not the first set): recording stops/restarts and targeting is\n // re-evaluated here, so session churn (timeout, multi-tab custom ids, explicit setSessionId)\n // is a prime suspect for \"sometimes records, sometimes not\". recordDiagnosticEvent ships to\n // DataDog AND mirrors to loggerProvider.debug. New tabs / refreshes keep the same id and won't\n // hit this — use the init diagnostic's navigationType for those.\n if (isSessionChange && previousSessionId !== undefined) {\n this.recordDiagnosticEvent(SrDiagnostic.sessionChanged, {\n from: previousSessionId,\n to: sessionId,\n deviceIdChanged: deviceId !== undefined && deviceId !== currentDeviceId,\n });\n }\n\n // Drop any beacon-buffered events from the previous session BEFORE installing the\n // new identifiers / start time. Otherwise the page-leave beacon path could attribute\n // old-session events to the new session id, and the gate (using the new start time)\n // would compute the wrong elapsed duration. Skip on a redundant same-sessionId call —\n // the buffer belongs to the *continuing* session and should ship via beacon as normal.\n if (isSessionChange) {\n this.rrwebEventManager?.dropPendingBeaconEvents();\n }\n\n const deviceIdForReplayId = deviceId || this.getDeviceId();\n this.identifiers = new SessionIdentifiers({\n sessionId: sessionId,\n deviceId: deviceIdForReplayId,\n });\n\n // Gate state and persisted start time only get reset on an actual session boundary.\n // A redundant setSessionId(currentId) call would otherwise overwrite both the in-memory\n // and stored start time with a fresh Date.now() — restarting the gate clock for what is\n // supposed to be a continuing session.\n if (isSessionChange) {\n this.sessionStartTime = Date.now();\n this.suppressedSendCount = 0;\n this.hasEmittedGateDecision = false;\n if (this.config?.apiKey) {\n setReplayStartTime(this.config.apiKey, sessionId, this.sessionStartTime, this.loggerProvider);\n if (previousSessionId !== undefined) {\n removeReplayStartTime(this.config.apiKey, previousSessionId, this.loggerProvider);\n }\n }\n }\n\n // If there is no previous session id, SDK is being initialized for the first time,\n // and config was just fetched in initialization, so no need to fetch it a second time\n if (this.joinedConfigGenerator && previousSessionId) {\n const { joinedConfig } = await this.joinedConfigGenerator.generateJoinedConfig();\n this.config = joinedConfig;\n }\n\n if (this.config?.targetingConfig) {\n await this.evaluateTargetingAndCapture(\n { userProperties: options?.userProperties, page: this.getCurrentPageForTargeting() },\n false,\n true,\n );\n } else {\n await this.recordEvents();\n }\n }\n\n getSessionReplayProperties() {\n const config = this.config;\n const identifiers = this.identifiers;\n if (!config || !identifiers) {\n this.loggerProvider.warn('Session replay init has not been called, cannot get session replay properties.');\n return {};\n }\n\n const shouldRecord = this.getShouldRecord();\n let eventProperties: { [key: string]: string | null } = {};\n\n if (shouldRecord) {\n eventProperties = {\n [DEFAULT_SESSION_REPLAY_PROPERTY]: identifiers.sessionReplayId ? identifiers.sessionReplayId : null,\n };\n if (config.debugMode) {\n eventProperties[SESSION_REPLAY_DEBUG_PROPERTY] = JSON.stringify({\n appHash: generateHashCode(config.apiKey).toString(),\n });\n }\n }\n\n void this.addCustomRRWebEvent(\n CustomRRwebEvent.GET_SR_PROPS,\n {\n shouldRecord,\n eventProperties: eventProperties,\n },\n this.eventCount === 10,\n );\n if (this.eventCount === 10) {\n this.eventCount = 0;\n }\n this.eventCount++;\n\n return eventProperties;\n }\n\n blurListener = () => {\n this.sendEvents();\n };\n\n focusListener = () => {\n if (this.recordCancelCallback && this.recordFunction) {\n // Recording is already active. The on-focus full snapshot is tunable: when\n // `captureFullSnapshotOnFocus` is false we skip it entirely so high focus-churn pages\n // don't generate a full snapshot (and, with eager send, a network request) per focus.\n if (this.config?.captureFullSnapshotOnFocus === false) {\n return;\n }\n try {\n this.recordFunction.takeFullSnapshot(true);\n } catch (error) {\n this.loggerProvider.warn('Failed to take full snapshot on focus:', error);\n }\n } else if (!this.recordEventsInFlight) {\n void this.recordEvents(false);\n }\n };\n\n /**\n * This is an instance member so that if init is called multiple times\n * it doesn't add another listener to the page leave event. This is to\n * prevent duplicate listener actions from firing.\n */\n private pageLeaveListener = (e: PageTransitionEvent | Event) => {\n // Synchronously drain any events still queued in the requestIdleCallback\n // pipeline so they are available to send before the page unloads.\n this.eventCompressor?.flushQueue();\n this.sendEvents();\n this.pageLeaveFns.forEach((fn) => {\n fn(e);\n });\n };\n\n evaluateTargetingAndCapture = async (\n targetingParams: SessionReplayTargetingInput,\n isInit = false,\n forceRestart = false,\n forceTargetingReevaluation = false,\n ) => {\n // What triggered this evaluation (init vs SPA URL change vs analytics event) — shows in\n // DataDog how often re-evaluation actually runs.\n this.incrementDiagnostic(\n SrDiagnostic.evalTrigger(isInit ? 'init' : forceTargetingReevaluation ? 'urlchange' : 'event'),\n );\n\n if (!this.identifiers || !this.identifiers.sessionId || !this.config) {\n // Q4: eval can't run because a prerequisite is missing — record exactly which one.\n this.incrementDiagnostic(SrDiagnostic.evalMissingPrereq);\n this.recordDiagnosticEvent(SrDiagnostic.evalMissingPrereq, {\n hasIdentifiers: !!this.identifiers,\n hasSessionId: !!this.identifiers?.sessionId,\n hasConfig: !!this.config,\n hasDeviceId: !!this.getDeviceId(),\n });\n if (this.identifiers && !this.identifiers.sessionId) {\n this.loggerProvider.log('Session ID has not been set yet, cannot evaluate targeting for Session Replay.');\n } else {\n this.loggerProvider.warn('Session replay init has not been called, cannot evaluate targeting.');\n }\n return;\n }\n\n // Handle cases where there's no targeting config\n if (!this.config.targetingConfig) {\n this.incrementDiagnostic(SrDiagnostic.evalNoConfig);\n if (isInit) {\n this.loggerProvider.log('Targeting config has not been set yet, cannot evaluate targeting.');\n } else {\n this.loggerProvider.log('No targeting config set, skipping initialization/recording for event.');\n return;\n }\n }\n\n // Store targeting parameters for use in getShouldRecord\n this.lastTargetingParams = targetingParams;\n\n // Re-evaluate only until we get the first match in this session.\n // Once matched, keep recording for the rest of the session.\n const targetingConfig = this.config.targetingConfig;\n const shouldReEvaluate = targetingConfig && !this.sessionTargetingMatch;\n if (shouldReEvaluate) {\n // Capture URL-change evaluation id so out-of-order async completions can be discarded.\n const urlChangeEvaluationId = forceTargetingReevaluation ? this.latestUrlChangeTargetingEvaluationId : undefined;\n let eventForTargeting = targetingParams.event;\n if (\n eventForTargeting &&\n Object.values(SpecialEventType).includes(eventForTargeting.event_type as SpecialEventType)\n ) {\n eventForTargeting = undefined;\n }\n\n const pageUrl = targetingParams.page?.url ?? getGlobalScope()?.location?.href ?? '';\n const pageForTargeting = targetingParams.page ?? (pageUrl !== '' ? { url: pageUrl } : undefined);\n\n // Record the targeting trigger event\n this.recordDiagnosticEvent(SrDiagnostic.targetingTrigger, {\n sessionId: this.identifiers.sessionId,\n deviceId: this.getDeviceId(),\n targetingConfig: this.config.targetingConfig,\n targetingParams: {\n userProperties: targetingParams.userProperties,\n event: eventForTargeting,\n page: pageForTargeting,\n },\n });\n\n const evalStart = Date.now();\n const targetingMatch = await evaluateTargetingAndStore({\n sessionId: this.identifiers.sessionId,\n targetingConfig,\n loggerProvider: this.loggerProvider,\n apiKey: this.config.apiKey,\n targetingParams: {\n userProperties: targetingParams.userProperties,\n event: eventForTargeting,\n page: pageForTargeting,\n },\n urlChange: forceTargetingReevaluation,\n diagnosticsClient: this.config.diagnosticsClient,\n deviceId: this.getDeviceId(),\n });\n const evalDurationMs = Date.now() - evalStart;\n const trigger = isInit ? 'init' : forceTargetingReevaluation ? 'urlchange' : 'event';\n // Evaluation latency — surfaces the slow-network residual gap (SR-4234) in DataDog as\n // sdk.diagnostics.sr.trc.eval.duration_ms.{avg,max,...}.\n this.recordDiagnosticHistogram(SrDiagnostic.evalDurationMs, evalDurationMs);\n\n if (\n forceTargetingReevaluation &&\n urlChangeEvaluationId !== undefined &&\n urlChangeEvaluationId !== this.latestUrlChangeTargetingEvaluationId\n ) {\n this.incrementDiagnostic(SrDiagnostic.evalStaleDiscarded);\n this.recordDiagnosticEvent(SrDiagnostic.evalStaleDiscarded, {\n sessionId: this.identifiers.sessionId,\n pageUrl: pageForTargeting?.url,\n evaluationId: urlChangeEvaluationId,\n latestEvaluationId: this.latestUrlChangeTargetingEvaluationId,\n evalDurationMs,\n });\n this.loggerProvider.debug(\n `Ignoring stale URL-change targeting result #${urlChangeEvaluationId}; latest is #${this.latestUrlChangeTargetingEvaluationId}.`,\n );\n return;\n }\n // Per-evaluation outcome (distinct from the per-session sr.gate.* gate counters).\n this.incrementDiagnostic(targetingMatch ? SrDiagnostic.evalMatch : SrDiagnostic.evalNoMatch);\n // Keep targeting match monotonic within a session: once true, always true.\n // This avoids races where an older in-flight evaluation resolves false after\n // a newer evaluation already resolved true.\n this.sessionTargetingMatch = this.sessionTargetingMatch || targetingMatch;\n // Q5: record ALL evaluation params (→ DataDog Logs) so a single evaluation can be fully\n // reconstructed by URL, identifiers, inputs, outcome, trigger and latency. userProperties\n // values are intentionally reduced to keys to avoid logging PII.\n this.recordDiagnosticEvent(SrDiagnostic.evalEvent, {\n // sessionId + deviceId are stamped by recordDiagnosticEvent.\n trigger,\n matched: targetingMatch,\n sessionTargetingMatch: this.sessionTargetingMatch,\n pageUrl: pageForTargeting?.url,\n hasDeviceId: !!this.getDeviceId(),\n hasEvent: !!eventForTargeting,\n eventType: eventForTargeting?.event_type,\n userPropertyKeys: targetingParams.userProperties ? Object.keys(targetingParams.userProperties) : [],\n evalDurationMs,\n });\n\n this.loggerProvider.debug(\n JSON.stringify(\n {\n name: 'targeted replay capture config',\n sessionTargetingMatch: this.sessionTargetingMatch,\n event: eventForTargeting,\n targetingParams: targetingParams,\n },\n null,\n 2,\n ),\n );\n } else if (targetingConfig && this.sessionTargetingMatch) {\n // Already matched earlier this session — recording continues without re-evaluation.\n this.incrementDiagnostic(SrDiagnostic.evalSkippedAlreadyMatched);\n }\n\n if (isInit) {\n void this.initialize(true);\n } else if (forceRestart || !this.recordCancelCallback) {\n this.loggerProvider.log('Recording events for session due to forceRestart or no ongoing recording.');\n await this.recordEvents();\n }\n };\n\n sendEvents(sessionId?: string | number) {\n const sessionIdToSend = sessionId || this.identifiers?.sessionId;\n const deviceId = this.getDeviceId();\n if (this.eventsManager && sessionIdToSend && deviceId) {\n if (this.isBelowMinSessionDuration()) {\n // Safe to dereference: isBelowMinSessionDuration() only returns true when both\n // this.config and this.sessionStartTime are defined.\n const startTime = this.sessionStartTime as number;\n const minMs = (this.config as SessionReplayJoinedConfig).minSessionDurationMs as number;\n this.loggerProvider.log(\n `Session ${sessionIdToSend} not sent: duration ${Date.now() - startTime}ms is below minimum ${minMs}ms.`,\n );\n // We deliberately do NOT clear the beacon buffer here. Blur/visibility-change\n // can call sendEvents() mid-session; if the session later crosses the threshold\n // those buffered events are legitimately sendable via beacon on page exit.\n // Cross-session leak is prevented in asyncSetSessionId, which drops the buffer\n // at the session transition. The page-leave path also gates independently.\n this.suppressedSendCount++;\n // gap #1: recording but events held back by min_session_duration — another \"recording yet\n // no replay in Amplitude\" cause.\n this.incrementDiagnostic(SrDiagnostic.sendSuppressedMinDuration);\n return;\n }\n // On the first send-after-pass for the session, emit a custom rrweb event so the\n // payload itself carries the gate verdict. Lets backend ingestion diff intended\n // vs actual replay counts to spot start-time-tracking regressions.\n //\n // Gate on recording being active too: addCustomRRWebEvent is a no-op when\n // recordCancelCallback/recordFunction aren't set yet (e.g. a blur-listener-fired\n // sendEvents reaches us before _recordEvents() activates on a reloaded long-lived\n // session). Tripping hasEmittedGateDecision unconditionally would lose the signal\n // for that session's first real send.\n if (\n !this.hasEmittedGateDecision &&\n this.config?.minSessionDurationMs !== undefined &&\n this.recordCancelCallback &&\n this.recordFunction\n ) {\n this.hasEmittedGateDecision = true;\n const elapsedMs = this.sessionStartTime !== undefined ? Date.now() - this.sessionStartTime : undefined;\n void this.addCustomRRWebEvent(\n CustomRRwebEvent.REPLAY_GATE_DECISION,\n {\n sessionId: sessionIdToSend,\n suppressedSendCount: this.suppressedSendCount,\n elapsedMs,\n minSessionDurationMs: this.config.minSessionDurationMs,\n },\n false,\n );\n }\n this.eventsManager.sendCurrentSequenceEvents({ sessionId: sessionIdToSend, deviceId });\n }\n }\n\n async initialize(shouldSendStoredEvents = false) {\n if (!this.identifiers?.sessionId) {\n this.loggerProvider.log(`Session is not being recorded due to lack of session id.`);\n return Promise.resolve();\n }\n\n const deviceId = this.getDeviceId();\n if (!deviceId) {\n this.loggerProvider.log(`Session is not being recorded due to lack of device id.`);\n return Promise.resolve();\n }\n this.eventsManager && shouldSendStoredEvents && void this.eventsManager.sendStoredEvents({ deviceId });\n\n return this.recordEvents();\n }\n\n shouldOptOut() {\n let identityStoreOptOut: boolean | undefined;\n if (this.config?.instanceName) {\n const identityStore = getAnalyticsConnector(this.config.instanceName).identityStore;\n identityStoreOptOut = identityStore.getIdentity().optOut;\n }\n\n return identityStoreOptOut !== undefined ? identityStoreOptOut : this.config?.optOut;\n }\n\n /**\n * Increment a diagnostics counter so the team can see the distribution of recording decisions\n * across a customer's sessions (e.g. lots of sr.gate.trc_no_match => rule isn't matching).\n * Ships via the analytics SDK's DiagnosticsClient. No-op when there's no client or diagnostics\n * isn't sampled in; never throws — diagnostics must never interfere with recording.\n */\n private incrementDiagnostic(counter: string) {\n try {\n // Mirror to the console (Debug level) so the full set of diagnostics is visible in the\n // browser, not only in DataDog — helps debugging when a customer can't share a repro env.\n this.loggerProvider.debug(`[SR diagnostics] ${counter}`);\n this.config?.diagnosticsClient?.increment(counter);\n } catch {\n // swallow — diagnostics is best-effort\n }\n }\n\n /**\n * Record a diagnostics histogram value (min/max/avg/count in DataDog). Same best-effort, never-\n * throws contract as incrementDiagnostic. Use for latencies/sizes, not per-call counts.\n */\n private recordDiagnosticHistogram(name: string, value: number) {\n try {\n // Mirror to the console (Debug level) — see incrementDiagnostic.\n this.loggerProvider.debug(`[SR diagnostics] ${name}=${value}`);\n // The only caller runs inside evaluateTargetingAndCapture's `this.config` guard, so the\n // `config == null` arm of this optional chain is unreachable here (kept as defensive parity\n // with recordDiagnosticEvent). The diagnosticsClient-absent arm IS exercised by no-client tests.\n /* istanbul ignore next */\n this.config?.diagnosticsClient?.recordHistogram(name, value);\n } catch {\n // swallow — diagnostics is best-effort\n }\n }\n\n /**\n * Record a diagnostics EVENT with properties. Events are forwarded to DataDog Logs, so the\n * properties become queryable fields (e.g. @matched, @pageUrl). Use sparingly vs counters: the\n * client caps in-memory events (~10 per save interval), so this is for context-rich signals at\n * meaningful decision points, not per-call tallies. Best-effort, never throws.\n */\n private recordDiagnosticEvent(name: string, properties: { [key: string]: unknown }) {\n try {\n const sessionId = this.identifiers?.sessionId;\n const deviceId = this.getDeviceId();\n // Always stamp sessionId, deviceId and srId so every diagnostics event (→ DataDog Logs) can\n // be correlated to a single session/device — and to the actual replay, since the Session\n // Replay ID is `${deviceId}/${sessionId}`. Caller props override if they pass their own.\n const enriched = {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n ...properties,\n };\n // Mirror to the console (Debug level) so the full event + props are visible in the browser,\n // not only in DataDog — see incrementDiagnostic.\n this.loggerProvider.debug(`[SR diagnostics] ${name} ${JSON.stringify(enriched)}`);\n this.config?.diagnosticsClient?.recordEvent(name, enriched);\n // Flush immediately so the event ships now rather than on the client's ~5-min timer (and so\n // short sessions that never reach the timer aren't lost). NOTE: this sends one capture POST\n // per event — higher request volume; revisit/gate before production.\n void this.config?.diagnosticsClient?._flush?.();\n } catch {\n // swallow — diagnostics is best-effort\n }\n }\n\n /**\n * Emit a single rich TRC decision snapshot per session to diagnostics — surfaced even when\n * nothing records (the exact case customers can't reproduce locally).\n */\n private recordTrcDecisionDiagnostic(shouldRecord: boolean) {\n const config = this.config;\n // Every caller is past getShouldRecord's `!this.identifiers`/`!this.config` guard, so both are\n // defined here; the `?.` arms below are unreachable defensive narrowing and excluded from\n // coverage. The reachable guards (no diagnosticsClient, undefined/duplicate sessionId) are tested.\n /* istanbul ignore next */\n if (!config) {\n return;\n }\n /* istanbul ignore next */\n const sessionId = this.identifiers?.sessionId;\n // Once past this guard, config.diagnosticsClient is truthy, so the fields below read config\n // directly rather than re-asserting with `?.` on every access.\n if (!config.diagnosticsClient || sessionId === undefined || sessionId === this.trcDiagnosticSessionId) {\n return;\n }\n this.trcDiagnosticSessionId = sessionId;\n // Goes through recordDiagnosticEvent so it carries sessionId + deviceId like every other event.\n this.recordDiagnosticEvent(SrDiagnostic.decision, {\n shouldRecord,\n captureEnabled: config.captureEnabled,\n hasTargetingConfig: !!config.targetingConfig,\n sessionTargetingMatch: this.sessionTargetingMatch,\n sampleRate: config.sampleRate,\n pageUrl: this.getCurrentPageForTargeting()?.url,\n sdkVersion: VERSION,\n });\n }\n\n getShouldRecord() {\n if (!this.identifiers || !this.config || !this.identifiers.sessionId) {\n this.loggerProvider.warn(`Session is not being recorded due to lack of config, please call sessionReplay.init.`);\n this.incrementDiagnostic(SrDiagnostic.gateNoIdentifiers);\n return false;\n }\n\n if (!this.config.captureEnabled) {\n this.loggerProvider.log(\n `Session ${this.identifiers.sessionId} not being captured due to capture being disabled for project or because the remote config could not be fetched.`,\n );\n this.incrementDiagnostic(SrDiagnostic.gateCaptureDisabled);\n this.recordTrcDecisionDiagnostic(false);\n return false;\n }\n\n if (this.shouldOptOut()) {\n this.loggerProvider.log(`Opting session ${this.identifiers.sessionId} out of recording due to optOut config.`);\n this.incrementDiagnostic(SrDiagnostic.gateOptOut);\n this.recordTrcDecisionDiagnostic(false);\n return false;\n }\n\n let shouldRecord = false;\n let message = '';\n let matched = false;\n\n // If targetingConfig exists, we'll use the sessionTargetingMatch to determine whether to record\n // Otherwise, we'll evaluate the session against the overall sample rate\n if (this.config.targetingConfig) {\n if (!this.sessionTargetingMatch) {\n message = `Not capturing replays for session ${this.identifiers.sessionId} due to not matching targeting conditions.`;\n this.loggerProvider.log(message);\n shouldRecord = false;\n matched = false;\n this.incrementDiagnostic(SrDiagnostic.gateTrcNoMatch);\n } else {\n message = `Capturing replays for session ${this.identifiers.sessionId} due to matching targeting conditions.`;\n this.loggerProvider.log(message);\n shouldRecord = true;\n matched = true;\n this.incrementDiagnostic(SrDiagnostic.gateTrcMatch);\n }\n } else {\n const isInSample = isSessionInSample(this.identifiers.sessionId, this.config.sampleRate);\n if (!isInSample) {\n message = `Opting session ${this.identifiers.sessionId} out of recording due to sample rate.`;\n this.loggerProvider.log(message);\n shouldRecord = false;\n matched = false;\n this.incrementDiagnostic(SrDiagnostic.gateSampleOut);\n } else {\n shouldRecord = true;\n matched = true;\n this.incrementDiagnostic(SrDiagnostic.gateSampleIn);\n }\n }\n\n // Only send custom rrweb event for targeting decision when the decision changes\n if (this.lastShouldRecordDecision !== shouldRecord && this.config.targetingConfig) {\n void this.addCustomRRWebEvent(CustomRRwebEvent.TARGETING_DECISION, {\n message,\n sessionId: this.identifiers.sessionId,\n matched,\n targetingParams: this.lastTargetingParams,\n });\n this.lastShouldRecordDecision = shouldRecord;\n }\n\n this.recordTrcDecisionDiagnostic(shouldRecord);\n\n return shouldRecord;\n }\n\n getBlockSelectors(): string | string[] | undefined {\n // For some reason, this defaults to empty array ([]) if undefined in the compiled script.\n // Empty arrays cause errors when being evaluated in Safari.\n // Force the selector to be undefined if it's an empty array.\n const blockSelector = this.config?.privacyConfig?.blockSelector ?? [];\n if (blockSelector.length === 0) {\n return undefined;\n }\n return blockSelector;\n }\n\n getMaskTextSelectors(): string | undefined {\n const privacyConfig = this.config?.privacyConfig;\n const effectiveLevel = privacyConfig ? getEffectiveMaskLevel(this.currentPageUrl, privacyConfig) : undefined;\n\n if (effectiveLevel === 'conservative') {\n return '*';\n }\n\n // If any urlMaskLevels rule uses 'conservative', always route all text nodes\n // through maskTextFn so the dynamic URL getter can decide at call time.\n // Without this, rrweb's static maskTextSelector would miss text nodes when\n // the user navigates from a non-conservative page to a conservative one.\n if (privacyConfig?.urlMaskLevels?.some((rule) => rule.maskLevel === 'conservative')) {\n return '*';\n }\n\n // If defaultMaskLevel is 'conservative' and URL rules exist, always route text through\n // maskTextFn — a page matching no rule falls back to the conservative default, and\n // rrweb must be set up at start to call maskTextFn for those text nodes.\n const urlMaskLevels = privacyConfig?.urlMaskLevels;\n if (privacyConfig?.defaultMaskLevel === 'conservative' && urlMaskLevels && urlMaskLevels.length > 0) {\n return '*';\n }\n\n const maskSelector = privacyConfig?.maskSelector;\n if (!maskSelector) {\n return;\n }\n\n return maskSelector as unknown as string;\n }\n\n async getRecordingPlugins(loggingConfig: LoggingConfig | undefined) {\n const plugins = [];\n\n // Add URL tracking plugin\n try {\n const urlTrackingPlugin = createUrlTrackingPlugin({\n ugcFilterRules: this.config?.interactionConfig?.ugcFilterRules || [],\n enablePolling: this.config?.enableUrlChangePolling || false,\n pollingInterval: this.config?.urlChangePollingInterval,\n captureDocumentTitle: this.config?.captureDocumentTitle,\n });\n\n plugins.push(urlTrackingPlugin);\n } catch (error) {\n this.loggerProvider.warn('Failed to create URL tracking plugin:', error);\n }\n\n // Default plugin settings -\n // {\n // level: ['info', 'log', 'warn', 'error'],\n // lengthThreshold: 10000,\n // stringifyOptions: {\n // stringLengthLimit: undefined,\n // numOfKeysLimit: 50,\n // depthOfLimit: 4,\n // },\n // logger: window.console,\n // }\n if (loggingConfig?.console?.enabled) {\n try {\n // Dynamic import keeps console plugin separate and only loads when needed\n const { getRecordConsolePlugin } = await import('@amplitude/rrweb-plugin-console-record');\n plugins.push(getRecordConsolePlugin({ level: loggingConfig.console.levels }));\n } catch (error) {\n this.loggerProvider.warn('Failed to load console plugin:', error);\n }\n }\n\n return plugins.length > 0 ? plugins : undefined;\n }\n\n private async getRecordFunction(): Promise<RecordFunction | null> {\n if (this.recordFunction) {\n return this.recordFunction;\n }\n\n try {\n const { record } = await import('@amplitude/rrweb-record');\n this.recordFunction = record;\n return record;\n } catch (error) {\n this.loggerProvider.warn('Failed to load rrweb-record module:', error);\n return null;\n }\n }\n\n async recordEvents(shouldLogMetadata = true) {\n if (this.recordEventsInFlight) {\n this.recordEventsPendingShouldLogMetadata = shouldLogMetadata;\n return;\n }\n this.recordEventsInFlight = true;\n try {\n await this._recordEvents(shouldLogMetadata);\n while (this.recordEventsPendingShouldLogMetadata !== null) {\n const pendingArgs = this.recordEventsPendingShouldLogMetadata;\n this.recordEventsPendingShouldLogMetadata = null;\n await this._recordEvents(pendingArgs);\n }\n } finally {\n this.recordEventsInFlight = false;\n this.recordEventsPendingShouldLogMetadata = null;\n }\n }\n\n private async _recordEvents(shouldLogMetadata = true) {\n const config = this.config;\n const shouldRecord = this.getShouldRecord();\n const sessionId = this.identifiers?.sessionId;\n if (!shouldRecord || !sessionId || !config) {\n return;\n }\n this.stopRecordingEvents();\n\n const recordFunction = await this.getRecordFunction();\n\n // May be undefined if cannot import rrweb-record\n if (!recordFunction) {\n // gap #1: gate said record, but rrweb couldn't load → no replay despite shouldRecord=true.\n this.incrementDiagnostic(SrDiagnostic.recordNoRecordFn);\n this.recordDiagnosticEvent(SrDiagnostic.recordNoRecordFn, {});\n return;\n }\n\n await this.initializeNetworkObservers();\n\n const networkLoggingConfig = config.loggingConfig?.network;\n const trackUrl = getServerUrl(config.serverZone, config.trackServerUrl);\n const ignoredUrls = [SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_EU_URL, SESSION_REPLAY_STAGING_URL, trackUrl];\n this.networkObservers?.start((event: NetworkRequestEvent) => {\n if (ignoredUrls.some((url) => event.url.startsWith(url))) return;\n void this.addCustomRRWebEvent(CustomRRwebEvent.FETCH_REQUEST, event);\n }, networkLoggingConfig);\n const { interactionConfig, loggingConfig } = config;\n\n const hooks = interactionConfig?.enabled\n ? {\n mouseInteraction:\n this.eventsManager &&\n this.clickHandler?.createHook({\n eventsManager: this.eventsManager,\n sessionId,\n deviceIdFn: this.getDeviceId.bind(this),\n mirror: recordFunction.mirror,\n ugcFilterRules: interactionConfig.ugcFilterRules ?? [],\n performanceOptions: config.performanceConfig?.interaction,\n }),\n scroll: this.scrollHook,\n }\n : {};\n\n const ugcFilterRules =\n interactionConfig?.enabled && interactionConfig.ugcFilterRules ? interactionConfig.ugcFilterRules : [];\n\n this.loggerProvider.log(`Session Replay capture beginning for ${sessionId}.`);\n // gap #1: rrweb is actually starting. Closes the \"gate said yes but no replay\" blind spot,\n // and its srId is the id the replay uploads under (compare with analytics events to catch the\n // device-id mismatch that breaks stitching).\n this.incrementDiagnostic(SrDiagnostic.recordStarted);\n this.recordDiagnosticEvent(SrDiagnostic.recordStarted, {});\n\n try {\n const crossOriginIframesEnabled = !!config.crossOriginIframes?.enabled;\n const coordinateChildren = config.crossOriginIframes?.coordinateChildren !== false;\n const childMode = crossOriginIframesEnabled && isInIframe();\n\n if (childMode && coordinateChildren) {\n // Child mode: don't self-start; wait for a start signal from the parent.\n // (The previous listener, if any, was already removed by stopRecordingEvents above.)\n this.crossOriginParentSignalCleanup = listenForParentSignals({\n onStart: () => this._recordEventsInChildMode(recordFunction, sessionId, config, hooks),\n onStop: () => {\n try {\n // Only cancel the rrweb recording — do NOT call stopRecordingEvents() here,\n // which would clear crossOriginParentSignalCleanup and make the child deaf\n // to subsequent start/stop cycles from the parent.\n this.recordCancelCallback && this.recordCancelCallback();\n this.recordCancelCallback = null;\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(\n `Error occurred while stopping child iframe replay capture: ${typedError.toString()}`,\n );\n }\n },\n });\n return;\n }\n\n this.recordCancelCallback = recordFunction({\n ...this.buildRRWebRecordOptions(\n config,\n hooks,\n (event: eventWithTime) => {\n if (this.shouldOptOut()) {\n this.loggerProvider.log(`Opting session ${sessionId} out of recording due to optOut config.`);\n this.stopRecordingEvents();\n this.sendEvents();\n return;\n }\n\n if (event.type === RRWebEventType.Meta) {\n event.data.href = getPageUrl(event.data.href, ugcFilterRules);\n }\n\n if (this.eventCompressor) {\n // Schedule processing during idle time if the browser supports requestIdleCallback\n this.eventCompressor.enqueueEvent(event, sessionId);\n } else {\n // eventCompressor is not yet ready (concurrent call racing _init()).\n // Buffer the event so it can be flushed once the compressor is initialized.\n this.pendingEmitEvents.push({ event, sessionId });\n }\n },\n 'Error while capturing replay: ',\n ),\n plugins: await this.getRecordingPlugins(loggingConfig),\n recordCrossOriginIframes: crossOriginIframesEnabled,\n });\n\n if (crossOriginIframesEnabled && !childMode && coordinateChildren) {\n if (!this.crossOriginIframeCoordinator) {\n this.crossOriginIframeCoordinator = new CrossOriginIframeCoordinator();\n }\n this.crossOriginIframeCoordinator.start();\n }\n\n void this.addCustomRRWebEvent(CustomRRwebEvent.DEBUG_INFO);\n if (shouldLogMetadata) {\n void this.addCustomRRWebEvent(CustomRRwebEvent.METADATA, this.metadata);\n }\n } catch (error) {\n this.loggerProvider.warn('Failed to initialize session replay:', error);\n }\n }\n\n private buildRRWebRecordOptions(\n config: SessionReplayJoinedConfig,\n hooks: { mouseInteraction?: any; scroll?: scrollCallback },\n emit: (event: eventWithTime) => void,\n errorLogPrefix: string,\n ): Parameters<RecordFunction>[0] {\n const { privacyConfig } = config;\n return {\n emit,\n inlineStylesheet: config.shouldInlineStylesheet,\n hooks,\n maskAllInputs: true,\n maskTextClass: MASK_TEXT_CLASS,\n blockClass: BLOCK_CLASS,\n blockSelector: this.getBlockSelectors() as string | undefined,\n applyBackgroundColorToBlockedElements: config.applyBackgroundColorToBlockedElements,\n maskInputFn: maskFn('input', privacyConfig, () => this.currentPageUrl),\n maskTextFn: maskFn('text', privacyConfig, () => this.currentPageUrl),\n maskAttributeFn: maskAttributeFn(privacyConfig, () => this.currentPageUrl),\n maskTextSelector: this.getMaskTextSelectors(),\n ...(config.fullSnapshotIntervalMs !== undefined && { checkoutEveryNms: config.fullSnapshotIntervalMs }),\n recordCanvas: false,\n captureAdoptedStyleSheets: config.captureAdoptedStyleSheets,\n // Strip nodes that are never rendered by the rrweb replay player.\n // None of these affect visual fidelity; omitting them reduces snapshot size.\n slimDOMOptions: {\n script: true,\n comment: true,\n headFavicon: true,\n headWhitespace: true,\n headMetaDescKeywords: true,\n headMetaSocial: true,\n headMetaRobots: true,\n headMetaHttpEquiv: true,\n headMetaAuthorship: true,\n headMetaVerification: true,\n },\n errorHandler: (error: unknown) => {\n const typedError = error as Error & { _external_?: boolean };\n // styled-components relies on this error being thrown and bubbled up, rrweb is otherwise suppressing it\n if (typedError.message.includes('insertRule') && typedError.message.includes('CSSStyleSheet')) {\n throw typedError;\n }\n // rrweb monkey-patches window functions like CSSStyleSheet.insertRule; errors from external callers\n // (e.g. styled-components) must be re-thrown so they aren't silently swallowed.\n if (typedError._external_) {\n throw typedError;\n }\n this.loggerProvider.warn(errorLogPrefix, typedError.toString());\n // Return true so that we don't clutter user's consoles with internal rrweb errors\n return true;\n },\n };\n }\n\n private _recordEventsInChildMode(\n recordFunction: RecordFunction,\n sessionId: string | number,\n config: SessionReplayJoinedConfig,\n hooks: { mouseInteraction?: any; scroll?: scrollCallback },\n ) {\n // In child mode, rrweb detects window.parent !== window and routes events via\n // postMessage to the parent instead of calling emit. The emit callback is unused.\n // Note: recording plugins (URL tracking, console capture) are intentionally omitted\n // here — the child's events are merged into the parent stream, so URL changes inside\n // the iframe should not be recorded as parent page-view events.\n try {\n // Stop only the previous rrweb recording. Do NOT call stopRecordingEvents() here:\n // that would clear crossOriginParentSignalCleanup — the very listener that invoked\n // this method — making the child permanently deaf to subsequent stop/start cycles.\n this.recordCancelCallback && this.recordCancelCallback();\n this.recordCancelCallback = null;\n this.recordCancelCallback = recordFunction({\n ...this.buildRRWebRecordOptions(\n config,\n hooks,\n () => {\n // no-op: child events are forwarded to parent via postMessage by rrweb\n },\n 'Error while capturing replay (child iframe): ',\n ),\n recordCrossOriginIframes: true, // child mode is only entered when crossOriginIframes.enabled is true\n });\n this.loggerProvider.log(`Session Replay child iframe capture beginning for session ${sessionId}.`);\n } catch (error) {\n this.loggerProvider.warn('Failed to initialize session replay in child iframe mode:', error);\n }\n }\n\n addCustomRRWebEvent = async (\n eventName: CustomRRwebEvent,\n eventData: { [key: string]: any } = {},\n addStorageInfo = true,\n ) => {\n try {\n let debugInfo: DebugInfo | undefined = undefined;\n const config = this.config;\n // Only add debug info for non-metadata events\n if (config && eventName !== CustomRRwebEvent.METADATA) {\n debugInfo = {\n config: getDebugConfig(config),\n version: VERSION,\n };\n if (addStorageInfo) {\n const storageSizeData = await getStorageSize();\n debugInfo = {\n ...storageSizeData,\n ...debugInfo,\n };\n }\n }\n // Check first to ensure we are recording\n if (this.recordCancelCallback && this.recordFunction) {\n this.recordFunction.addCustomEvent(eventName, {\n ...eventData,\n ...debugInfo,\n });\n } else {\n this.loggerProvider.debug(\n `Not able to add custom replay capture event ${eventName} due to no ongoing recording.`,\n );\n }\n } catch (e) {\n this.loggerProvider.debug('Error while adding custom replay capture event: ', e);\n }\n };\n\n stopRecordingEvents = () => {\n try {\n this.loggerProvider.log('Session Replay capture stopping.');\n this.recordCancelCallback && this.recordCancelCallback();\n this.recordCancelCallback = null;\n this.networkObservers?.stop();\n this.crossOriginIframeCoordinator?.stop();\n this.crossOriginIframeCoordinator = null;\n // Remove the child-mode parent signal listener so a later mode change\n // (e.g. crossOriginIframes disabled) does not leave a stale listener.\n this.crossOriginParentSignalCleanup?.();\n this.crossOriginParentSignalCleanup = null;\n } catch (error) {\n const typedError = error as Error;\n this.loggerProvider.warn(`Error occurred while stopping replay capture: ${typedError.toString()}`);\n }\n };\n\n getDeviceId() {\n return this.identifiers?.deviceId;\n }\n\n getSessionId() {\n return this.identifiers?.sessionId;\n }\n\n async flush(useRetry = false) {\n // Intentionally not gated on min_session_duration_ms. flush() forwards payloads\n // already queued in trackDestination, and every code path that queues into it —\n // sendCurrentSequenceEvents, addEvent's batch-split path, sendStoredEvents reading\n // sequencesToSend from IDB — has already passed the gate at the time of queuing.\n // A duplicate gate here would be unreachable.\n return this.eventsManager?.flush(useRetry);\n }\n\n shutdown() {\n this.urlChangeCleanup?.();\n this.crossOriginParentSignalCleanup?.();\n this.crossOriginParentSignalCleanup = null;\n this.teardownEventListeners(true);\n this.stopRecordingEvents();\n this.sendEvents();\n }\n\n private mapSDKType(sdkType: string | undefined) {\n if (sdkType === 'plugin') {\n return '@amplitude/plugin-session-replay-browser';\n }\n\n if (sdkType === 'segment') {\n return '@amplitude/segment-session-replay-plugin';\n }\n\n return null;\n }\n\n private setMetadata(\n sessionId: string | number | undefined,\n joinedConfig: SessionReplayJoinedConfig,\n localConfig: SessionReplayLocalConfig,\n remoteConfig: SessionReplayRemoteConfig | undefined,\n replaySDKVersion: string | undefined,\n standaloneSDKVersion: string | undefined,\n sdkType: string | undefined,\n ) {\n const hashValue = sessionId?.toString() ? generateHashCode(sessionId.toString()) : undefined;\n\n this.metadata = {\n joinedConfig,\n localConfig,\n remoteConfig,\n sessionId,\n hashValue,\n sampleRate: joinedConfig.sampleRate,\n replaySDKType: this.mapSDKType(sdkType),\n replaySDKVersion,\n standaloneSDKType: '@amplitude/session-replay-browser',\n standaloneSDKVersion,\n };\n }\n\n private async initializeNetworkObservers(): Promise<void> {\n if (this.config?.loggingConfig?.network?.enabled && !this.networkObservers) {\n try {\n const { NetworkObservers: NetworkObserversClass } = await import('./observers');\n this.networkObservers = new NetworkObserversClass();\n } catch (error) {\n this.loggerProvider.warn('Failed to import or instantiate NetworkObservers:', error);\n }\n }\n }\n}\n","import type { TargetingParameters } from '@amplitude/targeting';\nimport { TargetingConfig } from '../config/types';\nimport { Logger } from '@amplitude/analytics-types';\nimport { IDiagnosticsClient } from '@amplitude/analytics-core';\nimport { SessionReplayTargetingInput } from '../typings/session-replay';\nimport { targetingIDBStore } from './targeting-idb-store';\nimport { SrDiagnostic } from '../diagnostics';\n\nexport const evaluateTargetingAndStore = async ({\n sessionId,\n targetingConfig,\n loggerProvider,\n apiKey,\n targetingParams,\n urlChange = false,\n diagnosticsClient,\n deviceId,\n}: {\n sessionId: string | number;\n targetingConfig: TargetingConfig;\n loggerProvider: Logger;\n apiKey: string;\n targetingParams?: SessionReplayTargetingInput;\n urlChange?: boolean;\n diagnosticsClient?: IDiagnosticsClient;\n deviceId?: string;\n}) => {\n await targetingIDBStore.clearStoreOfOldSessions({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n currentSessionId: sessionId,\n });\n\n const idbTargetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n sessionId: sessionId,\n });\n\n // Skip IDB cache when re-evaluating with a new page (e.g. URL change); otherwise we'd never\n // re-evaluate and would keep returning true after navigating to a non-matching page.\n if (idbTargetingMatch === true && !urlChange) {\n return true;\n }\n\n // If the targeting config is undefined or an empty object,\n // assume the response was valid but no conditions were set,\n // so all users match targeting\n let sessionTargetingMatch = true;\n try {\n // Dynamic import of the targeting package\n const { evaluateTargeting: evaluateTargetingPackage } = await import('@amplitude/targeting');\n\n const params: TargetingParameters = {\n ...targetingParams,\n flag: targetingConfig,\n sessionId: typeof sessionId === 'string' ? parseInt(sessionId, 10) : sessionId,\n apiKey: apiKey,\n loggerProvider: loggerProvider,\n };\n diagnosticsClient?.recordEvent(SrDiagnostic.targetingTrigger, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n matched: sessionTargetingMatch,\n targetingConfig: targetingConfig,\n });\n const targetingResult = await evaluateTargetingPackage(params);\n if (targetingResult && targetingResult.sr_targeting_config) {\n sessionTargetingMatch = targetingResult.sr_targeting_config.key === 'on';\n }\n // gap #2: the raw engine verdict. variantKey 'on' => matched; 'off'/undefined => not.\n // Pair with the eval event's pageUrl to tell \"URL condition didn't match\" from \"URL matched\n // but the segment bucket (capture %) didn't allocate this session\".\n try {\n diagnosticsClient?.recordEvent(SrDiagnostic.evalResult, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n variantKey: targetingResult?.sr_targeting_config?.key ?? null,\n matched: sessionTargetingMatch,\n targetingConfig: targetingConfig,\n });\n // Flush now so the verdict ships immediately (vs the client's ~5-min timer). One capture\n // POST per event — higher volume; revisit/gate before production.\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n\n void targetingIDBStore.storeTargetingMatchForSession({\n loggerProvider: loggerProvider,\n apiKey: apiKey,\n sessionId: sessionId,\n targetingMatch: sessionTargetingMatch,\n });\n } catch (err: unknown) {\n const knownError = err as Error;\n // Q3 \"is the TRC failing?\": the targeting engine threw — record it so the team sees TRC\n // errors in DataDog (this exception is otherwise swallowed). Best-effort, never re-throws.\n try {\n diagnosticsClient?.increment(SrDiagnostic.evalError);\n diagnosticsClient?.recordEvent(SrDiagnostic.evalError, {\n sessionId,\n deviceId,\n srId: deviceId != null && sessionId != null ? `${deviceId}/${sessionId}` : undefined,\n pageUrl: targetingParams?.page?.url,\n message: knownError.message,\n });\n void diagnosticsClient?._flush?.();\n } catch {\n // diagnostics is best-effort\n }\n loggerProvider.warn(knownError.message);\n }\n return sessionTargetingMatch;\n};\n","import { AnalyticsConnector } from '@amplitude/analytics-connector';\nimport { DEFAULT_INSTANCE_NAME } from './types/constants';\nexport var getAnalyticsConnector = function (instanceName) {\n if (instanceName === void 0) { instanceName = DEFAULT_INSTANCE_NAME; }\n return AnalyticsConnector.getInstance(instanceName);\n};\nexport var setConnectorUserId = function (userId, instanceName) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n getAnalyticsConnector(instanceName).identityStore.editIdentity().setUserId(userId).commit();\n};\nexport var setConnectorDeviceId = function (deviceId, instanceName) {\n getAnalyticsConnector(instanceName).identityStore.editIdentity().setDeviceId(deviceId).commit();\n};\n//# sourceMappingURL=analytics-connector.js.map","import { debugWrapper, LogConfig } from '@amplitude/analytics-core';\nimport { getDefaultConfig } from './config/local-config';\nimport { SessionReplay } from './session-replay';\nimport { AmplitudeSessionReplay } from './typings/session-replay';\n\nexport const getLogConfig = (sessionReplay: SessionReplay) => (): LogConfig => {\n const { config } = sessionReplay;\n const { loggerProvider: logger, logLevel } = config || getDefaultConfig();\n return {\n logger,\n logLevel,\n };\n};\n\nconst createInstance: () => AmplitudeSessionReplay = () => {\n const sessionReplay = new SessionReplay();\n return {\n init: debugWrapper(sessionReplay.init.bind(sessionReplay), 'init', getLogConfig(sessionReplay)),\n evaluateTargetingAndCapture: debugWrapper(\n sessionReplay.evaluateTargetingAndCapture.bind(sessionReplay),\n 'evaluateTargetingAndRecord',\n getLogConfig(sessionReplay),\n ),\n setSessionId: debugWrapper(\n sessionReplay.setSessionId.bind(sessionReplay),\n 'setSessionId',\n getLogConfig(sessionReplay),\n ),\n getSessionId: debugWrapper(\n sessionReplay.getSessionId.bind(sessionReplay),\n 'getSessionId',\n getLogConfig(sessionReplay),\n ),\n getSessionReplayProperties: debugWrapper(\n sessionReplay.getSessionReplayProperties.bind(sessionReplay),\n 'getSessionReplayProperties',\n getLogConfig(sessionReplay),\n ),\n flush: debugWrapper(sessionReplay.flush.bind(sessionReplay), 'flush', getLogConfig(sessionReplay)),\n shutdown: debugWrapper(sessionReplay.shutdown.bind(sessionReplay), 'shutdown', getLogConfig(sessionReplay)),\n };\n};\n\nexport default createInstance();\n","import sessionReplay from './session-replay-factory';\nexport const {\n init,\n setSessionId,\n getSessionId,\n getSessionReplayProperties,\n flush,\n shutdown,\n evaluateTargetingAndCapture,\n} = sessionReplay;\nexport { SessionReplayOptions, StoreType } from './typings/session-replay';\nexport { SafeLoggerProvider } from './logger';\nexport { AmplitudeSessionReplay } from './typings/session-replay';\n"],"names":["IdentifyOperation","SpecialEventType","Status","DEFAULT_INSTANCE_NAME","AMPLITUDE_SERVER_URL","LogLevel","getGlobalScope","ampIntegrationContextName","globalThis","window","self","global","hex","__spreadArray","__read","Array","keys","map","index","toString","padStart","UUID","a","_a","globalScope","crypto","getRandomValues","Math","random","String","replace","legacyUUID","r","Uint8Array","entries","_b","int","includes","concat","join","returnWrapper","awaitable","promise","Promise","resolve","PREFIX","Logger","this","logLevel","None","prototype","disable","enable","Warn","log","args","_i","arguments","length","Verbose","console","warn","error","Error","debug","Debug","getDefaultConfig","flushMaxRetries","flushQueueSize","flushIntervalMillis","instanceName","loggerProvider","offline","optOut","serverUrl","serverZone","useBatch","Config","options","_c","_d","_optOut","defaultConfig","apiKey","minIdLength","plan","ingestionMetadata","undefined","storageProvider","transportProvider","serverConfig","createServerConfig","Object","defineProperty","get","set","enumerable","configurable","getServerUrl","_serverZone","debugWrapper","fn","fnName","getLogConfig","getStates","fnContext","logger","apply","ignoreDepth","debugContext","type","name","stacktrace","stack","split","slice","text","trim","time","start","Date","toISOString","states","before","result","then","after","end","JSON","stringify","ApplicationContextProviderImpl","getApplicationContext","versionName","language","getLanguage","platform","os","deviceModel","navigator","languages","EventBridgeImpl","queue","logEvent","event","receiver","push","setEventReceiver","forEach","__assign","assign","t","s","i","n","p","hasOwnProperty","call","__values","o","Symbol","iterator","m","next","value","done","TypeError","e","ar","SuppressedError","isEqual","obj1","obj2","e_1","typeA","primitive_1","primitive_1_1","e_1_1","return","isArrayA","isArray","isArrayB","sorted1","sort","sorted2","result_1","key","obj","ownProps","resArray","ServerZone","IdentityStoreImpl","identity","userProperties","listeners","Set","editIdentity","actingUserProperties","actingIdentity","setUserId","userId","setDeviceId","deviceId","setUserProperties","setOptOut","updateUserProperties","actions","e_2","e_3","actingProperties","_e","_f","action","properties","_g","_h","_j","e_2_1","_k","_l","e_3_1","commit","setIdentity","getIdentity","originalIdentity","listener","addIdentityListener","add","removeIdentityListener","delete","safeGlobal","AnalyticsConnector","identityStore","eventBridge","applicationContextProvider","getInstance","generateHashCode","str","hash","charCodeAt","isTimestampInSampleTemp","timestamp","sampleRate","hashNumber","abs","TABLE_NAMES","INTERNAL_KEYS","DiagnosticsStorage","dbPromise","dbName","substring","isSupported","indexedDB","getDB","__awaiter","__generator","openDB","_this","reject","request","open","onerror","onsuccess","db","onclose","close","onupgradeneeded","target","createTables","objectStoreNames","contains","createObjectStore","keyPath","autoIncrement","createIndex","unique","setTags","tags","transaction_1","store_1","error_1","label","trys","sent","transaction","objectStore","oncomplete","onabort","put","incrementCounters","counters","transaction_2","store_2","error_2","incrementValue","getRequest","existingRecord","existingValue","setHistogramStats","histogramStats","transaction_3","store_3","error_3","newStats","updatedStats","count","min","max","sum","addEventRecords","events","transaction_4","store_4","error_4","countRequest","currentCount","availableSlots","setInternal","transaction_5","store_5","error_5","getInternal","transaction_6","store_6","error_6","getLastFlushTimestamp","record","error_7","parseInt","setLastFlushTimestamp","error_8","clearTable","tableName","clear","getAllAndClear","error_9","all","getAllFromStore","getAll","detectSdkOrigin","payload","normalizedScriptUrls","scope","getNormalizedScriptUrls","normalizedScriptUrls_1","normalizedScriptUrls_1_1","normalizedScriptUrl","filename","extractFilenameFromStack","match","stringifyReason","reason","FLUSH_INTERVAL_MS","MAX_MEMORY_STORAGE_COUNT","DiagnosticsClient","inMemoryTags","inMemoryCounters","inMemoryHistograms","inMemoryEvents","saveTimer","flushTimer","config","enabled","startTimestamp","now","shouldTrack","storage","initializeFlushInterval","increment","client","addEventListener","capture","context","recordEvent","message","error_name","errorName","metadata","colno","lineno","isTrusted","matchReason","enableSdkErrorListeners","isStorageAndTrackEnabled","Boolean","setTag","startTimersIfNeeded","size","recordHistogram","existing","event_name","event_properties","setTimeout","saveAllDataToStorage","catch","finally","_flush","tagsToSave","countersToSave","histogramsToSave","eventsToSave","tagRecords","counterRecords","histogramStatsRecords","eventRecords","histogram","stats","avg","round","fetch","method","headers","body","ok","lastFlushTimestamp","timeSinceLastFlush","_setFlushTimer","delay","_setSampleRate","BaseTransport","send","_serverUrl","_payload","_enableRequestBodyCompression","buildResponse","responseJSON","_m","_o","_p","_q","_r","_s","_t","_u","_v","_w","_x","statusCode","code","status","buildStatus","Success","eventsIngested","events_ingested","payloadSizeBytes","payload_size_bytes","serverUploadTime","server_upload_time","Invalid","missingField","missing_field","eventsWithInvalidFields","events_with_invalid_fields","eventsWithMissingFields","events_with_missing_fields","eventsWithInvalidIdLengths","events_with_invalid_id_lengths","epsThreshold","eps_threshold","exceededDailyQuotaDevices","exceeded_daily_quota_devices","silencedDevices","silenced_devices","silencedEvents","silenced_events","throttledDevices","throttled_devices","throttledEvents","throttled_events","PayloadTooLarge","RateLimit","throttledUsers","throttled_users","exceededDailyQuotaUsers","exceeded_daily_quota_users","Timeout","isSuccessStatusCode","Failed","Unknown","FetchTransport","_super","customHeaders","__extends","response","responseText","Accept","parse","RemoteConfigLocalStorage","fetchConfig","failedRemoteConfigInfo","remoteConfig","lastFetch","localStorage","getItem","remoteConfigInfo","removeItem","setConfig","setItem","CODE_STATUS","RemoteConfigClient","callbackInfos","lastSuccessfulFetch","fetchPromise","isLastFetchInvalidApiKey","subscribe","deliveryMode","callback","id","callbackInfo","subscribeAll","subscribeWaitForRemote","timeout","unsubscribe","findIndex","splice","updateConfigs","getOrCreateFetchPromise","sendCallback","remotePromise","cachePromise","race","timeoutPromise","_","source","filteredConfig","lastCallback","reduce","retries","interval","_loop_1","this_1","attempt","state_1","shouldRetry","abortController","timeoutId","res","AbortController","abort","getUrlParams","signal","json","clearTimeout","getJitterDelay","baseDelay","floor","encodedApiKey","encodeURIComponent","urlParams","URLSearchParams","append","CONFIG_GROUP","AMPLITUDE_ORIGIN","AMPLITUDE_ORIGINS_MAP","US","EU","STAGING","MESSENGER_BRAND","MESSENGER_GLOBAL_KEY","BaseWindowMessenger","origin","isSetup","messageHandler","requestCallbacks","actionHandlers","Map","pendingMessages","scriptLoadPromises","endpoint","notify","opener","postMessage","sendRequest","substr","handleResponse","responseData","registerActionHandler","handler","has","queued","queued_1","queued_1_1","loadScriptOnce","url","loadPromise","document","querySelector","CSS","escape","scriptElement","createElement","async","src","once","head","appendChild","asyncLoadScript","setup","eventData","data","destroy","removeEventListener","getOrCreateWindowMessenger","messenger","BG_CAPTURE_BRAND","DEFAULT_EVENT_PROPERTY_PREFIX","DEFAULT_SESSION_REPLAY_PROPERTY","DEFAULT_SERVER_ZONE","DEFAULT_PERFORMANCE_CONFIG","DEFAULT_URL_CHANGE_POLLING_INTERVAL","SESSION_REPLAY_DEBUG_PROPERTY","MASK_TEXT_CLASS","UNMASK_TEXT_CLASS","SESSION_REPLAY_SERVER_URL","SESSION_REPLAY_EU_URL","SESSION_REPLAY_STAGING_URL","MAX_SINGLE_EVENT_SIZE","WAF_PAYLOAD_TOO_LARGE_PATTERN","MIN_INTERVAL","MAX_INTERVAL","KB_SIZE","CROSS_ORIGIN_IFRAME_MESSAGE_TYPE","CustomRRwebEvent","SafeLoggerProvider","constructor","getSafeMethod","__rrweb_original__","bind","DEFAULT_MASK_LEVEL","trackServerUrl","isMaskedForLevel","elementType","level","element","inputType","hasAttribute","toLowerCase","getInputType","autocomplete","startsWith","getEffectiveMaskLevel","urlMaskLevels","rule","globToRegex","test","maskLevel","defaultMaskLevel","isMasked","currentUrl","closest","shouldMask","maskSelector","some","selector","shouldUnmask","unmaskSelector","maskFn","getCurrentUrl","maskAttributeFn","maskAttributes","tagName","location","href","globRegexCache","glob","cached","T_TRAILING","T_MIDDLE","T_DSTAR","T_STAR","T_QUEST","regex","RegExp","getPageUrl","pageUrl","ugcFilterRules","replacement","getStorageSize","usage","quota","usageDetails","estimate","totalStorageSize","percentOfQuota","Number","EPSILON","getDebugConfig","debugConfig","SessionReplayLocalConfig","super","configServerUrl","shouldInlineStylesheet","version","performanceConfig","storeType","applyBackgroundColorToBlockedElements","enableUrlChangePolling","urlChangePollingInterval","captureDocumentTitle","fullSnapshotIntervalMs","eagerFullSnapshotSend","captureFullSnapshotOnFocus","maxPersistedEventsSizeBytes","sanitizeByteSize","MIN_EVENT_BYTE_SIZE","MAX_PERSISTED_EVENTS_SIZE_CEILING","maxSingleEventSizeBytes","MAX_SINGLE_EVENT_SIZE_CEILING","privacyConfig","from","interactionConfig","every","isValidGlobUrl","globUrl","validateUGCFilterRules","debugMode","legacyOptions","useWebWorker","experimental","enableTransportCompression","sendTimeoutMs","captureAdoptedStyleSheets","crossOriginIframes","flushIntervalConfig","raw","sanitized","minIntervalMs","isFinite","MIN_FLUSH_INTERVAL_FLOOR_MS","maxIntervalMs","isNaN","effectiveMin","effectiveMax","sanitizeFlushIntervalConfig","diagnosticsEnabled","diagnosticsSampleRate","diagnosticsClient","createStandaloneDiagnosticsClient","EventType","EventType2","IncrementalSource","IncrementalSource2","MouseInteractions","MouseInteractions2","SrDiagnostic","init","sessionChanged","configSource","configHasTargeting","configNoTargeting","configFetchFailed","configReceived","targetingTrigger","evalTrigger","trigger","evalNoConfig","evalMissingPrereq","evalMatch","evalNoMatch","evalError","evalStaleDiscarded","evalSkippedAlreadyMatched","evalDurationMs","evalEvent","evalResult","recordStarted","recordNoRecordFn","sendSuppressedMinDuration","gateNoIdentifiers","gateCaptureDisabled","gateOptOut","gateTrcMatch","gateTrcNoMatch","gateSampleIn","gateSampleOut","decision","urlChange","urlChangeEvent","urlListenerSetup","urlListenerAttached","urlListenerSkipped","urlPollTick","urlPollFirstTick","SessionReplayJoinedConfigGenerator","remoteConfigClient","localConfig","sessionId","generateJoinedConfig","sessionReplayRemoteConfig","captureEnabled","namespaceConfig","samplingConfig","sr_sampling_config","sr_privacy_config","targetingConfig","sr_targeting_config","samplingForLog","targetingSegments","segments","sr_interaction_config","loggingConfig","sr_logging_config","srId","hasSampling","capture_enabled","sample_rate","hasTargeting","targetingSegmentCount","hasPrivacy","joinedConfig","remotePrivacyConfig","minSessionDurationMs","sanitizeMinSessionDurationMs","min_session_duration_ms","localPrivacyConfig","joinedPrivacyConfig","blockSelector","privacyConfigSelectorMap","selectorMap","selectorType","fragment","createDocumentFragment","dropInvalidSelectors","selectors","filter","removeInvalidSelectorsFromPrivacyConfig","MAX_MIN_SESSION_DURATION_MS","isMergeableMutation","IncrementalSnapshot","Mutation","isAttachIframe","mergeStyleDiffs","diffs","merged","diff","prop","coalesceStyleAttributes","attributes","styleIndicesById","attr","list","styleValueAt","style","dropStyleAt","mergedStyleByIndex","indices","values","lastResetPos","idx","pos","survivingObjectIndices","lastObjectIdx","mergedStyle","rest","mergeGroup","first","firstAddEventIndex","lastAddEventIndex","firstRemoveEventIndex","lastRemoveEventIndex","lastParentById","adds","node","parentId","remove","removes","transientIds","preExistingTransientIds","firstAddIdx","firstRemoveIdx","cascadeDropAddsOnlyIds","changed","nodeId","nodeFirstRemoveIdx","nodeFirstAddIdx","needsFilter","filteredRemoves","eventIdx","allAdds","flatMap","allTexts","texts","allAttributes","mergedAttributes","mergeMutationEvents","j","EventCompressor","eventsManager","workerScript","onFullSnapshotProcessed","taskQueue","pendingQueue","isProcessing","compressEvent","addCompressedEventToManager","compressedEvent","eventSizeBytes","Blob","addEvent","addCompressedEvent","worker","err","flushQueue","mergeMutationTasks","task","shift","compressed","terminate","canUseIdleCallback","blob","blobUrl","URL","createObjectURL","Worker","preventDefault","onmessage","scheduleIdleProcessing","requestIdleCallback","idleDeadline","processQueue","enqueueEvent","RRWebEventType","FullSnapshot","allTasks","timeRemaining","didTimeout","tasks","mergeMutations","MAX_RETRIES_EXCEEDED_MESSAGE","STORAGE_FAILURE","SESSION_KILLED_MESSAGE","VERSION","SessionReplayTrackDestination","payloadBatcher","storageKey","retryTimeout","scheduled","sendIdCounter","pendingWorkerRequests","timedOutWorkerRequests","flushPauseUntilMs","mergeOnNextFlush","coalesceNextFlush","mergeLogFiredThisPause","killedSessions","pending","msg","handlePayloadTooLargeResponse","isWaf","timedOut","skipCode","applyServerDirective","completeRequest","sendEventsList","destinationData","addToQueue","attempts","markCoalesceNextFlush","schedule","sendBeacon","byteLength","trimmedEvents","lo","hi","mid","device_id","session_id","api_key","payloadBlob","pauseRemaining","effectiveTimeout","flush","useRetry","mergeQueueAfterThrottle","mergeDrainBacklog","coalesceByIdentity","groups","ctx","arr","group","current","currentBytes","flushCurrent","ctxBytes","prevOnComplete","onComplete","ctxOnComplete","allSettled","sendViaWorker","sendOnMainThread","rememberTimedOutRequest","eventType","sdkVersion","oldest","sessionReplayLibrary","payloadJson","gzipped","jsonStr","stream","CS","CompressionStream","writer","writable","getWriter","reader","readable","getReader","chunks","readPromise","read","write","TextEncoder","encode","totalLength","c","offset","chunk","gzipJson","payloadSize","controller","Authorization","keepalive","sendTimeout","responseBody","handleReponse","success","handleOtherResponse","handleSuccessResponse","totalSizeKB","noop","sizeOfEventsList","wasInPause","killSession","remaining","BaseEventsStore","timeAtLastSplit","_timeAtLastSplit","minInterval","maxInterval","maxPersistedEventsSize","shouldSplitEventsList","nextEventString","sizeOfNextEvent","getStringSize","getEventsArraySize","bytes","NaN","totalSize","logIdbError","currentSequenceKey","sequencesToSendKey","TX_DONE_TIMEOUT_MS","armTxDoneTimeout","txDone","ms","onTimeout","timer","defineObjectStores","sequencesStore","currentSequenceStore","createStore","v","withTimeout","upgrade","SessionReplayEventsIDBStore","maybeLogEmptyFiltered","emptyFilteredCount","consecutiveFailures","hasTriggeredFallback","getSequencesToSend","errorLogged","sequences","tx","recordFailure","cancelTimeout","cursor","store","openCursor","sequenceId","continue","recordSuccess","storeCurrentSequence","currentSequenceData","tabId","_tabId","__rest","addEventToCurrentSequence","sequenceEvents","ownedSequence","eventsToSend","storeSendingEvents","cleanUpSessionEventsStore","_sessionId","onPersistentFailure","consecutiveFailureThreshold","dbSuffix","randomUUID","generateUUID","getCurrentSequenceEvents","allEvents","InMemoryEventsStore","finalizedSequences","resetCurrentSequence","addSequence","buffered","sequenceReturn","createEventsManager","trackDestinationWorkerScript","shouldSend","maxSingleEventSize","trackDestination","getMemoryStore","lastKnownDeviceId","usingIdbStore","idb","new","seq","beaconBuffer","beaconWindowStart","advanceBeaconWindow","upToAbsoluteIdx","trimCount","rawEvents","sizedEvents","oversized","sendCurrentSequenceEvents","snapshotAbsIdx","currentSequence","canSend","absIdx","sequenceToSend","sendStoredEvents","sequencesToSend","sequence","getBeaconEvents","dropPendingBeaconEvents","MultiEventManager","managers","managersMap","manager","opts","promises","rootDocument","finder","input","nodeType","Node","ELEMENT_NODE","defaults","root","idName","_name","className","_value","seedMinLength","optimizedMinLength","threshold","maxNumberOfTries","timeoutMs","rootNode","DOCUMENT_NODE","ownerDocument","findRootDocument","path","bottomUpSearch","optimized","optimize","limit","fallback","elapsedTime","getTime","maybe","classNames","any","nth","dispensableNth","nthChild","findUniquePath","parentElement","paths","combinations","candidate","query","penalty","acc","css","querySelectorAll","elementId","getAttribute","attrs","classList","parent","parentNode","child","firstChild","nextSibling","notEmpty","b","counter","visited","newPath","newPathKey","same","clickNonBatcher","clickEvents","evt","clickBatcher","reduced","prev","curr","x","y","hour","k","ClickHandler","scrollWatcher","createHook","deviceIdFn","mirror","performanceOptions","Click","innerHeight","innerWidth","getNode","currentScrollX","currentScrollY","viewportHeight","viewportWidth","getViewportHeight","documentElement","clientHeight","getViewportWidth","clientWidth","BeaconTransport","sendXhr","xhr","XMLHttpRequest","setRequestHeader","basePageUrl","ScrollWatcher","transport","hook","update","scrollX","scrollY","maxScrollX","_maxScrollX","maxScrollY","_maxScrollY","maxScrollWidth","_maxScrollWidth","maxScrollHeight","_maxScrollHeight","_currentScrollX","_currentScrollY","width","height","SessionIdentifiers","sessionReplayId","generateSessionReplayId","REPLAY_START_TIME_TTL_MS","buildKeyPrefix","buildKey","getLocalStorage","targetingIDBStore","dbs","openOrCreateDB","getTargetingMatchForSession","sessionIdStr","targetingMatchForSession","targetingMatch","storeTargetingMatchForSession","lastUpdated","clearStoreOfOldSessions","currentSessionId","currentSessionIdStr","allTargetingMatchObjs","targetingMatchObj","amountOfTimeSinceSession","PRIME32_1","PRIME32_2","PRIME32_3","PRIME32_5","rotl32","imul","readU32","xxHash32","seed","toUTF8Bytes","len","h32","v1","v2","v3","v4","PATCH_MARKER","urlChangeSubscriptionsByScope","WeakMap","subscribeToUrlChanges","onUrlChange","enablePolling","pollingInterval","onPoll","getHref","lastHref","setInterval","clearInterval","subscriptionState","callbacks","createHistoryMethodPatch","originalMethod","patchedMethod","history","pushState","Reflect","replaceState","onPopStateOrHashChange","listenersAttached","state","createUrlTrackingPlugin","observer","cb","pluginOptions","lastTrackedUrl","emitUrlChange","currentTitle","title","createUrlChangeEvent","CrossOriginIframeCoordinator","pendingLoadListeners","mutationObserver","disconnect","sendToAllIframes","MutationObserver","mutations","mutation","addedNodes","HTMLIFrameElement","sendToIframeAfterLoad","Element","iframe","removedNodes","observe","childList","subtree","stop","sendStart","sendToIframe","contentWindow","SessionReplay","recordCancelCallback","eventCount","sessionTargetingMatch","trcDiagnosticSessionId","pageLeaveFns","suppressedSendCount","hasEmittedGateDecision","recordFunction","recordEventsInFlight","pendingEmitEvents","currentPageUrl","recordEventsPendingShouldLogMetadata","urlChangeCleanup","urlPollFirstTickRecorded","crossOriginIframeCoordinator","crossOriginParentSignalCleanup","latestUrlChangeTargetingEvaluationId","teardownEventListeners","teardown","blurListener","focusListener","pageLeaveListener","sendEvents","takeFullSnapshot","recordEvents","eventCompressor","evaluateTargetingAndCapture","targetingParams","isInit","forceRestart","forceTargetingReevaluation","incrementDiagnostic","identifiers","recordDiagnosticEvent","hasIdentifiers","hasSessionId","hasConfig","hasDeviceId","getDeviceId","lastTargetingParams","urlChangeEvaluationId","eventForTargeting","event_type","page","pageForTargeting","evalStart","evaluateTargeting","evaluateTargetingPackage","import","params","flag","matched","targetingResult","variantKey","knownError","evaluateTargetingAndStore","recordDiagnosticHistogram","evaluationId","latestEvaluationId","hasEvent","userPropertyKeys","initialize","addCustomRRWebEvent","eventName","addStorageInfo","debugInfo","METADATA","storageSizeData","addCustomEvent","stopRecordingEvents","networkObservers","typedError","_init","setupUrlChangeListener","alreadyMatched","isBelowMinSessionDuration","sessionStartTime","getCurrentPageForTargeting","getNavigationType","performance","getEntriesByType","navEntries","prefix","stale","parsed","pruneStaleReplayStartTimes","getOrInitReplayStartTime","joinedConfigGenerator","createSessionReplayJoinedConfigGenerator","setMetadata","default","scrollHook","clickHandler","compressionWorkerScript","compressionScript","trackDestinationScript","rrwebEventManager","batch","interactionEventManager","trackEveryNms","initializeNetworkObservers","branded","scriptUrl","backgroundCaptureInstance","onBackgroundCapture","backgroundCaptureData","resolvedUrl","amplitudeBackgroundCapture","enableBackgroundCapture","hasTargetingConfig","shouldOptOut","navigationType","needsUrlTracking","setSessionId","asyncSetSessionId","previousSessionId","currentDeviceId","lastShouldRecordDecision","isSessionChange","to","deviceIdChanged","deviceIdForReplayId","startTime","setReplayStartTime","removeReplayStartTime","getSessionReplayProperties","shouldRecord","getShouldRecord","eventProperties","appHash","GET_SR_PROPS","sessionIdToSend","minMs","elapsedMs","REPLAY_GATE_DECISION","shouldSendStoredEvents","identityStoreOptOut","enriched","recordTrcDecisionDiagnostic","TARGETING_DECISION","getBlockSelectors","getMaskTextSelectors","getRecordingPlugins","plugins","urlTrackingPlugin","getRecordConsolePlugin","levels","getRecordFunction","shouldLogMetadata","_recordEvents","pendingArgs","networkLoggingConfig","network","trackUrl","ignoredUrls","FETCH_REQUEST","hooks","mouseInteraction","interaction","scroll","crossOriginIframesEnabled","coordinateChildren","childMode","isInIframe","parentFrame","onStart","onStop","listenForParentSignals","_recordEventsInChildMode","buildRRWebRecordOptions","Meta","recordCrossOriginIframes","DEBUG_INFO","emit","errorLogPrefix","inlineStylesheet","maskAllInputs","maskTextClass","blockClass","maskInputFn","maskTextFn","maskTextSelector","checkoutEveryNms","recordCanvas","slimDOMOptions","script","comment","headFavicon","headWhitespace","headMetaDescKeywords","headMetaSocial","headMetaRobots","headMetaHttpEquiv","headMetaAuthorship","headMetaVerification","errorHandler","_external_","getSessionId","shutdown","mapSDKType","sdkType","replaySDKVersion","standaloneSDKVersion","hashValue","replaySDKType","standaloneSDKType","NetworkObservers","NetworkObserversClass","sessionReplay","createInstance"],"mappings":"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"}
|