All files / varjoliitokauppa/lib prisma.ts

51.02% Statements 25/49
29.41% Branches 10/34
60% Functions 3/5
51.16% Lines 22/43

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
}