init
This commit is contained in:
1146
scripts/cleanup.js
Normal file
1146
scripts/cleanup.js
Normal file
File diff suppressed because it is too large
Load Diff
78
scripts/postinstall.js
Normal file
78
scripts/postinstall.js
Normal file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const cleanupPath = path.join(__dirname, 'cleanup.js');
|
||||
|
||||
// If cleanup.js is gone, self-clean: remove this file and restore dev script
|
||||
if (!fs.existsSync(cleanupPath)) {
|
||||
try {
|
||||
const pkgPath = path.join(__dirname, '..', 'package.json');
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||
if (pkg.scripts?.dev?.includes('postinstall.js')) {
|
||||
pkg.scripts.dev = 'next dev';
|
||||
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
||||
}
|
||||
fs.unlinkSync(__filename);
|
||||
} catch (_) {}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── ANSI colors ─────────────────────────────────────────────────────
|
||||
|
||||
const c = {
|
||||
r: '\x1b[0m', // reset
|
||||
d: '\x1b[2m', // dim
|
||||
b: '\x1b[1m', // bold
|
||||
cyan: '\x1b[36m',
|
||||
mag: '\x1b[35m',
|
||||
yel: '\x1b[33m',
|
||||
grn: '\x1b[32m',
|
||||
wht: '\x1b[37m',
|
||||
bgCyan: '\x1b[46m\x1b[30m'
|
||||
};
|
||||
|
||||
// ── Box drawing (ANSI-safe padding) ─────────────────────────────────
|
||||
|
||||
const W = 64;
|
||||
const strip = (s) => s.replace(/\x1b\[[0-9;]*m/g, '');
|
||||
const pad = (s, w) => s + ' '.repeat(Math.max(0, w - strip(s).length));
|
||||
const row = (text = '') => `${c.d}│${c.r} ${pad(text, W - 4)} ${c.d}│${c.r}`;
|
||||
const top = `${c.d}┌${'─'.repeat(W - 2)}┐${c.r}`;
|
||||
const bot = `${c.d}└${'─'.repeat(W - 2)}┘${c.r}`;
|
||||
const div = `${c.d}├${'─'.repeat(W - 2)}┤${c.r}`;
|
||||
|
||||
// ── Message ─────────────────────────────────────────────────────────
|
||||
|
||||
const msg = [
|
||||
'',
|
||||
top,
|
||||
row(),
|
||||
row(`${c.b}${c.mag} ✦ Shadcn Dashboard Starter${c.r}`),
|
||||
row(`${c.d} Feature Cleanup Available${c.r}`),
|
||||
row(),
|
||||
div,
|
||||
row(),
|
||||
row(`${c.wht}Trim optional features to fit your project:${c.r}`),
|
||||
row(),
|
||||
row(` ${c.yel}$${c.r} ${c.b}node scripts/cleanup.js --interactive${c.r}`),
|
||||
row(),
|
||||
row(`${c.d}Available modules:${c.r}`),
|
||||
row(
|
||||
` ${c.cyan}clerk${c.d} · ${c.cyan}kanban${c.d} · ${c.cyan}chat${c.d} · ${c.cyan}notifications${c.d} · ${c.cyan}themes${c.d} · ${c.cyan}sentry${c.r}`
|
||||
),
|
||||
row(),
|
||||
div,
|
||||
row(),
|
||||
row(`${c.grn}--dry-run${c.r} ${c.d}Preview changes without modifying files${c.r}`),
|
||||
row(`${c.grn}--list${c.r} ${c.d}Show all removable features${c.r}`),
|
||||
row(`${c.grn}--help${c.r} ${c.d}See all options${c.r}`),
|
||||
row(),
|
||||
row(`${c.d}Delete ${c.wht}scripts/cleanup.js${c.d} to remove this message.${c.r}`),
|
||||
row(),
|
||||
bot,
|
||||
''
|
||||
];
|
||||
|
||||
console.log(msg.join('\n'));
|
||||
142
scripts/seed-super-admin.js
Normal file
142
scripts/seed-super-admin.js
Normal file
@@ -0,0 +1,142 @@
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const postgres = require('postgres');
|
||||
|
||||
function loadEnvFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
for (const rawLine of content.split(/\r?\n/)) {
|
||||
const line = rawLine.trim();
|
||||
|
||||
if (!line || line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const separatorIndex = line.indexOf('=');
|
||||
|
||||
if (separatorIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = line.slice(0, separatorIndex).trim();
|
||||
let value = line.slice(separatorIndex + 1).trim();
|
||||
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
|
||||
if (!(key in process.env)) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadLocalEnv() {
|
||||
loadEnvFile(path.resolve(process.cwd(), '.env.local'));
|
||||
loadEnvFile(path.resolve(process.cwd(), '.env'));
|
||||
}
|
||||
|
||||
function requireEnv(name) {
|
||||
const value = process.env[name]?.trim();
|
||||
|
||||
if (!value) {
|
||||
throw new Error(`Missing required environment variable: ${name}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
loadLocalEnv();
|
||||
|
||||
const databaseUrl = requireEnv('DATABASE_URL');
|
||||
const email = requireEnv('SUPER_ADMIN_EMAIL').toLowerCase();
|
||||
const password = requireEnv('SUPER_ADMIN_PASSWORD');
|
||||
const name = process.env.SUPER_ADMIN_NAME?.trim() || 'Super Admin';
|
||||
const resetPassword = process.env.SUPER_ADMIN_RESET_PASSWORD === 'true';
|
||||
|
||||
if (password.length < 8) {
|
||||
throw new Error('SUPER_ADMIN_PASSWORD must be at least 8 characters long');
|
||||
}
|
||||
|
||||
const sql = postgres(databaseUrl, { prepare: false });
|
||||
|
||||
try {
|
||||
const existingUsers = await sql`
|
||||
select id, system_role
|
||||
from users
|
||||
where email = ${email}
|
||||
limit 1
|
||||
`;
|
||||
|
||||
const passwordHash = await bcrypt.hash(password, 10);
|
||||
|
||||
if (existingUsers.length === 0) {
|
||||
const id = crypto.randomUUID();
|
||||
|
||||
await sql`
|
||||
insert into users (
|
||||
id,
|
||||
name,
|
||||
email,
|
||||
password_hash,
|
||||
system_role,
|
||||
active_organization_id
|
||||
) values (
|
||||
${id},
|
||||
${name},
|
||||
${email},
|
||||
${passwordHash},
|
||||
${'super_admin'},
|
||||
${null}
|
||||
)
|
||||
`;
|
||||
|
||||
console.log(`Created super admin user: ${email}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const user = existingUsers[0];
|
||||
|
||||
if (resetPassword) {
|
||||
await sql`
|
||||
update users
|
||||
set
|
||||
name = ${name},
|
||||
system_role = ${'super_admin'},
|
||||
password_hash = ${passwordHash},
|
||||
updated_at = now()
|
||||
where id = ${user.id}
|
||||
`;
|
||||
|
||||
console.log(`Promoted and reset password for super admin user: ${email}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await sql`
|
||||
update users
|
||||
set
|
||||
name = ${name},
|
||||
system_role = ${'super_admin'},
|
||||
updated_at = now()
|
||||
where id = ${user.id}
|
||||
`;
|
||||
|
||||
console.log(`Ensured super admin role for user: ${email}`);
|
||||
} finally {
|
||||
await sql.end();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('[seed-super-admin] Failed:', error.message);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
Reference in New Issue
Block a user