@hanzo/event 0.3.10 → 0.3.12
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/README.md +15 -0
- package/dist/{core-BCEdNp8H.d.cts → core-BZraSvcr.d.cts} +6 -3
- package/dist/{core-BCEdNp8H.d.ts → core-BZraSvcr.d.ts} +6 -3
- package/dist/index.cjs +18 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +18 -10
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +18 -10
- 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 +18 -10
- package/dist/react.mjs.map +1 -1
- package/hz.js +45 -4
- package/package.json +1 -1
- package/src/core.test.ts +33 -4
- package/src/core.ts +29 -11
- package/src/hz.test.ts +166 -36
- package/src/types.ts +6 -3
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -32,9 +32,18 @@ starve the other:
|
|
|
32
32
|
```html
|
|
33
33
|
<script async src="https://unpkg.com/@hanzo/event/hz.js"
|
|
34
34
|
data-product="hanzo.ai"
|
|
35
|
+
data-ingest-key="pk-…"
|
|
35
36
|
data-capture="1"></script>
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
> **`data-ingest-key` is required off the door's own origin**, and through
|
|
40
|
+
> 0.3.11 this file could not present one at all — no header, no query. A keyed
|
|
41
|
+
> static surface therefore sent UNATTRIBUTED writes, which the door refuses
|
|
42
|
+
> (`401 ingest_key_required`) silently, because nothing here reads the response.
|
|
43
|
+
> The tag measured fine in the browser and filed nothing. It now rides
|
|
44
|
+
> `Authorization: Bearer pk-…` on fetch and `?ingest_key=pk-…` on a headerless
|
|
45
|
+
> unload beacon — the same pair the npm client uses.
|
|
46
|
+
|
|
38
47
|
`hz.js` (in this package) is the **script-tag distribution** of this client, for
|
|
39
48
|
surfaces with no build step. It posts the SAME `{ batch: [WireEvent, …] }` to the
|
|
40
49
|
SAME `POST {host}/v1/event`, and adds DOM **autocapture** — `$click` (with an
|
|
@@ -42,6 +51,12 @@ element locator), `$outbound`, `$scroll`, `$form`, `$vitals` — which a bundled
|
|
|
42
51
|
does not need and a plain page cannot get. Manual API: `window.hanzo.track()` /
|
|
43
52
|
`identify()` / `page()`.
|
|
44
53
|
|
|
54
|
+
It honours the same consent sources the bundled stack does: an explicit stored
|
|
55
|
+
choice (`hz_consent`, the key a Hanzo consent banner writes) outranks the browser
|
|
56
|
+
signal in both directions; otherwise Global Privacy Control and Do Not Track are
|
|
57
|
+
refusals. A React app does not need this file — mount `<Hanzo analytics>` from
|
|
58
|
+
`@hanzo/ui`, which wires this client and the capture engine together.
|
|
59
|
+
|
|
45
60
|
> The tag used to live in `hanzoai/analytics` and post a **bare JSON array** of
|
|
46
61
|
> `{site, ts, type, path, …}` to `analytics.hanzo.ai/v1/event` — a second protocol
|
|
47
62
|
> behind an identical path spelling, served by a second collector with its own
|
|
@@ -108,9 +108,12 @@ interface AnalyticsConfig {
|
|
|
108
108
|
* a reading principal — so it is safe to ship in a bundle. Mint one per org with
|
|
109
109
|
* POST /v1/keys {"type":"publishable"}.
|
|
110
110
|
*
|
|
111
|
-
* Omit it and the client reads
|
|
112
|
-
*
|
|
113
|
-
*
|
|
111
|
+
* Omit it and the client reads NEXT_PUBLIC_EVENT_INGEST_KEY from the inlined
|
|
112
|
+
* build env, the same way `dsn` falls back — so a surface declares BOTH planes
|
|
113
|
+
* in its build and neither needs code to switch on. That is the ONE spelling
|
|
114
|
+
* the fleet already carries: KMS holds deploy/EVENT_INGEST_KEY, and each
|
|
115
|
+
* Dockerfile takes EVENT_INGEST_KEY as a build-arg and re-exports it with the
|
|
116
|
+
* NEXT_PUBLIC_ prefix that makes Next inline it.
|
|
114
117
|
*
|
|
115
118
|
* A surface with no key at all still reports for whoever is SIGNED IN (the
|
|
116
119
|
* session credential attributes them), and drops every logged-out visitor: the
|
|
@@ -108,9 +108,12 @@ interface AnalyticsConfig {
|
|
|
108
108
|
* a reading principal — so it is safe to ship in a bundle. Mint one per org with
|
|
109
109
|
* POST /v1/keys {"type":"publishable"}.
|
|
110
110
|
*
|
|
111
|
-
* Omit it and the client reads
|
|
112
|
-
*
|
|
113
|
-
*
|
|
111
|
+
* Omit it and the client reads NEXT_PUBLIC_EVENT_INGEST_KEY from the inlined
|
|
112
|
+
* build env, the same way `dsn` falls back — so a surface declares BOTH planes
|
|
113
|
+
* in its build and neither needs code to switch on. That is the ONE spelling
|
|
114
|
+
* the fleet already carries: KMS holds deploy/EVENT_INGEST_KEY, and each
|
|
115
|
+
* Dockerfile takes EVENT_INGEST_KEY as a build-arg and re-exports it with the
|
|
116
|
+
* NEXT_PUBLIC_ prefix that makes Next inline it.
|
|
114
117
|
*
|
|
115
118
|
* A surface with no key at all still reports for whoever is SIGNED IN (the
|
|
116
119
|
* session credential attributes them), and drops every logged-out visitor: the
|
package/dist/index.cjs
CHANGED
|
@@ -246,7 +246,7 @@ function uuidv7Time(id) {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
// src/version.ts
|
|
249
|
-
var VERSION = "0.3.
|
|
249
|
+
var VERSION = "0.3.12";
|
|
250
250
|
|
|
251
251
|
// src/sentry.ts
|
|
252
252
|
var MAX_FRAMES = 50;
|
|
@@ -618,13 +618,21 @@ var Analytics = class {
|
|
|
618
618
|
captureErrors: true,
|
|
619
619
|
...config,
|
|
620
620
|
// The publishable key resolves the SAME way the DSN below does: an explicit
|
|
621
|
-
// config wins, else the inlined build-time env.
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
|
|
621
|
+
// config wins, else the inlined build-time env.
|
|
622
|
+
//
|
|
623
|
+
// NEXT_PUBLIC_EVENT_INGEST_KEY is that env, and it is the name the fleet
|
|
624
|
+
// ALREADY carries end to end — KMS holds deploy/EVENT_INGEST_KEY, each
|
|
625
|
+
// Dockerfile takes it as the EVENT_INGEST_KEY build-arg and re-exports it
|
|
626
|
+
// with the NEXT_PUBLIC_ prefix Next needs to inline it. Reading anything
|
|
627
|
+
// else here would add a fourth spelling of one value.
|
|
628
|
+
//
|
|
629
|
+
// Without this the key was the one piece of wiring a surface could not
|
|
630
|
+
// declare the way it declares every other piece, so a surface that shipped
|
|
631
|
+
// without passing it in code sent its beacons unattributed — and an
|
|
632
|
+
// unattributed write is refused (401 ingest_key_required), which is silent
|
|
633
|
+
// in the page and invisible until you read the warehouse and find the host
|
|
634
|
+
// missing entirely.
|
|
635
|
+
ingestKey: config.ingestKey ?? readEnv("NEXT_PUBLIC_EVENT_INGEST_KEY")
|
|
628
636
|
};
|
|
629
637
|
this.transport = config.transport ?? new DefaultTransport();
|
|
630
638
|
this.dsn = parseDsn(config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product));
|
|
@@ -743,8 +751,8 @@ var Analytics = class {
|
|
|
743
751
|
const batch = this.queue;
|
|
744
752
|
this.queue = [];
|
|
745
753
|
this.clearTimer();
|
|
746
|
-
const
|
|
747
|
-
const
|
|
754
|
+
const token = this.cfg.getToken?.() ?? void 0;
|
|
755
|
+
const key = token ? void 0 : this.cfg.ingestKey?.trim() || void 0;
|
|
748
756
|
const useBeacon = beacon && !token;
|
|
749
757
|
const body = serializeBatch(batch);
|
|
750
758
|
if (body === null) {
|