@hifilabs/pixel 0.0.2 → 0.0.3

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.
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+ // src/react/BalanceAnalytics.tsx
3
+ import { useEffect } from "react";
4
+ import { usePathname, useSearchParams } from "next/navigation";
5
+ function BalanceAnalytics() {
6
+ const pathname = usePathname();
7
+ const searchParams = useSearchParams();
8
+ useEffect(() => {
9
+ if (typeof window !== "undefined" && window.balance) {
10
+ const url = window.location.href;
11
+ const title = document.title;
12
+ window.balance.page({ url, title });
13
+ }
14
+ }, [pathname, searchParams]);
15
+ return null;
16
+ }
17
+ export {
18
+ BalanceAnalytics
19
+ };
package/dist/index.js CHANGED
@@ -1,8 +1,56 @@
1
1
  var BalancePixel = (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined")
10
+ return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __export = (target, all) => {
14
+ for (var name in all)
15
+ __defProp(target, name, { get: all[name], enumerable: true });
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
26
+
27
+ // src/index.ts
28
+ var src_exports = {};
29
+ __export(src_exports, {
30
+ BalanceAnalytics: () => BalanceAnalytics
31
+ });
32
+
33
+ // src/react/BalanceAnalytics.tsx
34
+ var import_react = __require("react");
35
+ var import_navigation = __require("next/navigation");
36
+ function BalanceAnalytics() {
37
+ const pathname = (0, import_navigation.usePathname)();
38
+ const searchParams = (0, import_navigation.useSearchParams)();
39
+ (0, import_react.useEffect)(() => {
40
+ if (typeof window !== "undefined" && window.balance) {
41
+ const url = window.location.href;
42
+ const title = document.title;
43
+ window.balance.page({ url, title });
44
+ }
45
+ }, [pathname, searchParams]);
46
+ return null;
47
+ }
48
+
2
49
  // src/index.ts
3
50
  (function() {
4
51
  const currentScript = document.currentScript;
5
52
  const artistId = currentScript?.dataset.artistId;
53
+ const projectId = currentScript?.dataset.projectId;
6
54
  const useEmulator = currentScript?.dataset.emulator === "true";
7
55
  const debug = currentScript?.dataset.debug === "true";
8
56
  if (!artistId) {
@@ -14,7 +62,7 @@ var BalancePixel = (() => {
14
62
  const ATTRIBUTION_KEY = "balance_attribution";
15
63
  const FAN_ID_KEY = "balance_fan_id_hash";
16
64
  const CONSENT_STORAGE_KEY = "balance_consent";
17
- const SESSION_DURATION = 30 * 60 * 1e3;
65
+ const SESSION_DURATION = 60 * 60 * 1e3;
18
66
  const API_ENDPOINT = useEmulator ? `http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint` : `https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint`;
19
67
  let sessionId = null;
20
68
  let fanIdHash = null;
@@ -138,7 +186,7 @@ var BalancePixel = (() => {
138
186
  return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
139
187
  }
140
188
  function buildEvent(partial) {
141
- return {
189
+ const base = {
142
190
  artist_id: artistId,
143
191
  fan_session_id: sessionId,
144
192
  fan_id_hash: fanIdHash || void 0,
@@ -149,6 +197,10 @@ var BalancePixel = (() => {
149
197
  ...partial,
150
198
  ...attribution
151
199
  };
200
+ if (projectId && !partial.projectId) {
201
+ base.projectId = projectId;
202
+ }
203
+ return base;
152
204
  }
153
205
  function enqueueEvent(event) {
154
206
  const essentialEvents = ["identify", "consent_updated"];
@@ -218,7 +270,14 @@ var BalancePixel = (() => {
218
270
  try {
219
271
  fanIdHash = await hashEmail(email);
220
272
  localStorage.setItem(FAN_ID_KEY, fanIdHash);
221
- log("Fan identified:", fanIdHash);
273
+ const emailParts = email.split("@");
274
+ const maskedEmail = emailParts[0].charAt(0) + "***@" + (emailParts[1] || "");
275
+ log("Fan identified:", {
276
+ name: traits.name || "(no name)",
277
+ email: maskedEmail,
278
+ hash: fanIdHash.substring(0, 16) + "...",
279
+ traits
280
+ });
222
281
  const event = buildEvent({
223
282
  event_name: "identify",
224
283
  fan_id_hash: fanIdHash,
@@ -248,10 +307,20 @@ var BalancePixel = (() => {
248
307
  sessionId = getOrCreateSession();
249
308
  loadFanId();
250
309
  loadConsent();
310
+ if (!consent) {
311
+ consent = {
312
+ analytics: true,
313
+ marketing: false,
314
+ personalization: false,
315
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
316
+ };
317
+ log("Using default consent (dev mode):", consent);
318
+ }
251
319
  captureAttribution();
252
320
  startFlushTimer();
253
321
  log("Initialized", {
254
322
  artistId,
323
+ projectId: projectId || "(none - will track to all projects)",
255
324
  sessionId,
256
325
  fanIdHash,
257
326
  consent,
@@ -287,4 +356,5 @@ var BalancePixel = (() => {
287
356
  }
288
357
  log("Pixel script loaded");
289
358
  })();
359
+ return __toCommonJS(src_exports);
290
360
  })();
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- var BalancePixel=(()=>{(function(){let f=document.currentScript,m=f?.dataset.artistId,_=f?.dataset.emulator==="true",C=f?.dataset.debug==="true";if(!m){console.error("[BALANCE Pixel] Error: data-artist-id attribute is required");return}let v="balance_session_id",p="balance_session_timestamp",x="balance_attribution",S="balance_fan_id_hash",I="balance_consent",P=30*60*1e3,h=_?"http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint":"https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint",u=null,s=null,i=null,c={},a=[],y=null,r=(...e)=>{C&&console.log("[BALANCE Pixel]",...e)};function E(){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 N(){try{let e=localStorage.getItem(v),t=localStorage.getItem(p);if(e&&t&&Date.now()-parseInt(t,10)<P)return localStorage.setItem(p,Date.now().toString()),e;let n=E();return localStorage.setItem(v,n),localStorage.setItem(p,Date.now().toString()),n}catch{return E()}}function O(){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 T(){try{let e=localStorage.getItem(x);if(e){c=JSON.parse(e),r("Loaded attribution:",c);return}let t=O();Object.keys(t).length>0&&(c=t,localStorage.setItem(x,JSON.stringify(t)),r("Captured attribution:",c))}catch{}}function L(){try{s=localStorage.getItem(S)}catch{}}function R(){try{let e=localStorage.getItem(I);e&&(i=JSON.parse(e).preferences||null,r("Loaded consent:",i))}catch{}}function D(e){let t=i;i=e;try{let o={preferences:e,method:"explicit",version:1};localStorage.setItem(I,JSON.stringify(o)),r("Consent saved:",e)}catch(o){console.error("[BALANCE Pixel] Could not save consent:",o)}let n=l({event_name:"consent_updated",metadata:{consent_preferences:e,consent_method:"explicit",previous_consent:t||void 0}});d(n)}function U(){return i}function b(e){return i?.[e]===!0}async function k(e){let t=e.toLowerCase().trim(),o=new TextEncoder().encode(t),z=await crypto.subtle.digest("SHA-256",o);return Array.from(new Uint8Array(z)).map(J=>J.toString(16).padStart(2,"0")).join("")}function l(e){return{artist_id:m,fan_session_id:u,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,...e,...c}}function d(e){if(!["identify","consent_updated"].includes(e.event_name)&&!b("analytics")){r(`Event '${e.event_name}' blocked - no analytics consent`);return}a.push(e),r("Event queued:",e.event_name,"(queue:",a.length,")"),a.length>=10&&g()}async function g(){if(a.length===0)return;let e=[...a];a=[],r("Flushing",e.length,"events to",h);try{let t=await fetch(h,{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),a.length<50&&a.push(...e)}}function B(){y&&clearInterval(y),y=window.setInterval(()=>{a.length>0&&g()},5e3)}function w(e={}){let t=l({event_name:"pageview",page_title:e.title||document.title,source_url:e.url||window.location.href});d(t)}function F(e,t={}){let n=l({event_name:"custom",metadata:{event_type:e,...t}});d(n)}async function H(e,t={}){try{s=await k(e),localStorage.setItem(S,s),r("Fan identified:",s);let n=l({event_name:"identify",fan_id_hash:s,metadata:{email_sha256:s,traits:t,consent_preferences:i||void 0}});d(n)}catch(n){console.error("[BALANCE Pixel] Failed to identify:",n)}}function M(e,t="USD",n={}){let o=l({event_name:"purchase",metadata:{revenue:e,currency:t,...n}});d(o)}function A(){u=N(),L(),R(),T(),B(),r("Initialized",{artistId:m,sessionId:u,fanIdHash:s,consent:i,useEmulator:_,endpoint:h}),w(),window.addEventListener("beforeunload",()=>{g()}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&g()})}window.balance={track:F,identify:H,page:w,purchase:M,getSessionId:()=>u,getFanIdHash:()=>s,getAttribution:()=>c,setConsent:D,getConsent:U,hasConsent:b},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",A):A(),r("Pixel script loaded")})();})();
1
+ var BalancePixel=(()=>{var E=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var L=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(r,s)=>(typeof require<"u"?require:r)[s]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});var X=(n,r)=>{for(var s in r)E(n,s,{get:r[s],enumerable:!0})},Z=(n,r,s,u)=>{if(r&&typeof r=="object"||typeof r=="function")for(let g of V(r))!W.call(n,g)&&g!==s&&E(n,g,{get:()=>r[g],enumerable:!(u=Q(r,g))||u.enumerable});return n};var ee=n=>Z(E({},"__esModule",{value:!0}),n);var te={};X(te,{BalanceAnalytics:()=>k});var R=L("react"),_=L("next/navigation");function k(){let n=(0,_.usePathname)(),r=(0,_.useSearchParams)();return(0,R.useEffect)(()=>{if(typeof window<"u"&&window.balance){let s=window.location.href,u=document.title;window.balance.page({url:s,title:u})}},[n,r]),null}(function(){let n=document.currentScript,r=n?.dataset.artistId,s=n?.dataset.projectId,u=n?.dataset.emulator==="true",g=n?.dataset.debug==="true";if(!r){console.error("[BALANCE Pixel] Error: data-artist-id attribute is required");return}let w="balance_session_id",x="balance_session_timestamp",b="balance_attribution",A="balance_fan_id_hash",P="balance_consent",D=60*60*1e3,S=u?"http://localhost:5001/artist-os-distro/us-central1/pixelEndpoint":"https://us-central1-artist-os-distro.cloudfunctions.net/pixelEndpoint",h=null,l=null,c=null,f={},d=[],v=null,i=(...e)=>{g&&console.log("[BALANCE Pixel]",...e)};function C(){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 U(){try{let e=localStorage.getItem(w),t=localStorage.getItem(x);if(e&&t&&Date.now()-parseInt(t,10)<D)return localStorage.setItem(x,Date.now().toString()),e;let o=C();return localStorage.setItem(w,o),localStorage.setItem(x,Date.now().toString()),o}catch{return C()}}function B(){let e=new URLSearchParams(window.location.search),t={};return["source","medium","campaign","content","term"].forEach(o=>{let a=e.get(`utm_${o}`);a&&(t[`utm_${o}`]=a)}),t}function j(){try{let e=localStorage.getItem(b);if(e){f=JSON.parse(e),i("Loaded attribution:",f);return}let t=B();Object.keys(t).length>0&&(f=t,localStorage.setItem(b,JSON.stringify(t)),i("Captured attribution:",f))}catch{}}function F(){try{l=localStorage.getItem(A)}catch{}}function z(){try{let e=localStorage.getItem(P);e&&(c=JSON.parse(e).preferences||null,i("Loaded consent:",c))}catch{}}function H(e){let t=c;c=e;try{let a={preferences:e,method:"explicit",version:1};localStorage.setItem(P,JSON.stringify(a)),i("Consent saved:",e)}catch(a){console.error("[BALANCE Pixel] Could not save consent:",a)}let o=m({event_name:"consent_updated",metadata:{consent_preferences:e,consent_method:"explicit",previous_consent:t||void 0}});p(o)}function M(){return c}function N(e){return c?.[e]===!0}async function J(e){let t=e.toLowerCase().trim(),a=new TextEncoder().encode(t),I=await crypto.subtle.digest("SHA-256",a);return Array.from(new Uint8Array(I)).map(G=>G.toString(16).padStart(2,"0")).join("")}function m(e){let t={artist_id:r,fan_session_id:h,fan_id_hash:l||void 0,timestamp:new Date().toISOString(),source_url:window.location.href,referrer_url:document.referrer||void 0,user_agent:navigator.userAgent,...e,...f};return s&&!e.projectId&&(t.projectId=s),t}function p(e){if(!["identify","consent_updated"].includes(e.event_name)&&!N("analytics")){i(`Event '${e.event_name}' blocked - no analytics consent`);return}d.push(e),i("Event queued:",e.event_name,"(queue:",d.length,")"),d.length>=10&&y()}async function y(){if(d.length===0)return;let e=[...d];d=[],i("Flushing",e.length,"events to",S);try{let t=await fetch(S,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(!t.ok)throw new Error(`HTTP ${t.status}`);i("Events sent successfully")}catch(t){console.error("[BALANCE Pixel] Failed to send events:",t),d.length<50&&d.push(...e)}}function K(){v&&clearInterval(v),v=window.setInterval(()=>{d.length>0&&y()},5e3)}function O(e={}){let t=m({event_name:"pageview",page_title:e.title||document.title,source_url:e.url||window.location.href});p(t)}function Y(e,t={}){let o=m({event_name:"custom",metadata:{event_type:e,...t}});p(o)}async function q(e,t={}){try{l=await J(e),localStorage.setItem(A,l);let o=e.split("@"),a=o[0].charAt(0)+"***@"+(o[1]||"");i("Fan identified:",{name:t.name||"(no name)",email:a,hash:l.substring(0,16)+"...",traits:t});let I=m({event_name:"identify",fan_id_hash:l,metadata:{email_sha256:l,traits:t,consent_preferences:c||void 0}});p(I)}catch(o){console.error("[BALANCE Pixel] Failed to identify:",o)}}function $(e,t="USD",o={}){let a=m({event_name:"purchase",metadata:{revenue:e,currency:t,...o}});p(a)}function T(){h=U(),F(),z(),c||(c={analytics:!0,marketing:!1,personalization:!1,timestamp:new Date().toISOString()},i("Using default consent (dev mode):",c)),j(),K(),i("Initialized",{artistId:r,projectId:s||"(none - will track to all projects)",sessionId:h,fanIdHash:l,consent:c,useEmulator:u,endpoint:S}),O(),window.addEventListener("beforeunload",()=>{y()}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&y()})}window.balance={track:Y,identify:q,page:O,purchase:$,getSessionId:()=>h,getFanIdHash:()=>l,getAttribution:()=>f,setConsent:H,getConsent:M,hasConsent:N},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",T):T(),i("Pixel script loaded")})();return ee(te);})();
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@hifilabs/pixel",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "BALANCE Pixel - Lightweight browser tracking script for artist fan analytics",
5
5
  "main": "./dist/index.js",
6
+ "module": "./dist/index.esm.js",
6
7
  "types": "./dist/index.d.ts",
7
8
  "publishConfig": {
8
9
  "access": "restricted"
@@ -10,10 +11,6 @@
10
11
  "files": [
11
12
  "dist"
12
13
  ],
13
- "scripts": {
14
- "dev": "esbuild src/index.ts --bundle --outfile=dist/index.js --watch",
15
- "build": "node build.js"
16
- },
17
14
  "keywords": [
18
15
  "analytics",
19
16
  "tracking",
@@ -31,8 +28,17 @@
31
28
  "url": "https://github.com/hifilabs/artist-os-distro"
32
29
  },
33
30
  "homepage": "https://github.com/hifilabs/artist-os-distro#readme",
31
+ "peerDependencies": {
32
+ "react": "^18.0.0 || ^19.0.0",
33
+ "react-dom": "^18.0.0 || ^19.0.0",
34
+ "next": "^13.0.0 || ^14.0.0 || ^15.0.0"
35
+ },
34
36
  "devDependencies": {
35
37
  "esbuild": "^0.19.0",
36
38
  "typescript": "^5.4.5"
39
+ },
40
+ "scripts": {
41
+ "dev": "esbuild src/index.ts --bundle --outfile=dist/index.js --watch",
42
+ "build": "node build.js"
37
43
  }
38
- }
44
+ }