import { config } from 'dotenv' import { PrismaClient } from '@prisma/client' import { randomBytes, scryptSync } from 'node:crypto' import { readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' config({ path: fileURLToPath(new URL('../.env', import.meta.url)), quiet: true }) const prisma = new PrismaClient() try { const username = (process.env.SUPPLIED_ADMIN_USERNAME || 'admin').trim() const password = process.env.SUPPLIED_ADMIN_PASSWORD || `Sp!${randomBytes(12).toString('base64url')}9a` if (!username || username.length > 64 || password.length < 12 || password.length > 128) { throw new Error('账号长度需为 1-64,密码长度需为 12-128') } const tables = await prisma.$queryRaw`SELECT TABLE_NAME AS name FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND LOWER(TABLE_NAME) IN ('user', 'cartitem', 'supplied_cart_item')` const legacyUser = tables.find(row => row.name.toLowerCase() === 'user') const legacyCart = tables.find(row => row.name.toLowerCase() === 'cartitem') if (legacyUser) { const rows = await prisma.$queryRawUnsafe('SELECT COUNT(*) AS count FROM `' + legacyUser.name.replace(/`/g, '``') + '`') if (Number(rows[0].count) > 0) throw new Error('旧 user 表存在数据,未删除,请先处理原有数据') } if (legacyCart) { if (tables.some(row => row.name.toLowerCase() === 'supplied_cart_item')) throw new Error('新旧购物车表同时存在,未覆盖数据') await prisma.$executeRawUnsafe('RENAME TABLE `' + legacyCart.name.replace(/`/g, '``') + '` TO `supplied_cart_item`') } if (legacyUser) await prisma.$executeRawUnsafe('DROP TABLE `' + legacyUser.name.replace(/`/g, '``') + '`') await prisma.$executeRawUnsafe(readFileSync(new URL('./sql/supplied-user.sql', import.meta.url), 'utf8').trim().replace(/;$/, '')) const existing = await prisma.$queryRaw`SELECT id FROM supplied_user WHERE username = ${username} LIMIT 1` if (existing.length) throw new Error('账号已存在,未覆盖原有密码') const salt = randomBytes(16).toString('hex') const hash = scryptSync(password, salt, 64, { N: 32768, r: 8, p: 1, maxmem: 64 * 1024 * 1024 }).toString('hex') const passwordHash = `scrypt$${salt}$${hash}` await prisma.$executeRaw`INSERT INTO supplied_user (username, passwordHash, nickname) VALUES (${username}, ${passwordHash}, ${'管理员'})` console.log(JSON.stringify({ username, password, table: 'supplied_user' })) } catch (error) { console.error(error instanceof Error ? error.message : '初始化账号失败') process.exitCode = 1 } finally { await prisma.$disconnect() }