Skip to content

Commit 300b018

Browse files
logaretmclaude
andauthored
fix(core): Avoid parse-time SyntaxError on Safari <16.4 in postgresjs (#20498)
Bandaid fix for #20433. Constructs the negative-lookbehind regex via `new RegExp(...)` instead of a regex literal, so it is evaluated at runtime rather than at parse time. [Safari <16.4 does not support lookbehind assertions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion) as a literal, this causes a parse-time `SyntaxError` that kills the entire script. As a constructor call with `new RegExp`, parsing succeeds;. Correctness in Safari doesn't matter here, we just don't want the file to fail to parse and it would never execute anyways. The deeper issue is that server-only code from `@sentry/core` (postgresjs, express, trpc, mcp-server, the AI instrumentations, etc.) can end up in browser bundles because it seems like some bundlers can't tree-shake it out of the core barrel. We should be more disciplined about what the main `@sentry/core` entry re-exports so apps stop shipping server code that never executes. I managed to reproduce this setup in a webpack with CJS app and noticed it didn't tree-shake the postgres integration. Vite seems to do it correctly. Bringing this up next week, but we should not rely on tree-shaking to eliminate code-paths. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 786fdf7 commit 300b018

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

packages/core/src/integrations/postgresjs.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ export function _reconstructQuery(strings: string[] | undefined): string | undef
342342
return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');
343343
}
344344

345+
let integerLiteralRE: RegExp | undefined;
346+
345347
/**
346348
* Sanitize SQL query as per the OTEL semantic conventions
347349
* https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext
@@ -356,6 +358,13 @@ export function _sanitizeSqlQuery(sqlQuery: string | undefined): string {
356358
return 'Unknown SQL Query';
357359
}
358360

361+
// Lazy init: constructing this at module scope would evaluate the lookbehind
362+
// on import and crash Safari <16.4 browser bundles that reach this file via
363+
// the core barrel. Building it on first call keeps the cost off the import path.
364+
if (!integerLiteralRE) {
365+
integerLiteralRE = new RegExp('(?<!\\$)-?\\b\\d+\\b', 'g');
366+
}
367+
359368
return (
360369
sqlQuery
361370
// Remove comments first (they may contain newlines and extra spaces)
@@ -378,7 +387,7 @@ export function _sanitizeSqlQuery(sqlQuery: string | undefined): string {
378387
.replace(/-?\b\d+\.?\d*[eE][+-]?\d+\b/g, '?') // Scientific notation
379388
.replace(/-?\b\d+\.\d+\b/g, '?') // Decimals
380389
.replace(/-?\.\d+\b/g, '?') // Decimals starting with dot
381-
.replace(/(?<!\$)-?\b\d+\b/g, '?') // Integers (NOT $n placeholders)
390+
.replace(integerLiteralRE, '?') // Integers (NOT $n placeholders)
382391
// Collapse IN clauses for cardinality (both ? and $n variants)
383392
.replace(/\bIN\b\s*\(\s*\?(?:\s*,\s*\?)*\s*\)/gi, 'IN (?)')
384393
.replace(/\bIN\b\s*\(\s*\$\d+(?:\s*,\s*\$\d+)*\s*\)/gi, 'IN ($?)')

0 commit comments

Comments
 (0)