@@ -50,10 +50,7 @@ const withRetry = async <T>(
5050 const delay = INITIAL_RETRY_DELAY_MS * Math . pow ( 2 , attempt - 1 ) ;
5151
5252 if ( env . NODE_ENV === "development" ) {
53- console . warn (
54- `Database connection error (attempt ${ attempt } /${ MAX_RETRIES } ), retrying in ${ delay } ms...` ,
55- error instanceof Error ? error . message : String ( error ) ,
56- ) ;
53+ console . warn ( `Database connection error, retrying in ${ delay } ms (${ attempt } /${ MAX_RETRIES } )` ) ;
5754 }
5855
5956 await new Promise ( ( resolve ) => setTimeout ( resolve , delay ) ) ;
@@ -74,34 +71,32 @@ const withRetry = async <T>(
7471const createPrismaClient = ( ) => {
7572 // Validate DATABASE_URL is using pooled connection for Supabase
7673 const dbUrl = env . DATABASE_URL ;
77- if ( dbUrl && dbUrl . includes ( "supabase.com" ) ) {
78- const isPooler = dbUrl . includes ( "pooler" ) ;
79- const hasWrongPort = dbUrl . includes ( ":5432" ) ;
80- const hasCorrectPort = dbUrl . includes ( ":6543" ) ;
81-
82- // Critical error: Using pooler hostname with direct port
83- if ( isPooler && hasWrongPort ) {
84- console . error (
85- "❌ CRITICAL: DATABASE_URL uses pooler hostname but wrong port (5432). " +
86- "For Supabase connection pooler, you MUST use port 6543, not 5432. " +
87- "Fix: Replace :5432 with :6543 in your DATABASE_URL. " +
88- "Get correct URL from: Supabase Dashboard → Settings → Database → Connection Pooling → Transaction mode" ,
89- ) ;
90- }
91- // Error: Using direct connection instead of pooled
92- else if ( ! isPooler && hasWrongPort ) {
93- console . error (
94- "❌ DATABASE_URL is using direct connection (port 5432). " +
95- "For Vercel serverless with Supabase, you MUST use the connection pooler URL (port 6543). " +
96- "Get it from: Supabase Dashboard → Settings → Database → Connection Pooling → Transaction mode" ,
97- ) ;
98- }
99- // Warning: Pooler URL missing pgbouncer parameter
100- else if ( isPooler && hasCorrectPort && ! dbUrl . includes ( "pgbouncer=true" ) ) {
101- console . warn (
102- "⚠️ DATABASE_URL uses pooler but missing pgbouncer=true parameter. " +
103- "Add ?pgbouncer=true to your connection string for optimal performance." ,
104- ) ;
74+ if ( dbUrl ) {
75+ try {
76+ // Properly parse URL to validate hostname instead of substring matching
77+ const url = new URL ( dbUrl ) ;
78+ const hostname = url . hostname . toLowerCase ( ) ;
79+ const port = url . port ? parseInt ( url . port , 10 ) : ( url . protocol === "postgresql:" ? 5432 : null ) ;
80+ const isSupabase = hostname . endsWith ( ".supabase.com" ) || hostname === "supabase.com" ;
81+ const isPooler = hostname . includes ( "pooler" ) ;
82+ const searchParams = new URLSearchParams ( url . search ) ;
83+ const hasPgbouncer = searchParams . has ( "pgbouncer" ) && searchParams . get ( "pgbouncer" ) === "true" ;
84+
85+ if ( isSupabase ) {
86+ if ( isPooler && port === 5432 ) {
87+ console . error ( "DATABASE_URL: pooler hostname requires port 6543, not 5432" ) ;
88+ } else if ( ! isPooler && port === 5432 ) {
89+ console . error ( "DATABASE_URL: use connection pooler (port 6543) for serverless" ) ;
90+ } else if ( isPooler && port === 6543 && ! hasPgbouncer ) {
91+ console . warn ( "DATABASE_URL: add ?pgbouncer=true for optimal performance" ) ;
92+ }
93+ }
94+ } catch ( error ) {
95+ // If URL parsing fails, log warning but don't block initialization
96+ // Prisma will handle invalid URLs with its own error messages
97+ if ( env . NODE_ENV === "development" ) {
98+ console . warn ( "Could not parse DATABASE_URL for validation:" , error ) ;
99+ }
105100 }
106101 }
107102
0 commit comments