flnxi-Wu/scripts/prisma-local-dev.mjs
2026-05-28 15:11:36 +08:00

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)
})