posthog-js 1.232.0 → 1.232.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.
@@ -1 +1 @@
1
- {"version":3,"file":"customizations.full.js","sources":["../src/utils/globals.ts","../src/types.ts","../src/utils/string-utils.ts","../src/utils/type-utils.ts","../src/config.ts","../src/utils/logger.ts","../src/utils/index.ts","../src/utils/request-utils.ts","../src/utils/user-agent-utils.ts","../src/utils/event-utils.ts","../src/utils/number-utils.ts","../src/extensions/sampling.ts","../src/customizations/before-send.ts","../src/customizations/setAllPersonProfilePropertiesAsPersonPropertiesForFlags.ts","../src/entrypoints/customizations.full.ts"],"sourcesContent":["import { ErrorProperties } from '../extensions/exception-autocapture/error-conversion'\nimport type { PostHog } from '../posthog-core'\nimport { SessionIdManager } from '../sessionid'\nimport {\n DeadClicksAutoCaptureConfig,\n ErrorConversionArgs,\n ErrorMetadata,\n Properties,\n RemoteConfig,\n SiteAppLoader,\n} from '../types'\n\n/*\n * Global helpers to protect access to browser globals in a way that is safer for different targets\n * like DOM, SSR, Web workers etc.\n *\n * NOTE: Typically we want the \"window\" but globalThis works for both the typical browser context as\n * well as other contexts such as the web worker context. Window is still exported for any bits that explicitly require it.\n * If in doubt - export the global you need from this file and use that as an optional value. This way the code path is forced\n * to handle the case where the global is not available.\n */\n\n// eslint-disable-next-line no-restricted-globals\nconst win: (Window & typeof globalThis) | undefined = typeof window !== 'undefined' ? window : undefined\n\nexport type AssignableWindow = Window &\n typeof globalThis &\n Record<string, any> & {\n __PosthogExtensions__?: PostHogExtensions\n\n _POSTHOG_REMOTE_CONFIG?: Record<\n string,\n {\n config: RemoteConfig\n siteApps: SiteAppLoader[]\n }\n >\n }\n\n/**\n * This is our contract between (potentially) lazily loaded extensions and the SDK\n * changes to this interface can be breaking changes for users of the SDK\n */\n\nexport type PostHogExtensionKind =\n | 'toolbar'\n | 'exception-autocapture'\n | 'web-vitals'\n | 'recorder'\n | 'tracing-headers'\n | 'surveys'\n | 'dead-clicks-autocapture'\n | 'remote-config'\n\nexport interface LazyLoadedDeadClicksAutocaptureInterface {\n start: (observerTarget: Node) => void\n stop: () => void\n}\n\ninterface PostHogExtensions {\n loadExternalDependency?: (\n posthog: PostHog,\n kind: PostHogExtensionKind,\n callback: (error?: string | Event, event?: Event) => void\n ) => void\n\n loadSiteApp?: (posthog: PostHog, appUrl: string, callback: (error?: string | Event, event?: Event) => void) => void\n\n parseErrorAsProperties?: ({ error, event }: ErrorConversionArgs, metadata?: ErrorMetadata) => ErrorProperties\n errorWrappingFunctions?: {\n wrapOnError: (captureFn: (props: Properties) => void) => () => void\n wrapUnhandledRejection: (captureFn: (props: Properties) => void) => () => void\n }\n rrweb?: { record: any; version: string }\n rrwebPlugins?: { getRecordConsolePlugin: any; getRecordNetworkPlugin?: any }\n canActivateRepeatedly?: (survey: any) => boolean\n generateSurveys?: (posthog: PostHog) => any | undefined\n postHogWebVitalsCallbacks?: {\n onLCP: (metric: any) => void\n onCLS: (metric: any) => void\n onFCP: (metric: any) => void\n onINP: (metric: any) => void\n }\n tracingHeadersPatchFns?: {\n _patchFetch: (sessionManager?: SessionIdManager) => () => void\n _patchXHR: (sessionManager?: SessionIdManager) => () => void\n }\n initDeadClicksAutocapture?: (\n ph: PostHog,\n config: DeadClicksAutoCaptureConfig\n ) => LazyLoadedDeadClicksAutocaptureInterface\n}\n\nconst global: typeof globalThis | undefined = typeof globalThis !== 'undefined' ? globalThis : win\n\nexport const ArrayProto = Array.prototype\nexport const nativeForEach = ArrayProto.forEach\nexport const nativeIndexOf = ArrayProto.indexOf\n\nexport const navigator = global?.navigator\nexport const document = global?.document\nexport const location = global?.location\nexport const fetch = global?.fetch\nexport const XMLHttpRequest =\n global?.XMLHttpRequest && 'withCredentials' in new global.XMLHttpRequest() ? global.XMLHttpRequest : undefined\nexport const AbortController = global?.AbortController\nexport const userAgent = navigator?.userAgent\nexport const assignableWindow: AssignableWindow = win ?? ({} as any)\n\nexport { win as window }\n","import type { recordOptions } from './extensions/replay/types/rrweb'\nimport type { SegmentAnalytics } from './extensions/segment-integration'\nimport { PostHog } from './posthog-core'\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 *\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 `div`s 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 * Everything is allowed when there's no allowlist\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 /**\n * When set to true, autocapture will capture the text of any element that is cut or copied.\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 /**\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 /**\n * Works with session replay to use the browser's native performance observer to capture performance metrics\n */\n network_timing?: boolean\n\n /**\n * Use chrome's web vitals library to wrap fetch and capture web vitals\n */\n web_vitals?: boolean\n\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 *\n * @default 15 * 60 * 1000 (15 minutes)\n */\n __web_vitals_max_value?: number\n\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 * @default ['LCP', 'CLS', 'FCP', 'INP']\n */\n web_vitals_allowed_metrics?: SupportedWebVitalsMetrics[]\n\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 *\n * @default 5000\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 /**\n * We'll not consider a click to be a dead click, if it's followed by a scroll within `scroll_threshold_ms` milliseconds\n *\n * @default 100\n */\n scroll_threshold_ms?: number\n\n /**\n * We'll not consider a click to be a dead click, if it's followed by a selection change within `selection_change_threshold_ms` milliseconds\n *\n * @default 100\n */\n selection_change_threshold_ms?: number\n\n /**\n * We'll not consider a click to be a dead click, if it's followed by a mutation within `mutation_threshold_ms` milliseconds\n *\n * @default 2500\n */\n mutation_threshold_ms?: number\n\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 our own 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 * @default 1000\n */\n flush_interval_milliseconds: number\n}\n\nexport type BeforeSendFn = (cr: CaptureResult | null) => CaptureResult | null\n\n/**\n * Configuration options for the PostHog JavaScript SDK.\n * @see https://posthog.com/docs/libraries/js#config\n */\nexport interface PostHogConfig {\n /** URL of your PostHog instance.\n *\n * @default 'https://us.i.posthog.com'\n */\n api_host: string\n\n /**\n * If using a reverse proxy for `api_host` then this should be the actual PostHog app URL (e.g. https://us.posthog.com).\n * This ensures that links to PostHog point to the correct host.\n *\n * @default null\n */\n ui_host: string | null\n\n /**\n * The transport method to use for API requests.\n *\n * @default 'fetch'\n */\n api_transport?: 'XHR' | 'fetch'\n\n /**\n * The token for your PostHog project.\n * It should NOT be provided manually in the config, but rather passed as the first parameter to `posthog.init()`.\n */\n token: string\n\n /**\n * The name this instance will be identified by.\n * You don't need to set this most of the time,\n * but can be useful if you have several Posthog instances running at the same time.\n *\n * @default 'posthog'\n */\n name: string\n\n /**\n * Determines whether PostHog should autocapture events.\n * This setting does not affect capturing pageview events (see `capture_pageview`).\n *\n * @default true\n */\n autocapture: boolean | AutocaptureConfig\n\n /**\n * Determines whether PostHog should capture rage clicks.\n *\n * @default true\n */\n rageclick: boolean\n\n /**\n * Determines if cookie should be set on the top level domain (example.com).\n * If PostHog-js is loaded on a subdomain (test.example.com), and `cross_subdomain_cookie` is set to false,\n * it'll set the cookie on the subdomain only (test.example.com).\n *\n * NOTE: It will be set to `false` if we detect that the domain is a subdomain of a platform that is excluded from cross-subdomain cookie setting.\n * The current list of excluded platforms is `herokuapp.com`, `vercel.app`, and `netlify.app`.\n *\n * @see `isCrossDomainCookie`\n * @default true\n */\n cross_subdomain_cookie: boolean\n\n /**\n * Determines how PostHog stores information about the user. See [persistence](https://posthog.com/docs/libraries/js#persistence) for details.\n *\n * @default 'localStorage+cookie'\n */\n persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie' | 'sessionStorage'\n\n /**\n * The name for the super properties persistent store\n *\n * @default ''\n */\n persistence_name: string\n\n /** @deprecated - Use 'persistence_name' instead */\n cookie_name?: string\n\n /**\n * A function to be called once the PostHog scripts have loaded successfully.\n *\n * @param posthog_instance - The PostHog instance that has been loaded.\n */\n loaded: (posthog_instance: PostHog) => void\n\n /**\n * Determines whether PostHog should save referrer information.\n *\n * @default true\n */\n save_referrer: boolean\n\n /**\n * Determines whether PostHog should save marketing parameters.\n * These are `utm_*` paramaters and friends.\n *\n * @see {CAMPAIGN_PARAMS} from './utils/event-utils' - Default campaign parameters like utm_source, utm_medium, etc.\n * @default true\n */\n save_campaign_params: boolean\n\n /** @deprecated - Use `save_campaign_params` instead */\n store_google?: boolean\n\n /**\n * Used to extend the list of campaign parameters that are saved by default.\n *\n * @see {CAMPAIGN_PARAMS} from './utils/event-utils' - Default campaign parameters like utm_source, utm_medium, etc.\n * @default []\n */\n custom_campaign_params: string[]\n\n /**\n * Used to extend the list of user agents that are blocked by default.\n *\n * @see {DEFAULT_BLOCKED_UA_STRS} from './utils/blocked-uas' - Default list of blocked user agents.\n * @default []\n */\n custom_blocked_useragents: string[]\n\n /**\n * Determines whether PostHog should be in debug mode.\n * You can enable this to get more detailed logging.\n *\n * You can also enable this on your website by appending `?__posthog_debug=true` at the end of your URL\n * You can also call `posthog.debug()` in your code to enable debug mode\n *\n * @default false\n */\n debug: boolean\n\n /** @deprecated Use `debug` instead */\n verbose?: boolean\n\n /**\n * Determines whether PostHog should capture pageview events automatically.\n *\n * @default true\n */\n capture_pageview: boolean\n\n /**\n * Determines whether PostHog should capture pageleave events.\n * If set to `true`, it will capture pageleave events for all pages.\n * If set to `'if_capture_pageview'`, it will only capture pageleave events if `capture_pageview` is also set to `true`.\n *\n * @default 'if_capture_pageview'\n */\n capture_pageleave: boolean | 'if_capture_pageview'\n\n /**\n * Determines the number of days to store cookies for.\n *\n * @default 365\n */\n cookie_expiration: number\n\n /**\n * Determines whether PostHog should upgrade old cookies.\n * If set to `true`, the library will check for a cookie from our old js library and import super properties from it, then the old cookie is deleted.\n * This option only works in the initialization, so make sure you set it when you create the library.\n *\n * @default false\n */\n upgrade: boolean\n\n /**\n * Determines whether PostHog should disable session recording.\n *\n * @default false\n */\n disable_session_recording: boolean\n\n /**\n * Determines whether PostHog should disable persistence.\n * If set to `true`, the library will not save any data to the browser. It will also delete any data previously saved to the browser.\n *\n * @default false\n */\n disable_persistence: boolean\n\n /** @deprecated - use `disable_persistence` instead */\n disable_cookie?: boolean\n\n /**\n * Determines whether PostHog should disable surveys.\n *\n * @default false\n */\n disable_surveys: boolean\n\n /**\n * Determines whether PostHog should disable web experiments.\n *\n * Currently disabled while we're in BETA. It will be toggled to `true` in a future release.\n *\n * @default true\n */\n disable_web_experiments: boolean\n\n /**\n * Determines whether PostHog should disable any external dependency loading.\n * This will prevent PostHog from requesting any external scripts such as those needed for Session Replay, Surveys or Site Apps.\n *\n * @default false\n */\n disable_external_dependency_loading: boolean\n\n /**\n * A function to be called when a script is being loaded.\n * This can be used to modify the script before it is loaded.\n * This is useful for adding a nonce to the script, for example.\n *\n * @param script - The script element that is being loaded.\n * @returns The modified script element, or null if the script should not be loaded.\n */\n prepare_external_dependency_script?: (script: HTMLScriptElement) => HTMLScriptElement | null\n\n /**\n * A function to be called when a stylesheet is being loaded.\n * This can be used to modify the stylesheet before it is loaded.\n * This is useful for adding a nonce to the stylesheet, for example.\n *\n * @param stylesheet - The stylesheet element that is being loaded.\n * @returns The modified stylesheet element, or null if the stylesheet should not be loaded.\n */\n prepare_external_dependency_stylesheet?: (stylesheet: HTMLStyleElement) => HTMLStyleElement | null\n\n /**\n * Determines whether PostHog should enable recording console logs.\n * When undefined, it falls back to the remote config setting.\n *\n * @default undefined\n */\n enable_recording_console_log?: boolean\n\n /**\n * Determines whether PostHog should use secure cookies.\n * If this is `true`, PostHog cookies will be marked as secure,\n * meaning they will only be transmitted over HTTPS.\n *\n * @default window.location.protocol === 'https:'\n */\n secure_cookie: boolean\n\n /**\n * Determines whether PostHog should capture IP addresses.\n *\n * @default true\n */\n ip: boolean\n\n /**\n * Determines if users should be opted out of PostHog tracking by default,\n * requiring additional logic to opt them into capturing by calling `posthog.opt_in_capturing()`.\n *\n * @default false\n */\n opt_out_capturing_by_default: boolean\n\n /**\n * Determines where we'll save the information about whether users are opted out of capturing.\n *\n * @default 'localStorage'\n */\n opt_out_capturing_persistence_type: 'localStorage' | 'cookie'\n\n /**\n * Determines if users should be opted out of browser data storage by this PostHog instance by default,\n * requiring additional logic to opt them into capturing by calling `posthog.opt_in_capturing()`.\n *\n * @default false\n */\n opt_out_persistence_by_default?: boolean\n\n /**\n * Determines if users should be opted out of user agent filtering such as googlebot or other bots.\n * If this is set to `true`, PostHog will set `$browser_type` to either `bot` or `browser` for all events,\n * but will process all events as if they were from a browser.\n *\n * @default false\n */\n opt_out_useragent_filter: boolean\n\n /**\n * Determines the prefix for the cookie used to store the information about whether users are opted out of capturing.\n * When `null`, it falls back to the default prefix found in `consent.ts`.\n *\n * @default null\n */\n opt_out_capturing_cookie_prefix: string | null\n\n /**\n * Determines if users should be opted in to site apps.\n *\n * @default false\n */\n opt_in_site_apps: boolean\n\n /**\n * Determines whether PostHog should respect the Do Not Track header when computing\n * consent in `ConsentManager`.\n *\n * @see `ConsentManager`\n * @default false\n */\n respect_dnt: boolean\n\n /**\n * A list of properties that should never be sent with capture calls.\n *\n * @default []\n */\n property_denylist: string[]\n\n /** @deprecated - use `property_denylist` instead */\n property_blacklist?: string[]\n\n /**\n * A list of headers that should be sent with requests to the PostHog API.\n *\n * @default {}\n */\n request_headers: { [header_name: string]: string }\n\n /** @deprecated - use `request_headers` instead */\n xhr_headers?: { [header_name: string]: string }\n\n /**\n * A function that is called when a request to the PostHog API fails.\n *\n * @param error - The `RequestResponse` object that occurred.\n */\n on_request_error?: (error: RequestResponse) => void\n\n /** @deprecated - use `on_request_error` instead */\n on_xhr_error?: (failedRequest: XMLHttpRequest) => void\n\n /**\n * Determines whether PostHog should batch requests to the PostHog API.\n *\n * @default true\n */\n request_batching: boolean\n\n /**\n * Determines the maximum length of the properties string that can be sent with capture calls.\n *\n * @default 65535\n */\n properties_string_max_length: number\n\n /**\n * Determines the session recording options.\n *\n * @see `SessionRecordingOptions`\n * @default {}\n */\n session_recording: SessionRecordingOptions\n\n /**\n * Determines the session idle timeout in seconds.\n * Any new event that's happened after this timeout will create a new session.\n *\n * @default 30 * 60 -- 30 minutes\n */\n session_idle_timeout_seconds: number\n\n /**\n * Prevent autocapture from capturing any attribute names on elements.\n *\n * @default false\n */\n mask_all_element_attributes: boolean\n\n /**\n * Prevent autocapture from capturing `textContent` on elements.\n *\n * @default false\n */\n mask_all_text: boolean\n\n /**\n * Prevent autocapture from capturing personal data properties.\n * These include campaign parameters, UTM parameters, and other parameters that could be considered personal data under e.g. GDPR.\n *\n * @default false\n */\n mask_personal_data_properties: boolean\n\n /**\n * Custom list of personal data properties to mask.\n *\n * @default []\n */\n custom_personal_data_properties: string[]\n\n /**\n * One of the very first things the PostHog library does when init() is called\n * is make a request to the /decide endpoint on PostHog's backend.\n * This endpoint contains information on how to run the PostHog library\n * so events are properly received in the backend.\n *\n * This endpoint is required to run most features of the library.\n * However, if you're not using any of the described features,\n * you may wish to turn off the call completely to avoid an extra request\n * and reduce resource usage on both the client and the server.\n *\n * @default false\n */\n advanced_disable_decide: boolean\n\n /**\n * Will keep /decide running, but without any feature flag requests\n *\n * @default false\n */\n advanced_disable_feature_flags: boolean\n\n /**\n * Stops from firing feature flag requests on first page load.\n * Only requests feature flags when user identity or properties are updated,\n * or you manually request for flags to be loaded.\n *\n * @default false\n */\n advanced_disable_feature_flags_on_first_load: boolean\n\n /**\n * Determines whether PostHog should disable toolbar metrics.\n * This is our internal instrumentation for our toolbar in your website.\n *\n * @default false\n */\n advanced_disable_toolbar_metrics: boolean\n\n /**\n * Sets timeout for fetching feature flags\n *\n * @default 3000\n */\n feature_flag_request_timeout_ms: number\n\n /**\n * Sets timeout for fetching surveys\n *\n * @default 10000\n */\n surveys_request_timeout_ms: number\n\n /**\n * Function to get the device ID.\n * This doesn't usually need to be set, but can be useful if you want to use a custom device ID.\n *\n * @param uuid - The UUID we would use for the device ID.\n * @returns The device ID.\n *\n * @default (uuid) => uuid\n */\n get_device_id: (uuid: string) => string\n\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\n /** @deprecated - use `before_send` instead */\n sanitize_properties: ((properties: Properties, event_name: string) => Properties) | null\n\n /** @deprecated - use `before_send` instead */\n _onCapture: (eventName: string, eventData: CaptureResult) => void\n\n /**\n * Determines whether to capture performance metrics.\n * These include Network Timing and Web Vitals.\n *\n * When `undefined`, fallback to the remote configuration.\n * If `false`, neither network timing nor web vitals will work.\n * If an object, that will override the remote configuration.\n *\n * @see {PerformanceCaptureConfig}\n * @default undefined\n */\n capture_performance?: boolean | PerformanceCaptureConfig\n\n /**\n * Determines whether to disable compression when sending events to the server.\n * WARNING: Should only be used for testing. Could negatively impact performance.\n *\n * @default false\n */\n disable_compression: boolean\n\n /**\n * An object containing the `distinctID`, `isIdentifiedID`, and `featureFlags` keys,\n * where `distinctID` is a string, and `featureFlags` is an object of key-value pairs.\n *\n * Since there is a delay between initializing PostHog and fetching feature flags,\n * feature flags are not always available immediately.\n * This makes them unusable if you want to do something like redirecting a user\n * to a different page based on a feature flag.\n *\n * You can, therefore, fetch the feature flags in your server and pre-fill them here,\n * allowing PostHog to know the feature flag values immediately.\n *\n * After the SDK fetches feature flags from PostHog, it will use those flag values instead of bootstrapped ones.\n *\n * @default {}\n */\n bootstrap: BootstrapConfig\n\n /**\n * The segment analytics object.\n *\n * @see https://posthog.com/docs/libraries/segment\n */\n segment?: SegmentAnalytics\n\n /**\n * Determines whether to capture heatmaps.\n *\n * @see {HeatmapConfig}\n * @default undefined\n */\n capture_heatmaps?: boolean | HeatmapConfig\n\n /* @deprecated - use `capture_heatmaps` instead */\n enable_heatmaps?: boolean\n\n /**\n * Determines whether to capture dead clicks.\n *\n * @see {DeadClicksAutoCaptureConfig}\n * @default undefined\n */\n capture_dead_clicks?: boolean | DeadClicksAutoCaptureConfig\n\n /**\n * Determines whether to capture exceptions.\n *\n * @default undefined\n */\n capture_exceptions?: boolean\n\n /**\n * Determines whether to disable scroll properties.\n * These allow you to keep track of how far down someone scrolled in your website.\n *\n * @default false\n */\n disable_scroll_properties?: boolean\n\n /**\n * Let the pageview scroll stats use a custom css selector for the root element, e.g. `main`\n * It will use `window.document.documentElement` if not specified.\n */\n scroll_root_selector?: string | string[]\n\n /**\n * You can control whether events from PostHog-js have person processing enabled with the `person_profiles` config setting.\n * There are three options:\n * - `person_profiles: 'always'` - 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'` _(default)_ - 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 * @default 'identified_only'\n */\n person_profiles?: 'always' | 'never' | 'identified_only'\n\n /** @deprecated - use `person_profiles` instead */\n process_person?: 'always' | 'never' | 'identified_only'\n\n /**\n * Client side rate limiting\n */\n rate_limiting?: {\n /**\n * The average number of events per second that should be permitted\n *\n * @default 10\n */\n events_per_second?: number\n\n /**\n * How many events can be captured in a burst. This defaults to 10 times the events_per_second count\n *\n * @default 10 * `events_per_second`\n */\n events_burst_limit?: number\n }\n\n /**\n * Used when sending data via `fetch`, use with care.\n * This is intentionally meant to be used with NextJS `fetch`\n *\n * Incorrect `cache` 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 * Used to change the behavior of the request queue.\n * This is an advanced feature and should be used with caution.\n */\n request_queue_config?: RequestQueueConfig\n\n // ------- PREVIEW CONFIGS -------\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 // ------- RETIRED CONFIGS - NO REPLACEMENT OR USAGE -------\n\n /** @deprecated - NOT USED ANYMORE, kept here for backwards compatibility reasons */\n api_method?: string\n\n /** @deprecated - NOT USED ANYMORE, kept here for backwards compatibility reasons */\n inapp_protocol?: string\n\n /** @deprecated - NOT USED ANYMORE, kept here for backwards compatibility reasons */\n inapp_link_new_window?: boolean\n}\n\nexport interface SessionRecordingOptions {\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default 'ph-no-capture'\n */\n blockClass?: string | RegExp\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default null\n */\n blockSelector?: string | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default 'ph-ignore-input'\n */\n ignoreClass?: string | RegExp\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default 'ph-mask'\n */\n maskTextClass?: string | RegExp\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskTextSelector?: string | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskTextFn?: ((text: string, element?: HTMLElement) => string) | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskAllInputs?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskInputOptions?: recordOptions['maskInputOptions']\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskInputFn?: ((text: string, element?: HTMLElement) => string) | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default {}\n */\n slimDOMOptions?: recordOptions['slimDOMOptions']\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n collectFonts?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default true\n */\n inlineStylesheet?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n recordCrossOriginIframes?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n recordHeaders?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n recordBody?: boolean\n\n /**\n * Allows local config to override remote canvas recording settings from the decide response\n */\n captureCanvas?: SessionRecordingCanvasOptions\n\n /**\n * Modify the network request before it is captured. Returning null or undefined stops it being captured\n */\n maskCapturedNetworkRequestFn?: ((data: CapturedNetworkRequest) => CapturedNetworkRequest | null | undefined) | null\n\n /** @deprecated - use maskCapturedNetworkRequestFn instead */\n maskNetworkRequestFn?: ((data: NetworkRequest) => NetworkRequest | null | undefined) | null\n\n /**\n * ADVANCED: while a user is active we take a full snapshot of the browser every interval.\n * For very few sites playback performance might be better with different interval.\n * Set to 0 to disable\n *\n * @default 1000 * 60 * 5 (5 minutes)\n */\n full_snapshot_interval_millis?: number\n\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 * @default true\n */\n compress_events?: boolean\n\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 *\n * @default 1000 * 60 * 5 (5 minutes)\n */\n session_idle_threshold_ms?: number\n\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 *\n * @default 10\n */\n __mutationRateLimiterRefillRate?: number\n\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 *\n * @default 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 RequestWithOptions {\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 QueuedRequestWithOptions extends RequestWithOptions {\n /** key of queue, e.g. 'sessionRecording' vs 'event' */\n batchKey?: string\n}\n\n// Used explicitly for retriable requests\nexport interface RetriableRequestWithOptions extends QueuedRequestWithOptions {\n retriesPerformedSoFar?: number\n}\n\n// we used to call a request that was sent to the queue with options attached `RequestQueueOptions`\n// so we can't call the options used to configure the behavior of the RequestQueue that as well,\n// so instead we call them config\nexport interface RequestQueueConfig {\n /**\n * ADVANCED - alters the frequency which PostHog sends events to the server.\n * generally speaking this is only set when apps have automatic page refreshes, or very short visits.\n * Defaults to 3 seconds when not set\n * Allowed values between 250 and 5000\n * */\n flush_interval_ms?: number\n}\n\nexport interface CaptureOptions {\n /**\n * Used when `$identify` is called\n * Will set person properties overriding previous values\n */\n $set?: Properties\n\n /**\n * Used when `$identify` is called\n * Will set person properties but only once, it will NOT override previous values\n */\n $set_once?: Properties\n\n /**\n * Used to override the desired endpoint for the captured event\n */\n _url?: string\n\n /**\n * key of queue, e.g. 'sessionRecording' vs 'event'\n */\n _batchKey?: string\n\n /**\n * If set, overrides and disables config.properties_string_max_length\n */\n _noTruncate?: boolean\n\n /**\n * If set, skips the batched queue\n */\n send_instantly?: boolean\n\n /**\n * If set, skips the client side rate limiting\n */\n skip_client_rate_limiting?: boolean\n\n /**\n * If set, overrides the desired transport method\n */\n transport?: RequestWithOptions['transport']\n\n /**\n * If set, overrides the current timestamp\n */\n timestamp?: Date\n}\n\nexport type FlagVariant = { flag: string; variant: string }\n\nexport type SessionRecordingCanvasOptions = {\n /**\n * If set, records the canvas\n *\n * @default false\n */\n recordCanvas?: boolean | null\n\n /**\n * If set, records the canvas at the given FPS\n * Can be set in the remote configuration\n * Limited between 0 and 12\n * When canvas recording is enabled, if this is not set locally, then remote config sets this as 4\n *\n * @default null-ish\n */\n canvasFps?: number | null\n\n /**\n * If set, records the canvas at the given quality\n * Can be set in the remote configuration\n * Must be a string that is a valid decimal between 0 and 1\n * When canvas recording is enabled, if this is not set locally, then remote config sets this as \"0.4\"\n *\n * @default null-ish\n */\n canvasQuality?: string | null\n}\n\n/**\n * Remote configuration for the PostHog instance\n *\n * All of these settings can be configured directly in your PostHog instance\n * Any configuration set in the client overrides the information from the server\n */\nexport interface RemoteConfig {\n /**\n * Supported compression algorithms\n */\n supportedCompression: Compression[]\n\n /**\n * If set, disables autocapture\n */\n autocapture_opt_out?: boolean\n\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\n /**\n * Whether we should use a custom endpoint for analytics\n *\n * @default { endpoint: \"/e\" }\n */\n analytics?: {\n endpoint?: string\n }\n\n /**\n * Whether the `$elements_chain` property should be sent as a string or as an array\n *\n * @default false\n */\n elementsChainAsString?: boolean\n\n /**\n * This is currently in development and may have breaking changes without a major version bump\n */\n autocaptureExceptions?: boolean | { endpoint?: string }\n\n /**\n * Session recording configuration options\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 masking?: Pick<SessionRecordingOptions, 'maskAllInputs' | 'maskTextSelector'>\n urlTriggers?: SessionRecordingUrlTrigger[]\n scriptConfig?: { script?: string | undefined }\n urlBlocklist?: SessionRecordingUrlTrigger[]\n eventTriggers?: string[]\n }\n\n /**\n * Whether surveys are enabled\n */\n surveys?: boolean\n\n /**\n * Parameters for the toolbar\n */\n toolbarParams: ToolbarParams\n\n /**\n * @deprecated renamed to toolbarParams, still present on older API responses\n */\n editorParams?: ToolbarParams\n\n /**\n * @deprecated, moved to toolbarParams\n */\n toolbarVersion: 'toolbar'\n\n /**\n * Whether the user is authenticated\n */\n isAuthenticated: boolean\n\n /**\n * List of site apps with their IDs and URLs\n */\n siteApps: { id: string; url: string }[]\n\n /**\n * Whether heatmaps are enabled\n */\n heatmaps?: boolean\n\n /**\n * Whether to only capture identified users by default\n */\n defaultIdentifiedOnly?: boolean\n\n /**\n * Whether to capture dead clicks\n */\n captureDeadClicks?: boolean\n\n /**\n * Indicates if the team has any flags enabled (if not we don't need to load them)\n */\n hasFeatureFlags?: boolean\n}\n\n/**\n * Decide returns everything we have on the remote config plus feature flags and their payloads\n */\nexport interface DecideResponse extends RemoteConfig {\n featureFlags: Record<string, string | boolean>\n featureFlagPayloads: Record<string, JsonType>\n errorsWhileComputingFlags: boolean\n requestId?: string\n flags: Record<string, FeatureFlagDetail>\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 processedBuffer: 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 type FeatureFlagDetail = {\n key: string\n enabled: boolean\n // Only used when overriding a flag payload.\n original_enabled?: boolean | undefined\n variant: string | undefined\n // Only used when overriding a flag payload.\n original_variant?: string | undefined\n reason: EvaluationReason | undefined\n metadata: FeatureFlagMetadata | undefined\n}\n\nexport type FeatureFlagMetadata = {\n id: number\n version: number | undefined\n description: string | undefined\n payload: JsonType | undefined\n // Only used when overriding a flag payload.\n original_payload?: JsonType | undefined\n}\n\nexport type EvaluationReason = {\n code: string\n condition_index: number | undefined\n description: string | undefined\n}\n\nexport type RemoteConfigFeatureFlagCallback = (payload: JsonType) => 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 | undefined | 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 EarlyAccessFeatureStage = 'concept' | 'alpha' | 'beta' | 'general-availability'\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 ErrorConversionArgs = {\n event: string | Event\n error?: Error\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","export function includes<T = any>(str: T[] | string, needle: T): boolean {\n return (str as any).indexOf(needle) !== -1\n}\n\n// UNDERSCORE\n// Embed part of the Underscore Library\nexport const trim = function (str: string): string {\n return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '')\n}\nexport const stripLeadingDollar = function (s: string): string {\n return s.replace(/^\\$/, '')\n}\n\nexport function isDistinctIdStringLike(value: string): boolean {\n return ['distinct_id', 'distinctid'].includes(value.toLowerCase())\n}\n","import { window } from './globals'\nimport { knownUnsafeEditableEvent, KnownUnsafeEditableEvent } from '../types'\nimport { includes } from './string-utils'\n\n// eslint-disable-next-line posthog-js/no-direct-array-check\nconst nativeIsArray = Array.isArray\nconst ObjProto = Object.prototype\nexport const hasOwnProperty = ObjProto.hasOwnProperty\nconst toString = ObjProto.toString\n\nexport const isArray =\n nativeIsArray ||\n function (obj: any): obj is any[] {\n return toString.call(obj) === '[object Array]'\n }\n\n// from a comment on http://dbj.org/dbj/?p=286\n// fails on only one very rare and deliberate custom object:\n// let bomb = { toString : undefined, valueOf: function(o) { return \"function BOMBA!\"; }};\nexport const isFunction = (x: unknown): x is (...args: any[]) => any => {\n // eslint-disable-next-line posthog-js/no-direct-function-check\n return typeof x === 'function'\n}\n\nexport const isNativeFunction = (x: unknown): x is (...args: any[]) => any =>\n isFunction(x) && x.toString().indexOf('[native code]') !== -1\n\n// When angular patches functions they pass the above `isNativeFunction` check (at least the MutationObserver)\nexport const isAngularZonePresent = (): boolean => {\n return !!(window as any).Zone\n}\n\n// Underscore Addons\nexport const isObject = (x: unknown): x is Record<string, any> => {\n // eslint-disable-next-line posthog-js/no-direct-object-check\n return x === Object(x) && !isArray(x)\n}\nexport const isEmptyObject = (x: unknown) => {\n if (isObject(x)) {\n for (const key in x) {\n if (hasOwnProperty.call(x, key)) {\n return false\n }\n }\n return true\n }\n return false\n}\nexport const isUndefined = (x: unknown): x is undefined => x === void 0\n\nexport const isString = (x: unknown): x is string => {\n // eslint-disable-next-line posthog-js/no-direct-string-check\n return toString.call(x) == '[object String]'\n}\n\nexport const isEmptyString = (x: unknown): boolean => isString(x) && x.trim().length === 0\n\nexport const isNull = (x: unknown): x is null => {\n // eslint-disable-next-line posthog-js/no-direct-null-check\n return x === null\n}\n\n/*\n sometimes you want to check if something is null or undefined\n that's what this is for\n */\nexport const isNullish = (x: unknown): x is null | undefined => isUndefined(x) || isNull(x)\n\nexport const isNumber = (x: unknown): x is number => {\n // eslint-disable-next-line posthog-js/no-direct-number-check\n return toString.call(x) == '[object Number]'\n}\nexport const isBoolean = (x: unknown): x is boolean => {\n // eslint-disable-next-line posthog-js/no-direct-boolean-check\n return toString.call(x) === '[object Boolean]'\n}\n\nexport const isDocument = (x: unknown): x is Document => {\n // eslint-disable-next-line posthog-js/no-direct-document-check\n return x instanceof Document\n}\n\nexport const isFormData = (x: unknown): x is FormData => {\n // eslint-disable-next-line posthog-js/no-direct-form-data-check\n return x instanceof FormData\n}\n\nexport const isFile = (x: unknown): x is File => {\n // eslint-disable-next-line posthog-js/no-direct-file-check\n return x instanceof File\n}\n\nexport const isError = (x: unknown): x is Error => {\n return x instanceof Error\n}\n\nexport const isKnownUnsafeEditableEvent = (x: unknown): x is KnownUnsafeEditableEvent => {\n return includes(knownUnsafeEditableEvent as unknown as string[], x)\n}\n","import packageInfo from '../package.json'\n\n// overridden in posthog-core,\n// e.g. Config.DEBUG = Config.DEBUG || instance.config.debug\nconst Config = {\n DEBUG: false,\n LIB_VERSION: packageInfo.version,\n}\n\nexport default Config\n","import Config from '../config'\nimport { isUndefined } from './type-utils'\nimport { assignableWindow, window } from './globals'\n\nexport type Logger = {\n _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => void\n info: (...args: any[]) => void\n warn: (...args: any[]) => void\n error: (...args: any[]) => void\n critical: (...args: any[]) => void\n uninitializedWarning: (methodName: string) => void\n createLogger: (prefix: string) => Logger\n}\n\nconst _createLogger = (prefix: string): Logger => {\n const logger: Logger = {\n _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => {\n if (\n window &&\n (Config.DEBUG || assignableWindow.POSTHOG_DEBUG) &&\n !isUndefined(window.console) &&\n window.console\n ) {\n const consoleLog =\n '__rrweb_original__' in window.console[level]\n ? (window.console[level] as any)['__rrweb_original__']\n : window.console[level]\n\n // eslint-disable-next-line no-console\n consoleLog(prefix, ...args)\n }\n },\n\n info: (...args: any[]) => {\n logger._log('log', ...args)\n },\n\n warn: (...args: any[]) => {\n logger._log('warn', ...args)\n },\n\n error: (...args: any[]) => {\n logger._log('error', ...args)\n },\n\n critical: (...args: any[]) => {\n // Critical errors are always logged to the console\n // eslint-disable-next-line no-console\n console.error(prefix, ...args)\n },\n\n uninitializedWarning: (methodName: string) => {\n logger.error(`You must initialize PostHog before calling ${methodName}`)\n },\n\n createLogger: (additionalPrefix: string) => _createLogger(`${prefix} ${additionalPrefix}`),\n }\n return logger\n}\n\nexport const logger = _createLogger('[PostHog.js]')\n\nexport const createLogger = logger.createLogger\n","import { Breaker, Properties } from '../types'\nimport { hasOwnProperty, isArray, isFormData, isNull, isNullish, isString } from './type-utils'\nimport { logger } from './logger'\nimport { nativeForEach, nativeIndexOf } from './globals'\n\nconst breaker: Breaker = {}\n\nexport function eachArray<E = any>(\n obj: E[] | null | undefined,\n iterator: (value: E, key: number) => void | Breaker,\n thisArg?: any\n): void {\n if (isArray(obj)) {\n if (nativeForEach && obj.forEach === nativeForEach) {\n obj.forEach(iterator, thisArg)\n } else if ('length' in obj && obj.length === +obj.length) {\n for (let i = 0, l = obj.length; i < l; i++) {\n if (i in obj && iterator.call(thisArg, obj[i], i) === breaker) {\n return\n }\n }\n }\n }\n}\n\n/**\n * @param {*=} obj\n * @param {function(...*)=} iterator\n * @param {Object=} thisArg\n */\nexport function each(obj: any, iterator: (value: any, key: any) => void | Breaker, thisArg?: any): void {\n if (isNullish(obj)) {\n return\n }\n if (isArray(obj)) {\n return eachArray(obj, iterator, thisArg)\n }\n if (isFormData(obj)) {\n for (const pair of obj.entries()) {\n if (iterator.call(thisArg, pair[1], pair[0]) === breaker) {\n return\n }\n }\n return\n }\n for (const key in obj) {\n if (hasOwnProperty.call(obj, key)) {\n if (iterator.call(thisArg, obj[key], key) === breaker) {\n return\n }\n }\n }\n}\n\nexport const extend = function (obj: Record<string, any>, ...args: Record<string, any>[]): Record<string, any> {\n eachArray(args, function (source) {\n for (const prop in source) {\n if (source[prop] !== void 0) {\n obj[prop] = source[prop]\n }\n }\n })\n return obj\n}\n\nexport const extendArray = function <T>(obj: T[], ...args: T[][]): T[] {\n eachArray(args, function (source) {\n eachArray(source, function (item) {\n obj.push(item)\n })\n })\n return obj\n}\n\nexport const include = function (\n obj: null | string | Array<any> | Record<string, any>,\n target: any\n): boolean | Breaker {\n let found = false\n if (isNull(obj)) {\n return found\n }\n if (nativeIndexOf && obj.indexOf === nativeIndexOf) {\n return obj.indexOf(target) != -1\n }\n each(obj, function (value) {\n if (found || (found = value === target)) {\n return breaker\n }\n return\n })\n return found\n}\n\n/**\n * Object.entries() polyfill\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries\n */\nexport function entries<T = any>(obj: Record<string, T>): [string, T][] {\n const ownProps = Object.keys(obj)\n let i = ownProps.length\n const resArray = new Array(i) // preallocate the Array\n\n while (i--) {\n resArray[i] = [ownProps[i], obj[ownProps[i]]]\n }\n return resArray\n}\n\nexport const trySafe = function <T>(fn: () => T): T | undefined {\n try {\n return fn()\n } catch {\n return undefined\n }\n}\n\nexport const safewrap = function <F extends (...args: any[]) => any = (...args: any[]) => any>(f: F): F {\n return function (...args) {\n try {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return f.apply(this, args)\n } catch (e) {\n logger.critical(\n 'Implementation error. Please turn on debug mode and open a ticket on https://app.posthog.com/home#panel=support%3Asupport%3A.'\n )\n logger.critical(e)\n }\n } as F\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport const safewrapClass = function (klass: Function, functions: string[]): void {\n for (let i = 0; i < functions.length; i++) {\n klass.prototype[functions[i]] = safewrap(klass.prototype[functions[i]])\n }\n}\n\nexport const stripEmptyProperties = function (p: Properties): Properties {\n const ret: Properties = {}\n each(p, function (v, k) {\n if (isString(v) && v.length > 0) {\n ret[k] = v\n }\n })\n return ret\n}\n\n/**\n * Deep copies an object.\n * It handles cycles by replacing all references to them with `undefined`\n * Also supports customizing native values\n *\n * @param value\n * @param customizer\n * @returns {{}|undefined|*}\n */\nfunction deepCircularCopy<T extends Record<string, any> = Record<string, any>>(\n value: T,\n customizer?: <K extends keyof T = keyof T>(value: T[K], key?: K) => T[K]\n): T | undefined {\n const COPY_IN_PROGRESS_SET = new Set()\n\n function internalDeepCircularCopy(value: T, key?: string): T | undefined {\n if (value !== Object(value)) return customizer ? customizer(value as any, key) : value // primitive value\n\n if (COPY_IN_PROGRESS_SET.has(value)) return undefined\n COPY_IN_PROGRESS_SET.add(value)\n let result: T\n\n if (isArray(value)) {\n result = [] as any as T\n eachArray(value, (it) => {\n result.push(internalDeepCircularCopy(it))\n })\n } else {\n result = {} as T\n each(value, (val, key) => {\n if (!COPY_IN_PROGRESS_SET.has(val)) {\n ;(result as any)[key] = internalDeepCircularCopy(val, key)\n }\n })\n }\n return result\n }\n return internalDeepCircularCopy(value)\n}\n\nexport function _copyAndTruncateStrings<T extends Record<string, any> = Record<string, any>>(\n object: T,\n maxStringLength: number | null\n): T {\n return deepCircularCopy(object, (value: any) => {\n if (isString(value) && !isNull(maxStringLength)) {\n return (value as string).slice(0, maxStringLength)\n }\n return value\n }) as T\n}\n\n// NOTE: Update PostHogConfig docs if you change this list\n// We will not try to catch all bullets here, but we should make an effort to catch the most common ones\n// You should be highly against adding more to this list, because ultimately customers can configure\n// their `cross_subdomain_cookie` setting to anything they want.\nconst EXCLUDED_FROM_CROSS_SUBDOMAIN_COOKIE = ['herokuapp.com', 'vercel.app', 'netlify.app']\nexport function isCrossDomainCookie(documentLocation: Location | undefined) {\n const hostname = documentLocation?.hostname\n\n if (!isString(hostname)) {\n return false\n }\n // split and slice isn't a great way to match arbitrary domains,\n // but it's good enough for ensuring we only match herokuapp.com when it is the TLD\n // for the hostname\n const lastTwoParts = hostname.split('.').slice(-2).join('.')\n\n for (const excluded of EXCLUDED_FROM_CROSS_SUBDOMAIN_COOKIE) {\n if (lastTwoParts === excluded) {\n return false\n }\n }\n\n return true\n}\n\nexport function find<T>(value: T[], predicate: (value: T) => boolean): T | undefined {\n for (let i = 0; i < value.length; i++) {\n if (predicate(value[i])) {\n return value[i]\n }\n }\n return undefined\n}\n\n// Use this instead of element.addEventListener to avoid eslint errors\n// this properly implements the default options for passive event listeners\nexport function addEventListener(\n element: Window | Document | Element | undefined,\n event: string,\n callback: EventListener,\n options?: AddEventListenerOptions\n): void {\n const { capture = false, passive = true } = options ?? {}\n\n // This is the only place where we are allowed to call this function\n // because the whole idea is that we should be calling this instead of the built-in one\n // eslint-disable-next-line posthog-js/no-add-event-listener\n element?.addEventListener(event, callback, { capture, passive })\n}\n","import { each } from './'\n\nimport { isArray, isFile, isUndefined } from './type-utils'\nimport { logger } from './logger'\nimport { document } from './globals'\n\nconst localDomains = ['localhost', '127.0.0.1']\n\n/**\n * IE11 doesn't support `new URL`\n * so we can create an anchor element and use that to parse the URL\n * there's a lot of overlap between HTMLHyperlinkElementUtils and URL\n * meaning useful properties like `pathname` are available on both\n */\nexport const convertToURL = (url: string): HTMLAnchorElement | null => {\n const location = document?.createElement('a')\n if (isUndefined(location)) {\n return null\n }\n\n location.href = url\n return location\n}\n\nexport const formDataToQuery = function (formdata: Record<string, any> | FormData, arg_separator = '&'): string {\n let use_val: string\n let use_key: string\n const tph_arr: string[] = []\n\n each(formdata, function (val: File | string | undefined, key: string | undefined) {\n // the key might be literally the string undefined for e.g. if {undefined: 'something'}\n if (isUndefined(val) || isUndefined(key) || key === 'undefined') {\n return\n }\n\n use_val = encodeURIComponent(isFile(val) ? val.name : val.toString())\n use_key = encodeURIComponent(key)\n tph_arr[tph_arr.length] = use_key + '=' + use_val\n })\n\n return tph_arr.join(arg_separator)\n}\n\n// NOTE: Once we get rid of IE11/op_mini we can start using URLSearchParams\nexport const getQueryParam = function (url: string, param: string): string {\n const withoutHash: string = url.split('#')[0] || ''\n\n // Split only on the first ? to sort problem out for those with multiple ?s\n // and then remove them\n const queryParams: string = withoutHash.split(/\\?(.*)/)[1] || ''\n const cleanedQueryParams = queryParams.replace(/^\\?+/g, '')\n\n const queryParts = cleanedQueryParams.split('&')\n let keyValuePair\n\n for (let i = 0; i < queryParts.length; i++) {\n const parts = queryParts[i].split('=')\n if (parts[0] === param) {\n keyValuePair = parts\n break\n }\n }\n\n if (!isArray(keyValuePair) || keyValuePair.length < 2) {\n return ''\n } else {\n let result = keyValuePair[1]\n try {\n result = decodeURIComponent(result)\n } catch {\n logger.error('Skipping decoding for malformed query param: ' + result)\n }\n return result.replace(/\\+/g, ' ')\n }\n}\n\n// replace any query params in the url with the provided mask value. Tries to keep the URL as instant as possible,\n// including preserving malformed text in most cases\nexport const maskQueryParams = function <T extends string | undefined>(\n url: T,\n maskedParams: string[] | undefined,\n mask: string\n): T extends string ? string : undefined {\n if (!url || !maskedParams || !maskedParams.length) {\n return url as any\n }\n\n const splitHash = url.split('#')\n const withoutHash: string = splitHash[0] || ''\n const hash = splitHash[1]\n\n const splitQuery: string[] = withoutHash.split('?')\n const queryString: string = splitQuery[1]\n const urlWithoutQueryAndHash: string = splitQuery[0]\n const queryParts = (queryString || '').split('&')\n\n // use an array of strings rather than an object to preserve ordering and duplicates\n const paramStrings: string[] = []\n\n for (let i = 0; i < queryParts.length; i++) {\n const keyValuePair = queryParts[i].split('=')\n if (!isArray(keyValuePair)) {\n continue\n } else if (maskedParams.includes(keyValuePair[0])) {\n paramStrings.push(keyValuePair[0] + '=' + mask)\n } else {\n paramStrings.push(queryParts[i])\n }\n }\n\n let result = urlWithoutQueryAndHash\n if (queryString != null) {\n result += '?' + paramStrings.join('&')\n }\n if (hash != null) {\n result += '#' + hash\n }\n\n return result as any\n}\n\nexport const _getHashParam = function (hash: string, param: string): string | null {\n const matches = hash.match(new RegExp(param + '=([^&]*)'))\n return matches ? matches[1] : null\n}\n\nexport const isLocalhost = (): boolean => {\n return localDomains.includes(location.hostname)\n}\n","import { isFunction, isUndefined } from './type-utils'\nimport { includes } from './string-utils'\n\n/**\n * this device detection code is (at time of writing) about 3% of the size of the entire library\n * this is mostly because the identifiers user in regexes and results can't be minified away since\n * they have meaning\n *\n * so, there are some pre-uglifying choices in the code to help reduce the size\n * e.g. many repeated strings are stored as variables and then old-fashioned concatenated together\n *\n * TL;DR here be dragons\n */\nconst FACEBOOK = 'Facebook'\nconst MOBILE = 'Mobile'\nconst IOS = 'iOS'\nconst ANDROID = 'Android'\nconst TABLET = 'Tablet'\nconst ANDROID_TABLET = ANDROID + ' ' + TABLET\nconst IPAD = 'iPad'\nconst APPLE = 'Apple'\nconst APPLE_WATCH = APPLE + ' Watch'\nconst SAFARI = 'Safari'\nconst BLACKBERRY = 'BlackBerry'\nconst SAMSUNG = 'Samsung'\nconst SAMSUNG_BROWSER = SAMSUNG + 'Browser'\nconst SAMSUNG_INTERNET = SAMSUNG + ' Internet'\nconst CHROME = 'Chrome'\nconst CHROME_OS = CHROME + ' OS'\nconst CHROME_IOS = CHROME + ' ' + IOS\nconst INTERNET_EXPLORER = 'Internet Explorer'\nconst INTERNET_EXPLORER_MOBILE = INTERNET_EXPLORER + ' ' + MOBILE\nconst OPERA = 'Opera'\nconst OPERA_MINI = OPERA + ' Mini'\nconst EDGE = 'Edge'\nconst MICROSOFT_EDGE = 'Microsoft ' + EDGE\nconst FIREFOX = 'Firefox'\nconst FIREFOX_IOS = FIREFOX + ' ' + IOS\nconst NINTENDO = 'Nintendo'\nconst PLAYSTATION = 'PlayStation'\nconst XBOX = 'Xbox'\nconst ANDROID_MOBILE = ANDROID + ' ' + MOBILE\nconst MOBILE_SAFARI = MOBILE + ' ' + SAFARI\nconst WINDOWS = 'Windows'\nconst WINDOWS_PHONE = WINDOWS + ' Phone'\nconst NOKIA = 'Nokia'\nconst OUYA = 'Ouya'\nconst GENERIC = 'Generic'\nconst GENERIC_MOBILE = GENERIC + ' ' + MOBILE.toLowerCase()\nconst GENERIC_TABLET = GENERIC + ' ' + TABLET.toLowerCase()\nconst KONQUEROR = 'Konqueror'\n\nconst BROWSER_VERSION_REGEX_SUFFIX = '(\\\\d+(\\\\.\\\\d+)?)'\nconst DEFAULT_BROWSER_VERSION_REGEX = new RegExp('Version/' + BROWSER_VERSION_REGEX_SUFFIX)\n\nconst XBOX_REGEX = new RegExp(XBOX, 'i')\nconst PLAYSTATION_REGEX = new RegExp(PLAYSTATION + ' \\\\w+', 'i')\nconst NINTENDO_REGEX = new RegExp(NINTENDO + ' \\\\w+', 'i')\nconst BLACKBERRY_REGEX = new RegExp(BLACKBERRY + '|PlayBook|BB10', 'i')\n\nconst windowsVersionMap: Record<string, string> = {\n 'NT3.51': 'NT 3.11',\n 'NT4.0': 'NT 4.0',\n '5.0': '2000',\n '5.1': 'XP',\n '5.2': 'XP',\n '6.0': 'Vista',\n '6.1': '7',\n '6.2': '8',\n '6.3': '8.1',\n '6.4': '10',\n '10.0': '10',\n}\n\n/**\n * Safari detection turns out to be complicated. For e.g. https://stackoverflow.com/a/29696509\n * We can be slightly loose because some options have been ruled out (e.g. firefox on iOS)\n * before this check is made\n */\nfunction isSafari(userAgent: string): boolean {\n return includes(userAgent, SAFARI) && !includes(userAgent, CHROME) && !includes(userAgent, ANDROID)\n}\n\nconst safariCheck = (ua: string, vendor?: string) => (vendor && includes(vendor, APPLE)) || isSafari(ua)\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 */\nexport const detectBrowser = function (user_agent: string, vendor: string | undefined): string {\n vendor = vendor || '' // vendor is undefined for at least IE9\n\n if (includes(user_agent, ' OPR/') && includes(user_agent, 'Mini')) {\n return OPERA_MINI\n } else if (includes(user_agent, ' OPR/')) {\n return OPERA\n } else if (BLACKBERRY_REGEX.test(user_agent)) {\n return BLACKBERRY\n } else if (includes(user_agent, 'IE' + MOBILE) || includes(user_agent, 'WPDesktop')) {\n return INTERNET_EXPLORER_MOBILE\n }\n // https://developer.samsung.com/internet/user-agent-string-format\n else if (includes(user_agent, SAMSUNG_BROWSER)) {\n return SAMSUNG_INTERNET\n } else if (includes(user_agent, EDGE) || includes(user_agent, 'Edg/')) {\n return MICROSOFT_EDGE\n } else if (includes(user_agent, 'FBIOS')) {\n return FACEBOOK + ' ' + MOBILE\n } else if (includes(user_agent, 'UCWEB') || includes(user_agent, 'UCBrowser')) {\n return 'UC Browser'\n } else if (includes(user_agent, 'CriOS')) {\n return CHROME_IOS // why not just Chrome?\n } else if (includes(user_agent, 'CrMo')) {\n return CHROME\n } else if (includes(user_agent, CHROME)) {\n return CHROME\n } else if (includes(user_agent, ANDROID) && includes(user_agent, SAFARI)) {\n return ANDROID_MOBILE\n } else if (includes(user_agent, 'FxiOS')) {\n return FIREFOX_IOS\n } else if (includes(user_agent.toLowerCase(), KONQUEROR.toLowerCase())) {\n return KONQUEROR\n } else if (safariCheck(user_agent, vendor)) {\n return includes(user_agent, MOBILE) ? MOBILE_SAFARI : SAFARI\n } else if (includes(user_agent, FIREFOX)) {\n return FIREFOX\n } else if (includes(user_agent, 'MSIE') || includes(user_agent, 'Trident/')) {\n return INTERNET_EXPLORER\n } else if (includes(user_agent, 'Gecko')) {\n return FIREFOX\n }\n\n return ''\n}\n\nconst versionRegexes: Record<string, RegExp[]> = {\n [INTERNET_EXPLORER_MOBILE]: [new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)],\n [MICROSOFT_EDGE]: [new RegExp(EDGE + '?\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [CHROME]: [new RegExp('(' + CHROME + '|CrMo)\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [CHROME_IOS]: [new RegExp('CriOS\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n 'UC Browser': [new RegExp('(UCBrowser|UCWEB)\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [SAFARI]: [DEFAULT_BROWSER_VERSION_REGEX],\n [MOBILE_SAFARI]: [DEFAULT_BROWSER_VERSION_REGEX],\n [OPERA]: [new RegExp('(' + OPERA + '|OPR)\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [FIREFOX]: [new RegExp(FIREFOX + '\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [FIREFOX_IOS]: [new RegExp('FxiOS\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [KONQUEROR]: [new RegExp('Konqueror[:/]?' + BROWSER_VERSION_REGEX_SUFFIX, 'i')],\n // not every blackberry user agent has the version after the name\n [BLACKBERRY]: [new RegExp(BLACKBERRY + ' ' + BROWSER_VERSION_REGEX_SUFFIX), DEFAULT_BROWSER_VERSION_REGEX],\n [ANDROID_MOBILE]: [new RegExp('android\\\\s' + BROWSER_VERSION_REGEX_SUFFIX, 'i')],\n [SAMSUNG_INTERNET]: [new RegExp(SAMSUNG_BROWSER + '\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [INTERNET_EXPLORER]: [new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX)],\n Mozilla: [new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)],\n}\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 */\nexport const detectBrowserVersion = function (userAgent: string, vendor: string | undefined): number | null {\n const browser = detectBrowser(userAgent, vendor)\n const regexes: RegExp[] | undefined = versionRegexes[browser as keyof typeof versionRegexes]\n if (isUndefined(regexes)) {\n return null\n }\n\n for (let i = 0; i < regexes.length; i++) {\n const regex = regexes[i]\n const matches = userAgent.match(regex)\n if (matches) {\n return parseFloat(matches[matches.length - 2])\n }\n }\n return null\n}\n\n// to avoid repeating regexes or calling them twice, we have an array of matches\n// the first regex that matches uses its matcher function to return the result\nconst osMatchers: [\n RegExp,\n [string, string] | ((match: RegExpMatchArray | null, user_agent: string) => [string, string]),\n][] = [\n [\n new RegExp(XBOX + '; ' + XBOX + ' (.*?)[);]', 'i'),\n (match) => {\n return [XBOX, (match && match[1]) || '']\n },\n ],\n [new RegExp(NINTENDO, 'i'), [NINTENDO, '']],\n [new RegExp(PLAYSTATION, 'i'), [PLAYSTATION, '']],\n [BLACKBERRY_REGEX, [BLACKBERRY, '']],\n [\n new RegExp(WINDOWS, 'i'),\n (_, user_agent) => {\n if (/Phone/.test(user_agent) || /WPDesktop/.test(user_agent)) {\n return [WINDOWS_PHONE, '']\n }\n // not all JS versions support negative lookbehind, so we need two checks here\n if (new RegExp(MOBILE).test(user_agent) && !/IEMobile\\b/.test(user_agent)) {\n return [WINDOWS + ' ' + MOBILE, '']\n }\n const match = /Windows NT ([0-9.]+)/i.exec(user_agent)\n if (match && match[1]) {\n const version = match[1]\n let osVersion = windowsVersionMap[version] || ''\n if (/arm/i.test(user_agent)) {\n osVersion = 'RT'\n }\n return [WINDOWS, osVersion]\n }\n return [WINDOWS, '']\n },\n ],\n [\n /((iPhone|iPad|iPod).*?OS (\\d+)_(\\d+)_?(\\d+)?|iPhone)/,\n (match) => {\n if (match && match[3]) {\n const versionParts = [match[3], match[4], match[5] || '0']\n return [IOS, versionParts.join('.')]\n }\n return [IOS, '']\n },\n ],\n [\n /(watch.*\\/(\\d+\\.\\d+\\.\\d+)|watch os,(\\d+\\.\\d+),)/i,\n (match) => {\n // e.g. Watch4,3/5.3.8 (16U680)\n let version = ''\n if (match && match.length >= 3) {\n version = isUndefined(match[2]) ? match[3] : match[2]\n }\n return ['watchOS', version]\n },\n ],\n [\n new RegExp('(' + ANDROID + ' (\\\\d+)\\\\.(\\\\d+)\\\\.?(\\\\d+)?|' + ANDROID + ')', 'i'),\n (match) => {\n if (match && match[2]) {\n const versionParts = [match[2], match[3], match[4] || '0']\n return [ANDROID, versionParts.join('.')]\n }\n return [ANDROID, '']\n },\n ],\n [\n /Mac OS X (\\d+)[_.](\\d+)[_.]?(\\d+)?/i,\n (match) => {\n const result: [string, string] = ['Mac OS X', '']\n if (match && match[1]) {\n const versionParts = [match[1], match[2], match[3] || '0']\n result[1] = versionParts.join('.')\n }\n return result\n },\n ],\n [\n /Mac/i,\n // mop up a few non-standard UAs that should match mac\n ['Mac OS X', ''],\n ],\n [/CrOS/, [CHROME_OS, '']],\n [/Linux|debian/i, ['Linux', '']],\n]\n\nexport const detectOS = function (user_agent: string): [string, string] {\n for (let i = 0; i < osMatchers.length; i++) {\n const [rgex, resultOrFn] = osMatchers[i]\n const match = rgex.exec(user_agent)\n const result = match && (isFunction(resultOrFn) ? resultOrFn(match, user_agent) : resultOrFn)\n if (result) {\n return result\n }\n }\n return ['', '']\n}\n\nexport const detectDevice = function (user_agent: string): string {\n if (NINTENDO_REGEX.test(user_agent)) {\n return NINTENDO\n } else if (PLAYSTATION_REGEX.test(user_agent)) {\n return PLAYSTATION\n } else if (XBOX_REGEX.test(user_agent)) {\n return XBOX\n } else if (new RegExp(OUYA, 'i').test(user_agent)) {\n return OUYA\n } else if (new RegExp('(' + WINDOWS_PHONE + '|WPDesktop)', 'i').test(user_agent)) {\n return WINDOWS_PHONE\n } else if (/iPad/.test(user_agent)) {\n return IPAD\n } else if (/iPod/.test(user_agent)) {\n return 'iPod Touch'\n } else if (/iPhone/.test(user_agent)) {\n return 'iPhone'\n } else if (/(watch)(?: ?os[,/]|\\d,\\d\\/)[\\d.]+/i.test(user_agent)) {\n return APPLE_WATCH\n } else if (BLACKBERRY_REGEX.test(user_agent)) {\n return BLACKBERRY\n } else if (/(kobo)\\s(ereader|touch)/i.test(user_agent)) {\n return 'Kobo'\n } else if (new RegExp(NOKIA, 'i').test(user_agent)) {\n return NOKIA\n } else if (\n // Kindle Fire without Silk / Echo Show\n /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\\))/i.test(user_agent) ||\n // Kindle Fire HD\n /(kf[a-z]+)( bui|\\)).+silk\\//i.test(user_agent)\n ) {\n return 'Kindle Fire'\n } else if (/(Android|ZTE)/i.test(user_agent)) {\n if (\n !new RegExp(MOBILE).test(user_agent) ||\n /(9138B|TB782B|Nexus [97]|pixel c|HUAWEISHT|BTV|noble nook|smart ultra 6)/i.test(user_agent)\n ) {\n if (\n (/pixel[\\daxl ]{1,6}/i.test(user_agent) && !/pixel c/i.test(user_agent)) ||\n /(huaweimed-al00|tah-|APA|SM-G92|i980|zte|U304AA)/i.test(user_agent) ||\n (/lmy47v/i.test(user_agent) && !/QTAQZ3/i.test(user_agent))\n ) {\n return ANDROID\n }\n return ANDROID_TABLET\n } else {\n return ANDROID\n }\n } else if (new RegExp('(pda|' + MOBILE + ')', 'i').test(user_agent)) {\n return GENERIC_MOBILE\n } else if (new RegExp(TABLET, 'i').test(user_agent) && !new RegExp(TABLET + ' pc', 'i').test(user_agent)) {\n return GENERIC_TABLET\n } else {\n return ''\n }\n}\n\nexport const detectDeviceType = function (user_agent: string): string {\n const device = detectDevice(user_agent)\n if (\n device === IPAD ||\n device === ANDROID_TABLET ||\n device === 'Kobo' ||\n device === 'Kindle Fire' ||\n device === GENERIC_TABLET\n ) {\n return TABLET\n } else if (device === NINTENDO || device === XBOX || device === PLAYSTATION || device === OUYA) {\n return 'Console'\n } else if (device === APPLE_WATCH) {\n return 'Wearable'\n } else if (device) {\n return MOBILE\n } else {\n return 'Desktop'\n }\n}\n","import { getQueryParam, convertToURL, maskQueryParams } from './request-utils'\nimport { isNull } from './type-utils'\nimport { Properties } from '../types'\nimport Config from '../config'\nimport { each, extend, extendArray, stripEmptyProperties } from './index'\nimport { document, location, userAgent, window } from './globals'\nimport { detectBrowser, detectBrowserVersion, detectDevice, detectDeviceType, detectOS } from './user-agent-utils'\nimport { stripLeadingDollar } from './string-utils'\n\nconst URL_REGEX_PREFIX = 'https?://(.*)'\n\n// CAMPAIGN_PARAMS and EVENT_TO_PERSON_PROPERTIES should be kept in sync with\n// https://github.com/PostHog/posthog/blob/master/plugin-server/src/utils/db/utils.ts#L60\n\n// The list of campaign parameters that could be considered personal data under e.g. GDPR.\n// These can be masked in URLs and properties before being sent to posthog.\nexport const PERSONAL_DATA_CAMPAIGN_PARAMS = [\n 'gclid', // 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 'igshid', // instagram\n 'ttclid', // tiktok\n 'rdt_cid', // reddit\n 'irclid', // impact\n '_kx', // klaviyo\n]\n\nexport const CAMPAIGN_PARAMS = extendArray(\n [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_content',\n 'utm_term',\n 'gad_source', // google ads source\n 'mc_cid', // mailchimp campaign id\n ],\n PERSONAL_DATA_CAMPAIGN_PARAMS\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 MASKED = '<masked>'\n\nexport const Info = {\n campaignParams: function ({\n customTrackedParams,\n maskPersonalDataProperties,\n customPersonalDataProperties,\n }: {\n customTrackedParams?: string[]\n maskPersonalDataProperties?: boolean\n customPersonalDataProperties?: string[] | undefined\n } = {}): Record<string, string> {\n if (!document) {\n return {}\n }\n\n const paramsToMask = maskPersonalDataProperties\n ? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])\n : []\n\n return this._campaignParamsFromUrl(maskQueryParams(document.URL, paramsToMask, MASKED), customTrackedParams)\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 personInfo: function ({\n maskPersonalDataProperties,\n customPersonalDataProperties,\n }: {\n maskPersonalDataProperties?: boolean\n customPersonalDataProperties?: string[]\n } = {}) {\n const paramsToMask = maskPersonalDataProperties\n ? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])\n : []\n const url = location?.href.substring(0, 1000)\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: url ? maskQueryParams(url, paramsToMask, MASKED) : undefined,\n }\n },\n\n personPropsFromInfo: function (info: Record<string, any>): Record<string, any> {\n const { r: referrer, u: url } = info\n const referring_domain =\n referrer == null ? undefined : referrer == '$direct' ? '$direct' : convertToURL(referrer)?.host\n\n const props: Record<string, string | undefined> = {\n $referrer: referrer,\n $referring_domain: referring_domain,\n }\n if (url) {\n props['$current_url'] = url\n const location = convertToURL(url)\n props['$host'] = location?.host\n props['$pathname'] = location?.pathname\n const campaignParams = this._campaignParamsFromUrl(url)\n extend(props, campaignParams)\n }\n if (referrer) {\n const searchInfo = this._searchInfoFromReferrer(referrer)\n extend(props, searchInfo)\n }\n return props\n },\n\n initialPersonPropsFromInfo: function (info: Record<string, any>): Record<string, any> {\n const personProps = this.personPropsFromInfo(info)\n const props: Record<string, any> = {}\n each(personProps, function (val: any, key: string) {\n props[`$initial_${stripLeadingDollar(key)}`] = val\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 ({\n maskPersonalDataProperties,\n customPersonalDataProperties,\n }: {\n maskPersonalDataProperties?: boolean\n customPersonalDataProperties?: string[]\n } = {}): Properties {\n if (!userAgent) {\n return {}\n }\n const paramsToMask = maskPersonalDataProperties\n ? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])\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: maskQueryParams(location?.href, paramsToMask, MASKED),\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","import { isNumber } from './type-utils'\nimport { logger } from './logger'\n\n/**\n * Clamps a value to a range.\n * @param value the value to clamp\n * @param min the minimum value\n * @param max the maximum value\n * @param label if provided then enables logging and prefixes all logs with labels\n * @param fallbackValue if provided then returns this value if the value is not a valid number\n */\nexport function clampToRange(value: unknown, min: number, max: number, label?: string, fallbackValue?: number): number {\n if (min > max) {\n logger.warn('min cannot be greater than max.')\n min = max\n }\n\n if (!isNumber(value)) {\n label &&\n logger.warn(\n label + ' must be a number. using max or fallback. max: ' + max + ', fallback: ' + fallbackValue\n )\n return clampToRange(fallbackValue || max, min, max, label)\n } else if (value > max) {\n label && logger.warn(label + ' cannot be greater than max: ' + max + '. Using max value instead.')\n return max\n } else if (value < min) {\n label && logger.warn(label + ' cannot be less than min: ' + min + '. Using min value instead.')\n return min\n } else {\n return value\n }\n}\n","import { clampToRange } from '../utils/number-utils'\nimport { isArray, isUndefined } from '../utils/type-utils'\n\nexport function appendArray(currentValue: string[] | undefined, sampleType: string | string[]): string[] {\n return [...(currentValue ? currentValue : []), ...(isArray(sampleType) ? sampleType : [sampleType])]\n}\n\nexport function updateThreshold(currentValue: number | undefined, percent: number): number {\n return (isUndefined(currentValue) ? 1 : currentValue) * percent\n}\n\nexport function simpleHash(str: string) {\n let hash = 0\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) - hash + str.charCodeAt(i) // (hash * 31) + char code\n hash |= 0 // Convert to 32bit integer\n }\n return Math.abs(hash)\n}\n\n/*\n * receives percent as a number between 0 and 1\n */\nexport function sampleOnProperty(prop: string, percent: number): boolean {\n return simpleHash(prop) % 100 < clampToRange(percent * 100, 0, 100)\n}\n","import { clampToRange } from '../utils/number-utils'\nimport { BeforeSendFn, CaptureResult, KnownEventName } from '../types'\nimport { includes } from '../utils/string-utils'\nimport { appendArray, sampleOnProperty, updateThreshold } from '../extensions/sampling'\n\n/**\n * Provides an implementation of sampling that samples based on the distinct ID.\n * Using the provided percentage.\n * Can be used to create a beforeCapture fn for a PostHog instance.\n *\n * Setting 0.5 will cause roughly 50% of distinct ids to have events sent.\n * Not 50% of events for each distinct id.\n *\n * @param percent a number from 0 to 1, 1 means always send and, 0 means never send the event\n */\nexport function sampleByDistinctId(percent: number): BeforeSendFn {\n return (captureResult: CaptureResult | null): CaptureResult | null => {\n if (!captureResult) {\n return null\n }\n\n return sampleOnProperty(captureResult.properties.distinct_id, percent)\n ? {\n ...captureResult,\n properties: {\n ...captureResult.properties,\n $sample_type: ['sampleByDistinctId'],\n $sample_threshold: percent,\n },\n }\n : null\n }\n}\n\n/**\n * Provides an implementation of sampling that samples based on the session ID.\n * Using the provided percentage.\n * Can be used to create a beforeCapture fn for a PostHog instance.\n *\n * Setting 0.5 will cause roughly 50% of sessions to have events sent.\n * Not 50% of events for each session.\n *\n * @param percent a number from 0 to 1, 1 means always send and, 0 means never send the event\n */\nexport function sampleBySessionId(percent: number): BeforeSendFn {\n return (captureResult: CaptureResult | null): CaptureResult | null => {\n if (!captureResult) {\n return null\n }\n\n return sampleOnProperty(captureResult.properties.$session_id, percent)\n ? {\n ...captureResult,\n properties: {\n ...captureResult.properties,\n $sample_type: appendArray(captureResult.properties.$sample_type, 'sampleBySessionId'),\n $sample_threshold: updateThreshold(captureResult.properties.$sample_threshold, percent),\n },\n }\n : null\n }\n}\n\n/**\n * Provides an implementation of sampling that samples based on the event name.\n * Using the provided percentage.\n * Can be used to create a beforeCapture fn for a PostHog instance.\n *\n * @param eventNames an array of event names to sample, sampling is applied across events not per event name\n * @param percent a number from 0 to 1, 1 means always send, 0 means never send the event\n */\nexport function sampleByEvent(eventNames: KnownEventName[], percent: number): BeforeSendFn {\n return (captureResult: CaptureResult | null): CaptureResult | null => {\n if (!captureResult) {\n return null\n }\n\n if (!includes(eventNames, captureResult.event)) {\n return captureResult\n }\n\n const number = Math.random()\n return number * 100 < clampToRange(percent * 100, 0, 100)\n ? {\n ...captureResult,\n properties: {\n ...captureResult.properties,\n $sample_type: appendArray(captureResult.properties?.$sample_type, 'sampleByEvent'),\n $sample_threshold: updateThreshold(captureResult.properties?.$sample_threshold, percent),\n $sampled_events: appendArray(captureResult.properties?.$sampled_events, eventNames),\n },\n }\n : null\n }\n}\n\nexport const printAndDropEverything: BeforeSendFn = (result) => {\n // eslint-disable-next-line no-console\n console.log('Would have sent event:', result)\n return null\n}\n","import { PostHog } from '../posthog-core'\nimport { CAMPAIGN_PARAMS, EVENT_TO_PERSON_PROPERTIES, Info } from '../utils/event-utils'\nimport { each, extend } from '../utils'\nimport { includes } from '../utils/string-utils'\n\nexport const setAllPersonProfilePropertiesAsPersonPropertiesForFlags = (posthog: PostHog): void => {\n const allProperties = extend(\n {},\n Info.properties({\n maskPersonalDataProperties: posthog.config.mask_personal_data_properties,\n customPersonalDataProperties: posthog.config.custom_personal_data_properties,\n }),\n Info.campaignParams({\n customTrackedParams: posthog.config.custom_campaign_params,\n maskPersonalDataProperties: posthog.config.mask_personal_data_properties,\n customPersonalDataProperties: posthog.config.custom_personal_data_properties,\n }),\n Info.referrerInfo()\n )\n const personProperties: Record<string, string> = {}\n each(allProperties, function (v, k: string) {\n if (includes(CAMPAIGN_PARAMS, k) || includes(EVENT_TO_PERSON_PROPERTIES, k)) {\n personProperties[k] = v\n }\n })\n\n posthog.setPersonPropertiesForFlags(personProperties)\n}\n","// this file is called customizations.full.ts because it includes all customizations\n// this naming scheme allows us to create a lighter version in the future with only the most popular customizations\n// without breaking backwards compatibility\n\nimport * as customizations from '../customizations'\nimport { assignableWindow } from '../utils/globals'\nassignableWindow.posthogCustomizations = customizations\n"],"names":["win","window","undefined","global","globalThis","nativeForEach","Array","prototype","forEach","navigator","document","location","fetch","XMLHttpRequest","AbortController","Compression","userAgent","assignableWindow","includes","str","needle","indexOf","nativeIsArray","isArray","ObjProto","Object","hasOwnProperty","toString","obj","call","isUndefined","x","isNull","isNumber","Config","DEBUG","LIB_VERSION","_createLogger","prefix","logger","_log","level","console","consoleLog","_len","arguments","length","args","_key","info","_len2","_key2","warn","_len3","_key3","error","_len4","_key4","critical","_len5","_key5","uninitializedWarning","methodName","concat","createLogger","additionalPrefix","breaker","eachArray","iterator","thisArg","i","l","each","FormData","isFormData","pair","entries","key","extend","source","prop","extendArray","item","push","stripEmptyProperties","p","ret","v","k","convertToURL","url","createElement","href","getQueryParam","param","keyValuePair","queryParts","split","replace","parts","result","decodeURIComponent","_unused","maskQueryParams","maskedParams","mask","splitHash","withoutHash","hash","splitQuery","queryString","urlWithoutQueryAndHash","paramStrings","join","MOBILE","IOS","ANDROID","TABLET","ANDROID_TABLET","IPAD","APPLE","APPLE_WATCH","SAFARI","BLACKBERRY","SAMSUNG","SAMSUNG_BROWSER","SAMSUNG_INTERNET","CHROME","CHROME_OS","CHROME_IOS","INTERNET_EXPLORER","INTERNET_EXPLORER_MOBILE","OPERA","OPERA_MINI","EDGE","MICROSOFT_EDGE","FIREFOX","FIREFOX_IOS","NINTENDO","PLAYSTATION","XBOX","ANDROID_MOBILE","MOBILE_SAFARI","WINDOWS","WINDOWS_PHONE","NOKIA","OUYA","GENERIC","GENERIC_MOBILE","toLowerCase","GENERIC_TABLET","KONQUEROR","BROWSER_VERSION_REGEX_SUFFIX","DEFAULT_BROWSER_VERSION_REGEX","RegExp","XBOX_REGEX","PLAYSTATION_REGEX","NINTENDO_REGEX","BLACKBERRY_REGEX","windowsVersionMap","safariCheck","ua","vendor","isSafari","detectBrowser","user_agent","test","FACEBOOK","versionRegexes","Mozilla","osMatchers","match","_","exec","version","osVersion","versionParts","detectDevice","URL_REGEX_PREFIX","PERSONAL_DATA_CAMPAIGN_PARAMS","CAMPAIGN_PARAMS","EVENT_TO_PERSON_PROPERTIES","MASKED","Info","campaignParams","customTrackedParams","maskPersonalDataProperties","customPersonalDataProperties","paramsToMask","this","_campaignParamsFromUrl","URL","customParams","campaign_keywords","params","kwkey","kw","_searchEngine","referrer","search","_searchInfoFromReferrer","keyword","searchInfo","browser","browserVersion","regexes","regex","matches","parseFloat","browserLanguage","language","userLanguage","browserLanguagePrefix","os","rgex","resultOrFn","device","deviceType","referringDomain","_convertToURL","host","referrerInfo","$referrer","$referring_domain","personInfo","substring","r","u","personPropsFromInfo","_convertToURL2","props","pathname","initialPersonPropsFromInfo","personProps","val","s","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","timezoneOffset","Date","getTimezoneOffset","_unused2","properties","os_name","os_version","$os","$os_version","$browser","$device","$device_type","$timezone","$timezone_offset","$current_url","$host","$pathname","$raw_user_agent","$browser_version","$browser_language","$browser_language_prefix","$screen_height","screen","height","$screen_width","width","$viewport_height","innerHeight","$viewport_width","innerWidth","$lib","$lib_version","$insert_id","Math","random","$time","now","people_properties","clampToRange","value","min","max","label","fallbackValue","appendArray","currentValue","sampleType","updateThreshold","percent","sampleOnProperty","charCodeAt","abs","simpleHash","log","captureResult","distinct_id","_objectSpread","$sample_type","$sample_threshold","eventNames","_captureResult$proper","_captureResult$proper2","_captureResult$proper3","event","$sampled_events","$session_id","posthog","allProperties","config","mask_personal_data_properties","custom_personal_data_properties","custom_campaign_params","personProperties","setPersonPropertiesForFlags","posthogCustomizations","customizations"],"mappings":"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"}
1
+ {"version":3,"file":"customizations.full.js","sources":["../src/utils/globals.ts","../src/types.ts","../src/utils/string-utils.ts","../src/utils/type-utils.ts","../src/config.ts","../src/utils/logger.ts","../src/utils/index.ts","../src/utils/request-utils.ts","../src/utils/user-agent-utils.ts","../src/utils/event-utils.ts","../src/utils/number-utils.ts","../src/extensions/sampling.ts","../src/customizations/before-send.ts","../src/customizations/setAllPersonProfilePropertiesAsPersonPropertiesForFlags.ts","../src/entrypoints/customizations.full.ts"],"sourcesContent":["import { ErrorProperties } from '../extensions/exception-autocapture/error-conversion'\nimport type { PostHog } from '../posthog-core'\nimport { SessionIdManager } from '../sessionid'\nimport {\n DeadClicksAutoCaptureConfig,\n ErrorConversionArgs,\n ErrorMetadata,\n Properties,\n RemoteConfig,\n SiteAppLoader,\n} from '../types'\n\n/*\n * Global helpers to protect access to browser globals in a way that is safer for different targets\n * like DOM, SSR, Web workers etc.\n *\n * NOTE: Typically we want the \"window\" but globalThis works for both the typical browser context as\n * well as other contexts such as the web worker context. Window is still exported for any bits that explicitly require it.\n * If in doubt - export the global you need from this file and use that as an optional value. This way the code path is forced\n * to handle the case where the global is not available.\n */\n\n// eslint-disable-next-line no-restricted-globals\nconst win: (Window & typeof globalThis) | undefined = typeof window !== 'undefined' ? window : undefined\n\nexport type AssignableWindow = Window &\n typeof globalThis &\n Record<string, any> & {\n __PosthogExtensions__?: PostHogExtensions\n\n _POSTHOG_REMOTE_CONFIG?: Record<\n string,\n {\n config: RemoteConfig\n siteApps: SiteAppLoader[]\n }\n >\n }\n\n/**\n * This is our contract between (potentially) lazily loaded extensions and the SDK\n * changes to this interface can be breaking changes for users of the SDK\n */\n\nexport type PostHogExtensionKind =\n | 'toolbar'\n | 'exception-autocapture'\n | 'web-vitals'\n | 'recorder'\n | 'tracing-headers'\n | 'surveys'\n | 'dead-clicks-autocapture'\n | 'remote-config'\n\nexport interface LazyLoadedDeadClicksAutocaptureInterface {\n start: (observerTarget: Node) => void\n stop: () => void\n}\n\ninterface PostHogExtensions {\n loadExternalDependency?: (\n posthog: PostHog,\n kind: PostHogExtensionKind,\n callback: (error?: string | Event, event?: Event) => void\n ) => void\n\n loadSiteApp?: (posthog: PostHog, appUrl: string, callback: (error?: string | Event, event?: Event) => void) => void\n\n parseErrorAsProperties?: ({ error, event }: ErrorConversionArgs, metadata?: ErrorMetadata) => ErrorProperties\n errorWrappingFunctions?: {\n wrapOnError: (captureFn: (props: Properties) => void) => () => void\n wrapUnhandledRejection: (captureFn: (props: Properties) => void) => () => void\n }\n rrweb?: { record: any; version: string }\n rrwebPlugins?: { getRecordConsolePlugin: any; getRecordNetworkPlugin?: any }\n canActivateRepeatedly?: (survey: any) => boolean\n generateSurveys?: (posthog: PostHog) => any | undefined\n postHogWebVitalsCallbacks?: {\n onLCP: (metric: any) => void\n onCLS: (metric: any) => void\n onFCP: (metric: any) => void\n onINP: (metric: any) => void\n }\n tracingHeadersPatchFns?: {\n _patchFetch: (sessionManager?: SessionIdManager) => () => void\n _patchXHR: (sessionManager?: SessionIdManager) => () => void\n }\n initDeadClicksAutocapture?: (\n ph: PostHog,\n config: DeadClicksAutoCaptureConfig\n ) => LazyLoadedDeadClicksAutocaptureInterface\n}\n\nconst global: typeof globalThis | undefined = typeof globalThis !== 'undefined' ? globalThis : win\n\nexport const ArrayProto = Array.prototype\nexport const nativeForEach = ArrayProto.forEach\nexport const nativeIndexOf = ArrayProto.indexOf\n\nexport const navigator = global?.navigator\nexport const document = global?.document\nexport const location = global?.location\nexport const fetch = global?.fetch\nexport const XMLHttpRequest =\n global?.XMLHttpRequest && 'withCredentials' in new global.XMLHttpRequest() ? global.XMLHttpRequest : undefined\nexport const AbortController = global?.AbortController\nexport const userAgent = navigator?.userAgent\nexport const assignableWindow: AssignableWindow = win ?? ({} as any)\n\nexport { win as window }\n","import type { recordOptions } from './extensions/replay/types/rrweb'\nimport type { SegmentAnalytics } from './extensions/segment-integration'\nimport { PostHog } from './posthog-core'\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 *\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 `div`s 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 * Everything is allowed when there's no allowlist\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 /**\n * When set to true, autocapture will capture the text of any element that is cut or copied.\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 /**\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 /**\n * Works with session replay to use the browser's native performance observer to capture performance metrics\n */\n network_timing?: boolean\n\n /**\n * Use chrome's web vitals library to wrap fetch and capture web vitals\n */\n web_vitals?: boolean\n\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 *\n * @default 15 * 60 * 1000 (15 minutes)\n */\n __web_vitals_max_value?: number\n\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 * @default ['LCP', 'CLS', 'FCP', 'INP']\n */\n web_vitals_allowed_metrics?: SupportedWebVitalsMetrics[]\n\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 *\n * @default 5000\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 /**\n * We'll not consider a click to be a dead click, if it's followed by a scroll within `scroll_threshold_ms` milliseconds\n *\n * @default 100\n */\n scroll_threshold_ms?: number\n\n /**\n * We'll not consider a click to be a dead click, if it's followed by a selection change within `selection_change_threshold_ms` milliseconds\n *\n * @default 100\n */\n selection_change_threshold_ms?: number\n\n /**\n * We'll not consider a click to be a dead click, if it's followed by a mutation within `mutation_threshold_ms` milliseconds\n *\n * @default 2500\n */\n mutation_threshold_ms?: number\n\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 our own 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 * @default 1000\n */\n flush_interval_milliseconds: number\n}\n\nexport type BeforeSendFn = (cr: CaptureResult | null) => CaptureResult | null\n\n/**\n * Configuration options for the PostHog JavaScript SDK.\n * @see https://posthog.com/docs/libraries/js#config\n */\nexport interface PostHogConfig {\n /** URL of your PostHog instance.\n *\n * @default 'https://us.i.posthog.com'\n */\n api_host: string\n\n /**\n * If using a reverse proxy for `api_host` then this should be the actual PostHog app URL (e.g. https://us.posthog.com).\n * This ensures that links to PostHog point to the correct host.\n *\n * @default null\n */\n ui_host: string | null\n\n /**\n * The transport method to use for API requests.\n *\n * @default 'fetch'\n */\n api_transport?: 'XHR' | 'fetch'\n\n /**\n * The token for your PostHog project.\n * It should NOT be provided manually in the config, but rather passed as the first parameter to `posthog.init()`.\n */\n token: string\n\n /**\n * The name this instance will be identified by.\n * You don't need to set this most of the time,\n * but can be useful if you have several Posthog instances running at the same time.\n *\n * @default 'posthog'\n */\n name: string\n\n /**\n * Determines whether PostHog should autocapture events.\n * This setting does not affect capturing pageview events (see `capture_pageview`).\n *\n * @default true\n */\n autocapture: boolean | AutocaptureConfig\n\n /**\n * Determines whether PostHog should capture rage clicks.\n *\n * @default true\n */\n rageclick: boolean\n\n /**\n * Determines if cookie should be set on the top level domain (example.com).\n * If PostHog-js is loaded on a subdomain (test.example.com), and `cross_subdomain_cookie` is set to false,\n * it'll set the cookie on the subdomain only (test.example.com).\n *\n * NOTE: It will be set to `false` if we detect that the domain is a subdomain of a platform that is excluded from cross-subdomain cookie setting.\n * The current list of excluded platforms is `herokuapp.com`, `vercel.app`, and `netlify.app`.\n *\n * @see `isCrossDomainCookie`\n * @default true\n */\n cross_subdomain_cookie: boolean\n\n /**\n * Determines how PostHog stores information about the user. See [persistence](https://posthog.com/docs/libraries/js#persistence) for details.\n *\n * @default 'localStorage+cookie'\n */\n persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie' | 'sessionStorage'\n\n /**\n * The name for the super properties persistent store\n *\n * @default ''\n */\n persistence_name: string\n\n /** @deprecated - Use 'persistence_name' instead */\n cookie_name?: string\n\n /**\n * A function to be called once the PostHog scripts have loaded successfully.\n *\n * @param posthog_instance - The PostHog instance that has been loaded.\n */\n loaded: (posthog_instance: PostHog) => void\n\n /**\n * Determines whether PostHog should save referrer information.\n *\n * @default true\n */\n save_referrer: boolean\n\n /**\n * Determines whether PostHog should save marketing parameters.\n * These are `utm_*` paramaters and friends.\n *\n * @see {CAMPAIGN_PARAMS} from './utils/event-utils' - Default campaign parameters like utm_source, utm_medium, etc.\n * @default true\n */\n save_campaign_params: boolean\n\n /** @deprecated - Use `save_campaign_params` instead */\n store_google?: boolean\n\n /**\n * Used to extend the list of campaign parameters that are saved by default.\n *\n * @see {CAMPAIGN_PARAMS} from './utils/event-utils' - Default campaign parameters like utm_source, utm_medium, etc.\n * @default []\n */\n custom_campaign_params: string[]\n\n /**\n * Used to extend the list of user agents that are blocked by default.\n *\n * @see {DEFAULT_BLOCKED_UA_STRS} from './utils/blocked-uas' - Default list of blocked user agents.\n * @default []\n */\n custom_blocked_useragents: string[]\n\n /**\n * Determines whether PostHog should be in debug mode.\n * You can enable this to get more detailed logging.\n *\n * You can also enable this on your website by appending `?__posthog_debug=true` at the end of your URL\n * You can also call `posthog.debug()` in your code to enable debug mode\n *\n * @default false\n */\n debug: boolean\n\n /** @deprecated Use `debug` instead */\n verbose?: boolean\n\n /**\n * Determines whether PostHog should capture pageview events automatically.\n *\n * @default true\n */\n capture_pageview: boolean\n\n /**\n * Determines whether PostHog should capture pageleave events.\n * If set to `true`, it will capture pageleave events for all pages.\n * If set to `'if_capture_pageview'`, it will only capture pageleave events if `capture_pageview` is also set to `true`.\n *\n * @default 'if_capture_pageview'\n */\n capture_pageleave: boolean | 'if_capture_pageview'\n\n /**\n * Determines the number of days to store cookies for.\n *\n * @default 365\n */\n cookie_expiration: number\n\n /**\n * Determines whether PostHog should upgrade old cookies.\n * If set to `true`, the library will check for a cookie from our old js library and import super properties from it, then the old cookie is deleted.\n * This option only works in the initialization, so make sure you set it when you create the library.\n *\n * @default false\n */\n upgrade: boolean\n\n /**\n * Determines whether PostHog should disable session recording.\n *\n * @default false\n */\n disable_session_recording: boolean\n\n /**\n * Determines whether PostHog should disable persistence.\n * If set to `true`, the library will not save any data to the browser. It will also delete any data previously saved to the browser.\n *\n * @default false\n */\n disable_persistence: boolean\n\n /** @deprecated - use `disable_persistence` instead */\n disable_cookie?: boolean\n\n /**\n * Determines whether PostHog should disable surveys.\n *\n * @default false\n */\n disable_surveys: boolean\n\n /**\n * Determines whether PostHog should disable web experiments.\n *\n * Currently disabled while we're in BETA. It will be toggled to `true` in a future release.\n *\n * @default true\n */\n disable_web_experiments: boolean\n\n /**\n * Determines whether PostHog should disable any external dependency loading.\n * This will prevent PostHog from requesting any external scripts such as those needed for Session Replay, Surveys or Site Apps.\n *\n * @default false\n */\n disable_external_dependency_loading: boolean\n\n /**\n * A function to be called when a script is being loaded.\n * This can be used to modify the script before it is loaded.\n * This is useful for adding a nonce to the script, for example.\n *\n * @param script - The script element that is being loaded.\n * @returns The modified script element, or null if the script should not be loaded.\n */\n prepare_external_dependency_script?: (script: HTMLScriptElement) => HTMLScriptElement | null\n\n /**\n * A function to be called when a stylesheet is being loaded.\n * This can be used to modify the stylesheet before it is loaded.\n * This is useful for adding a nonce to the stylesheet, for example.\n *\n * @param stylesheet - The stylesheet element that is being loaded.\n * @returns The modified stylesheet element, or null if the stylesheet should not be loaded.\n */\n prepare_external_dependency_stylesheet?: (stylesheet: HTMLStyleElement) => HTMLStyleElement | null\n\n /**\n * Determines whether PostHog should enable recording console logs.\n * When undefined, it falls back to the remote config setting.\n *\n * @default undefined\n */\n enable_recording_console_log?: boolean\n\n /**\n * Determines whether PostHog should use secure cookies.\n * If this is `true`, PostHog cookies will be marked as secure,\n * meaning they will only be transmitted over HTTPS.\n *\n * @default window.location.protocol === 'https:'\n */\n secure_cookie: boolean\n\n /**\n * Determines whether PostHog should capture IP addresses.\n *\n * @default true\n */\n ip: boolean\n\n /**\n * Determines if users should be opted out of PostHog tracking by default,\n * requiring additional logic to opt them into capturing by calling `posthog.opt_in_capturing()`.\n *\n * @default false\n */\n opt_out_capturing_by_default: boolean\n\n /**\n * Determines where we'll save the information about whether users are opted out of capturing.\n *\n * @default 'localStorage'\n */\n opt_out_capturing_persistence_type: 'localStorage' | 'cookie'\n\n /**\n * Determines if users should be opted out of browser data storage by this PostHog instance by default,\n * requiring additional logic to opt them into capturing by calling `posthog.opt_in_capturing()`.\n *\n * @default false\n */\n opt_out_persistence_by_default?: boolean\n\n /**\n * Determines if users should be opted out of user agent filtering such as googlebot or other bots.\n * If this is set to `true`, PostHog will set `$browser_type` to either `bot` or `browser` for all events,\n * but will process all events as if they were from a browser.\n *\n * @default false\n */\n opt_out_useragent_filter: boolean\n\n /**\n * Determines the prefix for the cookie used to store the information about whether users are opted out of capturing.\n * When `null`, it falls back to the default prefix found in `consent.ts`.\n *\n * @default null\n */\n opt_out_capturing_cookie_prefix: string | null\n\n /**\n * Determines if users should be opted in to site apps.\n *\n * @default false\n */\n opt_in_site_apps: boolean\n\n /**\n * Determines whether PostHog should respect the Do Not Track header when computing\n * consent in `ConsentManager`.\n *\n * @see `ConsentManager`\n * @default false\n */\n respect_dnt: boolean\n\n /**\n * A list of properties that should never be sent with capture calls.\n *\n * @default []\n */\n property_denylist: string[]\n\n /** @deprecated - use `property_denylist` instead */\n property_blacklist?: string[]\n\n /**\n * A list of headers that should be sent with requests to the PostHog API.\n *\n * @default {}\n */\n request_headers: { [header_name: string]: string }\n\n /** @deprecated - use `request_headers` instead */\n xhr_headers?: { [header_name: string]: string }\n\n /**\n * A function that is called when a request to the PostHog API fails.\n *\n * @param error - The `RequestResponse` object that occurred.\n */\n on_request_error?: (error: RequestResponse) => void\n\n /** @deprecated - use `on_request_error` instead */\n on_xhr_error?: (failedRequest: XMLHttpRequest) => void\n\n /**\n * Determines whether PostHog should batch requests to the PostHog API.\n *\n * @default true\n */\n request_batching: boolean\n\n /**\n * Determines the maximum length of the properties string that can be sent with capture calls.\n *\n * @default 65535\n */\n properties_string_max_length: number\n\n /**\n * Determines the session recording options.\n *\n * @see `SessionRecordingOptions`\n * @default {}\n */\n session_recording: SessionRecordingOptions\n\n /**\n * Determines the session idle timeout in seconds.\n * Any new event that's happened after this timeout will create a new session.\n *\n * @default 30 * 60 -- 30 minutes\n */\n session_idle_timeout_seconds: number\n\n /**\n * Prevent autocapture from capturing any attribute names on elements.\n *\n * @default false\n */\n mask_all_element_attributes: boolean\n\n /**\n * Prevent autocapture from capturing `textContent` on elements.\n *\n * @default false\n */\n mask_all_text: boolean\n\n /**\n * Prevent autocapture from capturing personal data properties.\n * These include campaign parameters, UTM parameters, and other parameters that could be considered personal data under e.g. GDPR.\n *\n * @default false\n */\n mask_personal_data_properties: boolean\n\n /**\n * Custom list of personal data properties to mask.\n *\n * @default []\n */\n custom_personal_data_properties: string[]\n\n /**\n * One of the very first things the PostHog library does when init() is called\n * is make a request to the /decide endpoint on PostHog's backend.\n * This endpoint contains information on how to run the PostHog library\n * so events are properly received in the backend.\n *\n * This endpoint is required to run most features of the library.\n * However, if you're not using any of the described features,\n * you may wish to turn off the call completely to avoid an extra request\n * and reduce resource usage on both the client and the server.\n *\n * @default false\n */\n advanced_disable_decide: boolean\n\n /**\n * Will keep /decide running, but without any feature flag requests\n *\n * @default false\n */\n advanced_disable_feature_flags: boolean\n\n /**\n * Stops from firing feature flag requests on first page load.\n * Only requests feature flags when user identity or properties are updated,\n * or you manually request for flags to be loaded.\n *\n * @default false\n */\n advanced_disable_feature_flags_on_first_load: boolean\n\n /**\n * Determines whether PostHog should disable toolbar metrics.\n * This is our internal instrumentation for our toolbar in your website.\n *\n * @default false\n */\n advanced_disable_toolbar_metrics: boolean\n\n /**\n * Sets timeout for fetching feature flags\n *\n * @default 3000\n */\n feature_flag_request_timeout_ms: number\n\n /**\n * Sets timeout for fetching surveys\n *\n * @default 10000\n */\n surveys_request_timeout_ms: number\n\n /**\n * Function to get the device ID.\n * This doesn't usually need to be set, but can be useful if you want to use a custom device ID.\n *\n * @param uuid - The UUID we would use for the device ID.\n * @returns The device ID.\n *\n * @default (uuid) => uuid\n */\n get_device_id: (uuid: string) => string\n\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\n /** @deprecated - use `before_send` instead */\n sanitize_properties: ((properties: Properties, event_name: string) => Properties) | null\n\n /** @deprecated - use `before_send` instead */\n _onCapture: (eventName: string, eventData: CaptureResult) => void\n\n /**\n * Determines whether to capture performance metrics.\n * These include Network Timing and Web Vitals.\n *\n * When `undefined`, fallback to the remote configuration.\n * If `false`, neither network timing nor web vitals will work.\n * If an object, that will override the remote configuration.\n *\n * @see {PerformanceCaptureConfig}\n * @default undefined\n */\n capture_performance?: boolean | PerformanceCaptureConfig\n\n /**\n * Determines whether to disable compression when sending events to the server.\n * WARNING: Should only be used for testing. Could negatively impact performance.\n *\n * @default false\n */\n disable_compression: boolean\n\n /**\n * An object containing the `distinctID`, `isIdentifiedID`, and `featureFlags` keys,\n * where `distinctID` is a string, and `featureFlags` is an object of key-value pairs.\n *\n * Since there is a delay between initializing PostHog and fetching feature flags,\n * feature flags are not always available immediately.\n * This makes them unusable if you want to do something like redirecting a user\n * to a different page based on a feature flag.\n *\n * You can, therefore, fetch the feature flags in your server and pre-fill them here,\n * allowing PostHog to know the feature flag values immediately.\n *\n * After the SDK fetches feature flags from PostHog, it will use those flag values instead of bootstrapped ones.\n *\n * @default {}\n */\n bootstrap: BootstrapConfig\n\n /**\n * The segment analytics object.\n *\n * @see https://posthog.com/docs/libraries/segment\n */\n segment?: SegmentAnalytics\n\n /**\n * Determines whether to capture heatmaps.\n *\n * @see {HeatmapConfig}\n * @default undefined\n */\n capture_heatmaps?: boolean | HeatmapConfig\n\n /* @deprecated - use `capture_heatmaps` instead */\n enable_heatmaps?: boolean\n\n /**\n * Determines whether to capture dead clicks.\n *\n * @see {DeadClicksAutoCaptureConfig}\n * @default undefined\n */\n capture_dead_clicks?: boolean | DeadClicksAutoCaptureConfig\n\n /**\n * Determines whether to capture exceptions.\n *\n * @default undefined\n */\n capture_exceptions?: boolean\n\n /**\n * Determines whether to disable scroll properties.\n * These allow you to keep track of how far down someone scrolled in your website.\n *\n * @default false\n */\n disable_scroll_properties?: boolean\n\n /**\n * Let the pageview scroll stats use a custom css selector for the root element, e.g. `main`\n * It will use `window.document.documentElement` if not specified.\n */\n scroll_root_selector?: string | string[]\n\n /**\n * You can control whether events from PostHog-js have person processing enabled with the `person_profiles` config setting.\n * There are three options:\n * - `person_profiles: 'always'` - 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'` _(default)_ - 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 * @default 'identified_only'\n */\n person_profiles?: 'always' | 'never' | 'identified_only'\n\n /** @deprecated - use `person_profiles` instead */\n process_person?: 'always' | 'never' | 'identified_only'\n\n /**\n * Client side rate limiting\n */\n rate_limiting?: {\n /**\n * The average number of events per second that should be permitted\n *\n * @default 10\n */\n events_per_second?: number\n\n /**\n * How many events can be captured in a burst. This defaults to 10 times the events_per_second count\n *\n * @default 10 * `events_per_second`\n */\n events_burst_limit?: number\n }\n\n /**\n * Used when sending data via `fetch`, use with care.\n * This is intentionally meant to be used with NextJS `fetch`\n *\n * Incorrect `cache` 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 * Used to change the behavior of the request queue.\n * This is an advanced feature and should be used with caution.\n */\n request_queue_config?: RequestQueueConfig\n\n // ------- PREVIEW CONFIGS -------\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 // ------- RETIRED CONFIGS - NO REPLACEMENT OR USAGE -------\n\n /** @deprecated - NOT USED ANYMORE, kept here for backwards compatibility reasons */\n api_method?: string\n\n /** @deprecated - NOT USED ANYMORE, kept here for backwards compatibility reasons */\n inapp_protocol?: string\n\n /** @deprecated - NOT USED ANYMORE, kept here for backwards compatibility reasons */\n inapp_link_new_window?: boolean\n}\n\nexport interface SessionRecordingOptions {\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default 'ph-no-capture'\n */\n blockClass?: string | RegExp\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default null\n */\n blockSelector?: string | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default 'ph-ignore-input'\n */\n ignoreClass?: string | RegExp\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default 'ph-mask'\n */\n maskTextClass?: string | RegExp\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskTextSelector?: string | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskTextFn?: ((text: string, element?: HTMLElement) => string) | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskAllInputs?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskInputOptions?: recordOptions['maskInputOptions']\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n */\n maskInputFn?: ((text: string, element?: HTMLElement) => string) | null\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default {}\n */\n slimDOMOptions?: recordOptions['slimDOMOptions']\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n collectFonts?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default true\n */\n inlineStylesheet?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n recordCrossOriginIframes?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n recordHeaders?: boolean\n\n /**\n * Derived from `rrweb.record` options\n * @see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n * @default false\n */\n recordBody?: boolean\n\n /**\n * Allows local config to override remote canvas recording settings from the decide response\n */\n captureCanvas?: SessionRecordingCanvasOptions\n\n /**\n * Modify the network request before it is captured. Returning null or undefined stops it being captured\n */\n maskCapturedNetworkRequestFn?: ((data: CapturedNetworkRequest) => CapturedNetworkRequest | null | undefined) | null\n\n /** @deprecated - use maskCapturedNetworkRequestFn instead */\n maskNetworkRequestFn?: ((data: NetworkRequest) => NetworkRequest | null | undefined) | null\n\n /**\n * ADVANCED: while a user is active we take a full snapshot of the browser every interval.\n * For very few sites playback performance might be better with different interval.\n * Set to 0 to disable\n *\n * @default 1000 * 60 * 5 (5 minutes)\n */\n full_snapshot_interval_millis?: number\n\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 * @default true\n */\n compress_events?: boolean\n\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 *\n * @default 1000 * 60 * 5 (5 minutes)\n */\n session_idle_threshold_ms?: number\n\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 *\n * @default 10\n */\n __mutationRateLimiterRefillRate?: number\n\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 *\n * @default 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 RequestWithOptions {\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 QueuedRequestWithOptions extends RequestWithOptions {\n /** key of queue, e.g. 'sessionRecording' vs 'event' */\n batchKey?: string\n}\n\n// Used explicitly for retriable requests\nexport interface RetriableRequestWithOptions extends QueuedRequestWithOptions {\n retriesPerformedSoFar?: number\n}\n\n// we used to call a request that was sent to the queue with options attached `RequestQueueOptions`\n// so we can't call the options used to configure the behavior of the RequestQueue that as well,\n// so instead we call them config\nexport interface RequestQueueConfig {\n /**\n * ADVANCED - alters the frequency which PostHog sends events to the server.\n * generally speaking this is only set when apps have automatic page refreshes, or very short visits.\n * Defaults to 3 seconds when not set\n * Allowed values between 250 and 5000\n * */\n flush_interval_ms?: number\n}\n\nexport interface CaptureOptions {\n /**\n * Used when `$identify` is called\n * Will set person properties overriding previous values\n */\n $set?: Properties\n\n /**\n * Used when `$identify` is called\n * Will set person properties but only once, it will NOT override previous values\n */\n $set_once?: Properties\n\n /**\n * Used to override the desired endpoint for the captured event\n */\n _url?: string\n\n /**\n * key of queue, e.g. 'sessionRecording' vs 'event'\n */\n _batchKey?: string\n\n /**\n * If set, overrides and disables config.properties_string_max_length\n */\n _noTruncate?: boolean\n\n /**\n * If set, skips the batched queue\n */\n send_instantly?: boolean\n\n /**\n * If set, skips the client side rate limiting\n */\n skip_client_rate_limiting?: boolean\n\n /**\n * If set, overrides the desired transport method\n */\n transport?: RequestWithOptions['transport']\n\n /**\n * If set, overrides the current timestamp\n */\n timestamp?: Date\n}\n\nexport type FlagVariant = { flag: string; variant: string }\n\nexport type SessionRecordingCanvasOptions = {\n /**\n * If set, records the canvas\n *\n * @default false\n */\n recordCanvas?: boolean | null\n\n /**\n * If set, records the canvas at the given FPS\n * Can be set in the remote configuration\n * Limited between 0 and 12\n * When canvas recording is enabled, if this is not set locally, then remote config sets this as 4\n *\n * @default null-ish\n */\n canvasFps?: number | null\n\n /**\n * If set, records the canvas at the given quality\n * Can be set in the remote configuration\n * Must be a string that is a valid decimal between 0 and 1\n * When canvas recording is enabled, if this is not set locally, then remote config sets this as \"0.4\"\n *\n * @default null-ish\n */\n canvasQuality?: string | null\n}\n\n/**\n * Remote configuration for the PostHog instance\n *\n * All of these settings can be configured directly in your PostHog instance\n * Any configuration set in the client overrides the information from the server\n */\nexport interface RemoteConfig {\n /**\n * Supported compression algorithms\n */\n supportedCompression: Compression[]\n\n /**\n * If set, disables autocapture\n */\n autocapture_opt_out?: boolean\n\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\n /**\n * Whether we should use a custom endpoint for analytics\n *\n * @default { endpoint: \"/e\" }\n */\n analytics?: {\n endpoint?: string\n }\n\n /**\n * Whether the `$elements_chain` property should be sent as a string or as an array\n *\n * @default false\n */\n elementsChainAsString?: boolean\n\n /**\n * This is currently in development and may have breaking changes without a major version bump\n */\n autocaptureExceptions?: boolean | { endpoint?: string }\n\n /**\n * Session recording configuration options\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 masking?: Pick<SessionRecordingOptions, 'maskAllInputs' | 'maskTextSelector'>\n urlTriggers?: SessionRecordingUrlTrigger[]\n scriptConfig?: { script?: string | undefined }\n urlBlocklist?: SessionRecordingUrlTrigger[]\n eventTriggers?: string[]\n }\n\n /**\n * Whether surveys are enabled\n */\n surveys?: boolean\n\n /**\n * Parameters for the toolbar\n */\n toolbarParams: ToolbarParams\n\n /**\n * @deprecated renamed to toolbarParams, still present on older API responses\n */\n editorParams?: ToolbarParams\n\n /**\n * @deprecated, moved to toolbarParams\n */\n toolbarVersion: 'toolbar'\n\n /**\n * Whether the user is authenticated\n */\n isAuthenticated: boolean\n\n /**\n * List of site apps with their IDs and URLs\n */\n siteApps: { id: string; url: string }[]\n\n /**\n * Whether heatmaps are enabled\n */\n heatmaps?: boolean\n\n /**\n * Whether to only capture identified users by default\n */\n defaultIdentifiedOnly?: boolean\n\n /**\n * Whether to capture dead clicks\n */\n captureDeadClicks?: boolean\n\n /**\n * Indicates if the team has any flags enabled (if not we don't need to load them)\n */\n hasFeatureFlags?: boolean\n}\n\n/**\n * Decide returns everything we have on the remote config plus feature flags and their payloads\n */\nexport interface DecideResponse extends RemoteConfig {\n featureFlags: Record<string, string | boolean>\n featureFlagPayloads: Record<string, JsonType>\n errorsWhileComputingFlags: boolean\n requestId?: string\n flags: Record<string, FeatureFlagDetail>\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 processedBuffer: 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 type FeatureFlagDetail = {\n key: string\n enabled: boolean\n // Only used when overriding a flag payload.\n original_enabled?: boolean | undefined\n variant: string | undefined\n // Only used when overriding a flag payload.\n original_variant?: string | undefined\n reason: EvaluationReason | undefined\n metadata: FeatureFlagMetadata | undefined\n}\n\nexport type FeatureFlagMetadata = {\n id: number\n version: number | undefined\n description: string | undefined\n payload: JsonType | undefined\n // Only used when overriding a flag payload.\n original_payload?: JsonType | undefined\n}\n\nexport type EvaluationReason = {\n code: string\n condition_index: number | undefined\n description: string | undefined\n}\n\nexport type RemoteConfigFeatureFlagCallback = (payload: JsonType) => 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 | undefined | 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 EarlyAccessFeatureStage = 'concept' | 'alpha' | 'beta' | 'general-availability'\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 ErrorConversionArgs = {\n event: string | Event\n error?: Error\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","export function includes<T = any>(str: T[] | string, needle: T): boolean {\n return (str as any).indexOf(needle) !== -1\n}\n\n// UNDERSCORE\n// Embed part of the Underscore Library\nexport const trim = function (str: string): string {\n return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '')\n}\nexport const stripLeadingDollar = function (s: string): string {\n return s.replace(/^\\$/, '')\n}\n\nexport function isDistinctIdStringLike(value: string): boolean {\n return ['distinct_id', 'distinctid'].includes(value.toLowerCase())\n}\n","import { window } from './globals'\nimport { knownUnsafeEditableEvent, KnownUnsafeEditableEvent } from '../types'\nimport { includes } from './string-utils'\n\n// eslint-disable-next-line posthog-js/no-direct-array-check\nconst nativeIsArray = Array.isArray\nconst ObjProto = Object.prototype\nexport const hasOwnProperty = ObjProto.hasOwnProperty\nconst toString = ObjProto.toString\n\nexport const isArray =\n nativeIsArray ||\n function (obj: any): obj is any[] {\n return toString.call(obj) === '[object Array]'\n }\n\n// from a comment on http://dbj.org/dbj/?p=286\n// fails on only one very rare and deliberate custom object:\n// let bomb = { toString : undefined, valueOf: function(o) { return \"function BOMBA!\"; }};\nexport const isFunction = (x: unknown): x is (...args: any[]) => any => {\n // eslint-disable-next-line posthog-js/no-direct-function-check\n return typeof x === 'function'\n}\n\nexport const isNativeFunction = (x: unknown): x is (...args: any[]) => any =>\n isFunction(x) && x.toString().indexOf('[native code]') !== -1\n\n// When angular patches functions they pass the above `isNativeFunction` check (at least the MutationObserver)\nexport const isAngularZonePresent = (): boolean => {\n return !!(window as any).Zone\n}\n\n// Underscore Addons\nexport const isObject = (x: unknown): x is Record<string, any> => {\n // eslint-disable-next-line posthog-js/no-direct-object-check\n return x === Object(x) && !isArray(x)\n}\nexport const isEmptyObject = (x: unknown) => {\n if (isObject(x)) {\n for (const key in x) {\n if (hasOwnProperty.call(x, key)) {\n return false\n }\n }\n return true\n }\n return false\n}\nexport const isUndefined = (x: unknown): x is undefined => x === void 0\n\nexport const isString = (x: unknown): x is string => {\n // eslint-disable-next-line posthog-js/no-direct-string-check\n return toString.call(x) == '[object String]'\n}\n\nexport const isEmptyString = (x: unknown): boolean => isString(x) && x.trim().length === 0\n\nexport const isNull = (x: unknown): x is null => {\n // eslint-disable-next-line posthog-js/no-direct-null-check\n return x === null\n}\n\n/*\n sometimes you want to check if something is null or undefined\n that's what this is for\n */\nexport const isNullish = (x: unknown): x is null | undefined => isUndefined(x) || isNull(x)\n\nexport const isNumber = (x: unknown): x is number => {\n // eslint-disable-next-line posthog-js/no-direct-number-check\n return toString.call(x) == '[object Number]'\n}\nexport const isBoolean = (x: unknown): x is boolean => {\n // eslint-disable-next-line posthog-js/no-direct-boolean-check\n return toString.call(x) === '[object Boolean]'\n}\n\nexport const isDocument = (x: unknown): x is Document => {\n // eslint-disable-next-line posthog-js/no-direct-document-check\n return x instanceof Document\n}\n\nexport const isFormData = (x: unknown): x is FormData => {\n // eslint-disable-next-line posthog-js/no-direct-form-data-check\n return x instanceof FormData\n}\n\nexport const isFile = (x: unknown): x is File => {\n // eslint-disable-next-line posthog-js/no-direct-file-check\n return x instanceof File\n}\n\nexport const isError = (x: unknown): x is Error => {\n return x instanceof Error\n}\n\nexport const isKnownUnsafeEditableEvent = (x: unknown): x is KnownUnsafeEditableEvent => {\n return includes(knownUnsafeEditableEvent as unknown as string[], x)\n}\n","import packageInfo from '../package.json'\n\n// overridden in posthog-core,\n// e.g. Config.DEBUG = Config.DEBUG || instance.config.debug\nconst Config = {\n DEBUG: false,\n LIB_VERSION: packageInfo.version,\n}\n\nexport default Config\n","import Config from '../config'\nimport { isUndefined } from './type-utils'\nimport { assignableWindow, window } from './globals'\n\nexport type Logger = {\n _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => void\n info: (...args: any[]) => void\n warn: (...args: any[]) => void\n error: (...args: any[]) => void\n critical: (...args: any[]) => void\n uninitializedWarning: (methodName: string) => void\n createLogger: (prefix: string) => Logger\n}\n\nconst _createLogger = (prefix: string): Logger => {\n const logger: Logger = {\n _log: (level: 'log' | 'warn' | 'error', ...args: any[]) => {\n if (\n window &&\n (Config.DEBUG || assignableWindow.POSTHOG_DEBUG) &&\n !isUndefined(window.console) &&\n window.console\n ) {\n const consoleLog =\n '__rrweb_original__' in window.console[level]\n ? (window.console[level] as any)['__rrweb_original__']\n : window.console[level]\n\n // eslint-disable-next-line no-console\n consoleLog(prefix, ...args)\n }\n },\n\n info: (...args: any[]) => {\n logger._log('log', ...args)\n },\n\n warn: (...args: any[]) => {\n logger._log('warn', ...args)\n },\n\n error: (...args: any[]) => {\n logger._log('error', ...args)\n },\n\n critical: (...args: any[]) => {\n // Critical errors are always logged to the console\n // eslint-disable-next-line no-console\n console.error(prefix, ...args)\n },\n\n uninitializedWarning: (methodName: string) => {\n logger.error(`You must initialize PostHog before calling ${methodName}`)\n },\n\n createLogger: (additionalPrefix: string) => _createLogger(`${prefix} ${additionalPrefix}`),\n }\n return logger\n}\n\nexport const logger = _createLogger('[PostHog.js]')\n\nexport const createLogger = logger.createLogger\n","import { Breaker, Properties } from '../types'\nimport { hasOwnProperty, isArray, isFormData, isNull, isNullish, isString } from './type-utils'\nimport { logger } from './logger'\nimport { nativeForEach, nativeIndexOf } from './globals'\n\nconst breaker: Breaker = {}\n\nexport function eachArray<E = any>(\n obj: E[] | null | undefined,\n iterator: (value: E, key: number) => void | Breaker,\n thisArg?: any\n): void {\n if (isArray(obj)) {\n if (nativeForEach && obj.forEach === nativeForEach) {\n obj.forEach(iterator, thisArg)\n } else if ('length' in obj && obj.length === +obj.length) {\n for (let i = 0, l = obj.length; i < l; i++) {\n if (i in obj && iterator.call(thisArg, obj[i], i) === breaker) {\n return\n }\n }\n }\n }\n}\n\n/**\n * @param {*=} obj\n * @param {function(...*)=} iterator\n * @param {Object=} thisArg\n */\nexport function each(obj: any, iterator: (value: any, key: any) => void | Breaker, thisArg?: any): void {\n if (isNullish(obj)) {\n return\n }\n if (isArray(obj)) {\n return eachArray(obj, iterator, thisArg)\n }\n if (isFormData(obj)) {\n for (const pair of obj.entries()) {\n if (iterator.call(thisArg, pair[1], pair[0]) === breaker) {\n return\n }\n }\n return\n }\n for (const key in obj) {\n if (hasOwnProperty.call(obj, key)) {\n if (iterator.call(thisArg, obj[key], key) === breaker) {\n return\n }\n }\n }\n}\n\nexport const extend = function (obj: Record<string, any>, ...args: Record<string, any>[]): Record<string, any> {\n eachArray(args, function (source) {\n for (const prop in source) {\n if (source[prop] !== void 0) {\n obj[prop] = source[prop]\n }\n }\n })\n return obj\n}\n\nexport const extendArray = function <T>(obj: T[], ...args: T[][]): T[] {\n eachArray(args, function (source) {\n eachArray(source, function (item) {\n obj.push(item)\n })\n })\n return obj\n}\n\nexport const include = function (\n obj: null | string | Array<any> | Record<string, any>,\n target: any\n): boolean | Breaker {\n let found = false\n if (isNull(obj)) {\n return found\n }\n if (nativeIndexOf && obj.indexOf === nativeIndexOf) {\n return obj.indexOf(target) != -1\n }\n each(obj, function (value) {\n if (found || (found = value === target)) {\n return breaker\n }\n return\n })\n return found\n}\n\n/**\n * Object.entries() polyfill\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries\n */\nexport function entries<T = any>(obj: Record<string, T>): [string, T][] {\n const ownProps = Object.keys(obj)\n let i = ownProps.length\n const resArray = new Array(i) // preallocate the Array\n\n while (i--) {\n resArray[i] = [ownProps[i], obj[ownProps[i]]]\n }\n return resArray\n}\n\nexport const trySafe = function <T>(fn: () => T): T | undefined {\n try {\n return fn()\n } catch {\n return undefined\n }\n}\n\nexport const safewrap = function <F extends (...args: any[]) => any = (...args: any[]) => any>(f: F): F {\n return function (...args) {\n try {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return f.apply(this, args)\n } catch (e) {\n logger.critical(\n 'Implementation error. Please turn on debug mode and open a ticket on https://app.posthog.com/home#panel=support%3Asupport%3A.'\n )\n logger.critical(e)\n }\n } as F\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport const safewrapClass = function (klass: Function, functions: string[]): void {\n for (let i = 0; i < functions.length; i++) {\n klass.prototype[functions[i]] = safewrap(klass.prototype[functions[i]])\n }\n}\n\nexport const stripEmptyProperties = function (p: Properties): Properties {\n const ret: Properties = {}\n each(p, function (v, k) {\n if (isString(v) && v.length > 0) {\n ret[k] = v\n }\n })\n return ret\n}\n\n/**\n * Deep copies an object.\n * It handles cycles by replacing all references to them with `undefined`\n * Also supports customizing native values\n *\n * @param value\n * @param customizer\n * @returns {{}|undefined|*}\n */\nfunction deepCircularCopy<T extends Record<string, any> = Record<string, any>>(\n value: T,\n customizer?: <K extends keyof T = keyof T>(value: T[K], key?: K) => T[K]\n): T | undefined {\n const COPY_IN_PROGRESS_SET = new Set()\n\n function internalDeepCircularCopy(value: T, key?: string): T | undefined {\n if (value !== Object(value)) return customizer ? customizer(value as any, key) : value // primitive value\n\n if (COPY_IN_PROGRESS_SET.has(value)) return undefined\n COPY_IN_PROGRESS_SET.add(value)\n let result: T\n\n if (isArray(value)) {\n result = [] as any as T\n eachArray(value, (it) => {\n result.push(internalDeepCircularCopy(it))\n })\n } else {\n result = {} as T\n each(value, (val, key) => {\n if (!COPY_IN_PROGRESS_SET.has(val)) {\n ;(result as any)[key] = internalDeepCircularCopy(val, key)\n }\n })\n }\n return result\n }\n return internalDeepCircularCopy(value)\n}\n\nexport function _copyAndTruncateStrings<T extends Record<string, any> = Record<string, any>>(\n object: T,\n maxStringLength: number | null\n): T {\n return deepCircularCopy(object, (value: any) => {\n if (isString(value) && !isNull(maxStringLength)) {\n return (value as string).slice(0, maxStringLength)\n }\n return value\n }) as T\n}\n\n// NOTE: Update PostHogConfig docs if you change this list\n// We will not try to catch all bullets here, but we should make an effort to catch the most common ones\n// You should be highly against adding more to this list, because ultimately customers can configure\n// their `cross_subdomain_cookie` setting to anything they want.\nconst EXCLUDED_FROM_CROSS_SUBDOMAIN_COOKIE = ['herokuapp.com', 'vercel.app', 'netlify.app']\nexport function isCrossDomainCookie(documentLocation: Location | undefined) {\n const hostname = documentLocation?.hostname\n\n if (!isString(hostname)) {\n return false\n }\n // split and slice isn't a great way to match arbitrary domains,\n // but it's good enough for ensuring we only match herokuapp.com when it is the TLD\n // for the hostname\n const lastTwoParts = hostname.split('.').slice(-2).join('.')\n\n for (const excluded of EXCLUDED_FROM_CROSS_SUBDOMAIN_COOKIE) {\n if (lastTwoParts === excluded) {\n return false\n }\n }\n\n return true\n}\n\nexport function find<T>(value: T[], predicate: (value: T) => boolean): T | undefined {\n for (let i = 0; i < value.length; i++) {\n if (predicate(value[i])) {\n return value[i]\n }\n }\n return undefined\n}\n\n// Use this instead of element.addEventListener to avoid eslint errors\n// this properly implements the default options for passive event listeners\nexport function addEventListener(\n element: Window | Document | Element | undefined,\n event: string,\n callback: EventListener,\n options?: AddEventListenerOptions\n): void {\n const { capture = false, passive = true } = options ?? {}\n\n // This is the only place where we are allowed to call this function\n // because the whole idea is that we should be calling this instead of the built-in one\n // eslint-disable-next-line posthog-js/no-add-event-listener\n element?.addEventListener(event, callback, { capture, passive })\n}\n","import { each } from './'\n\nimport { isArray, isFile, isUndefined } from './type-utils'\nimport { logger } from './logger'\nimport { document } from './globals'\n\nconst localDomains = ['localhost', '127.0.0.1']\n\n/**\n * IE11 doesn't support `new URL`\n * so we can create an anchor element and use that to parse the URL\n * there's a lot of overlap between HTMLHyperlinkElementUtils and URL\n * meaning useful properties like `pathname` are available on both\n */\nexport const convertToURL = (url: string): HTMLAnchorElement | null => {\n const location = document?.createElement('a')\n if (isUndefined(location)) {\n return null\n }\n\n location.href = url\n return location\n}\n\nexport const formDataToQuery = function (formdata: Record<string, any> | FormData, arg_separator = '&'): string {\n let use_val: string\n let use_key: string\n const tph_arr: string[] = []\n\n each(formdata, function (val: File | string | undefined, key: string | undefined) {\n // the key might be literally the string undefined for e.g. if {undefined: 'something'}\n if (isUndefined(val) || isUndefined(key) || key === 'undefined') {\n return\n }\n\n use_val = encodeURIComponent(isFile(val) ? val.name : val.toString())\n use_key = encodeURIComponent(key)\n tph_arr[tph_arr.length] = use_key + '=' + use_val\n })\n\n return tph_arr.join(arg_separator)\n}\n\n// NOTE: Once we get rid of IE11/op_mini we can start using URLSearchParams\nexport const getQueryParam = function (url: string, param: string): string {\n const withoutHash: string = url.split('#')[0] || ''\n\n // Split only on the first ? to sort problem out for those with multiple ?s\n // and then remove them\n const queryParams: string = withoutHash.split(/\\?(.*)/)[1] || ''\n const cleanedQueryParams = queryParams.replace(/^\\?+/g, '')\n\n const queryParts = cleanedQueryParams.split('&')\n let keyValuePair\n\n for (let i = 0; i < queryParts.length; i++) {\n const parts = queryParts[i].split('=')\n if (parts[0] === param) {\n keyValuePair = parts\n break\n }\n }\n\n if (!isArray(keyValuePair) || keyValuePair.length < 2) {\n return ''\n } else {\n let result = keyValuePair[1]\n try {\n result = decodeURIComponent(result)\n } catch {\n logger.error('Skipping decoding for malformed query param: ' + result)\n }\n return result.replace(/\\+/g, ' ')\n }\n}\n\n// replace any query params in the url with the provided mask value. Tries to keep the URL as instant as possible,\n// including preserving malformed text in most cases\nexport const maskQueryParams = function <T extends string | undefined>(\n url: T,\n maskedParams: string[] | undefined,\n mask: string\n): T extends string ? string : undefined {\n if (!url || !maskedParams || !maskedParams.length) {\n return url as any\n }\n\n const splitHash = url.split('#')\n const withoutHash: string = splitHash[0] || ''\n const hash = splitHash[1]\n\n const splitQuery: string[] = withoutHash.split('?')\n const queryString: string = splitQuery[1]\n const urlWithoutQueryAndHash: string = splitQuery[0]\n const queryParts = (queryString || '').split('&')\n\n // use an array of strings rather than an object to preserve ordering and duplicates\n const paramStrings: string[] = []\n\n for (let i = 0; i < queryParts.length; i++) {\n const keyValuePair = queryParts[i].split('=')\n if (!isArray(keyValuePair)) {\n continue\n } else if (maskedParams.includes(keyValuePair[0])) {\n paramStrings.push(keyValuePair[0] + '=' + mask)\n } else {\n paramStrings.push(queryParts[i])\n }\n }\n\n let result = urlWithoutQueryAndHash\n if (queryString != null) {\n result += '?' + paramStrings.join('&')\n }\n if (hash != null) {\n result += '#' + hash\n }\n\n return result as any\n}\n\nexport const _getHashParam = function (hash: string, param: string): string | null {\n const matches = hash.match(new RegExp(param + '=([^&]*)'))\n return matches ? matches[1] : null\n}\n\nexport const isLocalhost = (): boolean => {\n return localDomains.includes(location.hostname)\n}\n","import { isFunction, isUndefined } from './type-utils'\nimport { includes } from './string-utils'\n\n/**\n * this device detection code is (at time of writing) about 3% of the size of the entire library\n * this is mostly because the identifiers user in regexes and results can't be minified away since\n * they have meaning\n *\n * so, there are some pre-uglifying choices in the code to help reduce the size\n * e.g. many repeated strings are stored as variables and then old-fashioned concatenated together\n *\n * TL;DR here be dragons\n */\nconst FACEBOOK = 'Facebook'\nconst MOBILE = 'Mobile'\nconst IOS = 'iOS'\nconst ANDROID = 'Android'\nconst TABLET = 'Tablet'\nconst ANDROID_TABLET = ANDROID + ' ' + TABLET\nconst IPAD = 'iPad'\nconst APPLE = 'Apple'\nconst APPLE_WATCH = APPLE + ' Watch'\nconst SAFARI = 'Safari'\nconst BLACKBERRY = 'BlackBerry'\nconst SAMSUNG = 'Samsung'\nconst SAMSUNG_BROWSER = SAMSUNG + 'Browser'\nconst SAMSUNG_INTERNET = SAMSUNG + ' Internet'\nconst CHROME = 'Chrome'\nconst CHROME_OS = CHROME + ' OS'\nconst CHROME_IOS = CHROME + ' ' + IOS\nconst INTERNET_EXPLORER = 'Internet Explorer'\nconst INTERNET_EXPLORER_MOBILE = INTERNET_EXPLORER + ' ' + MOBILE\nconst OPERA = 'Opera'\nconst OPERA_MINI = OPERA + ' Mini'\nconst EDGE = 'Edge'\nconst MICROSOFT_EDGE = 'Microsoft ' + EDGE\nconst FIREFOX = 'Firefox'\nconst FIREFOX_IOS = FIREFOX + ' ' + IOS\nconst NINTENDO = 'Nintendo'\nconst PLAYSTATION = 'PlayStation'\nconst XBOX = 'Xbox'\nconst ANDROID_MOBILE = ANDROID + ' ' + MOBILE\nconst MOBILE_SAFARI = MOBILE + ' ' + SAFARI\nconst WINDOWS = 'Windows'\nconst WINDOWS_PHONE = WINDOWS + ' Phone'\nconst NOKIA = 'Nokia'\nconst OUYA = 'Ouya'\nconst GENERIC = 'Generic'\nconst GENERIC_MOBILE = GENERIC + ' ' + MOBILE.toLowerCase()\nconst GENERIC_TABLET = GENERIC + ' ' + TABLET.toLowerCase()\nconst KONQUEROR = 'Konqueror'\n\nconst BROWSER_VERSION_REGEX_SUFFIX = '(\\\\d+(\\\\.\\\\d+)?)'\nconst DEFAULT_BROWSER_VERSION_REGEX = new RegExp('Version/' + BROWSER_VERSION_REGEX_SUFFIX)\n\nconst XBOX_REGEX = new RegExp(XBOX, 'i')\nconst PLAYSTATION_REGEX = new RegExp(PLAYSTATION + ' \\\\w+', 'i')\nconst NINTENDO_REGEX = new RegExp(NINTENDO + ' \\\\w+', 'i')\nconst BLACKBERRY_REGEX = new RegExp(BLACKBERRY + '|PlayBook|BB10', 'i')\n\nconst windowsVersionMap: Record<string, string> = {\n 'NT3.51': 'NT 3.11',\n 'NT4.0': 'NT 4.0',\n '5.0': '2000',\n '5.1': 'XP',\n '5.2': 'XP',\n '6.0': 'Vista',\n '6.1': '7',\n '6.2': '8',\n '6.3': '8.1',\n '6.4': '10',\n '10.0': '10',\n}\n\n/**\n * Safari detection turns out to be complicated. For e.g. https://stackoverflow.com/a/29696509\n * We can be slightly loose because some options have been ruled out (e.g. firefox on iOS)\n * before this check is made\n */\nfunction isSafari(userAgent: string): boolean {\n return includes(userAgent, SAFARI) && !includes(userAgent, CHROME) && !includes(userAgent, ANDROID)\n}\n\nconst safariCheck = (ua: string, vendor?: string) => (vendor && includes(vendor, APPLE)) || isSafari(ua)\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 */\nexport const detectBrowser = function (user_agent: string, vendor: string | undefined): string {\n vendor = vendor || '' // vendor is undefined for at least IE9\n\n if (includes(user_agent, ' OPR/') && includes(user_agent, 'Mini')) {\n return OPERA_MINI\n } else if (includes(user_agent, ' OPR/')) {\n return OPERA\n } else if (BLACKBERRY_REGEX.test(user_agent)) {\n return BLACKBERRY\n } else if (includes(user_agent, 'IE' + MOBILE) || includes(user_agent, 'WPDesktop')) {\n return INTERNET_EXPLORER_MOBILE\n }\n // https://developer.samsung.com/internet/user-agent-string-format\n else if (includes(user_agent, SAMSUNG_BROWSER)) {\n return SAMSUNG_INTERNET\n } else if (includes(user_agent, EDGE) || includes(user_agent, 'Edg/')) {\n return MICROSOFT_EDGE\n } else if (includes(user_agent, 'FBIOS')) {\n return FACEBOOK + ' ' + MOBILE\n } else if (includes(user_agent, 'UCWEB') || includes(user_agent, 'UCBrowser')) {\n return 'UC Browser'\n } else if (includes(user_agent, 'CriOS')) {\n return CHROME_IOS // why not just Chrome?\n } else if (includes(user_agent, 'CrMo')) {\n return CHROME\n } else if (includes(user_agent, CHROME)) {\n return CHROME\n } else if (includes(user_agent, ANDROID) && includes(user_agent, SAFARI)) {\n return ANDROID_MOBILE\n } else if (includes(user_agent, 'FxiOS')) {\n return FIREFOX_IOS\n } else if (includes(user_agent.toLowerCase(), KONQUEROR.toLowerCase())) {\n return KONQUEROR\n } else if (safariCheck(user_agent, vendor)) {\n return includes(user_agent, MOBILE) ? MOBILE_SAFARI : SAFARI\n } else if (includes(user_agent, FIREFOX)) {\n return FIREFOX\n } else if (includes(user_agent, 'MSIE') || includes(user_agent, 'Trident/')) {\n return INTERNET_EXPLORER\n } else if (includes(user_agent, 'Gecko')) {\n return FIREFOX\n }\n\n return ''\n}\n\nconst versionRegexes: Record<string, RegExp[]> = {\n [INTERNET_EXPLORER_MOBILE]: [new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)],\n [MICROSOFT_EDGE]: [new RegExp(EDGE + '?\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [CHROME]: [new RegExp('(' + CHROME + '|CrMo)\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [CHROME_IOS]: [new RegExp('CriOS\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n 'UC Browser': [new RegExp('(UCBrowser|UCWEB)\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [SAFARI]: [DEFAULT_BROWSER_VERSION_REGEX],\n [MOBILE_SAFARI]: [DEFAULT_BROWSER_VERSION_REGEX],\n [OPERA]: [new RegExp('(' + OPERA + '|OPR)\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [FIREFOX]: [new RegExp(FIREFOX + '\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [FIREFOX_IOS]: [new RegExp('FxiOS\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [KONQUEROR]: [new RegExp('Konqueror[:/]?' + BROWSER_VERSION_REGEX_SUFFIX, 'i')],\n // not every blackberry user agent has the version after the name\n [BLACKBERRY]: [new RegExp(BLACKBERRY + ' ' + BROWSER_VERSION_REGEX_SUFFIX), DEFAULT_BROWSER_VERSION_REGEX],\n [ANDROID_MOBILE]: [new RegExp('android\\\\s' + BROWSER_VERSION_REGEX_SUFFIX, 'i')],\n [SAMSUNG_INTERNET]: [new RegExp(SAMSUNG_BROWSER + '\\\\/' + BROWSER_VERSION_REGEX_SUFFIX)],\n [INTERNET_EXPLORER]: [new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX)],\n Mozilla: [new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)],\n}\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 */\nexport const detectBrowserVersion = function (userAgent: string, vendor: string | undefined): number | null {\n const browser = detectBrowser(userAgent, vendor)\n const regexes: RegExp[] | undefined = versionRegexes[browser as keyof typeof versionRegexes]\n if (isUndefined(regexes)) {\n return null\n }\n\n for (let i = 0; i < regexes.length; i++) {\n const regex = regexes[i]\n const matches = userAgent.match(regex)\n if (matches) {\n return parseFloat(matches[matches.length - 2])\n }\n }\n return null\n}\n\n// to avoid repeating regexes or calling them twice, we have an array of matches\n// the first regex that matches uses its matcher function to return the result\nconst osMatchers: [\n RegExp,\n [string, string] | ((match: RegExpMatchArray | null, user_agent: string) => [string, string]),\n][] = [\n [\n new RegExp(XBOX + '; ' + XBOX + ' (.*?)[);]', 'i'),\n (match) => {\n return [XBOX, (match && match[1]) || '']\n },\n ],\n [new RegExp(NINTENDO, 'i'), [NINTENDO, '']],\n [new RegExp(PLAYSTATION, 'i'), [PLAYSTATION, '']],\n [BLACKBERRY_REGEX, [BLACKBERRY, '']],\n [\n new RegExp(WINDOWS, 'i'),\n (_, user_agent) => {\n if (/Phone/.test(user_agent) || /WPDesktop/.test(user_agent)) {\n return [WINDOWS_PHONE, '']\n }\n // not all JS versions support negative lookbehind, so we need two checks here\n if (new RegExp(MOBILE).test(user_agent) && !/IEMobile\\b/.test(user_agent)) {\n return [WINDOWS + ' ' + MOBILE, '']\n }\n const match = /Windows NT ([0-9.]+)/i.exec(user_agent)\n if (match && match[1]) {\n const version = match[1]\n let osVersion = windowsVersionMap[version] || ''\n if (/arm/i.test(user_agent)) {\n osVersion = 'RT'\n }\n return [WINDOWS, osVersion]\n }\n return [WINDOWS, '']\n },\n ],\n [\n /((iPhone|iPad|iPod).*?OS (\\d+)_(\\d+)_?(\\d+)?|iPhone)/,\n (match) => {\n if (match && match[3]) {\n const versionParts = [match[3], match[4], match[5] || '0']\n return [IOS, versionParts.join('.')]\n }\n return [IOS, '']\n },\n ],\n [\n /(watch.*\\/(\\d+\\.\\d+\\.\\d+)|watch os,(\\d+\\.\\d+),)/i,\n (match) => {\n // e.g. Watch4,3/5.3.8 (16U680)\n let version = ''\n if (match && match.length >= 3) {\n version = isUndefined(match[2]) ? match[3] : match[2]\n }\n return ['watchOS', version]\n },\n ],\n [\n new RegExp('(' + ANDROID + ' (\\\\d+)\\\\.(\\\\d+)\\\\.?(\\\\d+)?|' + ANDROID + ')', 'i'),\n (match) => {\n if (match && match[2]) {\n const versionParts = [match[2], match[3], match[4] || '0']\n return [ANDROID, versionParts.join('.')]\n }\n return [ANDROID, '']\n },\n ],\n [\n /Mac OS X (\\d+)[_.](\\d+)[_.]?(\\d+)?/i,\n (match) => {\n const result: [string, string] = ['Mac OS X', '']\n if (match && match[1]) {\n const versionParts = [match[1], match[2], match[3] || '0']\n result[1] = versionParts.join('.')\n }\n return result\n },\n ],\n [\n /Mac/i,\n // mop up a few non-standard UAs that should match mac\n ['Mac OS X', ''],\n ],\n [/CrOS/, [CHROME_OS, '']],\n [/Linux|debian/i, ['Linux', '']],\n]\n\nexport const detectOS = function (user_agent: string): [string, string] {\n for (let i = 0; i < osMatchers.length; i++) {\n const [rgex, resultOrFn] = osMatchers[i]\n const match = rgex.exec(user_agent)\n const result = match && (isFunction(resultOrFn) ? resultOrFn(match, user_agent) : resultOrFn)\n if (result) {\n return result\n }\n }\n return ['', '']\n}\n\nexport const detectDevice = function (user_agent: string): string {\n if (NINTENDO_REGEX.test(user_agent)) {\n return NINTENDO\n } else if (PLAYSTATION_REGEX.test(user_agent)) {\n return PLAYSTATION\n } else if (XBOX_REGEX.test(user_agent)) {\n return XBOX\n } else if (new RegExp(OUYA, 'i').test(user_agent)) {\n return OUYA\n } else if (new RegExp('(' + WINDOWS_PHONE + '|WPDesktop)', 'i').test(user_agent)) {\n return WINDOWS_PHONE\n } else if (/iPad/.test(user_agent)) {\n return IPAD\n } else if (/iPod/.test(user_agent)) {\n return 'iPod Touch'\n } else if (/iPhone/.test(user_agent)) {\n return 'iPhone'\n } else if (/(watch)(?: ?os[,/]|\\d,\\d\\/)[\\d.]+/i.test(user_agent)) {\n return APPLE_WATCH\n } else if (BLACKBERRY_REGEX.test(user_agent)) {\n return BLACKBERRY\n } else if (/(kobo)\\s(ereader|touch)/i.test(user_agent)) {\n return 'Kobo'\n } else if (new RegExp(NOKIA, 'i').test(user_agent)) {\n return NOKIA\n } else if (\n // Kindle Fire without Silk / Echo Show\n /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\\))/i.test(user_agent) ||\n // Kindle Fire HD\n /(kf[a-z]+)( bui|\\)).+silk\\//i.test(user_agent)\n ) {\n return 'Kindle Fire'\n } else if (/(Android|ZTE)/i.test(user_agent)) {\n if (\n !new RegExp(MOBILE).test(user_agent) ||\n /(9138B|TB782B|Nexus [97]|pixel c|HUAWEISHT|BTV|noble nook|smart ultra 6)/i.test(user_agent)\n ) {\n if (\n (/pixel[\\daxl ]{1,6}/i.test(user_agent) && !/pixel c/i.test(user_agent)) ||\n /(huaweimed-al00|tah-|APA|SM-G92|i980|zte|U304AA)/i.test(user_agent) ||\n (/lmy47v/i.test(user_agent) && !/QTAQZ3/i.test(user_agent))\n ) {\n return ANDROID\n }\n return ANDROID_TABLET\n } else {\n return ANDROID\n }\n } else if (new RegExp('(pda|' + MOBILE + ')', 'i').test(user_agent)) {\n return GENERIC_MOBILE\n } else if (new RegExp(TABLET, 'i').test(user_agent) && !new RegExp(TABLET + ' pc', 'i').test(user_agent)) {\n return GENERIC_TABLET\n } else {\n return ''\n }\n}\n\nexport const detectDeviceType = function (user_agent: string): string {\n const device = detectDevice(user_agent)\n if (\n device === IPAD ||\n device === ANDROID_TABLET ||\n device === 'Kobo' ||\n device === 'Kindle Fire' ||\n device === GENERIC_TABLET\n ) {\n return TABLET\n } else if (device === NINTENDO || device === XBOX || device === PLAYSTATION || device === OUYA) {\n return 'Console'\n } else if (device === APPLE_WATCH) {\n return 'Wearable'\n } else if (device) {\n return MOBILE\n } else {\n return 'Desktop'\n }\n}\n","import { getQueryParam, convertToURL, maskQueryParams } from './request-utils'\nimport { isNull } from './type-utils'\nimport { Properties } from '../types'\nimport Config from '../config'\nimport { each, extend, extendArray, stripEmptyProperties } from './index'\nimport { document, location, userAgent, window } from './globals'\nimport { detectBrowser, detectBrowserVersion, detectDevice, detectDeviceType, detectOS } from './user-agent-utils'\nimport { stripLeadingDollar } from './string-utils'\n\nconst URL_REGEX_PREFIX = 'https?://(.*)'\n\n// CAMPAIGN_PARAMS and EVENT_TO_PERSON_PROPERTIES should be kept in sync with\n// https://github.com/PostHog/posthog/blob/master/plugin-server/src/utils/db/utils.ts#L60\n\n// The list of campaign parameters that could be considered personal data under e.g. GDPR.\n// These can be masked in URLs and properties before being sent to posthog.\nexport const PERSONAL_DATA_CAMPAIGN_PARAMS = [\n 'gclid', // 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 'igshid', // instagram\n 'ttclid', // tiktok\n 'rdt_cid', // reddit\n 'irclid', // impact\n '_kx', // klaviyo\n]\n\nexport const CAMPAIGN_PARAMS = extendArray(\n [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_content',\n 'utm_term',\n 'gad_source', // google ads source\n 'mc_cid', // mailchimp campaign id\n ],\n PERSONAL_DATA_CAMPAIGN_PARAMS\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 '$screen_height',\n '$screen_width',\n '$viewport_height',\n '$viewport_width',\n '$raw_user_agent',\n]\n\nexport const MASKED = '<masked>'\n\nexport const Info = {\n campaignParams: function ({\n customTrackedParams,\n maskPersonalDataProperties,\n customPersonalDataProperties,\n }: {\n customTrackedParams?: string[]\n maskPersonalDataProperties?: boolean\n customPersonalDataProperties?: string[] | undefined\n } = {}): Record<string, string> {\n if (!document) {\n return {}\n }\n\n const paramsToMask = maskPersonalDataProperties\n ? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])\n : []\n\n return this._campaignParamsFromUrl(maskQueryParams(document.URL, paramsToMask, MASKED), customTrackedParams)\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 personInfo: function ({\n maskPersonalDataProperties,\n customPersonalDataProperties,\n }: {\n maskPersonalDataProperties?: boolean\n customPersonalDataProperties?: string[]\n } = {}) {\n const paramsToMask = maskPersonalDataProperties\n ? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])\n : []\n const url = location?.href.substring(0, 1000)\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: url ? maskQueryParams(url, paramsToMask, MASKED) : undefined,\n }\n },\n\n personPropsFromInfo: function (info: Record<string, any>): Record<string, any> {\n const { r: referrer, u: url } = info\n const referring_domain =\n referrer == null ? undefined : referrer == '$direct' ? '$direct' : convertToURL(referrer)?.host\n\n const props: Record<string, string | undefined> = {\n $referrer: referrer,\n $referring_domain: referring_domain,\n }\n if (url) {\n props['$current_url'] = url\n const location = convertToURL(url)\n props['$host'] = location?.host\n props['$pathname'] = location?.pathname\n const campaignParams = this._campaignParamsFromUrl(url)\n extend(props, campaignParams)\n }\n if (referrer) {\n const searchInfo = this._searchInfoFromReferrer(referrer)\n extend(props, searchInfo)\n }\n return props\n },\n\n initialPersonPropsFromInfo: function (info: Record<string, any>): Record<string, any> {\n const personProps = this.personPropsFromInfo(info)\n const props: Record<string, any> = {}\n each(personProps, function (val: any, key: string) {\n props[`$initial_${stripLeadingDollar(key)}`] = val\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 ({\n maskPersonalDataProperties,\n customPersonalDataProperties,\n }: {\n maskPersonalDataProperties?: boolean\n customPersonalDataProperties?: string[]\n } = {}): Properties {\n if (!userAgent) {\n return {}\n }\n const paramsToMask = maskPersonalDataProperties\n ? extendArray([], PERSONAL_DATA_CAMPAIGN_PARAMS, customPersonalDataProperties || [])\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: maskQueryParams(location?.href, paramsToMask, MASKED),\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","import { isNumber } from './type-utils'\nimport { logger } from './logger'\n\n/**\n * Clamps a value to a range.\n * @param value the value to clamp\n * @param min the minimum value\n * @param max the maximum value\n * @param label if provided then enables logging and prefixes all logs with labels\n * @param fallbackValue if provided then returns this value if the value is not a valid number\n */\nexport function clampToRange(value: unknown, min: number, max: number, label?: string, fallbackValue?: number): number {\n if (min > max) {\n logger.warn('min cannot be greater than max.')\n min = max\n }\n\n if (!isNumber(value)) {\n label &&\n logger.warn(\n label + ' must be a number. using max or fallback. max: ' + max + ', fallback: ' + fallbackValue\n )\n return clampToRange(fallbackValue || max, min, max, label)\n } else if (value > max) {\n label && logger.warn(label + ' cannot be greater than max: ' + max + '. Using max value instead.')\n return max\n } else if (value < min) {\n label && logger.warn(label + ' cannot be less than min: ' + min + '. Using min value instead.')\n return min\n } else {\n return value\n }\n}\n","import { clampToRange } from '../utils/number-utils'\nimport { isArray, isUndefined } from '../utils/type-utils'\n\nexport function appendArray(currentValue: string[] | undefined, sampleType: string | string[]): string[] {\n return [...(currentValue ? currentValue : []), ...(isArray(sampleType) ? sampleType : [sampleType])]\n}\n\nexport function updateThreshold(currentValue: number | undefined, percent: number): number {\n return (isUndefined(currentValue) ? 1 : currentValue) * percent\n}\n\nexport function simpleHash(str: string) {\n let hash = 0\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) - hash + str.charCodeAt(i) // (hash * 31) + char code\n hash |= 0 // Convert to 32bit integer\n }\n return Math.abs(hash)\n}\n\n/*\n * receives percent as a number between 0 and 1\n */\nexport function sampleOnProperty(prop: string, percent: number): boolean {\n return simpleHash(prop) % 100 < clampToRange(percent * 100, 0, 100)\n}\n","import { clampToRange } from '../utils/number-utils'\nimport { BeforeSendFn, CaptureResult, KnownEventName } from '../types'\nimport { includes } from '../utils/string-utils'\nimport { appendArray, sampleOnProperty, updateThreshold } from '../extensions/sampling'\n\n/**\n * Provides an implementation of sampling that samples based on the distinct ID.\n * Using the provided percentage.\n * Can be used to create a beforeCapture fn for a PostHog instance.\n *\n * Setting 0.5 will cause roughly 50% of distinct ids to have events sent.\n * Not 50% of events for each distinct id.\n *\n * @param percent a number from 0 to 1, 1 means always send and, 0 means never send the event\n */\nexport function sampleByDistinctId(percent: number): BeforeSendFn {\n return (captureResult: CaptureResult | null): CaptureResult | null => {\n if (!captureResult) {\n return null\n }\n\n return sampleOnProperty(captureResult.properties.distinct_id, percent)\n ? {\n ...captureResult,\n properties: {\n ...captureResult.properties,\n $sample_type: ['sampleByDistinctId'],\n $sample_threshold: percent,\n },\n }\n : null\n }\n}\n\n/**\n * Provides an implementation of sampling that samples based on the session ID.\n * Using the provided percentage.\n * Can be used to create a beforeCapture fn for a PostHog instance.\n *\n * Setting 0.5 will cause roughly 50% of sessions to have events sent.\n * Not 50% of events for each session.\n *\n * @param percent a number from 0 to 1, 1 means always send and, 0 means never send the event\n */\nexport function sampleBySessionId(percent: number): BeforeSendFn {\n return (captureResult: CaptureResult | null): CaptureResult | null => {\n if (!captureResult) {\n return null\n }\n\n return sampleOnProperty(captureResult.properties.$session_id, percent)\n ? {\n ...captureResult,\n properties: {\n ...captureResult.properties,\n $sample_type: appendArray(captureResult.properties.$sample_type, 'sampleBySessionId'),\n $sample_threshold: updateThreshold(captureResult.properties.$sample_threshold, percent),\n },\n }\n : null\n }\n}\n\n/**\n * Provides an implementation of sampling that samples based on the event name.\n * Using the provided percentage.\n * Can be used to create a beforeCapture fn for a PostHog instance.\n *\n * @param eventNames an array of event names to sample, sampling is applied across events not per event name\n * @param percent a number from 0 to 1, 1 means always send, 0 means never send the event\n */\nexport function sampleByEvent(eventNames: KnownEventName[], percent: number): BeforeSendFn {\n return (captureResult: CaptureResult | null): CaptureResult | null => {\n if (!captureResult) {\n return null\n }\n\n if (!includes(eventNames, captureResult.event)) {\n return captureResult\n }\n\n const number = Math.random()\n return number * 100 < clampToRange(percent * 100, 0, 100)\n ? {\n ...captureResult,\n properties: {\n ...captureResult.properties,\n $sample_type: appendArray(captureResult.properties?.$sample_type, 'sampleByEvent'),\n $sample_threshold: updateThreshold(captureResult.properties?.$sample_threshold, percent),\n $sampled_events: appendArray(captureResult.properties?.$sampled_events, eventNames),\n },\n }\n : null\n }\n}\n\nexport const printAndDropEverything: BeforeSendFn = (result) => {\n // eslint-disable-next-line no-console\n console.log('Would have sent event:', result)\n return null\n}\n","import { PostHog } from '../posthog-core'\nimport { CAMPAIGN_PARAMS, EVENT_TO_PERSON_PROPERTIES, Info } from '../utils/event-utils'\nimport { each, extend } from '../utils'\nimport { includes } from '../utils/string-utils'\n\nexport const setAllPersonProfilePropertiesAsPersonPropertiesForFlags = (posthog: PostHog): void => {\n const allProperties = extend(\n {},\n Info.properties({\n maskPersonalDataProperties: posthog.config.mask_personal_data_properties,\n customPersonalDataProperties: posthog.config.custom_personal_data_properties,\n }),\n Info.campaignParams({\n customTrackedParams: posthog.config.custom_campaign_params,\n maskPersonalDataProperties: posthog.config.mask_personal_data_properties,\n customPersonalDataProperties: posthog.config.custom_personal_data_properties,\n }),\n Info.referrerInfo()\n )\n const personProperties: Record<string, string> = {}\n each(allProperties, function (v, k: string) {\n if (includes(CAMPAIGN_PARAMS, k) || includes(EVENT_TO_PERSON_PROPERTIES, k)) {\n personProperties[k] = v\n }\n })\n\n posthog.setPersonPropertiesForFlags(personProperties)\n}\n","// this file is called customizations.full.ts because it includes all customizations\n// this naming scheme allows us to create a lighter version in the future with only the most popular customizations\n// without breaking backwards compatibility\n\nimport * as customizations from '../customizations'\nimport { assignableWindow } from '../utils/globals'\nassignableWindow.posthogCustomizations = customizations\n"],"names":["win","window","undefined","global","globalThis","nativeForEach","Array","prototype","forEach","navigator","document","location","fetch","XMLHttpRequest","AbortController","Compression","userAgent","assignableWindow","includes","str","needle","indexOf","nativeIsArray","isArray","ObjProto","Object","hasOwnProperty","toString","obj","call","isUndefined","x","isNull","isNumber","Config","DEBUG","LIB_VERSION","_createLogger","prefix","logger","_log","level","console","consoleLog","_len","arguments","length","args","_key","info","_len2","_key2","warn","_len3","_key3","error","_len4","_key4","critical","_len5","_key5","uninitializedWarning","methodName","concat","createLogger","additionalPrefix","breaker","eachArray","iterator","thisArg","i","l","each","FormData","isFormData","pair","entries","key","extend","source","prop","extendArray","item","push","stripEmptyProperties","p","ret","v","k","convertToURL","url","createElement","href","getQueryParam","param","keyValuePair","queryParts","split","replace","parts","result","decodeURIComponent","_unused","maskQueryParams","maskedParams","mask","splitHash","withoutHash","hash","splitQuery","queryString","urlWithoutQueryAndHash","paramStrings","join","MOBILE","IOS","ANDROID","TABLET","ANDROID_TABLET","IPAD","APPLE","APPLE_WATCH","SAFARI","BLACKBERRY","SAMSUNG","SAMSUNG_BROWSER","SAMSUNG_INTERNET","CHROME","CHROME_OS","CHROME_IOS","INTERNET_EXPLORER","INTERNET_EXPLORER_MOBILE","OPERA","OPERA_MINI","EDGE","MICROSOFT_EDGE","FIREFOX","FIREFOX_IOS","NINTENDO","PLAYSTATION","XBOX","ANDROID_MOBILE","MOBILE_SAFARI","WINDOWS","WINDOWS_PHONE","NOKIA","OUYA","GENERIC","GENERIC_MOBILE","toLowerCase","GENERIC_TABLET","KONQUEROR","BROWSER_VERSION_REGEX_SUFFIX","DEFAULT_BROWSER_VERSION_REGEX","RegExp","XBOX_REGEX","PLAYSTATION_REGEX","NINTENDO_REGEX","BLACKBERRY_REGEX","windowsVersionMap","safariCheck","ua","vendor","isSafari","detectBrowser","user_agent","test","FACEBOOK","versionRegexes","Mozilla","osMatchers","match","_","exec","version","osVersion","versionParts","detectDevice","URL_REGEX_PREFIX","PERSONAL_DATA_CAMPAIGN_PARAMS","CAMPAIGN_PARAMS","EVENT_TO_PERSON_PROPERTIES","MASKED","Info","campaignParams","customTrackedParams","maskPersonalDataProperties","customPersonalDataProperties","paramsToMask","this","_campaignParamsFromUrl","URL","customParams","campaign_keywords","params","kwkey","kw","_searchEngine","referrer","search","_searchInfoFromReferrer","keyword","searchInfo","browser","browserVersion","regexes","regex","matches","parseFloat","browserLanguage","language","userLanguage","browserLanguagePrefix","os","rgex","resultOrFn","device","deviceType","referringDomain","_convertToURL","host","referrerInfo","$referrer","$referring_domain","personInfo","substring","r","u","personPropsFromInfo","_convertToURL2","props","pathname","initialPersonPropsFromInfo","personProps","val","s","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","timezoneOffset","Date","getTimezoneOffset","_unused2","properties","os_name","os_version","$os","$os_version","$browser","$device","$device_type","$timezone","$timezone_offset","$current_url","$host","$pathname","$raw_user_agent","$browser_version","$browser_language","$browser_language_prefix","$screen_height","screen","height","$screen_width","width","$viewport_height","innerHeight","$viewport_width","innerWidth","$lib","$lib_version","$insert_id","Math","random","$time","now","people_properties","clampToRange","value","min","max","label","fallbackValue","appendArray","currentValue","sampleType","updateThreshold","percent","sampleOnProperty","charCodeAt","abs","simpleHash","log","captureResult","distinct_id","_objectSpread","$sample_type","$sample_threshold","eventNames","_captureResult$proper","_captureResult$proper2","_captureResult$proper3","event","$sampled_events","$session_id","posthog","allProperties","config","mask_personal_data_properties","custom_personal_data_properties","custom_campaign_params","personProperties","setPersonPropertiesForFlags","posthogCustomizations","customizations"],"mappings":"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"}