@hifilabs/pixel 0.1.7 → 0.2.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.
package/dist/browser.js CHANGED
@@ -52,6 +52,7 @@ var BalancePixel = (() => {
52
52
  const heartbeatInterval = parseInt(currentScript?.dataset.heartbeatInterval || "30000", 10);
53
53
  const heartbeatEnabled = currentScript?.dataset.heartbeat !== "false";
54
54
  const explicitSource = currentScript?.dataset.source;
55
+ const customEndpoint = currentScript?.dataset.endpoint;
55
56
  function detectTrackingSource() {
56
57
  if (explicitSource)
57
58
  return explicitSource;
@@ -74,7 +75,7 @@ var BalancePixel = (() => {
74
75
  const CONSENT_STORAGE_KEY = "balance_consent";
75
76
  const SESSION_DURATION = 60 * 60 * 1e3;
76
77
  const STORAGE_PREFIX = "balance_";
77
- const API_ENDPOINT = useEmulator ? `http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint` : `https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint`;
78
+ const API_ENDPOINT = customEndpoint ? customEndpoint : useEmulator ? `http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint` : `https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint`;
78
79
  let sessionId = null;
79
80
  let fanIdHash = null;
80
81
  let consent = null;
@@ -532,6 +533,34 @@ var BalancePixel = (() => {
532
533
  }
533
534
  });
534
535
  }
536
+ const existingQueue = window.balance?.q || [];
537
+ function processQueue() {
538
+ if (existingQueue.length > 0) {
539
+ log("Processing", existingQueue.length, "queued commands");
540
+ for (const args of existingQueue) {
541
+ const [command, ...params] = args;
542
+ switch (command) {
543
+ case "track":
544
+ track(params[0], params[1]);
545
+ break;
546
+ case "identify":
547
+ identify(params[0], params[1]);
548
+ break;
549
+ case "page":
550
+ trackPageView(params[0]);
551
+ break;
552
+ case "purchase":
553
+ purchase(params[0], params[1], params[2]);
554
+ break;
555
+ case "setConsent":
556
+ setConsent(params[0]);
557
+ break;
558
+ default:
559
+ log("Unknown queued command:", command);
560
+ }
561
+ }
562
+ }
563
+ }
535
564
  window.balance = {
536
565
  track,
537
566
  identify,
@@ -545,9 +574,13 @@ var BalancePixel = (() => {
545
574
  hasConsent
546
575
  };
547
576
  if (document.readyState === "loading") {
548
- document.addEventListener("DOMContentLoaded", init);
577
+ document.addEventListener("DOMContentLoaded", () => {
578
+ init();
579
+ processQueue();
580
+ });
549
581
  } else {
550
582
  init();
583
+ processQueue();
551
584
  }
552
585
  log("Pixel script loaded");
553
586
  })();
@@ -1 +1 @@
1
- var BalancePixel=(()=>{(function(){function $(e){let t="desktop";/ipad|tablet|android(?!.*mobile)/i.test(e)?t="tablet":/mobile|iphone|android.*mobile|blackberry|iemobile/i.test(e)&&(t="mobile");let n="Unknown";/edg/i.test(e)?n="Edge":/opr|opera/i.test(e)?n="Opera":/firefox/i.test(e)?n="Firefox":/chrome/i.test(e)?n="Chrome":/safari/i.test(e)&&(n="Safari");let i="Unknown";return/iphone|ipad/i.test(e)?i="iOS":/android/i.test(e)?i="Android":/windows/i.test(e)?i="Windows":/mac os/i.test(e)?i="macOS":/linux/i.test(e)?i="Linux":/cros/i.test(e)&&(i="ChromeOS"),{device_type:t,browser:n,os:i}}let v=null;function W(){if(!v)try{v=$(navigator.userAgent)}catch{v={device_type:"desktop",browser:"Unknown",os:"Unknown"}}return v}let l=document.currentScript,w=l?.dataset.artistId,x=l?.dataset.projectId,L=l?.dataset.emulator==="true",V=l?.dataset.debug==="true",A=parseInt(l?.dataset.heartbeatInterval||"30000",10),U=l?.dataset.heartbeat!=="false",R=l?.dataset.source;function Q(){if(R)return R;let e=typeof window.dataLayer<"u"&&Array.isArray(window.dataLayer),t=typeof window.gtag=="function";return e&&t?"gtm":"pixel"}let b="pixel";if(!w){console.error("[BALANCE Pixel] Error: data-artist-id attribute is required");return}let H="session_id",E="session_timestamp",F="attribution",B="fan_id_hash",j="balance_consent",X=60*60*1e3,T="balance_",k=L?"http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint":"https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint",S=null,s=null,a=null,d={},o=[],P=null,c="session",u=null,Z=0,C=0,g=0,p=!0,ee=2*60*1e3,M=Date.now(),h=!1,r=(...e)=>{V&&console.log("[BALANCE Pixel]",...e)};function z(){try{return c==="local"?localStorage:sessionStorage}catch{return null}}function _(e){let t=z();if(!t)return null;try{let n=T+e,i=t.getItem(n);if(!i&&c==="session")try{i=localStorage.getItem(n)}catch{}return i}catch{return null}}function y(e,t){let n=z();if(n)try{n.setItem(T+e,t)}catch{}}function D(){if(c!=="local"){r("Upgrading storage tier: session -> local");try{let e=[];for(let t=0;t<sessionStorage.length;t++){let n=sessionStorage.key(t);n?.startsWith(T)&&e.push(n)}for(let t of e){let n=sessionStorage.getItem(t);n&&localStorage.setItem(t,n)}for(let t of e)sessionStorage.removeItem(t);c="local",r(`Storage tier upgraded, migrated ${e.length} items`)}catch(e){console.error("[BALANCE Pixel] Storage migration failed:",e)}}}function K(){return crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function te(){try{let e=_(H),t=_(E);if(e&&t&&Date.now()-parseInt(t,10)<X)return y(E,Date.now().toString()),e;let n=K();return y(H,n),y(E,Date.now().toString()),n}catch{return K()}}function ne(){let e=new URLSearchParams(window.location.search),t={};return["source","medium","campaign","content","term"].forEach(n=>{let i=e.get(`utm_${n}`);i&&(t[`utm_${n}`]=i)}),t}function re(){try{let e=_(F);if(e){d=JSON.parse(e),r("Loaded attribution:",d);return}let t=ne();Object.keys(t).length>0&&(d=t,y(F,JSON.stringify(t)),r("Captured attribution:",d))}catch{}}function ie(){try{s=_(B)}catch{}}function ae(){try{let e=localStorage.getItem(j);e&&(a=JSON.parse(e).preferences||null,r("Loaded consent:",a))}catch{}}function se(e){let t=a;a=e;try{let i={preferences:e,method:"explicit",version:1};localStorage.setItem(j,JSON.stringify(i)),r("Consent saved:",e)}catch(i){console.error("[BALANCE Pixel] Could not save consent:",i)}e.analytics===!0&&D();let n=f({event_name:"consent_updated",metadata:{consent_preferences:e,consent_method:"explicit",previous_consent:t||void 0}});m(n)}function oe(){return a}function ce(e){return a?.[e]===!0}async function le(e){let t=e.toLowerCase().trim(),i=new TextEncoder().encode(t),N=await crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(N)).map(ve=>ve.toString(16).padStart(2,"0")).join("")}function f(e){let t=W(),n={artist_id:w,fan_session_id:S,fan_id_hash:s||void 0,timestamp:new Date().toISOString(),source_url:window.location.href,referrer_url:document.referrer||void 0,user_agent:navigator.userAgent,device_type:t.device_type,browser:t.browser,os:t.os,tracking_source:b,...e,...d};return x&&!e.projectId&&(n.projectId=x),n}function m(e){o.push(e),r("Event queued:",e.event_name,"(queue:",o.length,")"),o.length>=10&&I()}async function I(){if(o.length===0)return;let e=[...o];o=[],r("Flushing",e.length,"events to",k);try{let t=await fetch(k,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(!t.ok)throw new Error(`HTTP ${t.status}`);r("Events sent successfully")}catch(t){console.error("[BALANCE Pixel] Failed to send events:",t),o.length<50&&o.push(...e)}}function de(){P&&clearInterval(P),P=window.setInterval(()=>{o.length>0&&I()},5e3)}function O(){g||(Z=Date.now()),g=Date.now(),p=!0,r("Active time tracking started/resumed")}function J(){g&&p&&(C+=Date.now()-g),p=!1,r("Active time tracking paused, accumulated:",C,"ms")}function ue(){let e=C;return p&&g&&(e+=Date.now()-g),e}function ge(){M=Date.now(),h&&(h=!1,O(),r("User returned from idle"))}function Y(){if(document.visibilityState==="hidden"){r("Skipping heartbeat - tab hidden");return}if(Date.now()-M>ee){h||(h=!0,J(),r("User idle - pausing heartbeat"));return}let e=ue(),t=Math.round(e/1e3),n=f({event_name:"engagement_heartbeat",metadata:{time_on_page_seconds:t,time_on_page_ms:e,heartbeat_interval_ms:A,is_active:p&&!h}});m(n),r("Heartbeat sent:",t,"seconds active")}function fe(){if(!U){r('Heartbeat disabled via data-heartbeat="false"');return}u&&clearInterval(u),O(),u=window.setInterval(()=>{Y()},A),r("Heartbeat started with interval:",A,"ms")}function me(){u&&(clearInterval(u),u=null),U&&(Y(),r("Heartbeat stopped, final time sent"))}function q(e={}){let t=f({event_name:"pageview",page_title:e.title||document.title,source_url:e.url||window.location.href});m(t)}function pe(e,t={}){let n=f({event_name:"custom",metadata:{event_type:e,...t}});m(n)}async function he(e,t={}){try{if(a&&a.analytics===!1){r("Identify skipped - user declined analytics consent");return}s=await le(e),a?.analytics===!0&&D(),y(B,s);let n=e.split("@"),i=n[0].charAt(0)+"***@"+(n[1]||"");r("Fan identified:",{name:t.name||"(no name)",email:i,hash:s.substring(0,16)+"...",traits:t,storageTier:c});let N=f({event_name:"identify",fan_id_hash:s,metadata:{email_sha256:s,traits:t,consent_preferences:a||void 0,storage_tier:c}});m(N)}catch(n){console.error("[BALANCE Pixel] Failed to identify:",n)}}function ye(e,t="USD",n={}){let i=f({event_name:"purchase",metadata:{revenue:e,currency:t,...n}});m(i)}function G(){b=Q(),r("Tracking source detected:",b),ae(),a?.analytics===!0?(c="local",r("Storage tier: local (analytics consent granted)")):(c="session",r("Storage tier: session (privacy by default)")),S=te(),ie(),a||(a={analytics:!0,marketing:!0,personalization:!0,timestamp:new Date().toISOString()},r("Default consent enabled (all tracking):",a),D()),re(),de(),r("Initialized",{artistId:w,projectId:x||"(none - will track to all projects)",sessionId:S,fanIdHash:s,consent:a,storageTier:c,trackingSource:b,useEmulator:L,endpoint:k}),window._balanceInitialPageviewFired=!0,q(),fe(),["mousemove","keydown","scroll","touchstart"].forEach(e=>{document.addEventListener(e,ge,{passive:!0})}),window.addEventListener("beforeunload",()=>{me(),I()}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?(J(),I()):O()})}window.balance={track:pe,identify:he,page:q,purchase:ye,getSessionId:()=>S,getFanIdHash:()=>s,getAttribution:()=>d,setConsent:se,getConsent:oe,hasConsent:ce},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",G):G(),r("Pixel script loaded")})();})();
1
+ var BalancePixel=(()=>{(function(){function te(e){let t="desktop";/ipad|tablet|android(?!.*mobile)/i.test(e)?t="tablet":/mobile|iphone|android.*mobile|blackberry|iemobile/i.test(e)&&(t="mobile");let n="Unknown";/edg/i.test(e)?n="Edge":/opr|opera/i.test(e)?n="Opera":/firefox/i.test(e)?n="Firefox":/chrome/i.test(e)?n="Chrome":/safari/i.test(e)&&(n="Safari");let i="Unknown";return/iphone|ipad/i.test(e)?i="iOS":/android/i.test(e)?i="Android":/windows/i.test(e)?i="Windows":/mac os/i.test(e)?i="macOS":/linux/i.test(e)?i="Linux":/cros/i.test(e)&&(i="ChromeOS"),{device_type:t,browser:n,os:i}}let v=null;function ne(){if(!v)try{v=te(navigator.userAgent)}catch{v={device_type:"desktop",browser:"Unknown",os:"Unknown"}}return v}let l=document.currentScript,I=l?.dataset.artistId,x=l?.dataset.projectId,R=l?.dataset.emulator==="true",re=l?.dataset.debug==="true",k=parseInt(l?.dataset.heartbeatInterval||"30000",10),H=l?.dataset.heartbeat!=="false",F=l?.dataset.source,B=l?.dataset.endpoint;function ie(){if(F)return F;let e=typeof window.dataLayer<"u"&&Array.isArray(window.dataLayer),t=typeof window.gtag=="function";return e&&t?"gtm":"pixel"}let b="pixel";if(!I){console.error("[BALANCE Pixel] Error: data-artist-id attribute is required");return}let j="session_id",E="session_timestamp",M="attribution",q="fan_id_hash",z="balance_consent",ae=60*60*1e3,A="balance_",T=B||(R?"http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint":"https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint"),S=null,s=null,a=null,d={},o=[],P=null,c="session",u=null,se=0,C=0,g=0,p=!0,oe=2*60*1e3,K=Date.now(),h=!1,r=(...e)=>{re&&console.log("[BALANCE Pixel]",...e)};function J(){try{return c==="local"?localStorage:sessionStorage}catch{return null}}function w(e){let t=J();if(!t)return null;try{let n=A+e,i=t.getItem(n);if(!i&&c==="session")try{i=localStorage.getItem(n)}catch{}return i}catch{return null}}function y(e,t){let n=J();if(n)try{n.setItem(A+e,t)}catch{}}function D(){if(c!=="local"){r("Upgrading storage tier: session -> local");try{let e=[];for(let t=0;t<sessionStorage.length;t++){let n=sessionStorage.key(t);n?.startsWith(A)&&e.push(n)}for(let t of e){let n=sessionStorage.getItem(t);n&&localStorage.setItem(t,n)}for(let t of e)sessionStorage.removeItem(t);c="local",r(`Storage tier upgraded, migrated ${e.length} items`)}catch(e){console.error("[BALANCE Pixel] Storage migration failed:",e)}}}function Y(){return crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function ce(){try{let e=w(j),t=w(E);if(e&&t&&Date.now()-parseInt(t,10)<ae)return y(E,Date.now().toString()),e;let n=Y();return y(j,n),y(E,Date.now().toString()),n}catch{return Y()}}function le(){let e=new URLSearchParams(window.location.search),t={};return["source","medium","campaign","content","term"].forEach(n=>{let i=e.get(`utm_${n}`);i&&(t[`utm_${n}`]=i)}),t}function de(){try{let e=w(M);if(e){d=JSON.parse(e),r("Loaded attribution:",d);return}let t=le();Object.keys(t).length>0&&(d=t,y(M,JSON.stringify(t)),r("Captured attribution:",d))}catch{}}function ue(){try{s=w(q)}catch{}}function ge(){try{let e=localStorage.getItem(z);e&&(a=JSON.parse(e).preferences||null,r("Loaded consent:",a))}catch{}}function G(e){let t=a;a=e;try{let i={preferences:e,method:"explicit",version:1};localStorage.setItem(z,JSON.stringify(i)),r("Consent saved:",e)}catch(i){console.error("[BALANCE Pixel] Could not save consent:",i)}e.analytics===!0&&D();let n=f({event_name:"consent_updated",metadata:{consent_preferences:e,consent_method:"explicit",previous_consent:t||void 0}});m(n)}function fe(){return a}function me(e){return a?.[e]===!0}async function pe(e){let t=e.toLowerCase().trim(),i=new TextEncoder().encode(t),L=await crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(L)).map(we=>we.toString(16).padStart(2,"0")).join("")}function f(e){let t=ne(),n={artist_id:I,fan_session_id:S,fan_id_hash:s||void 0,timestamp:new Date().toISOString(),source_url:window.location.href,referrer_url:document.referrer||void 0,user_agent:navigator.userAgent,device_type:t.device_type,browser:t.browser,os:t.os,tracking_source:b,...e,...d};return x&&!e.projectId&&(n.projectId=x),n}function m(e){o.push(e),r("Event queued:",e.event_name,"(queue:",o.length,")"),o.length>=10&&_()}async function _(){if(o.length===0)return;let e=[...o];o=[],r("Flushing",e.length,"events to",T);try{let t=await fetch(T,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(!t.ok)throw new Error(`HTTP ${t.status}`);r("Events sent successfully")}catch(t){console.error("[BALANCE Pixel] Failed to send events:",t),o.length<50&&o.push(...e)}}function he(){P&&clearInterval(P),P=window.setInterval(()=>{o.length>0&&_()},5e3)}function O(){g||(se=Date.now()),g=Date.now(),p=!0,r("Active time tracking started/resumed")}function $(){g&&p&&(C+=Date.now()-g),p=!1,r("Active time tracking paused, accumulated:",C,"ms")}function ye(){let e=C;return p&&g&&(e+=Date.now()-g),e}function ve(){K=Date.now(),h&&(h=!1,O(),r("User returned from idle"))}function Q(){if(document.visibilityState==="hidden"){r("Skipping heartbeat - tab hidden");return}if(Date.now()-K>oe){h||(h=!0,$(),r("User idle - pausing heartbeat"));return}let e=ye(),t=Math.round(e/1e3),n=f({event_name:"engagement_heartbeat",metadata:{time_on_page_seconds:t,time_on_page_ms:e,heartbeat_interval_ms:k,is_active:p&&!h}});m(n),r("Heartbeat sent:",t,"seconds active")}function be(){if(!H){r('Heartbeat disabled via data-heartbeat="false"');return}u&&clearInterval(u),O(),u=window.setInterval(()=>{Q()},k),r("Heartbeat started with interval:",k,"ms")}function Se(){u&&(clearInterval(u),u=null),H&&(Q(),r("Heartbeat stopped, final time sent"))}function N(e={}){let t=f({event_name:"pageview",page_title:e.title||document.title,source_url:e.url||window.location.href});m(t)}function W(e,t={}){let n=f({event_name:"custom",metadata:{event_type:e,...t}});m(n)}async function V(e,t={}){try{if(a&&a.analytics===!1){r("Identify skipped - user declined analytics consent");return}s=await pe(e),a?.analytics===!0&&D(),y(q,s);let n=e.split("@"),i=n[0].charAt(0)+"***@"+(n[1]||"");r("Fan identified:",{name:t.name||"(no name)",email:i,hash:s.substring(0,16)+"...",traits:t,storageTier:c});let L=f({event_name:"identify",fan_id_hash:s,metadata:{email_sha256:s,traits:t,consent_preferences:a||void 0,storage_tier:c}});m(L)}catch(n){console.error("[BALANCE Pixel] Failed to identify:",n)}}function X(e,t="USD",n={}){let i=f({event_name:"purchase",metadata:{revenue:e,currency:t,...n}});m(i)}function Z(){b=ie(),r("Tracking source detected:",b),ge(),a?.analytics===!0?(c="local",r("Storage tier: local (analytics consent granted)")):(c="session",r("Storage tier: session (privacy by default)")),S=ce(),ue(),a||(a={analytics:!0,marketing:!0,personalization:!0,timestamp:new Date().toISOString()},r("Default consent enabled (all tracking):",a),D()),de(),he(),r("Initialized",{artistId:I,projectId:x||"(none - will track to all projects)",sessionId:S,fanIdHash:s,consent:a,storageTier:c,trackingSource:b,useEmulator:R,endpoint:T}),window._balanceInitialPageviewFired=!0,N(),be(),["mousemove","keydown","scroll","touchstart"].forEach(e=>{document.addEventListener(e,ve,{passive:!0})}),window.addEventListener("beforeunload",()=>{Se(),_()}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?($(),_()):O()})}let U=window.balance?.q||[];function ee(){if(U.length>0){r("Processing",U.length,"queued commands");for(let e of U){let[t,...n]=e;switch(t){case"track":W(n[0],n[1]);break;case"identify":V(n[0],n[1]);break;case"page":N(n[0]);break;case"purchase":X(n[0],n[1],n[2]);break;case"setConsent":G(n[0]);break;default:r("Unknown queued command:",t)}}}}window.balance={track:W,identify:V,page:N,purchase:X,getSessionId:()=>S,getFanIdHash:()=>s,getAttribution:()=>d,setConsent:G,getConsent:fe,hasConsent:me},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{Z(),ee()}):(Z(),ee()),r("Pixel script loaded")})();})();