@workleap/mixpanel 2.1.9 → 3.0.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/js/MixpanelClient.d.ts +22 -0
  3. package/dist/js/MixpanelClient.js +71 -0
  4. package/dist/js/MixpanelClient.js.map +1 -0
  5. package/dist/js/context.d.ts +2 -2
  6. package/dist/js/context.js +3 -0
  7. package/dist/js/context.js.map +1 -1
  8. package/dist/js/createTrackingFunction.d.ts +4 -4
  9. package/dist/js/createTrackingFunction.js +5 -2
  10. package/dist/js/createTrackingFunction.js.map +1 -1
  11. package/dist/js/env.d.ts +2 -2
  12. package/dist/js/env.js.map +1 -1
  13. package/dist/js/index.d.ts +5 -3
  14. package/dist/js/index.js +7 -3
  15. package/dist/js/index.js.map +1 -1
  16. package/dist/js/initializeMixpanel.d.ts +28 -7
  17. package/dist/js/initializeMixpanel.js +67 -56
  18. package/dist/js/initializeMixpanel.js.map +1 -1
  19. package/dist/js/properties.d.ts +1 -6
  20. package/dist/js/properties.js +1 -19
  21. package/dist/js/properties.js.map +1 -1
  22. package/dist/react/MixpanelContext.d.ts +18 -0
  23. package/dist/react/MixpanelContext.js +34 -0
  24. package/dist/react/MixpanelContext.js.map +1 -0
  25. package/dist/react/index.d.ts +2 -0
  26. package/dist/react/index.js +7 -1
  27. package/dist/react/index.js.map +1 -1
  28. package/dist/react/useTrackingFunction.d.ts +10 -3
  29. package/dist/react/useTrackingFunction.js +17 -4
  30. package/dist/react/useTrackingFunction.js.map +1 -1
  31. package/package.json +15 -16
  32. package/src/js/MixpanelClient.ts +85 -0
  33. package/src/js/context.ts +6 -2
  34. package/src/js/createTrackingFunction.ts +11 -7
  35. package/src/js/env.ts +5 -6
  36. package/src/js/index.ts +5 -3
  37. package/src/js/initializeMixpanel.ts +123 -73
  38. package/src/js/properties.ts +1 -28
  39. package/src/react/MixpanelContext.tsx +41 -0
  40. package/src/react/index.ts +2 -0
  41. package/src/react/useTrackingFunction.ts +24 -5
  42. package/dist/internal.d.ts +0 -2
  43. package/dist/internal.js +0 -14
  44. package/dist/internal.js.map +0 -1
  45. package/dist/js/HasExecutedGuard.d.ts +0 -6
  46. package/dist/js/HasExecutedGuard.js +0 -21
  47. package/dist/js/HasExecutedGuard.js.map +0 -1
  48. package/src/internal.ts +0 -3
  49. package/src/js/HasExecutedGuard.ts +0 -19
@@ -1,12 +1,54 @@
1
+ import { HasExecutedGuard, type LogRocketInstrumentationPartialClient, type TelemetryContext } from "@workleap-telemetry/core";
1
2
  import { createCompositeLogger, type Logger, type RootLogger } from "@workleap/logging";
2
- import { createBootstrappingStore, createTelemetryContext } from "@workleap/telemetry";
3
3
  import { setMixpanelContext } from "./context.ts";
4
- import { getTrackingEndpoint, type Environment } from "./env.ts";
5
- import { HasExecutedGuard } from "./HasExecutedGuard.ts";
6
- import { getSuperProperties, getTelemetryProperties, OtherProperties, setSuperProperties, setSuperProperty } from "./properties.ts";
4
+ import { getTrackingEndpoint, type MixpanelEnvironment } from "./env.ts";
5
+ import { MixpanelClient, type MixpanelGlobalEventProperties } from "./MixpanelClient.ts";
6
+ import { getTelemetryProperties, OtherProperties } from "./properties.ts";
7
7
 
8
+ // DEPRECATED: Grace period ends on January 1th 2026.
9
+ // Don't forget to remove the tests as well.
8
10
  export const IsInitializedVariableName = "__WLP_MIXPANEL_IS_INITIALIZED__";
9
11
 
12
+ // DEPRECATED: Grace period ends on January 1th 2026.
13
+ function registerDeprecatedContextAndGlobalVariables(productId: string, endpoint: string, globalEventProperties: Map<string, unknown>, logger: Logger) {
14
+ setMixpanelContext({
15
+ productId,
16
+ endpoint,
17
+ globalEventProperties,
18
+ logger
19
+ });
20
+
21
+ // Indicates to the host applications that Mixpanel has been initialized.
22
+ // It's useful in cases where an "add-on", like the platform widgets needs
23
+ // to know whether or not the host application is using Mixpanel.
24
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
25
+ // @ts-ignore
26
+ globalThis[IsInitializedVariableName] = true;
27
+ }
28
+
29
+ ///////////////////////////
30
+
31
+ let registrationGuardInstance: HasExecutedGuard | undefined;
32
+
33
+ // It's important to use a lazy singleton instead of a singleton to avoid
34
+ // any future probleme related to HMR, tree-shaking, SSR, etc..
35
+ function getRegistrationGuard() {
36
+ if (!registrationGuardInstance) {
37
+ registrationGuardInstance = new HasExecutedGuard();
38
+ }
39
+
40
+ return registrationGuardInstance;
41
+ }
42
+
43
+ // This function should only be used by tests.
44
+ export function __resetRegistrationGuard() {
45
+ if (registrationGuardInstance) {
46
+ registrationGuardInstance.reset();
47
+ }
48
+ }
49
+
50
+ ///////////////////////////
51
+
10
52
  /**
11
53
  * @see {@link https://workleap.github.io/wl-telemetry}
12
54
  */
@@ -14,96 +56,104 @@ export interface InitializeMixpanelOptions {
14
56
  /**
15
57
  * An optional tracking endpoint.
16
58
  * @default "tracking/track"
59
+ * @see {@link https://workleap.github.io/wl-telemetry}
17
60
  */
18
61
  trackingEndpoint?: string;
62
+ /**
63
+ * Context including telemetry correlation ids.
64
+ * @see {@link https://workleap.github.io/wl-telemetry}
65
+ */
66
+ telemetryContext?: TelemetryContext;
67
+ /**
68
+ * An optional LogRocket client to automatically add the LogRocket
69
+ * session URL to Mixpanel events once it's available.
70
+ * @see {@link https://workleap.github.io/wl-telemetry}
71
+ */
72
+ logRocketInstrumentationClient?: LogRocketInstrumentationPartialClient;
19
73
  /**
20
74
  * Whether or not debug information should be logged to the console.
75
+ * @see {@link https://workleap.github.io/wl-telemetry}
21
76
  */
22
77
  verbose?: boolean;
23
78
  /**
24
79
  * An array of RootLogger instances.
80
+ * @see {@link https://workleap.github.io/wl-telemetry}
25
81
  */
26
82
  loggers?: RootLogger[];
27
83
  }
28
84
 
29
- function registerLogRocketSessionUrlListener(logger: Logger) {
30
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
31
- // @ts-ignore
32
- if (globalThis.__WLP_LOGROCKET_INSTRUMENTATION_REGISTER_GET_SESSION_URL_LISTENER__) {
33
- // Automatically add the LogRocket session URL to all Honeycomb traces as an attribute.
34
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
35
- // @ts-ignore
36
- globalThis.__WLP_LOGROCKET_INSTRUMENTATION_REGISTER_GET_SESSION_URL_LISTENER__((sessionUrl: string) => {
37
- logger
38
- .withText("[mixpanel] Received LogRocket session replay URL:")
39
- .withText(sessionUrl)
40
- .debug();
41
-
42
- setSuperProperty(OtherProperties.LogRocketSessionUrl, sessionUrl);
43
- });
44
- } else {
45
- logger.information("[mixpanel] Cannot integrate with LogRocket because \"globalThis.__WLP_LOGROCKET_INSTRUMENTATION_REGISTER_GET_SESSION_URL_LISTENER__\" is not available.");
85
+
86
+ export class MixpanelInitializer {
87
+ readonly #globalEventProperties: MixpanelGlobalEventProperties;
88
+
89
+ constructor(globalEventProperties: MixpanelGlobalEventProperties) {
90
+ this.#globalEventProperties = globalEventProperties;
46
91
  }
47
- }
48
92
 
49
- const initializationGuard = new HasExecutedGuard();
93
+ initialize(
94
+ productId: string,
95
+ envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}),
96
+ options: InitializeMixpanelOptions = {}
97
+ ) {
98
+ const {
99
+ trackingEndpoint,
100
+ telemetryContext,
101
+ logRocketInstrumentationClient,
102
+ verbose = false,
103
+ loggers = []
104
+ } = options;
50
105
 
51
- // This function should only be used by tests.
52
- export function __resetInitializationGuard() {
53
- initializationGuard.reset();
106
+ const logger = createCompositeLogger(verbose, loggers);
107
+ const endpoint = getTrackingEndpoint(envOrTrackingApiBaseUrl, trackingEndpoint);
108
+
109
+ // Set the telemetry correlation ids on every Mixpanel event.
110
+ if (telemetryContext) {
111
+ for (const [key, value] of Object.entries(getTelemetryProperties(telemetryContext))) {
112
+ this.#globalEventProperties.set(key, value);
113
+ }
114
+ }
115
+
116
+ // If a LogRocket client is already available, register a listener to get the LogRocket session url
117
+ // once it's available to set it on every Mixpanel event.
118
+ if (logRocketInstrumentationClient) {
119
+ logRocketInstrumentationClient.registerGetSessionUrlListener((sessionUrl: string) => {
120
+ logger
121
+ .withText("[mixpanel] Received LogRocket session replay URL:")
122
+ .withText(sessionUrl)
123
+ .debug();
124
+
125
+ this.#globalEventProperties.set(OtherProperties.LogRocketSessionUrl, sessionUrl);
126
+ });
127
+ }
128
+
129
+ registerDeprecatedContextAndGlobalVariables(productId, endpoint, this.#globalEventProperties, logger);
130
+
131
+ logger.information("[mixpanel] Mixpanel is initialized.");
132
+
133
+ return new MixpanelClient(productId, endpoint, this.#globalEventProperties, logger);
134
+ }
54
135
  }
55
136
 
56
137
  /**
57
- * Creates a function that sends tracking events to the tracking API.
58
- * @param productId Your product identifier.
138
+ * Initialize Mixpanel telemetry.
139
+ * @param productId The Mixpanel product identifier.
59
140
  * @param envOrTrackingApiBaseUrl The environment to get the navigation url from or a base URL.
60
- * @param options Options for creating the tracking function.
61
- * @returns A function that sends tracking events to the tracking API.
141
+ * @param options Mixpanel instrumentation options.
142
+ * @returns {MixpanelClient} A Mixpanel client instance.
62
143
  * @see {@link https://workleap.github.io/wl-telemetry}
63
144
  */
64
- export function initializeMixpanel(productId: string, envOrTrackingApiBaseUrl: Environment | (string & {}), options: InitializeMixpanelOptions = {}) {
65
- const {
66
- trackingEndpoint,
67
- verbose = false,
68
- loggers = []
69
- } = options;
70
-
71
- initializationGuard.throw("[mixpanel] Mixpanel has already been initialized. Did you call the \"initializeMixpanel\" function twice?");
72
-
73
- const logger = createCompositeLogger(verbose, loggers);
74
- const endpoint = getTrackingEndpoint(envOrTrackingApiBaseUrl, trackingEndpoint);
75
- const telemetryContext = createTelemetryContext(logger);
76
-
77
- setSuperProperties(getTelemetryProperties(telemetryContext));
78
-
79
- const bootstrappingStore = createBootstrappingStore(logger);
80
-
81
- // If LogRocket is already available, register the listener. Otherwise, subscribe to the bootstrapping store
82
- // and register the listener once a notification is received that LogRocket is registered.
83
- if (bootstrappingStore.state.isLogRocketReady) {
84
- registerLogRocketSessionUrlListener(logger);
85
- } else {
86
- bootstrappingStore.subscribe((action, store, unsubscribe) => {
87
- if (store.state.isLogRocketReady) {
88
- unsubscribe();
89
- registerLogRocketSessionUrlListener(logger);
90
- }
91
- });
92
- }
145
+ export function initializeMixpanel(
146
+ productId: string,
147
+ envOrTrackingApiBaseUrl: MixpanelEnvironment | (string & {}),
148
+ options?: InitializeMixpanelOptions
149
+ ) {
150
+ getRegistrationGuard().throw("[mixpanel] Mixpanel has already been initialized. Did you call the \"initializeMixpanel\" function twice?");
93
151
 
94
- setMixpanelContext({
152
+ return new MixpanelInitializer(
153
+ new Map<string, unknown>()
154
+ ).initialize(
95
155
  productId,
96
- endpoint,
97
- superProperties: getSuperProperties(),
98
- logger
99
- });
100
-
101
- // Indicates to the host applications that Mixpanel has been initialized.
102
- // It's useful in cases where an "add-on", like the platform widgets needs
103
- // to know whether or not the host application is using Mixpanel.
104
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
105
- // @ts-ignore
106
- globalThis[IsInitializedVariableName] = true;
107
-
108
- logger.information("[mixpanel] Mixpanel is initialized.");
156
+ envOrTrackingApiBaseUrl,
157
+ options
158
+ );
109
159
  }
@@ -1,5 +1,5 @@
1
1
 
2
- import type { TelemetryContext } from "@workleap/telemetry";
2
+ import type { TelemetryContext } from "@workleap-telemetry/core";
3
3
  import { browserName, browserVersion, deviceType, osName, referringDomain } from "./utils.ts";
4
4
 
5
5
  export type MixpanelEventProperties = Record<string, unknown>;
@@ -50,30 +50,3 @@ export function getTelemetryProperties(context: TelemetryContext) {
50
50
  export const OtherProperties = {
51
51
  LogRocketSessionUrl: "LogRocket Session Url"
52
52
  };
53
-
54
- //////////////////////
55
-
56
- export type SuperProperties = Map<string, unknown>;
57
-
58
- // Equivalent to: https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#setting-super-properties.
59
- const superProperties: SuperProperties = new Map<string, unknown>();
60
-
61
- export function setSuperProperty(key: string, value: unknown) {
62
- superProperties.set(key, value);
63
- }
64
-
65
- export function setSuperProperties(values: Record<string, unknown>) {
66
- Object.keys(values).forEach(x => {
67
- superProperties.set(x, values[x]);
68
- });
69
- }
70
-
71
- // Must always return the actual reference to the super properties, not a copy
72
- // because it will breaks the global context.
73
- export function getSuperProperties() {
74
- return superProperties;
75
- }
76
-
77
- export function __clearSuperProperties() {
78
- superProperties.clear();
79
- }
@@ -0,0 +1,41 @@
1
+ import { createContext, type PropsWithChildren, useContext } from "react";
2
+ import type { MixpanelClient } from "../js/MixpanelClient.ts";
3
+
4
+ export const MixpanelContext = createContext<MixpanelClient | undefined>(undefined);
5
+
6
+ /**
7
+ * @see {@link https://workleap.github.io/wl-telemetry}
8
+ */
9
+ export interface MixpanelProviderProps extends PropsWithChildren {
10
+ client: MixpanelClient;
11
+ }
12
+
13
+ /**
14
+ * @see {@link https://workleap.github.io/wl-telemetry}
15
+ */
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
+ );
27
+ }
28
+
29
+ /**
30
+ * Retrieve the Mixpanel client.
31
+ * @see {@link https://workleap.github.io/wl-telemetry}
32
+ */
33
+ export function useMixpanelClient() {
34
+ const client = useContext(MixpanelContext);
35
+
36
+ if (!client) {
37
+ throw new Error("[mixpanel] The useMixpanelClient function is called before a MixpanelClient instance has been provided.");
38
+ }
39
+
40
+ return client;
41
+ }
@@ -1,2 +1,4 @@
1
+ export * from "../js/index.ts";
2
+ export { MixpanelProvider, useMixpanelClient } from "./MixpanelContext.tsx";
1
3
  export { useTrackingFunction, type UseTrackingFunctionOptions } from "./useTrackingFunction.ts";
2
4
 
@@ -1,14 +1,33 @@
1
- import { useMemo } from "react";
2
- import { createTrackingFunction, type CreateTrackingFunctionOptions } from "../js/createTrackingFunction.ts";
1
+ import { useContext, useMemo } from "react";
2
+ import { createTrackingFunction, type CreateMixpanelTrackingFunctionOptions } from "../js/createTrackingFunction.ts";
3
+ import { MixpanelContext } from "./MixpanelContext.tsx";
3
4
 
4
- export type UseTrackingFunctionOptions = CreateTrackingFunctionOptions;
5
+ /**
6
+ * @see {@link https://workleap.github.io/wl-telemetry}
7
+ */
8
+ export type UseTrackingFunctionOptions = CreateMixpanelTrackingFunctionOptions;
5
9
 
10
+ /**
11
+ * Create a Mixpanel tracking function.
12
+ * @see {@link https://workleap.github.io/wl-telemetry}
13
+ */
6
14
  export function useTrackingFunction(options: UseTrackingFunctionOptions = {}) {
7
15
  const {
8
16
  targetProductId
9
17
  } = options;
10
18
 
19
+ const client = useContext(MixpanelContext);
20
+
11
21
  return useMemo(() => {
12
- return createTrackingFunction({ targetProductId });
13
- }, [targetProductId]);
22
+ const trackOptions = {
23
+ targetProductId
24
+ } satisfies CreateMixpanelTrackingFunctionOptions;
25
+
26
+ // DEPRECATED: Grace period ends on January 1th 2026.
27
+ // After the grace period, only create the tracking function from the client, remove the fallback
28
+ // and also use "useMixpanelClient" to retrieve the client rather than "useContext".
29
+ return client
30
+ ? client.createTrackingFunction(trackOptions)
31
+ : createTrackingFunction(trackOptions);
32
+ }, [client, targetProductId]);
14
33
  }
@@ -1,2 +0,0 @@
1
- export { __resetInitializationGuard } from "./js/initializeMixpanel.ts";
2
- export { __clearSuperProperties } from "./js/properties.ts";
package/dist/internal.js DELETED
@@ -1,14 +0,0 @@
1
- import { __resetInitializationGuard } from "./js/initializeMixpanel.js";
2
- import { __clearSuperProperties } from "./js/properties.js";
3
-
4
- ;// CONCATENATED MODULE: external "./js/initializeMixpanel.js"
5
-
6
- ;// CONCATENATED MODULE: external "./js/properties.js"
7
-
8
- ;// CONCATENATED MODULE: ./src/internal.ts
9
-
10
-
11
-
12
- export { __clearSuperProperties, __resetInitializationGuard };
13
-
14
- //# sourceMappingURL=internal.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"internal.js","sources":["webpack://@workleap/mixpanel/./src/internal.ts"],"sourcesContent":["export { __resetInitializationGuard } from \"./js/initializeMixpanel.ts\";\nexport { __clearSuperProperties } from \"./js/properties.ts\";\n\n"],"names":["__resetInitializationGuard","__clearSuperProperties"],"mappings":";;;;;;;;AAAwE;AACZ"}
@@ -1,6 +0,0 @@
1
- export declare class HasExecutedGuard {
2
- #private;
3
- throw(message: string): void;
4
- get hasExecuted(): boolean;
5
- reset(): void;
6
- }
@@ -1,21 +0,0 @@
1
-
2
- ;// CONCATENATED MODULE: ./src/js/HasExecutedGuard.ts
3
- class HasExecutedGuard {
4
- #hasExecuted = false;
5
- throw(message) {
6
- if (this.#hasExecuted) {
7
- throw new Error(message);
8
- }
9
- this.#hasExecuted = true;
10
- }
11
- get hasExecuted() {
12
- return this.#hasExecuted;
13
- }
14
- reset() {
15
- this.#hasExecuted = false;
16
- }
17
- }
18
-
19
- export { HasExecutedGuard };
20
-
21
- //# sourceMappingURL=HasExecutedGuard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"js/HasExecutedGuard.js","sources":["webpack://@workleap/mixpanel/./src/js/HasExecutedGuard.ts"],"sourcesContent":["export class HasExecutedGuard {\n #hasExecuted: boolean = false;\n\n throw(message: string) {\n if (this.#hasExecuted) {\n throw new Error(message);\n }\n\n this.#hasExecuted = true;\n }\n\n get hasExecuted() {\n return this.#hasExecuted;\n }\n\n reset() {\n this.#hasExecuted = false;\n }\n}\n"],"names":["HasExecutedGuard","message","Error"],"mappings":";;AAAO,MAAMA;IACT,YAAY,GAAY,MAAM;IAE9B,MAAMC,OAAe,EAAE;QACnB,IAAI,IAAI,CAAC,YAAY,EAAE;YACnB,MAAM,IAAIC,MAAMD;QACpB;QAEA,IAAI,CAAC,YAAY,GAAG;IACxB;IAEA,IAAI,cAAc;QACd,OAAO,IAAI,CAAC,YAAY;IAC5B;IAEA,QAAQ;QACJ,IAAI,CAAC,YAAY,GAAG;IACxB;AACJ"}
package/src/internal.ts DELETED
@@ -1,3 +0,0 @@
1
- export { __resetInitializationGuard } from "./js/initializeMixpanel.ts";
2
- export { __clearSuperProperties } from "./js/properties.ts";
3
-
@@ -1,19 +0,0 @@
1
- export class HasExecutedGuard {
2
- #hasExecuted: boolean = false;
3
-
4
- throw(message: string) {
5
- if (this.#hasExecuted) {
6
- throw new Error(message);
7
- }
8
-
9
- this.#hasExecuted = true;
10
- }
11
-
12
- get hasExecuted() {
13
- return this.#hasExecuted;
14
- }
15
-
16
- reset() {
17
- this.#hasExecuted = false;
18
- }
19
- }