@cross-deck/web 1.11.1 → 1.12.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.
package/dist/react.mjs CHANGED
@@ -72,7 +72,7 @@ function typeMapForStatus(status) {
72
72
  }
73
73
 
74
74
  // src/_version.ts
75
- var SDK_VERSION = "1.11.1";
75
+ var SDK_VERSION = "1.12.1";
76
76
  var SDK_NAME = "@cross-deck/web";
77
77
 
78
78
  // src/http.ts
@@ -1562,6 +1562,7 @@ var AutoTracker = class {
1562
1562
  this.pageviewId = null;
1563
1563
  this.storage = opts?.storage ?? null;
1564
1564
  this.sessionKey = opts?.storageKey ?? SESSION_STORAGE_KEY;
1565
+ this.cookieStorage = opts?.cookieStorage ?? null;
1565
1566
  }
1566
1567
  install() {
1567
1568
  if (!isBrowserSafe()) return;
@@ -1713,9 +1714,74 @@ var AutoTracker = class {
1713
1714
  lastActivityAt: now,
1714
1715
  hiddenAt: null,
1715
1716
  endedSent: false,
1716
- acquisition: captureAcquisition()
1717
+ acquisition: this.resolveAcquisition()
1717
1718
  };
1718
1719
  }
1720
+ /**
1721
+ * Session acquisition, with FIRST-TOUCH survival across sessions.
1722
+ *
1723
+ * WHY: `captureAcquisition()` reads the CURRENT page. That is correct for a
1724
+ * fresh arrival, but a session boundary (30-min idle, or a return visit next
1725
+ * week) starts a new session — and a visitor returning directly has no utm_*
1726
+ * and no click id, so the acquisition that actually WON them was silently
1727
+ * replaced with empty. Someone who arrives from LinkedIn on Monday, returns
1728
+ * direct on Tuesday and signs up on Wednesday converted with no source at all.
1729
+ *
1730
+ * That is exactly the question the product exists to answer — "where did this
1731
+ * PAYING CUSTOMER come from" — so origin has to outlive the session that
1732
+ * captured it. We persist the first touch that carried a real signal and,
1733
+ * whenever a later session arrives with nothing, fall back to it.
1734
+ *
1735
+ * Deliberately NOT last-touch-wins: a real new campaign click overwrites
1736
+ * nothing, it simply records a newer touch for that session while the stored
1737
+ * first touch stays put. Write-once by design.
1738
+ */
1739
+ resolveAcquisition() {
1740
+ const current = captureAcquisition();
1741
+ if (!this.storage && !this.cookieStorage) return current;
1742
+ const key = `${this.sessionKey}_origin_first`;
1743
+ const readFirstTouch = () => {
1744
+ try {
1745
+ const v = this.storage?.getItem(key);
1746
+ if (v) return v;
1747
+ } catch {
1748
+ }
1749
+ try {
1750
+ return this.cookieStorage?.getItem(key) ?? null;
1751
+ } catch {
1752
+ return null;
1753
+ }
1754
+ };
1755
+ const writeFirstTouch = (v) => {
1756
+ try {
1757
+ this.storage?.setItem(key, v);
1758
+ } catch {
1759
+ }
1760
+ try {
1761
+ this.cookieStorage?.setItem(key, v);
1762
+ } catch {
1763
+ }
1764
+ };
1765
+ const hasSignal = (a) => Boolean(a.utm_source || a.utm_medium || a.utm_campaign || a.utm_content || a.utm_term || a.gclid || a.fbclid || a.msclkid || a.ttclid || a.li_fat_id || a.twclid);
1766
+ try {
1767
+ if (hasSignal(current)) {
1768
+ if (readFirstTouch() === null) writeFirstTouch(JSON.stringify(current));
1769
+ return current;
1770
+ }
1771
+ const raw = readFirstTouch();
1772
+ if (raw) {
1773
+ const stored = JSON.parse(raw);
1774
+ return {
1775
+ ...EMPTY_ACQUISITION,
1776
+ ...stored,
1777
+ // Referrer always describes THIS visit, never the remembered one.
1778
+ referrer: current.referrer
1779
+ };
1780
+ }
1781
+ } catch {
1782
+ }
1783
+ return current;
1784
+ }
1719
1785
  /**
1720
1786
  * Read the persisted session continuity record. Returns null on no
1721
1787
  * storage, no record, malformed JSON, or a record missing its required
@@ -2711,7 +2777,7 @@ var BreadcrumbBuffer = class {
2711
2777
 
2712
2778
  // src/_diagnostic-telemetry.ts
2713
2779
  var DIAGNOSTIC_TELEMETRY_ENDPOINT = "https://api.cross-deck.com/v1/events";
2714
- var DIAGNOSTIC_TELEMETRY_PUBLISHABLE_KEY = "cd_pub_live_9490e7aa029c432abf";
2780
+ var DIAGNOSTIC_TELEMETRY_PUBLISHABLE_KEY = "cd_pub_live_eea2f84dbb834a45b7";
2715
2781
  function isDiagnosticTelemetryEnabled() {
2716
2782
  return !DIAGNOSTIC_TELEMETRY_PUBLISHABLE_KEY.startsWith(
2717
2783
  "cd_pub_RELIABILITY_PLACEHOLDER"
@@ -4762,7 +4828,15 @@ var CrossdeckClient = class {
4762
4828
  // a visit survives full-page navigations (multi-page sites
4763
4829
  // re-install the SDK on every page) and honours the same consent
4764
4830
  // posture — MemoryStorage when identity persistence is off.
4765
- { storage: effectiveStorage, storageKey: opts.storagePrefix + "session" }
4831
+ // cookieStorage is the SAME registrable-domain cookie identity uses.
4832
+ // First-touch origin rides it so the campaign that won a visitor on the
4833
+ // marketing site is still known when they land on the app subdomain —
4834
+ // localStorage alone is per-origin and would lose it at exactly that hop.
4835
+ {
4836
+ storage: effectiveStorage,
4837
+ storageKey: opts.storagePrefix + "session",
4838
+ cookieStorage: cookieStore ?? void 0
4839
+ }
4766
4840
  );
4767
4841
  this.state.autoTracker = tracker;
4768
4842
  tracker.install();
@@ -5608,7 +5682,7 @@ var CrossdeckClient = class {
5608
5682
  }
5609
5683
  }
5610
5684
  this.state.autoTracker?.uninstall();
5611
- this.state.identity.reset();
5685
+ if (this.state.developerUserId) this.state.identity.reset();
5612
5686
  bridgeReadCost({ actor: void 0 });
5613
5687
  this.state.entitlements.clearAll();
5614
5688
  this.state.events.reset();