@@ -10,6 +10,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '
10
10
import { setHttpStatus , SPAN_STATUS_ERROR , SPAN_STATUS_OK , startSpan } from '../tracing' ;
11
11
import type { IntegrationFn } from '../types-hoist/integration' ;
12
12
import { debug } from '../utils/debug-logger' ;
13
+ import type { SpanAttributes } from '../types-hoist/span' ;
13
14
import { isPlainObject } from '../utils/is' ;
14
15
15
16
const AUTH_OPERATIONS_TO_INSTRUMENT = [
@@ -64,7 +65,8 @@ export const FILTER_MAPPINGS = {
64
65
not : 'not' ,
65
66
} ;
66
67
67
- export const DB_OPERATIONS_TO_INSTRUMENT = [ 'select' , 'insert' , 'upsert' , 'update' , 'delete' ] ;
68
+ export const DB_OPERATIONS_TO_INSTRUMENT = [ 'select' , 'insert' , 'upsert' , 'update' , 'delete' ] as const ;
69
+ type DBOperation = ( typeof DB_OPERATIONS_TO_INSTRUMENT ) [ number ] ;
68
70
69
71
type AuthOperationFn = ( ...args : unknown [ ] ) => Promise < unknown > ;
70
72
type AuthOperationName = ( typeof AUTH_OPERATIONS_TO_INSTRUMENT ) [ number ] ;
@@ -86,7 +88,7 @@ export interface PostgRESTFilterBuilder {
86
88
headers : Record < string , string > ;
87
89
url : URL ;
88
90
schema : string ;
89
- body : any ;
91
+ body : unknown ;
90
92
}
91
93
92
94
export interface SupabaseResponse {
@@ -122,7 +124,7 @@ export interface SupabaseClientConstructor {
122
124
export interface PostgRESTProtoThenable {
123
125
then : < T > (
124
126
onfulfilled ?: ( ( value : T ) => T | PromiseLike < T > ) | null ,
125
- onrejected ?: ( ( reason : any ) => T | PromiseLike < T > ) | null ,
127
+ onrejected ?: ( ( reason : unknown ) => T | PromiseLike < T > ) | null ,
126
128
) => Promise < T > ;
127
129
}
128
130
@@ -152,7 +154,7 @@ function isInstrumented<T>(fn: T): boolean | undefined {
152
154
* @param headers - The request headers
153
155
* @returns The database operation type ('select', 'insert', 'upsert', 'update', or 'delete')
154
156
*/
155
- export function extractOperation ( method : string , headers : Record < string , string > = { } ) : string {
157
+ export function extractOperation ( method : string , headers : Record < string , string > = { } ) : DBOperation | '<unknown-op>' {
156
158
switch ( method ) {
157
159
case 'GET' : {
158
160
return 'select' ;
@@ -333,7 +335,7 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
333
335
const typedThis = thisArg as PostgRESTFilterBuilder ;
334
336
const operation = extractOperation ( typedThis . method , typedThis . headers ) ;
335
337
336
- if ( ! operations . includes ( operation ) ) {
338
+ if ( ! operations . includes ( operation as DBOperation ) ) {
337
339
return Reflect . apply ( target , thisArg , argumentsList ) ;
338
340
}
339
341
@@ -364,7 +366,7 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
364
366
' ' ,
365
367
) } from(${ table } )`;
366
368
367
- const attributes : Record < string , any > = {
369
+ const attributes : SpanAttributes = {
368
370
'db.table' : table ,
369
371
'db.schema' : typedThis . schema ,
370
372
'db.url' : typedThis . url . origin ,
@@ -380,7 +382,11 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
380
382
}
381
383
382
384
if ( Object . keys ( body ) . length ) {
383
- attributes [ 'db.body' ] = body ;
385
+ try {
386
+ attributes [ 'db.body' ] = JSON . stringify ( body ) ;
387
+ } catch {
388
+ // could not stringify body
389
+ }
384
390
}
385
391
386
392
return startSpan (
@@ -465,17 +471,19 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
465
471
markAsInstrumented ( ( PostgRESTFilterBuilder . prototype as unknown as PostgRESTProtoThenable ) . then ) ;
466
472
}
467
473
474
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
475
+ type BuilderPrototype = Record < DBOperation , ( ...args : any [ ] ) => any > ;
476
+
468
477
function instrumentPostgRESTQueryBuilder ( PostgRESTQueryBuilder : new ( ) => PostgRESTQueryBuilder ) : void {
469
478
// We need to wrap _all_ operations despite them sharing the same `PostgRESTFilterBuilder`
470
479
// constructor, as we don't know which method will be called first, and we don't want to miss any calls.
471
480
for ( const operation of DB_OPERATIONS_TO_INSTRUMENT ) {
472
- if ( isInstrumented ( ( PostgRESTQueryBuilder . prototype as Record < string , any > ) [ operation ] ) ) {
481
+ if ( isInstrumented ( ( PostgRESTQueryBuilder . prototype as BuilderPrototype ) [ operation ] ) ) {
473
482
continue ;
474
483
}
475
484
476
- type PostgRESTOperation = keyof Pick < PostgRESTQueryBuilder , 'select' | 'insert' | 'upsert' | 'update' | 'delete' > ;
477
- ( PostgRESTQueryBuilder . prototype as Record < string , any > ) [ operation as PostgRESTOperation ] = new Proxy (
478
- ( PostgRESTQueryBuilder . prototype as Record < string , any > ) [ operation as PostgRESTOperation ] ,
485
+ ( PostgRESTQueryBuilder . prototype as BuilderPrototype ) [ operation ] = new Proxy (
486
+ ( PostgRESTQueryBuilder . prototype as BuilderPrototype ) [ operation ] ,
479
487
{
480
488
apply ( target , thisArg , argumentsList ) {
481
489
const rv = Reflect . apply ( target , thisArg , argumentsList ) ;
@@ -490,7 +498,7 @@ function instrumentPostgRESTQueryBuilder(PostgRESTQueryBuilder: new () => PostgR
490
498
} ,
491
499
) ;
492
500
493
- markAsInstrumented ( ( PostgRESTQueryBuilder . prototype as Record < string , any > ) [ operation ] ) ;
501
+ markAsInstrumented ( ( PostgRESTQueryBuilder . prototype as BuilderPrototype ) [ operation ] ) ;
494
502
}
495
503
}
496
504
@@ -517,6 +525,7 @@ const _supabaseIntegration = ((supabaseClient: unknown) => {
517
525
} ;
518
526
} ) satisfies IntegrationFn ;
519
527
528
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
520
529
export const supabaseIntegration = defineIntegration ( ( options : { supabaseClient : any } ) => {
521
530
return _supabaseIntegration ( options . supabaseClient ) ;
522
531
} ) satisfies IntegrationFn ;
0 commit comments