@hanzo/event 0.3.13 → 0.3.15

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.ts CHANGED
@@ -6,7 +6,7 @@ declare function getFirstTouch(): Attribution | undefined;
6
6
  /** Read persisted cohort dimensions. */
7
7
  declare function getCohort(): Cohort | undefined;
8
8
 
9
- declare const VERSION = "0.3.13";
9
+ declare const VERSION = "0.3.15";
10
10
 
11
11
  /**
12
12
  * parseDsn parses "https://<version>:<hmac>@<host>/v1/sentry/<projectId>" into its
@@ -60,13 +60,20 @@ declare function buildSentryEvent(input: BuildEventInput): SentryEvent;
60
60
  */
61
61
  declare function buildEnvelope(event: SentryEvent, dsn: Dsn, sentAt?: string): string;
62
62
 
63
+ // Types for anon.js, which is hand-written ES5 rather than TypeScript because
64
+ // hz.js and the door's hosted tag inline it VERBATIM and neither has a compiler.
65
+ // The declarations are here so the bundled client still imports it typed.
66
+
67
+ /** Mints a time-ordered UUIDv7 (RFC 9562 §5.7) for `now` in epoch milliseconds. */
68
+ declare function hzUuidv7(now?: number): string
69
+
63
70
  /**
64
71
  * uuidv7 mints a time-ordered UUIDv7 for `now` (epoch milliseconds).
65
72
  *
66
73
  * Two ids minted in the same millisecond sort arbitrarily between themselves; ids
67
74
  * from different milliseconds sort by time, lexically and numerically alike.
68
75
  */
69
- declare function uuidv7(now?: number): string;
76
+
70
77
  /** The millisecond timestamp a v7 id was minted at — the inverse of uuidv7. */
71
78
  declare function uuidv7Time(id: string): number;
72
79
 
@@ -283,4 +290,4 @@ declare function hasAttribution(a: Attribution): boolean;
283
290
  /** isoWeek returns the ISO-8601 week label, e.g. "2026-W28". */
284
291
  declare function isoWeek(d: Date): string;
285
292
 
286
- export { Attribution, COHORTS, CaptureErrorOptions, Cohort, type CohortDef, Dsn, EVENTS, type ErrorIdentity, type EventName, FUNNELS, type FunnelDef, type FunnelId, type FunnelStep, GOALS, type GoalDef, PAGEVIEW, PRODUCTS, PRODUCT_DSN, type ProductId, SentryEvent, SentryFrame, VERSION, buildEnvelope, buildSentryEvent, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, uuidv7, uuidv7Time };
293
+ export { Attribution, COHORTS, CaptureErrorOptions, Cohort, type CohortDef, Dsn, EVENTS, type ErrorIdentity, type EventName, FUNNELS, type FunnelDef, type FunnelId, type FunnelStep, GOALS, type GoalDef, PAGEVIEW, PRODUCTS, PRODUCT_DSN, type ProductId, SentryEvent, SentryFrame, VERSION, buildEnvelope, buildSentryEvent, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
package/dist/index.mjs CHANGED
@@ -257,34 +257,115 @@ function scrubText(s2, capturePII = false) {
257
257
  return s2;
258
258
  }
259
259
 
260
- // src/uid.ts
261
- var HEX = Array.from({ length: 256 }, (_, i) => (i + 256).toString(16).slice(1));
262
- function fill(b) {
263
- const c = typeof crypto !== "undefined" ? crypto : void 0;
264
- if (c && typeof c.getRandomValues === "function") {
265
- c.getRandomValues(b);
266
- return b;
267
- }
268
- for (let i = 0; i < b.length; i++) b[i] = Math.random() * 256 | 0;
269
- return b;
270
- }
271
- function uuidv7(now = Date.now()) {
272
- const b = fill(new Uint8Array(16));
273
- let t = Math.floor(now);
274
- for (let i = 5; i >= 0; i--) {
260
+ // src/anon.js
261
+ var HZ_ANON_KEY = "hz_anon_id";
262
+ var HZ_ANON_LEGACY_KEY = "hz_id";
263
+ var HZ_ANON_DOMAIN = "hanzo.ai";
264
+ var HZ_ANON_MAX_AGE = 2 * 365 * 24 * 60 * 60;
265
+ var hzAnonMemo;
266
+ function hzUuidv7(now) {
267
+ var b = new Uint8Array(16);
268
+ var i;
269
+ var c = typeof crypto !== "undefined" ? crypto : void 0;
270
+ if (c && typeof c.getRandomValues === "function") c.getRandomValues(b);
271
+ else for (i = 0; i < 16; i++) b[i] = Math.random() * 256 | 0;
272
+ var t = Math.floor(now === void 0 ? Date.now() : now);
273
+ for (i = 5; i >= 0; i--) {
275
274
  b[i] = t % 256;
276
275
  t = Math.floor(t / 256);
277
276
  }
278
277
  b[6] = 112 | b[6] & 15;
279
278
  b[8] = 128 | b[8] & 63;
280
- return HEX[b[0]] + HEX[b[1]] + HEX[b[2]] + HEX[b[3]] + "-" + HEX[b[4]] + HEX[b[5]] + "-" + HEX[b[6]] + HEX[b[7]] + "-" + HEX[b[8]] + HEX[b[9]] + "-" + HEX[b[10]] + HEX[b[11]] + HEX[b[12]] + HEX[b[13]] + HEX[b[14]] + HEX[b[15]];
279
+ var h = "";
280
+ for (i = 0; i < 16; i++) {
281
+ h += (b[i] + 256).toString(16).slice(1);
282
+ if (i === 3 || i === 5 || i === 7 || i === 9) h += "-";
283
+ }
284
+ return h;
281
285
  }
286
+ function hzAnonJar() {
287
+ try {
288
+ if (typeof document === "undefined" || typeof document.cookie !== "string") return null;
289
+ return document;
290
+ } catch (e) {
291
+ return null;
292
+ }
293
+ }
294
+ function hzAnonStore() {
295
+ try {
296
+ if (typeof window === "undefined" || !window.localStorage) return null;
297
+ return window.localStorage;
298
+ } catch (e) {
299
+ return null;
300
+ }
301
+ }
302
+ function hzAnonItem(store, name) {
303
+ try {
304
+ return store && store.getItem(name) || "";
305
+ } catch (e) {
306
+ return "";
307
+ }
308
+ }
309
+ function hzAnonCookie(name) {
310
+ var d = hzAnonJar();
311
+ if (!d) return "";
312
+ var parts = d.cookie.split(";");
313
+ for (var i = 0; i < parts.length; i++) {
314
+ var eq = parts[i].indexOf("=");
315
+ if (eq < 0 || parts[i].slice(0, eq).trim() !== name) continue;
316
+ var v = parts[i].slice(eq + 1).trim();
317
+ if (!v) continue;
318
+ try {
319
+ return decodeURIComponent(v);
320
+ } catch (e) {
321
+ return v;
322
+ }
323
+ }
324
+ return "";
325
+ }
326
+ function hzAnonWrite(name, value) {
327
+ var d = hzAnonJar();
328
+ if (!d) return;
329
+ var host = "";
330
+ var secure = false;
331
+ try {
332
+ if (typeof window !== "undefined" && window.location) {
333
+ host = window.location.hostname || "";
334
+ secure = window.location.protocol === "https:";
335
+ }
336
+ } catch (e) {
337
+ }
338
+ var c = name + "=" + encodeURIComponent(value);
339
+ c += "; Path=/; Max-Age=" + HZ_ANON_MAX_AGE + "; SameSite=Lax";
340
+ if (("." + host).slice(-(HZ_ANON_DOMAIN.length + 1)) === "." + HZ_ANON_DOMAIN) {
341
+ c += "; Domain=" + HZ_ANON_DOMAIN;
342
+ }
343
+ if (secure) c += "; Secure";
344
+ try {
345
+ d.cookie = c;
346
+ } catch (e) {
347
+ }
348
+ }
349
+ function hzAnonId() {
350
+ if (typeof window === "undefined") return "";
351
+ var s2 = hzAnonStore();
352
+ var id = hzAnonCookie(HZ_ANON_KEY) || hzAnonItem(s2, HZ_ANON_KEY) || hzAnonItem(s2, HZ_ANON_LEGACY_KEY) || hzAnonMemo || hzUuidv7();
353
+ hzAnonMemo = id;
354
+ hzAnonWrite(HZ_ANON_KEY, id);
355
+ try {
356
+ if (s2 && s2.getItem(HZ_ANON_KEY) !== id) s2.setItem(HZ_ANON_KEY, id);
357
+ } catch (e) {
358
+ }
359
+ return id;
360
+ }
361
+
362
+ // src/uid.ts
282
363
  function uuidv7Time(id) {
283
364
  return parseInt(id.slice(0, 8) + id.slice(9, 13), 16);
284
365
  }
285
366
 
286
367
  // src/version.ts
287
- var VERSION = "0.3.13";
368
+ var VERSION = "0.3.15";
288
369
 
289
370
  // src/sentry.ts
290
371
  var MAX_FRAMES = 50;
@@ -293,7 +374,7 @@ var MAX_LINE_LEN = 2048;
293
374
  var MAX_TAG_LEN = 1024;
294
375
  var MAX_TAGS = 50;
295
376
  function eventId() {
296
- return uuidv7().replace(/-/g, "");
377
+ return hzUuidv7().replace(/-/g, "");
297
378
  }
298
379
  function byteLen(s2) {
299
380
  if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(s2).length;
@@ -479,7 +560,6 @@ ${payload}
479
560
 
480
561
  // src/storage.ts
481
562
  var KEY = {
482
- anon: "hz_anon_id",
483
563
  session: "hz_session",
484
564
  firstTouch: "hz_first_touch",
485
565
  cohort: "hz_cohort"
@@ -494,14 +574,7 @@ function ls() {
494
574
  }
495
575
  }
496
576
  function anonId() {
497
- const s2 = ls();
498
- if (!s2) return void 0;
499
- let v = s2.getItem(KEY.anon);
500
- if (!v) {
501
- v = uuidv7();
502
- s2.setItem(KEY.anon, v);
503
- }
504
- return v;
577
+ return hzAnonId() || void 0;
505
578
  }
506
579
  function sessionId(now = Date.now()) {
507
580
  const s2 = ls();
@@ -513,7 +586,7 @@ function sessionId(now = Date.now()) {
513
586
  state = null;
514
587
  }
515
588
  if (!state || now - state.last > SESSION_TTL_MS) {
516
- state = { id: uuidv7(now), last: now };
589
+ state = { id: hzUuidv7(now), last: now };
517
590
  } else {
518
591
  state.last = now;
519
592
  }
@@ -849,7 +922,7 @@ var Analytics = class {
849
922
  build(kind, event, extra) {
850
923
  const anon = anonId();
851
924
  const wire = {
852
- messageId: uuidv7(),
925
+ messageId: hzUuidv7(),
853
926
  type: kind,
854
927
  event,
855
928
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1045,7 +1118,28 @@ var COHORTS = {
1045
1118
  channel: { field: "channel", label: "Acquisition channel" },
1046
1119
  refCode: { field: "ref_code", label: "Referral code" }
1047
1120
  };
1121
+ /*! anon.js — THE anonymous-identity chain. ONE implementation, three distributions.
1122
+ *
1123
+ * One browser is ONE person on every Hanzo surface, whichever client a page
1124
+ * happens to have loaded. There were three implementations writing TWO keys —
1125
+ * `hz_anon_id` (the npm client, the hosted tag) and `hz_id` (hz.js) — so the same
1126
+ * visitor was several people depending on which snippet the surface shipped.
1127
+ *
1128
+ * The three call sites:
1129
+ * 1. src/storage.ts — the bundled npm client; IMPORTS this file.
1130
+ * 2. hz.js — the no-build script tag; INLINES the marked region.
1131
+ * 3. hanzoai/cloud apps/analytics/tag.js — the tag the door hosts at
1132
+ * /v1/event.js; vendors this file and its tag.go serves the marked region
1133
+ * with the tag as one asset, so the door holds no second copy either.
1134
+ *
1135
+ * (2) and (3) have no bundler and cannot import anything, which is why the chain
1136
+ * lives in a file that is plain ES5 rather than in a .ts: the region between the
1137
+ * BEGIN and END markers is COPIED VERBATIM, and src/anon.test.ts fails if hz.js's
1138
+ * copy is so much as a byte different. Keep the region ES5, dependency-free,
1139
+ * `hz`-prefixed (it is spliced into other people's scopes) and unformatted — a
1140
+ * reformat of one copy is a diff against the other.
1141
+ */
1048
1142
 
1049
- export { Analytics, COHORTS, EVENTS, FUNNELS, GOALS, PAGEVIEW, PRODUCTS, PRODUCT_DSN, VERSION, buildEnvelope, buildSentryEvent, createAnalytics, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, uuidv7, uuidv7Time };
1143
+ export { Analytics, COHORTS, EVENTS, FUNNELS, GOALS, PAGEVIEW, PRODUCTS, PRODUCT_DSN, VERSION, buildEnvelope, buildSentryEvent, createAnalytics, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
1050
1144
  //# sourceMappingURL=index.mjs.map
1051
1145
  //# sourceMappingURL=index.mjs.map