@hifilabs/pixel 0.1.4 → 0.1.5

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/index.js CHANGED
@@ -1,90 +1,5 @@
1
1
  var BalancePixel = (() => {
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
- }) : x)(function(x) {
11
- if (typeof require !== "undefined")
12
- return require.apply(this, arguments);
13
- throw Error('Dynamic require of "' + x + '" is not supported');
14
- });
15
- var __export = (target, all) => {
16
- for (var name in all)
17
- __defProp(target, name, { get: all[name], enumerable: true });
18
- };
19
- var __copyProps = (to, from, except, desc) => {
20
- if (from && typeof from === "object" || typeof from === "function") {
21
- for (let key of __getOwnPropNames(from))
22
- if (!__hasOwnProp.call(to, key) && key !== except)
23
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
- }
25
- return to;
26
- };
27
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
28
- // If the importer is in node compatibility mode or this is not an ESM
29
- // file that has been converted to a CommonJS file using a Babel-
30
- // compatible transform (i.e. "__esModule" has not been set), then set
31
- // "default" to the CommonJS "module.exports" for node compatibility.
32
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
33
- mod
34
- ));
35
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
-
37
- // src/index.ts
38
- var src_exports = {};
39
- __export(src_exports, {
40
- BalanceAnalytics: () => BalanceAnalytics,
41
- getAttribution: () => getAttribution,
42
- getConsent: () => getConsent,
43
- getFanIdHash: () => getFanIdHash,
44
- getSessionId: () => getSessionId,
45
- hasConsent: () => hasConsent,
46
- identify: () => identify,
47
- page: () => page,
48
- purchase: () => purchase,
49
- setConsent: () => setConsent,
50
- track: () => track
51
- });
52
-
53
- // src/react/BalanceAnalytics.tsx
54
- var import_react = __toESM(__require("react"));
55
- var import_navigation = __require("next/navigation");
56
- function BalanceAnalyticsInner() {
57
- const pathname = (0, import_navigation.usePathname)();
58
- const searchParams = (0, import_navigation.useSearchParams)();
59
- const isFirstRender = (0, import_react.useRef)(true);
60
- const lastTrackedPath = (0, import_react.useRef)(null);
61
- (0, import_react.useEffect)(() => {
62
- if (typeof window === "undefined" || !window.balance)
63
- return;
64
- const currentPath = pathname + (searchParams?.toString() || "");
65
- if (lastTrackedPath.current === currentPath) {
66
- return;
67
- }
68
- if (isFirstRender.current) {
69
- isFirstRender.current = false;
70
- if (window._balanceInitialPageviewFired) {
71
- lastTrackedPath.current = currentPath;
72
- console.log("[BalanceAnalytics] Skipping initial pageview (script already fired)");
73
- return;
74
- }
75
- }
76
- const url = window.location.href;
77
- const title = document.title;
78
- lastTrackedPath.current = currentPath;
79
- window.balance.page({ url, title });
80
- }, [pathname, searchParams]);
81
- return null;
82
- }
83
- function BalanceAnalytics() {
84
- return /* @__PURE__ */ import_react.default.createElement(import_react.Suspense, { fallback: null }, /* @__PURE__ */ import_react.default.createElement(BalanceAnalyticsInner, null));
85
- }
86
-
87
- // src/index.ts
2
+ // src/browser.ts
88
3
  (function() {
89
4
  function parseUserAgent(ua) {
90
5
  let device_type = "desktop";
@@ -313,7 +228,7 @@ var BalancePixel = (() => {
313
228
  } catch (e) {
314
229
  }
315
230
  }
316
- function setConsent2(preferences) {
231
+ function setConsent(preferences) {
317
232
  const previousConsent = consent;
318
233
  consent = preferences;
319
234
  try {
@@ -340,10 +255,10 @@ var BalancePixel = (() => {
340
255
  });
341
256
  enqueueEvent(event);
342
257
  }
343
- function getConsent2() {
258
+ function getConsent() {
344
259
  return consent;
345
260
  }
346
- function hasConsent2(type) {
261
+ function hasConsent(type) {
347
262
  return consent?.[type] === true;
348
263
  }
349
264
  async function hashEmail(email) {
@@ -506,7 +421,7 @@ var BalancePixel = (() => {
506
421
  });
507
422
  enqueueEvent(event);
508
423
  }
509
- function track2(eventName, properties = {}) {
424
+ function track(eventName, properties = {}) {
510
425
  const event = buildEvent({
511
426
  event_name: "custom",
512
427
  metadata: {
@@ -516,7 +431,7 @@ var BalancePixel = (() => {
516
431
  });
517
432
  enqueueEvent(event);
518
433
  }
519
- async function identify2(email, traits = {}) {
434
+ async function identify(email, traits = {}) {
520
435
  try {
521
436
  if (consent && consent.analytics === false) {
522
437
  log("Identify skipped - user declined analytics consent");
@@ -551,7 +466,7 @@ var BalancePixel = (() => {
551
466
  console.error("[BALANCE Pixel] Failed to identify:", error);
552
467
  }
553
468
  }
554
- function purchase2(revenue, currency = "USD", properties = {}) {
469
+ function purchase(revenue, currency = "USD", properties = {}) {
555
470
  const event = buildEvent({
556
471
  event_name: "purchase",
557
472
  metadata: {
@@ -618,16 +533,16 @@ var BalancePixel = (() => {
618
533
  });
619
534
  }
620
535
  window.balance = {
621
- track: track2,
622
- identify: identify2,
536
+ track,
537
+ identify,
623
538
  page: trackPageView,
624
- purchase: purchase2,
539
+ purchase,
625
540
  getSessionId: () => sessionId,
626
541
  getFanIdHash: () => fanIdHash,
627
542
  getAttribution: () => attribution,
628
- setConsent: setConsent2,
629
- getConsent: getConsent2,
630
- hasConsent: hasConsent2
543
+ setConsent,
544
+ getConsent,
545
+ hasConsent
631
546
  };
632
547
  if (document.readyState === "loading") {
633
548
  document.addEventListener("DOMContentLoaded", init);
@@ -636,76 +551,4 @@ var BalancePixel = (() => {
636
551
  }
637
552
  log("Pixel script loaded");
638
553
  })();
639
- var track = (eventName, properties) => {
640
- if (typeof window === "undefined")
641
- return;
642
- if (window.balance) {
643
- window.balance.track(eventName, properties);
644
- } else {
645
- console.warn("[Balance Pixel] track() called before pixel initialized:", eventName);
646
- }
647
- };
648
- var identify = (email, traits) => {
649
- if (typeof window === "undefined")
650
- return Promise.resolve();
651
- if (window.balance) {
652
- return window.balance.identify(email, traits);
653
- } else {
654
- console.warn("[Balance Pixel] identify() called before pixel initialized");
655
- return Promise.resolve();
656
- }
657
- };
658
- var page = (options) => {
659
- if (typeof window === "undefined")
660
- return;
661
- if (window.balance) {
662
- window.balance.page(options);
663
- } else {
664
- console.warn("[Balance Pixel] page() called before pixel initialized");
665
- }
666
- };
667
- var purchase = (revenue, currency, properties) => {
668
- if (typeof window === "undefined")
669
- return;
670
- if (window.balance) {
671
- window.balance.purchase(revenue, currency, properties);
672
- } else {
673
- console.warn("[Balance Pixel] purchase() called before pixel initialized");
674
- }
675
- };
676
- var getSessionId = () => {
677
- if (typeof window === "undefined")
678
- return null;
679
- return window.balance?.getSessionId() ?? null;
680
- };
681
- var getFanIdHash = () => {
682
- if (typeof window === "undefined")
683
- return null;
684
- return window.balance?.getFanIdHash() ?? null;
685
- };
686
- var getAttribution = () => {
687
- if (typeof window === "undefined")
688
- return {};
689
- return window.balance?.getAttribution() ?? {};
690
- };
691
- var setConsent = (preferences) => {
692
- if (typeof window === "undefined")
693
- return;
694
- if (window.balance) {
695
- window.balance.setConsent(preferences);
696
- } else {
697
- console.warn("[Balance Pixel] setConsent() called before pixel initialized");
698
- }
699
- };
700
- var getConsent = () => {
701
- if (typeof window === "undefined")
702
- return null;
703
- return window.balance?.getConsent() ?? null;
704
- };
705
- var hasConsent = (type) => {
706
- if (typeof window === "undefined")
707
- return false;
708
- return window.balance?.hasConsent(type) ?? false;
709
- };
710
- return __toCommonJS(src_exports);
711
554
  })();
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- var BalancePixel=(()=>{var Ae=Object.create;var T=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var Pe=Object.getOwnPropertyNames;var Ee=Object.getPrototypeOf,Te=Object.prototype.hasOwnProperty;var Z=(i=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(i,{get:(r,s)=>(typeof require<"u"?require:r)[s]}):i)(function(i){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+i+'" is not supported')});var Ce=(i,r)=>{for(var s in r)T(i,s,{get:r[s],enumerable:!0})},ee=(i,r,s,l)=>{if(r&&typeof r=="object"||typeof r=="function")for(let d of Pe(r))!Te.call(i,d)&&d!==s&&T(i,d,{get:()=>r[d],enumerable:!(l=ke(r,d))||l.enumerable});return i};var De=(i,r,s)=>(s=i!=null?Ae(Ee(i)):{},ee(r||!i||!i.__esModule?T(s,"default",{value:i,enumerable:!0}):s,i)),Oe=i=>ee(T({},"__esModule",{value:!0}),i);var Je={};Ce(Je,{BalanceAnalytics:()=>te,getAttribution:()=>ze,getConsent:()=>Me,getFanIdHash:()=>He,getSessionId:()=>Fe,hasConsent:()=>Ke,identify:()=>Re,page:()=>Ue,purchase:()=>Be,setConsent:()=>je,track:()=>Ne});var u=De(Z("react")),C=Z("next/navigation");function Le(){let i=(0,C.usePathname)(),r=(0,C.useSearchParams)(),s=(0,u.useRef)(!0),l=(0,u.useRef)(null);return(0,u.useEffect)(()=>{if(typeof window>"u"||!window.balance)return;let d=i+(r?.toString()||"");if(l.current===d)return;if(s.current&&(s.current=!1,window._balanceInitialPageviewFired)){l.current=d,console.log("[BalanceAnalytics] Skipping initial pageview (script already fired)");return}let v=window.location.href,_=document.title;l.current=d,window.balance.page({url:v,title:_})},[i,r]),null}function te(){return u.default.createElement(u.Suspense,{fallback:null},u.default.createElement(Le,null))}(function(){function i(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 o="Unknown";return/iphone|ipad/i.test(e)?o="iOS":/android/i.test(e)?o="Android":/windows/i.test(e)?o="Windows":/mac os/i.test(e)?o="macOS":/linux/i.test(e)?o="Linux":/cros/i.test(e)&&(o="ChromeOS"),{device_type:t,browser:n,os:o}}let r=null;function s(){if(!r)try{r=i(navigator.userAgent)}catch{r={device_type:"desktop",browser:"Unknown",os:"Unknown"}}return r}let l=document.currentScript,d=l?.dataset.artistId,v=l?.dataset.projectId,_=l?.dataset.emulator==="true",ne=l?.dataset.debug==="true",D=parseInt(l?.dataset.heartbeatInterval||"30000",10),z=l?.dataset.heartbeat!=="false",j=l?.dataset.source;function ie(){if(j)return j;let e=typeof window.dataLayer<"u"&&Array.isArray(window.dataLayer),t=typeof window.gtag=="function";return e&&t?"gtm":"pixel"}let A="pixel";if(!d){console.error("[BALANCE Pixel] Error: data-artist-id attribute is required");return}let M="session_id",O="session_timestamp",K="attribution",J="fan_id_hash",Y="balance_consent",re=60*60*1e3,L="balance_",N=_?"http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint":"https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint",k=null,f=null,c=null,m={},g=[],R=null,p="session",w=null,ae=0,U=0,y=0,x=!0,oe=2*60*1e3,q=Date.now(),S=!1,a=(...e)=>{ne&&console.log("[BALANCE Pixel]",...e)};function G(){try{return p==="local"?localStorage:sessionStorage}catch{return null}}function P(e){let t=G();if(!t)return null;try{let n=L+e,o=t.getItem(n);if(!o&&p==="session")try{o=localStorage.getItem(n)}catch{}return o}catch{return null}}function I(e,t){let n=G();if(n)try{n.setItem(L+e,t)}catch{}}function B(){if(p!=="local"){a("Upgrading storage tier: session -> local");try{let e=[];for(let t=0;t<sessionStorage.length;t++){let n=sessionStorage.key(t);n?.startsWith(L)&&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);p="local",a(`Storage tier upgraded, migrated ${e.length} items`)}catch(e){console.error("[BALANCE Pixel] Storage migration failed:",e)}}}function $(){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 se(){try{let e=P(M),t=P(O);if(e&&t&&Date.now()-parseInt(t,10)<re)return I(O,Date.now().toString()),e;let n=$();return I(M,n),I(O,Date.now().toString()),n}catch{return $()}}function ce(){let e=new URLSearchParams(window.location.search),t={};return["source","medium","campaign","content","term"].forEach(n=>{let o=e.get(`utm_${n}`);o&&(t[`utm_${n}`]=o)}),t}function le(){try{let e=P(K);if(e){m=JSON.parse(e),a("Loaded attribution:",m);return}let t=ce();Object.keys(t).length>0&&(m=t,I(K,JSON.stringify(t)),a("Captured attribution:",m))}catch{}}function de(){try{f=P(J)}catch{}}function ue(){try{let e=localStorage.getItem(Y);e&&(c=JSON.parse(e).preferences||null,a("Loaded consent:",c))}catch{}}function fe(e){let t=c;c=e;try{let o={preferences:e,method:"explicit",version:1};localStorage.setItem(Y,JSON.stringify(o)),a("Consent saved:",e)}catch(o){console.error("[BALANCE Pixel] Could not save consent:",o)}e.analytics===!0&&B();let n=b({event_name:"consent_updated",metadata:{consent_preferences:e,consent_method:"explicit",previous_consent:t||void 0}});h(n)}function ge(){return c}function pe(e){return c?.[e]===!0}async function me(e){let t=e.toLowerCase().trim(),o=new TextEncoder().encode(t),H=await crypto.subtle.digest("SHA-256",o);return Array.from(new Uint8Array(H)).map(_e=>_e.toString(16).padStart(2,"0")).join("")}function b(e){let t=s(),n={artist_id:d,fan_session_id:k,fan_id_hash:f||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:A,...e,...m};return v&&!e.projectId&&(n.projectId=v),n}function h(e){g.push(e),a("Event queued:",e.event_name,"(queue:",g.length,")"),g.length>=10&&E()}async function E(){if(g.length===0)return;let e=[...g];g=[],a("Flushing",e.length,"events to",N);try{let t=await fetch(N,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(!t.ok)throw new Error(`HTTP ${t.status}`);a("Events sent successfully")}catch(t){console.error("[BALANCE Pixel] Failed to send events:",t),g.length<50&&g.push(...e)}}function we(){R&&clearInterval(R),R=window.setInterval(()=>{g.length>0&&E()},5e3)}function F(){y||(ae=Date.now()),y=Date.now(),x=!0,a("Active time tracking started/resumed")}function W(){y&&x&&(U+=Date.now()-y),x=!1,a("Active time tracking paused, accumulated:",U,"ms")}function ye(){let e=U;return x&&y&&(e+=Date.now()-y),e}function be(){q=Date.now(),S&&(S=!1,F(),a("User returned from idle"))}function V(){if(document.visibilityState==="hidden"){a("Skipping heartbeat - tab hidden");return}if(Date.now()-q>oe){S||(S=!0,W(),a("User idle - pausing heartbeat"));return}let e=ye(),t=Math.round(e/1e3),n=b({event_name:"engagement_heartbeat",metadata:{time_on_page_seconds:t,time_on_page_ms:e,heartbeat_interval_ms:D,is_active:x&&!S}});h(n),a("Heartbeat sent:",t,"seconds active")}function he(){if(!z){a('Heartbeat disabled via data-heartbeat="false"');return}w&&clearInterval(w),F(),w=window.setInterval(()=>{V()},D),a("Heartbeat started with interval:",D,"ms")}function ve(){w&&(clearInterval(w),w=null),z&&(V(),a("Heartbeat stopped, final time sent"))}function Q(e={}){let t=b({event_name:"pageview",page_title:e.title||document.title,source_url:e.url||window.location.href});h(t)}function xe(e,t={}){let n=b({event_name:"custom",metadata:{event_type:e,...t}});h(n)}async function Se(e,t={}){try{if(c&&c.analytics===!1){a("Identify skipped - user declined analytics consent");return}f=await me(e),c?.analytics===!0&&B(),I(J,f);let n=e.split("@"),o=n[0].charAt(0)+"***@"+(n[1]||"");a("Fan identified:",{name:t.name||"(no name)",email:o,hash:f.substring(0,16)+"...",traits:t,storageTier:p});let H=b({event_name:"identify",fan_id_hash:f,metadata:{email_sha256:f,traits:t,consent_preferences:c||void 0,storage_tier:p}});h(H)}catch(n){console.error("[BALANCE Pixel] Failed to identify:",n)}}function Ie(e,t="USD",n={}){let o=b({event_name:"purchase",metadata:{revenue:e,currency:t,...n}});h(o)}function X(){A=ie(),a("Tracking source detected:",A),ue(),c?.analytics===!0?(p="local",a("Storage tier: local (analytics consent granted)")):(p="session",a("Storage tier: session (privacy by default)")),k=se(),de(),c||(c={analytics:!0,marketing:!0,personalization:!0,timestamp:new Date().toISOString()},a("Default consent enabled (all tracking):",c),B()),le(),we(),a("Initialized",{artistId:d,projectId:v||"(none - will track to all projects)",sessionId:k,fanIdHash:f,consent:c,storageTier:p,trackingSource:A,useEmulator:_,endpoint:N}),window._balanceInitialPageviewFired=!0,Q(),he(),["mousemove","keydown","scroll","touchstart"].forEach(e=>{document.addEventListener(e,be,{passive:!0})}),window.addEventListener("beforeunload",()=>{ve(),E()}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?(W(),E()):F()})}window.balance={track:xe,identify:Se,page:Q,purchase:Ie,getSessionId:()=>k,getFanIdHash:()=>f,getAttribution:()=>m,setConsent:fe,getConsent:ge,hasConsent:pe},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",X):X(),a("Pixel script loaded")})();var Ne=(i,r)=>{typeof window>"u"||(window.balance?window.balance.track(i,r):console.warn("[Balance Pixel] track() called before pixel initialized:",i))},Re=(i,r)=>typeof window>"u"?Promise.resolve():window.balance?window.balance.identify(i,r):(console.warn("[Balance Pixel] identify() called before pixel initialized"),Promise.resolve()),Ue=i=>{typeof window>"u"||(window.balance?window.balance.page(i):console.warn("[Balance Pixel] page() called before pixel initialized"))},Be=(i,r,s)=>{typeof window>"u"||(window.balance?window.balance.purchase(i,r,s):console.warn("[Balance Pixel] purchase() called before pixel initialized"))},Fe=()=>typeof window>"u"?null:window.balance?.getSessionId()??null,He=()=>typeof window>"u"?null:window.balance?.getFanIdHash()??null,ze=()=>typeof window>"u"?{}:window.balance?.getAttribution()??{},je=i=>{typeof window>"u"||(window.balance?window.balance.setConsent(i):console.warn("[Balance Pixel] setConsent() called before pixel initialized"))},Me=()=>typeof window>"u"?null:window.balance?.getConsent()??null,Ke=i=>typeof window>"u"?!1:window.balance?.hasConsent(i)??!1;return Oe(Je);})();
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")})();})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hifilabs/pixel",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "BALANCE Pixel - Lightweight browser tracking script for artist fan analytics",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",