@@ -10,6 +10,7 @@ import {
1010 extractTraceparentData ,
1111 isString ,
1212 logger ,
13+ normalize ,
1314} from '@sentry/utils' ;
1415import * as domain from 'domain' ;
1516import type * as http from 'http' ;
@@ -315,6 +316,48 @@ export function errorHandler(options?: {
315316 } ;
316317}
317318
319+ interface SentryTrpcMiddlewareOptions {
320+ attachRpcInput ?: boolean ;
321+ }
322+
323+ interface TrpcMiddlewareArguments < T > {
324+ path : string ;
325+ type : 'query' | 'mutation' | 'subscription' ;
326+ next : ( ) => T ;
327+ rawInput : unknown ;
328+ }
329+
330+ /**
331+ * Sentry tRPC middleware that names the handling transaction after the called procedure.
332+ *
333+ * Use the Sentry tRPC middleware in combination with the Sentry server integration,
334+ * e.g. Express Request Handlers or Next.js SDK.
335+ */
336+ export async function trpcMiddleware ( options : SentryTrpcMiddlewareOptions = { } ) {
337+ return function < T > ( { path, type, next, rawInput } : TrpcMiddlewareArguments < T > ) : T {
338+ const hub = getCurrentHub ( ) ;
339+ const clientOptions = hub . getClient ( ) ?. getOptions ( ) ;
340+ const sentryTransaction = hub . getScope ( ) ?. getTransaction ( ) ;
341+
342+ if ( sentryTransaction ) {
343+ sentryTransaction . setName ( `trcp/${ path } ` , 'route' ) ;
344+ sentryTransaction . op = 'rpc.server' ;
345+
346+ const trpcData : Record < string , unknown > = {
347+ procedureType : type ,
348+ } ;
349+
350+ if ( options . attachRpcInput !== undefined ? options . attachRpcInput : clientOptions ?. sendDefaultPii ) {
351+ trpcData . procedureInput = normalize ( rawInput ) ;
352+ }
353+
354+ sentryTransaction . setData ( 'trpc' , trpcData ) ;
355+ }
356+
357+ return next ( ) ;
358+ } ;
359+ }
360+
318361// TODO (v8 / #5257): Remove this
319362// eslint-disable-next-line deprecation/deprecation
320363export type { ParseRequestOptions , ExpressRequest } from './requestDataDeprecated' ;
0 commit comments