import { writeFileSync, existsSync, mkdirSync } from 'fs'; import { join, dirname } from 'path'; import { getDb, closeDb } from './lib/db'; import { seedProducts } from './lib/products'; import bcrypt from 'bcryptjs'; import crypto from 'crypto'; function env(key: string, def = ''): string { return process.env[key] || def; } async function main() { console.log('\n=== Zlattea - Setup ===\n'); const dbPath = env('DB_PATH', join(process.cwd(), 'data', 'shop.db')); const dataDir = dirname(dbPath); if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true }); const siteUrl = env('SITE_URL', 'http://localhost:3000'); const adminEmail = env('ADMIN_EMAIL', 'admin@zlattea.com'); const adminPass = env('ADMIN_PASSWORD'); const port = env('PORT', '3000'); const apiPort = env('API_PORT', String(Number(port) + 1)); const bind = env('HOST', '127.0.0.1'); const nostrPubkey = env('NOSTR_PUBKEY'); const lud16 = env('LUD16_ADDRESS', 'shop@zlattea.com'); if (!adminPass) { console.error('ADMIN_PASSWORD must be set explicitly - refusing to create an admin with a default password.'); process.exit(1); } const envFile = `# site SITE_URL=${siteUrl} PORT=${port} API_PORT=${apiPort} HOST=${bind} DB_PATH=${dbPath} # lightning LUD16_ADDRESS=${lud16} BTC_BGN_RATE=${env('BTC_BGN_RATE')} # stripe (card payments - google pay, apple pay come free with stripe) STRIPE_SECRET_KEY=${env('STRIPE_SECRET_KEY')} STRIPE_PUBLISHABLE_KEY=${env('STRIPE_PUBLISHABLE_KEY')} STRIPE_WEBHOOK_SECRET=${env('STRIPE_WEBHOOK_SECRET')} # btcpayserver (onchain bitcoin) BTCPAY_URL=${env('BTCPAY_URL')} BTCPAY_API_KEY=${env('BTCPAY_API_KEY')} BTCPAY_STORE_ID=${env('BTCPAY_STORE_ID')} BTCPAY_WEBHOOK_SECRET=${env('BTCPAY_WEBHOOK_SECRET')} # courier api credentials (optional - leave empty if not needed) SPEEDY_USERNAME=${env('SPEEDY_USERNAME')} SPEEDY_PASSWORD=${env('SPEEDY_PASSWORD')} # email (order confirmations; leave empty to disable) SMTP_HOST=${env('SMTP_HOST')} SMTP_PORT=${env('SMTP_PORT', '587')} SMTP_USER=${env('SMTP_USER')} SMTP_PASS=${env('SMTP_PASS')} MAIL_FROM=${env('MAIL_FROM', 'shop@zlattea.com')} `; writeFileSync(join(process.cwd(), '.env'), envFile); console.log('setting up database...'); process.env.DB_PATH = dbPath; const db = getDb(); // applies schema + migration const seeded = seedProducts(); console.log(`products: ${seeded}`); const existing = db.query('SELECT id FROM users WHERE email = ?').get(adminEmail) as any; if (existing) { console.log('admin user already exists.'); } else { const hash = bcrypt.hashSync(adminPass, 10); db.run('INSERT INTO users (id, email, password_hash, name, is_admin) VALUES (?, ?, ?, ?, 1)', [crypto.randomUUID(), adminEmail, hash, 'Admin']); console.log('admin user created.'); } if (nostrPubkey) { db.run('UPDATE users SET nostr_pubkey = ? WHERE email = ?', [nostrPubkey, adminEmail]); } // default shipping config db.run("INSERT OR IGNORE INTO content (key, value) VALUES ('shipping_rate_per_kg', '500')"); db.run("INSERT OR IGNORE INTO content (key, value) VALUES ('free_shipping_threshold', '5000')"); console.log('default shipping: 5.00 EUR/kg, free over 50.00 EUR'); closeDb(); console.log('\nsetup complete. run: bun run build && bun run start\n'); } main().catch(e => { console.error(e); process.exit(1); });