posthog-js 1.161.3 → 1.161.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.full.js +2 -2
- package/dist/array.full.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/exception-autocapture.js.map +1 -1
- package/dist/lib/src/constants.d.ts +1 -0
- package/dist/lib/src/posthog-core.d.ts +2 -0
- package/dist/lib/src/types.d.ts +4 -2
- package/dist/lib/src/web-experiments-types.d.ts +33 -0
- package/dist/lib/src/web-experiments.d.ts +21 -0
- package/dist/lib/src/web-experiments.test.d.ts +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +58 -3
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/lib/package.json +1 -1
- package/lib/src/constants.d.ts +1 -0
- package/lib/src/constants.js +1 -0
- package/lib/src/constants.js.map +1 -1
- package/lib/src/posthog-core.d.ts +2 -0
- package/lib/src/posthog-core.js +9 -5
- package/lib/src/posthog-core.js.map +1 -1
- package/lib/src/request.js +19 -6
- package/lib/src/request.js.map +1 -1
- package/lib/src/types.d.ts +4 -2
- package/lib/src/types.js.map +1 -1
- package/lib/src/web-experiments-types.d.ts +33 -0
- package/lib/src/web-experiments-types.js +2 -0
- package/lib/src/web-experiments-types.js.map +1 -0
- package/lib/src/web-experiments.d.ts +21 -0
- package/lib/src/web-experiments.js +205 -0
- package/lib/src/web-experiments.js.map +1 -0
- package/lib/src/web-experiments.test.d.ts +1 -0
- package/lib/src/web-experiments.test.js +310 -0
- package/lib/src/web-experiments.test.js.map +1 -0
- package/package.json +1 -1
package/lib/src/request.js
CHANGED
|
@@ -30,7 +30,7 @@ import Config from './config';
|
|
|
30
30
|
import { Compression } from './types';
|
|
31
31
|
import { formDataToQuery } from './utils/request-utils';
|
|
32
32
|
import { logger } from './utils/logger';
|
|
33
|
-
import {
|
|
33
|
+
import { AbortController, fetch, navigator, XMLHttpRequest } from './utils/globals';
|
|
34
34
|
import { gzipSync, strToU8 } from 'fflate';
|
|
35
35
|
// eslint-disable-next-line compat/compat
|
|
36
36
|
export var SUPPORTS_REQUEST = !!XMLHttpRequest || !!fetch;
|
|
@@ -58,21 +58,27 @@ var encodePostData = function (_a) {
|
|
|
58
58
|
}
|
|
59
59
|
if (compression === Compression.GZipJS) {
|
|
60
60
|
var gzipData = gzipSync(strToU8(JSON.stringify(data)), { mtime: 0 });
|
|
61
|
+
var blob = new Blob([gzipData], { type: CONTENT_TYPE_PLAIN });
|
|
61
62
|
return {
|
|
62
63
|
contentType: CONTENT_TYPE_PLAIN,
|
|
63
|
-
body:
|
|
64
|
+
body: blob,
|
|
65
|
+
estimatedSize: blob.size,
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
if (compression === Compression.Base64) {
|
|
67
69
|
var b64data = _base64Encode(JSON.stringify(data));
|
|
70
|
+
var encodedBody = encodeToDataString(b64data);
|
|
68
71
|
return {
|
|
69
72
|
contentType: CONTENT_TYPE_FORM,
|
|
70
|
-
body:
|
|
73
|
+
body: encodedBody,
|
|
74
|
+
estimatedSize: new Blob([encodedBody]).size,
|
|
71
75
|
};
|
|
72
76
|
}
|
|
77
|
+
var jsonBody = JSON.stringify(data);
|
|
73
78
|
return {
|
|
74
79
|
contentType: CONTENT_TYPE_JSON,
|
|
75
|
-
body:
|
|
80
|
+
body: jsonBody,
|
|
81
|
+
estimatedSize: new Blob([jsonBody]).size,
|
|
76
82
|
};
|
|
77
83
|
};
|
|
78
84
|
var xhr = function (options) {
|
|
@@ -115,7 +121,7 @@ var xhr = function (options) {
|
|
|
115
121
|
};
|
|
116
122
|
var _fetch = function (options) {
|
|
117
123
|
var _a;
|
|
118
|
-
var _b = (_a = encodePostData(options)) !== null && _a !== void 0 ? _a : {}, contentType = _b.contentType, body = _b.body;
|
|
124
|
+
var _b = (_a = encodePostData(options)) !== null && _a !== void 0 ? _a : {}, contentType = _b.contentType, body = _b.body, estimatedSize = _b.estimatedSize;
|
|
119
125
|
// eslint-disable-next-line compat/compat
|
|
120
126
|
var headers = new Headers();
|
|
121
127
|
each(options.headers, function (headerValue, headerName) {
|
|
@@ -136,7 +142,14 @@ var _fetch = function (options) {
|
|
|
136
142
|
fetch(url, {
|
|
137
143
|
method: (options === null || options === void 0 ? void 0 : options.method) || 'GET',
|
|
138
144
|
headers: headers,
|
|
139
|
-
|
|
145
|
+
// if body is greater than 64kb, then fetch with keepalive will error
|
|
146
|
+
// see 8:10:5 at https://fetch.spec.whatwg.org/#http-network-or-cache-fetch,
|
|
147
|
+
// but we do want to set keepalive sometimes as it can help with success
|
|
148
|
+
// when e.g. a page is being closed
|
|
149
|
+
// so let's get the best of both worlds and only set keepalive for POST requests
|
|
150
|
+
// where the body is less than 64kb
|
|
151
|
+
// NB this is fetch keepalive and not http keepalive
|
|
152
|
+
keepalive: options.method === 'POST' && (estimatedSize || 0) < 64 * 1024,
|
|
140
153
|
body: body,
|
|
141
154
|
signal: aborter === null || aborter === void 0 ? void 0 : aborter.signal,
|
|
142
155
|
})
|
package/lib/src/request.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/request.ts"],"names":[],"mappings":"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","sourcesContent":["import { _base64Encode, each, find } from './utils'\nimport Config from './config'\nimport { Compression, RequestOptions, RequestResponse } from './types'\nimport { formDataToQuery } from './utils/request-utils'\n\nimport { logger } from './utils/logger'\nimport { fetch, XMLHttpRequest, AbortController, navigator } from './utils/globals'\nimport { gzipSync, strToU8 } from 'fflate'\n\n// eslint-disable-next-line compat/compat\nexport const SUPPORTS_REQUEST = !!XMLHttpRequest || !!fetch\n\nconst CONTENT_TYPE_PLAIN = 'text/plain'\nconst CONTENT_TYPE_JSON = 'application/json'\nconst CONTENT_TYPE_FORM = 'application/x-www-form-urlencoded'\n\ntype EncodedBody = {\n contentType: string\n body: string | BlobPart\n}\n\nexport const extendURLParams = (url: string, params: Record<string, any>): string => {\n const [baseUrl, search] = url.split('?')\n const newParams = { ...params }\n\n search?.split('&').forEach((pair) => {\n const [key] = pair.split('=')\n delete newParams[key]\n })\n\n let newSearch = formDataToQuery(newParams)\n newSearch = newSearch ? (search ? search + '&' : '') + newSearch : search\n\n return `${baseUrl}?${newSearch}`\n}\n\nconst encodeToDataString = (data: string | Record<string, any>): string => {\n return 'data=' + encodeURIComponent(typeof data === 'string' ? data : JSON.stringify(data))\n}\n\nconst encodePostData = ({ data, compression }: RequestOptions): EncodedBody | undefined => {\n if (!data) {\n return\n }\n\n if (compression === Compression.GZipJS) {\n const gzipData = gzipSync(strToU8(JSON.stringify(data)), { mtime: 0 })\n return {\n contentType: CONTENT_TYPE_PLAIN,\n body: new Blob([gzipData], { type: CONTENT_TYPE_PLAIN }),\n }\n }\n\n if (compression === Compression.Base64) {\n const b64data = _base64Encode(JSON.stringify(data))\n\n return {\n contentType: CONTENT_TYPE_FORM,\n body: encodeToDataString(b64data),\n }\n }\n\n return {\n contentType: CONTENT_TYPE_JSON,\n body: JSON.stringify(data),\n }\n}\n\nconst xhr = (options: RequestOptions) => {\n const req = new XMLHttpRequest!()\n req.open(options.method || 'GET', options.url, true)\n const { contentType, body } = encodePostData(options) ?? {}\n\n each(options.headers, function (headerValue, headerName) {\n req.setRequestHeader(headerName, headerValue)\n })\n\n if (contentType) {\n req.setRequestHeader('Content-Type', contentType)\n }\n\n if (options.timeout) {\n req.timeout = options.timeout\n }\n // send the ph_optout cookie\n // withCredentials cannot be modified until after calling .open on Android and Mobile Safari\n req.withCredentials = true\n req.onreadystatechange = () => {\n // XMLHttpRequest.DONE == 4, except in safari 4\n if (req.readyState === 4) {\n const response: RequestResponse = {\n statusCode: req.status,\n text: req.responseText,\n }\n if (req.status === 200) {\n try {\n response.json = JSON.parse(req.responseText)\n } catch {\n // logger.error(e)\n }\n }\n\n options.callback?.(response)\n }\n }\n req.send(body)\n}\n\nconst _fetch = (options: RequestOptions) => {\n const { contentType, body } = encodePostData(options) ?? {}\n\n // eslint-disable-next-line compat/compat\n const headers = new Headers()\n each(options.headers, function (headerValue, headerName) {\n headers.append(headerName, headerValue)\n })\n\n if (contentType) {\n headers.append('Content-Type', contentType)\n }\n\n const url = options.url\n let aborter: { signal: any; timeout: ReturnType<typeof setTimeout> } | null = null\n\n if (AbortController) {\n const controller = new AbortController()\n aborter = {\n signal: controller.signal,\n timeout: setTimeout(() => controller.abort(), options.timeout),\n }\n }\n\n fetch!(url, {\n method: options?.method || 'GET',\n headers,\n keepalive: options.method === 'POST',\n body,\n signal: aborter?.signal,\n })\n .then((response) => {\n return response.text().then((responseText) => {\n const res: RequestResponse = {\n statusCode: response.status,\n text: responseText,\n }\n\n if (response.status === 200) {\n try {\n res.json = JSON.parse(responseText)\n } catch (e) {\n logger.error(e)\n }\n }\n\n options.callback?.(res)\n })\n })\n .catch((error) => {\n logger.error(error)\n options.callback?.({ statusCode: 0, text: error })\n })\n .finally(() => (aborter ? clearTimeout(aborter.timeout) : null))\n\n return\n}\n\nconst _sendBeacon = (options: RequestOptions) => {\n // beacon documentation https://w3c.github.io/beacon/\n // beacons format the message and use the type property\n\n const url = extendURLParams(options.url, {\n beacon: '1',\n })\n\n try {\n const { contentType, body } = encodePostData(options) ?? {}\n // sendBeacon requires a blob so we convert it\n const sendBeaconBody = typeof body === 'string' ? new Blob([body], { type: contentType }) : body\n navigator!.sendBeacon!(url, sendBeaconBody)\n } catch {\n // send beacon is a best-effort, fire-and-forget mechanism on page unload,\n // we don't want to throw errors here\n }\n}\n\nconst AVAILABLE_TRANSPORTS: { transport: RequestOptions['transport']; method: (options: RequestOptions) => void }[] = []\n\n// We add the transports in order of preference\n\nif (XMLHttpRequest) {\n AVAILABLE_TRANSPORTS.push({\n transport: 'XHR',\n method: xhr,\n })\n}\n\nif (fetch) {\n AVAILABLE_TRANSPORTS.push({\n transport: 'fetch',\n method: _fetch,\n })\n}\n\nif (navigator?.sendBeacon) {\n AVAILABLE_TRANSPORTS.push({\n transport: 'sendBeacon',\n method: _sendBeacon,\n })\n}\n\n// This is the entrypoint. It takes care of sanitizing the options and then calls the appropriate request method.\nexport const request = (_options: RequestOptions) => {\n // Clone the options so we don't modify the original object\n const options = { ..._options }\n options.timeout = options.timeout || 60000\n\n options.url = extendURLParams(options.url, {\n _: new Date().getTime().toString(),\n ver: Config.LIB_VERSION,\n compression: options.compression,\n })\n\n const transport = options.transport ?? 'XHR'\n\n const transportMethod =\n find(AVAILABLE_TRANSPORTS, (t) => t.transport === transport)?.method ?? AVAILABLE_TRANSPORTS[0].method\n\n if (!transportMethod) {\n throw new Error('No available transport method')\n }\n\n transportMethod(options)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/request.ts"],"names":[],"mappings":"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","sourcesContent":["import { _base64Encode, each, find } from './utils'\nimport Config from './config'\nimport { Compression, RequestOptions, RequestResponse } from './types'\nimport { formDataToQuery } from './utils/request-utils'\n\nimport { logger } from './utils/logger'\nimport { AbortController, fetch, navigator, XMLHttpRequest } from './utils/globals'\nimport { gzipSync, strToU8 } from 'fflate'\n\n// eslint-disable-next-line compat/compat\nexport const SUPPORTS_REQUEST = !!XMLHttpRequest || !!fetch\n\nconst CONTENT_TYPE_PLAIN = 'text/plain'\nconst CONTENT_TYPE_JSON = 'application/json'\nconst CONTENT_TYPE_FORM = 'application/x-www-form-urlencoded'\n\ntype EncodedBody = {\n contentType: string\n body: string | BlobPart\n estimatedSize: number\n}\n\nexport const extendURLParams = (url: string, params: Record<string, any>): string => {\n const [baseUrl, search] = url.split('?')\n const newParams = { ...params }\n\n search?.split('&').forEach((pair) => {\n const [key] = pair.split('=')\n delete newParams[key]\n })\n\n let newSearch = formDataToQuery(newParams)\n newSearch = newSearch ? (search ? search + '&' : '') + newSearch : search\n\n return `${baseUrl}?${newSearch}`\n}\n\nconst encodeToDataString = (data: string | Record<string, any>): string => {\n return 'data=' + encodeURIComponent(typeof data === 'string' ? data : JSON.stringify(data))\n}\n\nconst encodePostData = ({ data, compression }: RequestOptions): EncodedBody | undefined => {\n if (!data) {\n return\n }\n\n if (compression === Compression.GZipJS) {\n const gzipData = gzipSync(strToU8(JSON.stringify(data)), { mtime: 0 })\n const blob = new Blob([gzipData], { type: CONTENT_TYPE_PLAIN })\n return {\n contentType: CONTENT_TYPE_PLAIN,\n body: blob,\n estimatedSize: blob.size,\n }\n }\n\n if (compression === Compression.Base64) {\n const b64data = _base64Encode(JSON.stringify(data))\n const encodedBody = encodeToDataString(b64data)\n\n return {\n contentType: CONTENT_TYPE_FORM,\n body: encodedBody,\n estimatedSize: new Blob([encodedBody]).size,\n }\n }\n\n const jsonBody = JSON.stringify(data)\n return {\n contentType: CONTENT_TYPE_JSON,\n body: jsonBody,\n estimatedSize: new Blob([jsonBody]).size,\n }\n}\n\nconst xhr = (options: RequestOptions) => {\n const req = new XMLHttpRequest!()\n req.open(options.method || 'GET', options.url, true)\n const { contentType, body } = encodePostData(options) ?? {}\n\n each(options.headers, function (headerValue, headerName) {\n req.setRequestHeader(headerName, headerValue)\n })\n\n if (contentType) {\n req.setRequestHeader('Content-Type', contentType)\n }\n\n if (options.timeout) {\n req.timeout = options.timeout\n }\n // send the ph_optout cookie\n // withCredentials cannot be modified until after calling .open on Android and Mobile Safari\n req.withCredentials = true\n req.onreadystatechange = () => {\n // XMLHttpRequest.DONE == 4, except in safari 4\n if (req.readyState === 4) {\n const response: RequestResponse = {\n statusCode: req.status,\n text: req.responseText,\n }\n if (req.status === 200) {\n try {\n response.json = JSON.parse(req.responseText)\n } catch {\n // logger.error(e)\n }\n }\n\n options.callback?.(response)\n }\n }\n req.send(body)\n}\n\nconst _fetch = (options: RequestOptions) => {\n const { contentType, body, estimatedSize } = encodePostData(options) ?? {}\n\n // eslint-disable-next-line compat/compat\n const headers = new Headers()\n each(options.headers, function (headerValue, headerName) {\n headers.append(headerName, headerValue)\n })\n\n if (contentType) {\n headers.append('Content-Type', contentType)\n }\n\n const url = options.url\n let aborter: { signal: any; timeout: ReturnType<typeof setTimeout> } | null = null\n\n if (AbortController) {\n const controller = new AbortController()\n aborter = {\n signal: controller.signal,\n timeout: setTimeout(() => controller.abort(), options.timeout),\n }\n }\n\n fetch!(url, {\n method: options?.method || 'GET',\n headers,\n // if body is greater than 64kb, then fetch with keepalive will error\n // see 8:10:5 at https://fetch.spec.whatwg.org/#http-network-or-cache-fetch,\n // but we do want to set keepalive sometimes as it can help with success\n // when e.g. a page is being closed\n // so let's get the best of both worlds and only set keepalive for POST requests\n // where the body is less than 64kb\n // NB this is fetch keepalive and not http keepalive\n keepalive: options.method === 'POST' && (estimatedSize || 0) < 64 * 1024,\n body,\n signal: aborter?.signal,\n })\n .then((response) => {\n return response.text().then((responseText) => {\n const res: RequestResponse = {\n statusCode: response.status,\n text: responseText,\n }\n\n if (response.status === 200) {\n try {\n res.json = JSON.parse(responseText)\n } catch (e) {\n logger.error(e)\n }\n }\n\n options.callback?.(res)\n })\n })\n .catch((error) => {\n logger.error(error)\n options.callback?.({ statusCode: 0, text: error })\n })\n .finally(() => (aborter ? clearTimeout(aborter.timeout) : null))\n\n return\n}\n\nconst _sendBeacon = (options: RequestOptions) => {\n // beacon documentation https://w3c.github.io/beacon/\n // beacons format the message and use the type property\n\n const url = extendURLParams(options.url, {\n beacon: '1',\n })\n\n try {\n const { contentType, body } = encodePostData(options) ?? {}\n // sendBeacon requires a blob so we convert it\n const sendBeaconBody = typeof body === 'string' ? new Blob([body], { type: contentType }) : body\n navigator!.sendBeacon!(url, sendBeaconBody)\n } catch {\n // send beacon is a best-effort, fire-and-forget mechanism on page unload,\n // we don't want to throw errors here\n }\n}\n\nconst AVAILABLE_TRANSPORTS: { transport: RequestOptions['transport']; method: (options: RequestOptions) => void }[] = []\n\n// We add the transports in order of preference\n\nif (XMLHttpRequest) {\n AVAILABLE_TRANSPORTS.push({\n transport: 'XHR',\n method: xhr,\n })\n}\n\nif (fetch) {\n AVAILABLE_TRANSPORTS.push({\n transport: 'fetch',\n method: _fetch,\n })\n}\n\nif (navigator?.sendBeacon) {\n AVAILABLE_TRANSPORTS.push({\n transport: 'sendBeacon',\n method: _sendBeacon,\n })\n}\n\n// This is the entrypoint. It takes care of sanitizing the options and then calls the appropriate request method.\nexport const request = (_options: RequestOptions) => {\n // Clone the options so we don't modify the original object\n const options = { ..._options }\n options.timeout = options.timeout || 60000\n\n options.url = extendURLParams(options.url, {\n _: new Date().getTime().toString(),\n ver: Config.LIB_VERSION,\n compression: options.compression,\n })\n\n const transport = options.transport ?? 'XHR'\n\n const transportMethod =\n find(AVAILABLE_TRANSPORTS, (t) => t.transport === transport)?.method ?? AVAILABLE_TRANSPORTS[0].method\n\n if (!transportMethod) {\n throw new Error('No available transport method')\n }\n\n transportMethod(options)\n}\n"]}
|
package/lib/src/types.d.ts
CHANGED
|
@@ -135,6 +135,7 @@ export interface PostHogConfig {
|
|
|
135
135
|
/** @deprecated - use `disable_persistence` instead */
|
|
136
136
|
disable_cookie?: boolean;
|
|
137
137
|
disable_surveys: boolean;
|
|
138
|
+
disable_web_experiments: boolean;
|
|
138
139
|
/** If set, posthog-js will never load external scripts such as those needed for Session Replay or Surveys. */
|
|
139
140
|
disable_external_dependency_loading?: boolean;
|
|
140
141
|
enable_recording_console_log?: boolean;
|
|
@@ -368,9 +369,10 @@ export interface ToolbarParams {
|
|
|
368
369
|
featureFlags?: Record<string, string | boolean>;
|
|
369
370
|
}
|
|
370
371
|
export type SnippetArrayItem = [method: string, ...args: any[]];
|
|
371
|
-
export type
|
|
372
|
+
export type JsonRecord = {
|
|
372
373
|
[key: string]: JsonType;
|
|
373
|
-
}
|
|
374
|
+
};
|
|
375
|
+
export type JsonType = string | number | boolean | null | JsonRecord | Array<JsonType>;
|
|
374
376
|
/** A feature that isn't publicly available yet.*/
|
|
375
377
|
export interface EarlyAccessFeature {
|
|
376
378
|
name: string;
|
package/lib/src/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AA0RA,MAAM,CAAN,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,iCAAkB,CAAA;IAClB,gCAAiB,CAAA;AACrB,CAAC,EAHW,WAAW,KAAX,WAAW,QAGtB;AA6QD,2EAA2E;AAC3E,yEAAyE;AACzE,iFAAiF;AACjF,MAAM,CAAC,IAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA","sourcesContent":["import type { MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot'\nimport { PostHog } from './posthog-core'\nimport type { SegmentAnalytics } from './extensions/segment-integration'\n\nexport type Property = any\nexport type Properties = Record<string, Property>\n\nexport interface CaptureResult {\n uuid: string\n event: string\n properties: Properties\n $set?: Properties\n $set_once?: Properties\n timestamp?: Date\n}\n\nexport type AutocaptureCompatibleElement = 'a' | 'button' | 'form' | 'input' | 'select' | 'textarea' | 'label'\nexport type DomAutocaptureEvents = 'click' | 'change' | 'submit'\n\n/**\n * If an array is passed for an allowlist, autocapture events will only be sent for elements matching\n * at least one of the elements in the array. Multiple allowlists can be used\n */\nexport interface AutocaptureConfig {\n /**\n * List of URLs to allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on specific pages only\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_allowlist?: (string | RegExp)[]\n\n /**\n * List of URLs to not allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on most pages but not some specific ones\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_ignorelist?: (string | RegExp)[]\n\n /**\n * List of DOM events to allow autocapture on e.g. ['click', 'change', 'submit']\n */\n dom_event_allowlist?: DomAutocaptureEvents[]\n\n /**\n * List of DOM elements to allow autocapture on\n * e.g. ['a', 'button', 'form', 'input', 'select', 'textarea', 'label']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * if the allowlist has button then we allow the capture when the button or the svg is the click target\n * but not if either of the divs are detected as the click target\n */\n element_allowlist?: AutocaptureCompatibleElement[]\n\n /**\n * List of CSS selectors to allow autocapture on\n * e.g. ['[ph-capture]']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * and allow list config `['[id]']`\n * we will capture the click if the click-target or its parents has any id\n */\n css_selector_allowlist?: string[]\n\n /**\n * Exclude certain element attributes from autocapture\n * E.g. ['aria-label'] or [data-attr-pii]\n */\n element_attribute_ignorelist?: string[]\n\n capture_copied_text?: boolean\n}\n\nexport interface BootstrapConfig {\n distinctID?: string\n isIdentifiedID?: boolean\n featureFlags?: Record<string, boolean | string>\n featureFlagPayloads?: Record<string, JsonType>\n /**\n * Optionally provide a sessionID, this is so that you can provide an existing sessionID here to continue a user's session across a domain or device. It MUST be:\n * - unique to this user\n * - a valid UUID v7\n * - the timestamp part must be <= the timestamp of the first event in the session\n * - the timestamp of the last event in the session must be < the timestamp part + 24 hours\n * **/\n sessionID?: string\n}\n\nexport type SupportedWebVitalsMetrics = 'LCP' | 'CLS' | 'FCP' | 'INP'\n\nexport interface PerformanceCaptureConfig {\n /** works with session replay to use the browser's native performance observer to capture performance metrics */\n network_timing?: boolean\n /** use chrome's web vitals library to wrap fetch and capture web vitals */\n web_vitals?: boolean\n /**\n * We observe very large values reported by the Chrome web vitals library\n * These outliers are likely not real, useful values, and we exclude them\n * You can set this to 0 in order to include all values, NB this is not recommended\n * if not set this defaults to 15 minutes\n */\n __web_vitals_max_value?: number\n /**\n * By default all 4 metrics are captured\n * You can set this config to restrict which metrics are captured\n * e.g. ['CLS', 'FCP'] to only capture those two metrics\n * NB setting this does not override whether the capture is enabled\n */\n web_vitals_allowed_metrics?: SupportedWebVitalsMetrics[]\n}\n\nexport interface HeatmapConfig {\n /*\n * how often to send batched data in $$heatmap_data events\n * if set to 0 or not set, sends using the default interval of 1 second\n * */\n flush_interval_milliseconds: number\n}\n\nexport interface PostHogConfig {\n api_host: string\n /** @deprecated - This property is no longer supported */\n api_method?: string\n api_transport?: 'XHR' | 'fetch'\n ui_host: string | null\n token: string\n autocapture: boolean | AutocaptureConfig\n rageclick: boolean\n cross_subdomain_cookie: boolean\n persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie' | 'sessionStorage'\n persistence_name: string\n /** @deprecated - Use 'persistence_name' instead */\n cookie_name?: string\n loaded: (posthog_instance: PostHog) => void\n store_google: boolean\n custom_campaign_params: string[]\n // a list of strings to be tested against navigator.userAgent to determine if the source is a bot\n // this is **added to** the default list of bots that we check\n // defaults to the empty array\n custom_blocked_useragents: string[]\n save_referrer: boolean\n verbose: boolean\n capture_pageview: boolean\n capture_pageleave: boolean | 'if_capture_pageview'\n debug: boolean\n cookie_expiration: number\n upgrade: boolean\n disable_session_recording: boolean\n disable_persistence: boolean\n /** @deprecated - use `disable_persistence` instead */\n disable_cookie?: boolean\n disable_surveys: boolean\n /** If set, posthog-js will never load external scripts such as those needed for Session Replay or Surveys. */\n disable_external_dependency_loading?: boolean\n enable_recording_console_log?: boolean\n secure_cookie: boolean\n ip: boolean\n /** Starts the SDK in an opted out state requiring opt_in_capturing() to be called before events will b captured */\n opt_out_capturing_by_default: boolean\n opt_out_capturing_persistence_type: 'localStorage' | 'cookie'\n /** If set to true this will disable persistence if the user is opted out of capturing. @default false */\n opt_out_persistence_by_default?: boolean\n /** Opt out of user agent filtering such as googlebot or other bots. Defaults to `false` */\n opt_out_useragent_filter: boolean\n\n opt_out_capturing_cookie_prefix: string | null\n opt_in_site_apps: boolean\n respect_dnt: boolean\n /** @deprecated - use `property_denylist` instead */\n property_blacklist?: string[]\n property_denylist: string[]\n request_headers: { [header_name: string]: string }\n on_request_error?: (error: RequestResponse) => void\n /** @deprecated - use `request_headers` instead */\n xhr_headers?: { [header_name: string]: string }\n /** @deprecated - use `on_request_error` instead */\n on_xhr_error?: (failedRequest: XMLHttpRequest) => void\n inapp_protocol: string\n inapp_link_new_window: boolean\n request_batching: boolean\n sanitize_properties: ((properties: Properties, event_name: string) => Properties) | null\n properties_string_max_length: number\n session_recording: SessionRecordingOptions\n session_idle_timeout_seconds: number\n mask_all_element_attributes: boolean\n mask_all_text: boolean\n advanced_disable_decide: boolean\n advanced_disable_feature_flags: boolean\n advanced_disable_feature_flags_on_first_load: boolean\n advanced_disable_toolbar_metrics: boolean\n feature_flag_request_timeout_ms: number\n get_device_id: (uuid: string) => string\n name: string\n _onCapture: (eventName: string, eventData: CaptureResult) => void\n capture_performance?: boolean | PerformanceCaptureConfig\n // Should only be used for testing. Could negatively impact performance.\n disable_compression: boolean\n bootstrap: BootstrapConfig\n segment?: SegmentAnalytics\n __preview_send_client_session_params?: boolean\n /* @deprecated - use `capture_heatmaps` instead */\n enable_heatmaps?: boolean\n capture_heatmaps?: boolean | HeatmapConfig\n disable_scroll_properties?: boolean\n // Let the pageview scroll stats use a custom css selector for the root element, e.g. `main`\n scroll_root_selector?: string | string[]\n\n /** You can control whether events from PostHog-js have person processing enabled with the `person_profiles` config setting. There are three options:\n * - `person_profiles: 'always'` _(default)_ - we will process persons data for all events\n * - `person_profiles: 'never'` - we won't process persons for any event. This means that anonymous users will not be merged once they sign up or login, so you lose the ability to create funnels that track users from anonymous to identified. All events (including `$identify`) will be sent with `$process_person_profile: False`.\n * - `person_profiles: 'identified_only'` - we will only process persons when you call `posthog.identify`, `posthog.alias`, `posthog.setPersonProperties`, `posthog.group`, `posthog.setPersonPropertiesForFlags` or `posthog.setGroupPropertiesForFlags` Anonymous users won't get person profiles.\n */\n person_profiles?: 'always' | 'never' | 'identified_only'\n /** @deprecated - use `person_profiles` instead */\n process_person?: 'always' | 'never' | 'identified_only'\n\n /** Client side rate limiting */\n rate_limiting?: {\n /** The average number of events per second that should be permitted (defaults to 10) */\n events_per_second?: number\n /** How many events can be captured in a burst. This defaults to 10 times the events_per_second count */\n events_burst_limit?: number\n }\n\n /**\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\nexport interface OptInOutCapturingOptions {\n capture: (event: string, properties: Properties, options: CaptureOptions) => void\n capture_event_name: string\n capture_properties: Properties\n enable_persistence: boolean\n clear_persistence: boolean\n persistence_type: 'cookie' | 'localStorage' | 'localStorage+cookie'\n cookie_prefix: string\n cookie_expiration: number\n cross_subdomain_cookie: boolean\n secure_cookie: boolean\n}\n\nexport interface IsFeatureEnabledOptions {\n send_event: boolean\n}\n\nexport interface SessionRecordingOptions {\n blockClass?: string | RegExp\n blockSelector?: string | null\n ignoreClass?: string\n maskTextClass?: string | RegExp\n maskTextSelector?: string | null\n maskTextFn?: ((text: string, element: HTMLElement | null) => string) | null\n maskAllInputs?: boolean\n maskInputOptions?: MaskInputOptions\n maskInputFn?: ((text: string, element?: HTMLElement) => string) | null\n slimDOMOptions?: SlimDOMOptions | 'all' | true\n collectFonts?: boolean\n inlineStylesheet?: boolean\n recordCrossOriginIframes?: boolean\n /** @deprecated - use maskCapturedNetworkRequestFn instead */\n maskNetworkRequestFn?: ((data: NetworkRequest) => NetworkRequest | null | undefined) | null\n /** Modify the network request before it is captured. Returning null or undefined stops it being captured */\n maskCapturedNetworkRequestFn?: ((data: CapturedNetworkRequest) => CapturedNetworkRequest | null | undefined) | null\n // our settings here only support a subset of those proposed for rrweb's network capture plugin\n recordHeaders?: boolean\n recordBody?: boolean\n // ADVANCED: while a user is active we take a full snapshot of the browser every interval. For very few sites playback performance might be better with different interval. Set to 0 to disable\n full_snapshot_interval_millis?: number\n}\n\nexport type SessionIdChangedCallback = (sessionId: string, windowId: string | null | undefined) => 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\nexport interface RequestOptions {\n url: string\n // Data can be a single object or an array of objects when batched\n data?: Record<string, any> | Record<string, any>[]\n headers?: Record<string, any>\n transport?: 'XHR' | 'fetch' | 'sendBeacon'\n method?: 'POST' | 'GET'\n urlQueryArgs?: { compression: Compression }\n callback?: RequestCallback\n timeout?: number\n noRetries?: boolean\n compression?: Compression | 'best-available'\n}\n\n// Queued request types - the same as a request but with additional queueing information\n\nexport interface QueuedRequestOptions extends RequestOptions {\n batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n}\n\n// Used explicitly for retriable requests\nexport interface RetriableRequestOptions extends QueuedRequestOptions {\n retriesPerformedSoFar?: number\n}\n\nexport interface CaptureOptions {\n $set?: Properties /** used with $identify */\n $set_once?: Properties /** used with $identify */\n _url?: string /** Used to override the desired endpoint for the captured event */\n _batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n _noTruncate?: boolean /** if set, overrides and disables config.properties_string_max_length */\n send_instantly?: boolean /** if set skips the batched queue */\n skip_client_rate_limiting?: boolean /** if set skips the client side rate limiting */\n transport?: RequestOptions['transport'] /** if set, overrides the desired transport method */\n timestamp?: Date\n}\n\nexport type FlagVariant = { flag: string; variant: string }\n\nexport interface DecideResponse {\n supportedCompression: Compression[]\n featureFlags: Record<string, string | boolean>\n featureFlagPayloads: Record<string, JsonType>\n errorsWhileComputingFlags: boolean\n autocapture_opt_out?: boolean\n /**\n * originally capturePerformance was replay only and so boolean true\n * is equivalent to { network_timing: true }\n * now capture performance can be separately enabled within replay\n * and as a standalone web vitals tracker\n * people can have them enabled separately\n * they work standalone but enhance each other\n * TODO: deprecate this so we make a new config that doesn't need this explanation\n */\n capturePerformance?: boolean | PerformanceCaptureConfig\n analytics?: {\n endpoint?: string\n }\n elementsChainAsString?: boolean\n // this is currently in development and may have breaking changes without a major version bump\n autocaptureExceptions?:\n | boolean\n | {\n endpoint?: string\n }\n sessionRecording?: {\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 recordCanvas?: boolean | null\n canvasFps?: number | null\n // the API returns a decimal between 0 and 1 as a string\n canvasQuality?: string | null\n linkedFlag?: string | FlagVariant | null\n networkPayloadCapture?: Pick<NetworkRecordOptions, 'recordBody' | 'recordHeaders'>\n }\n surveys?: boolean\n toolbarParams: ToolbarParams\n editorParams?: ToolbarParams /** @deprecated, renamed to toolbarParams, still present on older API responses */\n toolbarVersion: 'toolbar' /** @deprecated, moved to toolbarParams */\n isAuthenticated: boolean\n siteApps: { id: number; url: string }[]\n heatmaps?: boolean\n}\n\nexport type FeatureFlagsCallback = (\n flags: string[],\n variants: Record<string, string | boolean>,\n context?: {\n errorsLoading?: boolean\n }\n) => void\n\nexport interface PersistentStore {\n is_supported: () => boolean\n error: (error: any) => void\n parse: (name: string) => any\n get: (name: string) => any\n set: (\n name: string,\n value: any,\n expire_days?: number | null,\n cross_subdomain?: boolean,\n secure?: boolean,\n debug?: boolean\n ) => void\n remove: (name: string, cross_subdomain?: boolean) => void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Breaker = {}\nexport type EventHandler = (event: Event) => boolean | void\n\nexport type ToolbarUserIntent = 'add-action' | 'edit-action'\nexport type ToolbarSource = 'url' | 'localstorage'\nexport type ToolbarVersion = 'toolbar'\n\n/* sync with posthog */\nexport interface ToolbarParams {\n token?: string /** public posthog-js token */\n temporaryToken?: string /** private temporary user token */\n actionId?: number\n userIntent?: ToolbarUserIntent\n source?: ToolbarSource\n toolbarVersion?: ToolbarVersion\n instrument?: boolean\n distinctId?: string\n userEmail?: string\n dataAttributes?: string[]\n featureFlags?: Record<string, string | boolean>\n}\n\nexport type SnippetArrayItem = [method: string, ...args: any[]]\n\nexport type JsonType = string | number | boolean | null | { [key: string]: JsonType } | Array<JsonType>\n\n/** A feature that isn't publicly available yet.*/\nexport interface EarlyAccessFeature {\n // Sync this with the backend's EarlyAccessFeatureSerializer!\n name: string\n description: string\n stage: 'concept' | 'alpha' | 'beta'\n documentationUrl: string | null\n flagKey: string | null\n}\n\nexport type EarlyAccessFeatureCallback = (earlyAccessFeatures: EarlyAccessFeature[]) => void\n\nexport interface EarlyAccessFeatureResponse {\n earlyAccessFeatures: EarlyAccessFeature[]\n}\n\nexport type Headers = Record<string, string>\n\n/* for rrweb/network@1\n ** when that is released as part of rrweb this can be removed\n ** don't rely on this type, it may change without notice\n */\nexport type InitiatorType =\n | 'audio'\n | 'beacon'\n | 'body'\n | 'css'\n | 'early-hint'\n | 'embed'\n | 'fetch'\n | 'frame'\n | 'iframe'\n | 'icon'\n | 'image'\n | 'img'\n | 'input'\n | 'link'\n | 'navigation'\n | 'object'\n | 'ping'\n | 'script'\n | 'track'\n | 'video'\n | 'xmlhttprequest'\n\nexport type NetworkRecordOptions = {\n initiatorTypes?: InitiatorType[]\n maskRequestFn?: (data: CapturedNetworkRequest) => CapturedNetworkRequest | undefined\n recordHeaders?: boolean | { request: boolean; response: boolean }\n recordBody?: boolean | string[] | { request: boolean | string[]; response: boolean | string[] }\n recordInitialRequests?: boolean\n /**\n * whether to record PerformanceEntry events for network requests\n */\n recordPerformance?: boolean\n /**\n * the PerformanceObserver will only observe these entry types\n */\n performanceEntryTypeToObserve: string[]\n /**\n * the maximum size of the request/response body to record\n * NB this will be at most 1MB even if set larger\n */\n payloadSizeLimitBytes: number\n /**\n * some domains we should never record the payload\n * for example other companies session replay ingestion payloads aren't super useful but are gigantic\n * if this isn't provided we use a default list\n * if this is provided - we add the provided list to the default list\n * i.e. we never record the payloads on the default deny list\n */\n payloadHostDenyList?: string[]\n}\n\n/** @deprecated - use CapturedNetworkRequest instead */\nexport type NetworkRequest = {\n url: string\n}\n\n// In rrweb this is called NetworkRequest, but we already exposed that as having only URL\n// we also want to vary from the rrweb NetworkRequest because we want to include\n// all PerformanceEntry properties too.\n// that has 4 required properties\n// readonly duration: DOMHighResTimeStamp;\n// readonly entryType: string;\n// readonly name: string;\n// readonly startTime: DOMHighResTimeStamp;\n// NB: properties below here are ALPHA, don't rely on them, they may change without notice\n\n// we mirror PerformanceEntry since we read into this type from a PerformanceObserver,\n// but we don't want to inherit its readonly-iness\ntype Writable<T> = { -readonly [P in keyof T]: T[P] }\n\nexport type CapturedNetworkRequest = Writable<Omit<PerformanceEntry, 'toJSON'>> & {\n // properties below here are ALPHA, don't rely on them, they may change without notice\n method?: string\n initiatorType?: InitiatorType\n status?: number\n timeOrigin?: number\n timestamp?: number\n startTime?: number\n endTime?: number\n requestHeaders?: Headers\n requestBody?: string | null\n responseHeaders?: Headers\n responseBody?: string | null\n // was this captured before fetch/xhr could have been wrapped\n isInitial?: boolean\n}\n\nexport type ErrorEventArgs = [\n event: string | Event,\n source?: string | undefined,\n lineno?: number | undefined,\n colno?: number | undefined,\n error?: Error | undefined\n]\n\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"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AA2RA,MAAM,CAAN,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,iCAAkB,CAAA;IAClB,gCAAiB,CAAA;AACrB,CAAC,EAHW,WAAW,KAAX,WAAW,QAGtB;AA8QD,2EAA2E;AAC3E,yEAAyE;AACzE,iFAAiF;AACjF,MAAM,CAAC,IAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA","sourcesContent":["import type { MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot'\nimport { PostHog } from './posthog-core'\nimport type { SegmentAnalytics } from './extensions/segment-integration'\n\nexport type Property = any\nexport type Properties = Record<string, Property>\n\nexport interface CaptureResult {\n uuid: string\n event: string\n properties: Properties\n $set?: Properties\n $set_once?: Properties\n timestamp?: Date\n}\n\nexport type AutocaptureCompatibleElement = 'a' | 'button' | 'form' | 'input' | 'select' | 'textarea' | 'label'\nexport type DomAutocaptureEvents = 'click' | 'change' | 'submit'\n\n/**\n * If an array is passed for an allowlist, autocapture events will only be sent for elements matching\n * at least one of the elements in the array. Multiple allowlists can be used\n */\nexport interface AutocaptureConfig {\n /**\n * List of URLs to allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on specific pages only\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_allowlist?: (string | RegExp)[]\n\n /**\n * List of URLs to not allow autocapture on, can be strings to match\n * or regexes e.g. ['https://example.com', 'test.com/.*']\n * this is useful when you want to autocapture on most pages but not some specific ones\n *\n * if you set both url_allowlist and url_ignorelist,\n * we check the allowlist first and then the ignorelist.\n * the ignorelist can override the allowlist\n */\n url_ignorelist?: (string | RegExp)[]\n\n /**\n * List of DOM events to allow autocapture on e.g. ['click', 'change', 'submit']\n */\n dom_event_allowlist?: DomAutocaptureEvents[]\n\n /**\n * List of DOM elements to allow autocapture on\n * e.g. ['a', 'button', 'form', 'input', 'select', 'textarea', 'label']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * if the allowlist has button then we allow the capture when the button or the svg is the click target\n * but not if either of the divs are detected as the click target\n */\n element_allowlist?: AutocaptureCompatibleElement[]\n\n /**\n * List of CSS selectors to allow autocapture on\n * e.g. ['[ph-capture]']\n * we consider the tree of elements from the root to the target element of the click event\n * so for the tree div > div > button > svg\n * and allow list config `['[id]']`\n * we will capture the click if the click-target or its parents has any id\n */\n css_selector_allowlist?: string[]\n\n /**\n * Exclude certain element attributes from autocapture\n * E.g. ['aria-label'] or [data-attr-pii]\n */\n element_attribute_ignorelist?: string[]\n\n capture_copied_text?: boolean\n}\n\nexport interface BootstrapConfig {\n distinctID?: string\n isIdentifiedID?: boolean\n featureFlags?: Record<string, boolean | string>\n featureFlagPayloads?: Record<string, JsonType>\n /**\n * Optionally provide a sessionID, this is so that you can provide an existing sessionID here to continue a user's session across a domain or device. It MUST be:\n * - unique to this user\n * - a valid UUID v7\n * - the timestamp part must be <= the timestamp of the first event in the session\n * - the timestamp of the last event in the session must be < the timestamp part + 24 hours\n * **/\n sessionID?: string\n}\n\nexport type SupportedWebVitalsMetrics = 'LCP' | 'CLS' | 'FCP' | 'INP'\n\nexport interface PerformanceCaptureConfig {\n /** works with session replay to use the browser's native performance observer to capture performance metrics */\n network_timing?: boolean\n /** use chrome's web vitals library to wrap fetch and capture web vitals */\n web_vitals?: boolean\n /**\n * We observe very large values reported by the Chrome web vitals library\n * These outliers are likely not real, useful values, and we exclude them\n * You can set this to 0 in order to include all values, NB this is not recommended\n * if not set this defaults to 15 minutes\n */\n __web_vitals_max_value?: number\n /**\n * By default all 4 metrics are captured\n * You can set this config to restrict which metrics are captured\n * e.g. ['CLS', 'FCP'] to only capture those two metrics\n * NB setting this does not override whether the capture is enabled\n */\n web_vitals_allowed_metrics?: SupportedWebVitalsMetrics[]\n}\n\nexport interface HeatmapConfig {\n /*\n * how often to send batched data in $$heatmap_data events\n * if set to 0 or not set, sends using the default interval of 1 second\n * */\n flush_interval_milliseconds: number\n}\n\nexport interface PostHogConfig {\n api_host: string\n /** @deprecated - This property is no longer supported */\n api_method?: string\n api_transport?: 'XHR' | 'fetch'\n ui_host: string | null\n token: string\n autocapture: boolean | AutocaptureConfig\n rageclick: boolean\n cross_subdomain_cookie: boolean\n persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie' | 'sessionStorage'\n persistence_name: string\n /** @deprecated - Use 'persistence_name' instead */\n cookie_name?: string\n loaded: (posthog_instance: PostHog) => void\n store_google: boolean\n custom_campaign_params: string[]\n // a list of strings to be tested against navigator.userAgent to determine if the source is a bot\n // this is **added to** the default list of bots that we check\n // defaults to the empty array\n custom_blocked_useragents: string[]\n save_referrer: boolean\n verbose: boolean\n capture_pageview: boolean\n capture_pageleave: boolean | 'if_capture_pageview'\n debug: boolean\n cookie_expiration: number\n upgrade: boolean\n disable_session_recording: boolean\n disable_persistence: boolean\n /** @deprecated - use `disable_persistence` instead */\n disable_cookie?: boolean\n disable_surveys: boolean\n disable_web_experiments: boolean\n /** If set, posthog-js will never load external scripts such as those needed for Session Replay or Surveys. */\n disable_external_dependency_loading?: boolean\n enable_recording_console_log?: boolean\n secure_cookie: boolean\n ip: boolean\n /** Starts the SDK in an opted out state requiring opt_in_capturing() to be called before events will b captured */\n opt_out_capturing_by_default: boolean\n opt_out_capturing_persistence_type: 'localStorage' | 'cookie'\n /** If set to true this will disable persistence if the user is opted out of capturing. @default false */\n opt_out_persistence_by_default?: boolean\n /** Opt out of user agent filtering such as googlebot or other bots. Defaults to `false` */\n opt_out_useragent_filter: boolean\n\n opt_out_capturing_cookie_prefix: string | null\n opt_in_site_apps: boolean\n respect_dnt: boolean\n /** @deprecated - use `property_denylist` instead */\n property_blacklist?: string[]\n property_denylist: string[]\n request_headers: { [header_name: string]: string }\n on_request_error?: (error: RequestResponse) => void\n /** @deprecated - use `request_headers` instead */\n xhr_headers?: { [header_name: string]: string }\n /** @deprecated - use `on_request_error` instead */\n on_xhr_error?: (failedRequest: XMLHttpRequest) => void\n inapp_protocol: string\n inapp_link_new_window: boolean\n request_batching: boolean\n sanitize_properties: ((properties: Properties, event_name: string) => Properties) | null\n properties_string_max_length: number\n session_recording: SessionRecordingOptions\n session_idle_timeout_seconds: number\n mask_all_element_attributes: boolean\n mask_all_text: boolean\n advanced_disable_decide: boolean\n advanced_disable_feature_flags: boolean\n advanced_disable_feature_flags_on_first_load: boolean\n advanced_disable_toolbar_metrics: boolean\n feature_flag_request_timeout_ms: number\n get_device_id: (uuid: string) => string\n name: string\n _onCapture: (eventName: string, eventData: CaptureResult) => void\n capture_performance?: boolean | PerformanceCaptureConfig\n // Should only be used for testing. Could negatively impact performance.\n disable_compression: boolean\n bootstrap: BootstrapConfig\n segment?: SegmentAnalytics\n __preview_send_client_session_params?: boolean\n /* @deprecated - use `capture_heatmaps` instead */\n enable_heatmaps?: boolean\n capture_heatmaps?: boolean | HeatmapConfig\n disable_scroll_properties?: boolean\n // Let the pageview scroll stats use a custom css selector for the root element, e.g. `main`\n scroll_root_selector?: string | string[]\n\n /** You can control whether events from PostHog-js have person processing enabled with the `person_profiles` config setting. There are three options:\n * - `person_profiles: 'always'` _(default)_ - we will process persons data for all events\n * - `person_profiles: 'never'` - we won't process persons for any event. This means that anonymous users will not be merged once they sign up or login, so you lose the ability to create funnels that track users from anonymous to identified. All events (including `$identify`) will be sent with `$process_person_profile: False`.\n * - `person_profiles: 'identified_only'` - we will only process persons when you call `posthog.identify`, `posthog.alias`, `posthog.setPersonProperties`, `posthog.group`, `posthog.setPersonPropertiesForFlags` or `posthog.setGroupPropertiesForFlags` Anonymous users won't get person profiles.\n */\n person_profiles?: 'always' | 'never' | 'identified_only'\n /** @deprecated - use `person_profiles` instead */\n process_person?: 'always' | 'never' | 'identified_only'\n\n /** Client side rate limiting */\n rate_limiting?: {\n /** The average number of events per second that should be permitted (defaults to 10) */\n events_per_second?: number\n /** How many events can be captured in a burst. This defaults to 10 times the events_per_second count */\n events_burst_limit?: number\n }\n\n /**\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\nexport interface OptInOutCapturingOptions {\n capture: (event: string, properties: Properties, options: CaptureOptions) => void\n capture_event_name: string\n capture_properties: Properties\n enable_persistence: boolean\n clear_persistence: boolean\n persistence_type: 'cookie' | 'localStorage' | 'localStorage+cookie'\n cookie_prefix: string\n cookie_expiration: number\n cross_subdomain_cookie: boolean\n secure_cookie: boolean\n}\n\nexport interface IsFeatureEnabledOptions {\n send_event: boolean\n}\n\nexport interface SessionRecordingOptions {\n blockClass?: string | RegExp\n blockSelector?: string | null\n ignoreClass?: string\n maskTextClass?: string | RegExp\n maskTextSelector?: string | null\n maskTextFn?: ((text: string, element: HTMLElement | null) => string) | null\n maskAllInputs?: boolean\n maskInputOptions?: MaskInputOptions\n maskInputFn?: ((text: string, element?: HTMLElement) => string) | null\n slimDOMOptions?: SlimDOMOptions | 'all' | true\n collectFonts?: boolean\n inlineStylesheet?: boolean\n recordCrossOriginIframes?: boolean\n /** @deprecated - use maskCapturedNetworkRequestFn instead */\n maskNetworkRequestFn?: ((data: NetworkRequest) => NetworkRequest | null | undefined) | null\n /** Modify the network request before it is captured. Returning null or undefined stops it being captured */\n maskCapturedNetworkRequestFn?: ((data: CapturedNetworkRequest) => CapturedNetworkRequest | null | undefined) | null\n // our settings here only support a subset of those proposed for rrweb's network capture plugin\n recordHeaders?: boolean\n recordBody?: boolean\n // ADVANCED: while a user is active we take a full snapshot of the browser every interval. For very few sites playback performance might be better with different interval. Set to 0 to disable\n full_snapshot_interval_millis?: number\n}\n\nexport type SessionIdChangedCallback = (sessionId: string, windowId: string | null | undefined) => 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\nexport interface RequestOptions {\n url: string\n // Data can be a single object or an array of objects when batched\n data?: Record<string, any> | Record<string, any>[]\n headers?: Record<string, any>\n transport?: 'XHR' | 'fetch' | 'sendBeacon'\n method?: 'POST' | 'GET'\n urlQueryArgs?: { compression: Compression }\n callback?: RequestCallback\n timeout?: number\n noRetries?: boolean\n compression?: Compression | 'best-available'\n}\n\n// Queued request types - the same as a request but with additional queueing information\n\nexport interface QueuedRequestOptions extends RequestOptions {\n batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n}\n\n// Used explicitly for retriable requests\nexport interface RetriableRequestOptions extends QueuedRequestOptions {\n retriesPerformedSoFar?: number\n}\n\nexport interface CaptureOptions {\n $set?: Properties /** used with $identify */\n $set_once?: Properties /** used with $identify */\n _url?: string /** Used to override the desired endpoint for the captured event */\n _batchKey?: string /** key of queue, e.g. 'sessionRecording' vs 'event' */\n _noTruncate?: boolean /** if set, overrides and disables config.properties_string_max_length */\n send_instantly?: boolean /** if set skips the batched queue */\n skip_client_rate_limiting?: boolean /** if set skips the client side rate limiting */\n transport?: RequestOptions['transport'] /** if set, overrides the desired transport method */\n timestamp?: Date\n}\n\nexport type FlagVariant = { flag: string; variant: string }\n\nexport interface DecideResponse {\n supportedCompression: Compression[]\n featureFlags: Record<string, string | boolean>\n featureFlagPayloads: Record<string, JsonType>\n errorsWhileComputingFlags: boolean\n autocapture_opt_out?: boolean\n /**\n * originally capturePerformance was replay only and so boolean true\n * is equivalent to { network_timing: true }\n * now capture performance can be separately enabled within replay\n * and as a standalone web vitals tracker\n * people can have them enabled separately\n * they work standalone but enhance each other\n * TODO: deprecate this so we make a new config that doesn't need this explanation\n */\n capturePerformance?: boolean | PerformanceCaptureConfig\n analytics?: {\n endpoint?: string\n }\n elementsChainAsString?: boolean\n // this is currently in development and may have breaking changes without a major version bump\n autocaptureExceptions?:\n | boolean\n | {\n endpoint?: string\n }\n sessionRecording?: {\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 recordCanvas?: boolean | null\n canvasFps?: number | null\n // the API returns a decimal between 0 and 1 as a string\n canvasQuality?: string | null\n linkedFlag?: string | FlagVariant | null\n networkPayloadCapture?: Pick<NetworkRecordOptions, 'recordBody' | 'recordHeaders'>\n }\n surveys?: boolean\n toolbarParams: ToolbarParams\n editorParams?: ToolbarParams /** @deprecated, renamed to toolbarParams, still present on older API responses */\n toolbarVersion: 'toolbar' /** @deprecated, moved to toolbarParams */\n isAuthenticated: boolean\n siteApps: { id: number; url: string }[]\n heatmaps?: boolean\n}\n\nexport type FeatureFlagsCallback = (\n flags: string[],\n variants: Record<string, string | boolean>,\n context?: {\n errorsLoading?: boolean\n }\n) => void\n\nexport interface PersistentStore {\n is_supported: () => boolean\n error: (error: any) => void\n parse: (name: string) => any\n get: (name: string) => any\n set: (\n name: string,\n value: any,\n expire_days?: number | null,\n cross_subdomain?: boolean,\n secure?: boolean,\n debug?: boolean\n ) => void\n remove: (name: string, cross_subdomain?: boolean) => void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Breaker = {}\nexport type EventHandler = (event: Event) => boolean | void\n\nexport type ToolbarUserIntent = 'add-action' | 'edit-action'\nexport type ToolbarSource = 'url' | 'localstorage'\nexport type ToolbarVersion = 'toolbar'\n\n/* sync with posthog */\nexport interface ToolbarParams {\n token?: string /** public posthog-js token */\n temporaryToken?: string /** private temporary user token */\n actionId?: number\n userIntent?: ToolbarUserIntent\n source?: ToolbarSource\n toolbarVersion?: ToolbarVersion\n instrument?: boolean\n distinctId?: string\n userEmail?: string\n dataAttributes?: string[]\n featureFlags?: Record<string, string | boolean>\n}\n\nexport type SnippetArrayItem = [method: string, ...args: any[]]\n\nexport type JsonRecord = { [key: string]: JsonType }\nexport type JsonType = string | number | boolean | null | JsonRecord | Array<JsonType>\n\n/** A feature that isn't publicly available yet.*/\nexport interface EarlyAccessFeature {\n // Sync this with the backend's EarlyAccessFeatureSerializer!\n name: string\n description: string\n stage: 'concept' | 'alpha' | 'beta'\n documentationUrl: string | null\n flagKey: string | null\n}\n\nexport type EarlyAccessFeatureCallback = (earlyAccessFeatures: EarlyAccessFeature[]) => void\n\nexport interface EarlyAccessFeatureResponse {\n earlyAccessFeatures: EarlyAccessFeature[]\n}\n\nexport type Headers = Record<string, string>\n\n/* for rrweb/network@1\n ** when that is released as part of rrweb this can be removed\n ** don't rely on this type, it may change without notice\n */\nexport type InitiatorType =\n | 'audio'\n | 'beacon'\n | 'body'\n | 'css'\n | 'early-hint'\n | 'embed'\n | 'fetch'\n | 'frame'\n | 'iframe'\n | 'icon'\n | 'image'\n | 'img'\n | 'input'\n | 'link'\n | 'navigation'\n | 'object'\n | 'ping'\n | 'script'\n | 'track'\n | 'video'\n | 'xmlhttprequest'\n\nexport type NetworkRecordOptions = {\n initiatorTypes?: InitiatorType[]\n maskRequestFn?: (data: CapturedNetworkRequest) => CapturedNetworkRequest | undefined\n recordHeaders?: boolean | { request: boolean; response: boolean }\n recordBody?: boolean | string[] | { request: boolean | string[]; response: boolean | string[] }\n recordInitialRequests?: boolean\n /**\n * whether to record PerformanceEntry events for network requests\n */\n recordPerformance?: boolean\n /**\n * the PerformanceObserver will only observe these entry types\n */\n performanceEntryTypeToObserve: string[]\n /**\n * the maximum size of the request/response body to record\n * NB this will be at most 1MB even if set larger\n */\n payloadSizeLimitBytes: number\n /**\n * some domains we should never record the payload\n * for example other companies session replay ingestion payloads aren't super useful but are gigantic\n * if this isn't provided we use a default list\n * if this is provided - we add the provided list to the default list\n * i.e. we never record the payloads on the default deny list\n */\n payloadHostDenyList?: string[]\n}\n\n/** @deprecated - use CapturedNetworkRequest instead */\nexport type NetworkRequest = {\n url: string\n}\n\n// In rrweb this is called NetworkRequest, but we already exposed that as having only URL\n// we also want to vary from the rrweb NetworkRequest because we want to include\n// all PerformanceEntry properties too.\n// that has 4 required properties\n// readonly duration: DOMHighResTimeStamp;\n// readonly entryType: string;\n// readonly name: string;\n// readonly startTime: DOMHighResTimeStamp;\n// NB: properties below here are ALPHA, don't rely on them, they may change without notice\n\n// we mirror PerformanceEntry since we read into this type from a PerformanceObserver,\n// but we don't want to inherit its readonly-iness\ntype Writable<T> = { -readonly [P in keyof T]: T[P] }\n\nexport type CapturedNetworkRequest = Writable<Omit<PerformanceEntry, 'toJSON'>> & {\n // properties below here are ALPHA, don't rely on them, they may change without notice\n method?: string\n initiatorType?: InitiatorType\n status?: number\n timeOrigin?: number\n timestamp?: number\n startTime?: number\n endTime?: number\n requestHeaders?: Headers\n requestBody?: string | null\n responseHeaders?: Headers\n responseBody?: string | null\n // was this captured before fetch/xhr could have been wrapped\n isInitial?: boolean\n}\n\nexport type ErrorEventArgs = [\n event: string | Event,\n source?: string | undefined,\n lineno?: number | undefined,\n colno?: number | undefined,\n error?: Error | undefined\n]\n\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"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface WebExperimentTransform {
|
|
2
|
+
attributes?: {
|
|
3
|
+
name: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}[];
|
|
6
|
+
selector?: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
html?: string;
|
|
9
|
+
imgUrl?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export type WebExperimentUrlMatchType = 'regex' | 'not_regex' | 'exact' | 'is_not' | 'icontains' | 'not_icontains';
|
|
13
|
+
export interface WebExperimentVariant {
|
|
14
|
+
conditions?: {
|
|
15
|
+
url?: string;
|
|
16
|
+
urlMatchType?: WebExperimentUrlMatchType;
|
|
17
|
+
utm?: {
|
|
18
|
+
utm_source?: string;
|
|
19
|
+
utm_medium?: string;
|
|
20
|
+
utm_campaign?: string;
|
|
21
|
+
utm_term?: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
variant_name: string;
|
|
25
|
+
transforms: WebExperimentTransform[];
|
|
26
|
+
}
|
|
27
|
+
export interface WebExperiment {
|
|
28
|
+
id: number;
|
|
29
|
+
name: string;
|
|
30
|
+
feature_flag_key?: string;
|
|
31
|
+
variants: Record<string, WebExperimentVariant>;
|
|
32
|
+
}
|
|
33
|
+
export type WebExperimentsCallback = (webExperiments: WebExperiment[]) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-experiments-types.js","sourceRoot":"","sources":["../../src/web-experiments-types.ts"],"names":[],"mappings":"","sourcesContent":["export interface WebExperimentTransform {\n attributes?:\n | {\n name: string\n value: string\n }[]\n selector?: string\n text?: string\n html?: string\n imgUrl?: string\n className?: string\n}\n\nexport type WebExperimentUrlMatchType = 'regex' | 'not_regex' | 'exact' | 'is_not' | 'icontains' | 'not_icontains'\n\nexport interface WebExperimentVariant {\n conditions?: {\n url?: string\n urlMatchType?: WebExperimentUrlMatchType\n utm?: {\n utm_source?: string\n utm_medium?: string\n utm_campaign?: string\n utm_term?: string\n }\n }\n variant_name: string\n transforms: WebExperimentTransform[]\n}\nexport interface WebExperiment {\n id: number\n name: string\n feature_flag_key?: string\n variants: Record<string, WebExperimentVariant>\n}\n\nexport type WebExperimentsCallback = (webExperiments: WebExperiment[]) => void\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PostHog } from './posthog-core';
|
|
2
|
+
import { DecideResponse } from './types';
|
|
3
|
+
import { WebExperimentsCallback, WebExperimentUrlMatchType } from './web-experiments-types';
|
|
4
|
+
export declare const webExperimentUrlValidationMap: Record<WebExperimentUrlMatchType, (conditionsUrl: string, location: Location) => boolean>;
|
|
5
|
+
export declare class WebExperiments {
|
|
6
|
+
instance: PostHog;
|
|
7
|
+
private _featureFlags?;
|
|
8
|
+
private _flagToExperiments?;
|
|
9
|
+
constructor(instance: PostHog);
|
|
10
|
+
applyFeatureFlagChanges(flags: string[]): void;
|
|
11
|
+
afterDecideResponse(response: DecideResponse): void;
|
|
12
|
+
loadIfEnabled(): void;
|
|
13
|
+
getWebExperimentsAndEvaluateDisplayLogic: (forceReload?: boolean) => void;
|
|
14
|
+
getWebExperiments(callback: WebExperimentsCallback, forceReload: boolean): void;
|
|
15
|
+
private static matchesTestVariant;
|
|
16
|
+
private static matchUrlConditions;
|
|
17
|
+
static getWindowLocation(): Location | undefined;
|
|
18
|
+
private static matchUTMConditions;
|
|
19
|
+
private static logInfo;
|
|
20
|
+
private static applyTransforms;
|
|
21
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { window } from './utils/globals';
|
|
2
|
+
import { WEB_EXPERIMENTS } from './constants';
|
|
3
|
+
import { isNullish } from './utils/type-utils';
|
|
4
|
+
import { isUrlMatchingRegex } from './utils/request-utils';
|
|
5
|
+
import { logger } from './utils/logger';
|
|
6
|
+
import { Info } from './utils/event-utils';
|
|
7
|
+
export var webExperimentUrlValidationMap = {
|
|
8
|
+
icontains: function (conditionsUrl, location) {
|
|
9
|
+
return !!window && location.href.toLowerCase().indexOf(conditionsUrl.toLowerCase()) > -1;
|
|
10
|
+
},
|
|
11
|
+
not_icontains: function (conditionsUrl, location) {
|
|
12
|
+
return !!window && location.href.toLowerCase().indexOf(conditionsUrl.toLowerCase()) === -1;
|
|
13
|
+
},
|
|
14
|
+
regex: function (conditionsUrl, location) { return !!window && isUrlMatchingRegex(location.href, conditionsUrl); },
|
|
15
|
+
not_regex: function (conditionsUrl, location) { return !!window && !isUrlMatchingRegex(location.href, conditionsUrl); },
|
|
16
|
+
exact: function (conditionsUrl, location) { return location.href === conditionsUrl; },
|
|
17
|
+
is_not: function (conditionsUrl, location) { return location.href !== conditionsUrl; },
|
|
18
|
+
};
|
|
19
|
+
var WebExperiments = /** @class */ (function () {
|
|
20
|
+
function WebExperiments(instance) {
|
|
21
|
+
var _this = this;
|
|
22
|
+
this.getWebExperimentsAndEvaluateDisplayLogic = function (forceReload) {
|
|
23
|
+
if (forceReload === void 0) { forceReload = false; }
|
|
24
|
+
_this.getWebExperiments(function (webExperiments) {
|
|
25
|
+
WebExperiments.logInfo("retrieved web experiments from the server");
|
|
26
|
+
_this._flagToExperiments = new Map();
|
|
27
|
+
webExperiments.forEach(function (webExperiment) {
|
|
28
|
+
var _a;
|
|
29
|
+
if (webExperiment.feature_flag_key &&
|
|
30
|
+
_this._featureFlags &&
|
|
31
|
+
_this._featureFlags[webExperiment.feature_flag_key]) {
|
|
32
|
+
if (_this._flagToExperiments) {
|
|
33
|
+
WebExperiments.logInfo("setting flag key ", webExperiment.feature_flag_key, " to web experiment ", webExperiment);
|
|
34
|
+
(_a = _this._flagToExperiments) === null || _a === void 0 ? void 0 : _a.set(webExperiment.feature_flag_key, webExperiment);
|
|
35
|
+
}
|
|
36
|
+
var selectedVariant = _this._featureFlags[webExperiment.feature_flag_key];
|
|
37
|
+
if (selectedVariant && webExperiment.variants[selectedVariant]) {
|
|
38
|
+
WebExperiments.applyTransforms(webExperiment.name, selectedVariant, webExperiment.variants[selectedVariant].transforms);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else if (webExperiment.variants) {
|
|
42
|
+
for (var variant in webExperiment.variants) {
|
|
43
|
+
var testVariant = webExperiment.variants[variant];
|
|
44
|
+
var matchTest = WebExperiments.matchesTestVariant(testVariant);
|
|
45
|
+
if (matchTest) {
|
|
46
|
+
WebExperiments.applyTransforms(webExperiment.name, variant, testVariant.transforms);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}, forceReload);
|
|
52
|
+
};
|
|
53
|
+
this.instance = instance;
|
|
54
|
+
var appFeatureFLags = function (flags) {
|
|
55
|
+
_this.applyFeatureFlagChanges(flags);
|
|
56
|
+
};
|
|
57
|
+
if (this.instance.onFeatureFlags) {
|
|
58
|
+
this.instance.onFeatureFlags(appFeatureFLags);
|
|
59
|
+
}
|
|
60
|
+
this._flagToExperiments = new Map();
|
|
61
|
+
}
|
|
62
|
+
WebExperiments.prototype.applyFeatureFlagChanges = function (flags) {
|
|
63
|
+
var _this = this;
|
|
64
|
+
WebExperiments.logInfo('applying feature flags', flags);
|
|
65
|
+
if (isNullish(this._flagToExperiments) || this.instance.config.disable_web_experiments) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
flags.forEach(function (flag) {
|
|
69
|
+
var _a, _b;
|
|
70
|
+
if (_this._flagToExperiments && ((_a = _this._flagToExperiments) === null || _a === void 0 ? void 0 : _a.has(flag))) {
|
|
71
|
+
var selectedVariant = _this.instance.getFeatureFlag(flag);
|
|
72
|
+
var webExperiment = (_b = _this._flagToExperiments) === null || _b === void 0 ? void 0 : _b.get(flag);
|
|
73
|
+
if (selectedVariant && (webExperiment === null || webExperiment === void 0 ? void 0 : webExperiment.variants[selectedVariant])) {
|
|
74
|
+
WebExperiments.applyTransforms(webExperiment.name, selectedVariant, webExperiment.variants[selectedVariant].transforms);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
WebExperiments.prototype.afterDecideResponse = function (response) {
|
|
80
|
+
this._featureFlags = response.featureFlags;
|
|
81
|
+
this.loadIfEnabled();
|
|
82
|
+
};
|
|
83
|
+
WebExperiments.prototype.loadIfEnabled = function () {
|
|
84
|
+
if (this.instance.config.disable_web_experiments) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.getWebExperimentsAndEvaluateDisplayLogic();
|
|
88
|
+
};
|
|
89
|
+
WebExperiments.prototype.getWebExperiments = function (callback, forceReload) {
|
|
90
|
+
if (this.instance.config.disable_web_experiments) {
|
|
91
|
+
return callback([]);
|
|
92
|
+
}
|
|
93
|
+
var existingWebExperiments = this.instance.get_property(WEB_EXPERIMENTS);
|
|
94
|
+
if (existingWebExperiments && !forceReload) {
|
|
95
|
+
return callback(existingWebExperiments);
|
|
96
|
+
}
|
|
97
|
+
this.instance._send_request({
|
|
98
|
+
url: this.instance.requestRouter.endpointFor('api', "/api/web_experiments/?token=".concat(this.instance.config.token)),
|
|
99
|
+
method: 'GET',
|
|
100
|
+
transport: 'XHR',
|
|
101
|
+
callback: function (response) {
|
|
102
|
+
if (response.statusCode !== 200 || !response.json) {
|
|
103
|
+
return callback([]);
|
|
104
|
+
}
|
|
105
|
+
var webExperiments = response.json.experiments || [];
|
|
106
|
+
return callback(webExperiments);
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
WebExperiments.matchesTestVariant = function (testVariant) {
|
|
111
|
+
if (isNullish(testVariant.conditions)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return WebExperiments.matchUrlConditions(testVariant) && WebExperiments.matchUTMConditions(testVariant);
|
|
115
|
+
};
|
|
116
|
+
WebExperiments.matchUrlConditions = function (testVariant) {
|
|
117
|
+
var _a, _b, _c, _d;
|
|
118
|
+
if (isNullish(testVariant.conditions) || isNullish((_a = testVariant.conditions) === null || _a === void 0 ? void 0 : _a.url)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
var location = WebExperiments.getWindowLocation();
|
|
122
|
+
if (location) {
|
|
123
|
+
var urlCheck = ((_b = testVariant.conditions) === null || _b === void 0 ? void 0 : _b.url)
|
|
124
|
+
? webExperimentUrlValidationMap[(_d = (_c = testVariant.conditions) === null || _c === void 0 ? void 0 : _c.urlMatchType) !== null && _d !== void 0 ? _d : 'icontains'](testVariant.conditions.url, location)
|
|
125
|
+
: true;
|
|
126
|
+
return urlCheck;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
};
|
|
130
|
+
WebExperiments.getWindowLocation = function () {
|
|
131
|
+
return window === null || window === void 0 ? void 0 : window.location;
|
|
132
|
+
};
|
|
133
|
+
WebExperiments.matchUTMConditions = function (testVariant) {
|
|
134
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
135
|
+
if (isNullish(testVariant.conditions) || isNullish((_a = testVariant.conditions) === null || _a === void 0 ? void 0 : _a.utm)) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
var campaignParams = Info.campaignParams();
|
|
139
|
+
if (campaignParams['utm_source']) {
|
|
140
|
+
// eslint-disable-next-line compat/compat
|
|
141
|
+
var utmCampaignMatched = ((_c = (_b = testVariant.conditions) === null || _b === void 0 ? void 0 : _b.utm) === null || _c === void 0 ? void 0 : _c.utm_campaign)
|
|
142
|
+
? ((_e = (_d = testVariant.conditions) === null || _d === void 0 ? void 0 : _d.utm) === null || _e === void 0 ? void 0 : _e.utm_campaign) == campaignParams['utm_campaign']
|
|
143
|
+
: true;
|
|
144
|
+
var utmSourceMatched = ((_g = (_f = testVariant.conditions) === null || _f === void 0 ? void 0 : _f.utm) === null || _g === void 0 ? void 0 : _g.utm_source)
|
|
145
|
+
? ((_j = (_h = testVariant.conditions) === null || _h === void 0 ? void 0 : _h.utm) === null || _j === void 0 ? void 0 : _j.utm_source) == campaignParams['utm_source']
|
|
146
|
+
: true;
|
|
147
|
+
var utmMediumMatched = ((_l = (_k = testVariant.conditions) === null || _k === void 0 ? void 0 : _k.utm) === null || _l === void 0 ? void 0 : _l.utm_medium)
|
|
148
|
+
? ((_o = (_m = testVariant.conditions) === null || _m === void 0 ? void 0 : _m.utm) === null || _o === void 0 ? void 0 : _o.utm_medium) == campaignParams['utm_medium']
|
|
149
|
+
: true;
|
|
150
|
+
var utmTermMatched = ((_q = (_p = testVariant.conditions) === null || _p === void 0 ? void 0 : _p.utm) === null || _q === void 0 ? void 0 : _q.utm_term)
|
|
151
|
+
? ((_s = (_r = testVariant.conditions) === null || _r === void 0 ? void 0 : _r.utm) === null || _s === void 0 ? void 0 : _s.utm_term) == campaignParams['utm_term']
|
|
152
|
+
: true;
|
|
153
|
+
return utmCampaignMatched && utmMediumMatched && utmTermMatched && utmSourceMatched;
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
};
|
|
157
|
+
WebExperiments.logInfo = function (msg) {
|
|
158
|
+
var args = [];
|
|
159
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
160
|
+
args[_i - 1] = arguments[_i];
|
|
161
|
+
}
|
|
162
|
+
logger.info("[WebExperiments] ".concat(msg), args);
|
|
163
|
+
};
|
|
164
|
+
WebExperiments.applyTransforms = function (experiment, variant, transforms) {
|
|
165
|
+
transforms.forEach(function (transform) {
|
|
166
|
+
if (transform.selector) {
|
|
167
|
+
WebExperiments.logInfo("applying transform of variant ".concat(variant, " for experiment ").concat(experiment, " "), transform);
|
|
168
|
+
// eslint-disable-next-line no-restricted-globals
|
|
169
|
+
var elements = document === null || document === void 0 ? void 0 : document.querySelectorAll(transform.selector);
|
|
170
|
+
elements === null || elements === void 0 ? void 0 : elements.forEach(function (element) {
|
|
171
|
+
var htmlElement = element;
|
|
172
|
+
if (transform.attributes) {
|
|
173
|
+
transform.attributes.forEach(function (attribute) {
|
|
174
|
+
switch (attribute.name) {
|
|
175
|
+
case 'text':
|
|
176
|
+
htmlElement.innerText = attribute.value;
|
|
177
|
+
break;
|
|
178
|
+
case 'html':
|
|
179
|
+
htmlElement.innerHTML = attribute.value;
|
|
180
|
+
break;
|
|
181
|
+
case 'cssClass':
|
|
182
|
+
htmlElement.className = attribute.value;
|
|
183
|
+
break;
|
|
184
|
+
default:
|
|
185
|
+
htmlElement.setAttribute(attribute.name, attribute.value);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (transform.text) {
|
|
190
|
+
htmlElement.innerText = transform.text;
|
|
191
|
+
}
|
|
192
|
+
if (transform.html) {
|
|
193
|
+
htmlElement.innerHTML = transform.html;
|
|
194
|
+
}
|
|
195
|
+
if (transform.className) {
|
|
196
|
+
htmlElement.className = transform.className;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
return WebExperiments;
|
|
203
|
+
}());
|
|
204
|
+
export { WebExperiments };
|
|
205
|
+
//# sourceMappingURL=web-experiments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-experiments.js","sourceRoot":"","sources":["../../src/web-experiments.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHog } from './posthog-core'\nimport { DecideResponse } from './types'\nimport { window } from './utils/globals'\nimport {\n WebExperiment,\n WebExperimentsCallback,\n WebExperimentTransform,\n WebExperimentUrlMatchType,\n WebExperimentVariant,\n} from './web-experiments-types'\nimport { WEB_EXPERIMENTS } from './constants'\nimport { isNullish } from './utils/type-utils'\nimport { isUrlMatchingRegex } from './utils/request-utils'\nimport { logger } from './utils/logger'\nimport { Info } from './utils/event-utils'\n\nexport const webExperimentUrlValidationMap: Record<\n WebExperimentUrlMatchType,\n (conditionsUrl: string, location: Location) => boolean\n> = {\n icontains: (conditionsUrl, location) =>\n !!window && location.href.toLowerCase().indexOf(conditionsUrl.toLowerCase()) > -1,\n not_icontains: (conditionsUrl, location) =>\n !!window && location.href.toLowerCase().indexOf(conditionsUrl.toLowerCase()) === -1,\n regex: (conditionsUrl, location) => !!window && isUrlMatchingRegex(location.href, conditionsUrl),\n not_regex: (conditionsUrl, location) => !!window && !isUrlMatchingRegex(location.href, conditionsUrl),\n exact: (conditionsUrl, location) => location.href === conditionsUrl,\n is_not: (conditionsUrl, location) => location.href !== conditionsUrl,\n}\n\nexport class WebExperiments {\n instance: PostHog\n private _featureFlags?: Record<string, string | boolean>\n private _flagToExperiments?: Map<string, WebExperiment>\n\n constructor(instance: PostHog) {\n this.instance = instance\n const appFeatureFLags = (flags: string[]) => {\n this.applyFeatureFlagChanges(flags)\n }\n\n if (this.instance.onFeatureFlags) {\n this.instance.onFeatureFlags(appFeatureFLags)\n }\n this._flagToExperiments = new Map<string, WebExperiment>()\n }\n\n applyFeatureFlagChanges(flags: string[]) {\n WebExperiments.logInfo('applying feature flags', flags)\n if (isNullish(this._flagToExperiments) || this.instance.config.disable_web_experiments) {\n return\n }\n\n flags.forEach((flag) => {\n if (this._flagToExperiments && this._flagToExperiments?.has(flag)) {\n const selectedVariant = this.instance.getFeatureFlag(flag) as unknown as string\n const webExperiment = this._flagToExperiments?.get(flag)\n if (selectedVariant && webExperiment?.variants[selectedVariant]) {\n WebExperiments.applyTransforms(\n webExperiment.name,\n selectedVariant,\n webExperiment.variants[selectedVariant].transforms\n )\n }\n }\n })\n }\n\n afterDecideResponse(response: DecideResponse) {\n this._featureFlags = response.featureFlags\n\n this.loadIfEnabled()\n }\n\n loadIfEnabled() {\n if (this.instance.config.disable_web_experiments) {\n return\n }\n\n this.getWebExperimentsAndEvaluateDisplayLogic()\n }\n\n public getWebExperimentsAndEvaluateDisplayLogic = (forceReload: boolean = false): void => {\n this.getWebExperiments((webExperiments) => {\n WebExperiments.logInfo(`retrieved web experiments from the server`)\n this._flagToExperiments = new Map<string, WebExperiment>()\n webExperiments.forEach((webExperiment) => {\n if (\n webExperiment.feature_flag_key &&\n this._featureFlags &&\n this._featureFlags[webExperiment.feature_flag_key]\n ) {\n if (this._flagToExperiments) {\n WebExperiments.logInfo(\n `setting flag key `,\n webExperiment.feature_flag_key,\n ` to web experiment `,\n webExperiment\n )\n this._flagToExperiments?.set(webExperiment.feature_flag_key, webExperiment)\n }\n\n const selectedVariant = this._featureFlags[webExperiment.feature_flag_key] as unknown as string\n if (selectedVariant && webExperiment.variants[selectedVariant]) {\n WebExperiments.applyTransforms(\n webExperiment.name,\n selectedVariant,\n webExperiment.variants[selectedVariant].transforms\n )\n }\n } else if (webExperiment.variants) {\n for (const variant in webExperiment.variants) {\n const testVariant = webExperiment.variants[variant]\n const matchTest = WebExperiments.matchesTestVariant(testVariant)\n if (matchTest) {\n WebExperiments.applyTransforms(webExperiment.name, variant, testVariant.transforms)\n }\n }\n }\n })\n }, forceReload)\n }\n\n public getWebExperiments(callback: WebExperimentsCallback, forceReload: boolean) {\n if (this.instance.config.disable_web_experiments) {\n return callback([])\n }\n\n const existingWebExperiments = this.instance.get_property(WEB_EXPERIMENTS)\n if (existingWebExperiments && !forceReload) {\n return callback(existingWebExperiments)\n }\n\n this.instance._send_request({\n url: this.instance.requestRouter.endpointFor(\n 'api',\n `/api/web_experiments/?token=${this.instance.config.token}`\n ),\n method: 'GET',\n transport: 'XHR',\n callback: (response) => {\n if (response.statusCode !== 200 || !response.json) {\n return callback([])\n }\n const webExperiments = response.json.experiments || []\n return callback(webExperiments)\n },\n })\n }\n\n private static matchesTestVariant(testVariant: WebExperimentVariant) {\n if (isNullish(testVariant.conditions)) {\n return false\n }\n return WebExperiments.matchUrlConditions(testVariant) && WebExperiments.matchUTMConditions(testVariant)\n }\n\n private static matchUrlConditions(testVariant: WebExperimentVariant): boolean {\n if (isNullish(testVariant.conditions) || isNullish(testVariant.conditions?.url)) {\n return true\n }\n\n const location = WebExperiments.getWindowLocation()\n if (location) {\n const urlCheck = testVariant.conditions?.url\n ? webExperimentUrlValidationMap[testVariant.conditions?.urlMatchType ?? 'icontains'](\n testVariant.conditions.url,\n location\n )\n : true\n return urlCheck\n }\n\n return false\n }\n\n public static getWindowLocation(): Location | undefined {\n return window?.location\n }\n\n private static matchUTMConditions(testVariant: WebExperimentVariant): boolean {\n if (isNullish(testVariant.conditions) || isNullish(testVariant.conditions?.utm)) {\n return true\n }\n const campaignParams = Info.campaignParams()\n if (campaignParams['utm_source']) {\n // eslint-disable-next-line compat/compat\n const utmCampaignMatched = testVariant.conditions?.utm?.utm_campaign\n ? testVariant.conditions?.utm?.utm_campaign == campaignParams['utm_campaign']\n : true\n\n const utmSourceMatched = testVariant.conditions?.utm?.utm_source\n ? testVariant.conditions?.utm?.utm_source == campaignParams['utm_source']\n : true\n\n const utmMediumMatched = testVariant.conditions?.utm?.utm_medium\n ? testVariant.conditions?.utm?.utm_medium == campaignParams['utm_medium']\n : true\n\n const utmTermMatched = testVariant.conditions?.utm?.utm_term\n ? testVariant.conditions?.utm?.utm_term == campaignParams['utm_term']\n : true\n\n return utmCampaignMatched && utmMediumMatched && utmTermMatched && utmSourceMatched\n }\n\n return false\n }\n\n private static logInfo(msg: string, ...args: any[]) {\n logger.info(`[WebExperiments] ${msg}`, args)\n }\n\n private static applyTransforms(experiment: string, variant: string, transforms: WebExperimentTransform[]) {\n transforms.forEach((transform) => {\n if (transform.selector) {\n WebExperiments.logInfo(\n `applying transform of variant ${variant} for experiment ${experiment} `,\n transform\n )\n // eslint-disable-next-line no-restricted-globals\n const elements = document?.querySelectorAll(transform.selector)\n elements?.forEach((element) => {\n const htmlElement = element as HTMLElement\n if (transform.attributes) {\n transform.attributes.forEach((attribute) => {\n switch (attribute.name) {\n case 'text':\n htmlElement.innerText = attribute.value\n break\n\n case 'html':\n htmlElement.innerHTML = attribute.value\n break\n\n case 'cssClass':\n htmlElement.className = attribute.value\n break\n\n default:\n htmlElement.setAttribute(attribute.name, attribute.value)\n }\n })\n }\n\n if (transform.text) {\n htmlElement.innerText = transform.text\n }\n\n if (transform.html) {\n htmlElement.innerHTML = transform.html\n }\n\n if (transform.className) {\n htmlElement.className = transform.className\n }\n })\n }\n })\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|