@hifilabs/pixel 0.16.4 → 0.16.6

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/browser.js CHANGED
@@ -8,7 +8,7 @@ var ArtistPixel = (() => {
8
8
 
9
9
  // src/browser.ts
10
10
  (function() {
11
- const PIXEL_VERSION = "0.16.4";
11
+ const PIXEL_VERSION = "0.16.6";
12
12
  function parseUserAgent(ua) {
13
13
  let device_type = "desktop";
14
14
  if (/ipad|tablet|android(?!.*mobile)/i.test(ua))
@@ -207,6 +207,7 @@ var ArtistPixel = (() => {
207
207
  }
208
208
  const PIXEL_PROXY_URL = "https://e.os.xyz";
209
209
  const FIREBASE_DIRECT_URL = "https://us-central1-artist-os-distro.cloudfunctions.net/ingestEvents";
210
+ const HASH_IDENTITY_ENDPOINT = "https://us-central1-artist-os-distro.cloudfunctions.net/identityHashIdentity";
210
211
  const API_ENDPOINT = customEndpoint ? customEndpoint : useEmulator ? `http://localhost:5001/artist-os-distro/us-central1/ingestEvents` : PIXEL_PROXY_URL;
211
212
  let sessionId = null;
212
213
  let visitorId = null;
@@ -1069,7 +1070,7 @@ var ArtistPixel = (() => {
1069
1070
  const normalizedUrl = normalizeUrlForRegistry(url);
1070
1071
  return linkRegistry[normalizedUrl] || null;
1071
1072
  }
1072
- async function hashEmail(email) {
1073
+ async function hashEmailLocal(email) {
1073
1074
  const normalized = email.toLowerCase().trim();
1074
1075
  const encoder = new TextEncoder();
1075
1076
  const data = encoder.encode(normalized);
@@ -1077,6 +1078,31 @@ var ArtistPixel = (() => {
1077
1078
  const hashArray = Array.from(new Uint8Array(hashBuffer));
1078
1079
  return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1079
1080
  }
1081
+ async function hashEmailFromServer(email) {
1082
+ if (!artistId)
1083
+ return null;
1084
+ try {
1085
+ const response = await fetch(HASH_IDENTITY_ENDPOINT, {
1086
+ method: "POST",
1087
+ headers: { "Content-Type": "application/json" },
1088
+ body: JSON.stringify({
1089
+ data: { email: email.toLowerCase().trim(), artistId }
1090
+ })
1091
+ });
1092
+ if (!response.ok) {
1093
+ log("hashIdentity endpoint failed:", response.status);
1094
+ return null;
1095
+ }
1096
+ const result = await response.json();
1097
+ return {
1098
+ hash: result.result.fanIdHash,
1099
+ version: result.result.hashVersion
1100
+ };
1101
+ } catch (error) {
1102
+ log("hashIdentity endpoint error:", error);
1103
+ return null;
1104
+ }
1105
+ }
1080
1106
  function buildEvent(partial) {
1081
1107
  const deviceInfo = getDeviceInfo();
1082
1108
  const base = {
@@ -1292,7 +1318,16 @@ var ArtistPixel = (() => {
1292
1318
  log("identify() skipped - no analytics consent");
1293
1319
  return;
1294
1320
  }
1295
- fanIdHash = await hashEmail(email);
1321
+ let hashVersion = 1;
1322
+ const serverResult = await hashEmailFromServer(email);
1323
+ if (serverResult) {
1324
+ fanIdHash = serverResult.hash;
1325
+ hashVersion = serverResult.version;
1326
+ log("identify() using server HMAC hash (v2)");
1327
+ } else {
1328
+ fanIdHash = await hashEmailLocal(email);
1329
+ log("identify() using local SHA256 hash (v1 fallback)");
1330
+ }
1296
1331
  if (consent?.analytics === true) {
1297
1332
  upgradeStorageTier();
1298
1333
  }
@@ -1309,6 +1344,7 @@ var ArtistPixel = (() => {
1309
1344
  name: traits.name || "(no name)",
1310
1345
  email: maskedEmail,
1311
1346
  hash: fanIdHash.substring(0, 16) + "...",
1347
+ hashVersion,
1312
1348
  traits,
1313
1349
  storageTier: currentStorageTier
1314
1350
  });
@@ -1320,6 +1356,7 @@ var ArtistPixel = (() => {
1320
1356
  email_sha256: fanIdHash,
1321
1357
  email_display: maskedEmail,
1322
1358
  // Safe for UI display (e.g., "j***@example.com")
1359
+ hash_version: hashVersion,
1323
1360
  traits,
1324
1361
  consent_preferences: consent || void 0,
1325
1362
  storage_tier: currentStorageTier
@@ -1,4 +1,4 @@
1
- var ArtistPixel=(()=>{var Ue=Object.defineProperty;var Fe=(_,k,v)=>k in _?Ue(_,k,{enumerable:!0,configurable:!0,writable:!0,value:v}):_[k]=v;var K=(_,k,v)=>(Fe(_,typeof k!="symbol"?k+"":k,v),v);(function(){let _="0.16.4";function k(t){let e="desktop";/ipad|tablet|android(?!.*mobile)/i.test(t)?e="tablet":/mobile|iphone|android.*mobile|blackberry|iemobile/i.test(t)&&(e="mobile");let n="Unknown";/edg/i.test(t)?n="Edge":/opr|opera/i.test(t)?n="Opera":/firefox/i.test(t)?n="Firefox":/chrome/i.test(t)?n="Chrome":/safari/i.test(t)&&(n="Safari");let o="Unknown";return/iphone|ipad/i.test(t)?o="iOS":/android/i.test(t)?o="Android":/windows/i.test(t)?o="Windows":/mac os/i.test(t)?o="macOS":/linux/i.test(t)?o="Linux":/cros/i.test(t)&&(o="ChromeOS"),{device_type:e,browser:n,os:o}}let v=null;function Kt(){if(!v)try{v=k(navigator.userAgent)}catch{v={device_type:"desktop",browser:"Unknown",os:"Unknown"}}return v}let r=document.currentScript,Y=r?.dataset.artistId,J=r?.dataset.projectId,X=J?Yt(J):void 0;function Yt(t){return!t||t.startsWith("release_")||t.startsWith("merch_")||t.startsWith("link_")||t.startsWith("custom_")?t:`custom_${t}`}let Q=r?.dataset.emulator==="true",ht=r?.dataset.debug==="true",Z=parseInt(r?.dataset.heartbeatInterval||"120000",10),bt=r?.dataset.heartbeat!=="false",vt=r?.dataset.source,_t=r?.dataset.endpoint,f=window.__artistPixelConfig||{},O=r?.dataset.metaPixelId||f.metaPixelId,L=r?.dataset.tiktokPixelId||f.tiktokPixelId,p=r?.dataset.googleAdsId||f.googleAdsId,kt=r?.dataset.googleAdsConversionLabel||f.googleAdsConversionLabel,j=r?.dataset.googleTagManagerId||f.googleTagManagerId,y=r?.dataset.googleAnalyticsId||f.googleAnalyticsId,m={pageview:(r?.dataset.forwardPageview??f.forwardPageview)!=="false",purchase:(r?.dataset.forwardPurchase??f.forwardPurchase)!=="false",addToCart:(r?.dataset.forwardAddToCart??f.forwardAddToCart)!=="false",lead:(r?.dataset.forwardLead??f.forwardLead)!=="false",viewContent:(r?.dataset.forwardViewContent??f.forwardViewContent)!=="false",initiateCheckout:(r?.dataset.forwardInitiateCheckout??f.forwardInitiateCheckout)!=="false",completeRegistration:(r?.dataset.forwardCompleteRegistration??f.forwardCompleteRegistration)!=="false",subscribe:(r?.dataset.forwardSubscribe??f.forwardSubscribe)!=="false",search:(r?.dataset.forwardSearch??f.forwardSearch)!=="false",contact:(r?.dataset.forwardContact??f.forwardContact)!=="false",custom:(r?.dataset.forwardCustom||f.forwardCustom||"").split(",").filter(Boolean)},U=!!(O||L||p||j||y),tt=r?.dataset.consentUi==="true",Jt=r?.dataset.consentStyle||"brutalist",Xt=r?.dataset.primaryColor,Qt=r?.dataset.bannerPosition||"bottom",It=r?.dataset.excludePages?.split(",").filter(Boolean)||[],xt=r?.dataset.trackFileDownloads==="true",Zt=r?.dataset.hashRouting==="true";function te(){if(vt)return vt;let t=typeof window.dataLayer<"u"&&Array.isArray(window.dataLayer),e=typeof window.gtag=="function";return t&&e?"gtm":"pixel"}let V="pixel";if(!Y){S(" Error: data-artist-id attribute is required");return}let Ct="session_id",et="session_timestamp",St="attribution",h="fan_id_hash",nt="visitor_id",G="artistPixel_consent",ee=365*24*60*60*1e3,ne=30*24*60*60*1e3,ae=60*60*1e3,w="balance_";function oe(t){let e=t.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp("^"+e+"$")}function ie(t){if(It.length===0)return!1;try{let e=new URL(t,window.location.origin).pathname;return It.some(n=>oe(n).test(e))}catch{return!1}}let re=[".pdf",".zip",".tar",".gz",".rar",".7z",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".mp3",".wav",".flac",".aac",".ogg",".mp4",".mov",".avi",".mkv",".webm",".exe",".dmg",".pkg",".deb",".rpm",".csv",".json",".xml",".txt"];function Pt(t){try{let e=new URL(t,window.location.origin).pathname.toLowerCase();return re.some(n=>e.endsWith(n))}catch{return!1}}function se(t,e){try{let o=new URL(t,window.location.origin).pathname.split("/").pop()||"unknown",d=o.includes(".")?o.split(".").pop():"unknown";a("File download tracked:",{url:t,fileName:o,fileExtension:d});let l=P({event_name:"custom",metadata:{event_type:"file_download",file_url:t,file_name:o,file_extension:d,link_text:e?.textContent?.trim().substring(0,100)||""}});E(l)}catch(n){S("Failed to track file download:",n)}}let ce="https://e.os.xyz",Et="https://us-central1-artist-os-distro.cloudfunctions.net/ingestEvents",A=_t||(Q?"http://localhost:5001/artist-os-distro/us-central1/ingestEvents":ce),F=null,b=null,g=null,c=null,R={},at={},I=[],ot=null,x="session",D=null,it=0,rt=0,M=0,q=!0,st=0,ct=!1,de=2*60*1e3,Tt=Date.now(),z=!1,le=!ht,a=(...t)=>{ht&&console.log("[artistPixel]",...t)},S=(...t)=>{le||console.error("[artistPixel]",...t)},dt={base:`
1
+ var ArtistPixel=(()=>{var qe=Object.defineProperty;var Ne=(_,k,v)=>k in _?qe(_,k,{enumerable:!0,configurable:!0,writable:!0,value:v}):_[k]=v;var J=(_,k,v)=>(Ne(_,typeof k!="symbol"?k+"":k,v),v);(function(){let _="0.16.6";function k(t){let e="desktop";/ipad|tablet|android(?!.*mobile)/i.test(t)?e="tablet":/mobile|iphone|android.*mobile|blackberry|iemobile/i.test(t)&&(e="mobile");let n="Unknown";/edg/i.test(t)?n="Edge":/opr|opera/i.test(t)?n="Opera":/firefox/i.test(t)?n="Firefox":/chrome/i.test(t)?n="Chrome":/safari/i.test(t)&&(n="Safari");let o="Unknown";return/iphone|ipad/i.test(t)?o="iOS":/android/i.test(t)?o="Android":/windows/i.test(t)?o="Windows":/mac os/i.test(t)?o="macOS":/linux/i.test(t)?o="Linux":/cros/i.test(t)&&(o="ChromeOS"),{device_type:e,browser:n,os:o}}let v=null;function Yt(){if(!v)try{v=k(navigator.userAgent)}catch{v={device_type:"desktop",browser:"Unknown",os:"Unknown"}}return v}let s=document.currentScript,O=s?.dataset.artistId,K=s?.dataset.projectId,X=K?Jt(K):void 0;function Jt(t){return!t||t.startsWith("release_")||t.startsWith("merch_")||t.startsWith("link_")||t.startsWith("custom_")?t:`custom_${t}`}let Q=s?.dataset.emulator==="true",yt=s?.dataset.debug==="true",Z=parseInt(s?.dataset.heartbeatInterval||"120000",10),bt=s?.dataset.heartbeat!=="false",vt=s?.dataset.source,_t=s?.dataset.endpoint,f=window.__artistPixelConfig||{},j=s?.dataset.metaPixelId||f.metaPixelId,L=s?.dataset.tiktokPixelId||f.tiktokPixelId,p=s?.dataset.googleAdsId||f.googleAdsId,kt=s?.dataset.googleAdsConversionLabel||f.googleAdsConversionLabel,U=s?.dataset.googleTagManagerId||f.googleTagManagerId,h=s?.dataset.googleAnalyticsId||f.googleAnalyticsId,m={pageview:(s?.dataset.forwardPageview??f.forwardPageview)!=="false",purchase:(s?.dataset.forwardPurchase??f.forwardPurchase)!=="false",addToCart:(s?.dataset.forwardAddToCart??f.forwardAddToCart)!=="false",lead:(s?.dataset.forwardLead??f.forwardLead)!=="false",viewContent:(s?.dataset.forwardViewContent??f.forwardViewContent)!=="false",initiateCheckout:(s?.dataset.forwardInitiateCheckout??f.forwardInitiateCheckout)!=="false",completeRegistration:(s?.dataset.forwardCompleteRegistration??f.forwardCompleteRegistration)!=="false",subscribe:(s?.dataset.forwardSubscribe??f.forwardSubscribe)!=="false",search:(s?.dataset.forwardSearch??f.forwardSearch)!=="false",contact:(s?.dataset.forwardContact??f.forwardContact)!=="false",custom:(s?.dataset.forwardCustom||f.forwardCustom||"").split(",").filter(Boolean)},F=!!(j||L||p||U||h),tt=s?.dataset.consentUi==="true",Kt=s?.dataset.consentStyle||"brutalist",Xt=s?.dataset.primaryColor,Qt=s?.dataset.bannerPosition||"bottom",It=s?.dataset.excludePages?.split(",").filter(Boolean)||[],xt=s?.dataset.trackFileDownloads==="true",Zt=s?.dataset.hashRouting==="true";function te(){if(vt)return vt;let t=typeof window.dataLayer<"u"&&Array.isArray(window.dataLayer),e=typeof window.gtag=="function";return t&&e?"gtm":"pixel"}let G="pixel";if(!O){S(" Error: data-artist-id attribute is required");return}let Ct="session_id",et="session_timestamp",St="attribution",y="fan_id_hash",nt="visitor_id",B="artistPixel_consent",ee=365*24*60*60*1e3,ne=30*24*60*60*1e3,ae=60*60*1e3,w="balance_";function oe(t){let e=t.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp("^"+e+"$")}function ie(t){if(It.length===0)return!1;try{let e=new URL(t,window.location.origin).pathname;return It.some(n=>oe(n).test(e))}catch{return!1}}let re=[".pdf",".zip",".tar",".gz",".rar",".7z",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".mp3",".wav",".flac",".aac",".ogg",".mp4",".mov",".avi",".mkv",".webm",".exe",".dmg",".pkg",".deb",".rpm",".csv",".json",".xml",".txt"];function Pt(t){try{let e=new URL(t,window.location.origin).pathname.toLowerCase();return re.some(n=>e.endsWith(n))}catch{return!1}}function se(t,e){try{let o=new URL(t,window.location.origin).pathname.split("/").pop()||"unknown",c=o.includes(".")?o.split(".").pop():"unknown";a("File download tracked:",{url:t,fileName:o,fileExtension:c});let d=P({event_name:"custom",metadata:{event_type:"file_download",file_url:t,file_name:o,file_extension:c,link_text:e?.textContent?.trim().substring(0,100)||""}});E(d)}catch(n){S("Failed to track file download:",n)}}let ce="https://e.os.xyz",Et="https://us-central1-artist-os-distro.cloudfunctions.net/ingestEvents",de="https://us-central1-artist-os-distro.cloudfunctions.net/identityHashIdentity",A=_t||(Q?"http://localhost:5001/artist-os-distro/us-central1/ingestEvents":ce),q=null,b=null,g=null,l=null,R={},at={},I=[],ot=null,x="session",D=null,it=0,rt=0,M=0,N=!0,st=0,ct=!1,le=2*60*1e3,Tt=Date.now(),H=!1,ge=!yt,a=(...t)=>{yt&&console.log("[artistPixel]",...t)},S=(...t)=>{ge||console.error("[artistPixel]",...t)},dt={base:`
2
2
  :host {
3
3
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4
4
  position: fixed;
@@ -83,12 +83,12 @@ var ArtistPixel=(()=>{var Ue=Object.defineProperty;var Fe=(_,k,v)=>k in _?Ue(_,k
83
83
  }
84
84
  .btn.accept { background: #fff; color: #000; border-color: #fff; }
85
85
  .btn:hover { opacity: 0.8; }
86
- `};class ge{constructor(e){K(this,"container",null);K(this,"shadow",null);K(this,"config");if(this.config=e,this.hasStoredConsent()){a("ConsentManager: Consent already exists, not showing banner");return}this.container=document.createElement("div"),this.container.id="artistPixel-consent-manager",this.shadow=this.container.attachShadow({mode:"closed"}),this.render(),document.body.appendChild(this.container),a("ConsentManager: Banner rendered")}hasStoredConsent(){try{return window._balanceConsentNeedsRefresh?!1:localStorage.getItem(G)!==null}catch{return!1}}render(){if(!this.shadow)return;let e=this.config.style||"brutalist",n=dt.base,o=dt[e]||dt.brutalist,d=this.config.position==="top"?"top: 0;":"bottom: 0;",l=this.config.primaryColor?`.btn.accept { background: ${this.config.primaryColor} !important; border-color: ${this.config.primaryColor} !important; color: #fff !important; }`:"";this.shadow.innerHTML=`
86
+ `};class ue{constructor(e){J(this,"container",null);J(this,"shadow",null);J(this,"config");if(this.config=e,this.hasStoredConsent()){a("ConsentManager: Consent already exists, not showing banner");return}this.container=document.createElement("div"),this.container.id="artistPixel-consent-manager",this.shadow=this.container.attachShadow({mode:"closed"}),this.render(),document.body.appendChild(this.container),a("ConsentManager: Banner rendered")}hasStoredConsent(){try{return window._balanceConsentNeedsRefresh?!1:localStorage.getItem(B)!==null}catch{return!1}}render(){if(!this.shadow)return;let e=this.config.style||"brutalist",n=dt.base,o=dt[e]||dt.brutalist,c=this.config.position==="top"?"top: 0;":"bottom: 0;",d=this.config.primaryColor?`.btn.accept { background: ${this.config.primaryColor} !important; border-color: ${this.config.primaryColor} !important; color: #fff !important; }`:"";this.shadow.innerHTML=`
87
87
  <style>
88
88
  ${n}
89
- :host { ${d} }
89
+ :host { ${c} }
90
90
  ${o}
91
- ${l}
91
+ ${d}
92
92
  </style>
93
93
  <div class="banner" role="dialog" aria-label="Cookie consent" aria-modal="false">
94
94
  <p class="text">
@@ -99,4 +99,4 @@ var ArtistPixel=(()=>{var Ue=Object.defineProperty;var Fe=(_,k,v)=>k in _?Ue(_,k
99
99
  <button id="accept" class="btn accept">Accept</button>
100
100
  </div>
101
101
  </div>
102
- `,this.shadow.getElementById("accept")?.addEventListener("click",()=>this.handleConsent(!0)),this.shadow.getElementById("decline")?.addEventListener("click",()=>this.handleConsent(!1))}handleConsent(e){window.balance?.setConsent&&window.balance.setConsent({analytics:e,marketing:e,personalization:e,timestamp:new Date().toISOString()}),e&&!window._balanceInitialPageviewFired&&(window._balanceInitialPageviewFired=!0,window.balance?.page&&window.balance.page(),ft(),a("Initial pageview fired after consent granted")),this.remove()}remove(){this.container&&(this.container.remove(),this.container=null,this.shadow=null,a("ConsentManager: Banner removed"))}}let Lt=!1,N=!1;function ue(){if(!O)return;if(window.fbq){a("[Platform:Meta] Already loaded, skipping");return}a("[Platform:Meta] Injecting pixel:",O);let t=function(...n){t.callMethod?t.callMethod.apply(t,n):t.queue.push(n)};window._fbq||(window._fbq=t),t.push=t,t.loaded=!0,t.version="2.0",t.queue=[],window.fbq=t;let e=document.createElement("script");e.async=!0,e.src="https://connect.facebook.net/en_US/fbevents.js",e.onload=()=>{window.fbq("init",O),m.pageview&&window.fbq("track","PageView"),a("[Platform:Meta] Initialized and PageView tracked")},document.head.appendChild(e)}function fe(){if(!L)return;if(window.ttq?._i?.[L]){a("[Platform:TikTok] Already loaded, skipping");return}a("[Platform:TikTok] Injecting pixel:",L);let t=window,e="ttq";t.TiktokAnalyticsObject=e;let n=t[e]=t[e]||[];n.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],n.setAndDefer=function(o,d){o[d]=function(...l){o.push([d].concat(l))}};for(let o=0;o<n.methods.length;o++)n.setAndDefer(n,n.methods[o]);n.instance=function(o){let d=n._i[o]||[];for(let l=0;l<n.methods.length;l++)n.setAndDefer(d,n.methods[l]);return d},n.load=function(o){let d="https://analytics.tiktok.com/i18n/pixel/events.js";n._i=n._i||{},n._i[o]=[],n._i[o]._u=d,n._t=n._t||{},n._t[o]=+new Date,n._o=n._o||{};let l=document.createElement("script");l.type="text/javascript",l.async=!0,l.src=d+"?sdkid="+o+"&lib="+e,document.head.appendChild(l)},n.load(L),m.pageview&&n.page(),a("[Platform:TikTok] Initialized and page() tracked")}function me(){if(!p)return;if(window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(...e){window.dataLayer.push(e)}),document.querySelector('script[src*="googletagmanager.com/gtag/js"]')){a("[Platform:GoogleAds] gtag.js already loaded, configuring"),window.gtag("config",p);return}a("[Platform:GoogleAds] Injecting gtag:",p),window.gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});let t=document.createElement("script");t.async=!0,t.src=`https://www.googletagmanager.com/gtag/js?id=${p}`,t.onload=()=>{window.gtag("js",new Date),window.gtag("config",p),a("[Platform:GoogleAds] Initialized")},document.head.appendChild(t)}function we(){if(!j)return;if(document.querySelector(`script[src*="googletagmanager.com/gtm.js?id=${j}"]`)){a("[Platform:GTM] Already loaded, skipping");return}a("[Platform:GTM] Injecting GTM:",j),window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(...n){window.dataLayer.push(n)});let t=N?"granted":"denied";window.gtag("consent","default",{ad_storage:t,ad_user_data:t,ad_personalization:t,analytics_storage:t}),window.gtag("set","wait_for_update",500),window.dataLayer.push({"gtm.start":new Date().getTime(),event:"gtm.js"});let e=document.createElement("script");e.async=!0,e.src=`https://www.googletagmanager.com/gtm.js?id=${j}`,e.onload=()=>{a("[Platform:GTM] Initialized")},document.head.appendChild(e)}function pe(){if(!y)return;let t=document.querySelector('script[src*="googletagmanager.com/gtag/js"]');window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(...o){window.dataLayer.push(o)});let e=N?"granted":"denied";if(window.gtag("consent","default",{ad_storage:e,ad_user_data:e,ad_personalization:e,analytics_storage:e}),t){a("[Platform:GA4] gtag.js already loaded, configuring"),window.gtag("config",y,{send_page_view:!1});return}a("[Platform:GA4] Injecting gtag:",y);let n=document.createElement("script");n.async=!0,n.src=`https://www.googletagmanager.com/gtag/js?id=${y}`,n.onload=()=>{window.gtag("js",new Date),window.gtag("config",y,{send_page_view:!1}),a("[Platform:GA4] Initialized")},document.head.appendChild(n)}function ye(){if(U){if(Lt){a("[Platform] Already loaded, skipping");return}if(!N){a("[Platform] Marketing consent not granted, deferring");return}a("[Platform] Injecting platform pixels (consent granted)"),Lt=!0,ue(),fe(),me(),we(),pe()}}function At(t){if(N=t,a("[Platform] Marketing consent:",t?"granted":"denied"),t&&ye(),window.ttq&&(t?window.ttq.grantConsent?.():window.ttq.revokeConsent?.()),typeof window.gtag=="function"){let e=t?"granted":"denied";window.gtag("consent","update",{ad_storage:e,ad_user_data:e,ad_personalization:e,analytics_storage:e})}}function lt(t){if(!U||!N)return!1;let e=t.toLowerCase();return e==="pageview"||e==="page_view"?m.pageview:e==="purchase"?m.purchase:e==="addtocart"||e==="add_to_cart"?m.addToCart:e==="lead"||e==="form_submit"?m.lead:e==="viewcontent"||e==="view_content"?m.viewContent:e==="initiatecheckout"||e==="initiate_checkout"?m.initiateCheckout:e==="completeregistration"||e==="complete_registration"?m.completeRegistration:e==="subscribe"?m.subscribe:e==="search"?m.search:e==="contact"?m.contact:m.custom.length>0?m.custom.some(n=>n.toLowerCase()===e):!1}function he(){lt("pageview")&&(a("[Platform] Forwarding PageView"),window.fbq&&window.fbq("track","PageView"),window.ttq&&window.ttq.page(),typeof window.gtag=="function"&&y&&window.gtag("event","page_view",{send_to:y}))}function be(t,e,n){if(lt("purchase")){if(a("[Platform] Forwarding Purchase:",t,e),window.fbq&&window.fbq("track","Purchase",{value:t,currency:e,content_ids:n?.contentIds,content_type:n?.contentType||"product",order_id:n?.transactionId}),window.ttq&&window.ttq.track("CompletePayment",{value:t,currency:e,order_id:n?.transactionId}),typeof window.gtag=="function"&&p){let o=kt?`${p}/${kt}`:p;window.gtag("event","conversion",{send_to:o,value:t,currency:e,transaction_id:n?.transactionId}),window.gtag("event","purchase",{send_to:p,value:t,currency:e,transaction_id:n?.transactionId})}typeof window.gtag=="function"&&y&&window.gtag("event","purchase",{send_to:y,value:t,currency:e,transaction_id:n?.transactionId,items:n?.items})}}function ve(t,e){if(!lt(t))return;let n=t.toLowerCase();a("[Platform] Forwarding custom event:",t);let o={addtocart:"AddToCart",add_to_cart:"AddToCart",lead:"Lead",form_submit:"Lead",viewcontent:"ViewContent",view_content:"ViewContent",search:"Search",subscribe:"Subscribe",contact:"Contact",completeregistration:"CompleteRegistration",complete_registration:"CompleteRegistration",initiatecheckout:"InitiateCheckout",initiate_checkout:"InitiateCheckout"},d={addtocart:"AddToCart",add_to_cart:"AddToCart",lead:"SubmitForm",form_submit:"SubmitForm",viewcontent:"ViewContent",view_content:"ViewContent",search:"Search",subscribe:"Subscribe",contact:"Contact",completeregistration:"CompleteRegistration",complete_registration:"CompleteRegistration",initiatecheckout:"InitiateCheckout",initiate_checkout:"InitiateCheckout"},l={addtocart:"add_to_cart",add_to_cart:"add_to_cart",lead:"generate_lead",form_submit:"generate_lead",viewcontent:"view_item",view_content:"view_item",search:"search",subscribe:"subscribe",contact:"contact",completeregistration:"sign_up",complete_registration:"sign_up",initiatecheckout:"begin_checkout",initiate_checkout:"begin_checkout"};if(window.fbq){let s=o[n];s?window.fbq("track",s,e):window.fbq("trackCustom",t,e)}if(window.ttq){let s=d[n]||t;window.ttq.track(s,e)}if(typeof window.gtag=="function"&&p){let s=l[n]||t;window.gtag("event",s,{send_to:p,...e})}if(typeof window.gtag=="function"&&y){let s=l[n]||t;window.gtag("event",s,{send_to:y,...e})}}function Rt(){try{return x==="local"?localStorage:sessionStorage}catch{return null}}function B(t){let e=Rt();if(!e)return null;try{let n=w+t,o=e.getItem(n);if(!o&&x==="session")try{o=localStorage.getItem(n)}catch{}return o}catch{return null}}function T(t,e){let n=Rt();if(n)try{n.setItem(w+t,e)}catch{}}function Dt(){if(x!=="local"){a("Upgrading storage tier: session -> local");try{let t=[];for(let e=0;e<sessionStorage.length;e++){let n=sessionStorage.key(e);n?.startsWith(w)&&t.push(n)}for(let e of t){let n=sessionStorage.getItem(e);n&&localStorage.setItem(e,n)}for(let e of t)sessionStorage.removeItem(e);x="local",a(`Storage tier upgraded, migrated ${t.length} items`)}catch(t){S(" Storage migration failed:",t)}}}function W(){return crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function _e(){try{let t=B(Ct),e=B(et);if(t&&e&&Date.now()-parseInt(e,10)<ae)return T(et,Date.now().toString()),t;let n=W();return T(Ct,n),T(et,Date.now().toString()),n}catch{return W()}}function ke(){let t=new URLSearchParams(window.location.search),e={};return["source","medium","campaign","content","term"].forEach(n=>{let o=t.get(`utm_${n}`);o&&(e[`utm_${n}`]=o)}),e}function Ie(){try{let t=B(St);if(t){R=JSON.parse(t),a("Loaded attribution:",R);return}let e=ke();Object.keys(e).length>0&&(R=e,T(St,JSON.stringify(e)),a("Captured attribution:",R))}catch{}}function xe(){try{if(c?.analytics!==!0){a("Skipping fan ID load - no analytics consent");return}g=localStorage.getItem(w+h),g&&a("Loaded fan ID hash:",g.substring(0,16)+"...")}catch{if(c?.analytics===!0)try{g=B(h)}catch{}}}function gt(){try{let t=localStorage.getItem(w+nt);if(t)return t;let e=W();return localStorage.setItem(w+nt,e),a("Created persistent visitor ID:",e.substring(0,8)+"..."),e}catch{return a("localStorage unavailable, using session ID as fallback"),F||W()}}function Ce(){try{b=localStorage.getItem(w+nt),b&&a("Loaded visitor ID:",b.substring(0,8)+"...")}catch{}}function Se(){try{let t=localStorage.getItem(G);if(t){let e=JSON.parse(t);if(e.expiresAt&&Date.now()>e.expiresAt){a("Consent expired - clearing stored consent"),localStorage.removeItem(G),c=null;return}if(e.expiresAt){let n=e.expiresAt-Date.now();n>0&&n<ne&&(a("Consent nearing expiration - will prompt for refresh"),window._balanceConsentNeedsRefresh=!0)}c=e.preferences||null,a("Loaded consent:",c)}}catch{}}function Mt(t){let e=c;c=t;try{let o={preferences:t,method:"explicit",version:1,expiresAt:Date.now()+ee};localStorage.setItem(G,JSON.stringify(o)),a("Consent saved with TTL:",t),window._balanceConsentNeedsRefresh=!1}catch(o){S(" Could not save consent:",o)}if(t.analytics===!0&&(Dt(),b||(b=gt()),g))try{localStorage.setItem(w+h,g),a("Fan ID hash persisted after consent granted")}catch{T(h,g)}if(t.analytics!==!0){try{localStorage.removeItem(w+h)}catch{}try{sessionStorage.removeItem(w+h)}catch{}g=null,a("Fan ID hash cleared from storage and memory (consent revoked)")}let n=P({event_name:"consent_updated",metadata:{consent_preferences:t,consent_method:"explicit",previous_consent:e||void 0}});E(n);try{window.dispatchEvent(new CustomEvent("artistPixel:consent:updated",{detail:t})),a("DOM event artistPixel:consent:updated dispatched")}catch{}U&&At(t.marketing===!0)}function Pe(){return c}function Ee(t){return c?.[t]===!0}function Te(t){for(let[e,n]of Object.entries(t))try{let o=Ot(e);at[o]=n}catch{at[e]=n}a("Registered",Object.keys(t).length,"links for tracking enrichment")}function Ot(t){try{let e=new URL(t);return`${e.protocol}//${e.host}${e.pathname}${e.search}`}catch{return t}}function Le(t){let e=Ot(t);return at[e]||null}async function Ae(t){let e=t.toLowerCase().trim(),o=new TextEncoder().encode(e),d=await crypto.subtle.digest("SHA-256",o);return Array.from(new Uint8Array(d)).map(s=>s.toString(16).padStart(2,"0")).join("")}function P(t){let e=Kt(),n={artist_id:Y,fan_session_id:F,visitor_id:b||gt(),fan_id_hash:g||void 0,timestamp:new Date().toISOString(),source_url:window.location.href,referrer_url:document.referrer||void 0,user_agent:navigator.userAgent,device_type:e.device_type,browser:e.browser,os:e.os,tracking_source:V,...t,...R};return X&&!t.projectId&&(n.projectId=X),n}function E(t){I.push(t),a("Event queued:",t.event_name,"(queue:",I.length,")"),I.length>=10&&H()}async function H(){if(I.length===0)return;let t=[...I];I=[],a("Flushing",t.length,"events to",A);try{let e=await fetch(A,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:t}),keepalive:!0});if(!e.ok)throw new Error(`HTTP ${e.status}`);a("Events sent successfully")}catch(e){if(S(" Failed to send events, trying fallback:",e),A!==Et&&!Q)try{if((await fetch(Et,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:t}),keepalive:!0})).ok){a("Events sent via fallback (no geo)");return}}catch(n){S(" Fallback also failed:",n)}I.length<50&&I.push(...t)}}function Re(){ot&&clearInterval(ot),ot=window.setInterval(()=>{I.length>0&&H()},5e3)}function ut(){M||(it=Date.now()),M=Date.now(),q=!0,a("Active time tracking started/resumed")}function jt(){M&&q&&(rt+=Date.now()-M),q=!1,a("Active time tracking paused, accumulated:",rt,"ms")}function Ut(){let t=rt;return q&&M&&(t+=Date.now()-M),t}function De(){Tt=Date.now(),z&&(z=!1,ut(),a("User returned from idle"))}function Me(){if(document.visibilityState==="hidden"){a("Skipping heartbeat - tab hidden");return}if(Date.now()-Tt>de){z||(z=!0,jt(),a("User idle - pausing heartbeat"));return}let t=Ut(),e=Math.round(t/1e3),n=P({event_name:"engagement_heartbeat",metadata:{time_on_page_seconds:e,time_on_page_ms:t,heartbeat_interval_ms:Z,is_active:q&&!z}});E(n),st++,a("Heartbeat sent:",e,"seconds active")}function ft(){if(!bt){a('Heartbeat disabled via data-heartbeat="false"');return}D&&clearInterval(D),ut(),D=window.setInterval(()=>{Me()},Z),a("Heartbeat started with interval:",Z,"ms")}function mt(){if(!ct){if(ct=!0,D&&(clearInterval(D),D=null),bt){let t=it?Date.now()-it:0,e=Ut(),n=P({event_name:"engagement_summary",metadata:{total_time_ms:t,active_time_ms:e,heartbeat_samples:st,page_path:window.location.pathname}});if(navigator.sendBeacon&&A){let o=JSON.stringify({events:[n]});navigator.sendBeacon(A,o),a("Engagement summary sent via sendBeacon:",Math.round(e/1e3),"seconds active")}else E(n),a("Engagement summary enqueued:",Math.round(e/1e3),"seconds active")}st=0}}function $(t={}){let e=t.url||window.location.href;if(ie(e)){a("Page excluded from tracking:",e);return}let n=P({event_name:"pageview",page_title:t.title||document.title,source_url:e});E(n),he()}function wt(t,e={}){let n=P({event_name:"custom",metadata:{event_type:t,...e}});E(n),ve(t,e)}async function Ft(t,e={}){try{if(c?.analytics!==!0){a("identify() skipped - no analytics consent");return}if(g=await Ae(t),c?.analytics===!0&&Dt(),c?.analytics===!0)try{localStorage.setItem(w+h,g)}catch{T(h,g)}let n=t.split("@"),o=n[0].charAt(0)+"***@"+(n[1]||"");a("Fan identified:",{name:e.name||"(no name)",email:o,hash:g.substring(0,16)+"...",traits:e,storageTier:x});let d=P({event_name:"identify",fan_id_hash:g,metadata:{email_sha256:g,email_display:o,traits:e,consent_preferences:c||void 0,storage_tier:x}});E(d)}catch(n){S(" Failed to identify:",n)}}function Oe(t){if(!t||typeof t!="string"){S("setFanIdHash: invalid hash provided");return}if(g=t,c?.analytics===!0)try{localStorage.setItem(w+h,t),a("Fan ID hash persisted:",t.substring(0,16)+"...")}catch{T(h,t)}else a("Fan ID hash set (memory only - no consent):",t.substring(0,16)+"...")}function qt(t,e="USD",n={}){let o=P({event_name:"purchase",metadata:{revenue:t,currency:e,...n}});E(o),be(t,e,n)}function zt(){if(V=te(),a("Tracking source detected:",V),Se(),c?.analytics!==!0){try{localStorage.removeItem(w+h)}catch{}try{sessionStorage.removeItem(w+h)}catch{}}c?.analytics===!0?(x="local",a("Storage tier: local (analytics consent granted)")):(x="session",a("Storage tier: session (privacy by default)")),F=_e(),xe(),Ce(),b||(b=gt()),c||a(tt?"Consent UI enabled, waiting for explicit user consent (Tier 0 mode)":"No consent - operating in privacy-first mode (session storage only, limited tracking)"),U&&c?.marketing===!0?(a("[Platform] Marketing consent already granted, initializing platform pixels"),At(!0)):U&&a("[Platform] Platform pixels configured:",{meta:O||"(none)",tiktok:L||"(none)",googleAds:p||"(none)"}),Ie(),Re(),a("Initialized",{artistId:Y,projectId:X||"(none - will track to all projects)",rawProjectId:J||"(none)",sessionId:F,visitorId:b?b.substring(0,8)+"...":null,fanIdHash:g,consent:c,storageTier:x,trackingSource:V,useEmulator:Q,endpoint:A}),c?.analytics===!0?(window._balanceInitialPageviewFired=!0,$(),ft(),a("Full tracking enabled (user consented)")):tt?a("Tracking dormant - waiting for explicit consent via ConsentManager"):(window._balanceInitialPageviewFired=!0,$(),ft(),a("Privacy-first tracking enabled (session-scoped, visitor_id for deduplication)")),["mousemove","keydown","scroll","touchstart"].forEach(s=>{document.addEventListener(s,De,{passive:!0})});let t=window.location.hostname;function e(s){try{let i=new URL(s).hostname.toLowerCase();return i.includes("spotify")?"spotify":i.includes("apple")||i.includes("music.apple")?"apple_music":i.includes("youtube")||i.includes("youtu.be")?"youtube":i.includes("soundcloud")?"soundcloud":i.includes("tidal")?"tidal":i.includes("deezer")?"deezer":i.includes("amazon")||i.includes("music.amazon")?"amazon_music":i.includes("bandcamp")?"bandcamp":i.includes("lnk.to")||i.includes("linkfire")?"linkfire":i.includes("linktr.ee")?"linktree":i.includes("shop")||i.includes("store")||i.includes("merch")?"shop":i.includes("ticketmaster")||i.includes("eventbrite")||i.includes("dice.fm")?"tickets":i.includes("instagram")?"instagram":i.includes("twitter")||i.includes("x.com")?"twitter":i.includes("tiktok")?"tiktok":i.includes("facebook")?"facebook":"external"}catch{return"external"}}function n(s){try{return new URL(s,window.location.origin).hostname!==t}catch{return!1}}function o(s,i){let u=e(s),C=Le(s),Gt=C?.title||i?.textContent?.trim().substring(0,100)||"",Bt=C?.id||i?.id||i?.getAttribute("data-link-id")||void 0,Wt=C?.category;a("External link clicked:",{url:s,platform:u,linkText:Gt,linkId:Bt,fromRegistry:!!C}),wt("page_link_click",{link_url:s,link_text:Gt,link_id:Bt,platform:u,link_type:"external",...Wt&&{link_category:Wt},...C&&Object.fromEntries(Object.entries(C).filter(([yt])=>!["title","id","category"].includes(yt)).map(([yt,je])=>[`link_${yt}`,je]))})}let d=window.open;if(window.open=function(s,i,u){if(s){let C=s.toString();n(C)&&o(C)}return d.call(window,s,i,u)},a("window.open interception enabled (always on)"),r?.dataset.autoTrackLinks==="true"&&(document.addEventListener("click",s=>{let u=s.target.closest("a");if(u&&u.href&&n(u.href)){if(xt&&(Pt(u.href)||u.hasAttribute("download")))return;o(u.href,u)}},{capture:!0,passive:!0}),a("External link click listener enabled (opt-in)")),xt&&(document.addEventListener("click",s=>{let u=s.target.closest("a");u?.href&&(Pt(u.href)||u.hasAttribute("download"))&&se(u.href,u)},{capture:!0,passive:!0}),a("File download tracking enabled")),Zt){let s=window.location.href;window.addEventListener("hashchange",()=>{let i=window.location.href;i!==s&&(s=i,setTimeout(()=>{$({title:document.title,url:i})},0))}),a("Hash routing tracking enabled")}document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?(jt(),mt(),H()):(ut(),ct=!1)}),window.addEventListener("pagehide",()=>{mt(),H()}),window.addEventListener("beforeunload",()=>{mt(),H()})}if(window.balance?._version&&window.balance._version!==_){console.warn(`[artistPixel] Version conflict: ${window.balance._version} already loaded, skipping ${_}`);return}let pt=window.balance?.q||[];function Nt(){if(pt.length>0){a("Processing",pt.length,"queued commands");for(let t of pt){let[e,...n]=t;switch(e){case"track":wt(n[0],n[1]);break;case"identify":Ft(n[0],n[1]);break;case"page":$(n[0]);break;case"purchase":qt(n[0],n[1],n[2]);break;case"setConsent":Mt(n[0]);break;default:a("Unknown queued command:",e)}}}}let Ht={track:wt,identify:Ft,page:$,purchase:qt,getSessionId:()=>F,getVisitorId:()=>b,getFanIdHash:()=>g,setFanIdHash:Oe,getAttribution:()=>R,setConsent:Mt,getConsent:Pe,hasConsent:Ee,registerLinks:Te,_version:_};window.artistPixel=Ht,window.balance=Ht;function $t(){tt&&!c&&new ge({style:Jt,primaryColor:Xt,position:Qt})}let Vt=window.requestIdleCallback||(t=>setTimeout(t,1));document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{zt(),Nt(),Vt(()=>$t())}):(zt(),Nt(),Vt(()=>$t())),a("Pixel script loaded")})();})();
102
+ `,this.shadow.getElementById("accept")?.addEventListener("click",()=>this.handleConsent(!0)),this.shadow.getElementById("decline")?.addEventListener("click",()=>this.handleConsent(!1))}handleConsent(e){window.balance?.setConsent&&window.balance.setConsent({analytics:e,marketing:e,personalization:e,timestamp:new Date().toISOString()}),e&&!window._balanceInitialPageviewFired&&(window._balanceInitialPageviewFired=!0,window.balance?.page&&window.balance.page(),ft(),a("Initial pageview fired after consent granted")),this.remove()}remove(){this.container&&(this.container.remove(),this.container=null,this.shadow=null,a("ConsentManager: Banner removed"))}}let Lt=!1,z=!1;function fe(){if(!j)return;if(window.fbq){a("[Platform:Meta] Already loaded, skipping");return}a("[Platform:Meta] Injecting pixel:",j);let t=function(...n){t.callMethod?t.callMethod.apply(t,n):t.queue.push(n)};window._fbq||(window._fbq=t),t.push=t,t.loaded=!0,t.version="2.0",t.queue=[],window.fbq=t;let e=document.createElement("script");e.async=!0,e.src="https://connect.facebook.net/en_US/fbevents.js",e.onload=()=>{window.fbq("init",j),m.pageview&&window.fbq("track","PageView"),a("[Platform:Meta] Initialized and PageView tracked")},document.head.appendChild(e)}function me(){if(!L)return;if(window.ttq?._i?.[L]){a("[Platform:TikTok] Already loaded, skipping");return}a("[Platform:TikTok] Injecting pixel:",L);let t=window,e="ttq";t.TiktokAnalyticsObject=e;let n=t[e]=t[e]||[];n.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],n.setAndDefer=function(o,c){o[c]=function(...d){o.push([c].concat(d))}};for(let o=0;o<n.methods.length;o++)n.setAndDefer(n,n.methods[o]);n.instance=function(o){let c=n._i[o]||[];for(let d=0;d<n.methods.length;d++)n.setAndDefer(c,n.methods[d]);return c},n.load=function(o){let c="https://analytics.tiktok.com/i18n/pixel/events.js";n._i=n._i||{},n._i[o]=[],n._i[o]._u=c,n._t=n._t||{},n._t[o]=+new Date,n._o=n._o||{};let d=document.createElement("script");d.type="text/javascript",d.async=!0,d.src=c+"?sdkid="+o+"&lib="+e,document.head.appendChild(d)},n.load(L),m.pageview&&n.page(),a("[Platform:TikTok] Initialized and page() tracked")}function we(){if(!p)return;if(window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(...e){window.dataLayer.push(e)}),document.querySelector('script[src*="googletagmanager.com/gtag/js"]')){a("[Platform:GoogleAds] gtag.js already loaded, configuring"),window.gtag("config",p);return}a("[Platform:GoogleAds] Injecting gtag:",p),window.gtag("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted"});let t=document.createElement("script");t.async=!0,t.src=`https://www.googletagmanager.com/gtag/js?id=${p}`,t.onload=()=>{window.gtag("js",new Date),window.gtag("config",p),a("[Platform:GoogleAds] Initialized")},document.head.appendChild(t)}function pe(){if(!U)return;if(document.querySelector(`script[src*="googletagmanager.com/gtm.js?id=${U}"]`)){a("[Platform:GTM] Already loaded, skipping");return}a("[Platform:GTM] Injecting GTM:",U),window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(...n){window.dataLayer.push(n)});let t=z?"granted":"denied";window.gtag("consent","default",{ad_storage:t,ad_user_data:t,ad_personalization:t,analytics_storage:t}),window.gtag("set","wait_for_update",500),window.dataLayer.push({"gtm.start":new Date().getTime(),event:"gtm.js"});let e=document.createElement("script");e.async=!0,e.src=`https://www.googletagmanager.com/gtm.js?id=${U}`,e.onload=()=>{a("[Platform:GTM] Initialized")},document.head.appendChild(e)}function he(){if(!h)return;let t=document.querySelector('script[src*="googletagmanager.com/gtag/js"]');window.dataLayer=window.dataLayer||[],typeof window.gtag!="function"&&(window.gtag=function(...o){window.dataLayer.push(o)});let e=z?"granted":"denied";if(window.gtag("consent","default",{ad_storage:e,ad_user_data:e,ad_personalization:e,analytics_storage:e}),t){a("[Platform:GA4] gtag.js already loaded, configuring"),window.gtag("config",h,{send_page_view:!1});return}a("[Platform:GA4] Injecting gtag:",h);let n=document.createElement("script");n.async=!0,n.src=`https://www.googletagmanager.com/gtag/js?id=${h}`,n.onload=()=>{window.gtag("js",new Date),window.gtag("config",h,{send_page_view:!1}),a("[Platform:GA4] Initialized")},document.head.appendChild(n)}function ye(){if(F){if(Lt){a("[Platform] Already loaded, skipping");return}if(!z){a("[Platform] Marketing consent not granted, deferring");return}a("[Platform] Injecting platform pixels (consent granted)"),Lt=!0,fe(),me(),we(),pe(),he()}}function At(t){if(z=t,a("[Platform] Marketing consent:",t?"granted":"denied"),t&&ye(),window.ttq&&(t?window.ttq.grantConsent?.():window.ttq.revokeConsent?.()),typeof window.gtag=="function"){let e=t?"granted":"denied";window.gtag("consent","update",{ad_storage:e,ad_user_data:e,ad_personalization:e,analytics_storage:e})}}function lt(t){if(!F||!z)return!1;let e=t.toLowerCase();return e==="pageview"||e==="page_view"?m.pageview:e==="purchase"?m.purchase:e==="addtocart"||e==="add_to_cart"?m.addToCart:e==="lead"||e==="form_submit"?m.lead:e==="viewcontent"||e==="view_content"?m.viewContent:e==="initiatecheckout"||e==="initiate_checkout"?m.initiateCheckout:e==="completeregistration"||e==="complete_registration"?m.completeRegistration:e==="subscribe"?m.subscribe:e==="search"?m.search:e==="contact"?m.contact:m.custom.length>0?m.custom.some(n=>n.toLowerCase()===e):!1}function be(){lt("pageview")&&(a("[Platform] Forwarding PageView"),window.fbq&&window.fbq("track","PageView"),window.ttq&&window.ttq.page(),typeof window.gtag=="function"&&h&&window.gtag("event","page_view",{send_to:h}))}function ve(t,e,n){if(lt("purchase")){if(a("[Platform] Forwarding Purchase:",t,e),window.fbq&&window.fbq("track","Purchase",{value:t,currency:e,content_ids:n?.contentIds,content_type:n?.contentType||"product",order_id:n?.transactionId}),window.ttq&&window.ttq.track("CompletePayment",{value:t,currency:e,order_id:n?.transactionId}),typeof window.gtag=="function"&&p){let o=kt?`${p}/${kt}`:p;window.gtag("event","conversion",{send_to:o,value:t,currency:e,transaction_id:n?.transactionId}),window.gtag("event","purchase",{send_to:p,value:t,currency:e,transaction_id:n?.transactionId})}typeof window.gtag=="function"&&h&&window.gtag("event","purchase",{send_to:h,value:t,currency:e,transaction_id:n?.transactionId,items:n?.items})}}function _e(t,e){if(!lt(t))return;let n=t.toLowerCase();a("[Platform] Forwarding custom event:",t);let o={addtocart:"AddToCart",add_to_cart:"AddToCart",lead:"Lead",form_submit:"Lead",viewcontent:"ViewContent",view_content:"ViewContent",search:"Search",subscribe:"Subscribe",contact:"Contact",completeregistration:"CompleteRegistration",complete_registration:"CompleteRegistration",initiatecheckout:"InitiateCheckout",initiate_checkout:"InitiateCheckout"},c={addtocart:"AddToCart",add_to_cart:"AddToCart",lead:"SubmitForm",form_submit:"SubmitForm",viewcontent:"ViewContent",view_content:"ViewContent",search:"Search",subscribe:"Subscribe",contact:"Contact",completeregistration:"CompleteRegistration",complete_registration:"CompleteRegistration",initiatecheckout:"InitiateCheckout",initiate_checkout:"InitiateCheckout"},d={addtocart:"add_to_cart",add_to_cart:"add_to_cart",lead:"generate_lead",form_submit:"generate_lead",viewcontent:"view_item",view_content:"view_item",search:"search",subscribe:"subscribe",contact:"contact",completeregistration:"sign_up",complete_registration:"sign_up",initiatecheckout:"begin_checkout",initiate_checkout:"begin_checkout"};if(window.fbq){let r=o[n];r?window.fbq("track",r,e):window.fbq("trackCustom",t,e)}if(window.ttq){let r=c[n]||t;window.ttq.track(r,e)}if(typeof window.gtag=="function"&&p){let r=d[n]||t;window.gtag("event",r,{send_to:p,...e})}if(typeof window.gtag=="function"&&h){let r=d[n]||t;window.gtag("event",r,{send_to:h,...e})}}function Rt(){try{return x==="local"?localStorage:sessionStorage}catch{return null}}function W(t){let e=Rt();if(!e)return null;try{let n=w+t,o=e.getItem(n);if(!o&&x==="session")try{o=localStorage.getItem(n)}catch{}return o}catch{return null}}function T(t,e){let n=Rt();if(n)try{n.setItem(w+t,e)}catch{}}function Dt(){if(x!=="local"){a("Upgrading storage tier: session -> local");try{let t=[];for(let e=0;e<sessionStorage.length;e++){let n=sessionStorage.key(e);n?.startsWith(w)&&t.push(n)}for(let e of t){let n=sessionStorage.getItem(e);n&&localStorage.setItem(e,n)}for(let e of t)sessionStorage.removeItem(e);x="local",a(`Storage tier upgraded, migrated ${t.length} items`)}catch(t){S(" Storage migration failed:",t)}}}function Y(){return crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function ke(){try{let t=W(Ct),e=W(et);if(t&&e&&Date.now()-parseInt(e,10)<ae)return T(et,Date.now().toString()),t;let n=Y();return T(Ct,n),T(et,Date.now().toString()),n}catch{return Y()}}function Ie(){let t=new URLSearchParams(window.location.search),e={};return["source","medium","campaign","content","term"].forEach(n=>{let o=t.get(`utm_${n}`);o&&(e[`utm_${n}`]=o)}),e}function xe(){try{let t=W(St);if(t){R=JSON.parse(t),a("Loaded attribution:",R);return}let e=Ie();Object.keys(e).length>0&&(R=e,T(St,JSON.stringify(e)),a("Captured attribution:",R))}catch{}}function Ce(){try{if(l?.analytics!==!0){a("Skipping fan ID load - no analytics consent");return}g=localStorage.getItem(w+y),g&&a("Loaded fan ID hash:",g.substring(0,16)+"...")}catch{if(l?.analytics===!0)try{g=W(y)}catch{}}}function gt(){try{let t=localStorage.getItem(w+nt);if(t)return t;let e=Y();return localStorage.setItem(w+nt,e),a("Created persistent visitor ID:",e.substring(0,8)+"..."),e}catch{return a("localStorage unavailable, using session ID as fallback"),q||Y()}}function Se(){try{b=localStorage.getItem(w+nt),b&&a("Loaded visitor ID:",b.substring(0,8)+"...")}catch{}}function Pe(){try{let t=localStorage.getItem(B);if(t){let e=JSON.parse(t);if(e.expiresAt&&Date.now()>e.expiresAt){a("Consent expired - clearing stored consent"),localStorage.removeItem(B),l=null;return}if(e.expiresAt){let n=e.expiresAt-Date.now();n>0&&n<ne&&(a("Consent nearing expiration - will prompt for refresh"),window._balanceConsentNeedsRefresh=!0)}l=e.preferences||null,a("Loaded consent:",l)}}catch{}}function Mt(t){let e=l;l=t;try{let o={preferences:t,method:"explicit",version:1,expiresAt:Date.now()+ee};localStorage.setItem(B,JSON.stringify(o)),a("Consent saved with TTL:",t),window._balanceConsentNeedsRefresh=!1}catch(o){S(" Could not save consent:",o)}if(t.analytics===!0&&(Dt(),b||(b=gt()),g))try{localStorage.setItem(w+y,g),a("Fan ID hash persisted after consent granted")}catch{T(y,g)}if(t.analytics!==!0){try{localStorage.removeItem(w+y)}catch{}try{sessionStorage.removeItem(w+y)}catch{}g=null,a("Fan ID hash cleared from storage and memory (consent revoked)")}let n=P({event_name:"consent_updated",metadata:{consent_preferences:t,consent_method:"explicit",previous_consent:e||void 0}});E(n);try{window.dispatchEvent(new CustomEvent("artistPixel:consent:updated",{detail:t})),a("DOM event artistPixel:consent:updated dispatched")}catch{}F&&At(t.marketing===!0)}function Ee(){return l}function Te(t){return l?.[t]===!0}function Le(t){for(let[e,n]of Object.entries(t))try{let o=Ot(e);at[o]=n}catch{at[e]=n}a("Registered",Object.keys(t).length,"links for tracking enrichment")}function Ot(t){try{let e=new URL(t);return`${e.protocol}//${e.host}${e.pathname}${e.search}`}catch{return t}}function Ae(t){let e=Ot(t);return at[e]||null}async function Re(t){let e=t.toLowerCase().trim(),o=new TextEncoder().encode(e),c=await crypto.subtle.digest("SHA-256",o);return Array.from(new Uint8Array(c)).map(r=>r.toString(16).padStart(2,"0")).join("")}async function De(t){if(!O)return null;try{let e=await fetch(de,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:{email:t.toLowerCase().trim(),artistId:O}})});if(!e.ok)return a("hashIdentity endpoint failed:",e.status),null;let n=await e.json();return{hash:n.result.fanIdHash,version:n.result.hashVersion}}catch(e){return a("hashIdentity endpoint error:",e),null}}function P(t){let e=Yt(),n={artist_id:O,fan_session_id:q,visitor_id:b||gt(),fan_id_hash:g||void 0,timestamp:new Date().toISOString(),source_url:window.location.href,referrer_url:document.referrer||void 0,user_agent:navigator.userAgent,device_type:e.device_type,browser:e.browser,os:e.os,tracking_source:G,...t,...R};return X&&!t.projectId&&(n.projectId=X),n}function E(t){I.push(t),a("Event queued:",t.event_name,"(queue:",I.length,")"),I.length>=10&&$()}async function $(){if(I.length===0)return;let t=[...I];I=[],a("Flushing",t.length,"events to",A);try{let e=await fetch(A,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:t}),keepalive:!0});if(!e.ok)throw new Error(`HTTP ${e.status}`);a("Events sent successfully")}catch(e){if(S(" Failed to send events, trying fallback:",e),A!==Et&&!Q)try{if((await fetch(Et,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:t}),keepalive:!0})).ok){a("Events sent via fallback (no geo)");return}}catch(n){S(" Fallback also failed:",n)}I.length<50&&I.push(...t)}}function Me(){ot&&clearInterval(ot),ot=window.setInterval(()=>{I.length>0&&$()},5e3)}function ut(){M||(it=Date.now()),M=Date.now(),N=!0,a("Active time tracking started/resumed")}function jt(){M&&N&&(rt+=Date.now()-M),N=!1,a("Active time tracking paused, accumulated:",rt,"ms")}function Ut(){let t=rt;return N&&M&&(t+=Date.now()-M),t}function Oe(){Tt=Date.now(),H&&(H=!1,ut(),a("User returned from idle"))}function je(){if(document.visibilityState==="hidden"){a("Skipping heartbeat - tab hidden");return}if(Date.now()-Tt>le){H||(H=!0,jt(),a("User idle - pausing heartbeat"));return}let t=Ut(),e=Math.round(t/1e3),n=P({event_name:"engagement_heartbeat",metadata:{time_on_page_seconds:e,time_on_page_ms:t,heartbeat_interval_ms:Z,is_active:N&&!H}});E(n),st++,a("Heartbeat sent:",e,"seconds active")}function ft(){if(!bt){a('Heartbeat disabled via data-heartbeat="false"');return}D&&clearInterval(D),ut(),D=window.setInterval(()=>{je()},Z),a("Heartbeat started with interval:",Z,"ms")}function mt(){if(!ct){if(ct=!0,D&&(clearInterval(D),D=null),bt){let t=it?Date.now()-it:0,e=Ut(),n=P({event_name:"engagement_summary",metadata:{total_time_ms:t,active_time_ms:e,heartbeat_samples:st,page_path:window.location.pathname}});if(navigator.sendBeacon&&A){let o=JSON.stringify({events:[n]});navigator.sendBeacon(A,o),a("Engagement summary sent via sendBeacon:",Math.round(e/1e3),"seconds active")}else E(n),a("Engagement summary enqueued:",Math.round(e/1e3),"seconds active")}st=0}}function V(t={}){let e=t.url||window.location.href;if(ie(e)){a("Page excluded from tracking:",e);return}let n=P({event_name:"pageview",page_title:t.title||document.title,source_url:e});E(n),be()}function wt(t,e={}){let n=P({event_name:"custom",metadata:{event_type:t,...e}});E(n),_e(t,e)}async function Ft(t,e={}){try{if(l?.analytics!==!0){a("identify() skipped - no analytics consent");return}let n=1,o=await De(t);if(o?(g=o.hash,n=o.version,a("identify() using server HMAC hash (v2)")):(g=await Re(t),a("identify() using local SHA256 hash (v1 fallback)")),l?.analytics===!0&&Dt(),l?.analytics===!0)try{localStorage.setItem(w+y,g)}catch{T(y,g)}let c=t.split("@"),d=c[0].charAt(0)+"***@"+(c[1]||"");a("Fan identified:",{name:e.name||"(no name)",email:d,hash:g.substring(0,16)+"...",hashVersion:n,traits:e,storageTier:x});let r=P({event_name:"identify",fan_id_hash:g,metadata:{email_sha256:g,email_display:d,hash_version:n,traits:e,consent_preferences:l||void 0,storage_tier:x}});E(r)}catch(n){S(" Failed to identify:",n)}}function Ue(t){if(!t||typeof t!="string"){S("setFanIdHash: invalid hash provided");return}if(g=t,l?.analytics===!0)try{localStorage.setItem(w+y,t),a("Fan ID hash persisted:",t.substring(0,16)+"...")}catch{T(y,t)}else a("Fan ID hash set (memory only - no consent):",t.substring(0,16)+"...")}function qt(t,e="USD",n={}){let o=P({event_name:"purchase",metadata:{revenue:t,currency:e,...n}});E(o),ve(t,e,n)}function Nt(){if(G=te(),a("Tracking source detected:",G),Pe(),l?.analytics!==!0){try{localStorage.removeItem(w+y)}catch{}try{sessionStorage.removeItem(w+y)}catch{}}l?.analytics===!0?(x="local",a("Storage tier: local (analytics consent granted)")):(x="session",a("Storage tier: session (privacy by default)")),q=ke(),Ce(),Se(),b||(b=gt()),l||a(tt?"Consent UI enabled, waiting for explicit user consent (Tier 0 mode)":"No consent - operating in privacy-first mode (session storage only, limited tracking)"),F&&l?.marketing===!0?(a("[Platform] Marketing consent already granted, initializing platform pixels"),At(!0)):F&&a("[Platform] Platform pixels configured:",{meta:j||"(none)",tiktok:L||"(none)",googleAds:p||"(none)"}),xe(),Me(),a("Initialized",{artistId:O,projectId:X||"(none - will track to all projects)",rawProjectId:K||"(none)",sessionId:q,visitorId:b?b.substring(0,8)+"...":null,fanIdHash:g,consent:l,storageTier:x,trackingSource:G,useEmulator:Q,endpoint:A}),l?.analytics===!0?(window._balanceInitialPageviewFired=!0,V(),ft(),a("Full tracking enabled (user consented)")):tt?a("Tracking dormant - waiting for explicit consent via ConsentManager"):(window._balanceInitialPageviewFired=!0,V(),ft(),a("Privacy-first tracking enabled (session-scoped, visitor_id for deduplication)")),["mousemove","keydown","scroll","touchstart"].forEach(r=>{document.addEventListener(r,Oe,{passive:!0})});let t=window.location.hostname;function e(r){try{let i=new URL(r).hostname.toLowerCase();return i.includes("spotify")?"spotify":i.includes("apple")||i.includes("music.apple")?"apple_music":i.includes("youtube")||i.includes("youtu.be")?"youtube":i.includes("soundcloud")?"soundcloud":i.includes("tidal")?"tidal":i.includes("deezer")?"deezer":i.includes("amazon")||i.includes("music.amazon")?"amazon_music":i.includes("bandcamp")?"bandcamp":i.includes("lnk.to")||i.includes("linkfire")?"linkfire":i.includes("linktr.ee")?"linktree":i.includes("shop")||i.includes("store")||i.includes("merch")?"shop":i.includes("ticketmaster")||i.includes("eventbrite")||i.includes("dice.fm")?"tickets":i.includes("instagram")?"instagram":i.includes("twitter")||i.includes("x.com")?"twitter":i.includes("tiktok")?"tiktok":i.includes("facebook")?"facebook":"external"}catch{return"external"}}function n(r){try{return new URL(r,window.location.origin).hostname!==t}catch{return!1}}function o(r,i){let u=e(r),C=Ae(r),Gt=C?.title||i?.textContent?.trim().substring(0,100)||"",Bt=C?.id||i?.id||i?.getAttribute("data-link-id")||void 0,Wt=C?.category;a("External link clicked:",{url:r,platform:u,linkText:Gt,linkId:Bt,fromRegistry:!!C}),wt("page_link_click",{link_url:r,link_text:Gt,link_id:Bt,platform:u,link_type:"external",...Wt&&{link_category:Wt},...C&&Object.fromEntries(Object.entries(C).filter(([ht])=>!["title","id","category"].includes(ht)).map(([ht,Fe])=>[`link_${ht}`,Fe]))})}let c=window.open;if(window.open=function(r,i,u){if(r){let C=r.toString();n(C)&&o(C)}return c.call(window,r,i,u)},a("window.open interception enabled (always on)"),s?.dataset.autoTrackLinks==="true"&&(document.addEventListener("click",r=>{let u=r.target.closest("a");if(u&&u.href&&n(u.href)){if(xt&&(Pt(u.href)||u.hasAttribute("download")))return;o(u.href,u)}},{capture:!0,passive:!0}),a("External link click listener enabled (opt-in)")),xt&&(document.addEventListener("click",r=>{let u=r.target.closest("a");u?.href&&(Pt(u.href)||u.hasAttribute("download"))&&se(u.href,u)},{capture:!0,passive:!0}),a("File download tracking enabled")),Zt){let r=window.location.href;window.addEventListener("hashchange",()=>{let i=window.location.href;i!==r&&(r=i,setTimeout(()=>{V({title:document.title,url:i})},0))}),a("Hash routing tracking enabled")}document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?(jt(),mt(),$()):(ut(),ct=!1)}),window.addEventListener("pagehide",()=>{mt(),$()}),window.addEventListener("beforeunload",()=>{mt(),$()})}if(window.balance?._version&&window.balance._version!==_){console.warn(`[artistPixel] Version conflict: ${window.balance._version} already loaded, skipping ${_}`);return}let pt=window.balance?.q||[];function Ht(){if(pt.length>0){a("Processing",pt.length,"queued commands");for(let t of pt){let[e,...n]=t;switch(e){case"track":wt(n[0],n[1]);break;case"identify":Ft(n[0],n[1]);break;case"page":V(n[0]);break;case"purchase":qt(n[0],n[1],n[2]);break;case"setConsent":Mt(n[0]);break;default:a("Unknown queued command:",e)}}}}let zt={track:wt,identify:Ft,page:V,purchase:qt,getSessionId:()=>q,getVisitorId:()=>b,getFanIdHash:()=>g,setFanIdHash:Ue,getAttribution:()=>R,setConsent:Mt,getConsent:Ee,hasConsent:Te,registerLinks:Le,_version:_};window.artistPixel=zt,window.balance=zt;function $t(){tt&&!l&&new ue({style:Kt,primaryColor:Xt,position:Qt})}let Vt=window.requestIdleCallback||(t=>setTimeout(t,1));document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{Nt(),Ht(),Vt(()=>$t())}):(Nt(),Ht(),Vt(()=>$t())),a("Pixel script loaded")})();})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hifilabs/pixel",
3
- "version": "0.16.4",
3
+ "version": "0.16.6",
4
4
  "description": "artistPixel - Lightweight browser tracking script for artist fan analytics",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",