{"version":3,"file":"static/js/session-manager.1afc2b84.chunk.js","mappings":"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","sources":["../../../../../../../../../tmp/mct/frontend/node_modules/@newrelic/browser-agent/dist/esm/common/timer/timer.js","../../../../../../../../../tmp/mct/frontend/node_modules/@newrelic/browser-agent/dist/esm/common/timer/interaction-timer.js","../../../../../../../../../tmp/mct/frontend/node_modules/@newrelic/browser-agent/dist/esm/common/session/session-entity.js","../../../../../../../../../tmp/mct/frontend/node_modules/@newrelic/browser-agent/dist/esm/common/storage/local-storage.js","../../../../../../../../../tmp/mct/frontend/node_modules/@newrelic/browser-agent/dist/esm/features/utils/agent-session.js"],"sourcesContent":["/**\n * Copyright 2020-2025 New Relic, Inc. All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nexport class Timer {\n constructor(opts, ms) {\n if (!opts.onEnd) throw new Error('onEnd handler is required');\n if (!ms) throw new Error('ms duration is required');\n this.onEnd = opts.onEnd;\n this.initialMs = ms;\n this.startTimestamp = Date.now();\n this.timer = this.create(this.onEnd, ms);\n }\n create(cb, ms) {\n if (this.timer) this.clear();\n return setTimeout(() => cb ? cb() : this.onEnd(), ms || this.initialMs);\n }\n clear() {\n clearTimeout(this.timer);\n this.timer = null;\n }\n end() {\n this.clear();\n this.onEnd();\n }\n isValid() {\n return this.initialMs - (Date.now() - this.startTimestamp) > 0;\n }\n}","/**\n * Copyright 2020-2025 New Relic, Inc. All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { Timer } from './timer';\nimport { subscribeToVisibilityChange } from '../window/page-visibility';\nimport { debounce } from '../util/invoke';\nimport { isBrowserScope } from '../constants/runtime';\nexport class InteractionTimer extends Timer {\n constructor(opts, ms) {\n super(opts, ms);\n this.onPause = typeof opts.onPause === 'function' ? opts.onPause : () => {/* noop */};\n this.onRefresh = typeof opts.onRefresh === 'function' ? opts.onRefresh : () => {/* noop */};\n this.onResume = typeof opts.onResume === 'function' ? opts.onResume : () => {/* noop */};\n\n /** used to double-check LS state at resume time */\n this.readStorage = opts.readStorage;\n\n // used by pause/resume\n this.remainingMs = undefined;\n if (!opts.refreshEvents) opts.refreshEvents = ['click', 'keydown', 'scroll'];\n\n // the abort controller is used to \"reset\" the event listeners and prevent them from duplicating when new sessions are created\n try {\n this.abortController = new AbortController();\n } catch (e) {\n // this try-catch can be removed when IE11 is completely unsupported & gone\n }\n if (isBrowserScope && opts.ee) {\n if (opts.ee) {\n this.ee = opts.ee;\n const debouncedRefresh = debounce(this.refresh.bind(this), 500, {\n leading: true\n });\n this.refreshHandler = evts => {\n if (opts.refreshEvents.includes(evts?.[0]?.type)) {\n debouncedRefresh();\n }\n };\n opts.ee.on('fn-end', this.refreshHandler);\n }\n\n // watch for the vis state changing. If the page is hidden, the local inactivity timer should be paused\n // if the page is brought BACK to visibility and the timer hasnt \"naturally\" expired, refresh the timer...\n // this is to support the concept that other tabs could be experiencing activity. The thought would be that\n // \"backgrounded\" tabs would pause, while \"closed\" tabs that \"reopen\" will just instantiate a new SessionEntity class if restored\n // which will do a \"hard\" check of the timestamps.\n\n // NOTE -- this does not account for 2 browser windows open side by side, blurring/focusing between them\n // IF DEEMED necessary, more event handling would be needed to account for this.\n subscribeToVisibilityChange(state => {\n if (state === 'hidden') this.pause();\n // vis change --> visible is treated like a new interaction with the page\n else this.resume();\n }, false, false, this.abortController?.signal);\n }\n }\n abort() {\n this.clear();\n this.abortController?.abort();\n if (this.refreshHandler) {\n this.ee.removeEventListener('fn-end', this.refreshHandler);\n this.refreshHandler = this.ee = null;\n }\n }\n pause() {\n this.onPause();\n clearTimeout(this.timer);\n this.remainingMs = this.initialMs - (Date.now() - this.startTimestamp);\n }\n resume() {\n try {\n const lsData = this.readStorage();\n const obj = typeof lsData === 'string' ? JSON.parse(lsData) : lsData;\n if (isExpired(obj.expiresAt) || isExpired(obj.inactiveAt)) this.end();else {\n this.refresh();\n this.onResume(); // emit resume event after state updated\n }\n } catch (err) {\n this.end();\n }\n function isExpired(timestamp) {\n return Date.now() > timestamp;\n }\n }\n refresh(cb, ms) {\n this.clear();\n this.timer = this.create(cb, ms);\n this.startTimestamp = Date.now();\n this.remainingMs = undefined;\n this.onRefresh();\n }\n}","/**\n * Copyright 2020-2025 New Relic, Inc. All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { generateRandomHexString } from '../ids/unique-id';\nimport { warn } from '../util/console';\nimport { stringify } from '../util/stringify';\nimport { ee } from '../event-emitter/contextual-ee';\nimport { Timer } from '../timer/timer';\nimport { isBrowserScope } from '../constants/runtime';\nimport { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, MODE, PREFIX, SESSION_EVENTS, SESSION_EVENT_TYPES } from './constants';\nimport { InteractionTimer } from '../timer/interaction-timer';\nimport { wrapEvents } from '../wrap/wrap-events';\nimport { getModeledObject } from '../config/configurable';\nimport { handle } from '../event-emitter/handle';\nimport { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants';\nimport { FEATURE_NAMES } from '../../loaders/features/features';\nimport { windowAddEventListener } from '../event-listener/event-listener-opts';\n\n// this is what can be stored in local storage (not enforced but probably should be)\n// these values should sync between local storage and the parent class props\nconst model = {\n value: '',\n inactiveAt: 0,\n expiresAt: 0,\n updatedAt: Date.now(),\n sessionReplayMode: MODE.OFF,\n sessionReplaySentFirstChunk: false,\n sessionTraceMode: MODE.OFF,\n traceHarvestStarted: false,\n serverTimeDiff: null,\n // set by TimeKeeper; \"undefined\" value will not be stringified and stored but \"null\" will\n custom: {}\n};\nexport class SessionEntity {\n /**\n * Create a self-managing Session Entity. This entity is scoped to the agent identifier which triggered it, allowing for multiple simultaneous session objects to exist.\n * There is one \"namespace\" an agent can store data in LS -- NRBA_{key}. If there are two agents on one page, and they both use the same key, they could overwrite each other since they would both use the same namespace in LS by default.\n * The value can be overridden in the constructor, but will default to a unique 16 character hex string\n * expiresMs and inactiveMs are used to \"expire\" the session, but can be overridden in the constructor. Pass 0 to disable expiration timers.\n */\n constructor(opts) {\n const {\n agentIdentifier,\n key,\n storage\n } = opts;\n if (!agentIdentifier || !key || !storage) {\n throw new Error(\"Missing required field(s):\".concat(!agentIdentifier ? ' agentID' : '').concat(!key ? ' key' : '').concat(!storage ? ' storage' : ''));\n }\n this.agentIdentifier = agentIdentifier;\n this.storage = storage;\n this.state = {};\n\n // key is intended to act as the k=v pair\n this.key = key;\n this.ee = ee.get(agentIdentifier);\n wrapEvents(this.ee);\n this.setup(opts);\n\n /**\n * Do not emit session storage events for IE11, because IE11 is unable to determine\n * if the event was spawned on the current page or an adjacent page, and the behavior tied\n * to storage events is critical to apply only to cross-tab behavior\n * */\n if (isBrowserScope) {\n windowAddEventListener('storage', event => {\n if (event.key === this.lookupKey) {\n const obj = typeof event.newValue === 'string' ? JSON.parse(event.newValue) : event.newValue;\n this.sync(obj);\n this.ee.emit(SESSION_EVENTS.UPDATE, [SESSION_EVENT_TYPES.CROSS_TAB, this.state]);\n }\n });\n }\n }\n setup({\n value = generateRandomHexString(16),\n expiresMs = DEFAULT_EXPIRES_MS,\n inactiveMs = DEFAULT_INACTIVE_MS\n }) {\n /** Ensure that certain properties are preserved across a reset if already set */\n const persistentAttributes = {\n serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff\n };\n this.state = {};\n this.sync({\n ...model,\n ...persistentAttributes\n });\n\n // value is intended to act as the primary value of the k=v pair\n this.state.value = value;\n this.expiresMs = expiresMs;\n this.inactiveMs = inactiveMs;\n\n // the first time the session entity class is instantiated, we check the storage API for an existing\n // object. If it exists, the values inside the object are used to inform the timers that run locally.\n // if the initial read is empty, it allows us to set a \"fresh\" \"new\" session immediately.\n // the local timers are used after the session is running to \"expire\" the session, allowing for pausing timers etc.\n // the timestamps stored in the storage API can be checked at initial run, and when the page is restored, otherwise we lean\n // on the local timers to expire the session\n const initialRead = this.read();\n\n // the set-up of the timer used to expire the session \"naturally\" at a certain time\n // this gets ignored if the value is falsy, allowing for session entities that do not expire\n if (expiresMs) {\n this.state.expiresAt = initialRead?.expiresAt || this.getFutureTimestamp(expiresMs);\n this.expiresTimer = new Timer({\n // When the inactive timer ends, collect a SM and reset the session\n onEnd: () => {\n this.collectSM('expired');\n this.collectSM('duration');\n this.reset();\n }\n }, this.state.expiresAt - Date.now());\n } else {\n this.state.expiresAt = Infinity;\n }\n\n // the set-up of the timer used to expire the session due to \"inactivity\" at a certain time\n // this gets ignored if the value is falsy, allowing for session entities that do not expire\n // this gets \"refreshed\" when \"activity\" is observed\n if (inactiveMs) {\n this.state.inactiveAt = initialRead?.inactiveAt || this.getFutureTimestamp(inactiveMs);\n this.inactiveTimer = new InteractionTimer({\n // When the inactive timer ends, collect a SM and reset the session\n onEnd: () => {\n this.collectSM('inactive');\n this.collectSM('duration');\n this.reset();\n },\n // When the inactive timer refreshes, it will update the storage values with an update timestamp\n onRefresh: this.refresh.bind(this),\n onResume: () => {\n this.ee.emit(SESSION_EVENTS.RESUME);\n },\n // When the inactive timer pauses, update the storage values with an update timestamp\n onPause: () => {\n if (this.initialized) this.ee.emit(SESSION_EVENTS.PAUSE);\n this.write(getModeledObject(this.state, model));\n },\n ee: this.ee,\n refreshEvents: ['click', 'keydown', 'scroll'],\n readStorage: () => this.storage.get(this.lookupKey)\n }, this.state.inactiveAt - Date.now());\n } else {\n this.state.inactiveAt = Infinity;\n }\n\n // The fact that the session is \"new\" or pre-existing is used in some places in the agent. Session Replay and Trace\n // can use this info to inform whether to trust a new sampling decision vs continue a previous tracking effort.\n /* [NR-230914] 02/2024 - the logical OR assignment is used so that isNew remains 'true' if it was already set as such. This fixes the expires and inactive timestamps timing out in localStorage\n while no page for a given domain is in-use and the session resetting upon user returning to the page as part of a fresh session. */\n this.isNew ||= !Object.keys(initialRead).length;\n // if its a \"new\" session, we write to storage API with the default values. These values may change over the lifespan of the agent run.\n // we can use a modeled object here to help us know and manage what values are being used. -- see \"model\" above\n if (this.isNew) this.write(getModeledObject(this.state, model), true);else this.sync(initialRead);\n this.initialized = true;\n this.ee.emit(SESSION_EVENTS.STARTED, [this.isNew]);\n }\n\n // This is the actual key appended to the storage API\n get lookupKey() {\n return \"\".concat(PREFIX, \"_\").concat(this.key);\n }\n sync(data) {\n Object.assign(this.state, data);\n }\n\n /**\n * Fetch the stored values from the storage API tied to this entity\n * @returns {Object}\n */\n read() {\n try {\n const val = this.storage.get(this.lookupKey);\n if (!val) return {};\n // TODO - decompression would need to happen here if we decide to do it\n const obj = typeof val === 'string' ? JSON.parse(val) : val;\n if (this.isInvalid(obj)) return {};\n // if the session expires, collect a SM count before resetting\n if (this.isExpired(obj.expiresAt)) {\n this.collectSM('expired');\n this.collectSM('duration', obj, true);\n return this.reset();\n }\n // if \"inactive\" timer is expired at \"read\" time -- esp. initial read -- reset\n // collect a SM count before resetting\n if (this.isExpired(obj.inactiveAt)) {\n this.collectSM('inactive');\n this.collectSM('duration', obj, true);\n return this.reset();\n }\n return obj;\n } catch (e) {\n warn(10, e);\n // storage is inaccessible\n return {};\n }\n }\n\n /**\n * Store data to the storage API tied to this entity\n * To preseve existing attributes, the output of ...session.read()\n * should be appended to the data argument\n * @param {Object} data\n * @returns {Object}\n */\n write(data) {\n try {\n if (!data || typeof data !== 'object') return;\n // everytime we update, we can update a timestamp for sanity\n data.updatedAt = Date.now();\n this.sync(data); // update the parent class \"state\" properties with the local storage values\n //\n // TODO - compression would need happen here if we decide to do it\n this.storage.set(this.lookupKey, stringify(this.state));\n this.ee.emit(SESSION_EVENTS.UPDATE, [SESSION_EVENT_TYPES.SAME_TAB, this.state]);\n return data;\n } catch (e) {\n // storage is inaccessible\n warn(11, e);\n return null;\n }\n }\n reset() {\n // this method should set off a chain of actions across the features by emitting 'new-session'\n // * send off pending payloads\n // * stop recording (stn and sr)...\n // * delete the session and start over\n try {\n if (this.initialized) this.ee.emit(SESSION_EVENTS.RESET);\n this.storage.remove(this.lookupKey);\n this.inactiveTimer?.abort?.();\n this.expiresTimer?.clear?.();\n delete this.isNew;\n this.setup({\n agentIdentifier: this.agentIdentifier,\n key: this.key,\n storage: this.storage,\n expiresMs: this.expiresMs,\n inactiveMs: this.inactiveMs\n });\n return this.read();\n } catch (e) {\n return {};\n }\n }\n\n /**\n * Refresh the inactivity timer data\n */\n refresh() {\n // read here & invalidate\n const existingData = this.read();\n this.write({\n ...existingData,\n inactiveAt: this.getFutureTimestamp(this.inactiveMs)\n });\n }\n\n /**\n * @param {number} timestamp\n * @returns {boolean}\n */\n isExpired(timestamp) {\n return Date.now() > timestamp;\n }\n\n /**\n * @param {Object} data\n * @returns {boolean}\n */\n isInvalid(data) {\n const requiredKeys = Object.keys(model);\n return !requiredKeys.every(x => Object.keys(data).includes(x));\n }\n collectSM(type, data, useUpdatedAt) {\n let value, tag;\n if (type === 'duration') {\n value = this.getDuration(data, useUpdatedAt);\n tag = 'Session/Duration/Ms';\n }\n if (type === 'expired') tag = 'Session/Expired/Seen';\n if (type === 'inactive') tag = 'Session/Inactive/Seen';\n if (tag) handle(SUPPORTABILITY_METRIC_CHANNEL, [tag, value], undefined, FEATURE_NAMES.metrics, this.ee);\n }\n getDuration(data = this.state, useUpdatedAt) {\n const startingTimestamp = data.expiresAt - this.expiresMs;\n const endingTimestamp = !useUpdatedAt ? data.updatedAt : Date.now();\n return endingTimestamp - startingTimestamp;\n }\n\n /**\n * @param {number} futureMs - The number of ms to use to generate a future timestamp\n * @returns {number}\n */\n getFutureTimestamp(futureMs) {\n return Date.now() + futureMs;\n }\n syncCustomAttribute(key, value) {\n if (!isBrowserScope) return;\n if (value === null) {\n const curr = this.read();\n if (curr.custom) {\n delete curr.custom[key];\n this.write({\n ...curr\n });\n }\n } else {\n const curr = this.read();\n this.custom = {\n ...(curr?.custom || {}),\n [key]: value\n };\n this.write({\n ...curr,\n custom: this.custom\n });\n }\n }\n}","/**\n * Copyright 2020-2025 New Relic, Inc. All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nexport class LocalStorage {\n get(key) {\n try {\n // localStorage strangely type-casts non-existing data to \"null\"...\n // Cast it back to undefined if it doesnt exist\n return localStorage.getItem(key) || undefined;\n } catch (err) {\n // Error is ignored\n return '';\n }\n }\n set(key, value) {\n try {\n if (value === undefined || value === null) return this.remove(key);\n return localStorage.setItem(key, value);\n } catch (err) {\n // Error is ignored\n }\n }\n remove(key) {\n try {\n localStorage.removeItem(key);\n } catch (err) {\n // Error is ignored\n }\n }\n}","/**\n * Copyright 2020-2025 New Relic, Inc. All rights reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { drain } from '../../common/drain/drain';\nimport { ee } from '../../common/event-emitter/contextual-ee';\nimport { registerHandler } from '../../common/event-emitter/register-handler';\nimport { SessionEntity } from '../../common/session/session-entity';\nimport { LocalStorage } from '../../common/storage/local-storage.js';\nimport { DEFAULT_KEY } from '../../common/session/constants';\nexport function setupAgentSession(agentRef) {\n if (agentRef.runtime.session) return agentRef.runtime.session; // already setup\n\n const sessionInit = agentRef.init.session;\n agentRef.runtime.session = new SessionEntity({\n agentIdentifier: agentRef.agentIdentifier,\n key: DEFAULT_KEY,\n storage: new LocalStorage(),\n expiresMs: sessionInit?.expiresMs,\n inactiveMs: sessionInit?.inactiveMs\n });\n\n // Retrieve & re-add all of the persisted setCustomAttribute|setUserId k-v from previous page load(s), if any was stored.\n const customSessionData = agentRef.runtime.session.state.custom;\n if (customSessionData) {\n agentRef.info.jsAttributes = {\n ...agentRef.info.jsAttributes,\n ...customSessionData\n };\n }\n const sharedEE = ee.get(agentRef.agentIdentifier);\n\n // any calls to newrelic.setCustomAttribute(<persisted>) will need to be added to:\n // local info.jsAttributes {}\n // the session's storage API\n registerHandler('api-setCustomAttribute', (time, key, value) => {\n agentRef.runtime.session.syncCustomAttribute(key, value);\n }, 'session', sharedEE);\n\n // any calls to newrelic.setUserId(...) will need to be added to:\n // local info.jsAttributes {}\n // the session's storage API\n registerHandler('api-setUserId', (time, key, value) => {\n agentRef.runtime.session.syncCustomAttribute(key, value);\n }, 'session', sharedEE);\n drain(agentRef.agentIdentifier, 'session');\n return agentRef.runtime.session;\n}"],"names":["Timer","constructor","opts","ms","onEnd","Error","this","initialMs","startTimestamp","Date","now","timer","create","cb","clear","setTimeout","clearTimeout","end","isValid","InteractionTimer","super","onPause","onRefresh","onResume","readStorage","remainingMs","undefined","refreshEvents","abortController","AbortController","e","isBrowserScope","ee","debouncedRefresh","debounce","refresh","bind","leading","refreshHandler","evts","includes","type","on","subscribeToVisibilityChange","state","pause","resume","signal","abort","removeEventListener","lsData","obj","JSON","parse","isExpired","expiresAt","inactiveAt","err","timestamp","model","value","updatedAt","sessionReplayMode","MODE","OFF","sessionReplaySentFirstChunk","sessionTraceMode","traceHarvestStarted","serverTimeDiff","custom","SessionEntity","agentIdentifier","key","storage","concat","get","wrapEvents","setup","windowAddEventListener","event","lookupKey","newValue","sync","emit","SESSION_EVENTS","UPDATE","SESSION_EVENT_TYPES","CROSS_TAB","_ref","generateRandomHexString","expiresMs","DEFAULT_EXPIRES_MS","inactiveMs","DEFAULT_INACTIVE_MS","persistentAttributes","initialRead","read","getFutureTimestamp","expiresTimer","collectSM","reset","Infinity","inactiveTimer","RESUME","initialized","PAUSE","write","getModeledObject","isNew","Object","keys","length","STARTED","PREFIX","data","assign","val","isInvalid","warn","set","stringify","SAME_TAB","RESET","remove","existingData","every","x","useUpdatedAt","tag","getDuration","handle","SUPPORTABILITY_METRIC_CHANNEL","FEATURE_NAMES","metrics","arguments","startingTimestamp","futureMs","syncCustomAttribute","curr","LocalStorage","localStorage","getItem","setItem","removeItem","setupAgentSession","agentRef","runtime","session","sessionInit","init","DEFAULT_KEY","customSessionData","info","jsAttributes","sharedEE","registerHandler","time","drain"],"sourceRoot":""}