@hanzo/event 0.3.18 → 0.3.20
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-D4PaPlOB.d.cts → core-CHLpJy51.d.cts} +56 -1
- package/dist/{core-D4PaPlOB.d.ts → core-CHLpJy51.d.ts} +56 -1
- package/dist/index.cjs +119 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -10
- package/dist/index.d.ts +70 -10
- package/dist/index.mjs +114 -12
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +113 -11
- 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 +113 -11
- package/dist/react.mjs.map +1 -1
- package/hz.js +1 -1
- package/package.json +10 -10
- package/src/core.test.ts +45 -12
- package/src/core.ts +30 -3
- package/src/dsn.test.ts +14 -11
- package/src/dsn.ts +19 -14
- package/src/events.ts +5 -0
- package/src/exception.test.ts +188 -0
- package/src/exception.ts +200 -0
- package/src/index.ts +6 -2
- package/src/types.ts +53 -0
- package/src/version.ts +1 -1
- package/LICENSE.md +0 -21
package/dist/index.d.cts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { C as Cohort, A as Attribution, S as SentryEvent, D as Dsn, a as CaptureErrorOptions, b as SentryFrame } from './core-
|
|
2
|
-
export {
|
|
1
|
+
import { C as Cohort, A as Attribution, S as SentryEvent, D as Dsn, a as CaptureErrorOptions, b as SentryFrame, E as ExceptionEntry, c as SentryLevel, d as ExceptionProperties } from './core-CHLpJy51.cjs';
|
|
2
|
+
export { e as Analytics, f as AnalyticsConfig, g as EventKind, h as Exception, i as ExceptionFrame, T as Transport, W as WireEvent, j as createAnalytics } from './core-CHLpJy51.cjs';
|
|
3
3
|
|
|
4
4
|
/** Read the persisted first-touch attribution. */
|
|
5
5
|
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.20";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* parseDsn parses "https://<version>:<hmac>@<host>/v1/sentry/<projectId>" into its
|
|
@@ -102,12 +102,19 @@ declare function uuidv7Time(id: string): number;
|
|
|
102
102
|
* (POST /v1/sentry/projects with X-Org-Id), then add its `dsn` here keyed by the
|
|
103
103
|
* product name the app passes to `createAnalytics`.
|
|
104
104
|
*/
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* project
|
|
105
|
+
/** PRODUCT_PROJECT maps a `product` to its Sentry project id. The DSN's KEY is no
|
|
106
|
+
* longer a per-project secret — it is the ONE org publishable key (below), so a
|
|
107
|
+
* surface's errors ride the SAME key its events do. The id only names WHICH
|
|
108
|
+
* project the errors group under, and cloud auto-provisions that project on first
|
|
109
|
+
* keyed ingest, so a new id needs nothing minted. `site` lives in the `hanzo-ai`
|
|
110
|
+
* project — an explicit map, because the projects predate this and do not derive
|
|
111
|
+
* cleanly from the product name. */
|
|
112
|
+
declare const PRODUCT_PROJECT: Readonly<Record<string, string>>;
|
|
113
|
+
/** dsnForProduct builds the product's Sentry DSN — the ONE org publishable key at
|
|
114
|
+
* its project's envelope endpoint — or undefined when the product has no project
|
|
115
|
+
* yet, which leaves the error plane inert rather than posting into the wrong one.
|
|
116
|
+
* Same key as the event stream: cloud resolves it to the org and attributes the
|
|
117
|
+
* errors there. */
|
|
111
118
|
declare function dsnForProduct(product: string | undefined): string | undefined;
|
|
112
119
|
|
|
113
120
|
/** redactSecrets removes known secret shapes. Always applied. */
|
|
@@ -163,6 +170,59 @@ declare const EVENTS: {
|
|
|
163
170
|
type EventName = (typeof EVENTS)[keyof typeof EVENTS];
|
|
164
171
|
/** The reserved event name a pageview is stored under (server + read lens). */
|
|
165
172
|
declare const PAGEVIEW = "$pageview";
|
|
173
|
+
/** The reserved name every captured exception is emitted under. Error Tracking
|
|
174
|
+
* reads exactly this name; an exception emitted under its own message instead
|
|
175
|
+
* makes every distinct message a permanent entry in the event taxonomy. */
|
|
176
|
+
declare const EXCEPTION = "$exception";
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* digest is a stable 32-hex-char (128-bit) content hash, computed synchronously.
|
|
180
|
+
*
|
|
181
|
+
* Grouping keys are needed on the capture path, which is synchronous and may be
|
|
182
|
+
* running inside an unload handler — SubtleCrypto is async and unavailable on
|
|
183
|
+
* insecure origins, so it cannot be used here. This is FNV-1a run over four seeds
|
|
184
|
+
* and concatenated. It is a GROUPING key, never a security boundary: it is not
|
|
185
|
+
* collision-resistant against a chosen-input adversary, and nothing authorizes or
|
|
186
|
+
* authenticates on it. The product treats the value as opaque.
|
|
187
|
+
*/
|
|
188
|
+
declare function digest(s: string): string;
|
|
189
|
+
/**
|
|
190
|
+
* exceptionEntry builds the single `$exception_list` entry for a throwable.
|
|
191
|
+
*
|
|
192
|
+
* One entry, not a chain: `Error.cause` chaining is a distinct fact with its own
|
|
193
|
+
* ordering rules, and emitting it wrongly is worse than not emitting it.
|
|
194
|
+
*/
|
|
195
|
+
declare function exceptionEntry(err: unknown, opts: {
|
|
196
|
+
handled: boolean;
|
|
197
|
+
id: string;
|
|
198
|
+
}): ExceptionEntry;
|
|
199
|
+
/**
|
|
200
|
+
* fingerprint is the issue grouping key.
|
|
201
|
+
*
|
|
202
|
+
* Keyed on exception type plus each in-app frame's function and source — the same
|
|
203
|
+
* pieces the server-side grouper records ("Exception Type", "Resolved function
|
|
204
|
+
* name", "Source file name"). Deliberately NOT the message: `Loading chunk 3324
|
|
205
|
+
* failed` and `Loading chunk 998 failed` are one bug, and grouping on message is
|
|
206
|
+
* precisely the mistake that made every distinct error string its own event name.
|
|
207
|
+
*
|
|
208
|
+
* Falls back to the type alone when no in-app frame survived, which keeps
|
|
209
|
+
* stackless errors (`Script error.`, cross-origin) in one issue instead of
|
|
210
|
+
* scattering them.
|
|
211
|
+
*/
|
|
212
|
+
declare function fingerprint(entry: ExceptionEntry): string;
|
|
213
|
+
/**
|
|
214
|
+
* exceptionProperties builds the full `$exception_*` property bag for one captured
|
|
215
|
+
* throwable — everything Error Tracking reads off the event.
|
|
216
|
+
*
|
|
217
|
+
* The denormalized arrays are ordered like `frames`: last element is the throw
|
|
218
|
+
* site, which is the element the issue list indexes at -1 for its source/function
|
|
219
|
+
* columns.
|
|
220
|
+
*/
|
|
221
|
+
declare function exceptionProperties(err: unknown, opts: {
|
|
222
|
+
handled: boolean;
|
|
223
|
+
id: string;
|
|
224
|
+
level?: SentryLevel;
|
|
225
|
+
}): ExceptionProperties;
|
|
166
226
|
|
|
167
227
|
/** The emitting surfaces — the closed set of `AnalyticsConfig.product` values.
|
|
168
228
|
* `product` is on every event, so a funnel scopes by product instead of every
|
|
@@ -290,4 +350,4 @@ declare function hasAttribution(a: Attribution): boolean;
|
|
|
290
350
|
/** isoWeek returns the ISO-8601 week label, e.g. "2026-W28". */
|
|
291
351
|
declare function isoWeek(d: Date): string;
|
|
292
352
|
|
|
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,
|
|
353
|
+
export { Attribution, COHORTS, CaptureErrorOptions, Cohort, type CohortDef, Dsn, EVENTS, EXCEPTION, type ErrorIdentity, type EventName, ExceptionEntry, ExceptionProperties, FUNNELS, type FunnelDef, type FunnelId, type FunnelStep, GOALS, type GoalDef, PAGEVIEW, PRODUCTS, PRODUCT_PROJECT, type ProductId, SentryEvent, SentryFrame, SentryLevel, VERSION, buildEnvelope, buildSentryEvent, deriveChannel, digest, dsnForProduct, eventsOf, exceptionEntry, exceptionProperties, fingerprint, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { C as Cohort, A as Attribution, S as SentryEvent, D as Dsn, a as CaptureErrorOptions, b as SentryFrame } from './core-
|
|
2
|
-
export {
|
|
1
|
+
import { C as Cohort, A as Attribution, S as SentryEvent, D as Dsn, a as CaptureErrorOptions, b as SentryFrame, E as ExceptionEntry, c as SentryLevel, d as ExceptionProperties } from './core-CHLpJy51.js';
|
|
2
|
+
export { e as Analytics, f as AnalyticsConfig, g as EventKind, h as Exception, i as ExceptionFrame, T as Transport, W as WireEvent, j as createAnalytics } from './core-CHLpJy51.js';
|
|
3
3
|
|
|
4
4
|
/** Read the persisted first-touch attribution. */
|
|
5
5
|
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.20";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* parseDsn parses "https://<version>:<hmac>@<host>/v1/sentry/<projectId>" into its
|
|
@@ -102,12 +102,19 @@ declare function uuidv7Time(id: string): number;
|
|
|
102
102
|
* (POST /v1/sentry/projects with X-Org-Id), then add its `dsn` here keyed by the
|
|
103
103
|
* product name the app passes to `createAnalytics`.
|
|
104
104
|
*/
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* project
|
|
105
|
+
/** PRODUCT_PROJECT maps a `product` to its Sentry project id. The DSN's KEY is no
|
|
106
|
+
* longer a per-project secret — it is the ONE org publishable key (below), so a
|
|
107
|
+
* surface's errors ride the SAME key its events do. The id only names WHICH
|
|
108
|
+
* project the errors group under, and cloud auto-provisions that project on first
|
|
109
|
+
* keyed ingest, so a new id needs nothing minted. `site` lives in the `hanzo-ai`
|
|
110
|
+
* project — an explicit map, because the projects predate this and do not derive
|
|
111
|
+
* cleanly from the product name. */
|
|
112
|
+
declare const PRODUCT_PROJECT: Readonly<Record<string, string>>;
|
|
113
|
+
/** dsnForProduct builds the product's Sentry DSN — the ONE org publishable key at
|
|
114
|
+
* its project's envelope endpoint — or undefined when the product has no project
|
|
115
|
+
* yet, which leaves the error plane inert rather than posting into the wrong one.
|
|
116
|
+
* Same key as the event stream: cloud resolves it to the org and attributes the
|
|
117
|
+
* errors there. */
|
|
111
118
|
declare function dsnForProduct(product: string | undefined): string | undefined;
|
|
112
119
|
|
|
113
120
|
/** redactSecrets removes known secret shapes. Always applied. */
|
|
@@ -163,6 +170,59 @@ declare const EVENTS: {
|
|
|
163
170
|
type EventName = (typeof EVENTS)[keyof typeof EVENTS];
|
|
164
171
|
/** The reserved event name a pageview is stored under (server + read lens). */
|
|
165
172
|
declare const PAGEVIEW = "$pageview";
|
|
173
|
+
/** The reserved name every captured exception is emitted under. Error Tracking
|
|
174
|
+
* reads exactly this name; an exception emitted under its own message instead
|
|
175
|
+
* makes every distinct message a permanent entry in the event taxonomy. */
|
|
176
|
+
declare const EXCEPTION = "$exception";
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* digest is a stable 32-hex-char (128-bit) content hash, computed synchronously.
|
|
180
|
+
*
|
|
181
|
+
* Grouping keys are needed on the capture path, which is synchronous and may be
|
|
182
|
+
* running inside an unload handler — SubtleCrypto is async and unavailable on
|
|
183
|
+
* insecure origins, so it cannot be used here. This is FNV-1a run over four seeds
|
|
184
|
+
* and concatenated. It is a GROUPING key, never a security boundary: it is not
|
|
185
|
+
* collision-resistant against a chosen-input adversary, and nothing authorizes or
|
|
186
|
+
* authenticates on it. The product treats the value as opaque.
|
|
187
|
+
*/
|
|
188
|
+
declare function digest(s: string): string;
|
|
189
|
+
/**
|
|
190
|
+
* exceptionEntry builds the single `$exception_list` entry for a throwable.
|
|
191
|
+
*
|
|
192
|
+
* One entry, not a chain: `Error.cause` chaining is a distinct fact with its own
|
|
193
|
+
* ordering rules, and emitting it wrongly is worse than not emitting it.
|
|
194
|
+
*/
|
|
195
|
+
declare function exceptionEntry(err: unknown, opts: {
|
|
196
|
+
handled: boolean;
|
|
197
|
+
id: string;
|
|
198
|
+
}): ExceptionEntry;
|
|
199
|
+
/**
|
|
200
|
+
* fingerprint is the issue grouping key.
|
|
201
|
+
*
|
|
202
|
+
* Keyed on exception type plus each in-app frame's function and source — the same
|
|
203
|
+
* pieces the server-side grouper records ("Exception Type", "Resolved function
|
|
204
|
+
* name", "Source file name"). Deliberately NOT the message: `Loading chunk 3324
|
|
205
|
+
* failed` and `Loading chunk 998 failed` are one bug, and grouping on message is
|
|
206
|
+
* precisely the mistake that made every distinct error string its own event name.
|
|
207
|
+
*
|
|
208
|
+
* Falls back to the type alone when no in-app frame survived, which keeps
|
|
209
|
+
* stackless errors (`Script error.`, cross-origin) in one issue instead of
|
|
210
|
+
* scattering them.
|
|
211
|
+
*/
|
|
212
|
+
declare function fingerprint(entry: ExceptionEntry): string;
|
|
213
|
+
/**
|
|
214
|
+
* exceptionProperties builds the full `$exception_*` property bag for one captured
|
|
215
|
+
* throwable — everything Error Tracking reads off the event.
|
|
216
|
+
*
|
|
217
|
+
* The denormalized arrays are ordered like `frames`: last element is the throw
|
|
218
|
+
* site, which is the element the issue list indexes at -1 for its source/function
|
|
219
|
+
* columns.
|
|
220
|
+
*/
|
|
221
|
+
declare function exceptionProperties(err: unknown, opts: {
|
|
222
|
+
handled: boolean;
|
|
223
|
+
id: string;
|
|
224
|
+
level?: SentryLevel;
|
|
225
|
+
}): ExceptionProperties;
|
|
166
226
|
|
|
167
227
|
/** The emitting surfaces — the closed set of `AnalyticsConfig.product` values.
|
|
168
228
|
* `product` is on every event, so a funnel scopes by product instead of every
|
|
@@ -290,4 +350,4 @@ declare function hasAttribution(a: Attribution): boolean;
|
|
|
290
350
|
/** isoWeek returns the ISO-8601 week label, e.g. "2026-W28". */
|
|
291
351
|
declare function isoWeek(d: Date): string;
|
|
292
352
|
|
|
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,
|
|
353
|
+
export { Attribution, COHORTS, CaptureErrorOptions, Cohort, type CohortDef, Dsn, EVENTS, EXCEPTION, type ErrorIdentity, type EventName, ExceptionEntry, ExceptionProperties, FUNNELS, type FunnelDef, type FunnelId, type FunnelStep, GOALS, type GoalDef, PAGEVIEW, PRODUCTS, PRODUCT_PROJECT, type ProductId, SentryEvent, SentryFrame, SentryLevel, VERSION, buildEnvelope, buildSentryEvent, deriveChannel, digest, dsnForProduct, eventsOf, exceptionEntry, exceptionProperties, fingerprint, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
|
package/dist/index.mjs
CHANGED
|
@@ -72,17 +72,19 @@ function isoWeek(d) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// src/dsn.ts
|
|
75
|
-
var
|
|
76
|
-
|
|
77
|
-
console
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
var PRODUCT_PROJECT = Object.freeze({
|
|
76
|
+
console: "019fa40b-94ae-7f1d-8f7b-e92f123fad42",
|
|
77
|
+
// console.hanzo.ai
|
|
78
|
+
app: "019f9b1e-57eb-7171-9d92-72c0b85e4b4b",
|
|
79
|
+
// hanzo.app
|
|
80
|
+
site: "019f9b1e-5785-7359-ad0b-f75db8e58c99"
|
|
81
|
+
// hanzo.ai (marketing; product `site`)
|
|
82
82
|
});
|
|
83
83
|
function dsnForProduct(product) {
|
|
84
84
|
if (!product) return void 0;
|
|
85
|
-
|
|
85
|
+
const projectId = PRODUCT_PROJECT[product];
|
|
86
|
+
if (!projectId) return void 0;
|
|
87
|
+
return `https://${HANZO_PUBLISHABLE_KEY}@api.hanzo.ai/v1/sentry/${projectId}`;
|
|
86
88
|
}
|
|
87
89
|
var HANZO_PUBLISHABLE_KEY = "pk-live-c88649f1085fb6ad441d8a0072933a9b";
|
|
88
90
|
function defaultPublishableKey(host) {
|
|
@@ -140,6 +142,7 @@ var EVENTS = {
|
|
|
140
142
|
DEPLOY_FAILED: "deploy_failed"
|
|
141
143
|
};
|
|
142
144
|
var PAGEVIEW = "$pageview";
|
|
145
|
+
var EXCEPTION = "$exception";
|
|
143
146
|
|
|
144
147
|
// src/scrub.ts
|
|
145
148
|
var REDACTED = "[redacted]";
|
|
@@ -369,7 +372,7 @@ function uuidv7Time(id) {
|
|
|
369
372
|
}
|
|
370
373
|
|
|
371
374
|
// src/version.ts
|
|
372
|
-
var VERSION = "0.3.
|
|
375
|
+
var VERSION = "0.3.20";
|
|
373
376
|
|
|
374
377
|
// src/sentry.ts
|
|
375
378
|
var MAX_FRAMES = 50;
|
|
@@ -561,6 +564,94 @@ ${itemHeader}
|
|
|
561
564
|
${payload}
|
|
562
565
|
`;
|
|
563
566
|
}
|
|
567
|
+
var MAX_VALUE = 4096;
|
|
568
|
+
function digest(s2) {
|
|
569
|
+
let out = "";
|
|
570
|
+
for (const seed of [2166136261, 16777619, 2654435769, 2246822507]) {
|
|
571
|
+
let h = seed >>> 0;
|
|
572
|
+
for (let i = 0; i < s2.length; i++) {
|
|
573
|
+
h ^= s2.charCodeAt(i);
|
|
574
|
+
h = h + (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24) >>> 0;
|
|
575
|
+
}
|
|
576
|
+
out += h.toString(16).padStart(8, "0");
|
|
577
|
+
}
|
|
578
|
+
return out;
|
|
579
|
+
}
|
|
580
|
+
function frameOf(f) {
|
|
581
|
+
const source = f.filename ?? "";
|
|
582
|
+
const name = f.function ?? "<anonymous>";
|
|
583
|
+
const line = f.lineno ?? 0;
|
|
584
|
+
const column = f.colno ?? 0;
|
|
585
|
+
return {
|
|
586
|
+
// Stable per code location, so the same frame groups and re-renders under one
|
|
587
|
+
// key. The '/part' suffix is the product's format for one raw frame expanding
|
|
588
|
+
// into several resolved ones; a browser frame is always part 0.
|
|
589
|
+
raw_id: `${digest(`${source}|${name}|${line}|${column}`)}/0`,
|
|
590
|
+
mangled_name: name,
|
|
591
|
+
source,
|
|
592
|
+
line,
|
|
593
|
+
column,
|
|
594
|
+
in_app: f.in_app ?? false,
|
|
595
|
+
lang: "javascript",
|
|
596
|
+
resolved: false,
|
|
597
|
+
resolve_failure: "no symbol set uploaded for this release",
|
|
598
|
+
resolved_name: null,
|
|
599
|
+
module: null
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function truncate2(s2, max) {
|
|
603
|
+
if (s2.length <= max) return s2;
|
|
604
|
+
let end = max;
|
|
605
|
+
const c = s2.charCodeAt(end - 1);
|
|
606
|
+
if (c >= 55296 && c <= 56319) end--;
|
|
607
|
+
return s2.slice(0, end);
|
|
608
|
+
}
|
|
609
|
+
function exceptionEntry(err, opts) {
|
|
610
|
+
const n = normalizeError(err);
|
|
611
|
+
const frames = framesFromStack(n.stack).slice(-50);
|
|
612
|
+
const entry = {
|
|
613
|
+
id: opts.id,
|
|
614
|
+
type: n.name,
|
|
615
|
+
value: truncate2(n.message, MAX_VALUE),
|
|
616
|
+
mechanism: {
|
|
617
|
+
type: "generic",
|
|
618
|
+
handled: opts.handled,
|
|
619
|
+
// An exception the app reported by hand was constructed, not thrown by the
|
|
620
|
+
// runtime at a real call site.
|
|
621
|
+
synthetic: !(err instanceof Error)
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
if (frames.length > 0) {
|
|
625
|
+
entry.stacktrace = { type: "resolved", frames: frames.map(frameOf) };
|
|
626
|
+
}
|
|
627
|
+
return entry;
|
|
628
|
+
}
|
|
629
|
+
function fingerprint(entry) {
|
|
630
|
+
const frames = entry.stacktrace?.frames ?? [];
|
|
631
|
+
const pieces = frames.filter((f) => f.in_app).map((f) => `${f.mangled_name}@${f.source}`);
|
|
632
|
+
return digest([entry.type, ...pieces].join("\n"));
|
|
633
|
+
}
|
|
634
|
+
function exceptionProperties(err, opts) {
|
|
635
|
+
const entry = exceptionEntry(err, opts);
|
|
636
|
+
const frames = entry.stacktrace?.frames ?? [];
|
|
637
|
+
const fp = fingerprint(entry);
|
|
638
|
+
return {
|
|
639
|
+
$exception_list: [entry],
|
|
640
|
+
$exception_fingerprint: fp,
|
|
641
|
+
// Records WHY this fingerprint holds. 'manual' is the honest value: the client
|
|
642
|
+
// supplied the key rather than a server grouper deriving one.
|
|
643
|
+
$exception_fingerprint_record: [{ type: "manual" }],
|
|
644
|
+
$exception_type: entry.type,
|
|
645
|
+
$exception_message: entry.value,
|
|
646
|
+
$exception_level: opts.level ?? "error",
|
|
647
|
+
$exception_handled: opts.handled,
|
|
648
|
+
$exception_synthetic: entry.mechanism?.synthetic ?? false,
|
|
649
|
+
$exception_types: [entry.type],
|
|
650
|
+
$exception_values: [entry.value],
|
|
651
|
+
$exception_sources: frames.map((f) => f.source).filter((s2) => !!s2),
|
|
652
|
+
$exception_functions: frames.map((f) => f.resolved_name ?? f.mangled_name).filter((s2) => !!s2)
|
|
653
|
+
};
|
|
654
|
+
}
|
|
564
655
|
|
|
565
656
|
// src/storage.ts
|
|
566
657
|
var KEY = {
|
|
@@ -837,9 +928,20 @@ var Analytics = class {
|
|
|
837
928
|
} catch {
|
|
838
929
|
}
|
|
839
930
|
try {
|
|
931
|
+
const handled = context?.handled ?? true;
|
|
840
932
|
const ex = normalizeError2(err);
|
|
841
|
-
ex.handled =
|
|
842
|
-
this.enqueue("
|
|
933
|
+
ex.handled = handled;
|
|
934
|
+
this.enqueue("event", EXCEPTION, {
|
|
935
|
+
error: ex,
|
|
936
|
+
properties: {
|
|
937
|
+
...context?.properties,
|
|
938
|
+
...exceptionProperties(err, {
|
|
939
|
+
handled,
|
|
940
|
+
id: hzUuidv7(),
|
|
941
|
+
level: context?.level
|
|
942
|
+
})
|
|
943
|
+
}
|
|
944
|
+
});
|
|
843
945
|
this.flush();
|
|
844
946
|
} catch {
|
|
845
947
|
}
|
|
@@ -1146,6 +1248,6 @@ var COHORTS = {
|
|
|
1146
1248
|
* reformat of one copy is a diff against the other.
|
|
1147
1249
|
*/
|
|
1148
1250
|
|
|
1149
|
-
export { Analytics, COHORTS, EVENTS, FUNNELS, GOALS, PAGEVIEW, PRODUCTS,
|
|
1251
|
+
export { Analytics, COHORTS, EVENTS, EXCEPTION, FUNNELS, GOALS, PAGEVIEW, PRODUCTS, PRODUCT_PROJECT, VERSION, buildEnvelope, buildSentryEvent, createAnalytics, deriveChannel, digest, dsnForProduct, eventsOf, exceptionEntry, exceptionProperties, fingerprint, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
|
|
1150
1252
|
//# sourceMappingURL=index.mjs.map
|
|
1151
1253
|
//# sourceMappingURL=index.mjs.map
|