@hanzo/event 0.3.8 → 0.3.10
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-B1XEdWLd.d.cts → core-BCEdNp8H.d.cts} +20 -8
- package/dist/{core-B1XEdWLd.d.ts → core-BCEdNp8H.d.ts} +20 -8
- package/dist/index.cjs +42 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.mjs +41 -21
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +37 -20
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +37 -20
- package/dist/react.mjs.map +1 -1
- package/hz.js +26 -5
- package/package.json +2 -2
- package/src/core.test.ts +34 -0
- package/src/core.ts +11 -7
- package/src/hz.test.ts +96 -0
- package/src/index.ts +1 -0
- package/src/sentry.ts +4 -6
- package/src/storage.ts +11 -9
- package/src/types.ts +20 -8
- package/src/uid.test.ts +73 -0
- package/src/uid.ts +70 -0
- package/src/version.ts +1 -1
|
@@ -100,14 +100,26 @@ interface AnalyticsConfig {
|
|
|
100
100
|
/** Bearer token provider for token-auth apps. Omit for cookie/session apps
|
|
101
101
|
* (the client then relies on same-origin credentials). */
|
|
102
102
|
getToken?: () => string | undefined | null;
|
|
103
|
-
/** Publishable ingest key (
|
|
104
|
-
* front door `/v1/event` with this key instead of a bearer/cookie: it rides
|
|
105
|
-
* Authorization: Bearer
|
|
106
|
-
* page-unload beacon, so
|
|
107
|
-
* without a bearer. The key is write-only
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
103
|
+
/** Publishable ingest key (pk-…). When set, the client attributes writes to the
|
|
104
|
+
* ONE front door `/v1/event` with this key instead of a bearer/cookie: it rides
|
|
105
|
+
* Authorization: Bearer pk-… on fetch and ?ingest_key=pk-… on a headerless
|
|
106
|
+
* page-unload beacon, so ANONYMOUS traffic is attributed and unload beacons work
|
|
107
|
+
* without a bearer. The key is write-only — it attributes a write and never mints
|
|
108
|
+
* a reading principal — so it is safe to ship in a bundle. Mint one per org with
|
|
109
|
+
* POST /v1/keys {"type":"publishable"}.
|
|
110
|
+
*
|
|
111
|
+
* Omit it and the client reads NEXT_PUBLIC_HANZO_EVENT_KEY, then HANZO_EVENT_KEY,
|
|
112
|
+
* from the inlined build env — the same resolution `dsn` uses, so a surface
|
|
113
|
+
* declares BOTH planes the same way and neither needs code to switch on.
|
|
114
|
+
*
|
|
115
|
+
* A surface with no key at all still reports for whoever is SIGNED IN (the
|
|
116
|
+
* session credential attributes them), and drops every logged-out visitor: the
|
|
117
|
+
* door refuses an unattributable write rather than filing it where its owner
|
|
118
|
+
* cannot read it. That failure is invisible from the page, which is why the key
|
|
119
|
+
* belongs in the env next to the DSN and not in a checklist.
|
|
120
|
+
*
|
|
121
|
+
* This attributes the EVENT STREAM only — the error plane authenticates
|
|
122
|
+
* independently with `dsn`, and one does not stand in for the other. */
|
|
111
123
|
ingestKey?: string;
|
|
112
124
|
/** Max events buffered before an automatic flush. */
|
|
113
125
|
batchSize?: number;
|
|
@@ -100,14 +100,26 @@ interface AnalyticsConfig {
|
|
|
100
100
|
/** Bearer token provider for token-auth apps. Omit for cookie/session apps
|
|
101
101
|
* (the client then relies on same-origin credentials). */
|
|
102
102
|
getToken?: () => string | undefined | null;
|
|
103
|
-
/** Publishable ingest key (
|
|
104
|
-
* front door `/v1/event` with this key instead of a bearer/cookie: it rides
|
|
105
|
-
* Authorization: Bearer
|
|
106
|
-
* page-unload beacon, so
|
|
107
|
-
* without a bearer. The key is write-only
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
103
|
+
/** Publishable ingest key (pk-…). When set, the client attributes writes to the
|
|
104
|
+
* ONE front door `/v1/event` with this key instead of a bearer/cookie: it rides
|
|
105
|
+
* Authorization: Bearer pk-… on fetch and ?ingest_key=pk-… on a headerless
|
|
106
|
+
* page-unload beacon, so ANONYMOUS traffic is attributed and unload beacons work
|
|
107
|
+
* without a bearer. The key is write-only — it attributes a write and never mints
|
|
108
|
+
* a reading principal — so it is safe to ship in a bundle. Mint one per org with
|
|
109
|
+
* POST /v1/keys {"type":"publishable"}.
|
|
110
|
+
*
|
|
111
|
+
* Omit it and the client reads NEXT_PUBLIC_HANZO_EVENT_KEY, then HANZO_EVENT_KEY,
|
|
112
|
+
* from the inlined build env — the same resolution `dsn` uses, so a surface
|
|
113
|
+
* declares BOTH planes the same way and neither needs code to switch on.
|
|
114
|
+
*
|
|
115
|
+
* A surface with no key at all still reports for whoever is SIGNED IN (the
|
|
116
|
+
* session credential attributes them), and drops every logged-out visitor: the
|
|
117
|
+
* door refuses an unattributable write rather than filing it where its owner
|
|
118
|
+
* cannot read it. That failure is invisible from the page, which is why the key
|
|
119
|
+
* belongs in the env next to the DSN and not in a checklist.
|
|
120
|
+
*
|
|
121
|
+
* This attributes the EVENT STREAM only — the error plane authenticates
|
|
122
|
+
* independently with `dsn`, and one does not stand in for the other. */
|
|
111
123
|
ingestKey?: string;
|
|
112
124
|
/** Max events buffered before an automatic flush. */
|
|
113
125
|
batchSize?: number;
|
package/dist/index.cjs
CHANGED
|
@@ -219,8 +219,34 @@ function scrubText(s2, capturePII = false) {
|
|
|
219
219
|
return s2;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
// src/uid.ts
|
|
223
|
+
var HEX = Array.from({ length: 256 }, (_, i) => (i + 256).toString(16).slice(1));
|
|
224
|
+
function fill(b) {
|
|
225
|
+
const c = typeof crypto !== "undefined" ? crypto : void 0;
|
|
226
|
+
if (c && typeof c.getRandomValues === "function") {
|
|
227
|
+
c.getRandomValues(b);
|
|
228
|
+
return b;
|
|
229
|
+
}
|
|
230
|
+
for (let i = 0; i < b.length; i++) b[i] = Math.random() * 256 | 0;
|
|
231
|
+
return b;
|
|
232
|
+
}
|
|
233
|
+
function uuidv7(now = Date.now()) {
|
|
234
|
+
const b = fill(new Uint8Array(16));
|
|
235
|
+
let t = Math.floor(now);
|
|
236
|
+
for (let i = 5; i >= 0; i--) {
|
|
237
|
+
b[i] = t % 256;
|
|
238
|
+
t = Math.floor(t / 256);
|
|
239
|
+
}
|
|
240
|
+
b[6] = 112 | b[6] & 15;
|
|
241
|
+
b[8] = 128 | b[8] & 63;
|
|
242
|
+
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]];
|
|
243
|
+
}
|
|
244
|
+
function uuidv7Time(id) {
|
|
245
|
+
return parseInt(id.slice(0, 8) + id.slice(9, 13), 16);
|
|
246
|
+
}
|
|
247
|
+
|
|
222
248
|
// src/version.ts
|
|
223
|
-
var VERSION = "0.3.
|
|
249
|
+
var VERSION = "0.3.9";
|
|
224
250
|
|
|
225
251
|
// src/sentry.ts
|
|
226
252
|
var MAX_FRAMES = 50;
|
|
@@ -229,11 +255,7 @@ var MAX_LINE_LEN = 2048;
|
|
|
229
255
|
var MAX_TAG_LEN = 1024;
|
|
230
256
|
var MAX_TAGS = 50;
|
|
231
257
|
function eventId() {
|
|
232
|
-
|
|
233
|
-
if (c && "randomUUID" in c) return c.randomUUID().replace(/-/g, "");
|
|
234
|
-
let s2 = "";
|
|
235
|
-
for (let i = 0; i < 32; i++) s2 += Math.floor(Math.random() * 16).toString(16);
|
|
236
|
-
return s2;
|
|
258
|
+
return uuidv7().replace(/-/g, "");
|
|
237
259
|
}
|
|
238
260
|
function byteLen(s2) {
|
|
239
261
|
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(s2).length;
|
|
@@ -433,17 +455,12 @@ function ls() {
|
|
|
433
455
|
return void 0;
|
|
434
456
|
}
|
|
435
457
|
}
|
|
436
|
-
function uid() {
|
|
437
|
-
const c = typeof crypto !== "undefined" ? crypto : void 0;
|
|
438
|
-
if (c && "randomUUID" in c) return c.randomUUID();
|
|
439
|
-
return "a-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
|
|
440
|
-
}
|
|
441
458
|
function anonId() {
|
|
442
459
|
const s2 = ls();
|
|
443
460
|
if (!s2) return void 0;
|
|
444
461
|
let v = s2.getItem(KEY.anon);
|
|
445
462
|
if (!v) {
|
|
446
|
-
v =
|
|
463
|
+
v = uuidv7();
|
|
447
464
|
s2.setItem(KEY.anon, v);
|
|
448
465
|
}
|
|
449
466
|
return v;
|
|
@@ -458,7 +475,7 @@ function sessionId(now = Date.now()) {
|
|
|
458
475
|
state = null;
|
|
459
476
|
}
|
|
460
477
|
if (!state || now - state.last > SESSION_TTL_MS) {
|
|
461
|
-
state = { id:
|
|
478
|
+
state = { id: uuidv7(now), last: now };
|
|
462
479
|
} else {
|
|
463
480
|
state.last = now;
|
|
464
481
|
}
|
|
@@ -527,11 +544,6 @@ function readEnv(name) {
|
|
|
527
544
|
function appendQuery(url, key, value) {
|
|
528
545
|
return url + (url.includes("?") ? "&" : "?") + key + "=" + encodeURIComponent(value);
|
|
529
546
|
}
|
|
530
|
-
function uid2() {
|
|
531
|
-
const c = typeof crypto !== "undefined" ? crypto : void 0;
|
|
532
|
-
if (c && "randomUUID" in c) return c.randomUUID();
|
|
533
|
-
return "m-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
|
|
534
|
-
}
|
|
535
547
|
function normalizeError2(err) {
|
|
536
548
|
const n = normalizeError(err);
|
|
537
549
|
return { type: n.name, message: n.message, stack: n.stack };
|
|
@@ -604,7 +616,15 @@ var Analytics = class {
|
|
|
604
616
|
flushIntervalMs: 5e3,
|
|
605
617
|
enabled: true,
|
|
606
618
|
captureErrors: true,
|
|
607
|
-
...config
|
|
619
|
+
...config,
|
|
620
|
+
// The publishable key resolves the SAME way the DSN below does: an explicit
|
|
621
|
+
// config wins, else the inlined build-time env. Without this the key was the
|
|
622
|
+
// one piece of wiring a surface could not declare the way it declares every
|
|
623
|
+
// other piece, so every surface that shipped without passing it in code sent
|
|
624
|
+
// its beacons unattributed — and an unattributed write is refused (401
|
|
625
|
+
// ingest_key_required), which is silent in the page and invisible until you
|
|
626
|
+
// read the warehouse and find the host missing entirely.
|
|
627
|
+
ingestKey: config.ingestKey ?? readEnv("NEXT_PUBLIC_HANZO_EVENT_KEY") ?? readEnv("HANZO_EVENT_KEY")
|
|
608
628
|
};
|
|
609
629
|
this.transport = config.transport ?? new DefaultTransport();
|
|
610
630
|
this.dsn = parseDsn(config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product));
|
|
@@ -783,7 +803,7 @@ var Analytics = class {
|
|
|
783
803
|
build(kind, event, extra) {
|
|
784
804
|
const anon = anonId();
|
|
785
805
|
const wire = {
|
|
786
|
-
messageId:
|
|
806
|
+
messageId: uuidv7(),
|
|
787
807
|
type: kind,
|
|
788
808
|
event,
|
|
789
809
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1006,5 +1026,7 @@ exports.parseDsn = parseDsn;
|
|
|
1006
1026
|
exports.redactSecrets = redactSecrets;
|
|
1007
1027
|
exports.scrubPII = scrubPII;
|
|
1008
1028
|
exports.scrubText = scrubText;
|
|
1029
|
+
exports.uuidv7 = uuidv7;
|
|
1030
|
+
exports.uuidv7Time = uuidv7Time;
|
|
1009
1031
|
//# sourceMappingURL=index.cjs.map
|
|
1010
1032
|
//# sourceMappingURL=index.cjs.map
|