@tracelog/lib 2.1.0 → 2.1.1

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.
@@ -720,7 +720,7 @@ var init_performance_constants = __esm({
720
720
  var version;
721
721
  var init_package = __esm({
722
722
  "package.json"() {
723
- version = "2.0.3";
723
+ version = "2.1.0";
724
724
  }
725
725
  });
726
726
 
@@ -3520,7 +3520,7 @@ var init_event_manager = __esm({
3520
3520
  type: data.type,
3521
3521
  page_url: currentPageUrl,
3522
3522
  timestamp,
3523
- ...isSessionStart && { referrer: document.referrer || "Direct" },
3523
+ ...isSessionStart && { referrer: this.getExternalReferrer() },
3524
3524
  ...data.from_page_url && { from_page_url: data.from_page_url },
3525
3525
  ...data.scroll_data && { scroll_data: data.scroll_data },
3526
3526
  ...data.click_data && { click_data: data.click_data },
@@ -3882,6 +3882,102 @@ var init_event_manager = __esm({
3882
3882
  log("warn", "Failed to cleanup expired session counts", { error });
3883
3883
  }
3884
3884
  }
3885
+ /**
3886
+ * Returns the referrer if it's external, or 'Direct' if internal/empty.
3887
+ *
3888
+ * **Purpose**: Filter out internal referrers (same domain) to ensure
3889
+ * accurate traffic source attribution. Internal referrers occur when:
3890
+ * - Session expires and user navigates within the same site
3891
+ * - User opens new tab from an internal link
3892
+ * - Page refresh after session timeout
3893
+ *
3894
+ * **Logic**:
3895
+ * - Empty referrer → 'Direct'
3896
+ * - Referrer from same domain or subdomain → 'Direct' (internal navigation)
3897
+ * - External referrer → Returns original referrer
3898
+ *
3899
+ * **Subdomain Detection**:
3900
+ * - `www.example.com` → `example.com` ✓ (internal)
3901
+ * - `blog.example.com` → `example.com` ✓ (internal)
3902
+ * - `example.com` → `www.example.com` ✓ (internal)
3903
+ *
3904
+ * @returns External referrer URL or 'Direct'
3905
+ *
3906
+ * @internal
3907
+ */
3908
+ getExternalReferrer() {
3909
+ const referrer = document.referrer;
3910
+ if (!referrer) {
3911
+ return "Direct";
3912
+ }
3913
+ try {
3914
+ const referrerHostname = new URL(referrer).hostname.toLowerCase();
3915
+ const currentHostname = window.location.hostname.toLowerCase();
3916
+ if (this.isSameDomain(referrerHostname, currentHostname)) {
3917
+ return "Direct";
3918
+ }
3919
+ return referrer;
3920
+ } catch (error) {
3921
+ log("debug", "Failed to parse referrer URL, using raw value", { error, data: { referrer } });
3922
+ return referrer;
3923
+ }
3924
+ }
3925
+ /**
3926
+ * Checks if two hostnames belong to the same domain (including subdomains).
3927
+ * Extracts root domain and compares to handle cross-subdomain navigation.
3928
+ *
3929
+ * @example
3930
+ * isSameDomain('www.example.com', 'example.com') // true
3931
+ * isSameDomain('app.example.com', 'www.example.com') // true
3932
+ * isSameDomain('example.co.uk', 'app.example.co.uk') // true
3933
+ *
3934
+ * @param hostname1 - First hostname (e.g., 'www.example.com')
3935
+ * @param hostname2 - Second hostname (e.g., 'app.example.com')
3936
+ * @returns true if same root domain
3937
+ *
3938
+ * @internal
3939
+ */
3940
+ isSameDomain(hostname1, hostname2) {
3941
+ if (hostname1 === hostname2) {
3942
+ return true;
3943
+ }
3944
+ return this.getRootDomain(hostname1) === this.getRootDomain(hostname2);
3945
+ }
3946
+ /**
3947
+ * Extracts the root (registrable) domain from a hostname.
3948
+ * Handles both standard TLDs (.com, .org) and compound TLDs (.co.uk, .com.br).
3949
+ *
3950
+ * @example
3951
+ * getRootDomain('www.example.com') // 'example.com'
3952
+ * getRootDomain('app.blog.example.com') // 'example.com'
3953
+ * getRootDomain('shop.example.co.uk') // 'example.co.uk'
3954
+ *
3955
+ * @internal
3956
+ */
3957
+ getRootDomain(hostname) {
3958
+ const parts = hostname.toLowerCase().split(".");
3959
+ if (parts.length <= 2) {
3960
+ return hostname.toLowerCase();
3961
+ }
3962
+ const compoundTlds = [
3963
+ "co.uk",
3964
+ "org.uk",
3965
+ "com.au",
3966
+ "net.au",
3967
+ "com.br",
3968
+ "co.nz",
3969
+ "co.jp",
3970
+ "com.mx",
3971
+ "co.in",
3972
+ "com.cn",
3973
+ "co.za"
3974
+ ];
3975
+ const lastTwo = parts.slice(-2).join(".");
3976
+ if (compoundTlds.includes(lastTwo)) {
3977
+ return parts.slice(-3).join(".");
3978
+ }
3979
+ return parts.slice(-2).join(".");
3980
+ }
3885
3981
  /**
3886
3982
  * Persists current session event counts to localStorage (debounced).
3887
3983
  *