@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/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';
@@ -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.41";
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
- this.attribution = hasAttribution(parsed) ? setFirstTouchOnce(parsed) : getFirstTouch() ?? parsed;
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