@tracelog/lib 2.1.0-rc.74.5 → 2.1.1-rc.75.2

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.

Potentially problematic release.


This version of @tracelog/lib might be problematic. Click here for more details.

@@ -688,6 +688,8 @@ interface State {
688
688
  hasStartSession: boolean;
689
689
  suppressNextScroll: boolean;
690
690
  scrollEventCount?: number;
691
+ sessionReferrer?: string;
692
+ sessionUtm?: UTM;
691
693
  }
692
694
 
693
695
  /**
@@ -1613,58 +1615,6 @@ declare class EventManager extends StateManager {
1613
1615
  * @internal
1614
1616
  */
1615
1617
  private cleanupExpiredSessionCounts;
1616
- /**
1617
- * Returns the referrer if it's external, or 'Direct' if internal/empty.
1618
- *
1619
- * **Purpose**: Filter out internal referrers (same domain) to ensure
1620
- * accurate traffic source attribution. Internal referrers occur when:
1621
- * - Session expires and user navigates within the same site
1622
- * - User opens new tab from an internal link
1623
- * - Page refresh after session timeout
1624
- *
1625
- * **Logic**:
1626
- * - Empty referrer → 'Direct'
1627
- * - Referrer from same domain or subdomain → 'Direct' (internal navigation)
1628
- * - External referrer → Returns original referrer
1629
- *
1630
- * **Subdomain Detection**:
1631
- * - `www.example.com` → `example.com` ✓ (internal)
1632
- * - `blog.example.com` → `example.com` ✓ (internal)
1633
- * - `example.com` → `www.example.com` ✓ (internal)
1634
- *
1635
- * @returns External referrer URL or 'Direct'
1636
- *
1637
- * @internal
1638
- */
1639
- private getExternalReferrer;
1640
- /**
1641
- * Checks if two hostnames belong to the same domain (including subdomains).
1642
- * Extracts root domain and compares to handle cross-subdomain navigation.
1643
- *
1644
- * @example
1645
- * isSameDomain('www.example.com', 'example.com') // true
1646
- * isSameDomain('app.example.com', 'www.example.com') // true
1647
- * isSameDomain('example.co.uk', 'app.example.co.uk') // true
1648
- *
1649
- * @param hostname1 - First hostname (e.g., 'www.example.com')
1650
- * @param hostname2 - Second hostname (e.g., 'app.example.com')
1651
- * @returns true if same root domain
1652
- *
1653
- * @internal
1654
- */
1655
- private isSameDomain;
1656
- /**
1657
- * Extracts the root (registrable) domain from a hostname.
1658
- * Handles both standard TLDs (.com, .org) and compound TLDs (.co.uk, .com.br).
1659
- *
1660
- * @example
1661
- * getRootDomain('www.example.com') // 'example.com'
1662
- * getRootDomain('app.blog.example.com') // 'example.com'
1663
- * getRootDomain('shop.example.co.uk') // 'example.co.uk'
1664
- *
1665
- * @internal
1666
- */
1667
- private getRootDomain;
1668
1618
  /**
1669
1619
  * Persists current session event counts to localStorage (debounced).
1670
1620
  *
@@ -688,6 +688,8 @@ interface State {
688
688
  hasStartSession: boolean;
689
689
  suppressNextScroll: boolean;
690
690
  scrollEventCount?: number;
691
+ sessionReferrer?: string;
692
+ sessionUtm?: UTM;
691
693
  }
692
694
 
693
695
  /**
@@ -1613,58 +1615,6 @@ declare class EventManager extends StateManager {
1613
1615
  * @internal
1614
1616
  */
1615
1617
  private cleanupExpiredSessionCounts;
1616
- /**
1617
- * Returns the referrer if it's external, or 'Direct' if internal/empty.
1618
- *
1619
- * **Purpose**: Filter out internal referrers (same domain) to ensure
1620
- * accurate traffic source attribution. Internal referrers occur when:
1621
- * - Session expires and user navigates within the same site
1622
- * - User opens new tab from an internal link
1623
- * - Page refresh after session timeout
1624
- *
1625
- * **Logic**:
1626
- * - Empty referrer → 'Direct'
1627
- * - Referrer from same domain or subdomain → 'Direct' (internal navigation)
1628
- * - External referrer → Returns original referrer
1629
- *
1630
- * **Subdomain Detection**:
1631
- * - `www.example.com` → `example.com` ✓ (internal)
1632
- * - `blog.example.com` → `example.com` ✓ (internal)
1633
- * - `example.com` → `www.example.com` ✓ (internal)
1634
- *
1635
- * @returns External referrer URL or 'Direct'
1636
- *
1637
- * @internal
1638
- */
1639
- private getExternalReferrer;
1640
- /**
1641
- * Checks if two hostnames belong to the same domain (including subdomains).
1642
- * Extracts root domain and compares to handle cross-subdomain navigation.
1643
- *
1644
- * @example
1645
- * isSameDomain('www.example.com', 'example.com') // true
1646
- * isSameDomain('app.example.com', 'www.example.com') // true
1647
- * isSameDomain('example.co.uk', 'app.example.co.uk') // true
1648
- *
1649
- * @param hostname1 - First hostname (e.g., 'www.example.com')
1650
- * @param hostname2 - Second hostname (e.g., 'app.example.com')
1651
- * @returns true if same root domain
1652
- *
1653
- * @internal
1654
- */
1655
- private isSameDomain;
1656
- /**
1657
- * Extracts the root (registrable) domain from a hostname.
1658
- * Handles both standard TLDs (.com, .org) and compound TLDs (.co.uk, .com.br).
1659
- *
1660
- * @example
1661
- * getRootDomain('www.example.com') // 'example.com'
1662
- * getRootDomain('app.blog.example.com') // 'example.com'
1663
- * getRootDomain('shop.example.co.uk') // 'example.co.uk'
1664
- *
1665
- * @internal
1666
- */
1667
- private getRootDomain;
1668
1618
  /**
1669
1619
  * Persists current session event counts to localStorage (debounced).
1670
1620
  *
@@ -718,7 +718,7 @@ var init_performance_constants = __esm({
718
718
  var version;
719
719
  var init_package = __esm({
720
720
  "package.json"() {
721
- version = "2.1.0";
721
+ version = "2.1.1";
722
722
  }
723
723
  });
724
724
 
@@ -827,6 +827,61 @@ var init_mode_utils = __esm({
827
827
  }
828
828
  });
829
829
 
830
+ // src/utils/browser/referrer.utils.ts
831
+ var COMPOUND_TLDS, getRootDomain, isSameDomain, getExternalReferrer;
832
+ var init_referrer_utils = __esm({
833
+ "src/utils/browser/referrer.utils.ts"() {
834
+ init_logging_utils();
835
+ COMPOUND_TLDS = [
836
+ "co.uk",
837
+ "org.uk",
838
+ "com.au",
839
+ "net.au",
840
+ "com.br",
841
+ "co.nz",
842
+ "co.jp",
843
+ "com.mx",
844
+ "co.in",
845
+ "com.cn",
846
+ "co.za"
847
+ ];
848
+ getRootDomain = (hostname) => {
849
+ const parts = hostname.toLowerCase().split(".");
850
+ if (parts.length <= 2) {
851
+ return hostname.toLowerCase();
852
+ }
853
+ const lastTwo = parts.slice(-2).join(".");
854
+ if (COMPOUND_TLDS.includes(lastTwo)) {
855
+ return parts.slice(-3).join(".");
856
+ }
857
+ return parts.slice(-2).join(".");
858
+ };
859
+ isSameDomain = (hostname1, hostname2) => {
860
+ if (hostname1 === hostname2) {
861
+ return true;
862
+ }
863
+ return getRootDomain(hostname1) === getRootDomain(hostname2);
864
+ };
865
+ getExternalReferrer = () => {
866
+ const referrer = document.referrer;
867
+ if (!referrer) {
868
+ return "Direct";
869
+ }
870
+ try {
871
+ const referrerHostname = new URL(referrer).hostname.toLowerCase();
872
+ const currentHostname = window.location.hostname.toLowerCase();
873
+ if (isSameDomain(referrerHostname, currentHostname)) {
874
+ return "Direct";
875
+ }
876
+ return referrer;
877
+ } catch (error) {
878
+ log("debug", "Failed to parse referrer URL, using raw value", { error, data: { referrer } });
879
+ return referrer;
880
+ }
881
+ };
882
+ }
883
+ });
884
+
830
885
  // src/utils/browser/utm-params.utils.ts
831
886
  var getUTMParameters;
832
887
  var init_utm_params_utils = __esm({
@@ -853,6 +908,7 @@ var init_browser = __esm({
853
908
  "src/utils/browser/index.ts"() {
854
909
  init_device_detector_utils();
855
910
  init_mode_utils();
911
+ init_referrer_utils();
856
912
  init_utm_params_utils();
857
913
  }
858
914
  });
@@ -3504,7 +3560,6 @@ var init_event_manager = __esm({
3504
3560
  return queue;
3505
3561
  }
3506
3562
  buildEventPayload(data) {
3507
- const isSessionStart = data.type === "session_start" /* SESSION_START */;
3508
3563
  const currentPageUrl = data.page_url ?? this.get("pageUrl");
3509
3564
  const timestamp = this.timeManager.now();
3510
3565
  const validation = this.timeManager.validateTimestamp(timestamp);
@@ -3513,12 +3568,14 @@ var init_event_manager = __esm({
3513
3568
  data: { type: data.type, error: validation.error }
3514
3569
  });
3515
3570
  }
3571
+ const sessionReferrer = this.get("sessionReferrer");
3572
+ const sessionUtm = this.get("sessionUtm");
3516
3573
  let payload = {
3517
3574
  id: generateEventId(),
3518
3575
  type: data.type,
3519
3576
  page_url: currentPageUrl,
3520
3577
  timestamp,
3521
- ...isSessionStart && { referrer: this.getExternalReferrer() },
3578
+ ...sessionReferrer && { referrer: sessionReferrer },
3522
3579
  ...data.from_page_url && { from_page_url: data.from_page_url },
3523
3580
  ...data.scroll_data && { scroll_data: data.scroll_data },
3524
3581
  ...data.click_data && { click_data: data.click_data },
@@ -3527,7 +3584,7 @@ var init_event_manager = __esm({
3527
3584
  ...data.error_data && { error_data: data.error_data },
3528
3585
  ...data.viewport_data && { viewport_data: data.viewport_data },
3529
3586
  ...data.page_view && { page_view: data.page_view },
3530
- ...isSessionStart && getUTMParameters() && { utm: getUTMParameters() }
3587
+ ...sessionUtm && { utm: sessionUtm }
3531
3588
  };
3532
3589
  const collectApiUrls = this.get("collectApiUrls");
3533
3590
  const hasCustomBackend = Boolean(collectApiUrls?.custom);
@@ -3880,102 +3937,6 @@ var init_event_manager = __esm({
3880
3937
  log("warn", "Failed to cleanup expired session counts", { error });
3881
3938
  }
3882
3939
  }
3883
- /**
3884
- * Returns the referrer if it's external, or 'Direct' if internal/empty.
3885
- *
3886
- * **Purpose**: Filter out internal referrers (same domain) to ensure
3887
- * accurate traffic source attribution. Internal referrers occur when:
3888
- * - Session expires and user navigates within the same site
3889
- * - User opens new tab from an internal link
3890
- * - Page refresh after session timeout
3891
- *
3892
- * **Logic**:
3893
- * - Empty referrer → 'Direct'
3894
- * - Referrer from same domain or subdomain → 'Direct' (internal navigation)
3895
- * - External referrer → Returns original referrer
3896
- *
3897
- * **Subdomain Detection**:
3898
- * - `www.example.com` → `example.com` ✓ (internal)
3899
- * - `blog.example.com` → `example.com` ✓ (internal)
3900
- * - `example.com` → `www.example.com` ✓ (internal)
3901
- *
3902
- * @returns External referrer URL or 'Direct'
3903
- *
3904
- * @internal
3905
- */
3906
- getExternalReferrer() {
3907
- const referrer = document.referrer;
3908
- if (!referrer) {
3909
- return "Direct";
3910
- }
3911
- try {
3912
- const referrerHostname = new URL(referrer).hostname.toLowerCase();
3913
- const currentHostname = window.location.hostname.toLowerCase();
3914
- if (this.isSameDomain(referrerHostname, currentHostname)) {
3915
- return "Direct";
3916
- }
3917
- return referrer;
3918
- } catch (error) {
3919
- log("debug", "Failed to parse referrer URL, using raw value", { error, data: { referrer } });
3920
- return referrer;
3921
- }
3922
- }
3923
- /**
3924
- * Checks if two hostnames belong to the same domain (including subdomains).
3925
- * Extracts root domain and compares to handle cross-subdomain navigation.
3926
- *
3927
- * @example
3928
- * isSameDomain('www.example.com', 'example.com') // true
3929
- * isSameDomain('app.example.com', 'www.example.com') // true
3930
- * isSameDomain('example.co.uk', 'app.example.co.uk') // true
3931
- *
3932
- * @param hostname1 - First hostname (e.g., 'www.example.com')
3933
- * @param hostname2 - Second hostname (e.g., 'app.example.com')
3934
- * @returns true if same root domain
3935
- *
3936
- * @internal
3937
- */
3938
- isSameDomain(hostname1, hostname2) {
3939
- if (hostname1 === hostname2) {
3940
- return true;
3941
- }
3942
- return this.getRootDomain(hostname1) === this.getRootDomain(hostname2);
3943
- }
3944
- /**
3945
- * Extracts the root (registrable) domain from a hostname.
3946
- * Handles both standard TLDs (.com, .org) and compound TLDs (.co.uk, .com.br).
3947
- *
3948
- * @example
3949
- * getRootDomain('www.example.com') // 'example.com'
3950
- * getRootDomain('app.blog.example.com') // 'example.com'
3951
- * getRootDomain('shop.example.co.uk') // 'example.co.uk'
3952
- *
3953
- * @internal
3954
- */
3955
- getRootDomain(hostname) {
3956
- const parts = hostname.toLowerCase().split(".");
3957
- if (parts.length <= 2) {
3958
- return hostname.toLowerCase();
3959
- }
3960
- const compoundTlds = [
3961
- "co.uk",
3962
- "org.uk",
3963
- "com.au",
3964
- "net.au",
3965
- "com.br",
3966
- "co.nz",
3967
- "co.jp",
3968
- "com.mx",
3969
- "co.in",
3970
- "com.cn",
3971
- "co.za"
3972
- ];
3973
- const lastTwo = parts.slice(-2).join(".");
3974
- if (compoundTlds.includes(lastTwo)) {
3975
- return parts.slice(-3).join(".");
3976
- }
3977
- return parts.slice(-2).join(".");
3978
- }
3979
3940
  /**
3980
3941
  * Persists current session event counts to localStorage (debounced).
3981
3942
  *
@@ -4152,10 +4113,12 @@ var init_session_manager = __esm({
4152
4113
  }
4153
4114
  return storedSession.id;
4154
4115
  }
4155
- persistSession(sessionId, lastActivity = Date.now()) {
4116
+ persistSession(sessionId, lastActivity = Date.now(), referrer, utm) {
4156
4117
  this.saveStoredSession({
4157
4118
  id: sessionId,
4158
- lastActivity
4119
+ lastActivity,
4120
+ ...referrer && { referrer },
4121
+ ...utm && { utm }
4159
4122
  });
4160
4123
  }
4161
4124
  clearStoredSession() {
@@ -4247,17 +4210,31 @@ var init_session_manager = __esm({
4247
4210
  }
4248
4211
  const recoveredSessionId = this.recoverSession();
4249
4212
  const sessionId = recoveredSessionId ?? this.generateSessionId();
4213
+ let sessionReferrer;
4214
+ let sessionUtm;
4215
+ if (recoveredSessionId) {
4216
+ const storedSession = this.loadStoredSession();
4217
+ sessionReferrer = storedSession?.referrer ?? getExternalReferrer();
4218
+ sessionUtm = storedSession?.utm ?? getUTMParameters();
4219
+ } else {
4220
+ sessionReferrer = getExternalReferrer();
4221
+ sessionUtm = getUTMParameters();
4222
+ }
4250
4223
  log("debug", "Session tracking initialized", {
4251
4224
  data: {
4252
4225
  sessionId,
4253
4226
  wasRecovered: !!recoveredSessionId,
4254
- willEmitSessionStart: true
4227
+ willEmitSessionStart: true,
4228
+ sessionReferrer,
4229
+ hasUtm: !!sessionUtm
4255
4230
  }
4256
4231
  });
4257
4232
  this.isTracking = true;
4258
4233
  try {
4259
4234
  this.set("sessionId", sessionId);
4260
- this.persistSession(sessionId);
4235
+ this.set("sessionReferrer", sessionReferrer);
4236
+ this.set("sessionUtm", sessionUtm);
4237
+ this.persistSession(sessionId, Date.now(), sessionReferrer, sessionUtm);
4261
4238
  this.initCrossTabSync();
4262
4239
  this.shareSession(sessionId);
4263
4240
  log("debug", "Emitting SESSION_START event", {
@@ -4293,7 +4270,7 @@ var init_session_manager = __esm({
4293
4270
  this.setupSessionTimeout();
4294
4271
  const sessionId = this.get("sessionId");
4295
4272
  if (sessionId) {
4296
- this.persistSession(sessionId);
4273
+ this.persistSession(sessionId, Date.now(), this.get("sessionReferrer"), this.get("sessionUtm"));
4297
4274
  }
4298
4275
  }
4299
4276
  clearSessionTimeout() {
@@ -4348,6 +4325,8 @@ var init_session_manager = __esm({
4348
4325
  this.clearStoredSession();
4349
4326
  this.set("sessionId", null);
4350
4327
  this.set("hasStartSession", false);
4328
+ this.set("sessionReferrer", void 0);
4329
+ this.set("sessionUtm", void 0);
4351
4330
  this.isTracking = false;
4352
4331
  }
4353
4332
  /**