@hanzo/event 0.3.19 → 0.3.21

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/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-D4PaPlOB.cjs';
2
- export { c as Analytics, d as AnalyticsConfig, E as EventKind, e as Exception, f as SentryLevel, T as Transport, W as WireEvent, g as createAnalytics } from './core-D4PaPlOB.cjs';
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.19";
9
+ declare const VERSION = "0.3.21";
10
10
 
11
11
  /**
12
12
  * parseDsn parses "https://<version>:<hmac>@<host>/v1/sentry/<projectId>" into its
@@ -110,12 +110,15 @@ declare function uuidv7Time(id: string): number;
110
110
  * project — an explicit map, because the projects predate this and do not derive
111
111
  * cleanly from the product name. */
112
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. */
118
- declare function dsnForProduct(product: string | undefined): string | undefined;
113
+ /** dsnForProduct builds the product's Sentry DSN from the caller's resolved
114
+ * publishable `key` and the product's projectthe SAME key the event stream
115
+ * carries, at the product's envelope endpoint. Returns undefined when there is no
116
+ * key or no project for the product, leaving the error plane inert rather than
117
+ * posting into the wrong one. The key is NOT baked here: it is the value the
118
+ * surface resolved (an explicit `ingestKey`, or the KMS-sourced
119
+ * NEXT_PUBLIC_PUBLISHABLE_KEY the build inlines) — the ONE live source, never a
120
+ * literal committed beside the code. */
121
+ declare function dsnForProduct(product: string | undefined, key: string | undefined): string | undefined;
119
122
 
120
123
  /** redactSecrets removes known secret shapes. Always applied. */
121
124
  declare function redactSecrets(s: string): string;
@@ -170,6 +173,59 @@ declare const EVENTS: {
170
173
  type EventName = (typeof EVENTS)[keyof typeof EVENTS];
171
174
  /** The reserved event name a pageview is stored under (server + read lens). */
172
175
  declare const PAGEVIEW = "$pageview";
176
+ /** The reserved name every captured exception is emitted under. Error Tracking
177
+ * reads exactly this name; an exception emitted under its own message instead
178
+ * makes every distinct message a permanent entry in the event taxonomy. */
179
+ declare const EXCEPTION = "$exception";
180
+
181
+ /**
182
+ * digest is a stable 32-hex-char (128-bit) content hash, computed synchronously.
183
+ *
184
+ * Grouping keys are needed on the capture path, which is synchronous and may be
185
+ * running inside an unload handler — SubtleCrypto is async and unavailable on
186
+ * insecure origins, so it cannot be used here. This is FNV-1a run over four seeds
187
+ * and concatenated. It is a GROUPING key, never a security boundary: it is not
188
+ * collision-resistant against a chosen-input adversary, and nothing authorizes or
189
+ * authenticates on it. The product treats the value as opaque.
190
+ */
191
+ declare function digest(s: string): string;
192
+ /**
193
+ * exceptionEntry builds the single `$exception_list` entry for a throwable.
194
+ *
195
+ * One entry, not a chain: `Error.cause` chaining is a distinct fact with its own
196
+ * ordering rules, and emitting it wrongly is worse than not emitting it.
197
+ */
198
+ declare function exceptionEntry(err: unknown, opts: {
199
+ handled: boolean;
200
+ id: string;
201
+ }): ExceptionEntry;
202
+ /**
203
+ * fingerprint is the issue grouping key.
204
+ *
205
+ * Keyed on exception type plus each in-app frame's function and source — the same
206
+ * pieces the server-side grouper records ("Exception Type", "Resolved function
207
+ * name", "Source file name"). Deliberately NOT the message: `Loading chunk 3324
208
+ * failed` and `Loading chunk 998 failed` are one bug, and grouping on message is
209
+ * precisely the mistake that made every distinct error string its own event name.
210
+ *
211
+ * Falls back to the type alone when no in-app frame survived, which keeps
212
+ * stackless errors (`Script error.`, cross-origin) in one issue instead of
213
+ * scattering them.
214
+ */
215
+ declare function fingerprint(entry: ExceptionEntry): string;
216
+ /**
217
+ * exceptionProperties builds the full `$exception_*` property bag for one captured
218
+ * throwable — everything Error Tracking reads off the event.
219
+ *
220
+ * The denormalized arrays are ordered like `frames`: last element is the throw
221
+ * site, which is the element the issue list indexes at -1 for its source/function
222
+ * columns.
223
+ */
224
+ declare function exceptionProperties(err: unknown, opts: {
225
+ handled: boolean;
226
+ id: string;
227
+ level?: SentryLevel;
228
+ }): ExceptionProperties;
173
229
 
174
230
  /** The emitting surfaces — the closed set of `AnalyticsConfig.product` values.
175
231
  * `product` is on every event, so a funnel scopes by product instead of every
@@ -297,4 +353,4 @@ declare function hasAttribution(a: Attribution): boolean;
297
353
  /** isoWeek returns the ISO-8601 week label, e.g. "2026-W28". */
298
354
  declare function isoWeek(d: Date): string;
299
355
 
300
- 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, PRODUCT_PROJECT, type ProductId, SentryEvent, SentryFrame, VERSION, buildEnvelope, buildSentryEvent, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
356
+ 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-D4PaPlOB.js';
2
- export { c as Analytics, d as AnalyticsConfig, E as EventKind, e as Exception, f as SentryLevel, T as Transport, W as WireEvent, g as createAnalytics } from './core-D4PaPlOB.js';
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.19";
9
+ declare const VERSION = "0.3.21";
10
10
 
11
11
  /**
12
12
  * parseDsn parses "https://<version>:<hmac>@<host>/v1/sentry/<projectId>" into its
@@ -110,12 +110,15 @@ declare function uuidv7Time(id: string): number;
110
110
  * project — an explicit map, because the projects predate this and do not derive
111
111
  * cleanly from the product name. */
112
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. */
118
- declare function dsnForProduct(product: string | undefined): string | undefined;
113
+ /** dsnForProduct builds the product's Sentry DSN from the caller's resolved
114
+ * publishable `key` and the product's projectthe SAME key the event stream
115
+ * carries, at the product's envelope endpoint. Returns undefined when there is no
116
+ * key or no project for the product, leaving the error plane inert rather than
117
+ * posting into the wrong one. The key is NOT baked here: it is the value the
118
+ * surface resolved (an explicit `ingestKey`, or the KMS-sourced
119
+ * NEXT_PUBLIC_PUBLISHABLE_KEY the build inlines) — the ONE live source, never a
120
+ * literal committed beside the code. */
121
+ declare function dsnForProduct(product: string | undefined, key: string | undefined): string | undefined;
119
122
 
120
123
  /** redactSecrets removes known secret shapes. Always applied. */
121
124
  declare function redactSecrets(s: string): string;
@@ -170,6 +173,59 @@ declare const EVENTS: {
170
173
  type EventName = (typeof EVENTS)[keyof typeof EVENTS];
171
174
  /** The reserved event name a pageview is stored under (server + read lens). */
172
175
  declare const PAGEVIEW = "$pageview";
176
+ /** The reserved name every captured exception is emitted under. Error Tracking
177
+ * reads exactly this name; an exception emitted under its own message instead
178
+ * makes every distinct message a permanent entry in the event taxonomy. */
179
+ declare const EXCEPTION = "$exception";
180
+
181
+ /**
182
+ * digest is a stable 32-hex-char (128-bit) content hash, computed synchronously.
183
+ *
184
+ * Grouping keys are needed on the capture path, which is synchronous and may be
185
+ * running inside an unload handler — SubtleCrypto is async and unavailable on
186
+ * insecure origins, so it cannot be used here. This is FNV-1a run over four seeds
187
+ * and concatenated. It is a GROUPING key, never a security boundary: it is not
188
+ * collision-resistant against a chosen-input adversary, and nothing authorizes or
189
+ * authenticates on it. The product treats the value as opaque.
190
+ */
191
+ declare function digest(s: string): string;
192
+ /**
193
+ * exceptionEntry builds the single `$exception_list` entry for a throwable.
194
+ *
195
+ * One entry, not a chain: `Error.cause` chaining is a distinct fact with its own
196
+ * ordering rules, and emitting it wrongly is worse than not emitting it.
197
+ */
198
+ declare function exceptionEntry(err: unknown, opts: {
199
+ handled: boolean;
200
+ id: string;
201
+ }): ExceptionEntry;
202
+ /**
203
+ * fingerprint is the issue grouping key.
204
+ *
205
+ * Keyed on exception type plus each in-app frame's function and source — the same
206
+ * pieces the server-side grouper records ("Exception Type", "Resolved function
207
+ * name", "Source file name"). Deliberately NOT the message: `Loading chunk 3324
208
+ * failed` and `Loading chunk 998 failed` are one bug, and grouping on message is
209
+ * precisely the mistake that made every distinct error string its own event name.
210
+ *
211
+ * Falls back to the type alone when no in-app frame survived, which keeps
212
+ * stackless errors (`Script error.`, cross-origin) in one issue instead of
213
+ * scattering them.
214
+ */
215
+ declare function fingerprint(entry: ExceptionEntry): string;
216
+ /**
217
+ * exceptionProperties builds the full `$exception_*` property bag for one captured
218
+ * throwable — everything Error Tracking reads off the event.
219
+ *
220
+ * The denormalized arrays are ordered like `frames`: last element is the throw
221
+ * site, which is the element the issue list indexes at -1 for its source/function
222
+ * columns.
223
+ */
224
+ declare function exceptionProperties(err: unknown, opts: {
225
+ handled: boolean;
226
+ id: string;
227
+ level?: SentryLevel;
228
+ }): ExceptionProperties;
173
229
 
174
230
  /** The emitting surfaces — the closed set of `AnalyticsConfig.product` values.
175
231
  * `product` is on every event, so a funnel scopes by product instead of every
@@ -297,4 +353,4 @@ declare function hasAttribution(a: Attribution): boolean;
297
353
  /** isoWeek returns the ISO-8601 week label, e.g. "2026-W28". */
298
354
  declare function isoWeek(d: Date): string;
299
355
 
300
- 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, PRODUCT_PROJECT, type ProductId, SentryEvent, SentryFrame, VERSION, buildEnvelope, buildSentryEvent, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
356
+ 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
@@ -80,15 +80,11 @@ var PRODUCT_PROJECT = Object.freeze({
80
80
  site: "019f9b1e-5785-7359-ad0b-f75db8e58c99"
81
81
  // hanzo.ai (marketing; product `site`)
82
82
  });
83
- function dsnForProduct(product) {
84
- if (!product) return void 0;
83
+ function dsnForProduct(product, key) {
84
+ if (!product || !key) return void 0;
85
85
  const projectId = PRODUCT_PROJECT[product];
86
86
  if (!projectId) return void 0;
87
- return `https://${HANZO_PUBLISHABLE_KEY}@api.hanzo.ai/v1/sentry/${projectId}`;
88
- }
89
- var HANZO_PUBLISHABLE_KEY = "pk-live-c88649f1085fb6ad441d8a0072933a9b";
90
- function defaultPublishableKey(host) {
91
- return host === void 0 || host === "https://api.hanzo.ai" ? HANZO_PUBLISHABLE_KEY : void 0;
87
+ return `https://${key}@api.hanzo.ai/v1/sentry/${projectId}`;
92
88
  }
93
89
 
94
90
  // src/events.ts
@@ -142,6 +138,7 @@ var EVENTS = {
142
138
  DEPLOY_FAILED: "deploy_failed"
143
139
  };
144
140
  var PAGEVIEW = "$pageview";
141
+ var EXCEPTION = "$exception";
145
142
 
146
143
  // src/scrub.ts
147
144
  var REDACTED = "[redacted]";
@@ -371,7 +368,7 @@ function uuidv7Time(id) {
371
368
  }
372
369
 
373
370
  // src/version.ts
374
- var VERSION = "0.3.19";
371
+ var VERSION = "0.3.21";
375
372
 
376
373
  // src/sentry.ts
377
374
  var MAX_FRAMES = 50;
@@ -563,6 +560,94 @@ ${itemHeader}
563
560
  ${payload}
564
561
  `;
565
562
  }
563
+ var MAX_VALUE = 4096;
564
+ function digest(s2) {
565
+ let out = "";
566
+ for (const seed of [2166136261, 16777619, 2654435769, 2246822507]) {
567
+ let h = seed >>> 0;
568
+ for (let i = 0; i < s2.length; i++) {
569
+ h ^= s2.charCodeAt(i);
570
+ h = h + (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24) >>> 0;
571
+ }
572
+ out += h.toString(16).padStart(8, "0");
573
+ }
574
+ return out;
575
+ }
576
+ function frameOf(f) {
577
+ const source = f.filename ?? "";
578
+ const name = f.function ?? "<anonymous>";
579
+ const line = f.lineno ?? 0;
580
+ const column = f.colno ?? 0;
581
+ return {
582
+ // Stable per code location, so the same frame groups and re-renders under one
583
+ // key. The '/part' suffix is the product's format for one raw frame expanding
584
+ // into several resolved ones; a browser frame is always part 0.
585
+ raw_id: `${digest(`${source}|${name}|${line}|${column}`)}/0`,
586
+ mangled_name: name,
587
+ source,
588
+ line,
589
+ column,
590
+ in_app: f.in_app ?? false,
591
+ lang: "javascript",
592
+ resolved: false,
593
+ resolve_failure: "no symbol set uploaded for this release",
594
+ resolved_name: null,
595
+ module: null
596
+ };
597
+ }
598
+ function truncate2(s2, max) {
599
+ if (s2.length <= max) return s2;
600
+ let end = max;
601
+ const c = s2.charCodeAt(end - 1);
602
+ if (c >= 55296 && c <= 56319) end--;
603
+ return s2.slice(0, end);
604
+ }
605
+ function exceptionEntry(err, opts) {
606
+ const n = normalizeError(err);
607
+ const frames = framesFromStack(n.stack).slice(-50);
608
+ const entry = {
609
+ id: opts.id,
610
+ type: n.name,
611
+ value: truncate2(n.message, MAX_VALUE),
612
+ mechanism: {
613
+ type: "generic",
614
+ handled: opts.handled,
615
+ // An exception the app reported by hand was constructed, not thrown by the
616
+ // runtime at a real call site.
617
+ synthetic: !(err instanceof Error)
618
+ }
619
+ };
620
+ if (frames.length > 0) {
621
+ entry.stacktrace = { type: "resolved", frames: frames.map(frameOf) };
622
+ }
623
+ return entry;
624
+ }
625
+ function fingerprint(entry) {
626
+ const frames = entry.stacktrace?.frames ?? [];
627
+ const pieces = frames.filter((f) => f.in_app).map((f) => `${f.mangled_name}@${f.source}`);
628
+ return digest([entry.type, ...pieces].join("\n"));
629
+ }
630
+ function exceptionProperties(err, opts) {
631
+ const entry = exceptionEntry(err, opts);
632
+ const frames = entry.stacktrace?.frames ?? [];
633
+ const fp = fingerprint(entry);
634
+ return {
635
+ $exception_list: [entry],
636
+ $exception_fingerprint: fp,
637
+ // Records WHY this fingerprint holds. 'manual' is the honest value: the client
638
+ // supplied the key rather than a server grouper deriving one.
639
+ $exception_fingerprint_record: [{ type: "manual" }],
640
+ $exception_type: entry.type,
641
+ $exception_message: entry.value,
642
+ $exception_level: opts.level ?? "error",
643
+ $exception_handled: opts.handled,
644
+ $exception_synthetic: entry.mechanism?.synthetic ?? false,
645
+ $exception_types: [entry.type],
646
+ $exception_values: [entry.value],
647
+ $exception_sources: frames.map((f) => f.source).filter((s2) => !!s2),
648
+ $exception_functions: frames.map((f) => f.resolved_name ?? f.mangled_name).filter((s2) => !!s2)
649
+ };
650
+ }
566
651
 
567
652
  // src/storage.ts
568
653
  var KEY = {
@@ -734,27 +819,24 @@ var Analytics = class {
734
819
  enabled: true,
735
820
  captureErrors: true,
736
821
  ...config,
737
- // The publishable key resolves the SAME way the DSN below does, and now
738
- // ends the SAME way too — in a baked default, so declaring nothing is
739
- // enough. Most specific first:
822
+ // The publishable key resolves from ONE live source, never a literal baked
823
+ // beside the code. Most specific first:
740
824
  // 1. an explicit `ingestKey` in config;
741
825
  // 2. NEXT_PUBLIC_PUBLISHABLE_KEY, the inlined build-time env the fleet
742
- // carries end to end (KMS `deploy/PUBLISHABLE_KEY` -> the PUBLISHABLE_KEY
743
- // build-arg -> the NEXT_PUBLIC_ prefix Next inlines);
744
- // 3. the hanzo org key baked in `dsn.ts`, on the hanzo cloud only.
826
+ // carries end to end KMS `deploy/PUBLISHABLE_KEY` -> the PUBLISHABLE_KEY
827
+ // build-arg -> the NEXT_PUBLIC_ prefix Next inlines.
745
828
  //
746
- // (3) is why this is `publishable_key for all`: a hanzo surface that passes
747
- // no key in code and inlines no env still emits attributed, exactly as
748
- // declaring `product` is enough for the DSN. Without it that surface sent
749
- // its beacons to `$public` which drops every track/identify/group and
750
- // still answers 200 silent in the page and invisible until you read the
751
- // warehouse and find the host missing entirely. A white-label surface on
752
- // its own cloud (a non-default host) gets no default, so the org this
753
- // attributes to is never the wrong one.
754
- ingestKey: config.ingestKey ?? readEnv("NEXT_PUBLIC_PUBLISHABLE_KEY") ?? defaultPublishableKey(config.host ?? DEFAULT_HOST)
829
+ // A surface that provides neither has no key, and its anonymous traffic
830
+ // files under `$public` (which drops track/identify/group and answers 200);
831
+ // the fix is to give it the KMS-sourced env, not to hardcode the org key
832
+ // here. The key is a credential-class value: its home is KMS, and the ONE
833
+ // build reads it from there.
834
+ ingestKey: config.ingestKey ?? readEnv("NEXT_PUBLIC_PUBLISHABLE_KEY")
755
835
  };
756
836
  this.transport = config.transport ?? new DefaultTransport();
757
- this.dsn = parseDsn(config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product));
837
+ this.dsn = parseDsn(
838
+ config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product, this.cfg.ingestKey)
839
+ );
758
840
  }
759
841
  /** errorPlaneEnabled reports whether captured exceptions can actually reach the
760
842
  * error host. False means a DSN was never configured — the documented
@@ -839,9 +921,20 @@ var Analytics = class {
839
921
  } catch {
840
922
  }
841
923
  try {
924
+ const handled = context?.handled ?? true;
842
925
  const ex = normalizeError2(err);
843
- ex.handled = context?.handled ?? true;
844
- this.enqueue("error", ex.message, { error: ex, properties: context?.properties });
926
+ ex.handled = handled;
927
+ this.enqueue("event", EXCEPTION, {
928
+ error: ex,
929
+ properties: {
930
+ ...context?.properties,
931
+ ...exceptionProperties(err, {
932
+ handled,
933
+ id: hzUuidv7(),
934
+ level: context?.level
935
+ })
936
+ }
937
+ });
845
938
  this.flush();
846
939
  } catch {
847
940
  }
@@ -1148,6 +1241,6 @@ var COHORTS = {
1148
1241
  * reformat of one copy is a diff against the other.
1149
1242
  */
1150
1243
 
1151
- export { Analytics, COHORTS, EVENTS, FUNNELS, GOALS, PAGEVIEW, PRODUCTS, PRODUCT_PROJECT, VERSION, buildEnvelope, buildSentryEvent, createAnalytics, deriveChannel, dsnForProduct, eventsOf, framesFromStack, getCohort, getFirstTouch, hasAttribution, hostOf, isoWeek, parseAttribution, parseDsn, redactSecrets, scrubPII, scrubText, hzUuidv7 as uuidv7, uuidv7Time };
1244
+ 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 };
1152
1245
  //# sourceMappingURL=index.mjs.map
1153
1246
  //# sourceMappingURL=index.mjs.map