@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/LICENSE.md +21 -0
- package/dist/index.cjs +124 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.mjs +124 -30
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +121 -29
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +121 -29
- package/dist/react.mjs.map +1 -1
- package/hz.js +188 -27
- package/package.json +10 -10
- package/src/anon.d.ts +14 -0
- package/src/anon.js +199 -0
- package/src/anon.test.ts +80 -0
- package/src/hz.test.ts +67 -12
- package/src/storage.test.ts +285 -0
- package/src/storage.ts +18 -10
- package/src/uid.ts +9 -35
- package/src/version.ts +1 -1
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.
|
|
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
|
-
|
|
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/
|
|
261
|
-
var
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|