posthog-js 1.200.2 → 1.201.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.
Files changed (57) hide show
  1. package/README.md +7 -0
  2. package/dist/all-external-dependencies.js.map +1 -1
  3. package/dist/array.full.es5.js +1 -1
  4. package/dist/array.full.es5.js.map +1 -1
  5. package/dist/array.full.js +1 -1
  6. package/dist/array.full.js.map +1 -1
  7. package/dist/array.full.no-external.js +1 -1
  8. package/dist/array.full.no-external.js.map +1 -1
  9. package/dist/array.js +1 -1
  10. package/dist/array.js.map +1 -1
  11. package/dist/array.no-external.js +1 -1
  12. package/dist/array.no-external.js.map +1 -1
  13. package/dist/customizations.full.js +1 -1
  14. package/dist/customizations.full.js.map +1 -1
  15. package/dist/dead-clicks-autocapture.js.map +1 -1
  16. package/dist/exception-autocapture.js.map +1 -1
  17. package/dist/external-scripts-loader.js.map +1 -1
  18. package/dist/main.js +1 -1
  19. package/dist/main.js.map +1 -1
  20. package/dist/module.d.ts +4 -2
  21. package/dist/module.full.d.ts +4 -2
  22. package/dist/module.full.js +1 -1
  23. package/dist/module.full.js.map +1 -1
  24. package/dist/module.full.no-external.d.ts +4 -2
  25. package/dist/module.full.no-external.js +1 -1
  26. package/dist/module.full.no-external.js.map +1 -1
  27. package/dist/module.js +1 -1
  28. package/dist/module.js.map +1 -1
  29. package/dist/module.no-external.d.ts +4 -2
  30. package/dist/module.no-external.js +1 -1
  31. package/dist/module.no-external.js.map +1 -1
  32. package/dist/recorder-v2.js.map +1 -1
  33. package/dist/recorder.js.map +1 -1
  34. package/dist/src/sessionid.d.ts +2 -0
  35. package/dist/src/types.d.ts +2 -2
  36. package/dist/surveys-preview.js.map +1 -1
  37. package/dist/surveys.js.map +1 -1
  38. package/dist/tracing-headers.js.map +1 -1
  39. package/lib/package.json +3 -3
  40. package/lib/src/entrypoints/dead-clicks-autocapture.js.map +1 -1
  41. package/lib/src/extensions/exception-autocapture/error-conversion.js +1 -1
  42. package/lib/src/extensions/exception-autocapture/error-conversion.js.map +1 -1
  43. package/lib/src/extensions/replay/config.js +1 -1
  44. package/lib/src/extensions/replay/config.js.map +1 -1
  45. package/lib/src/extensions/replay/sessionrecording.js.map +1 -1
  46. package/lib/src/posthog-core.js.map +1 -1
  47. package/lib/src/remote-config.js +30 -27
  48. package/lib/src/remote-config.js.map +1 -1
  49. package/lib/src/sessionid.d.ts +2 -0
  50. package/lib/src/sessionid.js +21 -9
  51. package/lib/src/sessionid.js.map +1 -1
  52. package/lib/src/types.d.ts +2 -2
  53. package/lib/src/types.js.map +1 -1
  54. package/lib/src/utils/event-utils.js.map +1 -1
  55. package/lib/src/utils/user-agent-utils.js.map +1 -1
  56. package/lib/src/web-experiments-types.js.map +1 -1
  57. package/package.json +3 -3
@@ -27,36 +27,35 @@ var RemoteConfigLoader = /** @class */ (function () {
27
27
  });
28
28
  };
29
29
  RemoteConfigLoader.prototype.load = function () {
30
- // Call decide to get what features are enabled and other settings.
31
- // As a reminder, if the /decide endpoint is disabled, feature flags, toolbar, session recording, autocapture,
32
- // and compression will not be available.
33
30
  var _this = this;
34
- if (!this.instance.config.__preview_remote_config) {
35
- return;
36
- }
37
- // Attempt 1 - use the pre-loaded config if it came as part of the token-specific array.js
38
- if (assignableWindow._POSTHOG_CONFIG) {
39
- logger.info('Using preloaded remote config', assignableWindow._POSTHOG_CONFIG);
40
- this.onRemoteConfig(assignableWindow._POSTHOG_CONFIG);
41
- return;
42
- }
43
- if (this.instance.config.advanced_disable_decide) {
44
- // This setting is essentially saying "dont call external APIs" hence we respect it here
45
- logger.warn('Remote config is disabled. Falling back to local config.');
46
- return;
47
- }
48
- // Attempt 2 - if we have the external deps loader then lets load the script version of the config that includes site apps
49
- this._loadRemoteConfigJs(function (config) {
50
- if (!config) {
51
- logger.info('No config found after loading remote JS config. Falling back to JSON.');
52
- // Attempt 3 Load the config json instead of the script - we won't get site apps etc. but we will get the config
53
- _this._loadRemoteConfigJSON(function (config) {
54
- _this.onRemoteConfig(config);
55
- });
31
+ try {
32
+ // Attempt 1 - use the pre-loaded config if it came as part of the token-specific array.js
33
+ if (assignableWindow._POSTHOG_CONFIG) {
34
+ logger.info('Using preloaded remote config', assignableWindow._POSTHOG_CONFIG);
35
+ this.onRemoteConfig(assignableWindow._POSTHOG_CONFIG);
56
36
  return;
57
37
  }
58
- _this.onRemoteConfig(config);
59
- });
38
+ if (this.instance.config.advanced_disable_decide) {
39
+ // This setting is essentially saying "dont call external APIs" hence we respect it here
40
+ logger.warn('Remote config is disabled. Falling back to local config.');
41
+ return;
42
+ }
43
+ // Attempt 2 - if we have the external deps loader then lets load the script version of the config that includes site apps
44
+ this._loadRemoteConfigJs(function (config) {
45
+ if (!config) {
46
+ logger.info('No config found after loading remote JS config. Falling back to JSON.');
47
+ // Attempt 3 Load the config json instead of the script - we won't get site apps etc. but we will get the config
48
+ _this._loadRemoteConfigJSON(function (config) {
49
+ _this.onRemoteConfig(config);
50
+ });
51
+ return;
52
+ }
53
+ _this.onRemoteConfig(config);
54
+ });
55
+ }
56
+ catch (error) {
57
+ logger.error('Error loading remote config', error);
58
+ }
60
59
  };
61
60
  RemoteConfigLoader.prototype.onRemoteConfig = function (config) {
62
61
  // NOTE: Once this is rolled out we will remove the "decide" related code above. Until then the code duplication is fine.
@@ -64,6 +63,10 @@ var RemoteConfigLoader = /** @class */ (function () {
64
63
  logger.error('Failed to fetch remote config from PostHog.');
65
64
  return;
66
65
  }
66
+ if (!this.instance.config.__preview_remote_config) {
67
+ logger.info('__preview_remote_config is disabled. Logging config instead', config);
68
+ return;
69
+ }
67
70
  this.instance._onRemoteConfig(config);
68
71
  // We only need to reload if we haven't already loaded the flags or if the request is in flight
69
72
  if (config.hasFeatureFlags !== false) {
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.js","sourceRoot":"","sources":["../../src/remote-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHog } from './posthog-core'\nimport { RemoteConfig } from './types'\n\nimport { createLogger } from './utils/logger'\nimport { assignableWindow } from './utils/globals'\n\nconst logger = createLogger('[Decide]')\n\nexport class RemoteConfigLoader {\n constructor(private readonly instance: PostHog) {}\n\n private _loadRemoteConfigJs(cb: (config?: RemoteConfig) => void): void {\n if (assignableWindow.__PosthogExtensions__?.loadExternalDependency) {\n assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, 'remote-config', () => {\n return cb(assignableWindow._POSTHOG_CONFIG)\n })\n } else {\n logger.error('PostHog Extensions not found. Cannot load remote config.')\n cb()\n }\n }\n\n private _loadRemoteConfigJSON(cb: (config?: RemoteConfig) => void): void {\n this.instance._send_request({\n method: 'GET',\n url: this.instance.requestRouter.endpointFor('assets', `/array/${this.instance.config.token}/config`),\n callback: (response) => {\n cb(response.json as RemoteConfig | undefined)\n },\n })\n }\n\n load(): void {\n // Call decide to get what features are enabled and other settings.\n // As a reminder, if the /decide endpoint is disabled, feature flags, toolbar, session recording, autocapture,\n // and compression will not be available.\n\n if (!this.instance.config.__preview_remote_config) {\n return\n }\n\n // Attempt 1 - use the pre-loaded config if it came as part of the token-specific array.js\n if (assignableWindow._POSTHOG_CONFIG) {\n logger.info('Using preloaded remote config', assignableWindow._POSTHOG_CONFIG)\n this.onRemoteConfig(assignableWindow._POSTHOG_CONFIG)\n return\n }\n\n if (this.instance.config.advanced_disable_decide) {\n // This setting is essentially saying \"dont call external APIs\" hence we respect it here\n logger.warn('Remote config is disabled. Falling back to local config.')\n return\n }\n\n // Attempt 2 - if we have the external deps loader then lets load the script version of the config that includes site apps\n this._loadRemoteConfigJs((config) => {\n if (!config) {\n logger.info('No config found after loading remote JS config. Falling back to JSON.')\n // Attempt 3 Load the config json instead of the script - we won't get site apps etc. but we will get the config\n this._loadRemoteConfigJSON((config) => {\n this.onRemoteConfig(config)\n })\n return\n }\n\n this.onRemoteConfig(config)\n })\n }\n\n private onRemoteConfig(config?: RemoteConfig): void {\n // NOTE: Once this is rolled out we will remove the \"decide\" related code above. Until then the code duplication is fine.\n if (!config) {\n logger.error('Failed to fetch remote config from PostHog.')\n return\n }\n this.instance._onRemoteConfig(config)\n\n // We only need to reload if we haven't already loaded the flags or if the request is in flight\n if (config.hasFeatureFlags !== false) {\n // If the config has feature flags, we need to call decide to get the feature flags\n // This completely separates it from the config logic which is good in terms of separation of concerns\n this.instance.featureFlags.ensureFlagsLoaded()\n }\n }\n}\n"]}
1
+ {"version":3,"file":"remote-config.js","sourceRoot":"","sources":["../../src/remote-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHog } from './posthog-core'\nimport { RemoteConfig } from './types'\n\nimport { createLogger } from './utils/logger'\nimport { assignableWindow } from './utils/globals'\n\nconst logger = createLogger('[Decide]')\n\nexport class RemoteConfigLoader {\n constructor(private readonly instance: PostHog) {}\n\n private _loadRemoteConfigJs(cb: (config?: RemoteConfig) => void): void {\n if (assignableWindow.__PosthogExtensions__?.loadExternalDependency) {\n assignableWindow.__PosthogExtensions__?.loadExternalDependency?.(this.instance, 'remote-config', () => {\n return cb(assignableWindow._POSTHOG_CONFIG)\n })\n } else {\n logger.error('PostHog Extensions not found. Cannot load remote config.')\n cb()\n }\n }\n\n private _loadRemoteConfigJSON(cb: (config?: RemoteConfig) => void): void {\n this.instance._send_request({\n method: 'GET',\n url: this.instance.requestRouter.endpointFor('assets', `/array/${this.instance.config.token}/config`),\n callback: (response) => {\n cb(response.json as RemoteConfig | undefined)\n },\n })\n }\n\n load(): void {\n try {\n // Attempt 1 - use the pre-loaded config if it came as part of the token-specific array.js\n if (assignableWindow._POSTHOG_CONFIG) {\n logger.info('Using preloaded remote config', assignableWindow._POSTHOG_CONFIG)\n this.onRemoteConfig(assignableWindow._POSTHOG_CONFIG)\n return\n }\n\n if (this.instance.config.advanced_disable_decide) {\n // This setting is essentially saying \"dont call external APIs\" hence we respect it here\n logger.warn('Remote config is disabled. Falling back to local config.')\n return\n }\n\n // Attempt 2 - if we have the external deps loader then lets load the script version of the config that includes site apps\n this._loadRemoteConfigJs((config) => {\n if (!config) {\n logger.info('No config found after loading remote JS config. Falling back to JSON.')\n // Attempt 3 Load the config json instead of the script - we won't get site apps etc. but we will get the config\n this._loadRemoteConfigJSON((config) => {\n this.onRemoteConfig(config)\n })\n return\n }\n\n this.onRemoteConfig(config)\n })\n } catch (error) {\n logger.error('Error loading remote config', error)\n }\n }\n\n private onRemoteConfig(config?: RemoteConfig): void {\n // NOTE: Once this is rolled out we will remove the \"decide\" related code above. Until then the code duplication is fine.\n if (!config) {\n logger.error('Failed to fetch remote config from PostHog.')\n return\n }\n\n if (!this.instance.config.__preview_remote_config) {\n logger.info('__preview_remote_config is disabled. Logging config instead', config)\n return\n }\n\n this.instance._onRemoteConfig(config)\n\n // We only need to reload if we haven't already loaded the flags or if the request is in flight\n if (config.hasFeatureFlags !== false) {\n // If the config has feature flags, we need to call decide to get the feature flags\n // This completely separates it from the config logic which is good in terms of separation of concerns\n this.instance.featureFlags.ensureFlagsLoaded()\n }\n }\n}\n"]}
@@ -15,6 +15,7 @@ export declare class SessionIdManager {
15
15
  private _sessionActivityTimestamp;
16
16
  private _sessionIdChangedHandlers;
17
17
  private readonly _sessionTimeoutMs;
18
+ private _enforceIdleTimeout;
18
19
  constructor(instance: PostHog, sessionIdGenerator?: () => string, windowIdGenerator?: () => string);
19
20
  get sessionTimeoutMs(): number;
20
21
  onSessionId(callback: SessionIdChangedCallback): () => void;
@@ -36,4 +37,5 @@ export declare class SessionIdManager {
36
37
  } | undefined;
37
38
  lastActivityTimestamp: number;
38
39
  };
40
+ private resetIdleTimer;
39
41
  }
@@ -49,6 +49,7 @@ var SessionIdManager = /** @class */ (function () {
49
49
  this._sessionTimeoutMs =
50
50
  clampToRange(desiredTimeout, MIN_SESSION_IDLE_TIMEOUT_SECONDS, MAX_SESSION_IDLE_TIMEOUT_SECONDS, 'session_idle_timeout_seconds', DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS) * 1000;
51
51
  instance.register({ $configured_session_timeout_ms: this._sessionTimeoutMs });
52
+ this.resetIdleTimer();
52
53
  this._window_id_storage_key = 'ph_' + persistenceName + '_window_id';
53
54
  this._primary_window_exists_storage_key = 'ph_' + persistenceName + '_primary_window_exists';
54
55
  // primary_window_exists is set when the DOM has been loaded and is cleared on unload
@@ -145,12 +146,12 @@ var SessionIdManager = /** @class */ (function () {
145
146
  if (this._sessionId && this._sessionActivityTimestamp && this._sessionStartTimestamp) {
146
147
  return [this._sessionActivityTimestamp, this._sessionId, this._sessionStartTimestamp];
147
148
  }
148
- var sessionId = this.persistence.props[SESSION_ID];
149
- if (isArray(sessionId) && sessionId.length === 2) {
149
+ var sessionIdInfo = this.persistence.props[SESSION_ID];
150
+ if (isArray(sessionIdInfo) && sessionIdInfo.length === 2) {
150
151
  // Storage does not yet have a session start time. Add the last activity timestamp as the start time
151
- sessionId.push(sessionId[0]);
152
+ sessionIdInfo.push(sessionIdInfo[0]);
152
153
  }
153
- return sessionId || [0, null, 0];
154
+ return sessionIdInfo || [0, null, 0];
154
155
  };
155
156
  // Resets the session id by setting it to null. On the subsequent call to checkAndGetSessionAndWindowId,
156
157
  // new ids will be generated.
@@ -195,14 +196,14 @@ var SessionIdManager = /** @class */ (function () {
195
196
  }
196
197
  var timestamp = _timestamp || new Date().getTime();
197
198
  // eslint-disable-next-line prefer-const
198
- var _a = __read(this._getSessionId(), 3), lastTimestamp = _a[0], sessionId = _a[1], startTimestamp = _a[2];
199
+ var _a = __read(this._getSessionId(), 3), lastActivityTimestamp = _a[0], sessionId = _a[1], startTimestamp = _a[2];
199
200
  var windowId = this._getWindowId();
200
201
  var sessionPastMaximumLength = isNumber(startTimestamp) &&
201
202
  startTimestamp > 0 &&
202
203
  Math.abs(timestamp - startTimestamp) > SESSION_LENGTH_LIMIT_MILLISECONDS;
203
204
  var valuesChanged = false;
204
205
  var noSessionId = !sessionId;
205
- var activityTimeout = !readOnly && Math.abs(timestamp - lastTimestamp) > this.sessionTimeoutMs;
206
+ var activityTimeout = !readOnly && Math.abs(timestamp - lastActivityTimestamp) > this.sessionTimeoutMs;
206
207
  if (noSessionId || activityTimeout || sessionPastMaximumLength) {
207
208
  sessionId = this._sessionIdGenerator();
208
209
  windowId = this._windowIdGenerator();
@@ -218,10 +219,13 @@ var SessionIdManager = /** @class */ (function () {
218
219
  windowId = this._windowIdGenerator();
219
220
  valuesChanged = true;
220
221
  }
221
- var newTimestamp = lastTimestamp === 0 || !readOnly || sessionPastMaximumLength ? timestamp : lastTimestamp;
222
+ var newActivityTimestamp = lastActivityTimestamp === 0 || !readOnly || sessionPastMaximumLength ? timestamp : lastActivityTimestamp;
222
223
  var sessionStartTimestamp = startTimestamp === 0 ? new Date().getTime() : startTimestamp;
223
224
  this._setWindowId(windowId);
224
- this._setSessionId(sessionId, newTimestamp, sessionStartTimestamp);
225
+ this._setSessionId(sessionId, newActivityTimestamp, sessionStartTimestamp);
226
+ if (!readOnly) {
227
+ this.resetIdleTimer();
228
+ }
225
229
  if (valuesChanged) {
226
230
  this._sessionIdChangedHandlers.forEach(function (handler) {
227
231
  return handler(sessionId, windowId, valuesChanged ? { noSessionId: noSessionId, activityTimeout: activityTimeout, sessionPastMaximumLength: sessionPastMaximumLength } : undefined);
@@ -232,9 +236,17 @@ var SessionIdManager = /** @class */ (function () {
232
236
  windowId: windowId,
233
237
  sessionStartTimestamp: sessionStartTimestamp,
234
238
  changeReason: valuesChanged ? { noSessionId: noSessionId, activityTimeout: activityTimeout, sessionPastMaximumLength: sessionPastMaximumLength } : undefined,
235
- lastActivityTimestamp: lastTimestamp,
239
+ lastActivityTimestamp: lastActivityTimestamp,
236
240
  };
237
241
  };
242
+ SessionIdManager.prototype.resetIdleTimer = function () {
243
+ var _this = this;
244
+ clearTimeout(this._enforceIdleTimeout);
245
+ this._enforceIdleTimeout = setTimeout(function () {
246
+ // enforce idle timeout a little after the session timeout to ensure the session is reset even without activity
247
+ _this.resetSessionId();
248
+ }, this.sessionTimeoutMs * 1.1);
249
+ };
238
250
  return SessionIdManager;
239
251
  }());
240
252
  export { SessionIdManager };
@@ -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 { isArray, isNumber, isUndefined } from './utils/type-utils'\nimport { createLogger } from './utils/logger'\n\nimport { clampToRange } from './utils/number-utils'\nimport { PostHog } from './posthog-core'\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 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.__preview_experimental_cookieless_mode) {\n throw new Error('SessionIdManager cannot be used with __preview_experimental_cookieless_mode')\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 'session_idle_timeout_seconds',\n DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS\n ) * 1000\n\n instance.register({ $configured_session_timeout_ms: this._sessionTimeoutMs })\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 sessionId = this.persistence.props[SESSION_ID]\n\n if (isArray(sessionId) && sessionId.length === 2) {\n // Storage does not yet have a session start time. Add the last activity timestamp as the start time\n sessionId.push(sessionId[0])\n }\n\n return sessionId || [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 window?.addEventListener('beforeunload', () => {\n if (this._canUseSessionStorage()) {\n sessionStore.remove(this._primary_window_exists_storage_key)\n }\n })\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.__preview_experimental_cookieless_mode) {\n throw new Error(\n 'checkAndGetSessionAndWindowId should not be called in __preview_experimental_cookieless_mode'\n )\n }\n const timestamp = _timestamp || new Date().getTime()\n\n // eslint-disable-next-line prefer-const\n let [lastTimestamp, 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 && Math.abs(timestamp - lastTimestamp) > this.sessionTimeoutMs\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 newTimestamp = lastTimestamp === 0 || !readOnly || sessionPastMaximumLength ? timestamp : lastTimestamp\n const sessionStartTimestamp = startTimestamp === 0 ? new Date().getTime() : startTimestamp\n\n this._setWindowId(windowId)\n this._setSessionId(sessionId, newTimestamp, sessionStartTimestamp)\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: lastTimestamp,\n }\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 { isArray, isNumber, isUndefined } from './utils/type-utils'\nimport { createLogger } from './utils/logger'\n\nimport { clampToRange } from './utils/number-utils'\nimport { PostHog } from './posthog-core'\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 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.__preview_experimental_cookieless_mode) {\n throw new Error('SessionIdManager cannot be used with __preview_experimental_cookieless_mode')\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 '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 window?.addEventListener('beforeunload', () => {\n if (this._canUseSessionStorage()) {\n sessionStore.remove(this._primary_window_exists_storage_key)\n }\n })\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.__preview_experimental_cookieless_mode) {\n throw new Error(\n 'checkAndGetSessionAndWindowId should not be called in __preview_experimental_cookieless_mode'\n )\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 && Math.abs(timestamp - lastActivityTimestamp) > this.sessionTimeoutMs\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 this.resetSessionId()\n }, this.sessionTimeoutMs * 1.1)\n }\n}\n"]}
@@ -11,7 +11,7 @@ export declare const knownUnsafeEditableEvent: readonly ["$snapshot", "$pageview
11
11
  *
12
12
  * Some features of PostHog rely on receiving 100% of these events
13
13
  */
14
- export type KnownUnsafeEditableEvent = typeof knownUnsafeEditableEvent[number];
14
+ export type KnownUnsafeEditableEvent = (typeof knownUnsafeEditableEvent)[number];
15
15
  /**
16
16
  * These are known events PostHog events that can be processed by the `beforeCapture` function
17
17
  * That means PostHog functionality does not rely on receiving 100% of these for calculations
@@ -601,7 +601,7 @@ export type ErrorMetadata = {
601
601
  defaultExceptionMessage?: string;
602
602
  };
603
603
  export declare const severityLevels: readonly ["fatal", "error", "warning", "log", "info", "debug"];
604
- export declare type SeverityLevel = typeof severityLevels[number];
604
+ export declare type SeverityLevel = (typeof severityLevels)[number];
605
605
  export interface ErrorProperties {
606
606
  $exception_type: string;
607
607
  $exception_message: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,IAAM,sBAAsB,GAAG,mBAAmB,CAAA;AAEzD,MAAM,CAAC,IAAM,wBAAwB,GAAG;IACpC,WAAW;IACX,WAAW;IACX,YAAY;IACZ,MAAM;IACN,kBAAkB;IAClB,aAAa;IACb,cAAc;IACd,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,4BAA4B;IAC5B,yBAAyB;IACzB,4BAA4B;IAC5B,sBAAsB;CAChB,CAAA;AAiaV,MAAM,CAAN,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,iCAAkB,CAAA;IAClB,gCAAiB,CAAA;AACrB,CAAC,EAHW,WAAW,KAAX,WAAW,QAGtB;AAyUD,2EAA2E;AAC3E,yEAAyE;AACzE,iFAAiF;AACjF,MAAM,CAAC,IAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA","sourcesContent":["import { PostHog } from './posthog-core'\nimport type { SegmentAnalytics } from './extensions/segment-integration'\nimport { recordOptions } from './extensions/replay/sessionrecording-utils'\n\nexport type Property = any\nexport type Properties = Record<string, Property>\n\nexport const COPY_AUTOCAPTURE_EVENT = '$copy_autocapture'\n\nexport const knownUnsafeEditableEvent = [\n '$snapshot',\n '$pageview',\n '$pageleave',\n '$set',\n 'survey dismissed',\n 'survey sent',\n 'survey shown',\n '$identify',\n '$groupidentify',\n '$create_alias',\n '$$client_ingestion_warning',\n '$web_experiment_applied',\n '$feature_enrollment_update',\n '$feature_flag_called',\n] as const\n\n/**\n * These events can be processed by the `beforeCapture` function\n * but can cause unexpected confusion in data.\n *\n * Some features of PostHog rely on receiving 100% of these events\n */\nexport type KnownUnsafeEditableEvent = typeof knownUnsafeEditableEvent[number]\n\n/**\n * These are known events PostHog events that can be processed by the `beforeCapture` function\n * That means PostHog functionality does not rely on receiving 100% of these for calculations\n * So, it is safe to sample them to reduce the volume of events sent to PostHog\n */\nexport type KnownEventName =\n | '$heatmaps_data'\n | '$opt_in'\n | '$exception'\n | '$$heatmap'\n | '$web_vitals'\n | '$dead_click'\n | '$autocapture'\n | typeof COPY_AUTOCAPTURE_EVENT\n | '$rageclick'\n\nexport type EventName =\n | KnownUnsafeEditableEvent\n | KnownEventName\n // magic value so that the type of EventName is a set of known strings or any other string\n // which means you get autocomplete for known strings\n // but no type complaints when you add an arbitrary string\n | (string & {})\n\nexport interface CaptureResult {\n uuid: string\n event: EventName\n properties: Properties\n $set?: Properties\n $set_once?: Properties\n timestamp?: Date\n}\n\nexport type AutocaptureCompatibleElement = 'a' | 'button' | 'form' | 'input' | 'select' | 'textarea' | 'label'\nexport type DomAutocaptureEvents = 'click' | 'change' | 'submit'\n\n/**\n * If an array is passed for an allowlist, autocapture events will only be sent for elements matching\n * at least one of the elements in the array. Multiple allowlists can be used\n */\nexport interface AutocaptureConfig {\n /**\n * List of URLs to allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on specific pages only\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_allowlist?: (string | RegExp)[]\n\n /**\n * List of URLs to not allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on most pages but not some specific ones\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_ignorelist?: (string | RegExp)[]\n\n /**\n * List of DOM events to allow autocapture on e.g. ['click', 'change', 'submit']\n */\n dom_event_allowlist?: DomAutocaptureEvents[]\n\n /**\n * List of DOM elements to allow autocapture on\n * e.g. ['a', 'button', 'form', 'input', 'select', 'textarea', 'label']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * if the allowlist has button then we allow the capture when the button or the svg is the click target\n * but not if either of the divs are detected as the click target\n */\n element_allowlist?: AutocaptureCompatibleElement[]\n\n /**\n * List of CSS selectors to allow autocapture on\n * e.g. ['[ph-capture]']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * and allow list config `['[id]']`\n * we will capture the click if the click-target or its parents has any id\n */\n css_selector_allowlist?: string[]\n\n /**\n * Exclude certain element attributes from autocapture\n * E.g. ['aria-label'] or [data-attr-pii]\n */\n element_attribute_ignorelist?: string[]\n\n capture_copied_text?: boolean\n}\n\nexport interface BootstrapConfig {\n distinctID?: string\n isIdentifiedID?: boolean\n featureFlags?: Record<string, boolean | string>\n featureFlagPayloads?: Record<string, JsonType>\n /**\n * Optionally provide a sessionID, this is so that you can provide an existing sessionID here to continue a user's session across a domain or device. It MUST be:\n * - unique to this user\n * - a valid UUID v7\n * - the timestamp part must be <= the timestamp of the first event in the session\n * - the timestamp of the last event in the session must be < the timestamp part + 24 hours\n * **/\n sessionID?: string\n}\n\nexport type SupportedWebVitalsMetrics = 'LCP' | 'CLS' | 'FCP' | 'INP'\n\nexport interface PerformanceCaptureConfig {\n /** works with session replay to use the browser's native performance observer to capture performance metrics */\n network_timing?: boolean\n /** use chrome's web vitals library to wrap fetch and capture web vitals */\n web_vitals?: boolean\n /**\n * We observe very large values reported by the Chrome web vitals library\n * These outliers are likely not real, useful values, and we exclude them\n * You can set this to 0 in order to include all values, NB this is not recommended\n * if not set this defaults to 15 minutes\n */\n __web_vitals_max_value?: number\n /**\n * By default all 4 metrics are captured\n * You can set this config to restrict which metrics are captured\n * e.g. ['CLS', 'FCP'] to only capture those two metrics\n * NB setting this does not override whether the capture is enabled\n */\n web_vitals_allowed_metrics?: SupportedWebVitalsMetrics[]\n /**\n * we delay flushing web vitals metrics to reduce the number of events we send\n * this is the maximum time we will wait before sending the metrics\n * if not set it defaults to 5 seconds\n */\n web_vitals_delayed_flush_ms?: number\n}\n\nexport interface DeadClickCandidate {\n node: Element\n originalEvent: MouseEvent\n timestamp: number\n // time between click and the most recent scroll\n scrollDelayMs?: number\n // time between click and the most recent mutation\n mutationDelayMs?: number\n // time between click and the most recent selection changed event\n selectionChangedDelayMs?: number\n // if neither scroll nor mutation seen before threshold passed\n absoluteDelayMs?: number\n}\n\nexport type DeadClicksAutoCaptureConfig = {\n // by default if a click is followed by a sroll within 100ms it is not a dead click\n scroll_threshold_ms?: number\n // by default if a click is followed by a selection change within 100ms it is not a dead click\n selection_change_threshold_ms?: number\n // by default if a click is followed by a mutation within 2500ms it is not a dead click\n mutation_threshold_ms?: number\n /**\n * Allows setting behavior for when a dead click is captured.\n * For e.g. to support capture to heatmaps\n *\n * If not provided the default behavior is to auto-capture dead click events\n *\n * Only intended to be provided by the SDK\n */\n __onCapture?: ((click: DeadClickCandidate, properties: Properties) => void) | undefined\n} & Pick<AutocaptureConfig, 'element_attribute_ignorelist'>\n\nexport interface HeatmapConfig {\n /*\n * how often to send batched data in $$heatmap_data events\n * if set to 0 or not set, sends using the default interval of 1 second\n * */\n flush_interval_milliseconds: number\n}\n\nexport type BeforeSendFn = (cr: CaptureResult | null) => CaptureResult | null\n\nexport interface PostHogConfig {\n api_host: string\n /** @deprecated - This property is no longer supported */\n api_method?: string\n api_transport?: 'XHR' | 'fetch'\n ui_host: string | null\n token: string\n autocapture: boolean | AutocaptureConfig\n rageclick: boolean\n cross_subdomain_cookie: boolean\n persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie' | 'sessionStorage'\n persistence_name: string\n /** @deprecated - Use 'persistence_name' instead */\n cookie_name?: string\n loaded: (posthog_instance: PostHog) => void\n store_google: boolean\n custom_campaign_params: string[]\n // a list of strings to be tested against navigator.userAgent to determine if the source is a bot\n // this is **added to** the default list of bots that we check\n // defaults to the empty array\n custom_blocked_useragents: string[]\n save_referrer: boolean\n verbose: boolean\n capture_pageview: boolean\n capture_pageleave: boolean | 'if_capture_pageview'\n debug: boolean\n cookie_expiration: number\n upgrade: boolean\n disable_session_recording: boolean\n disable_persistence: boolean\n /** @deprecated - use `disable_persistence` instead */\n disable_cookie?: boolean\n disable_surveys: boolean\n disable_web_experiments: boolean\n /** If set, posthog-js will never load external scripts such as those needed for Session Replay or Surveys. */\n disable_external_dependency_loading?: boolean\n enable_recording_console_log?: boolean\n secure_cookie: boolean\n ip: boolean\n /** Starts the SDK in an opted out state requiring opt_in_capturing() to be called before events will b captured */\n opt_out_capturing_by_default: boolean\n opt_out_capturing_persistence_type: 'localStorage' | 'cookie'\n /** If set to true this will disable persistence if the user is opted out of capturing. @default false */\n opt_out_persistence_by_default?: boolean\n /** Opt out of user agent filtering such as googlebot or other bots. Defaults to `false` */\n opt_out_useragent_filter: boolean\n\n opt_out_capturing_cookie_prefix: string | null\n opt_in_site_apps: boolean\n respect_dnt: boolean\n /** @deprecated - use `property_denylist` instead */\n property_blacklist?: string[]\n property_denylist: string[]\n request_headers: { [header_name: string]: string }\n on_request_error?: (error: RequestResponse) => void\n /** @deprecated - use `request_headers` instead */\n xhr_headers?: { [header_name: string]: string }\n /** @deprecated - use `on_request_error` instead */\n on_xhr_error?: (failedRequest: XMLHttpRequest) => void\n inapp_protocol: string\n inapp_link_new_window: boolean\n request_batching: boolean\n sanitize_properties: ((properties: Properties, event_name: string) => Properties) | null\n properties_string_max_length: number\n session_recording: SessionRecordingOptions\n session_idle_timeout_seconds: number\n mask_all_element_attributes: boolean\n mask_all_text: boolean\n advanced_disable_decide: boolean\n advanced_disable_feature_flags: boolean\n advanced_disable_feature_flags_on_first_load: boolean\n advanced_disable_toolbar_metrics: boolean\n feature_flag_request_timeout_ms: number\n get_device_id: (uuid: string) => string\n name: string\n /**\n * this is a read-only function that can be used to react to event capture\n * @deprecated - use `before_send` instead - NB before_send is not read only\n */\n _onCapture: (eventName: string, eventData: CaptureResult) => void\n /**\n * This function or array of functions - if provided - are called immediately before sending data to the server.\n * It allows you to edit data before it is sent, or choose not to send it all.\n * if provided as an array the functions are called in the order they are provided\n * any one function returning null means the event will not be sent\n */\n before_send?: BeforeSendFn | BeforeSendFn[]\n capture_performance?: boolean | PerformanceCaptureConfig\n // Should only be used for testing. Could negatively impact performance.\n disable_compression: boolean\n bootstrap: BootstrapConfig\n segment?: SegmentAnalytics\n __preview_send_client_session_params?: boolean\n /* @deprecated - use `capture_heatmaps` instead */\n enable_heatmaps?: boolean\n capture_heatmaps?: boolean | HeatmapConfig\n capture_dead_clicks?: boolean | DeadClicksAutoCaptureConfig\n disable_scroll_properties?: boolean\n // Let the pageview scroll stats use a custom css selector for the root element, e.g. `main`\n scroll_root_selector?: string | string[]\n\n /** You can control whether events from PostHog-js have person processing enabled with the `person_profiles` config setting. There are three options:\n * - `person_profiles: 'always'` _(default)_ - we will process persons data for all events\n * - `person_profiles: 'never'` - we won't process persons for any event. This means that anonymous users will not be merged once they sign up or login, so you lose the ability to create funnels that track users from anonymous to identified. All events (including `$identify`) will be sent with `$process_person_profile: False`.\n * - `person_profiles: 'identified_only'` - we will only process persons when you call `posthog.identify`, `posthog.alias`, `posthog.setPersonProperties`, `posthog.group`, `posthog.setPersonPropertiesForFlags` or `posthog.setGroupPropertiesForFlags` Anonymous users won't get person profiles.\n */\n person_profiles?: 'always' | 'never' | 'identified_only'\n /** @deprecated - use `person_profiles` instead */\n process_person?: 'always' | 'never' | 'identified_only'\n\n /** Client side rate limiting */\n rate_limiting?: {\n /** The average number of events per second that should be permitted (defaults to 10) */\n events_per_second?: number\n /** How many events can be captured in a burst. This defaults to 10 times the events_per_second count */\n events_burst_limit?: number\n }\n\n /** Used when sending data via `fetch`, use with care, this is intentionally meant to be used with NextJS `fetch`\n * Incorrect usage may cause out-of-date data for feature flags, actions tracking, etc.\n * See https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options\n */\n fetch_options?: {\n cache?: RequestInit['cache']\n next_options?: NextOptions\n }\n\n /**\n * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION\n * whether to wrap fetch and add tracing headers to the request\n * */\n __add_tracing_headers?: boolean\n\n /**\n * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION\n * enables the new RemoteConfig approach to loading config instead of decide\n * */\n __preview_remote_config?: boolean\n\n /**\n * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION\n * whether to send a sentinel value for distinct id, device id, and session id, which will be replaced server-side by a cookieless hash\n * */\n __preview_experimental_cookieless_mode?: boolean\n}\n\nexport interface OptInOutCapturingOptions {\n capture: (event: string, properties: Properties, options: CaptureOptions) => void\n capture_event_name: string\n capture_properties: Properties\n enable_persistence: boolean\n clear_persistence: boolean\n persistence_type: 'cookie' | 'localStorage' | 'localStorage+cookie'\n cookie_prefix: string\n cookie_expiration: number\n cross_subdomain_cookie: boolean\n secure_cookie: boolean\n}\n\nexport interface IsFeatureEnabledOptions {\n send_event: boolean\n}\n\nexport interface SessionRecordingOptions {\n blockClass?: string | RegExp\n blockSelector?: string | null\n ignoreClass?: string\n maskTextClass?: string | RegExp\n maskTextSelector?: string | null\n maskTextFn?: ((text: string, element: HTMLElement | null) => string) | null\n maskAllInputs?: boolean\n maskInputOptions?: recordOptions['maskInputOptions']\n maskInputFn?: ((text: string, element?: HTMLElement) => string) | null\n slimDOMOptions?: recordOptions['slimDOMOptions']\n collectFonts?: boolean\n inlineStylesheet?: boolean\n recordCrossOriginIframes?: boolean\n /**\n * Allows local config to override remote canvas recording settings from the decide response\n */\n captureCanvas?: SessionRecordingCanvasOptions\n /** @deprecated - use maskCapturedNetworkRequestFn instead */\n maskNetworkRequestFn?: ((data: NetworkRequest) => NetworkRequest | null | undefined) | null\n /** Modify the network request before it is captured. Returning null or undefined stops it being captured */\n maskCapturedNetworkRequestFn?: ((data: CapturedNetworkRequest) => CapturedNetworkRequest | null | undefined) | null\n // our settings here only support a subset of those proposed for rrweb's network capture plugin\n recordHeaders?: boolean\n recordBody?: boolean\n // ADVANCED: while a user is active we take a full snapshot of the browser every interval. For very few sites playback performance might be better with different interval. Set to 0 to disable\n full_snapshot_interval_millis?: number\n /*\n ADVANCED: whether to partially compress rrweb events before sending them to the server,\n defaults to true, can be set to false to disable partial compression\n NB requests are still compressed when sent to the server regardless of this setting\n */\n compress_events?: boolean\n /*\n ADVANCED: alters the threshold before a recording considers a user has become idle.\n Normally only altered alongside changes to session_idle_timeout_ms.\n Default is 5 minutes.\n */\n session_idle_threshold_ms?: number\n /*\n ADVANCED: alters the refill rate for the token bucket mutation throttling\n Normally only altered alongside posthog support guidance.\n Accepts values between 0 and 100\n Default is 10.\n */\n __mutationRateLimiterRefillRate?: number\n /*\n ADVANCED: alters the bucket size for the token bucket mutation throttling\n Normally only altered alongside posthog support guidance.\n Accepts values between 0 and 100\n Default is 100.\n */\n __mutationRateLimiterBucketSize?: number\n}\n\nexport type SessionIdChangedCallback = (\n sessionId: string,\n windowId: string | null | undefined,\n changeReason?: { noSessionId: boolean; activityTimeout: boolean; sessionPastMaximumLength: boolean }\n) => void\n\nexport enum Compression {\n GZipJS = 'gzip-js',\n Base64 = 'base64',\n}\n\n// Request types - these should be kept minimal to what request.ts needs\n\n// Minimal class to allow interop between different request methods (xhr / fetch)\nexport interface RequestResponse {\n statusCode: number\n text?: string\n json?: any\n}\n\nexport type RequestCallback = (response: RequestResponse) => void\n\n// See https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options\ntype NextOptions = { revalidate: false | 0 | number; tags: string[] }\n\nexport interface RequestOptions {\n url: string\n // Data can be a single object or an array of objects when batched\n data?: Record<string, any> | Record<string, any>[]\n headers?: Record<string, any>\n transport?: 'XHR' | 'fetch' | 'sendBeacon'\n method?: 'POST' | 'GET'\n urlQueryArgs?: { compression: Compression }\n callback?: RequestCallback\n timeout?: number\n noRetries?: boolean\n compression?: Compression | 'best-available'\n fetchOptions?: {\n cache?: RequestInit['cache']\n next?: NextOptions\n }\n}\n\n// Queued request types - the same as a request but with additional queueing information\n\nexport interface QueuedRequestOptions extends RequestOptions {\n batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n}\n\n// Used explicitly for retriable requests\nexport interface RetriableRequestOptions extends QueuedRequestOptions {\n retriesPerformedSoFar?: number\n}\n\nexport interface CaptureOptions {\n $set?: Properties /** used with $identify */\n $set_once?: Properties /** used with $identify */\n _url?: string /** Used to override the desired endpoint for the captured event */\n _batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n _noTruncate?: boolean /** if set, overrides and disables config.properties_string_max_length */\n send_instantly?: boolean /** if set skips the batched queue */\n skip_client_rate_limiting?: boolean /** if set skips the client side rate limiting */\n transport?: RequestOptions['transport'] /** if set, overrides the desired transport method */\n timestamp?: Date\n}\n\nexport type FlagVariant = { flag: string; variant: string }\n\nexport type SessionRecordingCanvasOptions = {\n recordCanvas?: boolean | null\n canvasFps?: number | null\n // the API returns a decimal between 0 and 1 as a string\n canvasQuality?: string | null\n}\n\nexport interface RemoteConfig {\n supportedCompression: Compression[]\n autocapture_opt_out?: boolean\n /**\n * originally capturePerformance was replay only and so boolean true\n * is equivalent to { network_timing: true }\n * now capture performance can be separately enabled within replay\n * and as a standalone web vitals tracker\n * people can have them enabled separately\n * they work standalone but enhance each other\n * TODO: deprecate this so we make a new config that doesn't need this explanation\n */\n capturePerformance?: boolean | PerformanceCaptureConfig\n analytics?: {\n endpoint?: string\n }\n elementsChainAsString?: boolean\n // this is currently in development and may have breaking changes without a major version bump\n autocaptureExceptions?:\n | boolean\n | {\n endpoint?: string\n }\n sessionRecording?: SessionRecordingCanvasOptions & {\n endpoint?: string\n consoleLogRecordingEnabled?: boolean\n // the API returns a decimal between 0 and 1 as a string\n sampleRate?: string | null\n minimumDurationMilliseconds?: number\n linkedFlag?: string | FlagVariant | null\n networkPayloadCapture?: Pick<NetworkRecordOptions, 'recordBody' | 'recordHeaders'>\n urlTriggers?: SessionRecordingUrlTrigger[]\n scriptConfig?: { script?: string | undefined }\n urlBlocklist?: SessionRecordingUrlTrigger[]\n eventTriggers?: string[]\n }\n surveys?: boolean\n toolbarParams: ToolbarParams\n editorParams?: ToolbarParams /** @deprecated, renamed to toolbarParams, still present on older API responses */\n toolbarVersion: 'toolbar' /** @deprecated, moved to toolbarParams */\n isAuthenticated: boolean\n siteApps: { id: string; url: string }[]\n heatmaps?: boolean\n defaultIdentifiedOnly?: boolean\n captureDeadClicks?: boolean\n hasFeatureFlags?: boolean // Indicates if the team has any flags enabled (if not we don't need to load them)\n}\n\nexport interface DecideResponse extends RemoteConfig {\n featureFlags: Record<string, string | boolean>\n featureFlagPayloads: Record<string, JsonType>\n errorsWhileComputingFlags: boolean\n}\n\nexport type SiteAppGlobals = {\n event: {\n uuid: string\n event: EventName\n properties: Properties\n timestamp?: Date\n elements_chain?: string\n distinct_id?: string\n }\n person: {\n properties: Properties\n }\n groups: Record<string, { id: string; type: string; properties: Properties }>\n}\n\nexport type SiteAppLoader = {\n id: string\n init: (config: { posthog: PostHog; callback: (success: boolean) => void }) => {\n processEvent?: (globals: SiteAppGlobals) => void\n }\n}\n\nexport type SiteApp = {\n id: string\n loaded: boolean\n errored: boolean\n processEvent?: (globals: SiteAppGlobals) => void\n}\n\nexport type FeatureFlagsCallback = (\n flags: string[],\n variants: Record<string, string | boolean>,\n context?: {\n errorsLoading?: boolean\n }\n) => void\n\nexport interface PersistentStore {\n is_supported: () => boolean\n error: (error: any) => void\n parse: (name: string) => any\n get: (name: string) => any\n set: (\n name: string,\n value: any,\n expire_days?: number | null,\n cross_subdomain?: boolean,\n secure?: boolean,\n debug?: boolean\n ) => void\n remove: (name: string, cross_subdomain?: boolean) => void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Breaker = {}\nexport type EventHandler = (event: Event) => boolean | void\n\nexport type ToolbarUserIntent = 'add-action' | 'edit-action'\nexport type ToolbarSource = 'url' | 'localstorage'\nexport type ToolbarVersion = 'toolbar'\n\n/* sync with posthog */\nexport interface ToolbarParams {\n token?: string /** public posthog-js token */\n temporaryToken?: string /** private temporary user token */\n actionId?: number\n userIntent?: ToolbarUserIntent\n source?: ToolbarSource\n toolbarVersion?: ToolbarVersion\n instrument?: boolean\n distinctId?: string\n userEmail?: string\n dataAttributes?: string[]\n featureFlags?: Record<string, string | boolean>\n}\n\nexport type SnippetArrayItem = [method: string, ...args: any[]]\n\nexport type JsonRecord = { [key: string]: JsonType }\nexport type JsonType = string | number | boolean | null | JsonRecord | Array<JsonType>\n\n/** A feature that isn't publicly available yet.*/\nexport interface EarlyAccessFeature {\n // Sync this with the backend's EarlyAccessFeatureSerializer!\n name: string\n description: string\n stage: 'concept' | 'alpha' | 'beta'\n documentationUrl: string | null\n flagKey: string | null\n}\n\nexport type EarlyAccessFeatureCallback = (earlyAccessFeatures: EarlyAccessFeature[]) => void\n\nexport interface EarlyAccessFeatureResponse {\n earlyAccessFeatures: EarlyAccessFeature[]\n}\n\nexport type Headers = Record<string, string>\n\n/* for rrweb/network@1\n ** when that is released as part of rrweb this can be removed\n ** don't rely on this type, it may change without notice\n */\nexport type InitiatorType =\n | 'audio'\n | 'beacon'\n | 'body'\n | 'css'\n | 'early-hint'\n | 'embed'\n | 'fetch'\n | 'frame'\n | 'iframe'\n | 'icon'\n | 'image'\n | 'img'\n | 'input'\n | 'link'\n | 'navigation'\n | 'object'\n | 'ping'\n | 'script'\n | 'track'\n | 'video'\n | 'xmlhttprequest'\n\nexport type NetworkRecordOptions = {\n initiatorTypes?: InitiatorType[]\n maskRequestFn?: (data: CapturedNetworkRequest) => CapturedNetworkRequest | undefined\n recordHeaders?: boolean | { request: boolean; response: boolean }\n recordBody?: boolean | string[] | { request: boolean | string[]; response: boolean | string[] }\n recordInitialRequests?: boolean\n /**\n * whether to record PerformanceEntry events for network requests\n */\n recordPerformance?: boolean\n /**\n * the PerformanceObserver will only observe these entry types\n */\n performanceEntryTypeToObserve: string[]\n /**\n * the maximum size of the request/response body to record\n * NB this will be at most 1MB even if set larger\n */\n payloadSizeLimitBytes: number\n /**\n * some domains we should never record the payload\n * for example other companies session replay ingestion payloads aren't super useful but are gigantic\n * if this isn't provided we use a default list\n * if this is provided - we add the provided list to the default list\n * i.e. we never record the payloads on the default deny list\n */\n payloadHostDenyList?: string[]\n}\n\n/** @deprecated - use CapturedNetworkRequest instead */\nexport type NetworkRequest = {\n url: string\n}\n\n// In rrweb this is called NetworkRequest, but we already exposed that as having only URL\n// we also want to vary from the rrweb NetworkRequest because we want to include\n// all PerformanceEntry properties too.\n// that has 4 required properties\n// readonly duration: DOMHighResTimeStamp;\n// readonly entryType: string;\n// readonly name: string;\n// readonly startTime: DOMHighResTimeStamp;\n// NB: properties below here are ALPHA, don't rely on them, they may change without notice\n\n// we mirror PerformanceEntry since we read into this type from a PerformanceObserver,\n// but we don't want to inherit its readonly-iness\ntype Writable<T> = { -readonly [P in keyof T]: T[P] }\n\nexport type CapturedNetworkRequest = Writable<Omit<PerformanceEntry, 'toJSON'>> & {\n // properties below here are ALPHA, don't rely on them, they may change without notice\n method?: string\n initiatorType?: InitiatorType\n status?: number\n timeOrigin?: number\n timestamp?: number\n startTime?: number\n endTime?: number\n requestHeaders?: Headers\n requestBody?: string | null\n responseHeaders?: Headers\n responseBody?: string | null\n // was this captured before fetch/xhr could have been wrapped\n isInitial?: boolean\n}\n\nexport type ErrorEventArgs = [\n event: string | Event,\n source?: string | undefined,\n lineno?: number | undefined,\n colno?: number | undefined,\n error?: Error | undefined\n]\n\nexport type ErrorMetadata = {\n handled?: boolean\n synthetic?: boolean\n syntheticException?: Error\n overrideExceptionType?: string\n overrideExceptionMessage?: string\n defaultExceptionType?: string\n defaultExceptionMessage?: string\n}\n\n// levels originally copied from Sentry to work with the sentry integration\n// and to avoid relying on a frequently changing @sentry/types dependency\n// but provided as an array of literal types, so we can constrain the level below\nexport const severityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug'] as const\nexport declare type SeverityLevel = typeof severityLevels[number]\n\nexport interface ErrorProperties {\n $exception_type: string\n $exception_message: string\n $exception_level: SeverityLevel\n $exception_source?: string\n $exception_lineno?: number\n $exception_colno?: number\n $exception_DOMException_code?: string\n $exception_is_synthetic?: boolean\n $exception_stack_trace_raw?: string\n $exception_handled?: boolean\n $exception_personURL?: string\n}\n\nexport interface ErrorConversions {\n errorToProperties: (args: ErrorEventArgs) => ErrorProperties\n unhandledRejectionToProperties: (args: [ev: PromiseRejectionEvent]) => ErrorProperties\n}\n\nexport interface SessionRecordingUrlTrigger {\n url: string\n matching: 'regex'\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,IAAM,sBAAsB,GAAG,mBAAmB,CAAA;AAEzD,MAAM,CAAC,IAAM,wBAAwB,GAAG;IACpC,WAAW;IACX,WAAW;IACX,YAAY;IACZ,MAAM;IACN,kBAAkB;IAClB,aAAa;IACb,cAAc;IACd,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,4BAA4B;IAC5B,yBAAyB;IACzB,4BAA4B;IAC5B,sBAAsB;CAChB,CAAA;AAiaV,MAAM,CAAN,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,iCAAkB,CAAA;IAClB,gCAAiB,CAAA;AACrB,CAAC,EAHW,WAAW,KAAX,WAAW,QAGtB;AAyUD,2EAA2E;AAC3E,yEAAyE;AACzE,iFAAiF;AACjF,MAAM,CAAC,IAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA","sourcesContent":["import { PostHog } from './posthog-core'\nimport type { SegmentAnalytics } from './extensions/segment-integration'\nimport { recordOptions } from './extensions/replay/sessionrecording-utils'\n\nexport type Property = any\nexport type Properties = Record<string, Property>\n\nexport const COPY_AUTOCAPTURE_EVENT = '$copy_autocapture'\n\nexport const knownUnsafeEditableEvent = [\n '$snapshot',\n '$pageview',\n '$pageleave',\n '$set',\n 'survey dismissed',\n 'survey sent',\n 'survey shown',\n '$identify',\n '$groupidentify',\n '$create_alias',\n '$$client_ingestion_warning',\n '$web_experiment_applied',\n '$feature_enrollment_update',\n '$feature_flag_called',\n] as const\n\n/**\n * These events can be processed by the `beforeCapture` function\n * but can cause unexpected confusion in data.\n *\n * Some features of PostHog rely on receiving 100% of these events\n */\nexport type KnownUnsafeEditableEvent = (typeof knownUnsafeEditableEvent)[number]\n\n/**\n * These are known events PostHog events that can be processed by the `beforeCapture` function\n * That means PostHog functionality does not rely on receiving 100% of these for calculations\n * So, it is safe to sample them to reduce the volume of events sent to PostHog\n */\nexport type KnownEventName =\n | '$heatmaps_data'\n | '$opt_in'\n | '$exception'\n | '$$heatmap'\n | '$web_vitals'\n | '$dead_click'\n | '$autocapture'\n | typeof COPY_AUTOCAPTURE_EVENT\n | '$rageclick'\n\nexport type EventName =\n | KnownUnsafeEditableEvent\n | KnownEventName\n // magic value so that the type of EventName is a set of known strings or any other string\n // which means you get autocomplete for known strings\n // but no type complaints when you add an arbitrary string\n | (string & {})\n\nexport interface CaptureResult {\n uuid: string\n event: EventName\n properties: Properties\n $set?: Properties\n $set_once?: Properties\n timestamp?: Date\n}\n\nexport type AutocaptureCompatibleElement = 'a' | 'button' | 'form' | 'input' | 'select' | 'textarea' | 'label'\nexport type DomAutocaptureEvents = 'click' | 'change' | 'submit'\n\n/**\n * If an array is passed for an allowlist, autocapture events will only be sent for elements matching\n * at least one of the elements in the array. Multiple allowlists can be used\n */\nexport interface AutocaptureConfig {\n /**\n * List of URLs to allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on specific pages only\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_allowlist?: (string | RegExp)[]\n\n /**\n * List of URLs to not allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on most pages but not some specific ones\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_ignorelist?: (string | RegExp)[]\n\n /**\n * List of DOM events to allow autocapture on e.g. ['click', 'change', 'submit']\n */\n dom_event_allowlist?: DomAutocaptureEvents[]\n\n /**\n * List of DOM elements to allow autocapture on\n * e.g. ['a', 'button', 'form', 'input', 'select', 'textarea', 'label']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * if the allowlist has button then we allow the capture when the button or the svg is the click target\n * but not if either of the divs are detected as the click target\n */\n element_allowlist?: AutocaptureCompatibleElement[]\n\n /**\n * List of CSS selectors to allow autocapture on\n * e.g. ['[ph-capture]']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * and allow list config `['[id]']`\n * we will capture the click if the click-target or its parents has any id\n */\n css_selector_allowlist?: string[]\n\n /**\n * Exclude certain element attributes from autocapture\n * E.g. ['aria-label'] or [data-attr-pii]\n */\n element_attribute_ignorelist?: string[]\n\n capture_copied_text?: boolean\n}\n\nexport interface BootstrapConfig {\n distinctID?: string\n isIdentifiedID?: boolean\n featureFlags?: Record<string, boolean | string>\n featureFlagPayloads?: Record<string, JsonType>\n /**\n * Optionally provide a sessionID, this is so that you can provide an existing sessionID here to continue a user's session across a domain or device. It MUST be:\n * - unique to this user\n * - a valid UUID v7\n * - the timestamp part must be <= the timestamp of the first event in the session\n * - the timestamp of the last event in the session must be < the timestamp part + 24 hours\n * **/\n sessionID?: string\n}\n\nexport type SupportedWebVitalsMetrics = 'LCP' | 'CLS' | 'FCP' | 'INP'\n\nexport interface PerformanceCaptureConfig {\n /** works with session replay to use the browser's native performance observer to capture performance metrics */\n network_timing?: boolean\n /** use chrome's web vitals library to wrap fetch and capture web vitals */\n web_vitals?: boolean\n /**\n * We observe very large values reported by the Chrome web vitals library\n * These outliers are likely not real, useful values, and we exclude them\n * You can set this to 0 in order to include all values, NB this is not recommended\n * if not set this defaults to 15 minutes\n */\n __web_vitals_max_value?: number\n /**\n * By default all 4 metrics are captured\n * You can set this config to restrict which metrics are captured\n * e.g. ['CLS', 'FCP'] to only capture those two metrics\n * NB setting this does not override whether the capture is enabled\n */\n web_vitals_allowed_metrics?: SupportedWebVitalsMetrics[]\n /**\n * we delay flushing web vitals metrics to reduce the number of events we send\n * this is the maximum time we will wait before sending the metrics\n * if not set it defaults to 5 seconds\n */\n web_vitals_delayed_flush_ms?: number\n}\n\nexport interface DeadClickCandidate {\n node: Element\n originalEvent: MouseEvent\n timestamp: number\n // time between click and the most recent scroll\n scrollDelayMs?: number\n // time between click and the most recent mutation\n mutationDelayMs?: number\n // time between click and the most recent selection changed event\n selectionChangedDelayMs?: number\n // if neither scroll nor mutation seen before threshold passed\n absoluteDelayMs?: number\n}\n\nexport type DeadClicksAutoCaptureConfig = {\n // by default if a click is followed by a sroll within 100ms it is not a dead click\n scroll_threshold_ms?: number\n // by default if a click is followed by a selection change within 100ms it is not a dead click\n selection_change_threshold_ms?: number\n // by default if a click is followed by a mutation within 2500ms it is not a dead click\n mutation_threshold_ms?: number\n /**\n * Allows setting behavior for when a dead click is captured.\n * For e.g. to support capture to heatmaps\n *\n * If not provided the default behavior is to auto-capture dead click events\n *\n * Only intended to be provided by the SDK\n */\n __onCapture?: ((click: DeadClickCandidate, properties: Properties) => void) | undefined\n} & Pick<AutocaptureConfig, 'element_attribute_ignorelist'>\n\nexport interface HeatmapConfig {\n /*\n * how often to send batched data in $$heatmap_data events\n * if set to 0 or not set, sends using the default interval of 1 second\n * */\n flush_interval_milliseconds: number\n}\n\nexport type BeforeSendFn = (cr: CaptureResult | null) => CaptureResult | null\n\nexport interface PostHogConfig {\n api_host: string\n /** @deprecated - This property is no longer supported */\n api_method?: string\n api_transport?: 'XHR' | 'fetch'\n ui_host: string | null\n token: string\n autocapture: boolean | AutocaptureConfig\n rageclick: boolean\n cross_subdomain_cookie: boolean\n persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie' | 'sessionStorage'\n persistence_name: string\n /** @deprecated - Use 'persistence_name' instead */\n cookie_name?: string\n loaded: (posthog_instance: PostHog) => void\n store_google: boolean\n custom_campaign_params: string[]\n // a list of strings to be tested against navigator.userAgent to determine if the source is a bot\n // this is **added to** the default list of bots that we check\n // defaults to the empty array\n custom_blocked_useragents: string[]\n save_referrer: boolean\n verbose: boolean\n capture_pageview: boolean\n capture_pageleave: boolean | 'if_capture_pageview'\n debug: boolean\n cookie_expiration: number\n upgrade: boolean\n disable_session_recording: boolean\n disable_persistence: boolean\n /** @deprecated - use `disable_persistence` instead */\n disable_cookie?: boolean\n disable_surveys: boolean\n disable_web_experiments: boolean\n /** If set, posthog-js will never load external scripts such as those needed for Session Replay or Surveys. */\n disable_external_dependency_loading?: boolean\n enable_recording_console_log?: boolean\n secure_cookie: boolean\n ip: boolean\n /** Starts the SDK in an opted out state requiring opt_in_capturing() to be called before events will b captured */\n opt_out_capturing_by_default: boolean\n opt_out_capturing_persistence_type: 'localStorage' | 'cookie'\n /** If set to true this will disable persistence if the user is opted out of capturing. @default false */\n opt_out_persistence_by_default?: boolean\n /** Opt out of user agent filtering such as googlebot or other bots. Defaults to `false` */\n opt_out_useragent_filter: boolean\n\n opt_out_capturing_cookie_prefix: string | null\n opt_in_site_apps: boolean\n respect_dnt: boolean\n /** @deprecated - use `property_denylist` instead */\n property_blacklist?: string[]\n property_denylist: string[]\n request_headers: { [header_name: string]: string }\n on_request_error?: (error: RequestResponse) => void\n /** @deprecated - use `request_headers` instead */\n xhr_headers?: { [header_name: string]: string }\n /** @deprecated - use `on_request_error` instead */\n on_xhr_error?: (failedRequest: XMLHttpRequest) => void\n inapp_protocol: string\n inapp_link_new_window: boolean\n request_batching: boolean\n sanitize_properties: ((properties: Properties, event_name: string) => Properties) | null\n properties_string_max_length: number\n session_recording: SessionRecordingOptions\n session_idle_timeout_seconds: number\n mask_all_element_attributes: boolean\n mask_all_text: boolean\n advanced_disable_decide: boolean\n advanced_disable_feature_flags: boolean\n advanced_disable_feature_flags_on_first_load: boolean\n advanced_disable_toolbar_metrics: boolean\n feature_flag_request_timeout_ms: number\n get_device_id: (uuid: string) => string\n name: string\n /**\n * this is a read-only function that can be used to react to event capture\n * @deprecated - use `before_send` instead - NB before_send is not read only\n */\n _onCapture: (eventName: string, eventData: CaptureResult) => void\n /**\n * This function or array of functions - if provided - are called immediately before sending data to the server.\n * It allows you to edit data before it is sent, or choose not to send it all.\n * if provided as an array the functions are called in the order they are provided\n * any one function returning null means the event will not be sent\n */\n before_send?: BeforeSendFn | BeforeSendFn[]\n capture_performance?: boolean | PerformanceCaptureConfig\n // Should only be used for testing. Could negatively impact performance.\n disable_compression: boolean\n bootstrap: BootstrapConfig\n segment?: SegmentAnalytics\n __preview_send_client_session_params?: boolean\n /* @deprecated - use `capture_heatmaps` instead */\n enable_heatmaps?: boolean\n capture_heatmaps?: boolean | HeatmapConfig\n capture_dead_clicks?: boolean | DeadClicksAutoCaptureConfig\n disable_scroll_properties?: boolean\n // Let the pageview scroll stats use a custom css selector for the root element, e.g. `main`\n scroll_root_selector?: string | string[]\n\n /** You can control whether events from PostHog-js have person processing enabled with the `person_profiles` config setting. There are three options:\n * - `person_profiles: 'always'` _(default)_ - we will process persons data for all events\n * - `person_profiles: 'never'` - we won't process persons for any event. This means that anonymous users will not be merged once they sign up or login, so you lose the ability to create funnels that track users from anonymous to identified. All events (including `$identify`) will be sent with `$process_person_profile: False`.\n * - `person_profiles: 'identified_only'` - we will only process persons when you call `posthog.identify`, `posthog.alias`, `posthog.setPersonProperties`, `posthog.group`, `posthog.setPersonPropertiesForFlags` or `posthog.setGroupPropertiesForFlags` Anonymous users won't get person profiles.\n */\n person_profiles?: 'always' | 'never' | 'identified_only'\n /** @deprecated - use `person_profiles` instead */\n process_person?: 'always' | 'never' | 'identified_only'\n\n /** Client side rate limiting */\n rate_limiting?: {\n /** The average number of events per second that should be permitted (defaults to 10) */\n events_per_second?: number\n /** How many events can be captured in a burst. This defaults to 10 times the events_per_second count */\n events_burst_limit?: number\n }\n\n /** Used when sending data via `fetch`, use with care, this is intentionally meant to be used with NextJS `fetch`\n * Incorrect usage may cause out-of-date data for feature flags, actions tracking, etc.\n * See https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options\n */\n fetch_options?: {\n cache?: RequestInit['cache']\n next_options?: NextOptions\n }\n\n /**\n * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION\n * whether to wrap fetch and add tracing headers to the request\n * */\n __add_tracing_headers?: boolean\n\n /**\n * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION\n * enables the new RemoteConfig approach to loading config instead of decide\n * */\n __preview_remote_config?: boolean\n\n /**\n * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION\n * whether to send a sentinel value for distinct id, device id, and session id, which will be replaced server-side by a cookieless hash\n * */\n __preview_experimental_cookieless_mode?: boolean\n}\n\nexport interface OptInOutCapturingOptions {\n capture: (event: string, properties: Properties, options: CaptureOptions) => void\n capture_event_name: string\n capture_properties: Properties\n enable_persistence: boolean\n clear_persistence: boolean\n persistence_type: 'cookie' | 'localStorage' | 'localStorage+cookie'\n cookie_prefix: string\n cookie_expiration: number\n cross_subdomain_cookie: boolean\n secure_cookie: boolean\n}\n\nexport interface IsFeatureEnabledOptions {\n send_event: boolean\n}\n\nexport interface SessionRecordingOptions {\n blockClass?: string | RegExp\n blockSelector?: string | null\n ignoreClass?: string\n maskTextClass?: string | RegExp\n maskTextSelector?: string | null\n maskTextFn?: ((text: string, element: HTMLElement | null) => string) | null\n maskAllInputs?: boolean\n maskInputOptions?: recordOptions['maskInputOptions']\n maskInputFn?: ((text: string, element?: HTMLElement) => string) | null\n slimDOMOptions?: recordOptions['slimDOMOptions']\n collectFonts?: boolean\n inlineStylesheet?: boolean\n recordCrossOriginIframes?: boolean\n /**\n * Allows local config to override remote canvas recording settings from the decide response\n */\n captureCanvas?: SessionRecordingCanvasOptions\n /** @deprecated - use maskCapturedNetworkRequestFn instead */\n maskNetworkRequestFn?: ((data: NetworkRequest) => NetworkRequest | null | undefined) | null\n /** Modify the network request before it is captured. Returning null or undefined stops it being captured */\n maskCapturedNetworkRequestFn?: ((data: CapturedNetworkRequest) => CapturedNetworkRequest | null | undefined) | null\n // our settings here only support a subset of those proposed for rrweb's network capture plugin\n recordHeaders?: boolean\n recordBody?: boolean\n // ADVANCED: while a user is active we take a full snapshot of the browser every interval. For very few sites playback performance might be better with different interval. Set to 0 to disable\n full_snapshot_interval_millis?: number\n /*\n ADVANCED: whether to partially compress rrweb events before sending them to the server,\n defaults to true, can be set to false to disable partial compression\n NB requests are still compressed when sent to the server regardless of this setting\n */\n compress_events?: boolean\n /*\n ADVANCED: alters the threshold before a recording considers a user has become idle.\n Normally only altered alongside changes to session_idle_timeout_ms.\n Default is 5 minutes.\n */\n session_idle_threshold_ms?: number\n /*\n ADVANCED: alters the refill rate for the token bucket mutation throttling\n Normally only altered alongside posthog support guidance.\n Accepts values between 0 and 100\n Default is 10.\n */\n __mutationRateLimiterRefillRate?: number\n /*\n ADVANCED: alters the bucket size for the token bucket mutation throttling\n Normally only altered alongside posthog support guidance.\n Accepts values between 0 and 100\n Default is 100.\n */\n __mutationRateLimiterBucketSize?: number\n}\n\nexport type SessionIdChangedCallback = (\n sessionId: string,\n windowId: string | null | undefined,\n changeReason?: { noSessionId: boolean; activityTimeout: boolean; sessionPastMaximumLength: boolean }\n) => void\n\nexport enum Compression {\n GZipJS = 'gzip-js',\n Base64 = 'base64',\n}\n\n// Request types - these should be kept minimal to what request.ts needs\n\n// Minimal class to allow interop between different request methods (xhr / fetch)\nexport interface RequestResponse {\n statusCode: number\n text?: string\n json?: any\n}\n\nexport type RequestCallback = (response: RequestResponse) => void\n\n// See https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options\ntype NextOptions = { revalidate: false | 0 | number; tags: string[] }\n\nexport interface RequestOptions {\n url: string\n // Data can be a single object or an array of objects when batched\n data?: Record<string, any> | Record<string, any>[]\n headers?: Record<string, any>\n transport?: 'XHR' | 'fetch' | 'sendBeacon'\n method?: 'POST' | 'GET'\n urlQueryArgs?: { compression: Compression }\n callback?: RequestCallback\n timeout?: number\n noRetries?: boolean\n compression?: Compression | 'best-available'\n fetchOptions?: {\n cache?: RequestInit['cache']\n next?: NextOptions\n }\n}\n\n// Queued request types - the same as a request but with additional queueing information\n\nexport interface QueuedRequestOptions extends RequestOptions {\n batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n}\n\n// Used explicitly for retriable requests\nexport interface RetriableRequestOptions extends QueuedRequestOptions {\n retriesPerformedSoFar?: number\n}\n\nexport interface CaptureOptions {\n $set?: Properties /** used with $identify */\n $set_once?: Properties /** used with $identify */\n _url?: string /** Used to override the desired endpoint for the captured event */\n _batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n _noTruncate?: boolean /** if set, overrides and disables config.properties_string_max_length */\n send_instantly?: boolean /** if set skips the batched queue */\n skip_client_rate_limiting?: boolean /** if set skips the client side rate limiting */\n transport?: RequestOptions['transport'] /** if set, overrides the desired transport method */\n timestamp?: Date\n}\n\nexport type FlagVariant = { flag: string; variant: string }\n\nexport type SessionRecordingCanvasOptions = {\n recordCanvas?: boolean | null\n canvasFps?: number | null\n // the API returns a decimal between 0 and 1 as a string\n canvasQuality?: string | null\n}\n\nexport interface RemoteConfig {\n supportedCompression: Compression[]\n autocapture_opt_out?: boolean\n /**\n * originally capturePerformance was replay only and so boolean true\n * is equivalent to { network_timing: true }\n * now capture performance can be separately enabled within replay\n * and as a standalone web vitals tracker\n * people can have them enabled separately\n * they work standalone but enhance each other\n * TODO: deprecate this so we make a new config that doesn't need this explanation\n */\n capturePerformance?: boolean | PerformanceCaptureConfig\n analytics?: {\n endpoint?: string\n }\n elementsChainAsString?: boolean\n // this is currently in development and may have breaking changes without a major version bump\n autocaptureExceptions?:\n | boolean\n | {\n endpoint?: string\n }\n sessionRecording?: SessionRecordingCanvasOptions & {\n endpoint?: string\n consoleLogRecordingEnabled?: boolean\n // the API returns a decimal between 0 and 1 as a string\n sampleRate?: string | null\n minimumDurationMilliseconds?: number\n linkedFlag?: string | FlagVariant | null\n networkPayloadCapture?: Pick<NetworkRecordOptions, 'recordBody' | 'recordHeaders'>\n urlTriggers?: SessionRecordingUrlTrigger[]\n scriptConfig?: { script?: string | undefined }\n urlBlocklist?: SessionRecordingUrlTrigger[]\n eventTriggers?: string[]\n }\n surveys?: boolean\n toolbarParams: ToolbarParams\n editorParams?: ToolbarParams /** @deprecated, renamed to toolbarParams, still present on older API responses */\n toolbarVersion: 'toolbar' /** @deprecated, moved to toolbarParams */\n isAuthenticated: boolean\n siteApps: { id: string; url: string }[]\n heatmaps?: boolean\n defaultIdentifiedOnly?: boolean\n captureDeadClicks?: boolean\n hasFeatureFlags?: boolean // Indicates if the team has any flags enabled (if not we don't need to load them)\n}\n\nexport interface DecideResponse extends RemoteConfig {\n featureFlags: Record<string, string | boolean>\n featureFlagPayloads: Record<string, JsonType>\n errorsWhileComputingFlags: boolean\n}\n\nexport type SiteAppGlobals = {\n event: {\n uuid: string\n event: EventName\n properties: Properties\n timestamp?: Date\n elements_chain?: string\n distinct_id?: string\n }\n person: {\n properties: Properties\n }\n groups: Record<string, { id: string; type: string; properties: Properties }>\n}\n\nexport type SiteAppLoader = {\n id: string\n init: (config: { posthog: PostHog; callback: (success: boolean) => void }) => {\n processEvent?: (globals: SiteAppGlobals) => void\n }\n}\n\nexport type SiteApp = {\n id: string\n loaded: boolean\n errored: boolean\n processEvent?: (globals: SiteAppGlobals) => void\n}\n\nexport type FeatureFlagsCallback = (\n flags: string[],\n variants: Record<string, string | boolean>,\n context?: {\n errorsLoading?: boolean\n }\n) => void\n\nexport interface PersistentStore {\n is_supported: () => boolean\n error: (error: any) => void\n parse: (name: string) => any\n get: (name: string) => any\n set: (\n name: string,\n value: any,\n expire_days?: number | null,\n cross_subdomain?: boolean,\n secure?: boolean,\n debug?: boolean\n ) => void\n remove: (name: string, cross_subdomain?: boolean) => void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Breaker = {}\nexport type EventHandler = (event: Event) => boolean | void\n\nexport type ToolbarUserIntent = 'add-action' | 'edit-action'\nexport type ToolbarSource = 'url' | 'localstorage'\nexport type ToolbarVersion = 'toolbar'\n\n/* sync with posthog */\nexport interface ToolbarParams {\n token?: string /** public posthog-js token */\n temporaryToken?: string /** private temporary user token */\n actionId?: number\n userIntent?: ToolbarUserIntent\n source?: ToolbarSource\n toolbarVersion?: ToolbarVersion\n instrument?: boolean\n distinctId?: string\n userEmail?: string\n dataAttributes?: string[]\n featureFlags?: Record<string, string | boolean>\n}\n\nexport type SnippetArrayItem = [method: string, ...args: any[]]\n\nexport type JsonRecord = { [key: string]: JsonType }\nexport type JsonType = string | number | boolean | null | JsonRecord | Array<JsonType>\n\n/** A feature that isn't publicly available yet.*/\nexport interface EarlyAccessFeature {\n // Sync this with the backend's EarlyAccessFeatureSerializer!\n name: string\n description: string\n stage: 'concept' | 'alpha' | 'beta'\n documentationUrl: string | null\n flagKey: string | null\n}\n\nexport type EarlyAccessFeatureCallback = (earlyAccessFeatures: EarlyAccessFeature[]) => void\n\nexport interface EarlyAccessFeatureResponse {\n earlyAccessFeatures: EarlyAccessFeature[]\n}\n\nexport type Headers = Record<string, string>\n\n/* for rrweb/network@1\n ** when that is released as part of rrweb this can be removed\n ** don't rely on this type, it may change without notice\n */\nexport type InitiatorType =\n | 'audio'\n | 'beacon'\n | 'body'\n | 'css'\n | 'early-hint'\n | 'embed'\n | 'fetch'\n | 'frame'\n | 'iframe'\n | 'icon'\n | 'image'\n | 'img'\n | 'input'\n | 'link'\n | 'navigation'\n | 'object'\n | 'ping'\n | 'script'\n | 'track'\n | 'video'\n | 'xmlhttprequest'\n\nexport type NetworkRecordOptions = {\n initiatorTypes?: InitiatorType[]\n maskRequestFn?: (data: CapturedNetworkRequest) => CapturedNetworkRequest | undefined\n recordHeaders?: boolean | { request: boolean; response: boolean }\n recordBody?: boolean | string[] | { request: boolean | string[]; response: boolean | string[] }\n recordInitialRequests?: boolean\n /**\n * whether to record PerformanceEntry events for network requests\n */\n recordPerformance?: boolean\n /**\n * the PerformanceObserver will only observe these entry types\n */\n performanceEntryTypeToObserve: string[]\n /**\n * the maximum size of the request/response body to record\n * NB this will be at most 1MB even if set larger\n */\n payloadSizeLimitBytes: number\n /**\n * some domains we should never record the payload\n * for example other companies session replay ingestion payloads aren't super useful but are gigantic\n * if this isn't provided we use a default list\n * if this is provided - we add the provided list to the default list\n * i.e. we never record the payloads on the default deny list\n */\n payloadHostDenyList?: string[]\n}\n\n/** @deprecated - use CapturedNetworkRequest instead */\nexport type NetworkRequest = {\n url: string\n}\n\n// In rrweb this is called NetworkRequest, but we already exposed that as having only URL\n// we also want to vary from the rrweb NetworkRequest because we want to include\n// all PerformanceEntry properties too.\n// that has 4 required properties\n// readonly duration: DOMHighResTimeStamp;\n// readonly entryType: string;\n// readonly name: string;\n// readonly startTime: DOMHighResTimeStamp;\n// NB: properties below here are ALPHA, don't rely on them, they may change without notice\n\n// we mirror PerformanceEntry since we read into this type from a PerformanceObserver,\n// but we don't want to inherit its readonly-iness\ntype Writable<T> = { -readonly [P in keyof T]: T[P] }\n\nexport type CapturedNetworkRequest = Writable<Omit<PerformanceEntry, 'toJSON'>> & {\n // properties below here are ALPHA, don't rely on them, they may change without notice\n method?: string\n initiatorType?: InitiatorType\n status?: number\n timeOrigin?: number\n timestamp?: number\n startTime?: number\n endTime?: number\n requestHeaders?: Headers\n requestBody?: string | null\n responseHeaders?: Headers\n responseBody?: string | null\n // was this captured before fetch/xhr could have been wrapped\n isInitial?: boolean\n}\n\nexport type ErrorEventArgs = [\n event: string | Event,\n source?: string | undefined,\n lineno?: number | undefined,\n colno?: number | undefined,\n error?: Error | undefined,\n]\n\nexport type ErrorMetadata = {\n handled?: boolean\n synthetic?: boolean\n syntheticException?: Error\n overrideExceptionType?: string\n overrideExceptionMessage?: string\n defaultExceptionType?: string\n defaultExceptionMessage?: string\n}\n\n// levels originally copied from Sentry to work with the sentry integration\n// and to avoid relying on a frequently changing @sentry/types dependency\n// but provided as an array of literal types, so we can constrain the level below\nexport const severityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug'] as const\nexport declare type SeverityLevel = (typeof severityLevels)[number]\n\nexport interface ErrorProperties {\n $exception_type: string\n $exception_message: string\n $exception_level: SeverityLevel\n $exception_source?: string\n $exception_lineno?: number\n $exception_colno?: number\n $exception_DOMException_code?: string\n $exception_is_synthetic?: boolean\n $exception_stack_trace_raw?: string\n $exception_handled?: boolean\n $exception_personURL?: string\n}\n\nexport interface ErrorConversions {\n errorToProperties: (args: ErrorEventArgs) => ErrorProperties\n unhandledRejectionToProperties: (args: [ev: PromiseRejectionEvent]) => ErrorProperties\n}\n\nexport interface SessionRecordingUrlTrigger {\n url: string\n matching: 'regex'\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"event-utils.js","sourceRoot":"","sources":["../../../src/utils/event-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { getQueryParam, convertToURL } from './request-utils'\nimport { isNull } from './type-utils'\nimport { Properties } from '../types'\nimport Config from '../config'\nimport { each, extend, stripEmptyProperties, stripLeadingDollar } from './index'\nimport { document, location, userAgent, window } from './globals'\nimport { detectBrowser, detectBrowserVersion, detectDevice, detectDeviceType, detectOS } from './user-agent-utils'\n\nconst URL_REGEX_PREFIX = 'https?://(.*)'\n\n// Should be kept in sync with https://github.com/PostHog/posthog/blob/master/plugin-server/src/utils/db/utils.ts#L60\nexport const CAMPAIGN_PARAMS = [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_content',\n 'utm_term',\n 'gclid', // google ads\n 'gad_source', // google ads\n 'gclsrc', // google ads 360\n 'dclid', // google display ads\n 'gbraid', // google ads, web to app\n 'wbraid', // google ads, app to web\n 'fbclid', // facebook\n 'msclkid', // microsoft\n 'twclid', // twitter\n 'li_fat_id', // linkedin\n 'mc_cid', // mailchimp campaign id\n 'igshid', // instagram\n 'ttclid', // tiktok\n 'rdt_cid', // reddit\n]\n\nexport const EVENT_TO_PERSON_PROPERTIES = [\n // mobile params\n '$app_build',\n '$app_name',\n '$app_namespace',\n '$app_version',\n // web params\n '$browser',\n '$browser_version',\n '$device_type',\n '$current_url',\n '$pathname',\n '$os',\n '$os_name', // $os_name is a special case, it's treated as an alias of $os!\n '$os_version',\n '$referring_domain',\n '$referrer',\n]\n\nexport const Info = {\n campaignParams: function (customParams?: string[]): Record<string, string> {\n if (!document) {\n return {}\n }\n return this._campaignParamsFromUrl(document.URL, customParams)\n },\n\n _campaignParamsFromUrl: function (url: string, customParams?: string[]): Record<string, string> {\n const campaign_keywords = CAMPAIGN_PARAMS.concat(customParams || [])\n\n const params: Record<string, any> = {}\n each(campaign_keywords, function (kwkey) {\n const kw = getQueryParam(url, kwkey)\n params[kwkey] = kw ? kw : null\n })\n\n return params\n },\n\n _searchEngine: function (referrer: string): string | null {\n if (!referrer) {\n return null\n } else {\n if (referrer.search(URL_REGEX_PREFIX + 'google.([^/?]*)') === 0) {\n return 'google'\n } else if (referrer.search(URL_REGEX_PREFIX + 'bing.com') === 0) {\n return 'bing'\n } else if (referrer.search(URL_REGEX_PREFIX + 'yahoo.com') === 0) {\n return 'yahoo'\n } else if (referrer.search(URL_REGEX_PREFIX + 'duckduckgo.com') === 0) {\n return 'duckduckgo'\n } else {\n return null\n }\n }\n },\n\n _searchInfoFromReferrer: function (referrer: string): Record<string, any> {\n const search = Info._searchEngine(referrer)\n const param = search != 'yahoo' ? 'q' : 'p'\n const ret: Record<string, any> = {}\n\n if (!isNull(search)) {\n ret['$search_engine'] = search\n\n const keyword = document ? getQueryParam(document.referrer, param) : ''\n if (keyword.length) {\n ret['ph_keyword'] = keyword\n }\n }\n\n return ret\n },\n\n searchInfo: function (): Record<string, any> {\n const referrer = document?.referrer\n if (!referrer) {\n return {}\n }\n return this._searchInfoFromReferrer(referrer)\n },\n\n /**\n * This function detects which browser is running this script.\n * The order of the checks are important since many user agents\n * include keywords used in later checks.\n */\n browser: detectBrowser,\n\n /**\n * This function detects which browser version is running this script,\n * parsing major and minor version (e.g., 42.1). User agent strings from:\n * http://www.useragentstring.com/pages/useragentstring.php\n *\n * `navigator.vendor` is passed in and used to help with detecting certain browsers\n * NB `navigator.vendor` is deprecated and not present in every browser\n */\n browserVersion: detectBrowserVersion,\n\n browserLanguage: function (): string | undefined {\n return (\n navigator.language || // Any modern browser\n (navigator as Record<string, any>).userLanguage // IE11\n )\n },\n\n browserLanguagePrefix: function (): string | undefined {\n const browserLanguage = this.browserLanguage()\n return typeof browserLanguage === 'string' ? browserLanguage.split('-')[0] : undefined\n },\n\n os: detectOS,\n\n device: detectDevice,\n\n deviceType: detectDeviceType,\n\n referrer: function (): string {\n return document?.referrer || '$direct'\n },\n\n referringDomain: function (): string {\n if (!document?.referrer) {\n return '$direct'\n }\n return convertToURL(document.referrer)?.host || '$direct'\n },\n\n referrerInfo: function (): Record<string, any> {\n return {\n $referrer: this.referrer(),\n $referring_domain: this.referringDomain(),\n }\n },\n\n initialPersonInfo: function (): Record<string, any> {\n // we're being a bit more economical with bytes here because this is stored in the cookie\n return {\n r: this.referrer().substring(0, 1000),\n u: location?.href.substring(0, 1000),\n }\n },\n\n initialPersonPropsFromInfo: function (info: Record<string, any>): Record<string, any> {\n const { r: initial_referrer, u: initial_current_url } = info\n const referring_domain =\n initial_referrer == null\n ? undefined\n : initial_referrer == '$direct'\n ? '$direct'\n : convertToURL(initial_referrer)?.host\n\n const props: Record<string, string | undefined> = {\n $initial_referrer: initial_referrer,\n $initial_referring_domain: referring_domain,\n }\n if (initial_current_url) {\n props['$initial_current_url'] = initial_current_url\n const location = convertToURL(initial_current_url)\n props['$initial_host'] = location?.host\n props['$initial_pathname'] = location?.pathname\n const campaignParams = this._campaignParamsFromUrl(initial_current_url)\n each(campaignParams, function (v, k: string) {\n props['$initial_' + stripLeadingDollar(k)] = v\n })\n }\n if (initial_referrer) {\n const searchInfo = this._searchInfoFromReferrer(initial_referrer)\n each(searchInfo, function (v, k: string) {\n props['$initial_' + stripLeadingDollar(k)] = v\n })\n }\n return props\n },\n\n timezone: function (): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone\n } catch {\n return undefined\n }\n },\n\n timezoneOffset: function (): number | undefined {\n try {\n return new Date().getTimezoneOffset()\n } catch {\n return undefined\n }\n },\n\n properties: function (): Properties {\n if (!userAgent) {\n return {}\n }\n const [os_name, os_version] = Info.os(userAgent)\n return extend(\n stripEmptyProperties({\n $os: os_name,\n $os_version: os_version,\n $browser: Info.browser(userAgent, navigator.vendor),\n $device: Info.device(userAgent),\n $device_type: Info.deviceType(userAgent),\n $timezone: Info.timezone(),\n $timezone_offset: Info.timezoneOffset(),\n }),\n {\n $current_url: location?.href,\n $host: location?.host,\n $pathname: location?.pathname,\n $raw_user_agent: userAgent.length > 1000 ? userAgent.substring(0, 997) + '...' : userAgent,\n $browser_version: Info.browserVersion(userAgent, navigator.vendor),\n $browser_language: Info.browserLanguage(),\n $browser_language_prefix: Info.browserLanguagePrefix(),\n $screen_height: window?.screen.height,\n $screen_width: window?.screen.width,\n $viewport_height: window?.innerHeight,\n $viewport_width: window?.innerWidth,\n $lib: 'web',\n $lib_version: Config.LIB_VERSION,\n $insert_id: Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10),\n $time: Date.now() / 1000, // epoch time in seconds\n }\n )\n },\n\n people_properties: function (): Properties {\n if (!userAgent) {\n return {}\n }\n\n const [os_name, os_version] = Info.os(userAgent)\n return extend(\n stripEmptyProperties({\n $os: os_name,\n $os_version: os_version,\n $browser: Info.browser(userAgent, navigator.vendor),\n }),\n {\n $browser_version: Info.browserVersion(userAgent, navigator.vendor),\n }\n )\n },\n}\n"]}
1
+ {"version":3,"file":"event-utils.js","sourceRoot":"","sources":["../../../src/utils/event-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { getQueryParam, convertToURL } from './request-utils'\nimport { isNull } from './type-utils'\nimport { Properties } from '../types'\nimport Config from '../config'\nimport { each, extend, stripEmptyProperties, stripLeadingDollar } from './index'\nimport { document, location, userAgent, window } from './globals'\nimport { detectBrowser, detectBrowserVersion, detectDevice, detectDeviceType, detectOS } from './user-agent-utils'\n\nconst URL_REGEX_PREFIX = 'https?://(.*)'\n\n// Should be kept in sync with https://github.com/PostHog/posthog/blob/master/plugin-server/src/utils/db/utils.ts#L60\nexport const CAMPAIGN_PARAMS = [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_content',\n 'utm_term',\n 'gclid', // google ads\n 'gad_source', // google ads\n 'gclsrc', // google ads 360\n 'dclid', // google display ads\n 'gbraid', // google ads, web to app\n 'wbraid', // google ads, app to web\n 'fbclid', // facebook\n 'msclkid', // microsoft\n 'twclid', // twitter\n 'li_fat_id', // linkedin\n 'mc_cid', // mailchimp campaign id\n 'igshid', // instagram\n 'ttclid', // tiktok\n 'rdt_cid', // reddit\n]\n\nexport const EVENT_TO_PERSON_PROPERTIES = [\n // mobile params\n '$app_build',\n '$app_name',\n '$app_namespace',\n '$app_version',\n // web params\n '$browser',\n '$browser_version',\n '$device_type',\n '$current_url',\n '$pathname',\n '$os',\n '$os_name', // $os_name is a special case, it's treated as an alias of $os!\n '$os_version',\n '$referring_domain',\n '$referrer',\n]\n\nexport const Info = {\n campaignParams: function (customParams?: string[]): Record<string, string> {\n if (!document) {\n return {}\n }\n return this._campaignParamsFromUrl(document.URL, customParams)\n },\n\n _campaignParamsFromUrl: function (url: string, customParams?: string[]): Record<string, string> {\n const campaign_keywords = CAMPAIGN_PARAMS.concat(customParams || [])\n\n const params: Record<string, any> = {}\n each(campaign_keywords, function (kwkey) {\n const kw = getQueryParam(url, kwkey)\n params[kwkey] = kw ? kw : null\n })\n\n return params\n },\n\n _searchEngine: function (referrer: string): string | null {\n if (!referrer) {\n return null\n } else {\n if (referrer.search(URL_REGEX_PREFIX + 'google.([^/?]*)') === 0) {\n return 'google'\n } else if (referrer.search(URL_REGEX_PREFIX + 'bing.com') === 0) {\n return 'bing'\n } else if (referrer.search(URL_REGEX_PREFIX + 'yahoo.com') === 0) {\n return 'yahoo'\n } else if (referrer.search(URL_REGEX_PREFIX + 'duckduckgo.com') === 0) {\n return 'duckduckgo'\n } else {\n return null\n }\n }\n },\n\n _searchInfoFromReferrer: function (referrer: string): Record<string, any> {\n const search = Info._searchEngine(referrer)\n const param = search != 'yahoo' ? 'q' : 'p'\n const ret: Record<string, any> = {}\n\n if (!isNull(search)) {\n ret['$search_engine'] = search\n\n const keyword = document ? getQueryParam(document.referrer, param) : ''\n if (keyword.length) {\n ret['ph_keyword'] = keyword\n }\n }\n\n return ret\n },\n\n searchInfo: function (): Record<string, any> {\n const referrer = document?.referrer\n if (!referrer) {\n return {}\n }\n return this._searchInfoFromReferrer(referrer)\n },\n\n /**\n * This function detects which browser is running this script.\n * The order of the checks are important since many user agents\n * include keywords used in later checks.\n */\n browser: detectBrowser,\n\n /**\n * This function detects which browser version is running this script,\n * parsing major and minor version (e.g., 42.1). User agent strings from:\n * http://www.useragentstring.com/pages/useragentstring.php\n *\n * `navigator.vendor` is passed in and used to help with detecting certain browsers\n * NB `navigator.vendor` is deprecated and not present in every browser\n */\n browserVersion: detectBrowserVersion,\n\n browserLanguage: function (): string | undefined {\n return (\n navigator.language || // Any modern browser\n (navigator as Record<string, any>).userLanguage // IE11\n )\n },\n\n browserLanguagePrefix: function (): string | undefined {\n const browserLanguage = this.browserLanguage()\n return typeof browserLanguage === 'string' ? browserLanguage.split('-')[0] : undefined\n },\n\n os: detectOS,\n\n device: detectDevice,\n\n deviceType: detectDeviceType,\n\n referrer: function (): string {\n return document?.referrer || '$direct'\n },\n\n referringDomain: function (): string {\n if (!document?.referrer) {\n return '$direct'\n }\n return convertToURL(document.referrer)?.host || '$direct'\n },\n\n referrerInfo: function (): Record<string, any> {\n return {\n $referrer: this.referrer(),\n $referring_domain: this.referringDomain(),\n }\n },\n\n initialPersonInfo: function (): Record<string, any> {\n // we're being a bit more economical with bytes here because this is stored in the cookie\n return {\n r: this.referrer().substring(0, 1000),\n u: location?.href.substring(0, 1000),\n }\n },\n\n initialPersonPropsFromInfo: function (info: Record<string, any>): Record<string, any> {\n const { r: initial_referrer, u: initial_current_url } = info\n const referring_domain =\n initial_referrer == null\n ? undefined\n : initial_referrer == '$direct'\n ? '$direct'\n : convertToURL(initial_referrer)?.host\n\n const props: Record<string, string | undefined> = {\n $initial_referrer: initial_referrer,\n $initial_referring_domain: referring_domain,\n }\n if (initial_current_url) {\n props['$initial_current_url'] = initial_current_url\n const location = convertToURL(initial_current_url)\n props['$initial_host'] = location?.host\n props['$initial_pathname'] = location?.pathname\n const campaignParams = this._campaignParamsFromUrl(initial_current_url)\n each(campaignParams, function (v, k: string) {\n props['$initial_' + stripLeadingDollar(k)] = v\n })\n }\n if (initial_referrer) {\n const searchInfo = this._searchInfoFromReferrer(initial_referrer)\n each(searchInfo, function (v, k: string) {\n props['$initial_' + stripLeadingDollar(k)] = v\n })\n }\n return props\n },\n\n timezone: function (): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone\n } catch {\n return undefined\n }\n },\n\n timezoneOffset: function (): number | undefined {\n try {\n return new Date().getTimezoneOffset()\n } catch {\n return undefined\n }\n },\n\n properties: function (): Properties {\n if (!userAgent) {\n return {}\n }\n const [os_name, os_version] = Info.os(userAgent)\n return extend(\n stripEmptyProperties({\n $os: os_name,\n $os_version: os_version,\n $browser: Info.browser(userAgent, navigator.vendor),\n $device: Info.device(userAgent),\n $device_type: Info.deviceType(userAgent),\n $timezone: Info.timezone(),\n $timezone_offset: Info.timezoneOffset(),\n }),\n {\n $current_url: location?.href,\n $host: location?.host,\n $pathname: location?.pathname,\n $raw_user_agent: userAgent.length > 1000 ? userAgent.substring(0, 997) + '...' : userAgent,\n $browser_version: Info.browserVersion(userAgent, navigator.vendor),\n $browser_language: Info.browserLanguage(),\n $browser_language_prefix: Info.browserLanguagePrefix(),\n $screen_height: window?.screen.height,\n $screen_width: window?.screen.width,\n $viewport_height: window?.innerHeight,\n $viewport_width: window?.innerWidth,\n $lib: 'web',\n $lib_version: Config.LIB_VERSION,\n $insert_id: Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10),\n $time: Date.now() / 1000, // epoch time in seconds\n }\n )\n },\n\n people_properties: function (): Properties {\n if (!userAgent) {\n return {}\n }\n\n const [os_name, os_version] = Info.os(userAgent)\n return extend(\n stripEmptyProperties({\n $os: os_name,\n $os_version: os_version,\n $browser: Info.browser(userAgent, navigator.vendor),\n }),\n {\n $browser_version: Info.browserVersion(userAgent, navigator.vendor),\n }\n )\n },\n}\n"]}