@hanzo/event 0.3.41 → 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/events.d.ts +1 -1
- package/dist/index.cjs +133 -5
- 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 +130 -6
- 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 +129 -5
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +129 -5
- package/dist/react.mjs.map +1 -1
- package/dist/scrub.d.ts +5 -0
- package/dist/scrub.d.ts.map +1 -1
- package/dist/storage.d.ts +6 -0
- package/dist/storage.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/anon.d.ts +3 -0
- package/src/anon.js +19 -1
- package/src/core.test.ts +19 -0
- package/src/core.ts +52 -7
- package/src/events.ts +1 -1
- package/src/index.ts +2 -0
- package/src/link.test.ts +222 -0
- package/src/link.ts +103 -0
- package/src/scrub.test.ts +34 -1
- package/src/scrub.ts +20 -0
- package/src/storage.ts +14 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { Analytics, createAnalytics, resetClients, VERSION, getCohort, getFirstTouch, } from './core';
|
|
2
2
|
export { parseDsn, buildSentryEvent, buildEnvelope, framesFromStack } from './sentry';
|
|
3
3
|
export { uuidv7, uuidv7Time } from './uid';
|
|
4
|
+
export { linkUrl, readLink, stripLink, LINK_PARAMS } from './link';
|
|
5
|
+
export type { LinkState } from './link';
|
|
4
6
|
export { PRODUCT_PROJECT, dsnForProduct } from './dsn';
|
|
5
7
|
export type { ErrorIdentity } from './sentry';
|
|
6
8
|
export { scrubText, redactSecrets, scrubPII } from './scrub';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { Analytics, createAnalytics, resetClients, VERSION, getCohort, getFirstTouch, } from './core';
|
|
2
2
|
export { parseDsn, buildSentryEvent, buildEnvelope, framesFromStack } from './sentry';
|
|
3
3
|
export { uuidv7, uuidv7Time } from './uid';
|
|
4
|
+
export { linkUrl, readLink, stripLink, LINK_PARAMS } from './link';
|
|
5
|
+
export type { LinkState } from './link';
|
|
4
6
|
export { PRODUCT_PROJECT, dsnForProduct } from './dsn';
|
|
5
7
|
export type { ErrorIdentity } from './sentry';
|
|
6
8
|
export { scrubText, redactSecrets, scrubPII } from './scrub';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,SAAS,EACT,eAAe,EACf,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,GACd,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AACrF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACtF,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACxC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACvD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,MAAM,EACN,OAAO,GACR,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,MAAM,EACN,GAAG,EACH,SAAS,EACT,SAAS,EACT,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,EACT,SAAS,GACV,MAAM,SAAS,CAAA;AAEhB;;;kEAGkE;AAClE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AACtE,YAAY,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,SAAS,EACT,eAAe,EACf,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,GACd,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AACrF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAClE,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACtF,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACxC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACvD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,MAAM,EACN,OAAO,GACR,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,MAAM,EACN,GAAG,EACH,SAAS,EACT,SAAS,EACT,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,EACT,SAAS,GACV,MAAM,SAAS,CAAA;AAEhB;;;kEAGkE;AAClE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AACtE,YAAY,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -253,11 +253,17 @@ var RE_CREDENTIAL_PARAM = new RegExp(
|
|
|
253
253
|
function redactCredentialParams(s) {
|
|
254
254
|
return s.replace(RE_CREDENTIAL_PARAM, (_m, prefix) => prefix + REDACTED);
|
|
255
255
|
}
|
|
256
|
+
var RE_SECRET43 = /(^|[^A-Za-z0-9_-]|%[0-9A-Fa-f]{2})((?=[A-Za-z0-9_-]{0,42}[a-z])(?=[A-Za-z0-9_-]{0,42}[A-Z])[A-Za-z0-9_-]{43})(?![A-Za-z0-9_-])/g;
|
|
256
257
|
function redactSecrets(s) {
|
|
257
258
|
s = redactCredentialParams(s);
|
|
258
259
|
for (const re of SECRET_PATTERNS) s = s.replace(re, REDACTED);
|
|
260
|
+
s = s.replace(RE_SECRET43, (_m, lead) => lead + REDACTED);
|
|
259
261
|
return redactPAN(s);
|
|
260
262
|
}
|
|
263
|
+
function withoutFragment(url) {
|
|
264
|
+
const at = url.indexOf("#");
|
|
265
|
+
return at < 0 ? url : url.slice(0, at);
|
|
266
|
+
}
|
|
261
267
|
function scrubPII(s) {
|
|
262
268
|
s = s.replace(RE_EMAIL, EMAIL_MARK);
|
|
263
269
|
s = s.replace(RE_IPV6, IP_MARK);
|
|
@@ -384,6 +390,15 @@ function hzAnonId() {
|
|
|
384
390
|
}
|
|
385
391
|
return id;
|
|
386
392
|
}
|
|
393
|
+
function hzAnonAdopt(id) {
|
|
394
|
+
hzAnonMemo = id;
|
|
395
|
+
hzAnonWrite(HZ_ANON_KEY, id);
|
|
396
|
+
try {
|
|
397
|
+
var s = hzAnonStore();
|
|
398
|
+
if (s) s.setItem(HZ_ANON_KEY, id);
|
|
399
|
+
} catch (e) {
|
|
400
|
+
}
|
|
401
|
+
}
|
|
387
402
|
|
|
388
403
|
// src/uid.ts
|
|
389
404
|
function uuidv7Time(id) {
|
|
@@ -391,7 +406,7 @@ function uuidv7Time(id) {
|
|
|
391
406
|
}
|
|
392
407
|
|
|
393
408
|
// package.json
|
|
394
|
-
var version = "0.3.
|
|
409
|
+
var version = "0.3.43";
|
|
395
410
|
|
|
396
411
|
// src/version.ts
|
|
397
412
|
var VERSION = version;
|
|
@@ -711,6 +726,13 @@ function sessionId(now = Date.now()) {
|
|
|
711
726
|
s.setItem(KEY.session, JSON.stringify(state));
|
|
712
727
|
return state.id;
|
|
713
728
|
}
|
|
729
|
+
function adoptSession(id, now = Date.now()) {
|
|
730
|
+
const s = ls();
|
|
731
|
+
if (s) s.setItem(KEY.session, JSON.stringify({ id, last: now }));
|
|
732
|
+
}
|
|
733
|
+
function adoptAnonId(id) {
|
|
734
|
+
hzAnonAdopt(id);
|
|
735
|
+
}
|
|
714
736
|
function getFirstTouch() {
|
|
715
737
|
const s = ls();
|
|
716
738
|
if (!s) return void 0;
|
|
@@ -750,6 +772,76 @@ function mergeCohort(patch) {
|
|
|
750
772
|
return next;
|
|
751
773
|
}
|
|
752
774
|
|
|
775
|
+
// src/link.ts
|
|
776
|
+
var LINK_PARAMS = { anon: "hz_aid", session: "hz_sid", firstTouch: "hz_ft" };
|
|
777
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
778
|
+
var isId = (v) => !!v && UUID.test(v);
|
|
779
|
+
function encodeFirstTouch(a) {
|
|
780
|
+
return JSON.stringify([
|
|
781
|
+
a.utm.source,
|
|
782
|
+
a.utm.medium,
|
|
783
|
+
a.utm.campaign,
|
|
784
|
+
a.utm.term,
|
|
785
|
+
a.utm.content,
|
|
786
|
+
a.refCode,
|
|
787
|
+
a.referrer,
|
|
788
|
+
a.channel
|
|
789
|
+
].map((v) => v ?? ""));
|
|
790
|
+
}
|
|
791
|
+
function decodeFirstTouch(raw) {
|
|
792
|
+
if (!raw || raw.length > 1024) return void 0;
|
|
793
|
+
try {
|
|
794
|
+
const t = JSON.parse(raw);
|
|
795
|
+
if (!Array.isArray(t) || t.length !== 8 || t.some((v) => typeof v !== "string")) return void 0;
|
|
796
|
+
const [source, medium, campaign, term, content, refCode, referrer, channel] = t;
|
|
797
|
+
const u = (v) => v || void 0;
|
|
798
|
+
return {
|
|
799
|
+
utm: { source: u(source), medium: u(medium), campaign: u(campaign), term: u(term), content: u(content) },
|
|
800
|
+
refCode: u(refCode),
|
|
801
|
+
referrer: u(referrer),
|
|
802
|
+
channel: u(channel)
|
|
803
|
+
};
|
|
804
|
+
} catch {
|
|
805
|
+
return void 0;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
function linkUrl(url, state, fromHost, base) {
|
|
809
|
+
let u;
|
|
810
|
+
try {
|
|
811
|
+
u = new URL(url, base);
|
|
812
|
+
} catch {
|
|
813
|
+
return url;
|
|
814
|
+
}
|
|
815
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return url;
|
|
816
|
+
if (!orgOf(u.hostname) || u.hostname === fromHost) return url;
|
|
817
|
+
const set = (k, v) => v && u.searchParams.set(k, v);
|
|
818
|
+
if (isId(state.anonId)) set(LINK_PARAMS.anon, state.anonId);
|
|
819
|
+
if (isId(state.sessionId)) set(LINK_PARAMS.session, state.sessionId);
|
|
820
|
+
if (state.firstTouch) set(LINK_PARAMS.firstTouch, encodeFirstTouch(state.firstTouch));
|
|
821
|
+
return u.toString();
|
|
822
|
+
}
|
|
823
|
+
function readLink(search) {
|
|
824
|
+
const q = new URLSearchParams(search || "");
|
|
825
|
+
const a = q.get(LINK_PARAMS.anon);
|
|
826
|
+
const s = q.get(LINK_PARAMS.session);
|
|
827
|
+
return {
|
|
828
|
+
anonId: isId(a) ? a : void 0,
|
|
829
|
+
sessionId: isId(s) ? s : void 0,
|
|
830
|
+
firstTouch: decodeFirstTouch(q.get(LINK_PARAMS.firstTouch))
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
function stripLink(href) {
|
|
834
|
+
const u = new URL(href);
|
|
835
|
+
let hit = false;
|
|
836
|
+
for (const k of Object.values(LINK_PARAMS)) {
|
|
837
|
+
if (u.searchParams.has(k)) {
|
|
838
|
+
u.searchParams.delete(k);
|
|
839
|
+
hit = true;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return hit ? u.pathname + u.search + u.hash : void 0;
|
|
843
|
+
}
|
|
844
|
+
|
|
753
845
|
// src/core.ts
|
|
754
846
|
var EVENT_PATH = "/v1/event";
|
|
755
847
|
var DEFAULT_HOST = "https://api.hanzo.ai";
|
|
@@ -910,8 +1002,19 @@ var Analytics = class {
|
|
|
910
1002
|
if (this.started || !this.cfg.enabled) return;
|
|
911
1003
|
this.started = true;
|
|
912
1004
|
if (!isBrowser()) return;
|
|
1005
|
+
const linked = readLink(window.location.search);
|
|
1006
|
+
if (linked.anonId) adoptAnonId(linked.anonId);
|
|
1007
|
+
if (linked.sessionId) adoptSession(linked.sessionId);
|
|
1008
|
+
const clean = stripLink(window.location.href);
|
|
1009
|
+
if (clean !== void 0) {
|
|
1010
|
+
try {
|
|
1011
|
+
window.history.replaceState(window.history.state, "", clean);
|
|
1012
|
+
} catch {
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
913
1015
|
const parsed = parseAttribution(window.location.search, document.referrer);
|
|
914
|
-
|
|
1016
|
+
const first = linked.firstTouch && !getFirstTouch() ? setFirstTouchOnce(linked.firstTouch) : void 0;
|
|
1017
|
+
this.attribution = first ?? (hasAttribution(parsed) ? setFirstTouchOnce(parsed) : getFirstTouch() ?? parsed);
|
|
915
1018
|
this.cohort = mergeCohort({
|
|
916
1019
|
channel: this.attribution.channel ?? deriveChannel(this.attribution),
|
|
917
1020
|
refCode: this.attribution.refCode
|
|
@@ -930,6 +1033,27 @@ var Analytics = class {
|
|
|
930
1033
|
});
|
|
931
1034
|
}
|
|
932
1035
|
}
|
|
1036
|
+
/** link returns `url` carrying this visitor's anonymous id, session and first
|
|
1037
|
+
* touch when the destination is a Hanzo-owned host, so the journey continues
|
|
1038
|
+
* across the hop. Any other URL comes back unchanged. */
|
|
1039
|
+
link(url) {
|
|
1040
|
+
if (!isBrowser()) return url;
|
|
1041
|
+
if (!this.started) this.init();
|
|
1042
|
+
return linkUrl(
|
|
1043
|
+
url,
|
|
1044
|
+
{ anonId: anonId(), sessionId: sessionId(), firstTouch: this.attribution },
|
|
1045
|
+
window.location.hostname,
|
|
1046
|
+
window.location.href
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
/** authorize decorates an OAuth authorize URL for the redirect to IAM and flushes
|
|
1050
|
+
* what is queued, because the page is about to unload. Assign the result to
|
|
1051
|
+
* `location`. */
|
|
1052
|
+
authorize(url) {
|
|
1053
|
+
const out = this.link(url);
|
|
1054
|
+
this.flush(true);
|
|
1055
|
+
return out;
|
|
1056
|
+
}
|
|
933
1057
|
/** identify binds the current visitor to a stable person id (post-login). */
|
|
934
1058
|
identify(personId, traits) {
|
|
935
1059
|
this.personId = personId;
|
|
@@ -1113,9 +1237,9 @@ var Analytics = class {
|
|
|
1113
1237
|
...extra
|
|
1114
1238
|
};
|
|
1115
1239
|
const capturePII = this.cfg.capturePII ?? false;
|
|
1116
|
-
if (wire.url) wire.url = scrubText(wire.url, capturePII);
|
|
1117
|
-
if (wire.path) wire.path = scrubText(wire.path, capturePII);
|
|
1118
|
-
if (wire.referrer) wire.referrer = scrubText(wire.referrer, capturePII);
|
|
1240
|
+
if (wire.url) wire.url = scrubText(withoutFragment(wire.url), capturePII);
|
|
1241
|
+
if (wire.path) wire.path = scrubText(withoutFragment(wire.path), capturePII);
|
|
1242
|
+
if (wire.referrer) wire.referrer = scrubText(withoutFragment(wire.referrer), capturePII);
|
|
1119
1243
|
return wire;
|
|
1120
1244
|
}
|
|
1121
1245
|
schedule() {
|
|
@@ -1219,6 +1343,6 @@ var COHORTS = {
|
|
|
1219
1343
|
* curl -fsSL https://unpkg.com/@hanzo/event/src/anon.js -o apps/analytics/anon.js
|
|
1220
1344
|
*/
|
|
1221
1345
|
|
|
1222
|
-
export { Analytics, COHORTS, GOALS, ORG_DOMAIN, ORG_KEY, PRODUCT_PROJECT, VERSION, buildEnvelope, buildSentryEvent, createAnalytics, deriveChannel, digest, dsnForProduct, exceptionEntry, exceptionProperties, fingerprint, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, keyFor, keyForPage, orgOf, parseAttribution, parseDsn, redactSecrets, resetClients, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
|
|
1346
|
+
export { Analytics, COHORTS, GOALS, LINK_PARAMS, ORG_DOMAIN, ORG_KEY, PRODUCT_PROJECT, VERSION, buildEnvelope, buildSentryEvent, createAnalytics, deriveChannel, digest, dsnForProduct, exceptionEntry, exceptionProperties, fingerprint, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, keyFor, keyForPage, linkUrl, orgOf, parseAttribution, parseDsn, readLink, redactSecrets, resetClients, scrubPII, scrubText, stripLink, hzUuidv7 as uuidv7, uuidv7Time };
|
|
1223
1347
|
//# sourceMappingURL=index.mjs.map
|
|
1224
1348
|
//# sourceMappingURL=index.mjs.map
|