@workleap/mixpanel 6.0.2 → 6.1.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @workleap/mixpanel
2
2
 
3
+ ## 6.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#281](https://github.com/workleap/wl-telemetry/pull/281) [`7bc53df`](https://github.com/workleap/wl-telemetry/commit/7bc53df81efadfc0bd87f475995ee92916b5802e) Thanks [@patricklafrance](https://github.com/patricklafrance)! - Redact the private query parameters from the `$current_url` and `$referrer` properties sent with every Mixpanel event, and remove the fragment from `$current_url`. The `token`, `email` and `password` query parameters are redacted by default, additional names can be provided with the new `privateQueryParameterNames` option. An application using hash routing will no longer get the route in `$current_url`.
8
+
9
+ ## 6.0.3
10
+
11
+ ### Patch Changes
12
+
13
+ - [#269](https://github.com/workleap/wl-telemetry/pull/269) [`0a200c0`](https://github.com/workleap/wl-telemetry/commit/0a200c0dcbb3997a4cc3857836a4c4e269c41723) Thanks [@patricklafrance](https://github.com/patricklafrance)! - Raise the minimum `@workleap/logging` version to `2.1.0`.
14
+ - Updated dependencies [[`0a200c0`](https://github.com/workleap/wl-telemetry/commit/0a200c0dcbb3997a4cc3857836a4c4e269c41723)]:
15
+ - @workleap-telemetry/core@2.0.7
16
+
3
17
  ## 6.0.2
4
18
 
5
19
  ### Patch Changes
@@ -25,6 +25,10 @@ export interface MixpanelClientOptions {
25
25
  * @see {@link https://workleap.github.io/wl-telemetry}
26
26
  */
27
27
  productId?: string;
28
+ /**
29
+ * @see {@link https://workleap.github.io/wl-telemetry}
30
+ */
31
+ privateQueryParameterNames?: string[];
28
32
  }
29
33
  export declare class MixpanelClientImpl implements MixpanelClient {
30
34
  #private;
@@ -2,16 +2,23 @@ import { getBaseProperties } from "./properties.js";
2
2
 
3
3
 
4
4
 
5
+ const DefaultPrivateQueryParameterNames = [
6
+ "token",
7
+ "email",
8
+ "password"
9
+ ];
5
10
  class MixpanelClientImpl {
6
11
  #globalEventProperties = new Map();
7
12
  #endpoint;
8
13
  #logger;
9
14
  #productId;
15
+ #privateQueryParameterNames;
10
16
  constructor(endpoint, logger, options = {}){
11
- const { productId } = options;
17
+ const { productId, privateQueryParameterNames = [] } = options;
12
18
  this.#endpoint = endpoint;
13
19
  this.#logger = logger;
14
20
  this.#productId = productId;
21
+ this.#privateQueryParameterNames = DefaultPrivateQueryParameterNames.concat(privateQueryParameterNames);
15
22
  }
16
23
  // IMPORTANT: If you update this method, make sure to update the MixpanelPartialClient
17
24
  // interface as well in @workleap-telemetry/core.
@@ -20,7 +27,7 @@ class MixpanelClientImpl {
20
27
  const trackFunction = async (eventName, properties, _options = {})=>{
21
28
  try {
22
29
  const { keepAlive = false } = _options;
23
- const baseProperties = getBaseProperties();
30
+ const baseProperties = getBaseProperties(this.#privateQueryParameterNames);
24
31
  const allProperties = {
25
32
  ...baseProperties,
26
33
  ...Object.fromEntries(this.#globalEventProperties),
@@ -1 +1 @@
1
- {"version":3,"file":"js/MixpanelClient.js","sources":["../../src/js/MixpanelClient.ts"],"sourcesContent":["import type { CreateMixpanelTrackingFunctionOptions, MixpanelTrackingFunction } from \"@workleap-telemetry/core\";\nimport type { Logger } from \"@workleap/logging\";\nimport { getBaseProperties } from \"./properties.ts\";\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelClient {\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n createTrackingFunction: (options?: CreateMixpanelTrackingFunctionOptions) => MixpanelTrackingFunction;\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n setGlobalEventProperty: (key: string, value: unknown) => void;\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n setGlobalEventProperties: (values: Record<string, unknown>) => void;\n}\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelClientOptions {\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n productId?: string;\n}\n\nexport class MixpanelClientImpl implements MixpanelClient {\n readonly #globalEventProperties = new Map<string, unknown>();\n readonly #endpoint: string;\n readonly #logger: Logger;\n readonly #productId?: string;\n\n constructor(endpoint: string, logger: Logger, options: MixpanelClientOptions = {}) {\n const {\n productId\n } = options;\n\n this.#endpoint = endpoint;\n this.#logger = logger;\n this.#productId = productId;\n }\n\n // IMPORTANT: If you update this method, make sure to update the MixpanelPartialClient\n // interface as well in @workleap-telemetry/core.\n createTrackingFunction(options: CreateMixpanelTrackingFunctionOptions = {}) {\n const {\n productId,\n targetProductId,\n additionalProperties = {}\n } = options;\n\n const trackFunction: MixpanelTrackingFunction = async (eventName, properties, _options = {}) => {\n try {\n const {\n keepAlive = false\n } = _options;\n\n const baseProperties = getBaseProperties();\n\n const allProperties = {\n ...baseProperties,\n ...Object.fromEntries(this.#globalEventProperties),\n ...additionalProperties,\n ...properties\n };\n\n await fetch(this.#endpoint, {\n method: \"POST\",\n credentials: \"include\",\n keepalive: keepAlive,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n eventName,\n productIdentifier: productId ?? this.#productId,\n // Not sure why, but it seems important to send \"null\" if not target product identifier\n // are provided.\n targetProductIdentifier: targetProductId ?? null,\n properties: allProperties\n })\n });\n } catch (error: unknown) {\n this.#logger\n .withText(`[mixpanel] An error occurred while sending a tracking event to \"${this.#endpoint}\":`)\n .withError(error as Error)\n .error();\n }\n };\n\n return trackFunction;\n }\n\n setGlobalEventProperty(key: string, value: unknown) {\n this.#globalEventProperties.set(key, value);\n }\n\n setGlobalEventProperties(values: Record<string, unknown>) {\n Object.keys(values).forEach(x => {\n this.#globalEventProperties.set(x, values[x]);\n });\n }\n}\n"],"names":["getBaseProperties","MixpanelClientImpl","Map","endpoint","logger","options","productId","targetProductId","additionalProperties","trackFunction","eventName","properties","_options","keepAlive","baseProperties","allProperties","Object","fetch","JSON","error","key","value","values","x"],"mappings":";;;AAEoD;AA8B7C,MAAMC,kBAAkBA;IAClB,sBAAsB,GAAG,IAAIC,MAAuB;IACpD,SAAS,CAAS;IAClB,OAAO,CAAS;IAChB,UAAU,CAAU;IAE7B,YAAYC,QAAgB,EAAEC,MAAc,EAAEC,UAAiC,CAAC,CAAC,CAAE;QAC/E,MAAM,EACFC,SAAS,EACZ,GAAGD;QAEJ,IAAI,CAAC,SAAS,GAAGF;QACjB,IAAI,CAAC,OAAO,GAAGC;QACf,IAAI,CAAC,UAAU,GAAGE;IACtB;IAEA,sFAAsF;IACtF,iDAAiD;IACjD,uBAAuBD,UAAiD,CAAC,CAAC,EAAE;QACxE,MAAM,EACFC,SAAS,EACTC,eAAe,EACfC,uBAAuB,CAAC,CAAC,EAC5B,GAAGH;QAEJ,MAAMI,gBAA0C,OAAOC,WAAWC,YAAYC,WAAW,CAAC,CAAC;YACvF,IAAI;gBACA,MAAM,EACFC,YAAY,KAAK,EACpB,GAAGD;gBAEJ,MAAME,iBAAiBd,iBAAiBA;gBAExC,MAAMe,gBAAgB;oBAClB,GAAGD,cAAc;oBACjB,GAAGE,OAAO,WAAW,CAAC,IAAI,CAAC,sBAAsB,CAAC;oBAClD,GAAGR,oBAAoB;oBACvB,GAAGG,UAAU;gBACjB;gBAEA,MAAMM,MAAM,IAAI,CAAC,SAAS,EAAE;oBACxB,QAAQ;oBACR,aAAa;oBACb,WAAWJ;oBACX,SAAS;wBAAE,gBAAgB;oBAAmB;oBAC9C,MAAMK,KAAK,SAAS,CAAC;wBACjBR;wBACA,mBAAmBJ,aAAa,IAAI,CAAC,UAAU;wBAC/C,uFAAuF;wBACvF,gBAAgB;wBAChB,yBAAyBC,mBAAmB;wBAC5C,YAAYQ;oBAChB;gBACJ;YACJ,EAAE,OAAOI,OAAgB;gBACrB,IAAI,CAAC,OAAO,CACP,QAAQ,CAAC,CAAC,gEAAgE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAC9F,SAAS,CAACA,OACV,KAAK;YACd;QACJ;QAEA,OAAOV;IACX;IAEA,uBAAuBW,GAAW,EAAEC,KAAc,EAAE;QAChD,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAACD,KAAKC;IACzC;IAEA,yBAAyBC,MAA+B,EAAE;QACtDN,OAAO,IAAI,CAACM,QAAQ,OAAO,CAACC,CAAAA;YACxB,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAACA,GAAGD,MAAM,CAACC,EAAE;QAChD;IACJ;AACJ"}
1
+ {"version":3,"file":"js/MixpanelClient.js","sources":["../../src/js/MixpanelClient.ts"],"sourcesContent":["import type { CreateMixpanelTrackingFunctionOptions, MixpanelTrackingFunction } from \"@workleap-telemetry/core\";\nimport type { Logger } from \"@workleap/logging\";\nimport { getBaseProperties } from \"./properties.ts\";\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelClient {\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n createTrackingFunction: (options?: CreateMixpanelTrackingFunctionOptions) => MixpanelTrackingFunction;\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n setGlobalEventProperty: (key: string, value: unknown) => void;\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n setGlobalEventProperties: (values: Record<string, unknown>) => void;\n}\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelClientOptions {\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n productId?: string;\n /**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n privateQueryParameterNames?: string[];\n}\n\nconst DefaultPrivateQueryParameterNames = [\"token\", \"email\", \"password\"];\n\nexport class MixpanelClientImpl implements MixpanelClient {\n readonly #globalEventProperties = new Map<string, unknown>();\n readonly #endpoint: string;\n readonly #logger: Logger;\n readonly #productId?: string;\n readonly #privateQueryParameterNames: string[];\n\n constructor(endpoint: string, logger: Logger, options: MixpanelClientOptions = {}) {\n const { productId, privateQueryParameterNames = [] } = options;\n\n this.#endpoint = endpoint;\n this.#logger = logger;\n this.#productId = productId;\n this.#privateQueryParameterNames = DefaultPrivateQueryParameterNames.concat(privateQueryParameterNames);\n }\n\n // IMPORTANT: If you update this method, make sure to update the MixpanelPartialClient\n // interface as well in @workleap-telemetry/core.\n createTrackingFunction(options: CreateMixpanelTrackingFunctionOptions = {}) {\n const { productId, targetProductId, additionalProperties = {} } = options;\n\n const trackFunction: MixpanelTrackingFunction = async (eventName, properties, _options = {}) => {\n try {\n const { keepAlive = false } = _options;\n\n const baseProperties = getBaseProperties(this.#privateQueryParameterNames);\n\n const allProperties = {\n ...baseProperties,\n ...Object.fromEntries(this.#globalEventProperties),\n ...additionalProperties,\n ...properties\n };\n\n await fetch(this.#endpoint, {\n method: \"POST\",\n credentials: \"include\",\n keepalive: keepAlive,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n eventName,\n productIdentifier: productId ?? this.#productId,\n // Not sure why, but it seems important to send \"null\" if not target product identifier\n // are provided.\n targetProductIdentifier: targetProductId ?? null,\n properties: allProperties\n })\n });\n } catch (error: unknown) {\n this.#logger\n .withText(`[mixpanel] An error occurred while sending a tracking event to \"${this.#endpoint}\":`)\n .withError(error as Error)\n .error();\n }\n };\n\n return trackFunction;\n }\n\n setGlobalEventProperty(key: string, value: unknown) {\n this.#globalEventProperties.set(key, value);\n }\n\n setGlobalEventProperties(values: Record<string, unknown>) {\n Object.keys(values).forEach(x => {\n this.#globalEventProperties.set(x, values[x]);\n });\n }\n}\n"],"names":["getBaseProperties","DefaultPrivateQueryParameterNames","MixpanelClientImpl","Map","endpoint","logger","options","productId","privateQueryParameterNames","targetProductId","additionalProperties","trackFunction","eventName","properties","_options","keepAlive","baseProperties","allProperties","Object","fetch","JSON","error","key","value","values","x"],"mappings":";;;AAEoD;AAkCpD,MAAMC,oCAAoC;IAAC;IAAS;IAAS;CAAW;AAEjE,MAAMC;IACA,sBAAsB,GAAG,IAAIC,MAAuB;IACpD,SAAS,CAAS;IAClB,OAAO,CAAS;IAChB,UAAU,CAAU;IACpB,2BAA2B,CAAW;IAE/C,YAAYC,QAAgB,EAAEC,MAAc,EAAEC,UAAiC,CAAC,CAAC,CAAE;QAC/E,MAAM,EAAEC,SAAS,EAAEC,6BAA6B,EAAE,EAAE,GAAGF;QAEvD,IAAI,CAAC,SAAS,GAAGF;QACjB,IAAI,CAAC,OAAO,GAAGC;QACf,IAAI,CAAC,UAAU,GAAGE;QAClB,IAAI,CAAC,2BAA2B,GAAGN,kCAAkC,MAAM,CAACO;IAChF;IAEA,sFAAsF;IACtF,iDAAiD;IACjD,uBAAuBF,UAAiD,CAAC,CAAC,EAAE;QACxE,MAAM,EAAEC,SAAS,EAAEE,eAAe,EAAEC,uBAAuB,CAAC,CAAC,EAAE,GAAGJ;QAElE,MAAMK,gBAA0C,OAAOC,WAAWC,YAAYC,WAAW,CAAC,CAAC;YACvF,IAAI;gBACA,MAAM,EAAEC,YAAY,KAAK,EAAE,GAAGD;gBAE9B,MAAME,iBAAiBhB,iBAAiBA,CAAC,IAAI,CAAC,2BAA2B;gBAEzE,MAAMiB,gBAAgB;oBAClB,GAAGD,cAAc;oBACjB,GAAGE,OAAO,WAAW,CAAC,IAAI,CAAC,sBAAsB,CAAC;oBAClD,GAAGR,oBAAoB;oBACvB,GAAGG,UAAU;gBACjB;gBAEA,MAAMM,MAAM,IAAI,CAAC,SAAS,EAAE;oBACxB,QAAQ;oBACR,aAAa;oBACb,WAAWJ;oBACX,SAAS;wBAAE,gBAAgB;oBAAmB;oBAC9C,MAAMK,KAAK,SAAS,CAAC;wBACjBR;wBACA,mBAAmBL,aAAa,IAAI,CAAC,UAAU;wBAC/C,uFAAuF;wBACvF,gBAAgB;wBAChB,yBAAyBE,mBAAmB;wBAC5C,YAAYQ;oBAChB;gBACJ;YACJ,EAAE,OAAOI,OAAgB;gBACrB,IAAI,CAAC,OAAO,CACP,QAAQ,CAAC,CAAC,gEAAgE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAC9F,SAAS,CAACA,OACV,KAAK;YACd;QACJ;QAEA,OAAOV;IACX;IAEA,uBAAuBW,GAAW,EAAEC,KAAc,EAAE;QAChD,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAACD,KAAKC;IACzC;IAEA,yBAAyBC,MAA+B,EAAE;QACtDN,OAAO,IAAI,CAACM,QAAQ,OAAO,CAACC,CAAAA;YACxB,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAACA,GAAGD,MAAM,CAACC,EAAE;QAChD;IACJ;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"js/NoopMixpanelClient.js","sources":["../../src/js/NoopMixpanelClient.ts"],"sourcesContent":["import type { MixpanelClient } from \"./MixpanelClient.ts\";\n\nexport class NoopMixpanelClient implements MixpanelClient {\n createTrackingFunction() {\n return () => Promise.resolve();\n }\n\n setGlobalEventProperty() {}\n setGlobalEventProperties() {}\n}\n"],"names":["NoopMixpanelClient","Promise"],"mappings":"AAEO,MAAMA,kBAAkBA;IAC3B,yBAAyB;QACrB,OAAO,IAAMC,QAAQ,OAAO;IAChC;IAEA,yBAAyB,CAAC;IAC1B,2BAA2B,CAAC;AAChC"}
1
+ {"version":3,"file":"js/NoopMixpanelClient.js","sources":["../../src/js/NoopMixpanelClient.ts"],"sourcesContent":["import type { MixpanelClient } from \"./MixpanelClient.ts\";\n\nexport class NoopMixpanelClient implements MixpanelClient {\n createTrackingFunction() {\n return () => Promise.resolve();\n }\n\n setGlobalEventProperty() {}\n setGlobalEventProperties() {}\n}\n"],"names":["NoopMixpanelClient","Promise"],"mappings":"AAEO,MAAMA;IACT,yBAAyB;QACrB,OAAO,IAAMC,QAAQ,OAAO;IAChC;IAEA,yBAAyB,CAAC;IAC1B,2BAA2B,CAAC;AAChC"}
package/dist/js/env.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  declare const EnvironmentList: readonly ["development", "staging", "production", "local", "msw"];
2
- export type MixpanelEnvironment = typeof EnvironmentList[number];
2
+ export type MixpanelEnvironment = (typeof EnvironmentList)[number];
3
3
  export declare function getTrackingEndpoint(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), trackingEndpoint?: string): string;
4
4
  export {};
package/dist/js/env.js CHANGED
@@ -6,11 +6,11 @@ const EnvironmentList = [
6
6
  "msw"
7
7
  ];
8
8
  const NavigationApiBaseUrl = {
9
- "production": "https://api.platform.workleap.com/shell/navigation/",
10
- "staging": "https://api.platform.workleap-stg.com/shell/navigation/",
11
- "development": "https://api.platform.workleap-dev.com/shell/navigation/",
12
- "local": "https://api.platform.workleap-dev.com/shell/navigation/",
13
- "msw": "/api/shell/navigation/"
9
+ production: "https://api.platform.workleap.com/shell/navigation/",
10
+ staging: "https://api.platform.workleap-stg.com/shell/navigation/",
11
+ development: "https://api.platform.workleap-dev.com/shell/navigation/",
12
+ local: "https://api.platform.workleap-dev.com/shell/navigation/",
13
+ msw: "/api/shell/navigation/"
14
14
  };
15
15
  // Cannot use URL() because it doesn't support relative base url: https://github.com/whatwg/url/issues/531.
16
16
  function resolveApiUrl(path, baseUrl) {
@@ -1 +1 @@
1
- {"version":3,"file":"js/env.js","sources":["../../src/js/env.ts"],"sourcesContent":["const EnvironmentList = [\"development\", \"staging\", \"production\", \"local\", \"msw\"] as const;\n\nexport type MixpanelEnvironment = typeof EnvironmentList[number];\n\nconst NavigationApiBaseUrl: Record<MixpanelEnvironment, string> = {\n \"production\": \"https://api.platform.workleap.com/shell/navigation/\",\n \"staging\": \"https://api.platform.workleap-stg.com/shell/navigation/\",\n \"development\": \"https://api.platform.workleap-dev.com/shell/navigation/\",\n \"local\": \"https://api.platform.workleap-dev.com/shell/navigation/\",\n \"msw\": \"/api/shell/navigation/\"\n};\n\n// Cannot use URL() because it doesn't support relative base url: https://github.com/whatwg/url/issues/531.\nfunction resolveApiUrl(path: string, baseUrl: string | undefined): string {\n return `${baseUrl}${baseUrl!.endsWith(\"/\") ? \"\" : \"/\"}${path.startsWith(\"/\") ? path.substring(1) : path}`;\n}\n\nexport function getTrackingEndpoint(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), trackingEndpoint = \"tracking/track\"): string {\n let baseUrl: string;\n\n if (EnvironmentList.includes(envOrTrackingApiBaseUrl as MixpanelEnvironment)) {\n baseUrl = NavigationApiBaseUrl[envOrTrackingApiBaseUrl as MixpanelEnvironment];\n } else {\n baseUrl = envOrTrackingApiBaseUrl;\n }\n\n return resolveApiUrl(trackingEndpoint, baseUrl);\n}\n"],"names":["EnvironmentList","NavigationApiBaseUrl","resolveApiUrl","path","baseUrl","getTrackingEndpoint","envOrTrackingApiBaseUrl","trackingEndpoint"],"mappings":"AAAA,MAAMA,eAAeA,GAAG;IAAC;IAAe;IAAW;IAAc;IAAS;CAAM;AAIhF,MAAMC,oBAAoBA,GAAwC;IAC9D,cAAc;IACd,WAAW;IACX,eAAe;IACf,SAAS;IACT,OAAO;AACX;AAEA,2GAA2G;AAC3G,SAASC,aAAaA,CAACC,IAAY,EAAEC,OAA2B;IAC5D,OAAO,GAAGA,UAAUA,QAAS,QAAQ,CAAC,OAAO,KAAK,MAAMD,KAAK,UAAU,CAAC,OAAOA,KAAK,SAAS,CAAC,KAAKA,MAAM;AAC7G;AAEO,SAASE,mBAAmBA,CAACC,uBAA4D,EAAEC,mBAAmB,gBAAgB;IACjI,IAAIH;IAEJ,IAAIJ,eAAeA,CAAC,QAAQ,CAACM,0BAAiD;QAC1EF,UAAUH,oBAAoB,CAACK,wBAA+C;IAClF,OAAO;QACHF,UAAUE;IACd;IAEA,OAAOJ,aAAaA,CAACK,kBAAkBH;AAC3C"}
1
+ {"version":3,"file":"js/env.js","sources":["../../src/js/env.ts"],"sourcesContent":["const EnvironmentList = [\"development\", \"staging\", \"production\", \"local\", \"msw\"] as const;\n\nexport type MixpanelEnvironment = (typeof EnvironmentList)[number];\n\nconst NavigationApiBaseUrl: Record<MixpanelEnvironment, string> = {\n production: \"https://api.platform.workleap.com/shell/navigation/\",\n staging: \"https://api.platform.workleap-stg.com/shell/navigation/\",\n development: \"https://api.platform.workleap-dev.com/shell/navigation/\",\n local: \"https://api.platform.workleap-dev.com/shell/navigation/\",\n msw: \"/api/shell/navigation/\"\n};\n\n// Cannot use URL() because it doesn't support relative base url: https://github.com/whatwg/url/issues/531.\nfunction resolveApiUrl(path: string, baseUrl: string | undefined): string {\n return `${baseUrl}${baseUrl!.endsWith(\"/\") ? \"\" : \"/\"}${path.startsWith(\"/\") ? path.substring(1) : path}`;\n}\n\nexport function getTrackingEndpoint(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), trackingEndpoint = \"tracking/track\"): string {\n let baseUrl: string;\n\n if (EnvironmentList.includes(envOrTrackingApiBaseUrl as MixpanelEnvironment)) {\n baseUrl = NavigationApiBaseUrl[envOrTrackingApiBaseUrl as MixpanelEnvironment];\n } else {\n baseUrl = envOrTrackingApiBaseUrl;\n }\n\n return resolveApiUrl(trackingEndpoint, baseUrl);\n}\n"],"names":["EnvironmentList","NavigationApiBaseUrl","resolveApiUrl","path","baseUrl","getTrackingEndpoint","envOrTrackingApiBaseUrl","trackingEndpoint"],"mappings":"AAAA,MAAMA,kBAAkB;IAAC;IAAe;IAAW;IAAc;IAAS;CAAM;AAIhF,MAAMC,uBAA4D;IAC9D,YAAY;IACZ,SAAS;IACT,aAAa;IACb,OAAO;IACP,KAAK;AACT;AAEA,2GAA2G;AAC3G,SAASC,cAAcC,IAAY,EAAEC,OAA2B;IAC5D,OAAO,GAAGA,UAAUA,QAAS,QAAQ,CAAC,OAAO,KAAK,MAAMD,KAAK,UAAU,CAAC,OAAOA,KAAK,SAAS,CAAC,KAAKA,MAAM;AAC7G;AAEO,SAASE,oBAAoBC,uBAA4D,EAAEC,mBAAmB,gBAAgB;IACjI,IAAIH;IAEJ,IAAIJ,gBAAgB,QAAQ,CAACM,0BAAiD;QAC1EF,UAAUH,oBAAoB,CAACK,wBAA+C;IAClF,OAAO;QACHF,UAAUE;IACd;IAEA,OAAOJ,cAAcK,kBAAkBH;AAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"js/index.js","sources":["../../src/js/index.ts"],"sourcesContent":["export { createTelemetryContext, type CreateTelemetryContextOptions, type TelemetryContext } from \"@workleap-telemetry/core\";\nexport type { CreateMixpanelTrackingFunctionOptions, MixpanelEventProperties, MixpanelTrackingFunction, MixpanelTrackingFunctionOptions } from \"@workleap-telemetry/core\";\nexport type { MixpanelEnvironment } from \"./env.ts\";\nexport { initializeMixpanel, type InitializeMixpanelOptions } from \"./initializeMixpanel.ts\";\nexport type { MixpanelClient } from \"./MixpanelClient.ts\";\nexport { NoopMixpanelClient } from \"./NoopMixpanelClient.ts\";\n\n"],"names":["createTelemetryContext","initializeMixpanel","NoopMixpanelClient"],"mappings":";;;AAA6H;AAGhC;AAEhC"}
1
+ {"version":3,"file":"js/index.js","sources":["../../src/js/index.ts"],"sourcesContent":["export { createTelemetryContext, type CreateTelemetryContextOptions, type TelemetryContext } from \"@workleap-telemetry/core\";\nexport type { CreateMixpanelTrackingFunctionOptions, MixpanelEventProperties, MixpanelTrackingFunction, MixpanelTrackingFunctionOptions } from \"@workleap-telemetry/core\";\nexport type { MixpanelEnvironment } from \"./env.ts\";\nexport { initializeMixpanel, type InitializeMixpanelOptions } from \"./initializeMixpanel.ts\";\nexport type { MixpanelClient } from \"./MixpanelClient.ts\";\nexport { NoopMixpanelClient } from \"./NoopMixpanelClient.ts\";\n"],"names":["createTelemetryContext","initializeMixpanel","NoopMixpanelClient"],"mappings":";;;AAA6H;AAGhC;AAEhC"}
@@ -18,6 +18,11 @@ export interface InitializeMixpanelOptions {
18
18
  * @see {@link https://workleap.github.io/wl-telemetry}
19
19
  */
20
20
  trackingEndpoint?: string;
21
+ /**
22
+ * Names of additional query parameters to redact from the URLs sent with every event.
23
+ * @see {@link https://workleap.github.io/wl-telemetry}
24
+ */
25
+ privateQueryParameterNames?: string[];
21
26
  /**
22
27
  * Context including telemetry correlation ids.
23
28
  * @see {@link https://workleap.github.io/wl-telemetry}
@@ -31,12 +31,13 @@ function __resetRegistrationGuard() {
31
31
  }
32
32
  class MixpanelInitializer {
33
33
  initialize(envOrTrackingApiBaseUrl, options = {}) {
34
- const { productId, trackingEndpoint, telemetryContext, logRocketInstrumentationClient, verbose = false, loggers = [] } = options;
34
+ const { productId, trackingEndpoint, privateQueryParameterNames, telemetryContext, logRocketInstrumentationClient, verbose = false, loggers = [] } = options;
35
35
  const logger = createCompositeLogger(verbose, loggers);
36
36
  const endpoint = getTrackingEndpoint(envOrTrackingApiBaseUrl, trackingEndpoint);
37
37
  logger.information("[mixpanel] Mixpanel is initialized.");
38
38
  const client = new MixpanelClientImpl(endpoint, logger, {
39
- productId
39
+ productId,
40
+ privateQueryParameterNames
40
41
  });
41
42
  // Set the telemetry correlation ids on every Mixpanel event.
42
43
  if (telemetryContext) {
@@ -63,7 +64,7 @@ class MixpanelInitializer {
63
64
  * @returns {MixpanelClient} A Mixpanel client instance.
64
65
  * @see {@link https://workleap.github.io/wl-telemetry}
65
66
  */ function initializeMixpanel(envOrTrackingApiBaseUrl, options) {
66
- getRegistrationGuard().throw("[mixpanel] Mixpanel has already been initialized. Did you call the \"initializeMixpanel\" function twice?");
67
+ getRegistrationGuard().throw('[mixpanel] Mixpanel has already been initialized. Did you call the "initializeMixpanel" function twice?');
67
68
  return new MixpanelInitializer().initialize(envOrTrackingApiBaseUrl, options);
68
69
  }
69
70
 
@@ -1 +1 @@
1
- {"version":3,"file":"js/initializeMixpanel.js","sources":["../../src/js/initializeMixpanel.ts"],"sourcesContent":["import { HasExecutedGuard, type LogRocketInstrumentationPartialClient, type TelemetryContext } from \"@workleap-telemetry/core\";\nimport { createCompositeLogger, type RootLogger } from \"@workleap/logging\";\nimport { getTrackingEndpoint, type MixpanelEnvironment } from \"./env.ts\";\nimport { MixpanelClientImpl, type MixpanelClient } from \"./MixpanelClient.ts\";\nimport { getTelemetryProperties, OtherProperties } from \"./properties.ts\";\n\nlet registrationGuardInstance: HasExecutedGuard | undefined;\n\n// It's important to use a lazy singleton instead of a singleton to avoid\n// any future probleme related to HMR, tree-shaking, SSR, etc..\nfunction getRegistrationGuard() {\n if (!registrationGuardInstance) {\n registrationGuardInstance = new HasExecutedGuard();\n }\n\n return registrationGuardInstance;\n}\n\n// This function should only be used by tests.\nexport function __resetRegistrationGuard() {\n if (registrationGuardInstance) {\n registrationGuardInstance.reset();\n }\n}\n\n///////////////////////////\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface InitializeMixpanelOptions {\n /**\n * An optional product id that will be attached to every event.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n productId?: string;\n /**\n * An optional tracking endpoint.\n * @default \"tracking/track\"\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n trackingEndpoint?: string;\n /**\n * Context including telemetry correlation ids.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n telemetryContext?: TelemetryContext;\n /**\n * An optional LogRocket client to automatically add the LogRocket\n * session URL to Mixpanel events once it's available.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n logRocketInstrumentationClient?: LogRocketInstrumentationPartialClient;\n /**\n * Whether or not debug information should be logged to the console.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n verbose?: boolean;\n /**\n * An array of RootLogger instances.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n loggers?: RootLogger[];\n}\n\nexport class MixpanelInitializer {\n initialize(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), options: Omit<InitializeMixpanelOptions, \"globalEventProperties\"> = {}) {\n const {\n productId,\n trackingEndpoint,\n telemetryContext,\n logRocketInstrumentationClient,\n verbose = false,\n loggers = []\n } = options;\n\n const logger = createCompositeLogger(verbose, loggers);\n const endpoint = getTrackingEndpoint(envOrTrackingApiBaseUrl, trackingEndpoint);\n\n logger.information(\"[mixpanel] Mixpanel is initialized.\");\n\n const client = new MixpanelClientImpl(endpoint, logger, {\n productId\n });\n\n // Set the telemetry correlation ids on every Mixpanel event.\n if (telemetryContext) {\n for (const [key, value] of Object.entries(getTelemetryProperties(telemetryContext))) {\n client.setGlobalEventProperty(key, value);\n }\n }\n\n // If a LogRocket client is already available, register a listener to get the LogRocket session url\n // once it's available to set it on every Mixpanel event.\n if (logRocketInstrumentationClient) {\n logRocketInstrumentationClient.registerGetSessionUrlListener((sessionUrl: string) => {\n logger\n .withText(\"[mixpanel] Received LogRocket session replay URL:\")\n .withText(sessionUrl)\n .debug();\n\n client.setGlobalEventProperty(OtherProperties.LogRocketSessionUrl, sessionUrl);\n });\n }\n\n // The cast is to normalize the inferred return type to the \"LogRocketInstrumentationClient\" type.\n return client as MixpanelClient;\n }\n}\n\n/**\n * Initialize Mixpanel telemetry.\n * @param envOrTrackingApiBaseUrl The environment to get the navigation url from or a base URL.\n * @param options Mixpanel instrumentation options.\n * @returns {MixpanelClient} A Mixpanel client instance.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function initializeMixpanel(\n envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}),\n options?: InitializeMixpanelOptions\n) {\n getRegistrationGuard().throw(\"[mixpanel] Mixpanel has already been initialized. Did you call the \\\"initializeMixpanel\\\" function twice?\");\n\n return new MixpanelInitializer().initialize(\n envOrTrackingApiBaseUrl,\n options\n );\n}\n"],"names":["HasExecutedGuard","createCompositeLogger","getTrackingEndpoint","MixpanelClientImpl","getTelemetryProperties","OtherProperties","registrationGuardInstance","getRegistrationGuard","__resetRegistrationGuard","MixpanelInitializer","envOrTrackingApiBaseUrl","options","productId","trackingEndpoint","telemetryContext","logRocketInstrumentationClient","verbose","loggers","logger","endpoint","client","key","value","Object","sessionUrl","initializeMixpanel"],"mappings":";;;;;;;;;;;AAA+H;AACpD;AACF;AACK;AACJ;AAE1E,IAAIM,yBAAyBA;AAE7B,yEAAyE;AACzE,+DAA+D;AAC/D,SAASC,oBAAoBA;IACzB,IAAI,CAACD,yBAAyBA,EAAE;QAC5BA,yBAAyBA,GAAG,IAAIN,gBAAgBA;IACpD;IAEA,OAAOM,yBAAyBA;AACpC;AAEA,8CAA8C;AACvC,SAASE,wBAAwBA;IACpC,IAAIF,yBAAyBA,EAAE;QAC3BA,yBAAyBA,CAAC,KAAK;IACnC;AACJ;AA0CO,MAAMG,mBAAmBA;IAC5B,WAAWC,uBAA4D,EAAEC,UAAoE,CAAC,CAAC,EAAE;QAC7I,MAAM,EACFC,SAAS,EACTC,gBAAgB,EAChBC,gBAAgB,EAChBC,8BAA8B,EAC9BC,UAAU,KAAK,EACfC,UAAU,EAAE,EACf,GAAGN;QAEJ,MAAMO,SAASjB,qBAAqBA,CAACe,SAASC;QAC9C,MAAME,WAAWjB,mBAAmBA,CAACQ,yBAAyBG;QAE9DK,OAAO,WAAW,CAAC;QAEnB,MAAME,SAAS,IAAIjB,kBAAkBA,CAACgB,UAAUD,QAAQ;YACpDN;QACJ;QAEA,6DAA6D;QAC7D,IAAIE,kBAAkB;YAClB,KAAK,MAAM,CAACO,KAAKC,MAAM,IAAIC,OAAO,OAAO,CAACnB,sBAAsBA,CAACU,mBAAoB;gBACjFM,OAAO,sBAAsB,CAACC,KAAKC;YACvC;QACJ;QAEA,mGAAmG;QACnG,yDAAyD;QACzD,IAAIP,gCAAgC;YAChCA,+BAA+B,6BAA6B,CAAC,CAACS;gBAC1DN,OACK,QAAQ,CAAC,qDACT,QAAQ,CAACM,YACT,KAAK;gBAEVJ,OAAO,sBAAsB,CAACf,mCAAmC,EAAEmB;YACvE;QACJ;QAEA,kGAAkG;QAClG,OAAOJ;IACX;AACJ;AAEA;;;;;;CAMC,GACM,SAASK,kBAAkBA,CAC9Bf,uBAA4D,EAC5DC,OAAmC;IAEnCJ,oBAAoBA,GAAG,KAAK,CAAC;IAE7B,OAAO,IAAIE,mBAAmBA,GAAG,UAAU,CACvCC,yBACAC;AAER"}
1
+ {"version":3,"file":"js/initializeMixpanel.js","sources":["../../src/js/initializeMixpanel.ts"],"sourcesContent":["import { HasExecutedGuard, type LogRocketInstrumentationPartialClient, type TelemetryContext } from \"@workleap-telemetry/core\";\nimport { createCompositeLogger, type RootLogger } from \"@workleap/logging\";\nimport { getTrackingEndpoint, type MixpanelEnvironment } from \"./env.ts\";\nimport { MixpanelClientImpl, type MixpanelClient } from \"./MixpanelClient.ts\";\nimport { getTelemetryProperties, OtherProperties } from \"./properties.ts\";\n\nlet registrationGuardInstance: HasExecutedGuard | undefined;\n\n// It's important to use a lazy singleton instead of a singleton to avoid\n// any future probleme related to HMR, tree-shaking, SSR, etc..\nfunction getRegistrationGuard() {\n if (!registrationGuardInstance) {\n registrationGuardInstance = new HasExecutedGuard();\n }\n\n return registrationGuardInstance;\n}\n\n// This function should only be used by tests.\nexport function __resetRegistrationGuard() {\n if (registrationGuardInstance) {\n registrationGuardInstance.reset();\n }\n}\n\n///////////////////////////\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface InitializeMixpanelOptions {\n /**\n * An optional product id that will be attached to every event.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n productId?: string;\n /**\n * An optional tracking endpoint.\n * @default \"tracking/track\"\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n trackingEndpoint?: string;\n /**\n * Names of additional query parameters to redact from the URLs sent with every event.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n privateQueryParameterNames?: string[];\n /**\n * Context including telemetry correlation ids.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n telemetryContext?: TelemetryContext;\n /**\n * An optional LogRocket client to automatically add the LogRocket\n * session URL to Mixpanel events once it's available.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n logRocketInstrumentationClient?: LogRocketInstrumentationPartialClient;\n /**\n * Whether or not debug information should be logged to the console.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n verbose?: boolean;\n /**\n * An array of RootLogger instances.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\n loggers?: RootLogger[];\n}\n\nexport class MixpanelInitializer {\n initialize(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), options: Omit<InitializeMixpanelOptions, \"globalEventProperties\"> = {}) {\n const { productId, trackingEndpoint, privateQueryParameterNames, telemetryContext, logRocketInstrumentationClient, verbose = false, loggers = [] } = options;\n\n const logger = createCompositeLogger(verbose, loggers);\n const endpoint = getTrackingEndpoint(envOrTrackingApiBaseUrl, trackingEndpoint);\n\n logger.information(\"[mixpanel] Mixpanel is initialized.\");\n\n const client = new MixpanelClientImpl(endpoint, logger, {\n productId,\n privateQueryParameterNames\n });\n\n // Set the telemetry correlation ids on every Mixpanel event.\n if (telemetryContext) {\n for (const [key, value] of Object.entries(getTelemetryProperties(telemetryContext))) {\n client.setGlobalEventProperty(key, value);\n }\n }\n\n // If a LogRocket client is already available, register a listener to get the LogRocket session url\n // once it's available to set it on every Mixpanel event.\n if (logRocketInstrumentationClient) {\n logRocketInstrumentationClient.registerGetSessionUrlListener((sessionUrl: string) => {\n logger.withText(\"[mixpanel] Received LogRocket session replay URL:\").withText(sessionUrl).debug();\n\n client.setGlobalEventProperty(OtherProperties.LogRocketSessionUrl, sessionUrl);\n });\n }\n\n // The cast is to normalize the inferred return type to the \"LogRocketInstrumentationClient\" type.\n return client as MixpanelClient;\n }\n}\n\n/**\n * Initialize Mixpanel telemetry.\n * @param envOrTrackingApiBaseUrl The environment to get the navigation url from or a base URL.\n * @param options Mixpanel instrumentation options.\n * @returns {MixpanelClient} A Mixpanel client instance.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function initializeMixpanel(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), options?: InitializeMixpanelOptions) {\n getRegistrationGuard().throw('[mixpanel] Mixpanel has already been initialized. Did you call the \"initializeMixpanel\" function twice?');\n\n return new MixpanelInitializer().initialize(envOrTrackingApiBaseUrl, options);\n}\n"],"names":["HasExecutedGuard","createCompositeLogger","getTrackingEndpoint","MixpanelClientImpl","getTelemetryProperties","OtherProperties","registrationGuardInstance","getRegistrationGuard","__resetRegistrationGuard","MixpanelInitializer","envOrTrackingApiBaseUrl","options","productId","trackingEndpoint","privateQueryParameterNames","telemetryContext","logRocketInstrumentationClient","verbose","loggers","logger","endpoint","client","key","value","Object","sessionUrl","initializeMixpanel"],"mappings":";;;;;;;;;;;AAA+H;AACpD;AACF;AACK;AACJ;AAE1E,IAAIM;AAEJ,yEAAyE;AACzE,+DAA+D;AAC/D,SAASC;IACL,IAAI,CAACD,2BAA2B;QAC5BA,4BAA4B,IAAIN,gBAAgBA;IACpD;IAEA,OAAOM;AACX;AAEA,8CAA8C;AACvC,SAASE;IACZ,IAAIF,2BAA2B;QAC3BA,0BAA0B,KAAK;IACnC;AACJ;AA+CO,MAAMG;IACT,WAAWC,uBAA4D,EAAEC,UAAoE,CAAC,CAAC,EAAE;QAC7I,MAAM,EAAEC,SAAS,EAAEC,gBAAgB,EAAEC,0BAA0B,EAAEC,gBAAgB,EAAEC,8BAA8B,EAAEC,UAAU,KAAK,EAAEC,UAAU,EAAE,EAAE,GAAGP;QAErJ,MAAMQ,SAASlB,qBAAqBA,CAACgB,SAASC;QAC9C,MAAME,WAAWlB,mBAAmBA,CAACQ,yBAAyBG;QAE9DM,OAAO,WAAW,CAAC;QAEnB,MAAME,SAAS,IAAIlB,kBAAkBA,CAACiB,UAAUD,QAAQ;YACpDP;YACAE;QACJ;QAEA,6DAA6D;QAC7D,IAAIC,kBAAkB;YAClB,KAAK,MAAM,CAACO,KAAKC,MAAM,IAAIC,OAAO,OAAO,CAACpB,sBAAsBA,CAACW,mBAAoB;gBACjFM,OAAO,sBAAsB,CAACC,KAAKC;YACvC;QACJ;QAEA,mGAAmG;QACnG,yDAAyD;QACzD,IAAIP,gCAAgC;YAChCA,+BAA+B,6BAA6B,CAAC,CAACS;gBAC1DN,OAAO,QAAQ,CAAC,qDAAqD,QAAQ,CAACM,YAAY,KAAK;gBAE/FJ,OAAO,sBAAsB,CAAChB,mCAAmC,EAAEoB;YACvE;QACJ;QAEA,kGAAkG;QAClG,OAAOJ;IACX;AACJ;AAEA;;;;;;CAMC,GACM,SAASK,mBAAmBhB,uBAA4D,EAAEC,OAAmC;IAChIJ,uBAAuB,KAAK,CAAC;IAE7B,OAAO,IAAIE,sBAAsB,UAAU,CAACC,yBAAyBC;AACzE"}
@@ -11,7 +11,7 @@ export declare const BaseProperties: {
11
11
  readonly ScreenHeight: "$screen_height";
12
12
  readonly ScreenWidth: "$screen_width";
13
13
  };
14
- export declare function getBaseProperties(): {
14
+ export declare function getBaseProperties(privateQueryParameterNames: string[]): {
15
15
  $os: string;
16
16
  $browser: string;
17
17
  $referrer: string;
@@ -1,4 +1,4 @@
1
- import { browserName, browserVersion, deviceType, osName, referringDomain } from "./utils.js";
1
+ import { browserName, browserVersion, deviceType, osName, redactQueryParameters, referringDomain } from "./utils.js";
2
2
 
3
3
 
4
4
 
@@ -14,16 +14,17 @@ const BaseProperties = {
14
14
  ScreenHeight: "$screen_height",
15
15
  ScreenWidth: "$screen_width"
16
16
  };
17
- function getBaseProperties() {
17
+ function getBaseProperties(privateQueryParameterNames) {
18
18
  const userAgent = navigator.userAgent;
19
19
  const device = deviceType(userAgent);
20
20
  return {
21
21
  [BaseProperties.Os]: osName(userAgent),
22
22
  [BaseProperties.Browser]: browserName(userAgent, navigator.vendor),
23
- [BaseProperties.Referrer]: document.referrer,
23
+ [BaseProperties.Referrer]: redactQueryParameters(document.referrer, privateQueryParameterNames),
24
24
  [BaseProperties.ReferringDomain]: referringDomain(document.referrer),
25
25
  [BaseProperties.Device]: device,
26
- [BaseProperties.CurrentUrl]: window.location.href,
26
+ // The fragment is removed because it can include sensitive values, such as an access token.
27
+ [BaseProperties.CurrentUrl]: redactQueryParameters(window.location.href.split("#")[0], privateQueryParameterNames),
27
28
  [BaseProperties.BrowserVersion]: browserVersion(userAgent, navigator.vendor),
28
29
  [BaseProperties.ScreenHeight]: window.screen.height,
29
30
  [BaseProperties.ScreenWidth]: window.screen.width,
@@ -1 +1 @@
1
- {"version":3,"file":"js/properties.js","sources":["../../src/js/properties.ts"],"sourcesContent":["\nimport type { MixpanelEventProperties, TelemetryContext } from \"@workleap-telemetry/core\";\nimport { browserName, browserVersion, deviceType, osName, referringDomain } from \"./utils.ts\";\n\nexport const BaseProperties = {\n Browser: \"$browser\",\n BrowserVersion: \"$browser_version\",\n CurrentUrl: \"$current_url\",\n Device: \"$device\",\n IsMobile: \"Is Mobile\",\n Os: \"$os\",\n Referrer: \"$referrer\",\n ReferringDomain: \"$referring_domain\",\n ScreenHeight: \"$screen_height\",\n ScreenWidth: \"$screen_width\"\n} as const;\n\nexport function getBaseProperties() {\n const userAgent = navigator.userAgent;\n const device = deviceType(userAgent);\n\n return {\n [BaseProperties.Os]: osName(userAgent),\n [BaseProperties.Browser]: browserName(userAgent, navigator.vendor),\n [BaseProperties.Referrer]: document.referrer,\n [BaseProperties.ReferringDomain]: referringDomain(document.referrer),\n [BaseProperties.Device]: device,\n [BaseProperties.CurrentUrl]: window.location.href,\n [BaseProperties.BrowserVersion]: browserVersion(userAgent, navigator.vendor),\n [BaseProperties.ScreenHeight]: window.screen.height,\n [BaseProperties.ScreenWidth]: window.screen.width,\n [BaseProperties.IsMobile]: device.length > 0\n } satisfies MixpanelEventProperties;\n}\n\nexport const TelemetryProperties = {\n DeviceId: \"Device Id\",\n TelemetryId: \"Telemetry Id\"\n} as const;\n\nexport function getTelemetryProperties(context: TelemetryContext) {\n return {\n [TelemetryProperties.TelemetryId]: context.telemetryId,\n [TelemetryProperties.DeviceId]: context.deviceId\n } satisfies MixpanelEventProperties;\n}\n\nexport const OtherProperties = {\n LogRocketSessionUrl: \"LogRocket Session Url\"\n};\n"],"names":["browserName","browserVersion","deviceType","osName","referringDomain","BaseProperties","getBaseProperties","userAgent","navigator","device","document","window","TelemetryProperties","getTelemetryProperties","context","OtherProperties"],"mappings":";;;AAE8F;AAEvF,MAAMK,cAAcA,GAAG;IAC1B,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,QAAQ;IACR,UAAU;IACV,IAAI;IACJ,UAAU;IACV,iBAAiB;IACjB,cAAc;IACd,aAAa;AACjB,EAAW;AAEJ,SAASC,iBAAiBA;IAC7B,MAAMC,YAAYC,UAAU,SAAS;IACrC,MAAMC,SAASP,UAAUA,CAACK;IAE1B,OAAO;QACH,CAACF,cAAcA,CAAC,EAAE,CAAC,EAAEF,MAAMA,CAACI;QAC5B,CAACF,cAAcA,CAAC,OAAO,CAAC,EAAEL,WAAWA,CAACO,WAAWC,UAAU,MAAM;QACjE,CAACH,cAAcA,CAAC,QAAQ,CAAC,EAAEK,SAAS,QAAQ;QAC5C,CAACL,cAAcA,CAAC,eAAe,CAAC,EAAED,eAAeA,CAACM,SAAS,QAAQ;QACnE,CAACL,cAAcA,CAAC,MAAM,CAAC,EAAEI;QACzB,CAACJ,cAAcA,CAAC,UAAU,CAAC,EAAEM,OAAO,QAAQ,CAAC,IAAI;QACjD,CAACN,cAAcA,CAAC,cAAc,CAAC,EAAEJ,cAAcA,CAACM,WAAWC,UAAU,MAAM;QAC3E,CAACH,cAAcA,CAAC,YAAY,CAAC,EAAEM,OAAO,MAAM,CAAC,MAAM;QACnD,CAACN,cAAcA,CAAC,WAAW,CAAC,EAAEM,OAAO,MAAM,CAAC,KAAK;QACjD,CAACN,cAAcA,CAAC,QAAQ,CAAC,EAAEI,OAAO,MAAM,GAAG;IAC/C;AACJ;AAEO,MAAMG,mBAAmBA,GAAG;IAC/B,UAAU;IACV,aAAa;AACjB,EAAW;AAEJ,SAASC,sBAAsBA,CAACC,OAAyB;IAC5D,OAAO;QACH,CAACF,mBAAmBA,CAAC,WAAW,CAAC,EAAEE,QAAQ,WAAW;QACtD,CAACF,mBAAmBA,CAAC,QAAQ,CAAC,EAAEE,QAAQ,QAAQ;IACpD;AACJ;AAEO,MAAMC,eAAeA,GAAG;IAC3B,qBAAqB;AACzB,EAAE"}
1
+ {"version":3,"file":"js/properties.js","sources":["../../src/js/properties.ts"],"sourcesContent":["import type { MixpanelEventProperties, TelemetryContext } from \"@workleap-telemetry/core\";\nimport { browserName, browserVersion, deviceType, osName, redactQueryParameters, referringDomain } from \"./utils.ts\";\n\nexport const BaseProperties = {\n Browser: \"$browser\",\n BrowserVersion: \"$browser_version\",\n CurrentUrl: \"$current_url\",\n Device: \"$device\",\n IsMobile: \"Is Mobile\",\n Os: \"$os\",\n Referrer: \"$referrer\",\n ReferringDomain: \"$referring_domain\",\n ScreenHeight: \"$screen_height\",\n ScreenWidth: \"$screen_width\"\n} as const;\n\nexport function getBaseProperties(privateQueryParameterNames: string[]) {\n const userAgent = navigator.userAgent;\n const device = deviceType(userAgent);\n\n return {\n [BaseProperties.Os]: osName(userAgent),\n [BaseProperties.Browser]: browserName(userAgent, navigator.vendor),\n [BaseProperties.Referrer]: redactQueryParameters(document.referrer, privateQueryParameterNames),\n [BaseProperties.ReferringDomain]: referringDomain(document.referrer),\n [BaseProperties.Device]: device,\n // The fragment is removed because it can include sensitive values, such as an access token.\n [BaseProperties.CurrentUrl]: redactQueryParameters(window.location.href.split(\"#\")[0], privateQueryParameterNames),\n [BaseProperties.BrowserVersion]: browserVersion(userAgent, navigator.vendor),\n [BaseProperties.ScreenHeight]: window.screen.height,\n [BaseProperties.ScreenWidth]: window.screen.width,\n [BaseProperties.IsMobile]: device.length > 0\n } satisfies MixpanelEventProperties;\n}\n\nexport const TelemetryProperties = {\n DeviceId: \"Device Id\",\n TelemetryId: \"Telemetry Id\"\n} as const;\n\nexport function getTelemetryProperties(context: TelemetryContext) {\n return {\n [TelemetryProperties.TelemetryId]: context.telemetryId,\n [TelemetryProperties.DeviceId]: context.deviceId\n } satisfies MixpanelEventProperties;\n}\n\nexport const OtherProperties = {\n LogRocketSessionUrl: \"LogRocket Session Url\"\n};\n"],"names":["browserName","browserVersion","deviceType","osName","redactQueryParameters","referringDomain","BaseProperties","getBaseProperties","privateQueryParameterNames","userAgent","navigator","device","document","window","TelemetryProperties","getTelemetryProperties","context","OtherProperties"],"mappings":";;;AACqH;AAE9G,MAAMM,iBAAiB;IAC1B,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,QAAQ;IACR,UAAU;IACV,IAAI;IACJ,UAAU;IACV,iBAAiB;IACjB,cAAc;IACd,aAAa;AACjB,EAAW;AAEJ,SAASC,kBAAkBC,0BAAoC;IAClE,MAAMC,YAAYC,UAAU,SAAS;IACrC,MAAMC,SAAST,UAAUA,CAACO;IAE1B,OAAO;QACH,CAACH,eAAe,EAAE,CAAC,EAAEH,MAAMA,CAACM;QAC5B,CAACH,eAAe,OAAO,CAAC,EAAEN,WAAWA,CAACS,WAAWC,UAAU,MAAM;QACjE,CAACJ,eAAe,QAAQ,CAAC,EAAEF,qBAAqBA,CAACQ,SAAS,QAAQ,EAAEJ;QACpE,CAACF,eAAe,eAAe,CAAC,EAAED,eAAeA,CAACO,SAAS,QAAQ;QACnE,CAACN,eAAe,MAAM,CAAC,EAAEK;QACzB,4FAA4F;QAC5F,CAACL,eAAe,UAAU,CAAC,EAAEF,qBAAqBA,CAACS,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAEL;QACvF,CAACF,eAAe,cAAc,CAAC,EAAEL,cAAcA,CAACQ,WAAWC,UAAU,MAAM;QAC3E,CAACJ,eAAe,YAAY,CAAC,EAAEO,OAAO,MAAM,CAAC,MAAM;QACnD,CAACP,eAAe,WAAW,CAAC,EAAEO,OAAO,MAAM,CAAC,KAAK;QACjD,CAACP,eAAe,QAAQ,CAAC,EAAEK,OAAO,MAAM,GAAG;IAC/C;AACJ;AAEO,MAAMG,sBAAsB;IAC/B,UAAU;IACV,aAAa;AACjB,EAAW;AAEJ,SAASC,uBAAuBC,OAAyB;IAC5D,OAAO;QACH,CAACF,oBAAoB,WAAW,CAAC,EAAEE,QAAQ,WAAW;QACtD,CAACF,oBAAoB,QAAQ,CAAC,EAAEE,QAAQ,QAAQ;IACpD;AACJ;AAEO,MAAMC,kBAAkB;IAC3B,qBAAqB;AACzB,EAAE"}
@@ -1,10 +1,11 @@
1
- export declare function browserName(userAgent: string, vendor?: string, opera?: object): "" | "Opera Mini" | "Opera" | "BlackBerry" | "Internet Explorer Mobile" | "Microsoft Edge" | "Facebook Mobile" | "Chrome" | "Chrome iOS" | "UC Browser" | "Firefox iOS" | "Mobile Safari" | "Safari" | "Android Mobile" | "Konqueror" | "Firefox" | "Internet Explorer" | "Mozilla";
1
+ export declare function browserName(userAgent: string, vendor?: string, opera?: object): "" | "Android Mobile" | "BlackBerry" | "Chrome" | "Chrome iOS" | "Facebook Mobile" | "Firefox" | "Firefox iOS" | "Internet Explorer" | "Internet Explorer Mobile" | "Konqueror" | "Microsoft Edge" | "Mobile Safari" | "Mozilla" | "Opera" | "Opera Mini" | "Safari" | "UC Browser";
2
2
  /**
3
3
  * This function detects which browser version is running this script,
4
4
  * parsing major and minor version (e.g., 42.1). User agent strings from:
5
5
  * http://www.useragentstring.com/pages/useragentstring.php
6
6
  */
7
7
  export declare function browserVersion(userAgent: string, vendor?: string, opera?: object): number | null;
8
- export declare function osName(userAgent: string): "" | "BlackBerry" | "Android" | "Windows Phone" | "Windows" | "iOS" | "Mac OS X" | "Linux" | "Chrome OS";
9
- export declare function deviceType(userAgent: string): "" | "BlackBerry" | "Android" | "Windows Phone" | "iPad" | "iPod Touch" | "iPhone";
8
+ export declare function osName(userAgent: string): "" | "Android" | "BlackBerry" | "Chrome OS" | "Linux" | "Mac OS X" | "Windows" | "Windows Phone" | "iOS";
9
+ export declare function deviceType(userAgent: string): "" | "Android" | "BlackBerry" | "Windows Phone" | "iPad" | "iPhone" | "iPod Touch";
10
10
  export declare function referringDomain(referrer: string): string;
11
+ export declare function redactQueryParameters(url: string, queryParameterNames: string[]): string;
package/dist/js/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // This code is adapted from https://github.com/mixpanel/mixpanel-js/blob/master/src/utils.js
2
2
  function browserName(userAgent, vendor, opera) {
3
3
  // vendor is undefined for at least IE9
4
- vendor = vendor || ""; // eslint-disable-line no-param-reassign
4
+ vendor = vendor || ""; // oxlint-disable-line eslint/no-param-reassign
5
5
  if (opera || userAgent.includes(" OPR/")) {
6
6
  if (userAgent.includes("Mini")) {
7
7
  return "Opera Mini";
@@ -50,19 +50,19 @@ function browserName(userAgent, vendor, opera) {
50
50
  const versionRegexs = {
51
51
  "Internet Explorer Mobile": /rv:(\d+(\.\d+)?)/,
52
52
  "Microsoft Edge": /Edge\/(\d+(\.\d+)?)/,
53
- "Chrome": /Chrome\/(\d+(\.\d+)?)/,
53
+ Chrome: /Chrome\/(\d+(\.\d+)?)/,
54
54
  "Chrome iOS": /CriOS\/(\d+(\.\d+)?)/,
55
55
  "UC Browser": /(UCBrowser|UCWEB)\/(\d+(\.\d+)?)/,
56
- "Safari": /Version\/(\d+(\.\d+)?)/,
56
+ Safari: /Version\/(\d+(\.\d+)?)/,
57
57
  "Mobile Safari": /Version\/(\d+(\.\d+)?)/,
58
- "Opera": /(Opera|OPR)\/(\d+(\.\d+)?)/,
59
- "Firefox": /Firefox\/(\d+(\.\d+)?)/,
58
+ Opera: /(Opera|OPR)\/(\d+(\.\d+)?)/,
59
+ Firefox: /Firefox\/(\d+(\.\d+)?)/,
60
60
  "Firefox iOS": /FxiOS\/(\d+(\.\d+)?)/,
61
- "Konqueror": /Konqueror:(\d+(\.\d+)?)/,
62
- "BlackBerry": /BlackBerry (\d+(\.\d+)?)/,
61
+ Konqueror: /Konqueror:(\d+(\.\d+)?)/,
62
+ BlackBerry: /BlackBerry (\d+(\.\d+)?)/,
63
63
  "Android Mobile": /android\s(\d+(\.\d+)?)/,
64
64
  "Internet Explorer": /(rv:|MSIE )(\d+(\.\d+)?)/,
65
- "Mozilla": /rv:(\d+(\.\d+)?)/
65
+ Mozilla: /rv:(\d+(\.\d+)?)/
66
66
  };
67
67
  const regex = versionRegexs[browser];
68
68
  if (regex === undefined) {
@@ -77,45 +77,36 @@ function browserName(userAgent, vendor, opera) {
77
77
  function osName(userAgent) {
78
78
  const a = userAgent;
79
79
  if (/Windows/i.test(a)) {
80
- // eslint-disable-next-line @typescript-eslint/prefer-includes
81
80
  if (/Phone/.test(a) || /WPDesktop/.test(a)) {
82
81
  return "Windows Phone";
83
82
  }
84
83
  return "Windows";
85
84
  } else if (/(iPhone|iPad|iPod)/.test(a)) {
86
85
  return "iOS";
87
- // eslint-disable-next-line @typescript-eslint/prefer-includes
88
86
  } else if (/Android/.test(a)) {
89
87
  return "Android";
90
88
  } else if (/(BlackBerry|PlayBook|BB10)/i.test(a)) {
91
89
  return "BlackBerry";
92
90
  } else if (/Mac/i.test(a)) {
93
91
  return "Mac OS X";
94
- // eslint-disable-next-line @typescript-eslint/prefer-includes
95
92
  } else if (/Linux/.test(a)) {
96
93
  return "Linux";
97
- // eslint-disable-next-line @typescript-eslint/prefer-includes
98
94
  } else if (/CrOS/.test(a)) {
99
95
  return "Chrome OS";
100
96
  }
101
97
  return "";
102
98
  }
103
99
  function deviceType(userAgent) {
104
- // eslint-disable-next-line @typescript-eslint/prefer-includes
105
100
  if (/Windows Phone/i.test(userAgent) || /WPDesktop/.test(userAgent)) {
106
101
  return "Windows Phone";
107
- // eslint-disable-next-line @typescript-eslint/prefer-includes
108
102
  } else if (/iPad/.test(userAgent)) {
109
103
  return "iPad";
110
- // eslint-disable-next-line @typescript-eslint/prefer-includes
111
104
  } else if (/iPod/.test(userAgent)) {
112
105
  return "iPod Touch";
113
- // eslint-disable-next-line @typescript-eslint/prefer-includes
114
106
  } else if (/iPhone/.test(userAgent)) {
115
107
  return "iPhone";
116
108
  } else if (/(BlackBerry|PlayBook|BB10)/i.test(userAgent)) {
117
109
  return "BlackBerry";
118
- // eslint-disable-next-line @typescript-eslint/prefer-includes
119
110
  } else if (/Android/.test(userAgent)) {
120
111
  return "Android";
121
112
  }
@@ -128,7 +119,19 @@ function referringDomain(referrer) {
128
119
  }
129
120
  return "";
130
121
  }
122
+ function redactQueryParameters(url, queryParameterNames) {
123
+ let redactedUrl = url;
124
+ for (const x of queryParameterNames){
125
+ // A name can include regular expression special characters, and can be percent-encoded in the URL, such as "user[email]" and "user%5Bemail%5D".
126
+ const escapedNames = [
127
+ x,
128
+ encodeURIComponent(x)
129
+ ].map((y)=>y.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
130
+ redactedUrl = redactedUrl.replace(new RegExp(`(?:${escapedNames.join("|")})=([^&]*)`, "gi"), ()=>`${x}=**redacted**`);
131
+ }
132
+ return redactedUrl;
133
+ }
131
134
 
132
- export { browserName, browserVersion, deviceType, osName, referringDomain };
135
+ export { browserName, browserVersion, deviceType, osName, redactQueryParameters, referringDomain };
133
136
 
134
137
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"js/utils.js","sources":["../../src/js/utils.ts"],"sourcesContent":["// This code is adapted from https://github.com/mixpanel/mixpanel-js/blob/master/src/utils.js\nexport function browserName(userAgent: string, vendor?: string, opera?: object) {\n // vendor is undefined for at least IE9\n vendor = vendor || \"\"; // eslint-disable-line no-param-reassign\n\n if (opera || userAgent.includes(\" OPR/\")) {\n if (userAgent.includes(\"Mini\")) {\n return \"Opera Mini\";\n }\n\n return \"Opera\";\n } else if (/(BlackBerry|PlayBook|BB10)/i.test(userAgent)) {\n return \"BlackBerry\";\n } else if (userAgent.includes(\"IEMobile\") || userAgent.includes(\"WPDesktop\")) {\n return \"Internet Explorer Mobile\";\n } else if (userAgent.includes(\"Edge\")) {\n return \"Microsoft Edge\";\n } else if (userAgent.includes(\"FBIOS\")) {\n return \"Facebook Mobile\";\n } else if (userAgent.includes(\"Chrome\")) {\n return \"Chrome\";\n } else if (userAgent.includes(\"CriOS\")) {\n return \"Chrome iOS\";\n } else if (userAgent.includes(\"UCWEB\") || userAgent.includes(\"UCBrowser\")) {\n return \"UC Browser\";\n } else if (userAgent.includes(\"FxiOS\")) {\n return \"Firefox iOS\";\n } else if (vendor.includes(\"Apple\")) {\n if (userAgent.includes(\"Mobile\")) {\n return \"Mobile Safari\";\n }\n\n return \"Safari\";\n } else if (userAgent.includes(\"Android\")) {\n return \"Android Mobile\";\n } else if (userAgent.includes(\"Konqueror\")) {\n return \"Konqueror\";\n } else if (userAgent.includes(\"Firefox\")) {\n return \"Firefox\";\n } else if (userAgent.includes(\"MSIE\") || userAgent.includes(\"Trident/\")) {\n return \"Internet Explorer\";\n } else if (userAgent.includes(\"Gecko\")) {\n return \"Mozilla\";\n }\n\n return \"\";\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 */\nexport function browserVersion(userAgent: string, vendor?: string, opera?: object) {\n const browser = browserName(userAgent, vendor, opera);\n const versionRegexs: { [key: string]: RegExp } = {\n \"Internet Explorer Mobile\": /rv:(\\d+(\\.\\d+)?)/,\n \"Microsoft Edge\": /Edge\\/(\\d+(\\.\\d+)?)/,\n \"Chrome\": /Chrome\\/(\\d+(\\.\\d+)?)/,\n \"Chrome iOS\": /CriOS\\/(\\d+(\\.\\d+)?)/,\n \"UC Browser\": /(UCBrowser|UCWEB)\\/(\\d+(\\.\\d+)?)/,\n \"Safari\": /Version\\/(\\d+(\\.\\d+)?)/,\n \"Mobile Safari\": /Version\\/(\\d+(\\.\\d+)?)/,\n \"Opera\": /(Opera|OPR)\\/(\\d+(\\.\\d+)?)/,\n \"Firefox\": /Firefox\\/(\\d+(\\.\\d+)?)/,\n \"Firefox iOS\": /FxiOS\\/(\\d+(\\.\\d+)?)/,\n \"Konqueror\": /Konqueror:(\\d+(\\.\\d+)?)/,\n \"BlackBerry\": /BlackBerry (\\d+(\\.\\d+)?)/,\n \"Android Mobile\": /android\\s(\\d+(\\.\\d+)?)/,\n \"Internet Explorer\": /(rv:|MSIE )(\\d+(\\.\\d+)?)/,\n \"Mozilla\": /rv:(\\d+(\\.\\d+)?)/\n };\n const regex = versionRegexs[browser];\n if (regex === undefined) {\n return null;\n }\n const matches = userAgent.match(regex);\n if (!matches) {\n return null;\n }\n\n return parseFloat(matches[matches.length - 2]);\n}\n\nexport function osName(userAgent: string) {\n const a = userAgent;\n if (/Windows/i.test(a)) {\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n if (/Phone/.test(a) || /WPDesktop/.test(a)) {\n return \"Windows Phone\";\n }\n\n return \"Windows\";\n } else if (/(iPhone|iPad|iPod)/.test(a)) {\n return \"iOS\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/Android/.test(a)) {\n return \"Android\";\n } else if (/(BlackBerry|PlayBook|BB10)/i.test(a)) {\n return \"BlackBerry\";\n } else if (/Mac/i.test(a)) {\n return \"Mac OS X\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/Linux/.test(a)) {\n return \"Linux\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/CrOS/.test(a)) {\n return \"Chrome OS\";\n }\n\n return \"\";\n}\n\nexport function deviceType(userAgent: string) {\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n if (/Windows Phone/i.test(userAgent) || /WPDesktop/.test(userAgent)) {\n return \"Windows Phone\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/iPad/.test(userAgent)) {\n return \"iPad\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/iPod/.test(userAgent)) {\n return \"iPod Touch\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/iPhone/.test(userAgent)) {\n return \"iPhone\";\n } else if (/(BlackBerry|PlayBook|BB10)/i.test(userAgent)) {\n return \"BlackBerry\";\n // eslint-disable-next-line @typescript-eslint/prefer-includes\n } else if (/Android/.test(userAgent)) {\n return \"Android\";\n }\n\n return \"\";\n}\n\nexport function referringDomain(referrer: string) {\n const split = referrer.split(\"/\");\n if (split.length >= 3) {\n return split[2];\n }\n\n return \"\";\n}\n"],"names":["browserName","userAgent","vendor","opera","browserVersion","browser","versionRegexs","regex","undefined","matches","parseFloat","osName","a","deviceType","referringDomain","referrer","split"],"mappings":"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"}
1
+ {"version":3,"file":"js/utils.js","sources":["../../src/js/utils.ts"],"sourcesContent":["// This code is adapted from https://github.com/mixpanel/mixpanel-js/blob/master/src/utils.js\nexport function browserName(userAgent: string, vendor?: string, opera?: object) {\n // vendor is undefined for at least IE9\n vendor = vendor || \"\"; // oxlint-disable-line eslint/no-param-reassign\n\n if (opera || userAgent.includes(\" OPR/\")) {\n if (userAgent.includes(\"Mini\")) {\n return \"Opera Mini\";\n }\n\n return \"Opera\";\n } else if (/(BlackBerry|PlayBook|BB10)/i.test(userAgent)) {\n return \"BlackBerry\";\n } else if (userAgent.includes(\"IEMobile\") || userAgent.includes(\"WPDesktop\")) {\n return \"Internet Explorer Mobile\";\n } else if (userAgent.includes(\"Edge\")) {\n return \"Microsoft Edge\";\n } else if (userAgent.includes(\"FBIOS\")) {\n return \"Facebook Mobile\";\n } else if (userAgent.includes(\"Chrome\")) {\n return \"Chrome\";\n } else if (userAgent.includes(\"CriOS\")) {\n return \"Chrome iOS\";\n } else if (userAgent.includes(\"UCWEB\") || userAgent.includes(\"UCBrowser\")) {\n return \"UC Browser\";\n } else if (userAgent.includes(\"FxiOS\")) {\n return \"Firefox iOS\";\n } else if (vendor.includes(\"Apple\")) {\n if (userAgent.includes(\"Mobile\")) {\n return \"Mobile Safari\";\n }\n\n return \"Safari\";\n } else if (userAgent.includes(\"Android\")) {\n return \"Android Mobile\";\n } else if (userAgent.includes(\"Konqueror\")) {\n return \"Konqueror\";\n } else if (userAgent.includes(\"Firefox\")) {\n return \"Firefox\";\n } else if (userAgent.includes(\"MSIE\") || userAgent.includes(\"Trident/\")) {\n return \"Internet Explorer\";\n } else if (userAgent.includes(\"Gecko\")) {\n return \"Mozilla\";\n }\n\n return \"\";\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 */\nexport function browserVersion(userAgent: string, vendor?: string, opera?: object) {\n const browser = browserName(userAgent, vendor, opera);\n const versionRegexs: { [key: string]: RegExp } = {\n \"Internet Explorer Mobile\": /rv:(\\d+(\\.\\d+)?)/,\n \"Microsoft Edge\": /Edge\\/(\\d+(\\.\\d+)?)/,\n Chrome: /Chrome\\/(\\d+(\\.\\d+)?)/,\n \"Chrome iOS\": /CriOS\\/(\\d+(\\.\\d+)?)/,\n \"UC Browser\": /(UCBrowser|UCWEB)\\/(\\d+(\\.\\d+)?)/,\n Safari: /Version\\/(\\d+(\\.\\d+)?)/,\n \"Mobile Safari\": /Version\\/(\\d+(\\.\\d+)?)/,\n Opera: /(Opera|OPR)\\/(\\d+(\\.\\d+)?)/,\n Firefox: /Firefox\\/(\\d+(\\.\\d+)?)/,\n \"Firefox iOS\": /FxiOS\\/(\\d+(\\.\\d+)?)/,\n Konqueror: /Konqueror:(\\d+(\\.\\d+)?)/,\n BlackBerry: /BlackBerry (\\d+(\\.\\d+)?)/,\n \"Android Mobile\": /android\\s(\\d+(\\.\\d+)?)/,\n \"Internet Explorer\": /(rv:|MSIE )(\\d+(\\.\\d+)?)/,\n Mozilla: /rv:(\\d+(\\.\\d+)?)/\n };\n const regex = versionRegexs[browser];\n if (regex === undefined) {\n return null;\n }\n const matches = userAgent.match(regex);\n if (!matches) {\n return null;\n }\n\n return parseFloat(matches[matches.length - 2]);\n}\n\nexport function osName(userAgent: string) {\n const a = userAgent;\n if (/Windows/i.test(a)) {\n if (/Phone/.test(a) || /WPDesktop/.test(a)) {\n return \"Windows Phone\";\n }\n\n return \"Windows\";\n } else if (/(iPhone|iPad|iPod)/.test(a)) {\n return \"iOS\";\n } else if (/Android/.test(a)) {\n return \"Android\";\n } else if (/(BlackBerry|PlayBook|BB10)/i.test(a)) {\n return \"BlackBerry\";\n } else if (/Mac/i.test(a)) {\n return \"Mac OS X\";\n } else if (/Linux/.test(a)) {\n return \"Linux\";\n } else if (/CrOS/.test(a)) {\n return \"Chrome OS\";\n }\n\n return \"\";\n}\n\nexport function deviceType(userAgent: string) {\n if (/Windows Phone/i.test(userAgent) || /WPDesktop/.test(userAgent)) {\n return \"Windows Phone\";\n } else if (/iPad/.test(userAgent)) {\n return \"iPad\";\n } else if (/iPod/.test(userAgent)) {\n return \"iPod Touch\";\n } else if (/iPhone/.test(userAgent)) {\n return \"iPhone\";\n } else if (/(BlackBerry|PlayBook|BB10)/i.test(userAgent)) {\n return \"BlackBerry\";\n } else if (/Android/.test(userAgent)) {\n return \"Android\";\n }\n\n return \"\";\n}\n\nexport function referringDomain(referrer: string) {\n const split = referrer.split(\"/\");\n if (split.length >= 3) {\n return split[2];\n }\n\n return \"\";\n}\n\nexport function redactQueryParameters(url: string, queryParameterNames: string[]) {\n let redactedUrl = url;\n\n for (const x of queryParameterNames) {\n // A name can include regular expression special characters, and can be percent-encoded in the URL, such as \"user[email]\" and \"user%5Bemail%5D\".\n const escapedNames = [x, encodeURIComponent(x)].map(y => y.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"));\n\n redactedUrl = redactedUrl.replace(new RegExp(`(?:${escapedNames.join(\"|\")})=([^&]*)`, \"gi\"), () => `${x}=**redacted**`);\n }\n\n return redactedUrl;\n}\n"],"names":["browserName","userAgent","vendor","opera","browserVersion","browser","versionRegexs","regex","undefined","matches","parseFloat","osName","a","deviceType","referringDomain","referrer","split","redactQueryParameters","url","queryParameterNames","redactedUrl","x","escapedNames","encodeURIComponent","y","RegExp"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"react/MixpanelContext.js","sources":["../../src/react/MixpanelContext.tsx"],"sourcesContent":["import { createContext, type PropsWithChildren, useContext } from \"react\";\nimport type { MixpanelClient } from \"../js/MixpanelClient.ts\";\n\nexport const MixpanelContext = createContext<MixpanelClient | undefined>(undefined);\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelProviderProps extends PropsWithChildren {\n client: MixpanelClient;\n}\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function MixpanelProvider(props: MixpanelProviderProps) {\n const {\n client,\n children\n } = props;\n\n return (\n <MixpanelContext.Provider value={client}>\n {children}\n </MixpanelContext.Provider>\n );\n}\n\nexport interface UseMixpanelClientOptions {\n /**\n * Whether or not an exception should be thrown if the client hasn't been provided.\n */\n throwOnUndefined?: boolean;\n}\n\nexport function useMixpanelClient(options?: { throwOnUndefined?: true }): MixpanelClient;\nexport function useMixpanelClient(options: { throwOnUndefined: false }): MixpanelClient | undefined;\n\n/**\n * Retrieve the Mixpanel client.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function useMixpanelClient(options: UseMixpanelClientOptions = {}) {\n const {\n throwOnUndefined = true\n } = options;\n\n const client = useContext(MixpanelContext);\n\n if (!client && throwOnUndefined) {\n throw new Error(\"[mixpanel] The useMixpanelClient function is called before a MixpanelClient instance has been provided.\");\n }\n\n return client;\n}\n"],"names":["createContext","useContext","MixpanelContext","undefined","MixpanelProvider","props","client","children","useMixpanelClient","options","throwOnUndefined","Error"],"mappings":";;;;;;AAA0E;AAGnE,MAAME,eAAeA,iBAAGF,aAAaA,CAA6BG,WAAW;AASpF;;CAEC,GACM,SAASC,gBAAgBA,CAACC,KAA4B;IACzD,MAAM,EACFC,MAAM,EACNC,QAAQ,EACX,GAAGF;IAEJ,qBACI,IAACH,eAAeA,CAAC,QAAQ;QAAC,OAAOI;kBAC5BC;;AAGb;AAYA;;;CAGC,GACM,SAASC,iBAAiBA,CAACC,UAAoC,CAAC,CAAC;IACpE,MAAM,EACFC,mBAAmB,IAAI,EAC1B,GAAGD;IAEJ,MAAMH,SAASL,UAAUA,CAACC,eAAeA;IAEzC,IAAI,CAACI,UAAUI,kBAAkB;QAC7B,MAAM,IAAIC,MAAM;IACpB;IAEA,OAAOL;AACX"}
1
+ {"version":3,"file":"react/MixpanelContext.js","sources":["../../src/react/MixpanelContext.tsx"],"sourcesContent":["import { createContext, type PropsWithChildren, useContext } from \"react\";\nimport type { MixpanelClient } from \"../js/MixpanelClient.ts\";\n\nexport const MixpanelContext = createContext<MixpanelClient | undefined>(undefined);\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelProviderProps extends PropsWithChildren {\n client: MixpanelClient;\n}\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function MixpanelProvider(props: MixpanelProviderProps) {\n const { client, children } = props;\n\n return <MixpanelContext.Provider value={client}>{children}</MixpanelContext.Provider>;\n}\n\nexport interface UseMixpanelClientOptions {\n /**\n * Whether or not an exception should be thrown if the client hasn't been provided.\n */\n throwOnUndefined?: boolean;\n}\n\nexport function useMixpanelClient(options?: { throwOnUndefined?: true }): MixpanelClient;\nexport function useMixpanelClient(options: { throwOnUndefined: false }): MixpanelClient | undefined;\n\n/**\n * Retrieve the Mixpanel client.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function useMixpanelClient(options: UseMixpanelClientOptions = {}) {\n const { throwOnUndefined = true } = options;\n\n const client = useContext(MixpanelContext);\n\n if (!client && throwOnUndefined) {\n throw new Error(\"[mixpanel] The useMixpanelClient function is called before a MixpanelClient instance has been provided.\");\n }\n\n return client;\n}\n"],"names":["createContext","useContext","MixpanelContext","undefined","MixpanelProvider","props","client","children","useMixpanelClient","options","throwOnUndefined","Error"],"mappings":";;;;;;AAA0E;AAGnE,MAAME,gCAAkBF,aAAaA,CAA6BG,WAAW;AASpF;;CAEC,GACM,SAASC,iBAAiBC,KAA4B;IACzD,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAE,GAAGF;IAE7B,qBAAO,IAACH,gBAAgB,QAAQ;QAAC,OAAOI;kBAASC;;AACrD;AAYA;;;CAGC,GACM,SAASC,kBAAkBC,UAAoC,CAAC,CAAC;IACpE,MAAM,EAAEC,mBAAmB,IAAI,EAAE,GAAGD;IAEpC,MAAMH,SAASL,UAAUA,CAACC;IAE1B,IAAI,CAACI,UAAUI,kBAAkB;QAC7B,MAAM,IAAIC,MAAM;IACpB;IAEA,OAAOL;AACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"react/MixpanelPropertiesProvider.js","sources":["../../src/react/MixpanelPropertiesProvider.tsx"],"sourcesContent":["import { createContext, type PropsWithChildren, useContext, useMemo } from \"react\";\n\nconst MixpanelPropertiesContext = createContext<Record<string, unknown>>({});\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelPropertiesProviderProps extends PropsWithChildren {\n value: Record<string, unknown>;\n}\n\n/**\n * Define Mixpanel properties that will be passed down to nested \"useTrackingFunction\" or \"useMixpanelTrackingFunction\" hook.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function MixpanelPropertiesProvider(props: MixpanelPropertiesProviderProps) {\n const {\n value,\n children\n } = props;\n\n const parentContext = useContext(MixpanelPropertiesContext);\n\n const contextValue = useMemo(() => ({\n ...parentContext,\n ...value\n }), [parentContext, value]);\n\n return (\n <MixpanelPropertiesContext.Provider value={contextValue}>\n {children}\n </MixpanelPropertiesContext.Provider>\n );\n}\n\n/**\n * Retrieve the Mixpanel properties from all parent providers.\n * @returns The context value or an empty object literal if no provider isdefined.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport const useMixpanelProviderProperties = () => {\n return useContext(MixpanelPropertiesContext);\n};\n"],"names":["createContext","useContext","useMemo","MixpanelPropertiesContext","MixpanelPropertiesProvider","props","value","children","parentContext","contextValue","useMixpanelProviderProperties"],"mappings":";;;;;;AAAmF;AAEnF,MAAMG,yBAAyBA,iBAAGH,aAAaA,CAA0B,CAAC;AAS1E;;;CAGC,GACM,SAASI,0BAA0BA,CAACC,KAAsC;IAC7E,MAAM,EACFC,KAAK,EACLC,QAAQ,EACX,GAAGF;IAEJ,MAAMG,gBAAgBP,UAAUA,CAACE,yBAAyBA;IAE1D,MAAMM,eAAeP,OAAOA,CAAC,IAAO;YAChC,GAAGM,aAAa;YAChB,GAAGF,KAAK;QACZ,IAAI;QAACE;QAAeF;KAAM;IAE1B,qBACI,IAACH,yBAAyBA,CAAC,QAAQ;QAAC,OAAOM;kBACtCF;;AAGb;AAEA;;;;CAIC,GACM,MAAMG,6BAA6BA,GAAG;IACzC,OAAOT,UAAUA,CAACE,yBAAyBA;AAC/C,EAAE"}
1
+ {"version":3,"file":"react/MixpanelPropertiesProvider.js","sources":["../../src/react/MixpanelPropertiesProvider.tsx"],"sourcesContent":["import { createContext, type PropsWithChildren, useContext, useMemo } from \"react\";\n\nconst MixpanelPropertiesContext = createContext<Record<string, unknown>>({});\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport interface MixpanelPropertiesProviderProps extends PropsWithChildren {\n value: Record<string, unknown>;\n}\n\n/**\n * Define Mixpanel properties that will be passed down to nested \"useTrackingFunction\" or \"useMixpanelTrackingFunction\" hook.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function MixpanelPropertiesProvider(props: MixpanelPropertiesProviderProps) {\n const { value, children } = props;\n\n const parentContext = useContext(MixpanelPropertiesContext);\n\n const contextValue = useMemo(\n () => ({\n ...parentContext,\n ...value\n }),\n [parentContext, value]\n );\n\n return <MixpanelPropertiesContext.Provider value={contextValue}>{children}</MixpanelPropertiesContext.Provider>;\n}\n\n/**\n * Retrieve the Mixpanel properties from all parent providers.\n * @returns The context value or an empty object literal if no provider isdefined.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport const useMixpanelProviderProperties = () => {\n return useContext(MixpanelPropertiesContext);\n};\n"],"names":["createContext","useContext","useMemo","MixpanelPropertiesContext","MixpanelPropertiesProvider","props","value","children","parentContext","contextValue","useMixpanelProviderProperties"],"mappings":";;;;;;AAAmF;AAEnF,MAAMG,0CAA4BH,aAAaA,CAA0B,CAAC;AAS1E;;;CAGC,GACM,SAASI,2BAA2BC,KAAsC;IAC7E,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGF;IAE5B,MAAMG,gBAAgBP,UAAUA,CAACE;IAEjC,MAAMM,eAAeP,OAAOA,CACxB,IAAO;YACH,GAAGM,aAAa;YAChB,GAAGF,KAAK;QACZ,IACA;QAACE;QAAeF;KAAM;IAG1B,qBAAO,IAACH,0BAA0B,QAAQ;QAAC,OAAOM;kBAAeF;;AACrE;AAEA;;;;CAIC,GACM,MAAMG,gCAAgC;IACzC,OAAOT,UAAUA,CAACE;AACtB,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"react/index.js","sources":["../../src/react/index.ts"],"sourcesContent":["export * from \"../js/index.ts\";\nexport { MixpanelProvider, useMixpanelClient, type UseMixpanelClientOptions } from \"./MixpanelContext.tsx\";\nexport { MixpanelPropertiesProvider, useMixpanelProviderProperties, type MixpanelPropertiesProviderProps } from \"./MixpanelPropertiesProvider.tsx\";\nexport { useTrackingFunction, type UseTrackingFunctionOptions } from \"./useTrackingFunction.ts\";\n\n"],"names":["MixpanelProvider","useMixpanelClient","MixpanelPropertiesProvider","useMixpanelProviderProperties","useTrackingFunction"],"mappings":";;;;AAA+B;AAC4E;AACwC;AACnD"}
1
+ {"version":3,"file":"react/index.js","sources":["../../src/react/index.ts"],"sourcesContent":["export * from \"../js/index.ts\";\nexport { MixpanelProvider, useMixpanelClient, type UseMixpanelClientOptions } from \"./MixpanelContext.tsx\";\nexport { MixpanelPropertiesProvider, useMixpanelProviderProperties, type MixpanelPropertiesProviderProps } from \"./MixpanelPropertiesProvider.tsx\";\nexport { useTrackingFunction, type UseTrackingFunctionOptions } from \"./useTrackingFunction.ts\";\n"],"names":["MixpanelProvider","useMixpanelClient","MixpanelPropertiesProvider","useMixpanelProviderProperties","useTrackingFunction"],"mappings":";;;;AAA+B;AAC4E;AACwC;AACnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"react/useTrackingFunction.js","sources":["../../src/react/useTrackingFunction.ts"],"sourcesContent":["import type { CreateMixpanelTrackingFunctionOptions } from \"@workleap-telemetry/core\";\nimport { useMemo } from \"react\";\nimport { useMixpanelClient } from \"./MixpanelContext.tsx\";\nimport { useMixpanelProviderProperties } from \"./MixpanelPropertiesProvider.tsx\";\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport type UseTrackingFunctionOptions = CreateMixpanelTrackingFunctionOptions;\n\n/**\n * Create a Mixpanel tracking function.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function useTrackingFunction(options: UseTrackingFunctionOptions = {}) {\n const {\n productId,\n targetProductId\n } = options;\n\n const client = useMixpanelClient();\n const additionalProperties = useMixpanelProviderProperties();\n\n return useMemo(() => {\n const trackOptions = {\n productId,\n targetProductId,\n additionalProperties\n } satisfies CreateMixpanelTrackingFunctionOptions;\n\n return client.createTrackingFunction(trackOptions);\n }, [client, productId, targetProductId, additionalProperties]);\n}\n"],"names":["useMemo","useMixpanelClient","useMixpanelProviderProperties","useTrackingFunction","options","productId","targetProductId","client","additionalProperties","trackOptions"],"mappings":";;;;;;;AACgC;AAC0B;AACuB;AAOjF;;;CAGC,GACM,SAASG,mBAAmBA,CAACC,UAAsC,CAAC,CAAC;IACxE,MAAM,EACFC,SAAS,EACTC,eAAe,EAClB,GAAGF;IAEJ,MAAMG,SAASN,iBAAiBA;IAChC,MAAMO,uBAAuBN,6BAA6BA;IAE1D,OAAOF,OAAOA,CAAC;QACX,MAAMS,eAAe;YACjBJ;YACAC;YACAE;QACJ;QAEA,OAAOD,OAAO,sBAAsB,CAACE;IACzC,GAAG;QAACF;QAAQF;QAAWC;QAAiBE;KAAqB;AACjE"}
1
+ {"version":3,"file":"react/useTrackingFunction.js","sources":["../../src/react/useTrackingFunction.ts"],"sourcesContent":["import type { CreateMixpanelTrackingFunctionOptions } from \"@workleap-telemetry/core\";\nimport { useMemo } from \"react\";\nimport { useMixpanelClient } from \"./MixpanelContext.tsx\";\nimport { useMixpanelProviderProperties } from \"./MixpanelPropertiesProvider.tsx\";\n\n/**\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport type UseTrackingFunctionOptions = CreateMixpanelTrackingFunctionOptions;\n\n/**\n * Create a Mixpanel tracking function.\n * @see {@link https://workleap.github.io/wl-telemetry}\n */\nexport function useTrackingFunction(options: UseTrackingFunctionOptions = {}) {\n const { productId, targetProductId } = options;\n\n const client = useMixpanelClient();\n const additionalProperties = useMixpanelProviderProperties();\n\n return useMemo(() => {\n const trackOptions = {\n productId,\n targetProductId,\n additionalProperties\n } satisfies CreateMixpanelTrackingFunctionOptions;\n\n return client.createTrackingFunction(trackOptions);\n }, [client, productId, targetProductId, additionalProperties]);\n}\n"],"names":["useMemo","useMixpanelClient","useMixpanelProviderProperties","useTrackingFunction","options","productId","targetProductId","client","additionalProperties","trackOptions"],"mappings":";;;;;;;AACgC;AAC0B;AACuB;AAOjF;;;CAGC,GACM,SAASG,oBAAoBC,UAAsC,CAAC,CAAC;IACxE,MAAM,EAAEC,SAAS,EAAEC,eAAe,EAAE,GAAGF;IAEvC,MAAMG,SAASN,iBAAiBA;IAChC,MAAMO,uBAAuBN,6BAA6BA;IAE1D,OAAOF,OAAOA,CAAC;QACX,MAAMS,eAAe;YACjBJ;YACAC;YACAE;QACJ;QAEA,OAAOD,OAAO,sBAAsB,CAACE;IACzC,GAAG;QAACF;QAAQF;QAAWC;QAAiBE;KAAqB;AACjE"}
package/package.json CHANGED
@@ -1,19 +1,21 @@
1
1
  {
2
2
  "name": "@workleap/mixpanel",
3
- "author": "Workleap",
4
- "version": "6.0.2",
3
+ "version": "6.1.0",
5
4
  "description": "A package containing utilities for Mixpanel telemetry.",
6
5
  "license": "Apache-2.0",
6
+ "author": "Workleap",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/workleap/wl-telemetry.git",
10
10
  "directory": "packages/mixpanel"
11
11
  },
12
+ "files": [
13
+ "src",
14
+ "dist",
15
+ "CHANGELOG.md"
16
+ ],
12
17
  "type": "module",
13
- "publishConfig": {
14
- "access": "public",
15
- "provenance": true
16
- },
18
+ "sideEffects": false,
17
19
  "exports": {
18
20
  ".": {
19
21
  "types": "./dist/js/index.d.ts",
@@ -26,14 +28,28 @@
26
28
  "default": "./dist/react/index.js"
27
29
  }
28
30
  },
29
- "files": [
30
- "src",
31
- "dist",
32
- "CHANGELOG.md"
33
- ],
31
+ "publishConfig": {
32
+ "access": "public",
33
+ "provenance": true
34
+ },
35
+ "dependencies": {
36
+ "@workleap-telemetry/core": "^2.0.7",
37
+ "@workleap/logging": "^2.1.0"
38
+ },
39
+ "devDependencies": {
40
+ "@rsbuild/core": "2.3.1",
41
+ "@rslib/core": "1.0.6",
42
+ "@types/node": "26.6.6",
43
+ "@types/react": "19.3.0",
44
+ "@workleap/rslib-configs": "2.1.1",
45
+ "@workleap/typescript-configs": "5.1.0",
46
+ "happy-dom": "21.0.4",
47
+ "typescript": "7.0.2",
48
+ "vitest": "5.1.0"
49
+ },
34
50
  "peerDependencies": {
35
51
  "@types/react": "^18.0.0 || ^19.0.0",
36
- "@workleap/logrocket": "^4.0.4",
52
+ "@workleap/logrocket": "^4.0.7",
37
53
  "react": "^18.0.0 || ^19.0.0",
38
54
  "react-dom": "^18.0.0 || ^19.0.0"
39
55
  },
@@ -51,32 +67,9 @@
51
67
  "optional": true
52
68
  }
53
69
  },
54
- "dependencies": {
55
- "@workleap-telemetry/core": "^2.0.6",
56
- "@workleap/logging": "^2.0.1"
57
- },
58
- "devDependencies": {
59
- "@eslint/js": "9.39.2",
60
- "@rsbuild/core": "2.2.14",
61
- "@rslib/core": "1.0.3",
62
- "@types/node": "26.6.5",
63
- "@types/react": "19.3.0",
64
- "@typescript-eslint/parser": "8.72.0",
65
- "@typescript/native-preview": "7.0.0-dev.20260707.2",
66
- "@workleap/eslint-configs": "2.0.6",
67
- "@workleap/rslib-configs": "2.0.0",
68
- "@workleap/typescript-configs": "5.0.0",
69
- "eslint": "9.39.2",
70
- "happy-dom": "21.0.4",
71
- "typescript": "6.0.3",
72
- "typescript-eslint": "8.72.0",
73
- "vitest": "5.0.5"
74
- },
75
- "sideEffects": false,
76
70
  "scripts": {
77
71
  "build": "rslib build --config ./rslib.build.ts",
78
- "eslint": "eslint . --max-warnings=0 --cache --cache-location node_modules/.cache/eslint",
79
- "typecheck": "tsgo",
72
+ "typecheck": "tsc",
80
73
  "test": "vitest --config vitest.config.ts --no-watch"
81
74
  }
82
75
  }
@@ -28,40 +28,40 @@ export interface MixpanelClientOptions {
28
28
  * @see {@link https://workleap.github.io/wl-telemetry}
29
29
  */
30
30
  productId?: string;
31
+ /**
32
+ * @see {@link https://workleap.github.io/wl-telemetry}
33
+ */
34
+ privateQueryParameterNames?: string[];
31
35
  }
32
36
 
37
+ const DefaultPrivateQueryParameterNames = ["token", "email", "password"];
38
+
33
39
  export class MixpanelClientImpl implements MixpanelClient {
34
40
  readonly #globalEventProperties = new Map<string, unknown>();
35
41
  readonly #endpoint: string;
36
42
  readonly #logger: Logger;
37
43
  readonly #productId?: string;
44
+ readonly #privateQueryParameterNames: string[];
38
45
 
39
46
  constructor(endpoint: string, logger: Logger, options: MixpanelClientOptions = {}) {
40
- const {
41
- productId
42
- } = options;
47
+ const { productId, privateQueryParameterNames = [] } = options;
43
48
 
44
49
  this.#endpoint = endpoint;
45
50
  this.#logger = logger;
46
51
  this.#productId = productId;
52
+ this.#privateQueryParameterNames = DefaultPrivateQueryParameterNames.concat(privateQueryParameterNames);
47
53
  }
48
54
 
49
55
  // IMPORTANT: If you update this method, make sure to update the MixpanelPartialClient
50
56
  // interface as well in @workleap-telemetry/core.
51
57
  createTrackingFunction(options: CreateMixpanelTrackingFunctionOptions = {}) {
52
- const {
53
- productId,
54
- targetProductId,
55
- additionalProperties = {}
56
- } = options;
58
+ const { productId, targetProductId, additionalProperties = {} } = options;
57
59
 
58
60
  const trackFunction: MixpanelTrackingFunction = async (eventName, properties, _options = {}) => {
59
61
  try {
60
- const {
61
- keepAlive = false
62
- } = _options;
62
+ const { keepAlive = false } = _options;
63
63
 
64
- const baseProperties = getBaseProperties();
64
+ const baseProperties = getBaseProperties(this.#privateQueryParameterNames);
65
65
 
66
66
  const allProperties = {
67
67
  ...baseProperties,
package/src/js/env.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  const EnvironmentList = ["development", "staging", "production", "local", "msw"] as const;
2
2
 
3
- export type MixpanelEnvironment = typeof EnvironmentList[number];
3
+ export type MixpanelEnvironment = (typeof EnvironmentList)[number];
4
4
 
5
5
  const NavigationApiBaseUrl: Record<MixpanelEnvironment, string> = {
6
- "production": "https://api.platform.workleap.com/shell/navigation/",
7
- "staging": "https://api.platform.workleap-stg.com/shell/navigation/",
8
- "development": "https://api.platform.workleap-dev.com/shell/navigation/",
9
- "local": "https://api.platform.workleap-dev.com/shell/navigation/",
10
- "msw": "/api/shell/navigation/"
6
+ production: "https://api.platform.workleap.com/shell/navigation/",
7
+ staging: "https://api.platform.workleap-stg.com/shell/navigation/",
8
+ development: "https://api.platform.workleap-dev.com/shell/navigation/",
9
+ local: "https://api.platform.workleap-dev.com/shell/navigation/",
10
+ msw: "/api/shell/navigation/"
11
11
  };
12
12
 
13
13
  // Cannot use URL() because it doesn't support relative base url: https://github.com/whatwg/url/issues/531.
package/src/js/index.ts CHANGED
@@ -4,4 +4,3 @@ export type { MixpanelEnvironment } from "./env.ts";
4
4
  export { initializeMixpanel, type InitializeMixpanelOptions } from "./initializeMixpanel.ts";
5
5
  export type { MixpanelClient } from "./MixpanelClient.ts";
6
6
  export { NoopMixpanelClient } from "./NoopMixpanelClient.ts";
7
-
@@ -40,6 +40,11 @@ export interface InitializeMixpanelOptions {
40
40
  * @see {@link https://workleap.github.io/wl-telemetry}
41
41
  */
42
42
  trackingEndpoint?: string;
43
+ /**
44
+ * Names of additional query parameters to redact from the URLs sent with every event.
45
+ * @see {@link https://workleap.github.io/wl-telemetry}
46
+ */
47
+ privateQueryParameterNames?: string[];
43
48
  /**
44
49
  * Context including telemetry correlation ids.
45
50
  * @see {@link https://workleap.github.io/wl-telemetry}
@@ -65,14 +70,7 @@ export interface InitializeMixpanelOptions {
65
70
 
66
71
  export class MixpanelInitializer {
67
72
  initialize(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), options: Omit<InitializeMixpanelOptions, "globalEventProperties"> = {}) {
68
- const {
69
- productId,
70
- trackingEndpoint,
71
- telemetryContext,
72
- logRocketInstrumentationClient,
73
- verbose = false,
74
- loggers = []
75
- } = options;
73
+ const { productId, trackingEndpoint, privateQueryParameterNames, telemetryContext, logRocketInstrumentationClient, verbose = false, loggers = [] } = options;
76
74
 
77
75
  const logger = createCompositeLogger(verbose, loggers);
78
76
  const endpoint = getTrackingEndpoint(envOrTrackingApiBaseUrl, trackingEndpoint);
@@ -80,7 +78,8 @@ export class MixpanelInitializer {
80
78
  logger.information("[mixpanel] Mixpanel is initialized.");
81
79
 
82
80
  const client = new MixpanelClientImpl(endpoint, logger, {
83
- productId
81
+ productId,
82
+ privateQueryParameterNames
84
83
  });
85
84
 
86
85
  // Set the telemetry correlation ids on every Mixpanel event.
@@ -94,10 +93,7 @@ export class MixpanelInitializer {
94
93
  // once it's available to set it on every Mixpanel event.
95
94
  if (logRocketInstrumentationClient) {
96
95
  logRocketInstrumentationClient.registerGetSessionUrlListener((sessionUrl: string) => {
97
- logger
98
- .withText("[mixpanel] Received LogRocket session replay URL:")
99
- .withText(sessionUrl)
100
- .debug();
96
+ logger.withText("[mixpanel] Received LogRocket session replay URL:").withText(sessionUrl).debug();
101
97
 
102
98
  client.setGlobalEventProperty(OtherProperties.LogRocketSessionUrl, sessionUrl);
103
99
  });
@@ -115,14 +111,8 @@ export class MixpanelInitializer {
115
111
  * @returns {MixpanelClient} A Mixpanel client instance.
116
112
  * @see {@link https://workleap.github.io/wl-telemetry}
117
113
  */
118
- export function initializeMixpanel(
119
- envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}),
120
- options?: InitializeMixpanelOptions
121
- ) {
122
- getRegistrationGuard().throw("[mixpanel] Mixpanel has already been initialized. Did you call the \"initializeMixpanel\" function twice?");
123
-
124
- return new MixpanelInitializer().initialize(
125
- envOrTrackingApiBaseUrl,
126
- options
127
- );
114
+ export function initializeMixpanel(envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}), options?: InitializeMixpanelOptions) {
115
+ getRegistrationGuard().throw('[mixpanel] Mixpanel has already been initialized. Did you call the "initializeMixpanel" function twice?');
116
+
117
+ return new MixpanelInitializer().initialize(envOrTrackingApiBaseUrl, options);
128
118
  }
@@ -1,6 +1,5 @@
1
-
2
1
  import type { MixpanelEventProperties, TelemetryContext } from "@workleap-telemetry/core";
3
- import { browserName, browserVersion, deviceType, osName, referringDomain } from "./utils.ts";
2
+ import { browserName, browserVersion, deviceType, osName, redactQueryParameters, referringDomain } from "./utils.ts";
4
3
 
5
4
  export const BaseProperties = {
6
5
  Browser: "$browser",
@@ -15,17 +14,18 @@ export const BaseProperties = {
15
14
  ScreenWidth: "$screen_width"
16
15
  } as const;
17
16
 
18
- export function getBaseProperties() {
17
+ export function getBaseProperties(privateQueryParameterNames: string[]) {
19
18
  const userAgent = navigator.userAgent;
20
19
  const device = deviceType(userAgent);
21
20
 
22
21
  return {
23
22
  [BaseProperties.Os]: osName(userAgent),
24
23
  [BaseProperties.Browser]: browserName(userAgent, navigator.vendor),
25
- [BaseProperties.Referrer]: document.referrer,
24
+ [BaseProperties.Referrer]: redactQueryParameters(document.referrer, privateQueryParameterNames),
26
25
  [BaseProperties.ReferringDomain]: referringDomain(document.referrer),
27
26
  [BaseProperties.Device]: device,
28
- [BaseProperties.CurrentUrl]: window.location.href,
27
+ // The fragment is removed because it can include sensitive values, such as an access token.
28
+ [BaseProperties.CurrentUrl]: redactQueryParameters(window.location.href.split("#")[0], privateQueryParameterNames),
29
29
  [BaseProperties.BrowserVersion]: browserVersion(userAgent, navigator.vendor),
30
30
  [BaseProperties.ScreenHeight]: window.screen.height,
31
31
  [BaseProperties.ScreenWidth]: window.screen.width,
package/src/js/utils.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // This code is adapted from https://github.com/mixpanel/mixpanel-js/blob/master/src/utils.js
2
2
  export function browserName(userAgent: string, vendor?: string, opera?: object) {
3
3
  // vendor is undefined for at least IE9
4
- vendor = vendor || ""; // eslint-disable-line no-param-reassign
4
+ vendor = vendor || ""; // oxlint-disable-line eslint/no-param-reassign
5
5
 
6
6
  if (opera || userAgent.includes(" OPR/")) {
7
7
  if (userAgent.includes("Mini")) {
@@ -56,19 +56,19 @@ export function browserVersion(userAgent: string, vendor?: string, opera?: objec
56
56
  const versionRegexs: { [key: string]: RegExp } = {
57
57
  "Internet Explorer Mobile": /rv:(\d+(\.\d+)?)/,
58
58
  "Microsoft Edge": /Edge\/(\d+(\.\d+)?)/,
59
- "Chrome": /Chrome\/(\d+(\.\d+)?)/,
59
+ Chrome: /Chrome\/(\d+(\.\d+)?)/,
60
60
  "Chrome iOS": /CriOS\/(\d+(\.\d+)?)/,
61
61
  "UC Browser": /(UCBrowser|UCWEB)\/(\d+(\.\d+)?)/,
62
- "Safari": /Version\/(\d+(\.\d+)?)/,
62
+ Safari: /Version\/(\d+(\.\d+)?)/,
63
63
  "Mobile Safari": /Version\/(\d+(\.\d+)?)/,
64
- "Opera": /(Opera|OPR)\/(\d+(\.\d+)?)/,
65
- "Firefox": /Firefox\/(\d+(\.\d+)?)/,
64
+ Opera: /(Opera|OPR)\/(\d+(\.\d+)?)/,
65
+ Firefox: /Firefox\/(\d+(\.\d+)?)/,
66
66
  "Firefox iOS": /FxiOS\/(\d+(\.\d+)?)/,
67
- "Konqueror": /Konqueror:(\d+(\.\d+)?)/,
68
- "BlackBerry": /BlackBerry (\d+(\.\d+)?)/,
67
+ Konqueror: /Konqueror:(\d+(\.\d+)?)/,
68
+ BlackBerry: /BlackBerry (\d+(\.\d+)?)/,
69
69
  "Android Mobile": /android\s(\d+(\.\d+)?)/,
70
70
  "Internet Explorer": /(rv:|MSIE )(\d+(\.\d+)?)/,
71
- "Mozilla": /rv:(\d+(\.\d+)?)/
71
+ Mozilla: /rv:(\d+(\.\d+)?)/
72
72
  };
73
73
  const regex = versionRegexs[browser];
74
74
  if (regex === undefined) {
@@ -85,7 +85,6 @@ export function browserVersion(userAgent: string, vendor?: string, opera?: objec
85
85
  export function osName(userAgent: string) {
86
86
  const a = userAgent;
87
87
  if (/Windows/i.test(a)) {
88
- // eslint-disable-next-line @typescript-eslint/prefer-includes
89
88
  if (/Phone/.test(a) || /WPDesktop/.test(a)) {
90
89
  return "Windows Phone";
91
90
  }
@@ -93,17 +92,14 @@ export function osName(userAgent: string) {
93
92
  return "Windows";
94
93
  } else if (/(iPhone|iPad|iPod)/.test(a)) {
95
94
  return "iOS";
96
- // eslint-disable-next-line @typescript-eslint/prefer-includes
97
95
  } else if (/Android/.test(a)) {
98
96
  return "Android";
99
97
  } else if (/(BlackBerry|PlayBook|BB10)/i.test(a)) {
100
98
  return "BlackBerry";
101
99
  } else if (/Mac/i.test(a)) {
102
100
  return "Mac OS X";
103
- // eslint-disable-next-line @typescript-eslint/prefer-includes
104
101
  } else if (/Linux/.test(a)) {
105
102
  return "Linux";
106
- // eslint-disable-next-line @typescript-eslint/prefer-includes
107
103
  } else if (/CrOS/.test(a)) {
108
104
  return "Chrome OS";
109
105
  }
@@ -112,21 +108,16 @@ export function osName(userAgent: string) {
112
108
  }
113
109
 
114
110
  export function deviceType(userAgent: string) {
115
- // eslint-disable-next-line @typescript-eslint/prefer-includes
116
111
  if (/Windows Phone/i.test(userAgent) || /WPDesktop/.test(userAgent)) {
117
112
  return "Windows Phone";
118
- // eslint-disable-next-line @typescript-eslint/prefer-includes
119
113
  } else if (/iPad/.test(userAgent)) {
120
114
  return "iPad";
121
- // eslint-disable-next-line @typescript-eslint/prefer-includes
122
115
  } else if (/iPod/.test(userAgent)) {
123
116
  return "iPod Touch";
124
- // eslint-disable-next-line @typescript-eslint/prefer-includes
125
117
  } else if (/iPhone/.test(userAgent)) {
126
118
  return "iPhone";
127
119
  } else if (/(BlackBerry|PlayBook|BB10)/i.test(userAgent)) {
128
120
  return "BlackBerry";
129
- // eslint-disable-next-line @typescript-eslint/prefer-includes
130
121
  } else if (/Android/.test(userAgent)) {
131
122
  return "Android";
132
123
  }
@@ -142,3 +133,16 @@ export function referringDomain(referrer: string) {
142
133
 
143
134
  return "";
144
135
  }
136
+
137
+ export function redactQueryParameters(url: string, queryParameterNames: string[]) {
138
+ let redactedUrl = url;
139
+
140
+ for (const x of queryParameterNames) {
141
+ // A name can include regular expression special characters, and can be percent-encoded in the URL, such as "user[email]" and "user%5Bemail%5D".
142
+ const escapedNames = [x, encodeURIComponent(x)].map(y => y.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
143
+
144
+ redactedUrl = redactedUrl.replace(new RegExp(`(?:${escapedNames.join("|")})=([^&]*)`, "gi"), () => `${x}=**redacted**`);
145
+ }
146
+
147
+ return redactedUrl;
148
+ }
@@ -14,16 +14,9 @@ export interface MixpanelProviderProps extends PropsWithChildren {
14
14
  * @see {@link https://workleap.github.io/wl-telemetry}
15
15
  */
16
16
  export function MixpanelProvider(props: MixpanelProviderProps) {
17
- const {
18
- client,
19
- children
20
- } = props;
21
-
22
- return (
23
- <MixpanelContext.Provider value={client}>
24
- {children}
25
- </MixpanelContext.Provider>
26
- );
17
+ const { client, children } = props;
18
+
19
+ return <MixpanelContext.Provider value={client}>{children}</MixpanelContext.Provider>;
27
20
  }
28
21
 
29
22
  export interface UseMixpanelClientOptions {
@@ -41,9 +34,7 @@ export function useMixpanelClient(options: { throwOnUndefined: false }): Mixpane
41
34
  * @see {@link https://workleap.github.io/wl-telemetry}
42
35
  */
43
36
  export function useMixpanelClient(options: UseMixpanelClientOptions = {}) {
44
- const {
45
- throwOnUndefined = true
46
- } = options;
37
+ const { throwOnUndefined = true } = options;
47
38
 
48
39
  const client = useContext(MixpanelContext);
49
40
 
@@ -14,23 +14,19 @@ export interface MixpanelPropertiesProviderProps extends PropsWithChildren {
14
14
  * @see {@link https://workleap.github.io/wl-telemetry}
15
15
  */
16
16
  export function MixpanelPropertiesProvider(props: MixpanelPropertiesProviderProps) {
17
- const {
18
- value,
19
- children
20
- } = props;
17
+ const { value, children } = props;
21
18
 
22
19
  const parentContext = useContext(MixpanelPropertiesContext);
23
20
 
24
- const contextValue = useMemo(() => ({
25
- ...parentContext,
26
- ...value
27
- }), [parentContext, value]);
28
-
29
- return (
30
- <MixpanelPropertiesContext.Provider value={contextValue}>
31
- {children}
32
- </MixpanelPropertiesContext.Provider>
21
+ const contextValue = useMemo(
22
+ () => ({
23
+ ...parentContext,
24
+ ...value
25
+ }),
26
+ [parentContext, value]
33
27
  );
28
+
29
+ return <MixpanelPropertiesContext.Provider value={contextValue}>{children}</MixpanelPropertiesContext.Provider>;
34
30
  }
35
31
 
36
32
  /**
@@ -2,4 +2,3 @@ export * from "../js/index.ts";
2
2
  export { MixpanelProvider, useMixpanelClient, type UseMixpanelClientOptions } from "./MixpanelContext.tsx";
3
3
  export { MixpanelPropertiesProvider, useMixpanelProviderProperties, type MixpanelPropertiesProviderProps } from "./MixpanelPropertiesProvider.tsx";
4
4
  export { useTrackingFunction, type UseTrackingFunctionOptions } from "./useTrackingFunction.ts";
5
-
@@ -13,10 +13,7 @@ export type UseTrackingFunctionOptions = CreateMixpanelTrackingFunctionOptions;
13
13
  * @see {@link https://workleap.github.io/wl-telemetry}
14
14
  */
15
15
  export function useTrackingFunction(options: UseTrackingFunctionOptions = {}) {
16
- const {
17
- productId,
18
- targetProductId
19
- } = options;
16
+ const { productId, targetProductId } = options;
20
17
 
21
18
  const client = useMixpanelClient();
22
19
  const additionalProperties = useMixpanelProviderProperties();