@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.
@@ -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.21";
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
- localStorage.setItem(GEOLOCATION_PERMISSION_KEY, timestamp.toString());
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
- const lastPermissionTimestamp = localStorage.getItem(
13841
- GEOLOCATION_PERMISSION_KEY
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
- if (isTrackerReady()) {
13855
- trackCustomEvent(GEOLOCATION_TRACK_EVENT, {
13856
- geolocationAccepted: true
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
- if (isTrackerReady()) {
13864
- trackCustomEvent(GEOLOCATION_TRACK_EVENT, {
13865
- geolocationAccepted: false
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 {