@@ -12,6 +12,14 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '
12
12
import { captureException } from '../exports' ;
13
13
import { SPAN_STATUS_ERROR , SPAN_STATUS_OK } from '../tracing' ;
14
14
15
+ export interface SupabaseClientConstructor {
16
+ prototype : {
17
+ from : ( table : string ) => PostgrestQueryBuilder ;
18
+ schema : ( schema : string ) => { rpc : ( ...args : unknown [ ] ) => Promise < unknown > } ;
19
+ } ;
20
+ rpc : ( fn : string , params : Record < string , unknown > ) => Promise < unknown > ;
21
+ }
22
+
15
23
const AUTH_OPERATIONS_TO_INSTRUMENT = [
16
24
'reauthenticate' ,
17
25
'signInAnonymously' ,
@@ -114,12 +122,6 @@ export interface SupabaseBreadcrumb {
114
122
} ;
115
123
}
116
124
117
- export interface SupabaseClientConstructor {
118
- prototype : {
119
- from : ( table : string ) => PostgrestQueryBuilder ;
120
- } ;
121
- }
122
-
123
125
export interface PostgrestProtoThenable {
124
126
then : < T > (
125
127
onfulfilled ?: ( ( value : T ) => T | PromiseLike < T > ) | null ,
@@ -197,6 +199,76 @@ export function translateFiltersIntoMethods(key: string, query: string): string
197
199
return `${ method } (${ key } , ${ value . join ( '.' ) } )` ;
198
200
}
199
201
202
+ function instrumentRpcReturnedFromSchemaCall ( SupabaseClient : unknown ) : void {
203
+ ( SupabaseClient as unknown as SupabaseClientConstructor ) . prototype . schema = new Proxy (
204
+ ( SupabaseClient as unknown as SupabaseClientConstructor ) . prototype . schema ,
205
+ {
206
+ apply ( target , thisArg , argumentsList ) {
207
+ const rv = Reflect . apply ( target , thisArg , argumentsList ) ;
208
+
209
+ return instrumentRpc ( rv ) ;
210
+ } ,
211
+ } ,
212
+ ) ;
213
+ }
214
+
215
+ function instrumentRpc ( SupabaseClient : unknown ) : unknown {
216
+ ( SupabaseClient as unknown as SupabaseClientConstructor ) . rpc = new Proxy (
217
+ ( SupabaseClient as unknown as SupabaseClientConstructor ) . rpc ,
218
+ {
219
+ apply ( target , thisArg , argumentsList ) {
220
+ const isProducerSpan = argumentsList [ 0 ] === 'enqueue' ;
221
+ const isConsumerSpan = argumentsList [ 0 ] === 'dequeue' ;
222
+
223
+ const maybeQueueParams = argumentsList [ 1 ] ;
224
+
225
+ // If the second argument is not an object, it's not a queue operation
226
+ if ( ! isPlainObject ( maybeQueueParams ) ) {
227
+ return Reflect . apply ( target , thisArg , argumentsList ) ;
228
+ }
229
+
230
+ const msg = maybeQueueParams ?. msg as { title : string } ;
231
+
232
+ const messageId = msg ?. title ;
233
+ const queueName = maybeQueueParams ?. queue_name as string ;
234
+
235
+ const op = isProducerSpan ? 'queue.publish' : isConsumerSpan ? 'queue.process' : '' ;
236
+
237
+ // If the operation is not a queue operation, return the original function
238
+ if ( ! op ) {
239
+ return Reflect . apply ( target , thisArg , argumentsList ) ;
240
+ }
241
+
242
+ return startSpan (
243
+ {
244
+ name : 'supabase.db.rpc' ,
245
+ attributes : {
246
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.db.supabase' ,
247
+ [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : op ,
248
+ } ,
249
+ } ,
250
+ async span => {
251
+ return ( Reflect . apply ( target , thisArg , argumentsList ) as Promise < unknown > ) . then ( ( res : unknown ) => {
252
+ if ( messageId ) {
253
+ span . setAttribute ( 'messaging.message.id' , messageId ) ;
254
+ }
255
+
256
+ if ( queueName ) {
257
+ span . setAttribute ( 'messaging.destination.name' , queueName ) ;
258
+ }
259
+
260
+ span . end ( ) ;
261
+ return res ;
262
+ } ) ;
263
+ } ,
264
+ ) ;
265
+ } ,
266
+ } ,
267
+ ) ;
268
+
269
+ return SupabaseClient ;
270
+ }
271
+
200
272
function instrumentAuthOperation ( operation : AuthOperationFn , isAdmin = false ) : AuthOperationFn {
201
273
return new Proxy ( operation , {
202
274
apply ( target , thisArg , argumentsList ) {
@@ -266,13 +338,13 @@ function instrumentSupabaseAuthClient(supabaseClientInstance: SupabaseClientInst
266
338
} ) ;
267
339
}
268
340
269
- function instrumentSupabaseClientConstructor ( SupabaseClient : unknown ) : void {
270
- if ( instrumented . has ( SupabaseClient ) ) {
341
+ function instrumentSupabaseClientConstructor ( SupabaseClientConstructor : unknown ) : void {
342
+ if ( instrumented . has ( SupabaseClientConstructor ) ) {
271
343
return ;
272
344
}
273
345
274
- ( SupabaseClient as unknown as SupabaseClientConstructor ) . prototype . from = new Proxy (
275
- ( SupabaseClient as unknown as SupabaseClientConstructor ) . prototype . from ,
346
+ ( SupabaseClientConstructor as unknown as SupabaseClientConstructor ) . prototype . from = new Proxy (
347
+ ( SupabaseClientConstructor as unknown as SupabaseClientConstructor ) . prototype . from ,
276
348
{
277
349
apply ( target , thisArg , argumentsList ) {
278
350
const rv = Reflect . apply ( target , thisArg , argumentsList ) ;
@@ -466,6 +538,8 @@ const instrumentSupabase = (supabaseClientInstance: unknown): void => {
466
538
supabaseClientInstance . constructor === Function ? supabaseClientInstance : supabaseClientInstance . constructor ;
467
539
468
540
instrumentSupabaseClientConstructor ( SupabaseClientConstructor ) ;
541
+ instrumentRpcReturnedFromSchemaCall ( SupabaseClientConstructor ) ;
542
+ instrumentRpc ( supabaseClientInstance as SupabaseClientInstance ) ;
469
543
instrumentSupabaseAuthClient ( supabaseClientInstance as SupabaseClientInstance ) ;
470
544
} ;
471
545
0 commit comments