posthog-js 1.274.3 → 1.275.1
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/dist/array.full.es5.js +1 -1
- package/dist/array.full.es5.js.map +1 -1
- package/dist/array.full.js +1 -1
- package/dist/array.full.js.map +1 -1
- package/dist/array.full.no-external.js +1 -1
- package/dist/array.full.no-external.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/array.no-external.js +1 -1
- package/dist/array.no-external.js.map +1 -1
- package/dist/customizations.full.js +1 -1
- package/dist/lazy-recorder.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +6 -0
- package/dist/module.full.d.ts +6 -0
- package/dist/module.full.js +1 -1
- package/dist/module.full.js.map +1 -1
- package/dist/module.full.no-external.d.ts +6 -0
- package/dist/module.full.no-external.js +1 -1
- package/dist/module.full.no-external.js.map +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/module.no-external.d.ts +6 -0
- package/dist/module.no-external.js +1 -1
- package/dist/module.no-external.js.map +1 -1
- package/dist/posthog-recorder.js +1 -1
- package/dist/src/sessionid.d.ts +6 -0
- package/dist/surveys-preview.d.ts +6 -0
- package/lib/package.json +1 -1
- package/lib/src/extensions/web-vitals/index.js +11 -2
- package/lib/src/extensions/web-vitals/index.js.map +1 -1
- package/lib/src/heatmaps.js +10 -2
- package/lib/src/heatmaps.js.map +1 -1
- package/lib/src/posthog-core.js +6 -4
- package/lib/src/posthog-core.js.map +1 -1
- package/lib/src/sessionid.d.ts +6 -0
- package/lib/src/sessionid.js +20 -4
- package/lib/src/sessionid.js.map +1 -1
- package/package.json +1 -1
package/lib/src/sessionid.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare class SessionIdManager {
|
|
|
16
16
|
private _sessionIdChangedHandlers;
|
|
17
17
|
private readonly _sessionTimeoutMs;
|
|
18
18
|
private _enforceIdleTimeout;
|
|
19
|
+
private _beforeUnloadListener;
|
|
19
20
|
private _eventEmitter;
|
|
20
21
|
on(event: 'forcedIdleReset', handler: () => void): () => void;
|
|
21
22
|
constructor(instance: PostHog, sessionIdGenerator?: () => string, windowIdGenerator?: () => string);
|
|
@@ -27,6 +28,11 @@ export declare class SessionIdManager {
|
|
|
27
28
|
private _setSessionId;
|
|
28
29
|
private _getSessionId;
|
|
29
30
|
resetSessionId(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Cleans up resources used by SessionIdManager.
|
|
33
|
+
* Should be called when the SessionIdManager is no longer needed to prevent memory leaks.
|
|
34
|
+
*/
|
|
35
|
+
destroy(): void;
|
|
30
36
|
private _listenToReloadWindow;
|
|
31
37
|
private _sessionHasBeenIdleTooLong;
|
|
32
38
|
checkAndGetSessionAndWindowId(readOnly?: boolean, _timestamp?: number | null): {
|
package/lib/src/sessionid.js
CHANGED
|
@@ -35,6 +35,7 @@ var SessionIdManager = /** @class */ (function () {
|
|
|
35
35
|
var _this = this;
|
|
36
36
|
var _a;
|
|
37
37
|
this._sessionIdChangedHandlers = [];
|
|
38
|
+
this._beforeUnloadListener = undefined;
|
|
38
39
|
this._eventEmitter = new simple_event_emitter_1.SimpleEventEmitter();
|
|
39
40
|
this._sessionHasBeenIdleTooLong = function (timestamp, lastActivityTimestamp) {
|
|
40
41
|
return Math.abs(timestamp - lastActivityTimestamp) > _this.sessionTimeoutMs;
|
|
@@ -170,6 +171,22 @@ var SessionIdManager = /** @class */ (function () {
|
|
|
170
171
|
SessionIdManager.prototype.resetSessionId = function () {
|
|
171
172
|
this._setSessionId(null, null, null);
|
|
172
173
|
};
|
|
174
|
+
/**
|
|
175
|
+
* Cleans up resources used by SessionIdManager.
|
|
176
|
+
* Should be called when the SessionIdManager is no longer needed to prevent memory leaks.
|
|
177
|
+
*/
|
|
178
|
+
SessionIdManager.prototype.destroy = function () {
|
|
179
|
+
// Clear the idle timeout timer
|
|
180
|
+
clearTimeout(this._enforceIdleTimeout);
|
|
181
|
+
this._enforceIdleTimeout = undefined;
|
|
182
|
+
// Remove the beforeunload event listener
|
|
183
|
+
if (this._beforeUnloadListener && globals_1.window) {
|
|
184
|
+
globals_1.window.removeEventListener('beforeunload', this._beforeUnloadListener, { capture: false });
|
|
185
|
+
this._beforeUnloadListener = undefined;
|
|
186
|
+
}
|
|
187
|
+
// Clear session id changed handlers
|
|
188
|
+
this._sessionIdChangedHandlers = [];
|
|
189
|
+
};
|
|
173
190
|
/*
|
|
174
191
|
* Listens to window unloads and removes the primaryWindowExists key from sessionStorage.
|
|
175
192
|
* Reloaded or fresh tabs created after a DOM unloads (reloading the same tab) WILL NOT have this primaryWindowExists flag in session storage.
|
|
@@ -178,13 +195,12 @@ var SessionIdManager = /** @class */ (function () {
|
|
|
178
195
|
*/
|
|
179
196
|
SessionIdManager.prototype._listenToReloadWindow = function () {
|
|
180
197
|
var _this = this;
|
|
181
|
-
|
|
198
|
+
this._beforeUnloadListener = function () {
|
|
182
199
|
if (_this._canUseSessionStorage()) {
|
|
183
200
|
storage_1.sessionStore._remove(_this._primary_window_exists_storage_key);
|
|
184
201
|
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
{ capture: false });
|
|
202
|
+
};
|
|
203
|
+
(0, utils_1.addEventListener)(globals_1.window, 'beforeunload', this._beforeUnloadListener, { capture: false });
|
|
188
204
|
};
|
|
189
205
|
/*
|
|
190
206
|
* This function returns the current sessionId and windowId. It should be used to
|
package/lib/src/sessionid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionid.js","sourceRoot":"","sources":["../../src/sessionid.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHogPersistence } from './posthog-persistence'\nimport { SESSION_ID } from './constants'\nimport { sessionStore } from './storage'\nimport { PostHogConfig, SessionIdChangedCallback } from './types'\nimport { uuid7ToTimestampMs, uuidv7 } from './uuidv7'\nimport { window } from './utils/globals'\n\nimport { createLogger } from './utils/logger'\n\nimport { isArray, isNumber, isUndefined, clampToRange } from '@posthog/core'\nimport { PostHog } from './posthog-core'\nimport { addEventListener } from './utils'\nimport { SimpleEventEmitter } from './utils/simple-event-emitter'\n\nconst logger = createLogger('[SessionId]')\n\nexport const DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS = 30 * 60 // 30 minutes\nexport const MAX_SESSION_IDLE_TIMEOUT_SECONDS = 10 * 60 * 60 // 10 hours\nconst MIN_SESSION_IDLE_TIMEOUT_SECONDS = 60 // 1 minute\nconst SESSION_LENGTH_LIMIT_MILLISECONDS = 24 * 3600 * 1000 // 24 hours\n\nexport class SessionIdManager {\n private readonly _sessionIdGenerator: () => string\n private readonly _windowIdGenerator: () => string\n private _config: Partial<PostHogConfig>\n private _persistence: PostHogPersistence\n private _windowId: string | null | undefined\n private _sessionId: string | null | undefined\n private readonly _window_id_storage_key: string\n private readonly _primary_window_exists_storage_key: string\n private _sessionStartTimestamp: number | null\n\n private _sessionActivityTimestamp: number | null\n private _sessionIdChangedHandlers: SessionIdChangedCallback[] = []\n private readonly _sessionTimeoutMs: number\n\n // we track activity so we can end the session proactively when it has passed the idle timeout\n private _enforceIdleTimeout: ReturnType<typeof setTimeout> | undefined\n\n private _eventEmitter: SimpleEventEmitter = new SimpleEventEmitter()\n public on(event: 'forcedIdleReset', handler: () => void): () => void {\n return this._eventEmitter.on(event, handler)\n }\n\n constructor(instance: PostHog, sessionIdGenerator?: () => string, windowIdGenerator?: () => string) {\n if (!instance.persistence) {\n throw new Error('SessionIdManager requires a PostHogPersistence instance')\n }\n if (instance.config.cookieless_mode === 'always') {\n throw new Error('SessionIdManager cannot be used with cookieless_mode=\"always\"')\n }\n\n this._config = instance.config\n this._persistence = instance.persistence\n this._windowId = undefined\n this._sessionId = undefined\n this._sessionStartTimestamp = null\n this._sessionActivityTimestamp = null\n this._sessionIdGenerator = sessionIdGenerator || uuidv7\n this._windowIdGenerator = windowIdGenerator || uuidv7\n\n const persistenceName = this._config['persistence_name'] || this._config['token']\n\n const desiredTimeout = this._config['session_idle_timeout_seconds'] || DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS\n this._sessionTimeoutMs =\n clampToRange(\n desiredTimeout,\n MIN_SESSION_IDLE_TIMEOUT_SECONDS,\n MAX_SESSION_IDLE_TIMEOUT_SECONDS,\n logger.createLogger('session_idle_timeout_seconds'),\n DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS\n ) * 1000\n\n instance.register({ $configured_session_timeout_ms: this._sessionTimeoutMs })\n this._resetIdleTimer()\n\n this._window_id_storage_key = 'ph_' + persistenceName + '_window_id'\n this._primary_window_exists_storage_key = 'ph_' + persistenceName + '_primary_window_exists'\n\n // primary_window_exists is set when the DOM has been loaded and is cleared on unload\n // if it exists here it means there was no unload which suggests this window is opened as a tab duplication, window.open, etc.\n if (this._canUseSessionStorage()) {\n const lastWindowId = sessionStore._parse(this._window_id_storage_key)\n\n const primaryWindowExists = sessionStore._parse(this._primary_window_exists_storage_key)\n if (lastWindowId && !primaryWindowExists) {\n // Persist window from previous storage state\n this._windowId = lastWindowId\n } else {\n // Wipe any reference to previous window id\n sessionStore._remove(this._window_id_storage_key)\n }\n // Flag this session as having a primary window\n sessionStore._set(this._primary_window_exists_storage_key, true)\n }\n\n if (this._config.bootstrap?.sessionID) {\n try {\n const sessionStartTimestamp = uuid7ToTimestampMs(this._config.bootstrap.sessionID)\n this._setSessionId(this._config.bootstrap.sessionID, new Date().getTime(), sessionStartTimestamp)\n } catch (e) {\n logger.error('Invalid sessionID in bootstrap', e)\n }\n }\n\n this._listenToReloadWindow()\n }\n\n get sessionTimeoutMs(): number {\n return this._sessionTimeoutMs\n }\n\n onSessionId(callback: SessionIdChangedCallback): () => void {\n // KLUDGE: when running in tests the handlers array was always undefined\n // it's yucky but safe to set it here so that it's always definitely available\n if (isUndefined(this._sessionIdChangedHandlers)) {\n this._sessionIdChangedHandlers = []\n }\n\n this._sessionIdChangedHandlers.push(callback)\n if (this._sessionId) {\n callback(this._sessionId, this._windowId)\n }\n return () => {\n this._sessionIdChangedHandlers = this._sessionIdChangedHandlers.filter((h) => h !== callback)\n }\n }\n\n private _canUseSessionStorage(): boolean {\n // We only want to use sessionStorage if persistence is enabled and not memory storage\n return this._config.persistence !== 'memory' && !this._persistence._disabled && sessionStore._is_supported()\n }\n\n // Note: this tries to store the windowId in sessionStorage. SessionStorage is unique to the current window/tab,\n // and persists page loads/reloads. So it's uniquely suited for storing the windowId. This function also respects\n // when persistence is disabled (by user config) and when sessionStorage is not supported (it *should* be supported on all browsers),\n // and in that case, it falls back to memory (which sadly, won't persist page loads)\n private _setWindowId(windowId: string): void {\n if (windowId !== this._windowId) {\n this._windowId = windowId\n if (this._canUseSessionStorage()) {\n sessionStore._set(this._window_id_storage_key, windowId)\n }\n }\n }\n\n private _getWindowId(): string | null {\n if (this._windowId) {\n return this._windowId\n }\n if (this._canUseSessionStorage()) {\n return sessionStore._parse(this._window_id_storage_key)\n }\n // New window id will be generated\n return null\n }\n\n // Note: 'this.persistence.register' can be disabled in the config.\n // In that case, this works by storing sessionId and the timestamp in memory.\n private _setSessionId(\n sessionId: string | null,\n sessionActivityTimestamp: number | null,\n sessionStartTimestamp: number | null\n ): void {\n if (\n sessionId !== this._sessionId ||\n sessionActivityTimestamp !== this._sessionActivityTimestamp ||\n sessionStartTimestamp !== this._sessionStartTimestamp\n ) {\n this._sessionStartTimestamp = sessionStartTimestamp\n this._sessionActivityTimestamp = sessionActivityTimestamp\n this._sessionId = sessionId\n\n this._persistence.register({\n [SESSION_ID]: [sessionActivityTimestamp, sessionId, sessionStartTimestamp],\n })\n }\n }\n\n private _getSessionId(): [number, string, number] {\n if (this._sessionId && this._sessionActivityTimestamp && this._sessionStartTimestamp) {\n return [this._sessionActivityTimestamp, this._sessionId, this._sessionStartTimestamp]\n }\n const sessionIdInfo = this._persistence.props[SESSION_ID]\n\n if (isArray(sessionIdInfo) && sessionIdInfo.length === 2) {\n // Storage does not yet have a session start time. Add the last activity timestamp as the start time\n sessionIdInfo.push(sessionIdInfo[0])\n }\n\n return sessionIdInfo || [0, null, 0]\n }\n\n // Resets the session id by setting it to null. On the subsequent call to checkAndGetSessionAndWindowId,\n // new ids will be generated.\n resetSessionId(): void {\n this._setSessionId(null, null, null)\n }\n\n /*\n * Listens to window unloads and removes the primaryWindowExists key from sessionStorage.\n * Reloaded or fresh tabs created after a DOM unloads (reloading the same tab) WILL NOT have this primaryWindowExists flag in session storage.\n * Cloned sessions (new tab, tab duplication, window.open(), ...) WILL have this primaryWindowExists flag in their copied session storage.\n * We conditionally check the primaryWindowExists value in the constructor to decide if the window id in the last session storage should be carried over.\n */\n private _listenToReloadWindow(): void {\n addEventListener(\n window,\n 'beforeunload',\n () => {\n if (this._canUseSessionStorage()) {\n sessionStore._remove(this._primary_window_exists_storage_key)\n }\n },\n // Not making it passive to try and force the browser to handle this before the page is unloaded\n { capture: false }\n )\n }\n\n private _sessionHasBeenIdleTooLong = (timestamp: number, lastActivityTimestamp: number) => {\n return Math.abs(timestamp - lastActivityTimestamp) > this.sessionTimeoutMs\n }\n\n /*\n * This function returns the current sessionId and windowId. It should be used to\n * access these values over directly calling `._sessionId` or `._windowId`.\n * In addition to returning the sessionId and windowId, this function also manages cycling the\n * sessionId and windowId when appropriate by doing the following:\n *\n * 1. If the sessionId or windowId is not set, it will generate a new one and store it.\n * 2. If the readOnly param is set to false, it will:\n * a. Check if it has been > SESSION_CHANGE_THRESHOLD since the last call with this flag set.\n * If so, it will generate a new sessionId and store it.\n * b. Update the timestamp stored with the sessionId to ensure the current session is extended\n * for the appropriate amount of time.\n *\n * @param {boolean} readOnly (optional) Defaults to False. Should be set to True when the call to the function should not extend or cycle the session (e.g. being called for non-user generated events)\n * @param {Number} timestamp (optional) Defaults to the current time. The timestamp to be stored with the sessionId (used when determining if a new sessionId should be generated)\n */\n checkAndGetSessionAndWindowId(readOnly = false, _timestamp: number | null = null) {\n if (this._config.cookieless_mode === 'always') {\n throw new Error('checkAndGetSessionAndWindowId should not be called with cookieless_mode=\"always\"')\n }\n const timestamp = _timestamp || new Date().getTime()\n\n // eslint-disable-next-line prefer-const\n let [lastActivityTimestamp, sessionId, startTimestamp] = this._getSessionId()\n let windowId = this._getWindowId()\n\n const sessionPastMaximumLength =\n isNumber(startTimestamp) &&\n startTimestamp > 0 &&\n Math.abs(timestamp - startTimestamp) > SESSION_LENGTH_LIMIT_MILLISECONDS\n\n let valuesChanged = false\n const noSessionId = !sessionId\n const activityTimeout = !readOnly && this._sessionHasBeenIdleTooLong(timestamp, lastActivityTimestamp)\n if (noSessionId || activityTimeout || sessionPastMaximumLength) {\n sessionId = this._sessionIdGenerator()\n windowId = this._windowIdGenerator()\n logger.info('new session ID generated', {\n sessionId,\n windowId,\n changeReason: { noSessionId, activityTimeout, sessionPastMaximumLength },\n })\n startTimestamp = timestamp\n valuesChanged = true\n } else if (!windowId) {\n windowId = this._windowIdGenerator()\n valuesChanged = true\n }\n\n const newActivityTimestamp =\n lastActivityTimestamp === 0 || !readOnly || sessionPastMaximumLength ? timestamp : lastActivityTimestamp\n const sessionStartTimestamp = startTimestamp === 0 ? new Date().getTime() : startTimestamp\n\n this._setWindowId(windowId)\n this._setSessionId(sessionId, newActivityTimestamp, sessionStartTimestamp)\n\n if (!readOnly) {\n this._resetIdleTimer()\n }\n\n if (valuesChanged) {\n this._sessionIdChangedHandlers.forEach((handler) =>\n handler(\n sessionId,\n windowId,\n valuesChanged ? { noSessionId, activityTimeout, sessionPastMaximumLength } : undefined\n )\n )\n }\n\n return {\n sessionId,\n windowId,\n sessionStartTimestamp,\n changeReason: valuesChanged ? { noSessionId, activityTimeout, sessionPastMaximumLength } : undefined,\n lastActivityTimestamp: lastActivityTimestamp,\n }\n }\n\n private _resetIdleTimer() {\n clearTimeout(this._enforceIdleTimeout)\n this._enforceIdleTimeout = setTimeout(() => {\n // enforce idle timeout a little after the session timeout to ensure the session is reset even without activity\n // we need to check session activity first in case a different window has kept the session active\n // while this window has been idle - and the timer has not progressed - e.g. window memory frozen while hidden\n const [lastActivityTimestamp] = this._getSessionId()\n if (this._sessionHasBeenIdleTooLong(new Date().getTime(), lastActivityTimestamp)) {\n const idleSessionId = this._sessionId\n this.resetSessionId()\n this._eventEmitter.emit('forcedIdleReset', { idleSessionId })\n }\n }, this.sessionTimeoutMs * 1.1)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sessionid.js","sourceRoot":"","sources":["../../src/sessionid.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHogPersistence } from './posthog-persistence'\nimport { SESSION_ID } from './constants'\nimport { sessionStore } from './storage'\nimport { PostHogConfig, SessionIdChangedCallback } from './types'\nimport { uuid7ToTimestampMs, uuidv7 } from './uuidv7'\nimport { window } from './utils/globals'\n\nimport { createLogger } from './utils/logger'\n\nimport { isArray, isNumber, isUndefined, clampToRange } from '@posthog/core'\nimport { PostHog } from './posthog-core'\nimport { addEventListener } from './utils'\nimport { SimpleEventEmitter } from './utils/simple-event-emitter'\n\nconst logger = createLogger('[SessionId]')\n\nexport const DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS = 30 * 60 // 30 minutes\nexport const MAX_SESSION_IDLE_TIMEOUT_SECONDS = 10 * 60 * 60 // 10 hours\nconst MIN_SESSION_IDLE_TIMEOUT_SECONDS = 60 // 1 minute\nconst SESSION_LENGTH_LIMIT_MILLISECONDS = 24 * 3600 * 1000 // 24 hours\n\nexport class SessionIdManager {\n private readonly _sessionIdGenerator: () => string\n private readonly _windowIdGenerator: () => string\n private _config: Partial<PostHogConfig>\n private _persistence: PostHogPersistence\n private _windowId: string | null | undefined\n private _sessionId: string | null | undefined\n private readonly _window_id_storage_key: string\n private readonly _primary_window_exists_storage_key: string\n private _sessionStartTimestamp: number | null\n\n private _sessionActivityTimestamp: number | null\n private _sessionIdChangedHandlers: SessionIdChangedCallback[] = []\n private readonly _sessionTimeoutMs: number\n\n // we track activity so we can end the session proactively when it has passed the idle timeout\n private _enforceIdleTimeout: ReturnType<typeof setTimeout> | undefined\n\n private _beforeUnloadListener: (() => void) | undefined = undefined\n\n private _eventEmitter: SimpleEventEmitter = new SimpleEventEmitter()\n public on(event: 'forcedIdleReset', handler: () => void): () => void {\n return this._eventEmitter.on(event, handler)\n }\n\n constructor(instance: PostHog, sessionIdGenerator?: () => string, windowIdGenerator?: () => string) {\n if (!instance.persistence) {\n throw new Error('SessionIdManager requires a PostHogPersistence instance')\n }\n if (instance.config.cookieless_mode === 'always') {\n throw new Error('SessionIdManager cannot be used with cookieless_mode=\"always\"')\n }\n\n this._config = instance.config\n this._persistence = instance.persistence\n this._windowId = undefined\n this._sessionId = undefined\n this._sessionStartTimestamp = null\n this._sessionActivityTimestamp = null\n this._sessionIdGenerator = sessionIdGenerator || uuidv7\n this._windowIdGenerator = windowIdGenerator || uuidv7\n\n const persistenceName = this._config['persistence_name'] || this._config['token']\n\n const desiredTimeout = this._config['session_idle_timeout_seconds'] || DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS\n this._sessionTimeoutMs =\n clampToRange(\n desiredTimeout,\n MIN_SESSION_IDLE_TIMEOUT_SECONDS,\n MAX_SESSION_IDLE_TIMEOUT_SECONDS,\n logger.createLogger('session_idle_timeout_seconds'),\n DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS\n ) * 1000\n\n instance.register({ $configured_session_timeout_ms: this._sessionTimeoutMs })\n this._resetIdleTimer()\n\n this._window_id_storage_key = 'ph_' + persistenceName + '_window_id'\n this._primary_window_exists_storage_key = 'ph_' + persistenceName + '_primary_window_exists'\n\n // primary_window_exists is set when the DOM has been loaded and is cleared on unload\n // if it exists here it means there was no unload which suggests this window is opened as a tab duplication, window.open, etc.\n if (this._canUseSessionStorage()) {\n const lastWindowId = sessionStore._parse(this._window_id_storage_key)\n\n const primaryWindowExists = sessionStore._parse(this._primary_window_exists_storage_key)\n if (lastWindowId && !primaryWindowExists) {\n // Persist window from previous storage state\n this._windowId = lastWindowId\n } else {\n // Wipe any reference to previous window id\n sessionStore._remove(this._window_id_storage_key)\n }\n // Flag this session as having a primary window\n sessionStore._set(this._primary_window_exists_storage_key, true)\n }\n\n if (this._config.bootstrap?.sessionID) {\n try {\n const sessionStartTimestamp = uuid7ToTimestampMs(this._config.bootstrap.sessionID)\n this._setSessionId(this._config.bootstrap.sessionID, new Date().getTime(), sessionStartTimestamp)\n } catch (e) {\n logger.error('Invalid sessionID in bootstrap', e)\n }\n }\n\n this._listenToReloadWindow()\n }\n\n get sessionTimeoutMs(): number {\n return this._sessionTimeoutMs\n }\n\n onSessionId(callback: SessionIdChangedCallback): () => void {\n // KLUDGE: when running in tests the handlers array was always undefined\n // it's yucky but safe to set it here so that it's always definitely available\n if (isUndefined(this._sessionIdChangedHandlers)) {\n this._sessionIdChangedHandlers = []\n }\n\n this._sessionIdChangedHandlers.push(callback)\n if (this._sessionId) {\n callback(this._sessionId, this._windowId)\n }\n return () => {\n this._sessionIdChangedHandlers = this._sessionIdChangedHandlers.filter((h) => h !== callback)\n }\n }\n\n private _canUseSessionStorage(): boolean {\n // We only want to use sessionStorage if persistence is enabled and not memory storage\n return this._config.persistence !== 'memory' && !this._persistence._disabled && sessionStore._is_supported()\n }\n\n // Note: this tries to store the windowId in sessionStorage. SessionStorage is unique to the current window/tab,\n // and persists page loads/reloads. So it's uniquely suited for storing the windowId. This function also respects\n // when persistence is disabled (by user config) and when sessionStorage is not supported (it *should* be supported on all browsers),\n // and in that case, it falls back to memory (which sadly, won't persist page loads)\n private _setWindowId(windowId: string): void {\n if (windowId !== this._windowId) {\n this._windowId = windowId\n if (this._canUseSessionStorage()) {\n sessionStore._set(this._window_id_storage_key, windowId)\n }\n }\n }\n\n private _getWindowId(): string | null {\n if (this._windowId) {\n return this._windowId\n }\n if (this._canUseSessionStorage()) {\n return sessionStore._parse(this._window_id_storage_key)\n }\n // New window id will be generated\n return null\n }\n\n // Note: 'this.persistence.register' can be disabled in the config.\n // In that case, this works by storing sessionId and the timestamp in memory.\n private _setSessionId(\n sessionId: string | null,\n sessionActivityTimestamp: number | null,\n sessionStartTimestamp: number | null\n ): void {\n if (\n sessionId !== this._sessionId ||\n sessionActivityTimestamp !== this._sessionActivityTimestamp ||\n sessionStartTimestamp !== this._sessionStartTimestamp\n ) {\n this._sessionStartTimestamp = sessionStartTimestamp\n this._sessionActivityTimestamp = sessionActivityTimestamp\n this._sessionId = sessionId\n\n this._persistence.register({\n [SESSION_ID]: [sessionActivityTimestamp, sessionId, sessionStartTimestamp],\n })\n }\n }\n\n private _getSessionId(): [number, string, number] {\n if (this._sessionId && this._sessionActivityTimestamp && this._sessionStartTimestamp) {\n return [this._sessionActivityTimestamp, this._sessionId, this._sessionStartTimestamp]\n }\n const sessionIdInfo = this._persistence.props[SESSION_ID]\n\n if (isArray(sessionIdInfo) && sessionIdInfo.length === 2) {\n // Storage does not yet have a session start time. Add the last activity timestamp as the start time\n sessionIdInfo.push(sessionIdInfo[0])\n }\n\n return sessionIdInfo || [0, null, 0]\n }\n\n // Resets the session id by setting it to null. On the subsequent call to checkAndGetSessionAndWindowId,\n // new ids will be generated.\n resetSessionId(): void {\n this._setSessionId(null, null, null)\n }\n\n /**\n * Cleans up resources used by SessionIdManager.\n * Should be called when the SessionIdManager is no longer needed to prevent memory leaks.\n */\n destroy(): void {\n // Clear the idle timeout timer\n clearTimeout(this._enforceIdleTimeout)\n this._enforceIdleTimeout = undefined\n\n // Remove the beforeunload event listener\n if (this._beforeUnloadListener && window) {\n window.removeEventListener('beforeunload', this._beforeUnloadListener, { capture: false } as any)\n this._beforeUnloadListener = undefined\n }\n\n // Clear session id changed handlers\n this._sessionIdChangedHandlers = []\n }\n\n /*\n * Listens to window unloads and removes the primaryWindowExists key from sessionStorage.\n * Reloaded or fresh tabs created after a DOM unloads (reloading the same tab) WILL NOT have this primaryWindowExists flag in session storage.\n * Cloned sessions (new tab, tab duplication, window.open(), ...) WILL have this primaryWindowExists flag in their copied session storage.\n * We conditionally check the primaryWindowExists value in the constructor to decide if the window id in the last session storage should be carried over.\n */\n private _listenToReloadWindow(): void {\n this._beforeUnloadListener = () => {\n if (this._canUseSessionStorage()) {\n sessionStore._remove(this._primary_window_exists_storage_key)\n }\n }\n addEventListener(window, 'beforeunload', this._beforeUnloadListener, { capture: false })\n }\n\n private _sessionHasBeenIdleTooLong = (timestamp: number, lastActivityTimestamp: number) => {\n return Math.abs(timestamp - lastActivityTimestamp) > this.sessionTimeoutMs\n }\n\n /*\n * This function returns the current sessionId and windowId. It should be used to\n * access these values over directly calling `._sessionId` or `._windowId`.\n * In addition to returning the sessionId and windowId, this function also manages cycling the\n * sessionId and windowId when appropriate by doing the following:\n *\n * 1. If the sessionId or windowId is not set, it will generate a new one and store it.\n * 2. If the readOnly param is set to false, it will:\n * a. Check if it has been > SESSION_CHANGE_THRESHOLD since the last call with this flag set.\n * If so, it will generate a new sessionId and store it.\n * b. Update the timestamp stored with the sessionId to ensure the current session is extended\n * for the appropriate amount of time.\n *\n * @param {boolean} readOnly (optional) Defaults to False. Should be set to True when the call to the function should not extend or cycle the session (e.g. being called for non-user generated events)\n * @param {Number} timestamp (optional) Defaults to the current time. The timestamp to be stored with the sessionId (used when determining if a new sessionId should be generated)\n */\n checkAndGetSessionAndWindowId(readOnly = false, _timestamp: number | null = null) {\n if (this._config.cookieless_mode === 'always') {\n throw new Error('checkAndGetSessionAndWindowId should not be called with cookieless_mode=\"always\"')\n }\n const timestamp = _timestamp || new Date().getTime()\n\n // eslint-disable-next-line prefer-const\n let [lastActivityTimestamp, sessionId, startTimestamp] = this._getSessionId()\n let windowId = this._getWindowId()\n\n const sessionPastMaximumLength =\n isNumber(startTimestamp) &&\n startTimestamp > 0 &&\n Math.abs(timestamp - startTimestamp) > SESSION_LENGTH_LIMIT_MILLISECONDS\n\n let valuesChanged = false\n const noSessionId = !sessionId\n const activityTimeout = !readOnly && this._sessionHasBeenIdleTooLong(timestamp, lastActivityTimestamp)\n if (noSessionId || activityTimeout || sessionPastMaximumLength) {\n sessionId = this._sessionIdGenerator()\n windowId = this._windowIdGenerator()\n logger.info('new session ID generated', {\n sessionId,\n windowId,\n changeReason: { noSessionId, activityTimeout, sessionPastMaximumLength },\n })\n startTimestamp = timestamp\n valuesChanged = true\n } else if (!windowId) {\n windowId = this._windowIdGenerator()\n valuesChanged = true\n }\n\n const newActivityTimestamp =\n lastActivityTimestamp === 0 || !readOnly || sessionPastMaximumLength ? timestamp : lastActivityTimestamp\n const sessionStartTimestamp = startTimestamp === 0 ? new Date().getTime() : startTimestamp\n\n this._setWindowId(windowId)\n this._setSessionId(sessionId, newActivityTimestamp, sessionStartTimestamp)\n\n if (!readOnly) {\n this._resetIdleTimer()\n }\n\n if (valuesChanged) {\n this._sessionIdChangedHandlers.forEach((handler) =>\n handler(\n sessionId,\n windowId,\n valuesChanged ? { noSessionId, activityTimeout, sessionPastMaximumLength } : undefined\n )\n )\n }\n\n return {\n sessionId,\n windowId,\n sessionStartTimestamp,\n changeReason: valuesChanged ? { noSessionId, activityTimeout, sessionPastMaximumLength } : undefined,\n lastActivityTimestamp: lastActivityTimestamp,\n }\n }\n\n private _resetIdleTimer() {\n clearTimeout(this._enforceIdleTimeout)\n this._enforceIdleTimeout = setTimeout(() => {\n // enforce idle timeout a little after the session timeout to ensure the session is reset even without activity\n // we need to check session activity first in case a different window has kept the session active\n // while this window has been idle - and the timer has not progressed - e.g. window memory frozen while hidden\n const [lastActivityTimestamp] = this._getSessionId()\n if (this._sessionHasBeenIdleTooLong(new Date().getTime(), lastActivityTimestamp)) {\n const idleSessionId = this._sessionId\n this.resetSessionId()\n this._eventEmitter.emit('forcedIdleReset', { idleSessionId })\n }\n }, this.sessionTimeoutMs * 1.1)\n }\n}\n"]}
|
package/package.json
CHANGED