@hanzo/event 0.3.0 → 0.3.2
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 +61 -17
- package/dist/core-B1XEdWLd.d.cts +296 -0
- package/dist/core-B1XEdWLd.d.ts +296 -0
- package/dist/{index.js → index.cjs} +401 -20
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +65 -3
- package/dist/index.d.ts +65 -3
- package/dist/index.mjs +393 -19
- package/dist/index.mjs.map +1 -1
- package/dist/{react.js → react.cjs} +394 -20
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +392 -18
- package/dist/react.mjs.map +1 -1
- package/package.json +19 -9
- package/src/core.test.ts +258 -5
- package/src/core.ts +225 -37
- package/src/index.ts +8 -0
- package/src/scrub.test.ts +96 -0
- package/src/scrub.ts +112 -0
- package/src/sentry.test.ts +260 -0
- package/src/sentry.ts +279 -0
- package/src/types.ts +117 -15
- package/src/version.ts +4 -0
- package/dist/core-CrbiAQhN.d.cts +0 -186
- package/dist/core-CrbiAQhN.d.ts +0 -186
- package/dist/index.js.map +0 -1
- package/dist/react.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,23 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
The ONE telemetry client for Hanzo surfaces. Emits every kind of event —
|
|
4
4
|
`pageview` / `event` / `identify` / `group` **and errors** — to **Hanzo Cloud**,
|
|
5
|
-
never to a third-party.
|
|
5
|
+
never to a third-party.
|
|
6
|
+
|
|
7
|
+
ONE API surface over **TWO** planes. They are separate pipes, and neither can
|
|
8
|
+
starve the other:
|
|
6
9
|
|
|
7
10
|
```
|
|
8
|
-
POST {host}/v1/event
|
|
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)
|
|
9
13
|
```
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
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.
|
|
29
|
+
|
|
30
|
+
Web analytics (analytics.hanzo.ai) is a **third, separate** plane and is NOT this
|
|
31
|
+
client — it is the `hz.js` tag, which speaks a different wire (a bare JSON array).
|
|
32
|
+
Note that `analytics.hanzo.ai/v1/event` and `api.hanzo.ai/v1/event` share a path
|
|
33
|
+
spelling but are **different protocols**; point this client at the API host.
|
|
15
34
|
|
|
16
35
|
- **Batched** with a size + interval flush, and **beacon-on-unload**
|
|
17
36
|
(`sendBeacon` for cookie/publishable-key apps, `fetch(keepalive)` for token apps).
|
|
18
37
|
- **Auto error capture** (subsumes `@sentry`): `window.onerror`,
|
|
19
|
-
`unhandledrejection`, and a React `ErrorBoundary`
|
|
20
|
-
|
|
21
|
-
`captureErrors: false`.
|
|
38
|
+
`unhandledrejection`, and a React `ErrorBoundary` are reported on both planes —
|
|
39
|
+
a Sentry envelope to the DSN host, and a correlated `type:'error'` event on the
|
|
40
|
+
stream. Opt out with `captureErrors: false`.
|
|
41
|
+
- **Scrubbed at the source**: secrets are always redacted and PII is masked
|
|
42
|
+
client-side before an error leaves the device.
|
|
22
43
|
- **First-touch attribution**: UTM + referrer + `refCode` are parsed once and
|
|
23
44
|
persisted, then attached to every event.
|
|
24
45
|
- **Cohorts**: `signupWeek`, `channel`, `refCode` ride each event.
|
|
@@ -76,10 +97,12 @@ Unhandled errors and promise rejections are captured automatically. React render
|
|
|
76
97
|
errors never reach `window.onerror`, so wrap your tree in the `ErrorBoundary` to
|
|
77
98
|
catch those too. Report caught errors yourself with `captureError`.
|
|
78
99
|
|
|
100
|
+
**Pass a `dsn` or none of this reaches Sentry.**
|
|
101
|
+
|
|
79
102
|
```tsx
|
|
80
103
|
import { ErrorBoundary } from '@hanzo/event/react'
|
|
81
104
|
|
|
82
|
-
<AnalyticsProvider config={{ product: 'console' }}>
|
|
105
|
+
<AnalyticsProvider config={{ product: 'console', dsn: process.env.NEXT_PUBLIC_HANZO_EVENT_DSN }}>
|
|
83
106
|
<ErrorBoundary fallback={(err, reset) => <Crash error={err} onReset={reset} />}>
|
|
84
107
|
<App />
|
|
85
108
|
</ErrorBoundary>
|
|
@@ -90,19 +113,40 @@ import { ErrorBoundary } from '@hanzo/event/react'
|
|
|
90
113
|
try { risky() } catch (err) { analytics.captureError(err, { properties: { where: 'checkout' } }) }
|
|
91
114
|
```
|
|
92
115
|
|
|
93
|
-
Each
|
|
94
|
-
|
|
95
|
-
|
|
116
|
+
Each report goes to both planes:
|
|
117
|
+
|
|
118
|
+
- **Sentry** — a real Sentry envelope to the DSN's ingest route. This is the only
|
|
119
|
+
thing that creates an issue in the error dashboard, with grouping and stack
|
|
120
|
+
frames. Sent one envelope per error, immediately; batching a crash report is
|
|
121
|
+
how you lose it.
|
|
122
|
+
- **the event stream** — a `type:'error'` event; Cloud folds the exception into
|
|
123
|
+
`properties.$exception` and stamps `event_type='error'`, so the error stays
|
|
124
|
+
correlated with the session's pageviews (`GET /v1/errors`). This is product
|
|
125
|
+
signal, *not* error tracking, and it never reaches Sentry on its own.
|
|
126
|
+
|
|
127
|
+
The message and any `properties` are scrubbed of secrets and PII before sending,
|
|
128
|
+
and the message is capped at 8KB. `captureError` never throws back into your app,
|
|
129
|
+
and a failure on one plane cannot suppress the other.
|
|
96
130
|
|
|
97
131
|
## Publishable key (public pages, no bearer)
|
|
98
132
|
|
|
99
133
|
Marketing/public pages have no session. Mint a write-only publishable key
|
|
100
|
-
(`POST /v1/ingest/keys`) and pass it as `ingestKey`; it rides `Authorization`
|
|
101
|
-
|
|
102
|
-
|
|
134
|
+
(`POST /v1/ingest/keys`) and pass it as `ingestKey`; it rides `Authorization` on
|
|
135
|
+
fetch and `?ingest_key` on an unload beacon, so the **event stream** accepts
|
|
136
|
+
anonymous traffic. It is safe to ship in a bundle (write-only, cannot read).
|
|
137
|
+
|
|
138
|
+
The `ingestKey` authenticates the event stream ONLY. The error plane
|
|
139
|
+
authenticates independently with the DSN key on `?sentry_key=`, and the two
|
|
140
|
+
credentials are never sent to each other's host. A public page that wants errors
|
|
141
|
+
in Sentry needs the `dsn` as well:
|
|
103
142
|
|
|
104
143
|
```ts
|
|
105
|
-
createAnalytics({
|
|
144
|
+
createAnalytics({
|
|
145
|
+
product: 'site',
|
|
146
|
+
host: 'https://api.hanzo.ai',
|
|
147
|
+
ingestKey: 'pk_live_…', // event stream
|
|
148
|
+
dsn: process.env.NEXT_PUBLIC_HANZO_EVENT_DSN, // error plane
|
|
149
|
+
})
|
|
106
150
|
```
|
|
107
151
|
|
|
108
152
|
## Goals & cohorts
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/** The event kinds — the closed set the server understands. `error` marks the
|
|
2
|
+
* breadcrumb an exception leaves on the event stream (Cloud stamps
|
|
3
|
+
* event_type='error' for the warehouse, GET /v1/errors). It does NOT reach the
|
|
4
|
+
* Sentry dashboard — the envelope on the error plane does that. */
|
|
5
|
+
type EventKind = 'pageview' | 'event' | 'identify' | 'group' | 'error';
|
|
6
|
+
/** A captured exception as it rides the EVENT STREAM — Cloud folds it into
|
|
7
|
+
* properties.$exception for the warehouse. The richer copy (parsed stack frames,
|
|
8
|
+
* grouping, release) travels on the error plane as a Sentry envelope; see
|
|
9
|
+
* AnalyticsConfig.dsn. */
|
|
10
|
+
interface Exception {
|
|
11
|
+
/** Constructor/class name, e.g. "TypeError". */
|
|
12
|
+
type?: string;
|
|
13
|
+
/** The error message. */
|
|
14
|
+
message: string;
|
|
15
|
+
/** Stack trace when available. */
|
|
16
|
+
stack?: string;
|
|
17
|
+
/** false = an unhandled/global error (window.onerror, unhandledrejection);
|
|
18
|
+
* true = a caught error the app chose to report. Defaults true. */
|
|
19
|
+
handled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** First-touch marketing attribution, parsed once and persisted. */
|
|
22
|
+
interface Attribution {
|
|
23
|
+
utm: {
|
|
24
|
+
source?: string;
|
|
25
|
+
medium?: string;
|
|
26
|
+
campaign?: string;
|
|
27
|
+
term?: string;
|
|
28
|
+
content?: string;
|
|
29
|
+
};
|
|
30
|
+
referrer?: string;
|
|
31
|
+
refCode?: string;
|
|
32
|
+
/** Derived acquisition channel: direct | organic | paid | social | referral. */
|
|
33
|
+
channel?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Cohort dimensions carried on every event once known (see goals.ts COHORTS). */
|
|
36
|
+
interface Cohort {
|
|
37
|
+
/** ISO week the person first signed up, e.g. "2026-W28". */
|
|
38
|
+
signupWeek?: string;
|
|
39
|
+
channel?: string;
|
|
40
|
+
refCode?: string;
|
|
41
|
+
}
|
|
42
|
+
/** One event as sent on the wire — the canonical Hanzo Cloud event. Maps 1:1 to
|
|
43
|
+
* the cloud `CaptureEvent` (camelCase JSON keys); a batch of these is POSTed to
|
|
44
|
+
* the ONE front door `/v1/event` as `{ batch: [WireEvent, …] }`. tenant/org is
|
|
45
|
+
* NEVER a field here — the server stamps it from the validated session/key. */
|
|
46
|
+
interface WireEvent {
|
|
47
|
+
messageId: string;
|
|
48
|
+
type: EventKind;
|
|
49
|
+
event?: string;
|
|
50
|
+
timestamp: string;
|
|
51
|
+
distinctId?: string;
|
|
52
|
+
anonymousId?: string;
|
|
53
|
+
personId?: string;
|
|
54
|
+
sessionId?: string;
|
|
55
|
+
product?: string;
|
|
56
|
+
url?: string;
|
|
57
|
+
path?: string;
|
|
58
|
+
referrer?: string;
|
|
59
|
+
utm?: Attribution['utm'];
|
|
60
|
+
refCode?: string;
|
|
61
|
+
channel?: string;
|
|
62
|
+
groupId?: string;
|
|
63
|
+
signupWeek?: string;
|
|
64
|
+
productId?: string;
|
|
65
|
+
quantity?: number;
|
|
66
|
+
revenue?: number;
|
|
67
|
+
currency?: string;
|
|
68
|
+
/** Set on `type:'error'` events — the captured exception. Cloud lifts it into
|
|
69
|
+
* properties.$exception (foldException) for the event warehouse. Not a Sentry
|
|
70
|
+
* path: the envelope on the error plane is what feeds the dashboard. */
|
|
71
|
+
error?: Exception;
|
|
72
|
+
properties?: Record<string, unknown>;
|
|
73
|
+
library?: string;
|
|
74
|
+
libraryVersion?: string;
|
|
75
|
+
}
|
|
76
|
+
/** Injectable transports — overridden in tests; the default in core.ts uses fetch
|
|
77
|
+
* (keepalive) and sendBeacon. A bearer JWT or a publishable pk_ key rides
|
|
78
|
+
* Authorization on fetch; on a headerless beacon a publishable key rides the
|
|
79
|
+
* ?ingest_key query. */
|
|
80
|
+
interface Transport {
|
|
81
|
+
/** Durable POST usable during page unload (fetch keepalive / sendBeacon).
|
|
82
|
+
* `contentType` defaults to application/json; the error plane overrides it with
|
|
83
|
+
* application/x-sentry-envelope. */
|
|
84
|
+
send(url: string, body: string, opts: {
|
|
85
|
+
beacon: boolean;
|
|
86
|
+
token?: string;
|
|
87
|
+
ingestKey?: string;
|
|
88
|
+
contentType?: string;
|
|
89
|
+
/** Surface non-OK / failed ingest on the console. Never on by default. */
|
|
90
|
+
debug?: boolean;
|
|
91
|
+
}): void;
|
|
92
|
+
}
|
|
93
|
+
interface AnalyticsConfig {
|
|
94
|
+
/** Cloud base URL. Defaults to "https://api.hanzo.ai" (the one edge). Set to
|
|
95
|
+
* same-origin ("") for cookie-auth apps served behind the same edge
|
|
96
|
+
* (console/admin/chat), so the browser rides the session cookie. */
|
|
97
|
+
host?: string;
|
|
98
|
+
/** Emitting surface: console | chat | app | site | admin. */
|
|
99
|
+
product: string;
|
|
100
|
+
/** Bearer token provider for token-auth apps. Omit for cookie/session apps
|
|
101
|
+
* (the client then relies on same-origin credentials). */
|
|
102
|
+
getToken?: () => string | undefined | null;
|
|
103
|
+
/** Publishable ingest key (pk_…). When set, the client authenticates to the ONE
|
|
104
|
+
* 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 accepted and unload beacons work
|
|
107
|
+
* without a bearer. The key is write-only (cannot read) and safe to ship in a
|
|
108
|
+
* bundle; mint one per org via POST /v1/ingest/keys. This authenticates the
|
|
109
|
+
* EVENT STREAM only — the error plane authenticates independently with `dsn`,
|
|
110
|
+
* and one does not stand in for the other. */
|
|
111
|
+
ingestKey?: string;
|
|
112
|
+
/** Max events buffered before an automatic flush. */
|
|
113
|
+
batchSize?: number;
|
|
114
|
+
/** Auto-flush cadence in ms. */
|
|
115
|
+
flushIntervalMs?: number;
|
|
116
|
+
/** Turn the client off entirely (e.g. opt-out / DNT). Defaults to enabled. */
|
|
117
|
+
enabled?: boolean;
|
|
118
|
+
/** Auto-capture unhandled errors + promise rejections (window.onerror,
|
|
119
|
+
* unhandledrejection). Browser-only, defaults to enabled. Together with `dsn`
|
|
120
|
+
* this is what makes the client a drop-in @sentry replacement — without a
|
|
121
|
+
* `dsn` the captures never reach the Sentry dashboard. */
|
|
122
|
+
captureErrors?: boolean;
|
|
123
|
+
/** Override the transport (tests). */
|
|
124
|
+
transport?: Transport;
|
|
125
|
+
/** Debug logging. */
|
|
126
|
+
debug?: boolean;
|
|
127
|
+
/** Hanzo-minted Sentry DSN: "https://<version>:<hmac>@<host>/v1/sentry/<projectId>".
|
|
128
|
+
* Publishable — the key authorizes writes to ONE project and can read nothing,
|
|
129
|
+
* so it is safe in a browser bundle (same trust class as `ingestKey`). When
|
|
130
|
+
* absent the client reads NEXT_PUBLIC_HANZO_EVENT_DSN; when neither is set the
|
|
131
|
+
* error plane is inert (fail-safe: nothing sent, nothing thrown, analytics
|
|
132
|
+
* unaffected). Mint one per property: POST /v1/sentry/projects. */
|
|
133
|
+
dsn?: string;
|
|
134
|
+
/** Release stamped on error events (a git SHA / app version). */
|
|
135
|
+
release?: string;
|
|
136
|
+
/** Deployment environment for error events (production | staging | …). */
|
|
137
|
+
environment?: string;
|
|
138
|
+
/** Retain end-user PII (emails/IPs) in error text. Default false = scrub
|
|
139
|
+
* client-side before anything leaves the device (the server scrubs again). */
|
|
140
|
+
capturePII?: boolean;
|
|
141
|
+
}
|
|
142
|
+
type SentryLevel = 'fatal' | 'error' | 'warning' | 'info' | 'debug';
|
|
143
|
+
interface SentryFrame {
|
|
144
|
+
filename?: string;
|
|
145
|
+
function?: string;
|
|
146
|
+
module?: string;
|
|
147
|
+
abs_path?: string;
|
|
148
|
+
lineno?: number;
|
|
149
|
+
colno?: number;
|
|
150
|
+
in_app?: boolean;
|
|
151
|
+
}
|
|
152
|
+
interface SentryExceptionValue {
|
|
153
|
+
type?: string;
|
|
154
|
+
value?: string;
|
|
155
|
+
module?: string;
|
|
156
|
+
stacktrace?: {
|
|
157
|
+
frames: SentryFrame[];
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
interface SentryUser {
|
|
161
|
+
/** Stable subject id (OIDC sub / anon id). NEVER email/username/ip. */
|
|
162
|
+
id?: string;
|
|
163
|
+
}
|
|
164
|
+
interface SentryEvent {
|
|
165
|
+
event_id: string;
|
|
166
|
+
timestamp: number;
|
|
167
|
+
platform: 'javascript';
|
|
168
|
+
level: SentryLevel;
|
|
169
|
+
logger?: string;
|
|
170
|
+
environment?: string;
|
|
171
|
+
release?: string;
|
|
172
|
+
transaction?: string;
|
|
173
|
+
fingerprint?: string[];
|
|
174
|
+
message?: string;
|
|
175
|
+
exception?: {
|
|
176
|
+
values: SentryExceptionValue[];
|
|
177
|
+
};
|
|
178
|
+
tags?: Record<string, string>;
|
|
179
|
+
user?: SentryUser;
|
|
180
|
+
contexts?: Record<string, Record<string, unknown>>;
|
|
181
|
+
sdk?: {
|
|
182
|
+
name: string;
|
|
183
|
+
version: string;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/** Parsed DSN — the public key + the derived ingest URL. */
|
|
187
|
+
interface Dsn {
|
|
188
|
+
/** "<version>:<hmac>" public key presented via ?sentry_key= (beacon-safe). */
|
|
189
|
+
publicKey: string;
|
|
190
|
+
/** Ingest origin, e.g. "https://sentry.hanzo.ai". */
|
|
191
|
+
origin: string;
|
|
192
|
+
/** Project id segment. */
|
|
193
|
+
projectId: string;
|
|
194
|
+
/** Fully-derived envelope ingest URL incl. ?sentry_key=. */
|
|
195
|
+
ingestUrl: string;
|
|
196
|
+
}
|
|
197
|
+
/** Options for Analytics.captureError. */
|
|
198
|
+
interface CaptureErrorOptions {
|
|
199
|
+
/** false => uncaught (window.onerror / unhandledrejection / render crash). */
|
|
200
|
+
handled?: boolean;
|
|
201
|
+
/** Severity + free-form context; merged into the event's tags. */
|
|
202
|
+
properties?: Record<string, unknown>;
|
|
203
|
+
/** Override the event level (default: error, or fatal when handled === false). */
|
|
204
|
+
level?: SentryLevel;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
declare class Analytics {
|
|
208
|
+
private cfg;
|
|
209
|
+
private transport;
|
|
210
|
+
private queue;
|
|
211
|
+
private timer;
|
|
212
|
+
private personId?;
|
|
213
|
+
private attribution;
|
|
214
|
+
private cohort;
|
|
215
|
+
private started;
|
|
216
|
+
/** Parsed error-plane DSN, or null when the plane is inert. */
|
|
217
|
+
private dsn;
|
|
218
|
+
/** Guards against an error thrown *inside* the error path re-entering it. */
|
|
219
|
+
private reentrant;
|
|
220
|
+
constructor(config: AnalyticsConfig);
|
|
221
|
+
/** errorPlaneEnabled reports whether captured exceptions can actually reach the
|
|
222
|
+
* error host. False means a DSN was never configured — the documented
|
|
223
|
+
* fail-safe. Exposed so an app (or a test) can assert its wiring instead of
|
|
224
|
+
* discovering months later that nothing was ever reported. */
|
|
225
|
+
get errorPlaneEnabled(): boolean;
|
|
226
|
+
/** errorIngestUrl is the fully-derived envelope endpoint, or undefined when the
|
|
227
|
+
* plane is inert. Diagnostics only. */
|
|
228
|
+
get errorIngestUrl(): string | undefined;
|
|
229
|
+
/** init is idempotent and browser-only for its side effects: capture first-touch
|
|
230
|
+
* attribution, hydrate cohort, register the unload flush, and (unless opted out)
|
|
231
|
+
* auto-capture unhandled errors. Safe to call from a React effect on every
|
|
232
|
+
* render. */
|
|
233
|
+
init(): void;
|
|
234
|
+
/** identify binds the current visitor to a stable person id (post-login). */
|
|
235
|
+
identify(personId: string, traits?: Record<string, unknown>): void;
|
|
236
|
+
/** group associates the visitor with an org/team (analytics grouping, not the
|
|
237
|
+
* server tenant — the server still derives tenant from the session). */
|
|
238
|
+
group(groupId: string, traits?: Record<string, unknown>): void;
|
|
239
|
+
/** pageview records a $pageview for the current (or given) location. */
|
|
240
|
+
pageview(path?: string, properties?: Record<string, unknown>): void;
|
|
241
|
+
/** capture records a named product event with optional properties. Commerce
|
|
242
|
+
* fields (productId/quantity/revenue/currency) may be passed for order events. */
|
|
243
|
+
capture(event: string, properties?: Record<string, unknown>, commerce?: Pick<WireEvent, 'productId' | 'quantity' | 'revenue' | 'currency'>): void;
|
|
244
|
+
/** track is an alias of capture (Segment familiarity). */
|
|
245
|
+
track: (event: string, properties?: Record<string, unknown>, commerce?: Pick<WireEvent, "productId" | "quantity" | "revenue" | "currency">) => void;
|
|
246
|
+
/** captureError reports a caught error, an unhandled rejection, a React render
|
|
247
|
+
* error, or a manual report to BOTH planes, from one call:
|
|
248
|
+
*
|
|
249
|
+
* - the ERROR PLANE — a real Sentry envelope to the DSN host. This is the one
|
|
250
|
+
* that produces an issue in sentry.hanzo.ai (grouping, stack frames, AST).
|
|
251
|
+
* Inert when no DSN is configured.
|
|
252
|
+
* - the EVENT STREAM — a `type:'error'` row in the cloud event warehouse, so
|
|
253
|
+
* an error stays correlated with the session's pageviews for product
|
|
254
|
+
* analysis (readable via GET /v1/errors).
|
|
255
|
+
*
|
|
256
|
+
* Both carry the SAME session and subject id, so an error and the pageview
|
|
257
|
+
* before it join up. Never throws back into the app; errors are higher-signal
|
|
258
|
+
* than pageviews, so both planes flush promptly (a crash may unload the page
|
|
259
|
+
* moments later). */
|
|
260
|
+
captureError(err: unknown, context?: CaptureErrorOptions): void;
|
|
261
|
+
/** captureException — @sentry-familiar alias of captureError. */
|
|
262
|
+
captureException: (err: unknown, context?: CaptureErrorOptions) => void;
|
|
263
|
+
/** setCohort persists cohort dimensions (e.g. signupWeek at signup) so they ride
|
|
264
|
+
* every subsequent event. */
|
|
265
|
+
setCohort(patch: Cohort): void;
|
|
266
|
+
/** flush drains the buffer to the server as ONE batch through the ONE ingest
|
|
267
|
+
* front door POST /v1/event, body { batch: [Event…] }. beacon=true selects the
|
|
268
|
+
* unload-safe transport. Auth is orthogonal to the wire:
|
|
269
|
+
*
|
|
270
|
+
* • publishable key set → rides Authorization: Bearer pk_… (fetch) or
|
|
271
|
+
* ?ingest_key=pk_… (beacon), so unload beacons work anonymously.
|
|
272
|
+
* • else a bearer JWT rides Authorization (fetch only — sendBeacon cannot
|
|
273
|
+
* carry a header, so token apps fall back to keepalive fetch on unload).
|
|
274
|
+
* • else a cookie app rides same-origin credentials (beacon carries the
|
|
275
|
+
* cookie fine).
|
|
276
|
+
*/
|
|
277
|
+
flush(beacon?: boolean): void;
|
|
278
|
+
/** sendError frames one exception as a Sentry envelope and posts it to the DSN's
|
|
279
|
+
* ingest URL. The DSN's own key rides ?sentry_key= (the credential channel the
|
|
280
|
+
* server trusts, and the only one a headerless beacon can carry), so NO bearer
|
|
281
|
+
* or publishable key is attached here — the two planes authenticate
|
|
282
|
+
* independently. Errors are sent one envelope per event, immediately: batching
|
|
283
|
+
* a crash report is how you lose it. */
|
|
284
|
+
private sendError;
|
|
285
|
+
/** errorIdentity is the SAME identity the event stream stamps — the OIDC subject
|
|
286
|
+
* once identify() has run, else the anon id. Never email/PII. */
|
|
287
|
+
private errorIdentity;
|
|
288
|
+
private enqueue;
|
|
289
|
+
private build;
|
|
290
|
+
private schedule;
|
|
291
|
+
private clearTimer;
|
|
292
|
+
}
|
|
293
|
+
/** createAnalytics builds a client instance. Most apps use one shared instance. */
|
|
294
|
+
declare function createAnalytics(config: AnalyticsConfig): Analytics;
|
|
295
|
+
|
|
296
|
+
export { type Attribution as A, type Cohort as C, type Dsn as D, type EventKind as E, type SentryEvent as S, type Transport as T, type WireEvent as W, type CaptureErrorOptions as a, type SentryFrame as b, Analytics as c, type AnalyticsConfig as d, type Exception as e, type SentryLevel as f, createAnalytics as g };
|