Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import { PrismaClient } from '@prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'
import { Pool } from 'pg'
const decodeApiKey = (apiKey: string): Record<string, unknown> | null => {
try {
const normalized = apiKey.replace(/-/g, '+').replace(/_/g, '/')
const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4))
const json = Buffer.from(normalized + padding, 'base64').toString('utf-8')
return JSON.parse(json) as Record<string, unknown>
} catch {
return null
}
}
const normalizeLocalhost = (urlString: string): string => {
try {
const url = new URL(urlString)
Eif (url.hostname === 'localhost') url.hostname = '127.0.0.1'
return url.toString()
} catch {
return urlString
}
}
const getDirectDatabaseUrl = (): string | undefined => {
const direct = process.env.DIRECT_URL
Eif (direct) return normalizeLocalhost(direct)
const raw = process.env.DATABASE_URL
if (!raw) return undefined
if (raw.startsWith('postgres://') || raw.startsWith('postgresql://')) {
return normalizeLocalhost(raw)
}
if (!raw.startsWith('prisma+postgres://')) return raw
try {
const url = new URL(raw)
const apiKey = url.searchParams.get('api_key')
if (!apiKey) return undefined
const payload = decodeApiKey(apiKey)
const directUrl =
(payload?.databaseUrl as string | undefined) ||
(payload?.databaseURL as string | undefined) ||
(payload?.url as string | undefined) ||
(payload?.connectionString as string | undefined)
return directUrl ? normalizeLocalhost(directUrl) : undefined
} catch {
return undefined
}
}
const createPool = (connectionString: string) => new Pool({
connectionString,
max: 1, // Prisma Postgres local requires single connection
connectionTimeoutMillis: 10000, // 10 second timeout (increased for slow starts)
idleTimeoutMillis: 30000, // 30 second idle timeout
allowExitOnIdle: false, // Keep pool alive
})
// PrismaClient is attached to the `global` object in development to prevent
// exhausting your database connection limit during hot reloads in Next.js
const globalForPrisma = global as unknown as { prisma?: PrismaClient; pool?: Pool }
const connectionString = getDirectDatabaseUrl()
Iif (!connectionString) {
throw new Error('Missing direct database URL. Set DIRECT_URL or use a postgres:// DATABASE_URL.')
}
const pool = globalForPrisma.pool || createPool(connectionString)
Eif (!globalForPrisma.pool) {
// Handle pool errors and attempt reconnection
pool.on('error', (err) => {
console.warn('Prisma pool error, will retry on next request:', err.message)
})
}
const adapter = new PrismaPg(pool)
export const prisma =
globalForPrisma.prisma ||
new PrismaClient({
adapter,
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
})
Eif (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
globalForPrisma.pool = pool
}
|