import { ExecutionContext , Injectable , NestInterceptor , CallHandler , } from '@nestjs/common' ; import { IRavenInterceptorOptions , IRavenScopeTransformerFunction , } from './raven.interfaces' ; import { Observable } from 'rxjs' ; import { tap } from 'rxjs/operators' ; import * as Sentry from '@sentry/minimal' ; import { Scope } from '@sentry/hub' ; import { RpcArgumentsHost , WsArgumentsHost , HttpArgumentsHost , } from '@nestjs/common/interfaces' ; import { Handlers } from '@sentry/node' ; import type { GraphQLArgumentsHost , GqlContextType } from '@nestjs/graphql' ; import { Reflector } from '@nestjs/core' ; import { RAVEN_LOCAL_TRANSFORMERS_METADATA } from './raven.decorators' ; let GqlArgumentsHost ; try { ( { GqlArgumentsHost } = require ( '@nestjs/graphql' ) ) ; } catch ( e ) { } @ Injectable ( ) export class RavenInterceptor implements NestInterceptor { constructor ( private readonly options = { } , private readonly reflector = new Reflector ( ) ) { } intercept ( context , next ) { const localTransformers = this . reflector . get < IRavenScopeTransformerFunction [ ] > ( RAVEN_LOCAL_TRANSFORMERS_METADATA , context . getHandler ( ) ) ; return next . handle ( ) . pipe ( tap ( { error : ( exception ) => { if ( this . shouldReport ( exception ) ) { Sentry . withScope ( ( scope ) => { switch ( context . getType < GqlContextType > ( ) ) { case 'http' : this . addHttpExceptionMetadatas ( scope , context . switchToHttp ( ) ) ; return this . captureException ( scope , exception , localTransformers ) ; case 'ws' : this . addWsExceptionMetadatas ( scope , context . switchToWs ( ) ) ; return this . captureException ( scope , exception , localTransformers ) ; case 'rpc' : this . addRpcExceptionMetadatas ( scope , context . switchToRpc ( ) ) ; return this . captureException ( scope , exception , localTransformers ) ; case 'graphql' : if ( ! GqlArgumentsHost ) return this . captureException ( scope , exception , localTransformers ) ; this . addGraphQLExceptionMetadatas ( scope , GqlArgumentsHost . create ( context ) ) ; return this . captureException ( scope , exception , localTransformers ) ; default : return this . captureException ( scope , exception , localTransformers ) ; } } ) ; } } , } ) ) ; } private addGraphQLExceptionMetadatas ( scope , gqlHost ) { const context = gqlHost . getContext ( ) ; const data = Handlers . parseRequest ( { } , context ?. req || context , this . options ) ; scope . setExtra ( 'req' , data . request ) ; data . extra && scope . setExtras ( data . extra ) ; if ( data . user ) scope . setUser ( data . user ) ; const info = gqlHost . getInfo ( ) ; scope . setExtra ( 'fieldName' , info . fieldName ) ; const args = gqlHost . getArgs ( ) ; scope . setExtra ( 'args' , args ) ; } private addHttpExceptionMetadatas ( scope , http ) { const data = Handlers . parseRequest ( < any > { } , http . getRequest ( ) , this . options ) ; scope . setExtra ( 'req' , data . request ) ; data . extra && scope . setExtras ( data . extra ) ; if ( data . user ) scope . setUser ( data . user ) ; } private addRpcExceptionMetadatas ( scope , rpc ) { scope . setExtra ( 'rpc_data' , rpc . getData ( ) ) ; } private addWsExceptionMetadatas ( scope , ws ) { scope . setExtra ( 'ws_client' , ws . getClient ( ) ) ; scope . setExtra ( 'ws_data' , ws . getData ( ) ) ; } private captureException ( scope , exception , localTransformers ) { if ( this . options . level ) scope . setLevel ( this . options . level ) ; if ( this . options . fingerprint ) scope . setFingerprint ( this . options . fingerprint ) ; if ( this . options . extra ) scope . setExtras ( this . options . extra ) ; if ( this . options . tags ) scope . setTags ( this . options . tags ) ; if ( this . options . transformers ) this . options . transformers . forEach ( ( transformer ) => transformer ( scope ) ) ; if ( localTransformers ) localTransformers . forEach ( ( transformer ) => transformer ( scope ) ) ; Sentry . captureException ( exception ) ; } private shouldReport ( exception ) { if ( ! this . options . filters ) return true ; return this . options . filters . every ( ( { type , filter } ) => { return ! ( exception instanceof type && ( ! filter || filter ( exception ) ) ) ; } ) ; } }