@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 CHANGED
@@ -37,6 +37,14 @@ export declare class Analytics {
37
37
  * auto-capture unhandled errors. Safe to call from a React effect on every
38
38
  * render. */
39
39
  init(): void;
40
+ /** link returns `url` carrying this visitor's anonymous id, session and first
41
+ * touch when the destination is a Hanzo-owned host, so the journey continues
42
+ * across the hop. Any other URL comes back unchanged. */
43
+ link(url: string): string;
44
+ /** authorize decorates an OAuth authorize URL for the redirect to IAM and flushes
45
+ * what is queued, because the page is about to unload. Assign the result to
46
+ * `location`. */
47
+ authorize(url: string): string;
40
48
  /** identify binds the current visitor to a stable person id (post-login). */
41
49
  identify(personId: string, traits?: Record<string, unknown>): void;
42
50
  /** group associates the visitor with an org/team (analytics grouping, not the
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AA2DA,OAAO,EAGL,aAAa,EAEb,SAAS,EAEV,MAAM,WAAW,CAAA;AAElB,OAAO,KAAK,EACV,eAAe,EAEf,mBAAmB,EACnB,MAAM,EAKN,SAAS,EACV,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,OAAO,EAAE,CAAA;AA2KlB,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAGM;IACjB,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,QAAQ,CAAC,CAAQ;IACzB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAQ;IACvB,0DAA0D;IAC1D,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,+DAA+D;IAC/D,OAAO,CAAC,GAAG,CAAY;IACvB,6EAA6E;IAC7E,OAAO,CAAC,SAAS,CAAQ;IAEzB,YAAY,MAAM,EAAE,eAAe,EAwClC;IAED;;;;8EAI0E;IAC1E,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAQnC;IAED;;;mEAG+D;IAC/D,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED;4CACwC;IACxC,IAAI,cAAc,IAAI,MAAM,GAAG,SAAS,CAEvC;IAED;;;kBAGc;IACd,IAAI,IAAI,IAAI,CAgCX;IAED,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAGjE;IAED;6EACyE;IACzE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE7D;IAED;;oEAEgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAclE;IAED;uFACmF;IACnF,OAAO,CACL,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,GAC5E,IAAI,CAEN;IAED;;;;;;;;;;;;;0BAasB;IACtB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAuD9D;IAED;kCAC8B;IAC9B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE7B;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,UAAQ,GAAG,IAAI,CAmC1B;IAID;;;;;6CAKyC;IACzC,OAAO,CAAC,SAAS;IAiBjB;sEACkE;IAClE,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,KAAK;IA+Db,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,UAAU;CAMnB;AAiCD;;;;;;;;;;;4DAW4D;AAC5D,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED;;iEAEiE;AACjE,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAmBlE;AAID,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AA2DA,OAAO,EAKL,aAAa,EAEb,SAAS,EAEV,MAAM,WAAW,CAAA;AAGlB,OAAO,KAAK,EACV,eAAe,EAEf,mBAAmB,EACnB,MAAM,EAKN,SAAS,EACV,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,OAAO,EAAE,CAAA;AA2KlB,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAGM;IACjB,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,QAAQ,CAAC,CAAQ;IACzB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAQ;IACvB,0DAA0D;IAC1D,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,+DAA+D;IAC/D,OAAO,CAAC,GAAG,CAAY;IACvB,6EAA6E;IAC7E,OAAO,CAAC,SAAS,CAAQ;IAEzB,YAAY,MAAM,EAAE,eAAe,EAwClC;IAED;;;;8EAI0E;IAC1E,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAQnC;IAED;;;mEAG+D;IAC/D,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED;4CACwC;IACxC,IAAI,cAAc,IAAI,MAAM,GAAG,SAAS,CAEvC;IAED;;;kBAGc;IACd,IAAI,IAAI,IAAI,CAgDX;IAED;;8DAE0D;IAC1D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASxB;IAED;;sBAEkB;IAClB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7B;IAED,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAGjE;IAED;6EACyE;IACzE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE7D;IAED;;oEAEgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAclE;IAED;uFACmF;IACnF,OAAO,CACL,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,GAC5E,IAAI,CAEN;IAED;;;;;;;;;;;;;0BAasB;IACtB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAuD9D;IAED;kCAC8B;IAC9B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE7B;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,UAAQ,GAAG,IAAI,CAmC1B;IAID;;;;;6CAKyC;IACzC,OAAO,CAAC,SAAS;IAiBjB;sEACkE;IAClE,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,KAAK;IAkEb,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,UAAU;CAMnB;AAiCD;;;;;;;;;;;4DAW4D;AAC5D,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED;;iEAEiE;AACjE,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAmBlE;AAID,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA"}
package/dist/events.d.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * and there is still exactly one definition.
10
10
  *
11
11
  * Nothing about the API moved. Every existing import keeps working, the names
12
- * and their values are unchanged, and `pkgs/events/test/catalog.mjs` fails the
12
+ * and their values are unchanged, and `pkg/events/test/catalog.mjs` fails the
13
13
  * build if a name and its meaning ever disagree.
14
14
  *
15
15
  * The naming convention lives with the names, in @hanzo/events and TAXONOMY.md:
package/dist/index.cjs CHANGED
@@ -254,11 +254,17 @@ var RE_CREDENTIAL_PARAM = new RegExp(
254
254
  function redactCredentialParams(s) {
255
255
  return s.replace(RE_CREDENTIAL_PARAM, (_m, prefix) => prefix + REDACTED);
256
256
  }
257
+ 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;
257
258
  function redactSecrets(s) {
258
259
  s = redactCredentialParams(s);
259
260
  for (const re of SECRET_PATTERNS) s = s.replace(re, REDACTED);
261
+ s = s.replace(RE_SECRET43, (_m, lead) => lead + REDACTED);
260
262
  return redactPAN(s);
261
263
  }
264
+ function withoutFragment(url) {
265
+ const at = url.indexOf("#");
266
+ return at < 0 ? url : url.slice(0, at);
267
+ }
262
268
  function scrubPII(s) {
263
269
  s = s.replace(RE_EMAIL, EMAIL_MARK);
264
270
  s = s.replace(RE_IPV6, IP_MARK);
@@ -385,6 +391,15 @@ function hzAnonId() {
385
391
  }
386
392
  return id;
387
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
+ }
388
403
 
389
404
  // src/uid.ts
390
405
  function uuidv7Time(id) {
@@ -392,7 +407,7 @@ function uuidv7Time(id) {
392
407
  }
393
408
 
394
409
  // package.json
395
- var version = "0.3.41";
410
+ var version = "0.3.43";
396
411
 
397
412
  // src/version.ts
398
413
  var VERSION = version;
@@ -712,6 +727,13 @@ function sessionId(now = Date.now()) {
712
727
  s.setItem(KEY.session, JSON.stringify(state));
713
728
  return state.id;
714
729
  }
730
+ function adoptSession(id, now = Date.now()) {
731
+ const s = ls();
732
+ if (s) s.setItem(KEY.session, JSON.stringify({ id, last: now }));
733
+ }
734
+ function adoptAnonId(id) {
735
+ hzAnonAdopt(id);
736
+ }
715
737
  function getFirstTouch() {
716
738
  const s = ls();
717
739
  if (!s) return void 0;
@@ -751,6 +773,76 @@ function mergeCohort(patch) {
751
773
  return next;
752
774
  }
753
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 set = (k, v) => v && u.searchParams.set(k, v);
819
+ if (isId(state.anonId)) set(LINK_PARAMS.anon, state.anonId);
820
+ if (isId(state.sessionId)) set(LINK_PARAMS.session, state.sessionId);
821
+ if (state.firstTouch) set(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
+
754
846
  // src/core.ts
755
847
  var EVENT_PATH = "/v1/event";
756
848
  var DEFAULT_HOST = "https://api.hanzo.ai";
@@ -911,8 +1003,19 @@ var Analytics = class {
911
1003
  if (this.started || !this.cfg.enabled) return;
912
1004
  this.started = true;
913
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
+ }
914
1016
  const parsed = parseAttribution(window.location.search, document.referrer);
915
- this.attribution = hasAttribution(parsed) ? setFirstTouchOnce(parsed) : getFirstTouch() ?? parsed;
1017
+ const first = linked.firstTouch && !getFirstTouch() ? setFirstTouchOnce(linked.firstTouch) : void 0;
1018
+ this.attribution = first ?? (hasAttribution(parsed) ? setFirstTouchOnce(parsed) : getFirstTouch() ?? parsed);
916
1019
  this.cohort = mergeCohort({
917
1020
  channel: this.attribution.channel ?? deriveChannel(this.attribution),
918
1021
  refCode: this.attribution.refCode
@@ -931,6 +1034,27 @@ var Analytics = class {
931
1034
  });
932
1035
  }
933
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
+ }
934
1058
  /** identify binds the current visitor to a stable person id (post-login). */
935
1059
  identify(personId, traits) {
936
1060
  this.personId = personId;
@@ -1114,9 +1238,9 @@ var Analytics = class {
1114
1238
  ...extra
1115
1239
  };
1116
1240
  const capturePII = this.cfg.capturePII ?? false;
1117
- if (wire.url) wire.url = scrubText(wire.url, capturePII);
1118
- if (wire.path) wire.path = scrubText(wire.path, capturePII);
1119
- if (wire.referrer) wire.referrer = scrubText(wire.referrer, capturePII);
1241
+ if (wire.url) wire.url = scrubText(withoutFragment(wire.url), capturePII);
1242
+ if (wire.path) wire.path = scrubText(withoutFragment(wire.path), capturePII);
1243
+ if (wire.referrer) wire.referrer = scrubText(withoutFragment(wire.referrer), capturePII);
1120
1244
  return wire;
1121
1245
  }
1122
1246
  schedule() {
@@ -1247,6 +1371,7 @@ Object.defineProperty(exports, "eventsOf", {
1247
1371
  exports.Analytics = Analytics;
1248
1372
  exports.COHORTS = COHORTS;
1249
1373
  exports.GOALS = GOALS;
1374
+ exports.LINK_PARAMS = LINK_PARAMS;
1250
1375
  exports.ORG_DOMAIN = ORG_DOMAIN;
1251
1376
  exports.ORG_KEY = ORG_KEY;
1252
1377
  exports.PRODUCT_PROJECT = PRODUCT_PROJECT;
@@ -1268,13 +1393,16 @@ exports.hostOf = hostOf;
1268
1393
  exports.isoWeek = isoWeek;
1269
1394
  exports.keyFor = keyFor;
1270
1395
  exports.keyForPage = keyForPage;
1396
+ exports.linkUrl = linkUrl;
1271
1397
  exports.orgOf = orgOf;
1272
1398
  exports.parseAttribution = parseAttribution;
1273
1399
  exports.parseDsn = parseDsn;
1400
+ exports.readLink = readLink;
1274
1401
  exports.redactSecrets = redactSecrets;
1275
1402
  exports.resetClients = resetClients;
1276
1403
  exports.scrubPII = scrubPII;
1277
1404
  exports.scrubText = scrubText;
1405
+ exports.stripLink = stripLink;
1278
1406
  exports.uuidv7 = hzUuidv7;
1279
1407
  exports.uuidv7Time = uuidv7Time;
1280
1408
  //# sourceMappingURL=index.cjs.map