@@ -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,49 @@ export function errorHandler(options?: {
315316 } ;
316317}
317318
319+ interface SentryTrpcMiddlewareOptions {
320+ /** Whether to include procedure inputs in reported events. Defaults to `false`. */
321+ attachRpcInput ?: boolean ;
322+ }
323+
324+ interface TrpcMiddlewareArguments < T > {
325+ path : string ;
326+ type : 'query' | 'mutation' | 'subscription' ;
327+ next : ( ) => T ;
328+ rawInput : unknown ;
329+ }
330+
331+ /**
332+ * Sentry tRPC middleware that names the handling transaction after the called procedure.
333+ *
334+ * Use the Sentry tRPC middleware in combination with the Sentry server integration,
335+ * e.g. Express Request Handlers or Next.js SDK.
336+ */
337+ export async function trpcMiddleware ( options : SentryTrpcMiddlewareOptions = { } ) {
338+ return function < T > ( { path, type, next, rawInput } : TrpcMiddlewareArguments < T > ) : T {
339+ const hub = getCurrentHub ( ) ;
340+ const clientOptions = hub . getClient ( ) ?. getOptions ( ) ;
341+ const sentryTransaction = hub . getScope ( ) ?. getTransaction ( ) ;
342+
343+ if ( sentryTransaction ) {
344+ sentryTransaction . setName ( `trcp/${ path } ` , 'route' ) ;
345+ sentryTransaction . op = 'rpc.server' ;
346+
347+ const trpcContext : Record < string , unknown > = {
348+ procedure_type : type ,
349+ } ;
350+
351+ if ( options . attachRpcInput !== undefined ? options . attachRpcInput : clientOptions ?. sendDefaultPii ) {
352+ trpcContext . input = normalize ( rawInput ) ;
353+ }
354+
355+ sentryTransaction . setContext ( 'trpc' , trpcContext ) ;
356+ }
357+
358+ return next ( ) ;
359+ } ;
360+ }
361+
318362// TODO (v8 / #5257): Remove this
319363// eslint-disable-next-line deprecation/deprecation
320364export type { ParseRequestOptions , ExpressRequest } from './requestDataDeprecated' ;
0 commit comments