@@ -4,14 +4,14 @@ import type {
44 ClientOptions ,
55 Event ,
66 EventHint ,
7+ Scope as ScopeInterface ,
78 ScopeContext ,
89 StackFrame ,
910 StackParser ,
1011} from '@sentry/types' ;
1112import {
1213 addExceptionMechanism ,
1314 dateTimestampInSeconds ,
14- dropUndefinedKeys ,
1515 GLOBAL_OBJ ,
1616 normalize ,
1717 resolvedSyncPromise ,
@@ -23,6 +23,15 @@ import { DEFAULT_ENVIRONMENT } from '../constants';
2323import { getGlobalEventProcessors , notifyEventProcessors } from '../eventProcessors' ;
2424import { Scope } from '../scope' ;
2525
26+ /**
27+ * This type makes sure that we get either a CaptureContext, OR an EventHint.
28+ * It does not allow mixing them, which could lead to unexpected outcomes, e.g. this is disallowed:
29+ * { user: { id: '123' }, mechanism: { handled: false } }
30+ */
31+ export type ExclusiveEventHintOrCaptureContext =
32+ | ( CaptureContext & Partial < { [ key in keyof EventHint ] : never } > )
33+ | ( EventHint & Partial < { [ key in keyof ScopeContext ] : never } > ) ;
34+
2635/**
2736 * Adds common information to events.
2837 *
@@ -336,7 +345,9 @@ function normalizeEvent(event: Event | null, depth: number, maxBreadth: number):
336345 * Parse either an `EventHint` directly, or convert a `CaptureContext` to an `EventHint`.
337346 * This is used to allow to update method signatures that used to accept a `CaptureContext` but should now accept an `EventHint`.
338347 */
339- export function parseEventHintOrCaptureContext ( hint : CaptureContext | EventHint | undefined ) : EventHint | undefined {
348+ export function parseEventHintOrCaptureContext (
349+ hint : ExclusiveEventHintOrCaptureContext | undefined ,
350+ ) : EventHint | undefined {
340351 if ( ! hint ) {
341352 return undefined ;
342353 }
@@ -346,24 +357,33 @@ export function parseEventHintOrCaptureContext(hint: CaptureContext | EventHint
346357 return { captureContext : hint } ;
347358 }
348359
349- const hintOrScopeContext = hint as Partial < ScopeContext > & Partial < EventHint > ;
350-
351- // Else, we need to make sure to pick the legacy CaptureContext fields off & merge them into the hint
352- const { user, level, extra, contexts, tags, fingerprint, requestSession, propagationContext, ...eventHint } =
353- hintOrScopeContext ;
354-
355- const captureContext = {
356- ...dropUndefinedKeys ( { user, level, extra, contexts, tags, fingerprint, requestSession, propagationContext } ) ,
357- ...hintOrScopeContext . captureContext ,
358- } ;
359-
360- if ( Object . keys ( captureContext ) . length ) {
361- eventHint . captureContext = captureContext ;
360+ if ( hintIsScopeContext ( hint ) ) {
361+ return {
362+ captureContext : hint ,
363+ } ;
362364 }
363365
364- return eventHint ;
366+ return hint ;
365367}
366368
367- function hintIsScopeOrFunction ( hint : CaptureContext | EventHint ) : hint is Scope | ( ( ) => Scope ) {
369+ function hintIsScopeOrFunction (
370+ hint : CaptureContext | EventHint ,
371+ ) : hint is ScopeInterface | ( ( scope : ScopeInterface ) => ScopeInterface ) {
368372 return hint instanceof Scope || typeof hint === 'function' ;
369373}
374+
375+ type ScopeContextProperty = keyof ScopeContext ;
376+ const captureContextKeys : readonly ScopeContextProperty [ ] = [
377+ 'user' ,
378+ 'level' ,
379+ 'extra' ,
380+ 'contexts' ,
381+ 'tags' ,
382+ 'fingerprint' ,
383+ 'requestSession' ,
384+ 'propagationContext' ,
385+ ] as const ;
386+
387+ function hintIsScopeContext ( hint : Partial < ScopeContext > | EventHint ) : hint is Partial < ScopeContext > {
388+ return Object . keys ( hint ) . some ( key => captureContextKeys . includes ( key as ScopeContextProperty ) ) ;
389+ }
0 commit comments