@reservamos/browser-analytics 1.0.7 → 1.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reservamos/browser-analytics",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/reservamos/reservamos-browser-analytics.git"
@@ -88,6 +88,6 @@
88
88
  "upgradeps": "^2.0.6",
89
89
  "vite": "^5.0.12",
90
90
  "vitest": "^1.2.1",
91
- "@reservamos/js-api-client": "5.26.0"
91
+ "@reservamos/js-api-client": "6.0.0-alpha.2"
92
92
  }
93
93
  }
@@ -18,7 +18,7 @@ function trackCustomEvent(
18
18
  trackEvent(eventName, eventData, meta);
19
19
  } catch (error) {
20
20
  console.error('Error trackCustomEvent:', error);
21
- trackEventError(eventName, error);
21
+ trackEventError(eventName, error, eventData);
22
22
  }
23
23
  }
24
24
 
@@ -1,5 +1,5 @@
1
- import { getApiConfig } from '@/init';
2
1
  import createAnonymousProfile from '@/profiles/createAnonymousProfile';
2
+ import configService from '@/services/config';
3
3
  import geolocationService from '@/services/geolocation';
4
4
  import validatorService from '@/services/validator';
5
5
  import { trackEventError, tryTrackEvent } from '@/track';
@@ -53,7 +53,6 @@ const identifyWithLocation = async (
53
53
  properties: UserProperties,
54
54
  ) => {
55
55
  try {
56
- const apiConfig = getApiConfig();
57
56
  const coordinates = geolocationService.getCoordinates();
58
57
 
59
58
  if (!coordinates) {
@@ -69,12 +68,13 @@ const identifyWithLocation = async (
69
68
  delete properties.firstName;
70
69
  delete properties.lastName;
71
70
 
72
- fetch(`${apiConfig?.coreUrl}/${apiConfig?.coreVersion}/datalake/identify`, {
71
+ const coreApiConfig = configService.getCoreAPIConfig();
72
+ fetch(`${coreApiConfig.baseUrl}/v1/datalake/identify`, {
73
73
  method: 'POST',
74
74
  headers: {
75
75
  'Content-Type': 'application/json',
76
- 'Authorization': apiConfig?.coreApiKey || '',
77
- ...(apiConfig?.headers || {}),
76
+ 'Authorization': coreApiConfig.defaultHeaders?.Authorization || '',
77
+ 'Origin': coreApiConfig.defaultHeaders?.Origin || '',
78
78
  },
79
79
  body: JSON.stringify({
80
80
  profile_params: {
@@ -99,8 +99,8 @@ async function identify(
99
99
  userId: string,
100
100
  properties: UserProperties = {},
101
101
  ): Promise<void> {
102
- try {
103
- tryTrackEvent('Identify', async () => {
102
+ tryTrackEvent(async () => {
103
+ try {
104
104
  validatorService.parseIdentifyProps(properties);
105
105
 
106
106
  if (!userId) {
@@ -118,13 +118,13 @@ async function identify(
118
118
  if (fingerprint) {
119
119
  mixpanelService.attachProperty(FINGERPRINT_PROPERTY, fingerprint);
120
120
  }
121
- });
122
- } catch (error) {
123
- console.error('Error identifying user', error);
124
- trackEventError('Identify', error);
125
- } finally {
126
- identifyWithLocation(userId, properties);
127
- }
121
+ } catch (error) {
122
+ console.error('Error identifying user', error);
123
+ trackEventError('Identify', error, { userId, properties });
124
+ } finally {
125
+ identifyWithLocation(userId, properties);
126
+ }
127
+ });
128
128
  }
129
129
 
130
130
  export default identify;
package/src/index.ts CHANGED
@@ -26,7 +26,6 @@ import init, { isTrackerReady } from '@/init';
26
26
  import createAnonymousProfile from '@/profiles/createAnonymousProfile';
27
27
  import fingerprintService from '@/services/fingerprint';
28
28
  import mixpanelService from '@/services/mixpanel';
29
- import './js-api-client.d.ts';
30
29
  import trackPurchaseCanceled from './events/purchaseCanceled/trackPurchaseCanceled.js';
31
30
 
32
31
  const analytics = {
package/src/init.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { setConfig as setApiConfig } from '@reservamos/js-api-client';
1
+ import coreApi from '@reservamos/js-api-client/core';
2
2
  import { z } from 'zod';
3
3
  import configService from '@/services/config';
4
4
  import fingerprintService from '@/services/fingerprint';
@@ -21,15 +21,6 @@ function onLoaded() {
21
21
  window.dispatchEvent(new CustomEvent('Tracker Ready'));
22
22
  }
23
23
 
24
- interface ApiConfig {
25
- coreUrl: string;
26
- coreVersion: string;
27
- headers: { Origin: string };
28
- coreApiKey: string;
29
- }
30
-
31
- let apiConfig: ApiConfig | null = null;
32
-
33
24
  /**
34
25
  * Initializes the tracking library with the provided configuration.
35
26
  * @param {InitConfig} config - The configuration object for initialization.
@@ -60,10 +51,8 @@ async function init(config: InitConfig) {
60
51
  console.error('Error initializing identification service:', error);
61
52
  }
62
53
 
63
- const environment = isSandbox ? 'sandbox' : 'prod';
64
- apiConfig = configService.coreAPIConfig[environment];
65
-
66
- setApiConfig(apiConfig);
54
+ configService.setEnvironment(isSandbox ? 'sandbox' : 'prod');
55
+ coreApi.setConfig(configService.getCoreAPIConfig());
67
56
 
68
57
  // Dispatch the 'Tracker Ready' event
69
58
  onLoaded();
@@ -79,12 +68,5 @@ function isTrackerReady(): boolean {
79
68
  return mixpanelService.isReady();
80
69
  }
81
70
 
82
- /**
83
- * Returns the current API configuration.
84
- * @returns {ApiConfig | null} The current API configuration or null if not initialized.
85
- */
86
- function getApiConfig(): ApiConfig | null {
87
- return apiConfig;
88
- }
89
- export { isTrackerReady, getApiConfig };
71
+ export { isTrackerReady };
90
72
  export default init;
@@ -1,31 +1,20 @@
1
+ import type {
2
+ AnonymousIdentifier,
3
+ AnonymousProfile,
4
+ CreateAnonymousProfilePayload,
5
+ IdentifierKey,
6
+ } from '@reservamos/js-api-client/core';
1
7
  import type { CreateAnonymousProfileProps } from './createAnonymousProfileSchema';
2
- import { core as coreApi } from '@reservamos/js-api-client';
8
+ import coreApi from '@reservamos/js-api-client/core';
3
9
  import fingerprintService from '@/services/fingerprint';
4
10
  import mixpanelService from '@/services/mixpanel';
5
11
  import validatorService from '@/services/validator';
6
12
  import CreateAnonymousProfileSchema from './createAnonymousProfileSchema';
7
13
 
8
- type IdentifierKey = 'phone' | 'email';
9
-
10
- interface AnonymousProfilePayload {
11
- identifier_key: IdentifierKey;
12
- identifier_value: string;
13
- identifiers: AnonymousIdentifier[];
14
- details: Record<string, string>;
15
- }
16
- interface AnonymousProfileResponse {
17
- id: string;
18
- }
19
- /**
20
- * Transforms the identifier object based on the provided values.
21
- * @param {CreateAnonymousProfileProps} values - The values to transform.
22
- * @param {AnonymousIdentifier[]} identifiersProps - Additional identifiers to include.
23
- * @returns {AnonymousProfilePayload} The transformed identifier object.
24
- */
25
14
  function getAnonymousProfilePayload(
26
15
  values: CreateAnonymousProfileProps,
27
16
  identifiersProps: AnonymousIdentifier[],
28
- ): AnonymousProfilePayload {
17
+ ): CreateAnonymousProfilePayload {
29
18
  let identifier_key: IdentifierKey = 'phone';
30
19
  let identifier_value: string = values.phone || '';
31
20
  const identifiers: AnonymousIdentifier[] = [];
@@ -65,19 +54,9 @@ function getAnonymousProfilePayload(
65
54
  };
66
55
  }
67
56
 
68
- interface AnonymousIdentifier {
69
- key: string;
70
- value: string;
71
- }
72
-
73
- /**
74
- * Creates an anonymous profile using the provided payload.
75
- * @param {CreateAnonymousProfileProps} payload - The payload to create the anonymous profile.
76
- * @returns {Promise<void>} - A promise that resolves when the anonymous profile is created.
77
- */
78
57
  async function createAnonymousProfile(
79
58
  payload: CreateAnonymousProfileProps,
80
- ): Promise<AnonymousProfileResponse | undefined> {
59
+ ): Promise<AnonymousProfile | undefined> {
81
60
  try {
82
61
  validatorService.validateProps(payload, CreateAnonymousProfileSchema);
83
62
 
@@ -90,9 +69,7 @@ async function createAnonymousProfile(
90
69
  if (distinctId) identifiers.push({ key: 'distinct_id', value: distinctId });
91
70
 
92
71
  const dataPayload = getAnonymousProfilePayload(payload, identifiers);
93
-
94
- const result = await coreApi.createAnonymousProfile(dataPayload);
95
- return result.data;
72
+ return await coreApi.profiles.createAnonymousProfile(dataPayload);
96
73
  } catch (error) {
97
74
  console.error('Could not create anonymous profile:', error);
98
75
  return undefined;
@@ -1,26 +1,49 @@
1
+ import type { ApiConfig } from '@reservamos/js-api-client/core';
2
+
3
+ type AvailableEnvironments = 'sandbox' | 'prod';
4
+
5
+ let environment: AvailableEnvironments | undefined;
1
6
  const origin = window.location.origin;
2
7
 
3
- const coreAPIConfig = {
8
+ type CoreAPIConfig = Record<AvailableEnvironments, ApiConfig>;
9
+
10
+ const coreAPIConfig: CoreAPIConfig = {
4
11
  sandbox: {
5
- coreUrl: 'https://datalake-api-dev.reservamossaas.com/api',
6
- coreVersion: 'v1',
7
- headers: {
12
+ baseUrl: 'https://datalake-api-dev.reservamossaas.com/api',
13
+ defaultHeaders: {
8
14
  Origin: origin,
15
+ Authorization: 'Bearer 753bf0710dc920a84236d42241d4f487',
9
16
  },
10
- coreApiKey: 'Bearer 753bf0710dc920a84236d42241d4f487'
11
17
  },
12
18
  prod: {
13
- coreUrl: 'https://data-lake.reservamossaas.com/api',
14
- coreVersion: 'v1',
15
- headers: {
19
+ baseUrl: 'https://data-lake.reservamossaas.com/api',
20
+ defaultHeaders: {
16
21
  Origin: origin,
22
+ Authorization: 'Bearer 753bf0710dc920a84236d42241d4f487',
17
23
  },
18
- coreApiKey:'Bearer 753bf0710dc920a84236d42241d4f487'
19
24
  },
20
25
  };
21
26
 
27
+ function setEnvironment(env: AvailableEnvironments) {
28
+ environment = env;
29
+ }
30
+
31
+ /**
32
+ * Returns the core API config for the current environment.
33
+ * @throws {Error} Throws an error if the environment is not set.
34
+ */
35
+ function getCoreAPIConfig(): ApiConfig {
36
+ if (!environment) {
37
+ throw new Error(
38
+ 'Unable to get core API config, environment not set. Use configService.setEnvironment(environment) to set the environment.',
39
+ );
40
+ }
41
+ return coreAPIConfig[environment];
42
+ }
43
+
22
44
  const configService = {
23
- coreAPIConfig,
45
+ setEnvironment,
46
+ getCoreAPIConfig,
24
47
  };
25
48
 
26
49
  export default configService;
@@ -1,4 +1,5 @@
1
1
  import mixpanel from 'mixpanel-browser';
2
+ import { version } from '../../package.json';
2
3
 
3
4
  declare global {
4
5
  interface Window {
@@ -79,8 +80,7 @@ function track(eventName: string, properties: Record<string, unknown>): void {
79
80
  if (!isReady()) {
80
81
  return;
81
82
  }
82
-
83
- mixpanel.track(eventName, properties);
83
+ mixpanel.track(eventName, { ...properties, 'Reservamos Version': version });
84
84
  }
85
85
 
86
86
  /**
package/src/track.ts CHANGED
@@ -64,51 +64,36 @@ function flattenEventData(data: object): EventData {
64
64
  }, {} as EventData);
65
65
  }
66
66
 
67
- type EventTrackedFrom = 'Mixpanel Ready' | 'Mixpanel Ready Listener';
68
-
69
- function trackEventTracked(eventName: string, from: EventTrackedFrom) {
70
- mixpanelService.track('Event Tracked', {
71
- 'Event Name': eventName,
72
- 'From': from,
73
- });
74
- }
75
-
76
67
  /**
77
68
  * Send an error event to Mixpanel when an event fails to track.
78
69
  * The event contains the event name, error message, and validation errors.
79
70
  */
80
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
- export function trackEventError(eventName: string, error: any): void {
82
- try {
83
- tryTrackEvent('Track Event Error', async () => {
71
+ export function trackEventError(
72
+ eventName: string,
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ error: any,
75
+ payload: object,
76
+ ): void {
77
+ tryTrackEvent(async () => {
78
+ try {
84
79
  mixpanelService.track('Track Event Error', {
85
80
  'Failed Event Name': eventName,
86
81
  'Error Message': error?.message ?? 'Failed to track event',
87
82
  'Validation Errors': error?.errors || [],
83
+ 'Event Payload': payload,
88
84
  });
89
- });
90
- } catch (trackingError) {
91
- console.error('Failed to track error event:', trackingError);
92
- }
85
+ } catch (trackingError) {
86
+ console.error('Failed to track error event:', trackingError);
87
+ }
88
+ });
93
89
  }
94
90
 
95
- export async function tryTrackEvent(
96
- eventName: string,
97
- trackEventCallback: () => Promise<void>,
98
- ) {
91
+ export async function tryTrackEvent(trackEventCallback: () => Promise<void>) {
99
92
  if (mixpanelService.isReady()) {
100
93
  await trackEventCallback();
101
- trackEventTracked(eventName, 'Mixpanel Ready');
102
94
  } else {
103
95
  window.addEventListener('Tracker Ready', async () => {
104
- try {
105
- await trackEventCallback();
106
- trackEventTracked(eventName, 'Mixpanel Ready Listener');
107
- } catch (error) {
108
- // Errors inside a listener cannot be handled from outside the listener.
109
- // So we need to track the error here.
110
- trackEventError(eventName, error);
111
- }
96
+ await trackEventCallback();
112
97
  });
113
98
  }
114
99
  }
@@ -158,7 +143,7 @@ export async function trackEvent(
158
143
  mixpanelService.track(eventName, properties);
159
144
  } catch (error) {
160
145
  console.error(`Error tracking event '${eventName}':`, error);
161
- trackEventError(eventName, error);
146
+ trackEventError(eventName, error, eventProperties);
162
147
  }
163
148
  }
164
149
 
@@ -1,15 +0,0 @@
1
- declare module '@reservamos/js-api-client' {
2
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
- export const core: any; // Replace 'any' with a more specific type if possible
4
-
5
- interface ConfigOptions {
6
- coreUrl: string;
7
- coreVersion?: string;
8
- withCredentials?: boolean;
9
- headers?: {
10
- Origin?: string;
11
- };
12
- }
13
-
14
- export function setConfig(options: ConfigOptions): void;
15
- }