@hanzo/event 0.3.42 → 0.3.44
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/consent.d.ts +36 -0
- package/dist/consent.d.ts.map +1 -0
- package/dist/cookie.d.ts +5 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/core.d.ts +8 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/index.cjs +594 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +572 -33
- package/dist/index.mjs.map +1 -1
- package/dist/link.d.ts +28 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/react.cjs +120 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +120 -2
- package/dist/react.mjs.map +1 -1
- package/dist/storage.d.ts +6 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/tags.d.ts +42 -0
- package/dist/tags.d.ts.map +1 -0
- package/dist/touch.d.ts +7 -0
- package/dist/touch.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/anon.d.ts +3 -0
- package/src/anon.js +19 -1
- package/src/consent.test.ts +140 -0
- package/src/consent.ts +116 -0
- package/src/cookie.ts +28 -0
- package/src/core.ts +45 -3
- package/src/events.ts +1 -1
- package/src/index.ts +10 -0
- package/src/link.test.ts +222 -0
- package/src/link.ts +103 -0
- package/src/storage.ts +14 -1
- package/src/tags.test.ts +187 -0
- package/src/tags.ts +449 -0
- package/src/touch.ts +68 -0
package/dist/index.cjs
CHANGED
|
@@ -19,20 +19,20 @@ var SOCIAL_HOSTS = [
|
|
|
19
19
|
var SEARCH_HOSTS = ["google.", "bing.", "duckduckgo.", "yahoo.", "baidu.", "ecosia."];
|
|
20
20
|
function parseAttribution(search, referrer) {
|
|
21
21
|
const q = new URLSearchParams(search || "");
|
|
22
|
-
const
|
|
22
|
+
const get2 = (k) => {
|
|
23
23
|
const v = q.get(k);
|
|
24
24
|
return v ? v.trim() : void 0;
|
|
25
25
|
};
|
|
26
26
|
const a = {
|
|
27
27
|
utm: {
|
|
28
|
-
source:
|
|
29
|
-
medium:
|
|
30
|
-
campaign:
|
|
31
|
-
term:
|
|
32
|
-
content:
|
|
28
|
+
source: get2("utm_source"),
|
|
29
|
+
medium: get2("utm_medium"),
|
|
30
|
+
campaign: get2("utm_campaign"),
|
|
31
|
+
term: get2("utm_term"),
|
|
32
|
+
content: get2("utm_content")
|
|
33
33
|
},
|
|
34
34
|
referrer: referrer ? referrer.trim() : void 0,
|
|
35
|
-
refCode:
|
|
35
|
+
refCode: get2("ref") || get2("refCode") || get2("ref_code") || void 0
|
|
36
36
|
};
|
|
37
37
|
a.channel = deriveChannel(a);
|
|
38
38
|
return a;
|
|
@@ -289,13 +289,13 @@ var HZ_ANON_ADOPT = ["hz_anon_id", "hz_id"];
|
|
|
289
289
|
var HZ_ANON_DOMAIN = "hanzo.ai";
|
|
290
290
|
var HZ_ANON_MAX_AGE = 2 * 365 * 24 * 60 * 60;
|
|
291
291
|
var hzAnonMemo;
|
|
292
|
-
function hzUuidv7(
|
|
292
|
+
function hzUuidv7(now2) {
|
|
293
293
|
var b = new Uint8Array(16);
|
|
294
294
|
var i;
|
|
295
295
|
var c = typeof crypto !== "undefined" ? crypto : void 0;
|
|
296
296
|
if (c && typeof c.getRandomValues === "function") c.getRandomValues(b);
|
|
297
297
|
else for (i = 0; i < 16; i++) b[i] = Math.random() * 256 | 0;
|
|
298
|
-
var t = Math.floor(
|
|
298
|
+
var t = Math.floor(now2 === void 0 ? Date.now() : now2);
|
|
299
299
|
for (i = 5; i >= 0; i--) {
|
|
300
300
|
b[i] = t % 256;
|
|
301
301
|
t = Math.floor(t / 256);
|
|
@@ -391,6 +391,15 @@ function hzAnonId() {
|
|
|
391
391
|
}
|
|
392
392
|
return id;
|
|
393
393
|
}
|
|
394
|
+
function hzAnonAdopt(id) {
|
|
395
|
+
hzAnonMemo = id;
|
|
396
|
+
hzAnonWrite(HZ_ANON_KEY, id);
|
|
397
|
+
try {
|
|
398
|
+
var s = hzAnonStore();
|
|
399
|
+
if (s) s.setItem(HZ_ANON_KEY, id);
|
|
400
|
+
} catch (e) {
|
|
401
|
+
}
|
|
402
|
+
}
|
|
394
403
|
|
|
395
404
|
// src/uid.ts
|
|
396
405
|
function uuidv7Time(id) {
|
|
@@ -398,7 +407,7 @@ function uuidv7Time(id) {
|
|
|
398
407
|
}
|
|
399
408
|
|
|
400
409
|
// package.json
|
|
401
|
-
var version = "0.3.
|
|
410
|
+
var version = "0.3.44";
|
|
402
411
|
|
|
403
412
|
// src/version.ts
|
|
404
413
|
var VERSION = version;
|
|
@@ -531,22 +540,22 @@ function coerceTag(v) {
|
|
|
531
540
|
return s.length > MAX_TAG_LEN ? s.slice(0, MAX_TAG_LEN) : s;
|
|
532
541
|
}
|
|
533
542
|
function buildSentryEvent(input) {
|
|
534
|
-
const { error, options = {}, identity, capturePII = false } = input;
|
|
543
|
+
const { error, options: options2 = {}, identity, capturePII = false } = input;
|
|
535
544
|
const norm = normalizeError(error);
|
|
536
|
-
const handled =
|
|
537
|
-
const level =
|
|
538
|
-
const
|
|
539
|
-
if (identity.product)
|
|
540
|
-
if (identity.sessionId)
|
|
545
|
+
const handled = options2.handled !== false;
|
|
546
|
+
const level = options2.level ?? (handled ? "error" : "fatal");
|
|
547
|
+
const tags2 = { handled: String(handled) };
|
|
548
|
+
if (identity.product) tags2.product = identity.product;
|
|
549
|
+
if (identity.sessionId) tags2.session = identity.sessionId;
|
|
541
550
|
try {
|
|
542
|
-
const props =
|
|
551
|
+
const props = options2.properties ?? {};
|
|
543
552
|
let n = 0;
|
|
544
553
|
for (const k of Object.keys(props)) {
|
|
545
554
|
if (n >= MAX_TAGS) break;
|
|
546
555
|
try {
|
|
547
556
|
const val = props[k];
|
|
548
557
|
if (val === void 0 || val === null) continue;
|
|
549
|
-
|
|
558
|
+
tags2[k] = scrubText(coerceTag(val), capturePII);
|
|
550
559
|
n++;
|
|
551
560
|
} catch {
|
|
552
561
|
continue;
|
|
@@ -571,7 +580,7 @@ function buildSentryEvent(input) {
|
|
|
571
580
|
}
|
|
572
581
|
]
|
|
573
582
|
},
|
|
574
|
-
tags,
|
|
583
|
+
tags: tags2,
|
|
575
584
|
sdk: { name: "@hanzo/event", version: VERSION }
|
|
576
585
|
};
|
|
577
586
|
if (identity.userId) event.user = { id: identity.userId };
|
|
@@ -701,7 +710,7 @@ function ls() {
|
|
|
701
710
|
function anonId() {
|
|
702
711
|
return hzAnonId() || void 0;
|
|
703
712
|
}
|
|
704
|
-
function sessionId(
|
|
713
|
+
function sessionId(now2 = Date.now()) {
|
|
705
714
|
const s = ls();
|
|
706
715
|
if (!s) return void 0;
|
|
707
716
|
let state = null;
|
|
@@ -710,14 +719,21 @@ function sessionId(now = Date.now()) {
|
|
|
710
719
|
} catch {
|
|
711
720
|
state = null;
|
|
712
721
|
}
|
|
713
|
-
if (!state ||
|
|
714
|
-
state = { id: hzUuidv7(
|
|
722
|
+
if (!state || now2 - state.last > SESSION_TTL_MS) {
|
|
723
|
+
state = { id: hzUuidv7(now2), last: now2 };
|
|
715
724
|
} else {
|
|
716
|
-
state.last =
|
|
725
|
+
state.last = now2;
|
|
717
726
|
}
|
|
718
727
|
s.setItem(KEY.session, JSON.stringify(state));
|
|
719
728
|
return state.id;
|
|
720
729
|
}
|
|
730
|
+
function adoptSession(id, now2 = Date.now()) {
|
|
731
|
+
const s = ls();
|
|
732
|
+
if (s) s.setItem(KEY.session, JSON.stringify({ id, last: now2 }));
|
|
733
|
+
}
|
|
734
|
+
function adoptAnonId(id) {
|
|
735
|
+
hzAnonAdopt(id);
|
|
736
|
+
}
|
|
721
737
|
function getFirstTouch() {
|
|
722
738
|
const s = ls();
|
|
723
739
|
if (!s) return void 0;
|
|
@@ -757,6 +773,76 @@ function mergeCohort(patch) {
|
|
|
757
773
|
return next;
|
|
758
774
|
}
|
|
759
775
|
|
|
776
|
+
// src/link.ts
|
|
777
|
+
var LINK_PARAMS = { anon: "hz_aid", session: "hz_sid", firstTouch: "hz_ft" };
|
|
778
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
779
|
+
var isId = (v) => !!v && UUID.test(v);
|
|
780
|
+
function encodeFirstTouch(a) {
|
|
781
|
+
return JSON.stringify([
|
|
782
|
+
a.utm.source,
|
|
783
|
+
a.utm.medium,
|
|
784
|
+
a.utm.campaign,
|
|
785
|
+
a.utm.term,
|
|
786
|
+
a.utm.content,
|
|
787
|
+
a.refCode,
|
|
788
|
+
a.referrer,
|
|
789
|
+
a.channel
|
|
790
|
+
].map((v) => v ?? ""));
|
|
791
|
+
}
|
|
792
|
+
function decodeFirstTouch(raw) {
|
|
793
|
+
if (!raw || raw.length > 1024) return void 0;
|
|
794
|
+
try {
|
|
795
|
+
const t = JSON.parse(raw);
|
|
796
|
+
if (!Array.isArray(t) || t.length !== 8 || t.some((v) => typeof v !== "string")) return void 0;
|
|
797
|
+
const [source, medium, campaign, term, content, refCode, referrer, channel] = t;
|
|
798
|
+
const u = (v) => v || void 0;
|
|
799
|
+
return {
|
|
800
|
+
utm: { source: u(source), medium: u(medium), campaign: u(campaign), term: u(term), content: u(content) },
|
|
801
|
+
refCode: u(refCode),
|
|
802
|
+
referrer: u(referrer),
|
|
803
|
+
channel: u(channel)
|
|
804
|
+
};
|
|
805
|
+
} catch {
|
|
806
|
+
return void 0;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function linkUrl(url, state, fromHost, base) {
|
|
810
|
+
let u;
|
|
811
|
+
try {
|
|
812
|
+
u = new URL(url, base);
|
|
813
|
+
} catch {
|
|
814
|
+
return url;
|
|
815
|
+
}
|
|
816
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return url;
|
|
817
|
+
if (!orgOf(u.hostname) || u.hostname === fromHost) return url;
|
|
818
|
+
const set2 = (k, v) => v && u.searchParams.set(k, v);
|
|
819
|
+
if (isId(state.anonId)) set2(LINK_PARAMS.anon, state.anonId);
|
|
820
|
+
if (isId(state.sessionId)) set2(LINK_PARAMS.session, state.sessionId);
|
|
821
|
+
if (state.firstTouch) set2(LINK_PARAMS.firstTouch, encodeFirstTouch(state.firstTouch));
|
|
822
|
+
return u.toString();
|
|
823
|
+
}
|
|
824
|
+
function readLink(search) {
|
|
825
|
+
const q = new URLSearchParams(search || "");
|
|
826
|
+
const a = q.get(LINK_PARAMS.anon);
|
|
827
|
+
const s = q.get(LINK_PARAMS.session);
|
|
828
|
+
return {
|
|
829
|
+
anonId: isId(a) ? a : void 0,
|
|
830
|
+
sessionId: isId(s) ? s : void 0,
|
|
831
|
+
firstTouch: decodeFirstTouch(q.get(LINK_PARAMS.firstTouch))
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function stripLink(href) {
|
|
835
|
+
const u = new URL(href);
|
|
836
|
+
let hit = false;
|
|
837
|
+
for (const k of Object.values(LINK_PARAMS)) {
|
|
838
|
+
if (u.searchParams.has(k)) {
|
|
839
|
+
u.searchParams.delete(k);
|
|
840
|
+
hit = true;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return hit ? u.pathname + u.search + u.hash : void 0;
|
|
844
|
+
}
|
|
845
|
+
|
|
760
846
|
// src/core.ts
|
|
761
847
|
var EVENT_PATH = "/v1/event";
|
|
762
848
|
var DEFAULT_HOST = "https://api.hanzo.ai";
|
|
@@ -917,8 +1003,19 @@ var Analytics = class {
|
|
|
917
1003
|
if (this.started || !this.cfg.enabled) return;
|
|
918
1004
|
this.started = true;
|
|
919
1005
|
if (!isBrowser()) return;
|
|
1006
|
+
const linked = readLink(window.location.search);
|
|
1007
|
+
if (linked.anonId) adoptAnonId(linked.anonId);
|
|
1008
|
+
if (linked.sessionId) adoptSession(linked.sessionId);
|
|
1009
|
+
const clean = stripLink(window.location.href);
|
|
1010
|
+
if (clean !== void 0) {
|
|
1011
|
+
try {
|
|
1012
|
+
window.history.replaceState(window.history.state, "", clean);
|
|
1013
|
+
} catch {
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
920
1016
|
const parsed = parseAttribution(window.location.search, document.referrer);
|
|
921
|
-
|
|
1017
|
+
const first = linked.firstTouch && !getFirstTouch() ? setFirstTouchOnce(linked.firstTouch) : void 0;
|
|
1018
|
+
this.attribution = first ?? (hasAttribution(parsed) ? setFirstTouchOnce(parsed) : getFirstTouch() ?? parsed);
|
|
922
1019
|
this.cohort = mergeCohort({
|
|
923
1020
|
channel: this.attribution.channel ?? deriveChannel(this.attribution),
|
|
924
1021
|
refCode: this.attribution.refCode
|
|
@@ -937,6 +1034,27 @@ var Analytics = class {
|
|
|
937
1034
|
});
|
|
938
1035
|
}
|
|
939
1036
|
}
|
|
1037
|
+
/** link returns `url` carrying this visitor's anonymous id, session and first
|
|
1038
|
+
* touch when the destination is a Hanzo-owned host, so the journey continues
|
|
1039
|
+
* across the hop. Any other URL comes back unchanged. */
|
|
1040
|
+
link(url) {
|
|
1041
|
+
if (!isBrowser()) return url;
|
|
1042
|
+
if (!this.started) this.init();
|
|
1043
|
+
return linkUrl(
|
|
1044
|
+
url,
|
|
1045
|
+
{ anonId: anonId(), sessionId: sessionId(), firstTouch: this.attribution },
|
|
1046
|
+
window.location.hostname,
|
|
1047
|
+
window.location.href
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
/** authorize decorates an OAuth authorize URL for the redirect to IAM and flushes
|
|
1051
|
+
* what is queued, because the page is about to unload. Assign the result to
|
|
1052
|
+
* `location`. */
|
|
1053
|
+
authorize(url) {
|
|
1054
|
+
const out = this.link(url);
|
|
1055
|
+
this.flush(true);
|
|
1056
|
+
return out;
|
|
1057
|
+
}
|
|
940
1058
|
/** identify binds the current visitor to a stable person id (post-login). */
|
|
941
1059
|
identify(personId, traits) {
|
|
942
1060
|
this.personId = personId;
|
|
@@ -1050,11 +1168,11 @@ var Analytics = class {
|
|
|
1050
1168
|
* or publishable key is attached here — the two planes authenticate
|
|
1051
1169
|
* independently. Errors are sent one envelope per event, immediately: batching
|
|
1052
1170
|
* a crash report is how you lose it. */
|
|
1053
|
-
sendError(err,
|
|
1171
|
+
sendError(err, options2) {
|
|
1054
1172
|
if (!this.cfg.enabled || !this.dsn) return;
|
|
1055
1173
|
const event = buildSentryEvent({
|
|
1056
1174
|
error: err,
|
|
1057
|
-
options,
|
|
1175
|
+
options: options2,
|
|
1058
1176
|
identity: this.errorIdentity(),
|
|
1059
1177
|
capturePII: this.cfg.capturePII ?? false
|
|
1060
1178
|
});
|
|
@@ -1141,16 +1259,16 @@ var Analytics = class {
|
|
|
1141
1259
|
};
|
|
1142
1260
|
var CLIENTS = /* @__PURE__ */ Symbol.for("hanzo.event.clients");
|
|
1143
1261
|
function registry() {
|
|
1144
|
-
const
|
|
1145
|
-
const existing =
|
|
1262
|
+
const g2 = globalThis;
|
|
1263
|
+
const existing = g2[CLIENTS];
|
|
1146
1264
|
if (existing) return existing;
|
|
1147
1265
|
const fresh = /* @__PURE__ */ new Map();
|
|
1148
|
-
|
|
1266
|
+
g2[CLIENTS] = fresh;
|
|
1149
1267
|
return fresh;
|
|
1150
1268
|
}
|
|
1151
1269
|
function resetClients() {
|
|
1152
|
-
const
|
|
1153
|
-
delete
|
|
1270
|
+
const g2 = globalThis;
|
|
1271
|
+
delete g2[CLIENTS];
|
|
1154
1272
|
}
|
|
1155
1273
|
function createAnalytics(config) {
|
|
1156
1274
|
if (!isBrowser() || config.enabled === false) return new Analytics(config);
|
|
@@ -1166,6 +1284,427 @@ function createAnalytics(config) {
|
|
|
1166
1284
|
return fresh;
|
|
1167
1285
|
}
|
|
1168
1286
|
|
|
1287
|
+
// src/cookie.ts
|
|
1288
|
+
var DAY = 86400;
|
|
1289
|
+
function domain() {
|
|
1290
|
+
const h = window.location.hostname;
|
|
1291
|
+
if (h === "localhost" || /^[\d.]+$/.test(h) || h.includes(":")) return "";
|
|
1292
|
+
const parts = h.split(".");
|
|
1293
|
+
return parts.length > 2 ? `; Domain=.${parts.slice(-2).join(".")}` : `; Domain=.${h}`;
|
|
1294
|
+
}
|
|
1295
|
+
function get(name) {
|
|
1296
|
+
if (typeof document === "undefined") return void 0;
|
|
1297
|
+
const hit = document.cookie.split("; ").find((c) => c.startsWith(`${name}=`));
|
|
1298
|
+
return hit ? decodeURIComponent(hit.slice(name.length + 1)) : void 0;
|
|
1299
|
+
}
|
|
1300
|
+
function set(name, value, days) {
|
|
1301
|
+
if (typeof document === "undefined") return;
|
|
1302
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
1303
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${days * DAY}; Path=/; SameSite=Lax${domain()}${secure}`;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// src/consent.ts
|
|
1307
|
+
var CONSENT_COOKIE = "hz_consent";
|
|
1308
|
+
var CONSENT_EVENT = "hzconsent";
|
|
1309
|
+
var US = /^(America\/(New_York|Chicago|Denver|Los_Angeles|Phoenix|Anchorage|Adak|Boise|Detroit|Juneau|Sitka|Nome|Yakutat|Menominee|Metlakatla|Indiana\/.*|Kentucky\/.*|North_Dakota\/.*)|Pacific\/Honolulu|US\/.*)$/;
|
|
1310
|
+
function gpc() {
|
|
1311
|
+
if (typeof navigator === "undefined") return false;
|
|
1312
|
+
return navigator.globalPrivacyControl === true;
|
|
1313
|
+
}
|
|
1314
|
+
function refused() {
|
|
1315
|
+
if (typeof window === "undefined") return false;
|
|
1316
|
+
const n = navigator;
|
|
1317
|
+
const dnt = n.doNotTrack ?? window.doNotTrack ?? n.msDoNotTrack;
|
|
1318
|
+
return gpc() || dnt === "1" || dnt === "yes";
|
|
1319
|
+
}
|
|
1320
|
+
function region() {
|
|
1321
|
+
try {
|
|
1322
|
+
const zone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? "";
|
|
1323
|
+
return US.test(zone) ? "opt-out" : "opt-in";
|
|
1324
|
+
} catch {
|
|
1325
|
+
return "opt-in";
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
function stored() {
|
|
1329
|
+
return get(CONSENT_COOKIE) !== void 0;
|
|
1330
|
+
}
|
|
1331
|
+
function read2() {
|
|
1332
|
+
const kept = get(CONSENT_COOKIE);
|
|
1333
|
+
const on = kept !== void 0 ? kept.split(",") : region() === "opt-in" || refused() ? [] : ["analytics", "marketing", "ads"];
|
|
1334
|
+
const has = (k) => on.includes(k);
|
|
1335
|
+
return { analytics: has("analytics"), marketing: has("marketing") && !gpc(), ads: has("ads") && !gpc() };
|
|
1336
|
+
}
|
|
1337
|
+
function asks() {
|
|
1338
|
+
return typeof document !== "undefined" && region() === "opt-in" && !stored();
|
|
1339
|
+
}
|
|
1340
|
+
function render(c) {
|
|
1341
|
+
return ["analytics", "marketing", "ads"].filter((k) => c[k]).join(",");
|
|
1342
|
+
}
|
|
1343
|
+
function save(c) {
|
|
1344
|
+
const out = { analytics: c.analytics, marketing: c.marketing && !gpc(), ads: c.ads && !gpc() };
|
|
1345
|
+
set(CONSENT_COOKIE, render(out), 395);
|
|
1346
|
+
if (typeof window !== "undefined") window.dispatchEvent(new Event(CONSENT_EVENT));
|
|
1347
|
+
}
|
|
1348
|
+
var acceptAll = () => save({ analytics: true, marketing: true, ads: true });
|
|
1349
|
+
var rejectAll = () => save({ analytics: false, marketing: false, ads: false });
|
|
1350
|
+
|
|
1351
|
+
// src/touch.ts
|
|
1352
|
+
var CLICK_IDS = ["gclid", "gbraid", "wbraid", "fbclid", "li_fat_id", "twclid", "ttclid"];
|
|
1353
|
+
var DAYS = 90;
|
|
1354
|
+
var now = () => Math.floor(Date.now() / 1e3);
|
|
1355
|
+
var rand = () => Math.floor(Math.random() * 2 ** 31);
|
|
1356
|
+
function capture(c) {
|
|
1357
|
+
if (typeof window === "undefined") return;
|
|
1358
|
+
if (c.marketing) {
|
|
1359
|
+
const q = new URLSearchParams(window.location.search);
|
|
1360
|
+
const click = {};
|
|
1361
|
+
for (const k of CLICK_IDS) {
|
|
1362
|
+
const v = q.get(k)?.trim();
|
|
1363
|
+
if (v) click[k] = v;
|
|
1364
|
+
}
|
|
1365
|
+
if (Object.keys(click).length) {
|
|
1366
|
+
click.clicked = now();
|
|
1367
|
+
set("hz_touch", JSON.stringify(click), DAYS);
|
|
1368
|
+
if (click.fbclid) set("_fbc", `fb.1.${Date.now()}.${click.fbclid}`, DAYS);
|
|
1369
|
+
}
|
|
1370
|
+
if (!get("_fbp")) set("_fbp", `fb.1.${Date.now()}.${rand()}`, DAYS);
|
|
1371
|
+
}
|
|
1372
|
+
if (c.analytics && !get("_ga") && !get("hz_cid")) set("hz_cid", `${rand()}.${now()}`, 730);
|
|
1373
|
+
}
|
|
1374
|
+
function touch(c) {
|
|
1375
|
+
const out = {};
|
|
1376
|
+
if (c.marketing) {
|
|
1377
|
+
try {
|
|
1378
|
+
Object.assign(out, JSON.parse(get("hz_touch") ?? "{}"));
|
|
1379
|
+
} catch {
|
|
1380
|
+
}
|
|
1381
|
+
const fbc = get("_fbc");
|
|
1382
|
+
const fbp = get("_fbp");
|
|
1383
|
+
if (fbc) out.fbc = fbc;
|
|
1384
|
+
if (fbp) out.fbp = fbp;
|
|
1385
|
+
}
|
|
1386
|
+
if (c.analytics) {
|
|
1387
|
+
const ga = get("_ga")?.split(".");
|
|
1388
|
+
const cid = ga && ga.length >= 4 ? ga.slice(-2).join(".") : get("hz_cid");
|
|
1389
|
+
if (cid) out.cid = cid;
|
|
1390
|
+
}
|
|
1391
|
+
return out;
|
|
1392
|
+
}
|
|
1393
|
+
var page = () => window;
|
|
1394
|
+
var tags = [];
|
|
1395
|
+
var configured = false;
|
|
1396
|
+
var options = {};
|
|
1397
|
+
var loaded = /* @__PURE__ */ new Set();
|
|
1398
|
+
var google = "idle";
|
|
1399
|
+
var configAnswered = false;
|
|
1400
|
+
var held = [];
|
|
1401
|
+
var leaving = false;
|
|
1402
|
+
function settled() {
|
|
1403
|
+
return configAnswered && google !== "wait";
|
|
1404
|
+
}
|
|
1405
|
+
function flush() {
|
|
1406
|
+
if (settled() || leaving) held.splice(0).forEach((send) => send());
|
|
1407
|
+
}
|
|
1408
|
+
function script(src, onload, onerror) {
|
|
1409
|
+
const s = document.createElement("script");
|
|
1410
|
+
s.async = true;
|
|
1411
|
+
s.src = src;
|
|
1412
|
+
if (onload) s.onload = onload;
|
|
1413
|
+
if (onerror) s.onerror = onerror;
|
|
1414
|
+
document.head.appendChild(s);
|
|
1415
|
+
}
|
|
1416
|
+
function gtagStub() {
|
|
1417
|
+
const p = page();
|
|
1418
|
+
p.dataLayer = p.dataLayer || [];
|
|
1419
|
+
if (!p.gtag) {
|
|
1420
|
+
p.gtag = function() {
|
|
1421
|
+
p.dataLayer.push(arguments);
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
return p.gtag;
|
|
1425
|
+
}
|
|
1426
|
+
var g = (on) => on ? "granted" : "denied";
|
|
1427
|
+
function consentMode(c, first) {
|
|
1428
|
+
const gtag = gtagStub();
|
|
1429
|
+
const state = {
|
|
1430
|
+
analytics_storage: g(c.analytics),
|
|
1431
|
+
ad_storage: g(c.marketing),
|
|
1432
|
+
ad_user_data: g(c.marketing),
|
|
1433
|
+
ad_personalization: g(c.marketing && c.ads)
|
|
1434
|
+
};
|
|
1435
|
+
if (first) {
|
|
1436
|
+
gtag("consent", "default", {
|
|
1437
|
+
analytics_storage: "denied",
|
|
1438
|
+
ad_storage: "denied",
|
|
1439
|
+
ad_user_data: "denied",
|
|
1440
|
+
ad_personalization: "denied",
|
|
1441
|
+
wait_for_update: 500
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
gtag("consent", "update", state);
|
|
1445
|
+
}
|
|
1446
|
+
function loadGoogle(ids) {
|
|
1447
|
+
const gtag = gtagStub();
|
|
1448
|
+
const fresh = ids.filter((id) => !loaded.has(id));
|
|
1449
|
+
if (!fresh.length) return;
|
|
1450
|
+
if (google === "idle") {
|
|
1451
|
+
google = "wait";
|
|
1452
|
+
gtag("js", /* @__PURE__ */ new Date());
|
|
1453
|
+
const done = (to) => () => {
|
|
1454
|
+
if (google !== "wait") return;
|
|
1455
|
+
google = to;
|
|
1456
|
+
flush();
|
|
1457
|
+
};
|
|
1458
|
+
script(`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(fresh[0])}`, done("loaded"), done("failed"));
|
|
1459
|
+
setTimeout(done("failed"), 8e3);
|
|
1460
|
+
}
|
|
1461
|
+
for (const id of fresh) {
|
|
1462
|
+
loaded.add(id);
|
|
1463
|
+
gtag("config", id, options.domains ? { linker: { domains: options.domains } } : {});
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
function loadMeta(id, c) {
|
|
1467
|
+
const p = page();
|
|
1468
|
+
if (!p.fbq) {
|
|
1469
|
+
const n = p.fbq = function(...a) {
|
|
1470
|
+
if (n.callMethod) n.callMethod(...a);
|
|
1471
|
+
else n.queue.push(a);
|
|
1472
|
+
};
|
|
1473
|
+
if (!p._fbq) p._fbq = n;
|
|
1474
|
+
n.push = n;
|
|
1475
|
+
n.loaded = true;
|
|
1476
|
+
n.version = "2.0";
|
|
1477
|
+
n.queue = [];
|
|
1478
|
+
script("https://connect.facebook.net/en_US/fbevents.js");
|
|
1479
|
+
}
|
|
1480
|
+
if (!c.ads) p.fbq("dataProcessingOptions", ["LDU"], 0, 0);
|
|
1481
|
+
p.fbq("init", id);
|
|
1482
|
+
p.fbq("track", "PageView");
|
|
1483
|
+
}
|
|
1484
|
+
function loadLinkedIn(id) {
|
|
1485
|
+
const p = page();
|
|
1486
|
+
p._linkedin_data_partner_ids = p._linkedin_data_partner_ids || [];
|
|
1487
|
+
p._linkedin_data_partner_ids.push(id);
|
|
1488
|
+
if (!p.lintrk) {
|
|
1489
|
+
const l = p.lintrk = function(...a) {
|
|
1490
|
+
l.q.push(a);
|
|
1491
|
+
};
|
|
1492
|
+
l.q = [];
|
|
1493
|
+
}
|
|
1494
|
+
script("https://snap.licdn.com/li.lms-analytics/insight.min.js");
|
|
1495
|
+
}
|
|
1496
|
+
function loadX(id) {
|
|
1497
|
+
const p = page();
|
|
1498
|
+
if (!p.twq) {
|
|
1499
|
+
const s = p.twq = function(...a) {
|
|
1500
|
+
if (s.exe) s.exe(...a);
|
|
1501
|
+
else s.queue.push(a);
|
|
1502
|
+
};
|
|
1503
|
+
s.version = "1.1";
|
|
1504
|
+
s.queue = [];
|
|
1505
|
+
script("https://static.ads-twitter.com/uwt.js");
|
|
1506
|
+
}
|
|
1507
|
+
p.twq("config", id);
|
|
1508
|
+
}
|
|
1509
|
+
var TIKTOK_METHODS = ["page", "track", "identify", "instances", "debug", "on", "off", "once", "ready", "alias", "group", "enableCookie", "disableCookie"];
|
|
1510
|
+
function loadTikTok(id) {
|
|
1511
|
+
const p = page();
|
|
1512
|
+
p.TiktokAnalyticsObject = "ttq";
|
|
1513
|
+
const q = p.ttq = p.ttq || [];
|
|
1514
|
+
if (!q._i) {
|
|
1515
|
+
q.methods = TIKTOK_METHODS;
|
|
1516
|
+
for (const m of TIKTOK_METHODS) q[m] = (...a) => q.push([m, ...a]);
|
|
1517
|
+
q._i = {};
|
|
1518
|
+
q._t = {};
|
|
1519
|
+
q._o = {};
|
|
1520
|
+
q.load = (sdk) => {
|
|
1521
|
+
q._i[sdk] = [];
|
|
1522
|
+
q._t[sdk] = Date.now();
|
|
1523
|
+
script(`https://analytics.tiktok.com/i18n/pixel/events.js?sdkid=${encodeURIComponent(sdk)}&lib=ttq`);
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
q.load(id);
|
|
1527
|
+
q.page();
|
|
1528
|
+
}
|
|
1529
|
+
var NEEDS = {
|
|
1530
|
+
ga: "analytics",
|
|
1531
|
+
gads: "marketing",
|
|
1532
|
+
meta: "marketing",
|
|
1533
|
+
linkedin: "marketing",
|
|
1534
|
+
x: "marketing",
|
|
1535
|
+
tiktok: "marketing"
|
|
1536
|
+
};
|
|
1537
|
+
var allowed = (t, c) => t.type === "ga" ? c.analytics || c.marketing : Boolean(NEEDS[t.type] && c[NEEDS[t.type]]);
|
|
1538
|
+
function apply() {
|
|
1539
|
+
if (typeof window === "undefined" || !configured) return;
|
|
1540
|
+
const c = read2();
|
|
1541
|
+
capture(c);
|
|
1542
|
+
const on = tags.filter((t) => allowed(t, c));
|
|
1543
|
+
const ids = on.filter((t) => t.type === "ga" || t.type === "gads").map((t) => t.id);
|
|
1544
|
+
if (ids.length) {
|
|
1545
|
+
consentMode(c, !loaded.has("consent"));
|
|
1546
|
+
loaded.add("consent");
|
|
1547
|
+
loadGoogle(ids);
|
|
1548
|
+
}
|
|
1549
|
+
for (const t of on) {
|
|
1550
|
+
const k = `${t.type}:${t.id}`;
|
|
1551
|
+
if (loaded.has(k)) continue;
|
|
1552
|
+
if (t.type === "meta") loadMeta(t.id, c);
|
|
1553
|
+
else if (t.type === "linkedin") loadLinkedIn(t.id);
|
|
1554
|
+
else if (t.type === "x") loadX(t.id);
|
|
1555
|
+
else if (t.type === "tiktok") loadTikTok(t.id);
|
|
1556
|
+
else continue;
|
|
1557
|
+
loaded.add(k);
|
|
1558
|
+
}
|
|
1559
|
+
flush();
|
|
1560
|
+
}
|
|
1561
|
+
function start(o = {}) {
|
|
1562
|
+
if (typeof window === "undefined") return () => void 0;
|
|
1563
|
+
options = o;
|
|
1564
|
+
addEventListener(CONSENT_EVENT, apply);
|
|
1565
|
+
addEventListener("pagehide", pagehide);
|
|
1566
|
+
if (!configured) {
|
|
1567
|
+
configured = true;
|
|
1568
|
+
const base = (o.base ?? "https://api.hanzo.ai").replace(/\/$/, "");
|
|
1569
|
+
const q = new URLSearchParams();
|
|
1570
|
+
if (o.key) q.set("key", o.key);
|
|
1571
|
+
q.set("host", o.host ?? window.location.hostname);
|
|
1572
|
+
const answer = (list) => {
|
|
1573
|
+
tags = list;
|
|
1574
|
+
configAnswered = true;
|
|
1575
|
+
apply();
|
|
1576
|
+
};
|
|
1577
|
+
const cap = setTimeout(() => answer([]), 3e3);
|
|
1578
|
+
fetch(`${base}/v1/project/tags?${q}`).then((r) => r.ok ? r.json() : { tags: [] }).then((j) => {
|
|
1579
|
+
clearTimeout(cap);
|
|
1580
|
+
answer(Array.isArray(j.tags) ? j.tags : []);
|
|
1581
|
+
}).catch(() => {
|
|
1582
|
+
clearTimeout(cap);
|
|
1583
|
+
answer([]);
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
return () => {
|
|
1587
|
+
removeEventListener(CONSENT_EVENT, apply);
|
|
1588
|
+
removeEventListener("pagehide", pagehide);
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function pagehide() {
|
|
1592
|
+
leaving = true;
|
|
1593
|
+
flush();
|
|
1594
|
+
}
|
|
1595
|
+
function reach() {
|
|
1596
|
+
const c = read2();
|
|
1597
|
+
const to = [];
|
|
1598
|
+
for (const t of tags) {
|
|
1599
|
+
if (!allowed(t, c)) continue;
|
|
1600
|
+
const running = t.type === "ga" ? google === "loaded" && c.analytics : t.type === "gads" ? google === "loaded" && c.marketing : loaded.has(`${t.type}:${t.id}`);
|
|
1601
|
+
if (running && !to.includes(t.type)) to.push(t.type);
|
|
1602
|
+
}
|
|
1603
|
+
return to.join(",");
|
|
1604
|
+
}
|
|
1605
|
+
var META_STANDARD = /* @__PURE__ */ new Set([
|
|
1606
|
+
"AddPaymentInfo",
|
|
1607
|
+
"AddToCart",
|
|
1608
|
+
"AddToWishlist",
|
|
1609
|
+
"CompleteRegistration",
|
|
1610
|
+
"Contact",
|
|
1611
|
+
"CustomizeProduct",
|
|
1612
|
+
"Donate",
|
|
1613
|
+
"FindLocation",
|
|
1614
|
+
"InitiateCheckout",
|
|
1615
|
+
"Lead",
|
|
1616
|
+
"Purchase",
|
|
1617
|
+
"Schedule",
|
|
1618
|
+
"Search",
|
|
1619
|
+
"StartTrial",
|
|
1620
|
+
"SubmitApplication",
|
|
1621
|
+
"Subscribe",
|
|
1622
|
+
"ViewContent"
|
|
1623
|
+
]);
|
|
1624
|
+
function shape(platform, p) {
|
|
1625
|
+
const items = Array.isArray(p.items) ? p.items : [];
|
|
1626
|
+
const out = {};
|
|
1627
|
+
if (typeof p.value === "number") out.value = p.value;
|
|
1628
|
+
out.currency = typeof p.currency === "string" ? p.currency : "USD";
|
|
1629
|
+
if (!items.length) return out;
|
|
1630
|
+
if (platform === "meta") {
|
|
1631
|
+
out.content_type = "product";
|
|
1632
|
+
out.content_ids = items.map((i) => i.item_id);
|
|
1633
|
+
out.contents = items.map((i) => ({ id: i.item_id, quantity: i.quantity ?? 1, item_price: i.price }));
|
|
1634
|
+
out.content_name = items[0].item_name;
|
|
1635
|
+
out.num_items = items.reduce((n, i) => n + (i.quantity ?? 1), 0);
|
|
1636
|
+
} else if (platform === "tiktok") {
|
|
1637
|
+
out.content_type = "product";
|
|
1638
|
+
out.contents = items.map((i) => ({ content_id: i.item_id, content_name: i.item_name, quantity: i.quantity ?? 1, price: i.price }));
|
|
1639
|
+
} else {
|
|
1640
|
+
out.contents = items.map((i) => ({ content_id: i.item_id, content_name: i.item_name, content_price: i.price, num_items: i.quantity ?? 1 }));
|
|
1641
|
+
}
|
|
1642
|
+
return out;
|
|
1643
|
+
}
|
|
1644
|
+
function unpriced(p) {
|
|
1645
|
+
const out = { ...p, value: 0 };
|
|
1646
|
+
if (Array.isArray(p.items)) out.items = p.items.map((i) => ({ ...i, price: 0 }));
|
|
1647
|
+
return out;
|
|
1648
|
+
}
|
|
1649
|
+
function mirror(name, params, id, to = reach()) {
|
|
1650
|
+
const p = page();
|
|
1651
|
+
const on = new Set(to.split(",").filter(Boolean));
|
|
1652
|
+
const ga4 = events.namesOn(name, "ga4");
|
|
1653
|
+
const test = params.test === true;
|
|
1654
|
+
if (test) params = unpriced(params);
|
|
1655
|
+
const transaction = typeof params.order_id === "string" ? { transaction_id: params.order_id } : {};
|
|
1656
|
+
for (const t of tags) {
|
|
1657
|
+
if (!on.has(t.type)) continue;
|
|
1658
|
+
const rule = t.events?.[name];
|
|
1659
|
+
if (t.type === "ga") {
|
|
1660
|
+
for (const n of ga4) {
|
|
1661
|
+
p.gtag?.("event", n, { ...params, ...transaction, event_id: id, transport_type: "beacon", ...test ? { debug_mode: true } : {} });
|
|
1662
|
+
}
|
|
1663
|
+
} else if (t.type === "gads" && rule) {
|
|
1664
|
+
p.gtag?.("event", "conversion", {
|
|
1665
|
+
send_to: rule,
|
|
1666
|
+
value: typeof params.value === "number" ? params.value : void 0,
|
|
1667
|
+
currency: typeof params.currency === "string" ? params.currency : "USD",
|
|
1668
|
+
...transaction
|
|
1669
|
+
});
|
|
1670
|
+
} else if (t.type === "meta") {
|
|
1671
|
+
for (const n of events.namesOn(name, "meta")) {
|
|
1672
|
+
p.fbq?.(META_STANDARD.has(n) ? "track" : "trackCustom", n, shape("meta", params), { eventID: id });
|
|
1673
|
+
}
|
|
1674
|
+
} else if (t.type === "tiktok") {
|
|
1675
|
+
for (const n of events.namesOn(name, "tiktok")) p.ttq?.track?.(n, shape("tiktok", params), { event_id: id });
|
|
1676
|
+
} else if (t.type === "linkedin" && rule && events.namesOn(name, "linkedin").length) {
|
|
1677
|
+
p.lintrk?.("track", { conversion_id: Number(rule) });
|
|
1678
|
+
} else if (t.type === "x" && rule && events.namesOn(name, "x").length) {
|
|
1679
|
+
p.twq?.("event", rule, { ...shape("x", params), conversion_id: id });
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
function track(stream, name, params = {}) {
|
|
1684
|
+
if (typeof window === "undefined") return;
|
|
1685
|
+
if (!leaving && !settled()) {
|
|
1686
|
+
held.push(() => track(stream, name, params));
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
const c = read2();
|
|
1690
|
+
const event_id = crypto.randomUUID();
|
|
1691
|
+
const to = reach();
|
|
1692
|
+
mirror(name, params, event_id, to);
|
|
1693
|
+
stream?.capture(name, {
|
|
1694
|
+
...params,
|
|
1695
|
+
...touch(c),
|
|
1696
|
+
event_id,
|
|
1697
|
+
consent: render(c),
|
|
1698
|
+
tags: to,
|
|
1699
|
+
userAgent: navigator.userAgent,
|
|
1700
|
+
url: window.location.href
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
function visit() {
|
|
1704
|
+
const c = read2();
|
|
1705
|
+
return { ...touch(c), consent: render(c), tags: reach(), userAgent: navigator.userAgent, url: window.location.href };
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1169
1708
|
// src/goals.ts
|
|
1170
1709
|
var GOALS = {
|
|
1171
1710
|
// Signup: the conversion is signup_completed, along the site signup funnel.
|
|
@@ -1251,14 +1790,21 @@ Object.defineProperty(exports, "eventsOf", {
|
|
|
1251
1790
|
get: function () { return events.eventsOf; }
|
|
1252
1791
|
});
|
|
1253
1792
|
exports.Analytics = Analytics;
|
|
1793
|
+
exports.CLICK_IDS = CLICK_IDS;
|
|
1254
1794
|
exports.COHORTS = COHORTS;
|
|
1795
|
+
exports.CONSENT_COOKIE = CONSENT_COOKIE;
|
|
1796
|
+
exports.CONSENT_EVENT = CONSENT_EVENT;
|
|
1255
1797
|
exports.GOALS = GOALS;
|
|
1798
|
+
exports.LINK_PARAMS = LINK_PARAMS;
|
|
1256
1799
|
exports.ORG_DOMAIN = ORG_DOMAIN;
|
|
1257
1800
|
exports.ORG_KEY = ORG_KEY;
|
|
1258
1801
|
exports.PRODUCT_PROJECT = PRODUCT_PROJECT;
|
|
1259
1802
|
exports.VERSION = VERSION;
|
|
1803
|
+
exports.acceptAll = acceptAll;
|
|
1804
|
+
exports.asks = asks;
|
|
1260
1805
|
exports.buildEnvelope = buildEnvelope;
|
|
1261
1806
|
exports.buildSentryEvent = buildSentryEvent;
|
|
1807
|
+
exports.captureClick = capture;
|
|
1262
1808
|
exports.createAnalytics = createAnalytics;
|
|
1263
1809
|
exports.deriveChannel = deriveChannel;
|
|
1264
1810
|
exports.digest = digest;
|
|
@@ -1269,19 +1815,36 @@ exports.fingerprint = fingerprint;
|
|
|
1269
1815
|
exports.framesFromStack = framesFromStack;
|
|
1270
1816
|
exports.getCohort = getCohort;
|
|
1271
1817
|
exports.getFirstTouch = getFirstTouch;
|
|
1818
|
+
exports.gpc = gpc;
|
|
1272
1819
|
exports.hasAttribution = hasAttribution;
|
|
1273
1820
|
exports.hostOf = hostOf;
|
|
1274
1821
|
exports.isoWeek = isoWeek;
|
|
1275
1822
|
exports.keyFor = keyFor;
|
|
1276
1823
|
exports.keyForPage = keyForPage;
|
|
1824
|
+
exports.linkUrl = linkUrl;
|
|
1825
|
+
exports.mirror = mirror;
|
|
1277
1826
|
exports.orgOf = orgOf;
|
|
1278
1827
|
exports.parseAttribution = parseAttribution;
|
|
1279
1828
|
exports.parseDsn = parseDsn;
|
|
1829
|
+
exports.reach = reach;
|
|
1830
|
+
exports.readConsent = read2;
|
|
1831
|
+
exports.readLink = readLink;
|
|
1280
1832
|
exports.redactSecrets = redactSecrets;
|
|
1833
|
+
exports.refused = refused;
|
|
1834
|
+
exports.region = region;
|
|
1835
|
+
exports.rejectAll = rejectAll;
|
|
1836
|
+
exports.renderConsent = render;
|
|
1281
1837
|
exports.resetClients = resetClients;
|
|
1838
|
+
exports.saveConsent = save;
|
|
1282
1839
|
exports.scrubPII = scrubPII;
|
|
1283
1840
|
exports.scrubText = scrubText;
|
|
1841
|
+
exports.startTags = start;
|
|
1842
|
+
exports.storedConsent = stored;
|
|
1843
|
+
exports.stripLink = stripLink;
|
|
1844
|
+
exports.touch = touch;
|
|
1845
|
+
exports.track = track;
|
|
1284
1846
|
exports.uuidv7 = hzUuidv7;
|
|
1285
1847
|
exports.uuidv7Time = uuidv7Time;
|
|
1848
|
+
exports.visit = visit;
|
|
1286
1849
|
//# sourceMappingURL=index.cjs.map
|
|
1287
1850
|
//# sourceMappingURL=index.cjs.map
|