@@ -4,14 +4,14 @@ import type {
4
4
ClientOptions ,
5
5
Event ,
6
6
EventHint ,
7
+ Scope as ScopeInterface ,
7
8
ScopeContext ,
8
9
StackFrame ,
9
10
StackParser ,
10
11
} from '@sentry/types' ;
11
12
import {
12
13
addExceptionMechanism ,
13
14
dateTimestampInSeconds ,
14
- dropUndefinedKeys ,
15
15
GLOBAL_OBJ ,
16
16
normalize ,
17
17
resolvedSyncPromise ,
@@ -23,6 +23,15 @@ import { DEFAULT_ENVIRONMENT } from '../constants';
23
23
import { getGlobalEventProcessors , notifyEventProcessors } from '../eventProcessors' ;
24
24
import { Scope } from '../scope' ;
25
25
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
+
26
35
/**
27
36
* Adds common information to events.
28
37
*
@@ -336,7 +345,9 @@ function normalizeEvent(event: Event | null, depth: number, maxBreadth: number):
336
345
* Parse either an `EventHint` directly, or convert a `CaptureContext` to an `EventHint`.
337
346
* This is used to allow to update method signatures that used to accept a `CaptureContext` but should now accept an `EventHint`.
338
347
*/
339
- export function parseEventHintOrCaptureContext ( hint : CaptureContext | EventHint | undefined ) : EventHint | undefined {
348
+ export function parseEventHintOrCaptureContext (
349
+ hint : ExclusiveEventHintOrCaptureContext | undefined ,
350
+ ) : EventHint | undefined {
340
351
if ( ! hint ) {
341
352
return undefined ;
342
353
}
@@ -346,24 +357,33 @@ export function parseEventHintOrCaptureContext(hint: CaptureContext | EventHint
346
357
return { captureContext : hint } ;
347
358
}
348
359
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
+ } ;
362
364
}
363
365
364
- return eventHint ;
366
+ return hint ;
365
367
}
366
368
367
- function hintIsScopeOrFunction ( hint : CaptureContext | EventHint ) : hint is Scope | ( ( ) => Scope ) {
369
+ function hintIsScopeOrFunction (
370
+ hint : CaptureContext | EventHint ,
371
+ ) : hint is ScopeInterface | ( ( scope : ScopeInterface ) => ScopeInterface ) {
368
372
return hint instanceof Scope || typeof hint === 'function' ;
369
373
}
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