@hanzo/event 0.3.48 → 0.3.50

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 CHANGED
@@ -4,28 +4,9 @@ The ONE telemetry client for Hanzo surfaces. Emits every kind of event —
4
4
  `pageview` / `event` / `identify` / `group` **and errors** — to **Hanzo Cloud**,
5
5
  never to a third-party.
6
6
 
7
- ONE API surface over **TWO** planes. They are separate pipes, and neither can
8
- starve the other:
9
-
10
- ```
11
- 1. event stream POST {host}/v1/event body: { batch: [Event, …] } -> { accepted, dropped }
12
- 2. error plane POST {dsn}/v1/sentry/{projectId}/envelope/?sentry_key=… (a real Sentry envelope)
13
- ```
14
-
15
- > ### Errors need a DSN. Without one, nothing reaches Sentry.
16
- >
17
- > **There is no server-side fan-out from `/v1/event` into Sentry.** Versions
18
- > ≤ 0.3.1 of this README claimed there was — that "Cloud fans the one stream out
19
- > into three lenses". It does not. `/v1/event` writes a `type:'error'` row to the
20
- > cloud event warehouse (readable via `GET /v1/errors`) and stops there. Because
21
- > every Hanzo property believed that claim, nobody set a DSN, and the entire
22
- > fleet reported **zero** errors to Sentry until 0.3.2 added the envelope.
23
- >
24
- > Set `dsn` (or `NEXT_PUBLIC_HANZO_EVENT_DSN`). Mint one per property with
25
- > `POST /v1/sentry/projects`. The key is publishable and write-only — safe in a
26
- > browser bundle, same trust class as a `pk_` ingest key. No DSN means the error
27
- > plane is **inert**: nothing is sent, nothing throws, analytics is unaffected.
28
- > Assert `client.errorPlaneEnabled` if you want to know which you have.
7
+ ONE endpoint, `POST {host}/v1/event`, body `{ batch: [Event, …] }`. Pageviews,
8
+ events, identifies, groups and errors all ride it; there is no second endpoint,
9
+ DSN or envelope.
29
10
 
30
11
  ### No bundler? Use the hosted tag
31
12
 
@@ -78,9 +59,8 @@ refusals. A React app does not need this file — mount `<Hanzo analytics>` from
78
59
  - **Batched** with a size + interval flush, and **beacon-on-unload**
79
60
  (`sendBeacon` for cookie/publishable-key apps, `fetch(keepalive)` for token apps).
80
61
  - **Auto error capture** (subsumes `@sentry`): `window.onerror`,
81
- `unhandledrejection`, and a React `ErrorBoundary` are reported on both planes —
82
- a Sentry envelope to the DSN host, and a correlated `type:'error'` event on the
83
- stream. Opt out with `captureErrors: false`.
62
+ `unhandledrejection`, and a React `ErrorBoundary` are reported as one
63
+ `type:'error'` event each. Opt out with `captureErrors: false`.
84
64
  - **Scrubbed at the source**: secrets are always redacted and PII is masked
85
65
  client-side before an error leaves the device.
86
66
  - **First-touch attribution**: UTM + referrer + `refCode` are parsed once and
@@ -140,12 +120,10 @@ Unhandled errors and promise rejections are captured automatically. React render
140
120
  errors never reach `window.onerror`, so wrap your tree in the `ErrorBoundary` to
141
121
  catch those too. Report caught errors yourself with `captureError`.
142
122
 
143
- **Pass a `dsn` or none of this reaches Sentry.**
144
-
145
123
  ```tsx
146
124
  import { ErrorBoundary } from '@hanzo/event/react'
147
125
 
148
- <AnalyticsProvider config={{ product: 'console', dsn: process.env.NEXT_PUBLIC_HANZO_EVENT_DSN }}>
126
+ <AnalyticsProvider config={{ product: 'console' }}>
149
127
  <ErrorBoundary fallback={(err, reset) => <Crash error={err} onReset={reset} />}>
150
128
  <App />
151
129
  </ErrorBoundary>
@@ -156,20 +134,13 @@ import { ErrorBoundary } from '@hanzo/event/react'
156
134
  try { risky() } catch (err) { analytics.captureError(err, { properties: { where: 'checkout' } }) }
157
135
  ```
158
136
 
159
- Each report goes to both planes:
160
-
161
- - **Sentry** — a real Sentry envelope to the DSN's ingest route. This is the only
162
- thing that creates an issue in the error dashboard, with grouping and stack
163
- frames. Sent one envelope per error, immediately; batching a crash report is
164
- how you lose it.
165
- - **the event stream** — a `type:'error'` event; Cloud folds the exception into
166
- `properties.$exception` and stamps `event_type='error'`, so the error stays
167
- correlated with the session's pageviews (`GET /v1/errors`). This is product
168
- signal, *not* error tracking, and it never reaches Sentry on its own.
137
+ Each report is one `type:'error'` event carrying `error` (`type`, `message`,
138
+ `frames`, `stack`, `handled`) plus `release`, `environment`, `site`, `product` and
139
+ `level`. The server files it on the error plane and groups it into an issue.
169
140
 
170
141
  The message and any `properties` are scrubbed of secrets and PII before sending,
171
142
  and the message is capped at 8KB. `captureError` never throws back into your app,
172
- and a failure on one plane cannot suppress the other.
143
+
173
144
 
174
145
  ## Publishable key (public pages, no bearer)
175
146
 
@@ -178,18 +149,8 @@ Marketing/public pages have no session. Mint a write-only publishable key
178
149
  fetch and `?ingest_key` on an unload beacon, so the **event stream** accepts
179
150
  anonymous traffic. It is safe to ship in a bundle (write-only, cannot read).
180
151
 
181
- The `ingestKey` authenticates the event stream ONLY. The error plane
182
- authenticates independently with the DSN key on `?sentry_key=`, and the two
183
- credentials are never sent to each other's host. A public page that wants errors
184
- in Sentry needs the `dsn` as well:
185
-
186
152
  ```ts
187
- createAnalytics({
188
- product: 'site',
189
- host: 'https://api.hanzo.ai',
190
- ingestKey: 'pk_live_…', // event stream
191
- dsn: process.env.NEXT_PUBLIC_HANZO_EVENT_DSN, // error plane
192
- })
153
+ createAnalytics({ product: 'site', host: 'https://api.hanzo.ai', ingestKey: 'pk_live_…' })
193
154
  ```
194
155
 
195
156
  ## Taxonomy, funnels & goals
package/dist/core.d.ts CHANGED
@@ -13,25 +13,13 @@ export declare class Analytics {
13
13
  private started;
14
14
  /** The view pageview() last counted — path + location. */
15
15
  private counted?;
16
- /** Parsed error-plane DSN, or null when the plane is inert. */
17
- private dsn;
18
16
  /** Guards against an error thrown *inside* the error path re-entering it. */
19
17
  private reentrant;
20
18
  constructor(config: AnalyticsConfig);
21
19
  /** adopt gives this client a credential it does not have. The key belongs to
22
20
  * the stream, not to whichever caller happened to ask for the handle first,
23
- * so a later caller carrying one hands it over. The error plane derives from
24
- * the key, so it comes up here too when it was inert for want of one.
25
- * Present fields are never overwritten: the first caller's key stays. */
21
+ * so a later caller carrying one hands it over. Present fields are never overwritten: the first caller's key stays. */
26
22
  adopt(config: AnalyticsConfig): void;
27
- /** errorPlaneEnabled reports whether captured exceptions can actually reach the
28
- * error host. False means a DSN was never configured — the documented
29
- * fail-safe. Exposed so an app (or a test) can assert its wiring instead of
30
- * discovering months later that nothing was ever reported. */
31
- get errorPlaneEnabled(): boolean;
32
- /** errorIngestUrl is the fully-derived envelope endpoint, or undefined when the
33
- * plane is inert. Diagnostics only. */
34
- get errorIngestUrl(): string | undefined;
35
23
  /** init is idempotent and browser-only for its side effects: capture first-touch
36
24
  * attribution, hydrate cohort, register the unload flush, and (unless opted out)
37
25
  * auto-capture unhandled errors. Safe to call from a React effect on every
@@ -58,19 +46,11 @@ export declare class Analytics {
58
46
  * fields (productId/quantity/revenue/currency) may be passed for order events. */
59
47
  capture(event: string, properties?: Record<string, unknown>, commerce?: Pick<WireEvent, 'productId' | 'quantity' | 'revenue' | 'currency'>): void;
60
48
  /** captureError reports a caught error, an unhandled rejection, a React render
61
- * error, or a manual report to BOTH planes, from one call:
62
- *
63
- * - the ERROR PLANE — a real Sentry envelope to the DSN host. This is the one
64
- * that produces an issue in sentry.hanzo.ai (grouping, stack frames, AST).
65
- * Inert when no DSN is configured.
66
- * - the EVENT STREAM — a `type:'error'` row in the cloud event warehouse, so
67
- * an error stays correlated with the session's pageviews for product
68
- * analysis (readable via GET /v1/errors).
69
- *
70
- * Both carry the SAME session and subject id, so an error and the pageview
71
- * before it join up. Never throws back into the app; errors are higher-signal
72
- * than pageviews, so both planes flush promptly (a crash may unload the page
73
- * moments later). */
49
+ * error, or a manual report as ONE event of type 'error' on the one stream.
50
+ * It carries the exception (type, message, frames, stack, handled) and the
51
+ * release, environment, site, product and level that group and scope it, and
52
+ * flushes promptly (a crash may unload the page moments later). Never throws
53
+ * back into the app. */
74
54
  captureError(err: unknown, context?: CaptureErrorOptions): void;
75
55
  /** setCohort persists cohort dimensions (e.g. signupWeek at signup) so they ride
76
56
  * every subsequent event. */
@@ -87,16 +67,6 @@ export declare class Analytics {
87
67
  * cookie fine).
88
68
  */
89
69
  flush(beacon?: boolean): void;
90
- /** sendError frames one exception as a Sentry envelope and posts it to the DSN's
91
- * ingest URL. The DSN's own key rides ?sentry_key= (the credential channel the
92
- * server trusts, and the only one a headerless beacon can carry), so NO bearer
93
- * or publishable key is attached here — the two planes authenticate
94
- * independently. Errors are sent one envelope per event, immediately: batching
95
- * a crash report is how you lose it. */
96
- private sendError;
97
- /** errorIdentity is the SAME identity the event stream stamps — the OIDC subject
98
- * once identify() has run, else the anon id. Never email/PII. */
99
- private errorIdentity;
100
70
  private enqueue;
101
71
  private build;
102
72
  private schedule;
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAoCA,OAAO,EAKL,aAAa,EAEb,SAAS,EAEV,MAAM,WAAW,CAAA;AAGlB,OAAO,KAAK,EACV,eAAe,EAEf,mBAAmB,EACnB,MAAM,EAIN,SAAS,EACV,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,OAAO,EAAE,CAAA;AAoKlB,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,6EAA6E;IAC7E,OAAO,CAAC,SAAS,CAAQ;IAEzB,YAAY,MAAM,EAAE,eAAe,EAgClC;IAED;;4HAEwH;IACxH,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAGnC;IAED;;;kBAGc;IACd,IAAI,IAAI,IAAI,CA6CX;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;;;;;6BAKyB;IACzB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAsB9D;IAED;kCAC8B;IAC9B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE7B;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,UAAQ,GAAG,IAAI,CAyB1B;IAID,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"}