@reservamos/browser-analytics 1.0.21 → 1.0.22-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 +12 -0
- package/dist/browser-analytics.cjs +2 -2
- package/dist/browser-analytics.cjs.map +1 -1
- package/dist/browser-analytics.d.ts +13 -0
- package/dist/browser-analytics.esm.js +160 -22
- package/dist/browser-analytics.esm.js.map +1 -1
- package/dist/browser-analytics.iife.js +2 -2
- package/dist/browser-analytics.iife.js.map +1 -1
- package/package.json +1 -1
- package/src/events/geolocationSelected/geolocationSelectedSchema.ts +13 -0
- package/src/events/geolocationSelected/index.ts +7 -0
- package/src/events/geolocationSelected/trackGeolocationSelected.ts +21 -0
- package/src/index.ts +4 -0
- package/src/init.ts +2 -2
- package/src/services/fingerprint.ts +4 -0
- package/src/services/geolocation.test.ts +261 -0
- package/src/services/geolocation.ts +270 -24
- package/src/services/mixpanel.ts +13 -0
- package/src/services/validator/validator.ts +2 -0
|
@@ -22,6 +22,18 @@ export type AllowedPrimitive = string | boolean | number | undefined;
|
|
|
22
22
|
export type EventData = Record<string, AllowedPrimitive | AllowedPrimitive[]>;
|
|
23
23
|
export type EventMetadata = EventData;
|
|
24
24
|
declare function trackCustomEvent(eventName: string, eventData?: EventData, meta?: EventMetadata): void;
|
|
25
|
+
declare const geolocationSelectedSchema: z.ZodObject<{
|
|
26
|
+
"Selected City": z.ZodString;
|
|
27
|
+
"Selected Country Code": z.ZodString;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
"Selected City": string;
|
|
30
|
+
"Selected Country Code": string;
|
|
31
|
+
}, {
|
|
32
|
+
"Selected City": string;
|
|
33
|
+
"Selected Country Code": string;
|
|
34
|
+
}>;
|
|
35
|
+
export type GeolocationSelectedProps = z.infer<typeof geolocationSelectedSchema>;
|
|
36
|
+
declare function trackGeolocationSelected(eventData: GeolocationSelectedProps, meta?: EventMetadata): void;
|
|
25
37
|
declare const interestInHomeSchema: z.ZodObject<{
|
|
26
38
|
product: z.ZodEffects<z.ZodEnum<[
|
|
27
39
|
"web",
|
|
@@ -1286,6 +1298,7 @@ declare const analytics: {
|
|
|
1286
1298
|
pickedDeparture: typeof trackSearch;
|
|
1287
1299
|
customEvent: typeof trackCustomEvent;
|
|
1288
1300
|
purchaseCanceled: typeof trackPurchaseCanceled;
|
|
1301
|
+
geolocationSelected: typeof trackGeolocationSelected;
|
|
1289
1302
|
};
|
|
1290
1303
|
};
|
|
1291
1304
|
|
|
@@ -4555,6 +4555,9 @@ async function initFingerprint(apiKey, proxyUrl) {
|
|
|
4555
4555
|
}
|
|
4556
4556
|
async function getFingerprint(cacheOnly = false) {
|
|
4557
4557
|
if (!window.fingerprintConfig) {
|
|
4558
|
+
if (cacheOnly) {
|
|
4559
|
+
return "";
|
|
4560
|
+
}
|
|
4558
4561
|
throw new Error("Fingerprint configuration is not initialized.");
|
|
4559
4562
|
}
|
|
4560
4563
|
const cachedFingerprint = getCachedFingerprint();
|
|
@@ -13392,7 +13395,7 @@ function loadNoop(_src, onload) {
|
|
|
13392
13395
|
onload();
|
|
13393
13396
|
}
|
|
13394
13397
|
var mixpanel = init_as_module(loadNoop);
|
|
13395
|
-
const version = "1.0.
|
|
13398
|
+
const version = "1.0.22-alpha.0";
|
|
13396
13399
|
const MIXPANEL_DISTINCT_ID_CACHE_KEY = "mp_distinct_id";
|
|
13397
13400
|
function init$2(mixpanelToken, debug = false, proxyUrl) {
|
|
13398
13401
|
return new Promise((resolve) => {
|
|
@@ -13417,6 +13420,12 @@ function attachProperty(key, value) {
|
|
|
13417
13420
|
}
|
|
13418
13421
|
mixpanel.people.union(key, [value]);
|
|
13419
13422
|
}
|
|
13423
|
+
function setPeopleProperties(properties) {
|
|
13424
|
+
if (!isReady()) {
|
|
13425
|
+
return;
|
|
13426
|
+
}
|
|
13427
|
+
mixpanel.people.set(properties);
|
|
13428
|
+
}
|
|
13420
13429
|
function isReady() {
|
|
13421
13430
|
return window.mixpanel !== void 0;
|
|
13422
13431
|
}
|
|
@@ -13446,8 +13455,18 @@ const mixpanelService = {
|
|
|
13446
13455
|
track,
|
|
13447
13456
|
identify: identify$1,
|
|
13448
13457
|
attachProperty,
|
|
13458
|
+
setPeopleProperties,
|
|
13449
13459
|
getMixpanelDistinctId
|
|
13450
13460
|
};
|
|
13461
|
+
const geolocationSelectedSchema = z.object({
|
|
13462
|
+
"Selected City": z.string().min(1, "Selected city is required"),
|
|
13463
|
+
"Selected Country Code": z.string().min(1, "Selected Country Code is required")
|
|
13464
|
+
});
|
|
13465
|
+
const EVENT_NAME$a = "Geolocation Selected";
|
|
13466
|
+
function trackGeolocationSelected(eventData, meta = {}) {
|
|
13467
|
+
trackEvent(EVENT_NAME$a, eventData, meta);
|
|
13468
|
+
mixpanelService.setPeopleProperties(eventData);
|
|
13469
|
+
}
|
|
13451
13470
|
const IdentifySchema = z.object({
|
|
13452
13471
|
firstName: z.string().optional(),
|
|
13453
13472
|
lastName: z.string().optional(),
|
|
@@ -13757,7 +13776,8 @@ const eventSchemas = {
|
|
|
13757
13776
|
"Interest In Search": interestInSearchSchema,
|
|
13758
13777
|
"View Results": viewResultsSchema,
|
|
13759
13778
|
"Purchase Attempt": purchaseAttemptSchema,
|
|
13760
|
-
"Picked Departure": pickedDepartureSchema
|
|
13779
|
+
"Picked Departure": pickedDepartureSchema,
|
|
13780
|
+
"Geolocation Selected": geolocationSelectedSchema
|
|
13761
13781
|
};
|
|
13762
13782
|
function parseEventProps(eventName, eventData) {
|
|
13763
13783
|
const eventSchema = eventSchemas[eventName] || customEventSchema;
|
|
@@ -13807,7 +13827,6 @@ async function init$1(config) {
|
|
|
13807
13827
|
mixpanelProxyUrl,
|
|
13808
13828
|
identifyProxyUrl
|
|
13809
13829
|
} = config;
|
|
13810
|
-
geolocationService.init();
|
|
13811
13830
|
await mixpanelService.init(mixpanelToken, debug, mixpanelProxyUrl);
|
|
13812
13831
|
try {
|
|
13813
13832
|
await fingerprintService.initFingerprint(
|
|
@@ -13817,6 +13836,7 @@ async function init$1(config) {
|
|
|
13817
13836
|
} catch (error) {
|
|
13818
13837
|
console.error("Error initializing identification service:", error);
|
|
13819
13838
|
}
|
|
13839
|
+
geolocationService.init();
|
|
13820
13840
|
configService.setEnvironment(isSandbox ? "sandbox" : "prod");
|
|
13821
13841
|
f.setConfig(configService.getCoreAPIConfig());
|
|
13822
13842
|
onLoaded();
|
|
@@ -13826,47 +13846,164 @@ function isTrackerReady() {
|
|
|
13826
13846
|
}
|
|
13827
13847
|
let currentCoordinates = null;
|
|
13828
13848
|
const GEOLOCATION_PERMISSION_KEY = "geolocationPermissionTimestamp";
|
|
13849
|
+
const GEOLOCATION_CACHE_KEY = "geolocationCache";
|
|
13850
|
+
const GEOLOCATION_TRACK_EVENT = "Geolocation Requested";
|
|
13829
13851
|
const SEVEN_DAYS_IN_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
13852
|
+
const GEOLOCATION_REQUEST_TIMEOUT_MS = 1e4;
|
|
13853
|
+
const GEOLOCATION_OPTIONS = {
|
|
13854
|
+
enableHighAccuracy: true,
|
|
13855
|
+
timeout: GEOLOCATION_REQUEST_TIMEOUT_MS,
|
|
13856
|
+
maximumAge: 0
|
|
13857
|
+
};
|
|
13858
|
+
function safeGetItem(key) {
|
|
13859
|
+
try {
|
|
13860
|
+
return localStorage.getItem(key);
|
|
13861
|
+
} catch {
|
|
13862
|
+
return null;
|
|
13863
|
+
}
|
|
13864
|
+
}
|
|
13865
|
+
function safeSetItem(key, value) {
|
|
13866
|
+
try {
|
|
13867
|
+
localStorage.setItem(key, value);
|
|
13868
|
+
} catch {
|
|
13869
|
+
}
|
|
13870
|
+
}
|
|
13871
|
+
function toISO(timestamp) {
|
|
13872
|
+
return new Date(timestamp).toISOString();
|
|
13873
|
+
}
|
|
13874
|
+
function isGeolocationCache(value) {
|
|
13875
|
+
if (typeof value !== "object" || value === null) {
|
|
13876
|
+
return false;
|
|
13877
|
+
}
|
|
13878
|
+
const cache = value;
|
|
13879
|
+
return typeof cache.lat === "number" && typeof cache.long === "number" && typeof cache.updatedAt === "string" && (cache.accuracy === void 0 || typeof cache.accuracy === "number");
|
|
13880
|
+
}
|
|
13881
|
+
function loadCoordinatesFromStorage() {
|
|
13882
|
+
const raw = safeGetItem(GEOLOCATION_CACHE_KEY);
|
|
13883
|
+
if (!raw) {
|
|
13884
|
+
return null;
|
|
13885
|
+
}
|
|
13886
|
+
try {
|
|
13887
|
+
const parsed = JSON.parse(raw);
|
|
13888
|
+
return isGeolocationCache(parsed) ? parsed : null;
|
|
13889
|
+
} catch {
|
|
13890
|
+
return null;
|
|
13891
|
+
}
|
|
13892
|
+
}
|
|
13893
|
+
function saveCoordinatesToStorage(coords, updatedAt, accuracy) {
|
|
13894
|
+
safeSetItem(
|
|
13895
|
+
GEOLOCATION_CACHE_KEY,
|
|
13896
|
+
JSON.stringify({
|
|
13897
|
+
lat: coords.lat,
|
|
13898
|
+
long: coords.long,
|
|
13899
|
+
updatedAt,
|
|
13900
|
+
...accuracy !== void 0 && { accuracy }
|
|
13901
|
+
})
|
|
13902
|
+
);
|
|
13903
|
+
}
|
|
13904
|
+
function restoreCoordinatesFromStorage() {
|
|
13905
|
+
const cache = loadCoordinatesFromStorage();
|
|
13906
|
+
if (cache) {
|
|
13907
|
+
currentCoordinates = { lat: cache.lat, long: cache.long };
|
|
13908
|
+
}
|
|
13909
|
+
}
|
|
13830
13910
|
function isPermissionTimestampValid(lastPermissionTimestamp) {
|
|
13831
13911
|
if (!lastPermissionTimestamp) return false;
|
|
13832
13912
|
const now = Date.now();
|
|
13833
13913
|
return now - parseInt(lastPermissionTimestamp, 10) < SEVEN_DAYS_IN_MS;
|
|
13834
13914
|
}
|
|
13835
13915
|
function updatePermissionTimestamp(timestamp) {
|
|
13836
|
-
|
|
13916
|
+
safeSetItem(GEOLOCATION_PERMISSION_KEY, timestamp.toString());
|
|
13917
|
+
}
|
|
13918
|
+
function getGeolocationStatus(error) {
|
|
13919
|
+
return error.code === error.PERMISSION_DENIED ? "denied" : "error";
|
|
13920
|
+
}
|
|
13921
|
+
function buildGeolocationEventProperties(data) {
|
|
13922
|
+
const properties = {
|
|
13923
|
+
"Geolocation Updated At": data.updatedAt,
|
|
13924
|
+
"Geolocation Status": data.status
|
|
13925
|
+
};
|
|
13926
|
+
if (data.accuracy !== void 0) {
|
|
13927
|
+
properties["Geolocation Accuracy"] = data.accuracy;
|
|
13928
|
+
}
|
|
13929
|
+
if (data.errorCode !== void 0) {
|
|
13930
|
+
properties["Geolocation Error Code"] = data.errorCode;
|
|
13931
|
+
}
|
|
13932
|
+
const coordinates = getCoordinates();
|
|
13933
|
+
if (coordinates) {
|
|
13934
|
+
properties.$latitude = coordinates.lat;
|
|
13935
|
+
properties.$longitude = coordinates.long;
|
|
13936
|
+
}
|
|
13937
|
+
return properties;
|
|
13938
|
+
}
|
|
13939
|
+
function buildGeolocationProfileProperties(data) {
|
|
13940
|
+
const properties = {
|
|
13941
|
+
"Geolocation Updated At": data.updatedAt,
|
|
13942
|
+
"Geolocation Status": data.status
|
|
13943
|
+
};
|
|
13944
|
+
const coordinates = getCoordinates();
|
|
13945
|
+
if (coordinates) {
|
|
13946
|
+
properties.$latitude = coordinates.lat;
|
|
13947
|
+
properties.$longitude = coordinates.long;
|
|
13948
|
+
}
|
|
13949
|
+
return properties;
|
|
13950
|
+
}
|
|
13951
|
+
function syncGeolocationToMixpanel(data) {
|
|
13952
|
+
if (!isTrackerReady()) {
|
|
13953
|
+
return;
|
|
13954
|
+
}
|
|
13955
|
+
const eventProperties = buildGeolocationEventProperties(data);
|
|
13956
|
+
const profileProperties = buildGeolocationProfileProperties(data);
|
|
13957
|
+
trackCustomEvent(GEOLOCATION_TRACK_EVENT, eventProperties);
|
|
13958
|
+
mixpanelService.setPeopleProperties(profileProperties);
|
|
13837
13959
|
}
|
|
13838
13960
|
function init() {
|
|
13961
|
+
restoreCoordinatesFromStorage();
|
|
13839
13962
|
return new Promise((resolve) => {
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
);
|
|
13963
|
+
var _a;
|
|
13964
|
+
const lastPermissionTimestamp = safeGetItem(GEOLOCATION_PERMISSION_KEY);
|
|
13843
13965
|
if (isPermissionTimestampValid(lastPermissionTimestamp)) {
|
|
13966
|
+
const cache = loadCoordinatesFromStorage();
|
|
13967
|
+
const updatedAt2 = (cache == null ? void 0 : cache.updatedAt) ?? (lastPermissionTimestamp ? toISO(parseInt(lastPermissionTimestamp, 10)) : (/* @__PURE__ */ new Date()).toISOString());
|
|
13968
|
+
syncGeolocationToMixpanel({
|
|
13969
|
+
status: "skipped_cache",
|
|
13970
|
+
updatedAt: updatedAt2,
|
|
13971
|
+
accuracy: cache == null ? void 0 : cache.accuracy
|
|
13972
|
+
});
|
|
13844
13973
|
resolve(currentCoordinates);
|
|
13845
13974
|
return;
|
|
13846
13975
|
}
|
|
13847
|
-
const GEOLOCATION_TRACK_EVENT = "Geolocation Requested";
|
|
13848
13976
|
const now = Date.now();
|
|
13977
|
+
const updatedAt = toISO(now);
|
|
13978
|
+
if (!((_a = navigator.geolocation) == null ? void 0 : _a.getCurrentPosition)) {
|
|
13979
|
+
syncGeolocationToMixpanel({ status: "error", updatedAt });
|
|
13980
|
+
resolve(null);
|
|
13981
|
+
return;
|
|
13982
|
+
}
|
|
13849
13983
|
navigator.geolocation.getCurrentPosition(
|
|
13850
13984
|
(geolocation) => {
|
|
13851
|
-
const { latitude: lat, longitude: long } = geolocation.coords;
|
|
13985
|
+
const { latitude: lat, longitude: long, accuracy } = geolocation.coords;
|
|
13852
13986
|
currentCoordinates = { lat, long };
|
|
13987
|
+
saveCoordinatesToStorage(currentCoordinates, updatedAt, accuracy);
|
|
13853
13988
|
updatePermissionTimestamp(now);
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
}
|
|
13989
|
+
syncGeolocationToMixpanel({
|
|
13990
|
+
status: "granted",
|
|
13991
|
+
updatedAt,
|
|
13992
|
+
accuracy
|
|
13993
|
+
});
|
|
13859
13994
|
resolve(currentCoordinates);
|
|
13860
13995
|
},
|
|
13861
|
-
() => {
|
|
13996
|
+
(error) => {
|
|
13997
|
+
const status = getGeolocationStatus(error);
|
|
13862
13998
|
updatePermissionTimestamp(now);
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
}
|
|
13999
|
+
syncGeolocationToMixpanel({
|
|
14000
|
+
status,
|
|
14001
|
+
updatedAt,
|
|
14002
|
+
errorCode: error.code
|
|
14003
|
+
});
|
|
13868
14004
|
resolve(null);
|
|
13869
|
-
}
|
|
14005
|
+
},
|
|
14006
|
+
GEOLOCATION_OPTIONS
|
|
13870
14007
|
);
|
|
13871
14008
|
});
|
|
13872
14009
|
}
|
|
@@ -14369,7 +14506,8 @@ const analytics = {
|
|
|
14369
14506
|
purchaseAttempt: trackPurchaseAttempt,
|
|
14370
14507
|
pickedDeparture: trackSearch$1,
|
|
14371
14508
|
customEvent: trackCustomEvent,
|
|
14372
|
-
purchaseCanceled: trackPurchaseCanceled
|
|
14509
|
+
purchaseCanceled: trackPurchaseCanceled,
|
|
14510
|
+
geolocationSelected: trackGeolocationSelected
|
|
14373
14511
|
}
|
|
14374
14512
|
};
|
|
14375
14513
|
export {
|