@hanzo/event 0.3.42 → 0.3.43
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/core.d.ts +8 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/index.cjs +124 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +121 -3
- 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/package.json +1 -1
- package/src/anon.d.ts +3 -0
- package/src/anon.js +19 -1
- package/src/core.ts +45 -3
- package/src/index.ts +2 -0
- package/src/link.test.ts +222 -0
- package/src/link.ts +103 -0
- package/src/storage.ts +14 -1
package/dist/react.mjs
CHANGED
|
@@ -384,9 +384,18 @@ function hzAnonId() {
|
|
|
384
384
|
}
|
|
385
385
|
return id;
|
|
386
386
|
}
|
|
387
|
+
function hzAnonAdopt(id) {
|
|
388
|
+
hzAnonMemo = id;
|
|
389
|
+
hzAnonWrite(HZ_ANON_KEY, id);
|
|
390
|
+
try {
|
|
391
|
+
var s = hzAnonStore();
|
|
392
|
+
if (s) s.setItem(HZ_ANON_KEY, id);
|
|
393
|
+
} catch (e) {
|
|
394
|
+
}
|
|
395
|
+
}
|
|
387
396
|
|
|
388
397
|
// package.json
|
|
389
|
-
var version = "0.3.
|
|
398
|
+
var version = "0.3.43";
|
|
390
399
|
|
|
391
400
|
// src/version.ts
|
|
392
401
|
var VERSION = version;
|
|
@@ -706,6 +715,13 @@ function sessionId(now = Date.now()) {
|
|
|
706
715
|
s.setItem(KEY.session, JSON.stringify(state));
|
|
707
716
|
return state.id;
|
|
708
717
|
}
|
|
718
|
+
function adoptSession(id, now = Date.now()) {
|
|
719
|
+
const s = ls();
|
|
720
|
+
if (s) s.setItem(KEY.session, JSON.stringify({ id, last: now }));
|
|
721
|
+
}
|
|
722
|
+
function adoptAnonId(id) {
|
|
723
|
+
hzAnonAdopt(id);
|
|
724
|
+
}
|
|
709
725
|
function getFirstTouch() {
|
|
710
726
|
const s = ls();
|
|
711
727
|
if (!s) return void 0;
|
|
@@ -745,6 +761,76 @@ function mergeCohort(patch) {
|
|
|
745
761
|
return next;
|
|
746
762
|
}
|
|
747
763
|
|
|
764
|
+
// src/link.ts
|
|
765
|
+
var LINK_PARAMS = { anon: "hz_aid", session: "hz_sid", firstTouch: "hz_ft" };
|
|
766
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
767
|
+
var isId = (v) => !!v && UUID.test(v);
|
|
768
|
+
function encodeFirstTouch(a) {
|
|
769
|
+
return JSON.stringify([
|
|
770
|
+
a.utm.source,
|
|
771
|
+
a.utm.medium,
|
|
772
|
+
a.utm.campaign,
|
|
773
|
+
a.utm.term,
|
|
774
|
+
a.utm.content,
|
|
775
|
+
a.refCode,
|
|
776
|
+
a.referrer,
|
|
777
|
+
a.channel
|
|
778
|
+
].map((v) => v ?? ""));
|
|
779
|
+
}
|
|
780
|
+
function decodeFirstTouch(raw) {
|
|
781
|
+
if (!raw || raw.length > 1024) return void 0;
|
|
782
|
+
try {
|
|
783
|
+
const t = JSON.parse(raw);
|
|
784
|
+
if (!Array.isArray(t) || t.length !== 8 || t.some((v) => typeof v !== "string")) return void 0;
|
|
785
|
+
const [source, medium, campaign, term, content, refCode, referrer, channel] = t;
|
|
786
|
+
const u = (v) => v || void 0;
|
|
787
|
+
return {
|
|
788
|
+
utm: { source: u(source), medium: u(medium), campaign: u(campaign), term: u(term), content: u(content) },
|
|
789
|
+
refCode: u(refCode),
|
|
790
|
+
referrer: u(referrer),
|
|
791
|
+
channel: u(channel)
|
|
792
|
+
};
|
|
793
|
+
} catch {
|
|
794
|
+
return void 0;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
function linkUrl(url, state, fromHost, base) {
|
|
798
|
+
let u;
|
|
799
|
+
try {
|
|
800
|
+
u = new URL(url, base);
|
|
801
|
+
} catch {
|
|
802
|
+
return url;
|
|
803
|
+
}
|
|
804
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return url;
|
|
805
|
+
if (!orgOf(u.hostname) || u.hostname === fromHost) return url;
|
|
806
|
+
const set = (k, v) => v && u.searchParams.set(k, v);
|
|
807
|
+
if (isId(state.anonId)) set(LINK_PARAMS.anon, state.anonId);
|
|
808
|
+
if (isId(state.sessionId)) set(LINK_PARAMS.session, state.sessionId);
|
|
809
|
+
if (state.firstTouch) set(LINK_PARAMS.firstTouch, encodeFirstTouch(state.firstTouch));
|
|
810
|
+
return u.toString();
|
|
811
|
+
}
|
|
812
|
+
function readLink(search) {
|
|
813
|
+
const q = new URLSearchParams(search || "");
|
|
814
|
+
const a = q.get(LINK_PARAMS.anon);
|
|
815
|
+
const s = q.get(LINK_PARAMS.session);
|
|
816
|
+
return {
|
|
817
|
+
anonId: isId(a) ? a : void 0,
|
|
818
|
+
sessionId: isId(s) ? s : void 0,
|
|
819
|
+
firstTouch: decodeFirstTouch(q.get(LINK_PARAMS.firstTouch))
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
function stripLink(href) {
|
|
823
|
+
const u = new URL(href);
|
|
824
|
+
let hit = false;
|
|
825
|
+
for (const k of Object.values(LINK_PARAMS)) {
|
|
826
|
+
if (u.searchParams.has(k)) {
|
|
827
|
+
u.searchParams.delete(k);
|
|
828
|
+
hit = true;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return hit ? u.pathname + u.search + u.hash : void 0;
|
|
832
|
+
}
|
|
833
|
+
|
|
748
834
|
// src/core.ts
|
|
749
835
|
var EVENT_PATH = "/v1/event";
|
|
750
836
|
var DEFAULT_HOST = "https://api.hanzo.ai";
|
|
@@ -905,8 +991,19 @@ var Analytics = class {
|
|
|
905
991
|
if (this.started || !this.cfg.enabled) return;
|
|
906
992
|
this.started = true;
|
|
907
993
|
if (!isBrowser()) return;
|
|
994
|
+
const linked = readLink(window.location.search);
|
|
995
|
+
if (linked.anonId) adoptAnonId(linked.anonId);
|
|
996
|
+
if (linked.sessionId) adoptSession(linked.sessionId);
|
|
997
|
+
const clean = stripLink(window.location.href);
|
|
998
|
+
if (clean !== void 0) {
|
|
999
|
+
try {
|
|
1000
|
+
window.history.replaceState(window.history.state, "", clean);
|
|
1001
|
+
} catch {
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
908
1004
|
const parsed = parseAttribution(window.location.search, document.referrer);
|
|
909
|
-
|
|
1005
|
+
const first = linked.firstTouch && !getFirstTouch() ? setFirstTouchOnce(linked.firstTouch) : void 0;
|
|
1006
|
+
this.attribution = first ?? (hasAttribution(parsed) ? setFirstTouchOnce(parsed) : getFirstTouch() ?? parsed);
|
|
910
1007
|
this.cohort = mergeCohort({
|
|
911
1008
|
channel: this.attribution.channel ?? deriveChannel(this.attribution),
|
|
912
1009
|
refCode: this.attribution.refCode
|
|
@@ -925,6 +1022,27 @@ var Analytics = class {
|
|
|
925
1022
|
});
|
|
926
1023
|
}
|
|
927
1024
|
}
|
|
1025
|
+
/** link returns `url` carrying this visitor's anonymous id, session and first
|
|
1026
|
+
* touch when the destination is a Hanzo-owned host, so the journey continues
|
|
1027
|
+
* across the hop. Any other URL comes back unchanged. */
|
|
1028
|
+
link(url) {
|
|
1029
|
+
if (!isBrowser()) return url;
|
|
1030
|
+
if (!this.started) this.init();
|
|
1031
|
+
return linkUrl(
|
|
1032
|
+
url,
|
|
1033
|
+
{ anonId: anonId(), sessionId: sessionId(), firstTouch: this.attribution },
|
|
1034
|
+
window.location.hostname,
|
|
1035
|
+
window.location.href
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
/** authorize decorates an OAuth authorize URL for the redirect to IAM and flushes
|
|
1039
|
+
* what is queued, because the page is about to unload. Assign the result to
|
|
1040
|
+
* `location`. */
|
|
1041
|
+
authorize(url) {
|
|
1042
|
+
const out = this.link(url);
|
|
1043
|
+
this.flush(true);
|
|
1044
|
+
return out;
|
|
1045
|
+
}
|
|
928
1046
|
/** identify binds the current visitor to a stable person id (post-login). */
|
|
929
1047
|
identify(personId, traits) {
|
|
930
1048
|
this.personId = personId;
|