Skip to content

Commit 8f2dedf

Browse files
committed
fix stuff
1 parent 4a29639 commit 8f2dedf

2 files changed

Lines changed: 64 additions & 7 deletions

File tree

packages/core/src/integrations/supabase.ts

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,25 @@ function isInstrumented<T>(fn: T): boolean | undefined {
149149
}
150150
}
151151

152+
/**
153+
* Plain-object bodies are copied into `plainBody`; array inserts (and other non-plain shapes) stay only on `rawBody`.
154+
* Returns a payload suitable for span attributes / breadcrumbs when the client has `sendDefaultPii` enabled.
155+
*/
156+
function getMutationBodyPayloadForTelemetry(rawBody: unknown, plainBody: Record<string, unknown>): unknown | undefined {
157+
if (Object.keys(plainBody).length > 0) {
158+
return plainBody;
159+
}
160+
if (Array.isArray(rawBody) && rawBody.length > 0) {
161+
return rawBody;
162+
}
163+
return undefined;
164+
}
165+
166+
/** True when the PostgREST builder carries a mutation body (for `insert(...)`, etc. in span descriptions). */
167+
function hasMutationBodyForDescription(rawBody: unknown, plainBody: Record<string, unknown>): boolean {
168+
return getMutationBodyPayloadForTelemetry(rawBody, plainBody) !== undefined;
169+
}
170+
152171
/**
153172
* Extracts the database operation type from the HTTP method and headers
154173
* @param method - The HTTP method of the request
@@ -363,11 +382,15 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
363382
}
364383

365384
const sendDefaultPii = Boolean(getClient()?.getOptions().sendDefaultPii);
385+
const bodyPayload = getMutationBodyPayloadForTelemetry(typedThis.body, body);
366386

367387
// Adding operation to the beginning of the description if it's not a `select` operation
368388
// For example, it can be an `insert` or `update` operation but the query can be `select(...)`
369389
// For `select` operations, we don't need repeat it in the description
370-
const mutationPart = operation === 'select' ? '' : `${operation}${Object.keys(body).length ? '(...) ' : ''}`;
390+
const mutationPart =
391+
operation === 'select'
392+
? ''
393+
: `${operation}${hasMutationBodyForDescription(typedThis.body, body) ? '(...) ' : ''}`;
371394
const queryPart = sendDefaultPii ? queryItems.join(' ') : queryItems.length > 0 ? '[redacted]' : '';
372395
const descriptionMiddle = [mutationPart.trimEnd(), queryPart].filter(Boolean).join(' ');
373396
const description = descriptionMiddle ? `${descriptionMiddle} from(${table})` : `from(${table})`;
@@ -387,8 +410,8 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
387410
attributes['db.query'] = queryItems;
388411
}
389412

390-
if (Object.keys(body).length && sendDefaultPii) {
391-
attributes['db.body'] = body;
413+
if (bodyPayload !== undefined && sendDefaultPii) {
414+
attributes['db.body'] = bodyPayload;
392415
}
393416

394417
return startSpan(
@@ -420,8 +443,8 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
420443
if (queryItems.length && sendDefaultPii) {
421444
supabaseContext.query = queryItems;
422445
}
423-
if (Object.keys(body).length && sendDefaultPii) {
424-
supabaseContext.body = body;
446+
if (bodyPayload !== undefined && sendDefaultPii) {
447+
supabaseContext.body = bodyPayload;
425448
}
426449

427450
captureException(err, scope => {
@@ -452,8 +475,8 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder: PostgRESTFilte
452475
data.query = queryItems;
453476
}
454477

455-
if (Object.keys(body).length && sendDefaultPii) {
456-
data.body = body;
478+
if (bodyPayload !== undefined && sendDefaultPii) {
479+
data.body = bodyPayload;
457480
}
458481

459482
if (Object.keys(data).length) {

packages/core/test/lib/integrations/supabase.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,38 @@ describe('Supabase Integration', () => {
310310
expect(contexts.supabase).toEqual({});
311311
});
312312
});
313+
314+
describe('array insert body', () => {
315+
beforeEach(() => {
316+
vi.spyOn(breadcrumbModule, 'addBreadcrumb').mockImplementation(() => {});
317+
});
318+
319+
afterEach(() => {
320+
vi.restoreAllMocks();
321+
});
322+
323+
it('includes insert(...) in span description and db.body when payload is a non-empty array', async () => {
324+
tracingMocks.startSpan.mockClear();
325+
const client = createMockSupabaseClient(
326+
{ status: 200 },
327+
{
328+
method: 'POST',
329+
url: 'https://example.supabase.co/rest/v1/todos?columns=',
330+
body: [{ title: 'Test Todo' }],
331+
sendDefaultPii: true,
332+
},
333+
);
334+
instrumentSupabaseClient(client);
335+
336+
await (client as any).from('todos').insert({}).then();
337+
338+
const spanOptions = tracingMocks.startSpan.mock.calls[0]![0] as {
339+
name: string;
340+
attributes: Record<string, unknown>;
341+
};
342+
expect(spanOptions.name).toMatch(/^insert\(\.\.\.\)/);
343+
expect(spanOptions.name).toContain('from(todos)');
344+
expect(spanOptions.attributes['db.body']).toEqual([{ title: 'Test Todo' }]);
345+
});
346+
});
313347
});

0 commit comments

Comments
 (0)