@reservamos/browser-analytics 1.1.7-alpha.1 → 1.1.8-alpha.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 +9 -0
- package/README.md +12 -10
- package/dist/browser-analytics.cjs +3 -3
- package/dist/browser-analytics.cjs.map +1 -1
- package/dist/browser-analytics.esm.js +911 -817
- package/dist/browser-analytics.esm.js.map +1 -1
- package/dist/browser-analytics.iife.js +3 -3
- package/dist/browser-analytics.iife.js.map +1 -1
- package/package.json +4 -4
- package/src/init.test.ts +287 -0
- package/src/init.ts +34 -12
- package/src/services/botDetectionRelay.test.ts +58 -31
- package/src/services/botDetectionRelay.ts +13 -23
- package/src/services/fingerprint.test.ts +18 -0
- package/src/services/fingerprint.ts +2 -11
- package/src/services/mixpanel.test.ts +61 -0
- package/src/services/mixpanel.ts +16 -16
- package/src/track.test.ts +315 -71
- package/src/track.ts +88 -24
package/src/track.ts
CHANGED
|
@@ -89,12 +89,42 @@ export function trackEventError(
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
/** Waits for one bounded attempt, then consumes callback failures. */
|
|
93
|
+
export async function tryTrackEvent(
|
|
94
|
+
trackEventCallback: () => Promise<void>,
|
|
95
|
+
eventName = 'Track Event Error',
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
if (!mixpanelService.isReady()) {
|
|
98
|
+
const ready = await new Promise<boolean>((resolve) => {
|
|
99
|
+
const finish = (isReady: boolean) => {
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
window.removeEventListener('Tracker Ready', onReady);
|
|
102
|
+
resolve(isReady);
|
|
103
|
+
};
|
|
104
|
+
const onReady = () => {
|
|
105
|
+
if (mixpanelService.isReady()) finish(true);
|
|
106
|
+
};
|
|
107
|
+
const timer = setTimeout(() => finish(mixpanelService.isReady()), 5000);
|
|
108
|
+
window.addEventListener('Tracker Ready', onReady);
|
|
109
|
+
onReady();
|
|
110
|
+
});
|
|
111
|
+
if (!ready) {
|
|
112
|
+
console.error('Tracking diagnostic', {
|
|
113
|
+
eventName,
|
|
114
|
+
stage: 'readiness',
|
|
115
|
+
reason: 'timeout',
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
94
122
|
await trackEventCallback();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
123
|
+
} catch {
|
|
124
|
+
console.error('Tracking diagnostic', {
|
|
125
|
+
eventName,
|
|
126
|
+
stage: 'submission',
|
|
127
|
+
reason: 'failed',
|
|
98
128
|
});
|
|
99
129
|
}
|
|
100
130
|
}
|
|
@@ -105,33 +135,50 @@ export async function tryTrackEvent(trackEventCallback: () => Promise<void>) {
|
|
|
105
135
|
* @param {string} eventName - The name of the event to track.
|
|
106
136
|
* @param {object} eventProperties - The properties of the event to track.
|
|
107
137
|
* @param {EventMetadata} meta - Additional metadata to include in the event.
|
|
108
|
-
*
|
|
138
|
+
* Waits up to five seconds for Mixpanel readiness before event submission.
|
|
139
|
+
* Optional fingerprint failure does not discard an otherwise valid event.
|
|
109
140
|
*/
|
|
110
|
-
export
|
|
141
|
+
export function trackEvent(
|
|
111
142
|
eventName: string,
|
|
112
143
|
eventProperties: object,
|
|
113
144
|
meta: EventMetadata = {},
|
|
114
145
|
): Promise<void> {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
146
|
+
return tryTrackEvent(
|
|
147
|
+
() => submitEvent(eventName, eventProperties, meta),
|
|
148
|
+
eventName,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
118
151
|
|
|
152
|
+
async function submitEvent(
|
|
153
|
+
eventName: string,
|
|
154
|
+
eventProperties: object,
|
|
155
|
+
meta: EventMetadata,
|
|
156
|
+
): Promise<void> {
|
|
119
157
|
try {
|
|
120
158
|
validator.parseEventProps(eventName, eventProperties);
|
|
121
159
|
// Call the Mixpanel service to store the distinct ID in the cache
|
|
122
160
|
const distinctId = mixpanelService.getMixpanelDistinctId();
|
|
123
161
|
const botDetectionEnabled =
|
|
124
162
|
botDetectionRelayService.isEnabledFor(eventName);
|
|
125
|
-
let fingerprint
|
|
126
|
-
let fingerprintRequestId: string | undefined;
|
|
163
|
+
let fingerprint = '';
|
|
127
164
|
|
|
128
|
-
if (botDetectionEnabled
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
165
|
+
if (botDetectionEnabled) {
|
|
166
|
+
try {
|
|
167
|
+
fingerprint = fingerprintService.getCachedFingerprint() ?? '';
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error('Error reading cached fingerprint:', error);
|
|
170
|
+
}
|
|
132
171
|
} else {
|
|
133
172
|
const cacheOnly = !FP_TRIGGER_EVENTS.includes(eventName);
|
|
134
|
-
|
|
173
|
+
try {
|
|
174
|
+
fingerprint = await fingerprintService.getFingerprint(cacheOnly);
|
|
175
|
+
} catch {
|
|
176
|
+
console.error('Tracking diagnostic', {
|
|
177
|
+
eventName,
|
|
178
|
+
stage: 'fingerprint',
|
|
179
|
+
reason: 'failed',
|
|
180
|
+
});
|
|
181
|
+
}
|
|
135
182
|
}
|
|
136
183
|
const defaultCoordinates: Record<string, string | number> = {};
|
|
137
184
|
const coordinates = geolocationService.getCoordinates();
|
|
@@ -159,13 +206,8 @@ export async function trackEvent(
|
|
|
159
206
|
|
|
160
207
|
mixpanelService.track(eventName, properties);
|
|
161
208
|
|
|
162
|
-
if (
|
|
163
|
-
void
|
|
164
|
-
requestId: fingerprintRequestId,
|
|
165
|
-
visitorId: fingerprint,
|
|
166
|
-
...(distinctId && { distinctId }),
|
|
167
|
-
eventName,
|
|
168
|
-
});
|
|
209
|
+
if (botDetectionEnabled) {
|
|
210
|
+
void identifyAndRelayFingerprint(eventName, distinctId);
|
|
169
211
|
}
|
|
170
212
|
} catch (error) {
|
|
171
213
|
console.error(`Error tracking event '${eventName}':`, error);
|
|
@@ -173,6 +215,28 @@ export async function trackEvent(
|
|
|
173
215
|
}
|
|
174
216
|
}
|
|
175
217
|
|
|
218
|
+
/** Identifies and relays only after the original event has been submitted. */
|
|
219
|
+
async function identifyAndRelayFingerprint(
|
|
220
|
+
eventName: string,
|
|
221
|
+
distinctId: string | null,
|
|
222
|
+
): Promise<void> {
|
|
223
|
+
try {
|
|
224
|
+
if (!fingerprintService.isFingerprintReady()) return;
|
|
225
|
+
|
|
226
|
+
const identification = await fingerprintService.identifyVisitor(true);
|
|
227
|
+
if (!identification.requestId) return;
|
|
228
|
+
|
|
229
|
+
await botDetectionRelayService.relay({
|
|
230
|
+
requestId: identification.requestId,
|
|
231
|
+
visitorId: identification.visitorId,
|
|
232
|
+
...(distinctId && { distinctId }),
|
|
233
|
+
eventName,
|
|
234
|
+
});
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error(`Error running Bot Detection for '${eventName}':`, error);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
176
240
|
/**
|
|
177
241
|
* Extracts UTM and other tracking parameters from the current URL that match predefined fields.
|
|
178
242
|
* @returns {Record<string, string>} An object containing matched tracking parameters.
|