127 lines
3.3 KiB
JavaScript
127 lines
3.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { spawn } from 'node:child_process'
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = path.dirname(__filename)
|
|
const projectRoot = path.resolve(__dirname, '..')
|
|
const envFile = path.join(projectRoot, '.env.development.local')
|
|
const args = process.argv.slice(2)
|
|
|
|
function parseEnvFile(filePath) {
|
|
const values = {}
|
|
const raw = fs.readFileSync(filePath, 'utf8')
|
|
|
|
for (const line of raw.split(/\r?\n/)) {
|
|
const trimmed = line.trim()
|
|
if (!trimmed || trimmed.startsWith('#')) continue
|
|
|
|
const normalized = trimmed.startsWith('export ') ? trimmed.slice(7).trim() : trimmed
|
|
const eqIndex = normalized.indexOf('=')
|
|
if (eqIndex <= 0) continue
|
|
|
|
const key = normalized.slice(0, eqIndex).trim()
|
|
let value = normalized.slice(eqIndex + 1).trim()
|
|
|
|
if (
|
|
(value.startsWith('"') && value.endsWith('"')) ||
|
|
(value.startsWith("'") && value.endsWith("'"))
|
|
) {
|
|
value = value.slice(1, -1)
|
|
}
|
|
|
|
values[key] = value
|
|
}
|
|
|
|
return values
|
|
}
|
|
|
|
function describeDatabase(url) {
|
|
try {
|
|
const parsed = new URL(url)
|
|
const port = parsed.port ? `:${parsed.port}` : ''
|
|
const database = parsed.pathname && parsed.pathname !== '/' ? parsed.pathname.slice(1) : '(default)'
|
|
|
|
return {
|
|
host: parsed.hostname,
|
|
label: `${parsed.hostname}${port}/${database}`,
|
|
}
|
|
} catch {
|
|
return {
|
|
host: '',
|
|
label: '(invalid DATABASE_URL)',
|
|
}
|
|
}
|
|
}
|
|
|
|
function isLocalDatabaseHost(host) {
|
|
const normalized = host.toLowerCase()
|
|
return [
|
|
'localhost',
|
|
'127.0.0.1',
|
|
'::1',
|
|
'[::1]',
|
|
'host.docker.internal',
|
|
].includes(normalized)
|
|
}
|
|
|
|
if (args.length === 0) {
|
|
console.error('Usage: npm run prisma:dev -- <prisma arguments>')
|
|
console.error('Example: npm run prisma:dev -- migrate status')
|
|
process.exit(1)
|
|
}
|
|
|
|
if (!fs.existsSync(envFile)) {
|
|
console.error('[prisma-local-dev] Missing .env.development.local.')
|
|
console.error('[prisma-local-dev] Refusing to guess a database target from .env or .env.local.')
|
|
process.exit(1)
|
|
}
|
|
|
|
const localEnv = parseEnvFile(envFile)
|
|
const databaseUrl = localEnv.DATABASE_URL
|
|
|
|
if (!databaseUrl) {
|
|
console.error('[prisma-local-dev] .env.development.local does not define DATABASE_URL.')
|
|
process.exit(1)
|
|
}
|
|
|
|
const database = describeDatabase(databaseUrl)
|
|
|
|
if (!isLocalDatabaseHost(database.host) && process.env.ALLOW_NONLOCAL_PRISMA_DEV_DB !== '1') {
|
|
console.error(`[prisma-local-dev] Refusing non-local DATABASE_URL host: ${database.host || '(unknown)'}`)
|
|
console.error('[prisma-local-dev] Set ALLOW_NONLOCAL_PRISMA_DEV_DB=1 only when you intentionally need this.')
|
|
process.exit(1)
|
|
}
|
|
|
|
const childEnv = {
|
|
...process.env,
|
|
...localEnv,
|
|
}
|
|
|
|
console.log(`[prisma-local-dev] Using .env.development.local -> ${database.label}`)
|
|
|
|
const prismaCli = path.join(projectRoot, 'node_modules', 'prisma', 'build', 'index.js')
|
|
|
|
if (!fs.existsSync(prismaCli)) {
|
|
console.error('[prisma-local-dev] Prisma CLI is missing. Run npm install first.')
|
|
process.exit(1)
|
|
}
|
|
|
|
const child = spawn(process.execPath, [prismaCli, ...args], {
|
|
cwd: projectRoot,
|
|
env: childEnv,
|
|
stdio: 'inherit',
|
|
})
|
|
|
|
child.on('exit', (code, signal) => {
|
|
if (signal) {
|
|
process.kill(process.pid, signal)
|
|
return
|
|
}
|
|
|
|
process.exit(code ?? 1)
|
|
})
|