ts-node is a devDependency and isn't available after a production install; scripts/create-user.js only needs packages already in dependencies so it runs on the deployed server. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
"db:migrate": "prisma migrate dev",
|
"db:migrate": "prisma migrate dev",
|
||||||
"db:seed": "ts-node -P tsconfig.seed.json prisma/seed.ts",
|
"db:seed": "ts-node -P tsconfig.seed.json prisma/seed.ts",
|
||||||
"db:create-user": "ts-node -P tsconfig.seed.json scripts/create-user.ts",
|
"db:create-user": "ts-node -P tsconfig.seed.json scripts/create-user.ts",
|
||||||
|
"db:create-user:prod": "node scripts/create-user.js",
|
||||||
"db:studio": "prisma studio"
|
"db:studio": "prisma studio"
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
// Minimal .env loader (avoids depending on the `dotenv` package, which may
|
||||||
|
// not be installed in a production deployment that skipped devDependencies).
|
||||||
|
function loadEnvFile(file) {
|
||||||
|
if (!fs.existsSync(file)) return;
|
||||||
|
for (const line of fs.readFileSync(file, "utf8").split("\n")) {
|
||||||
|
const match = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/);
|
||||||
|
if (!match) continue;
|
||||||
|
const key = match[1];
|
||||||
|
let value = (match[2] ?? "").trim();
|
||||||
|
if (value.startsWith('"') && value.endsWith('"')) value = value.slice(1, -1);
|
||||||
|
else if (value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
|
||||||
|
if (!(key in process.env)) process.env[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadEnvFile(path.join(__dirname, "..", ".env"));
|
||||||
|
|
||||||
|
const { PrismaClient } = require("@prisma/client");
|
||||||
|
const { PrismaPg } = require("@prisma/adapter-pg");
|
||||||
|
const bcrypt = require("bcryptjs");
|
||||||
|
|
||||||
|
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
|
||||||
|
const prisma = new PrismaClient({ adapter });
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const [, , email, password, name] = process.argv;
|
||||||
|
|
||||||
|
if (!email || !password) {
|
||||||
|
console.error("Usage: node scripts/create-user.js <email> <password> [name]");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length < 8) {
|
||||||
|
console.error("Password must be at least 8 characters long.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashedPassword = await bcrypt.hash(password, 12);
|
||||||
|
const normalizedEmail = email.toLowerCase().trim();
|
||||||
|
|
||||||
|
const user = await prisma.user.upsert({
|
||||||
|
where: { email: normalizedEmail },
|
||||||
|
create: {
|
||||||
|
email: normalizedEmail,
|
||||||
|
password: hashedPassword,
|
||||||
|
name: name ?? null,
|
||||||
|
role: "ADMIN",
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
password: hashedPassword,
|
||||||
|
...(name ? { name } : {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`✅ User ready: ${user.email} (role: ${user.role})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
})
|
||||||
|
.finally(async () => {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user