4 Commits
Author SHA1 Message Date
NixReaper ba9e00d65b fix(seed): upsert admin so re-runs sync password from .env
Using findUnique+create skipped admin creation on re-runs, leaving
the password in .env out of sync with the DB hash after a failed
install. Upsert ensures the DB password always matches .env.
2026-04-12 05:05:04 -05:00
NixReaper aa9998cbd8 fix(installer): preserve secrets across re-runs
Re-running the installer after a failed build regenerated JWT_SECRET
and MARIADB_ROOT_PASS, overwriting .env with values that didn't match
the already-set MariaDB password. Now reads existing .env values and
only generates new ones on a fresh install.
2026-04-12 04:56:27 -05:00
NixReaper f9352617b0 fix(nixserver): widen SectionCard icon prop to accept Lucide components
Lucide icons type size as string | number but SectionCardProps declared
size as number only, causing TS2322 and failing the nixserver build.
2026-04-12 04:51:10 -05:00
NixReaper 17b0becc82 fix(installer): replace confirmation prompt with 5-second countdown
curl | bash pipes stdin so read gets EOF and returns non-zero, which
set -euo pipefail treats as an error and aborts immediately. Replaced
the interactive prompt with a sleep 5 countdown — works whether the
script is piped or run directly.

Bumps version to 0.6.3.
2026-04-12 04:44:07 -05:00
6 changed files with 55 additions and 23 deletions
+28
View File
@@ -6,6 +6,34 @@ Pre-1.0 versions treat MINOR as feature releases and PATCH as bug fixes.
--- ---
## [0.6.6] — 2026-04-12
### Bug Fixes
- **`seed.ts` skips admin on re-run** — `findUnique` + `create` meant re-running the seed after a failed install left the admin password in `.env` out of sync with the hashed password in the database. Changed to `upsert` so the seed always writes the current `.env` password, making re-runs safe.
---
## [0.6.5] — 2026-04-12
### Bug Fixes
- **`install.sh` regenerates secrets on re-run** — `JWT_SECRET`, `JWT_REFRESH_SECRET`, and `MARIADB_ROOT_PASS` were always generated fresh, so re-running the installer after a failed build overwrote `.env` with secrets that no longer matched the already-configured MariaDB password. The installer now reads existing values from `.env` (if present) and only generates new secrets when none exist.
---
## [0.6.4] — 2026-04-12
### Bug Fixes
- **`SectionCard.tsx` TypeScript build error** — `icon` prop typed as `ComponentType<{ size?: number }>` but Lucide icons declare `size?: string | number`. Widened the prop type to `size?: number | string` to match Lucide's `LucideProps`.
---
## [0.6.3] — 2026-04-12
### Bug Fixes
- **`install.sh` aborts immediately when piped via `curl | bash`** — Interactive confirmation prompt (`read`) received EOF from the pipe and exited non-zero, causing `set -euo pipefail` to kill the script before installation began. Replaced the prompt entirely with a 5-second countdown (`sleep 5`) so the installer works correctly whether piped or run from a file.
---
## [0.6.2] — 2026-04-12 ## [0.6.2] — 2026-04-12
### Bug Fixes ### Bug Fixes
+1 -1
View File
@@ -5,7 +5,7 @@ interface SectionCardProps {
label: string label: string
description?: string description?: string
to: string to: string
icon?: ComponentType<{ size?: number; className?: string }> icon?: ComponentType<{ size?: number | string; className?: string }>
comingSoon?: boolean comingSoon?: boolean
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "nixpanel-server", "name": "nixpanel-server",
"version": "0.6.2", "version": "0.6.6",
"private": true, "private": true,
"workspaces": [ "workspaces": [
"server", "server",
+16 -7
View File
@@ -82,11 +82,21 @@ if [[ -z "$ADMIN_EMAIL" ]]; then
ADMIN_EMAIL="admin@$(hostname -f 2>/dev/null || echo localhost)" ADMIN_EMAIL="admin@$(hostname -f 2>/dev/null || echo localhost)"
fi fi
# Redirect all interactive reads to /dev/tty so curl | bash works correctly # ── Preserve secrets across re-runs ──────────────────────────────────────────
# If .env already exists, reuse the same secrets so a failed-and-retried
# install doesn't leave MariaDB with a password that doesn't match .env.
_EXISTING_ENV="${INSTALL_DIR}/server/.env"
if [[ -f "$_EXISTING_ENV" ]]; then
_read_env() { grep -m1 "^$1=" "$_EXISTING_ENV" 2>/dev/null | cut -d= -f2- | tr -d '"'; }
MARIADB_ROOT_PASS=$(_read_env MARIADB_PASSWORD)
JWT_SECRET=$(_read_env JWT_SECRET)
JWT_REFRESH_SECRET=$(_read_env JWT_REFRESH_SECRET)
fi
MARIADB_ROOT_PASS=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 24) # Fill in any values that weren't in the existing .env (or first install)
JWT_SECRET=$(gen_secret) MARIADB_ROOT_PASS=${MARIADB_ROOT_PASS:-$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 24)}
JWT_REFRESH_SECRET=$(gen_secret) JWT_SECRET=${JWT_SECRET:-$(gen_secret)}
JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET:-$(gen_secret)}
# ── Confirm ─────────────────────────────────────────────────────────────────── # ── Confirm ───────────────────────────────────────────────────────────────────
echo -e "${BOLD}Installation summary:${RESET}" echo -e "${BOLD}Installation summary:${RESET}"
@@ -95,9 +105,8 @@ echo " Admin username : $ADMIN_USER"
echo " Admin email : $ADMIN_EMAIL" echo " Admin email : $ADMIN_EMAIL"
echo " Admin password : $([ "$GENERATED_PASS" = "true" ] && echo "<auto-generated>" || echo "$ADMIN_PASS")" echo " Admin password : $([ "$GENERATED_PASS" = "true" ] && echo "<auto-generated>" || echo "$ADMIN_PASS")"
echo "" echo ""
read -r -p "Continue? [Y/n] " CONFIRM < /dev/tty || CONFIRM="Y" echo " Starting in 5 seconds — press Ctrl+C to abort."
CONFIRM="${CONFIRM:-Y}" sleep 5
[[ "$CONFIRM" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 0; }
# ── Logging ─────────────────────────────────────────────────────────────────── # ── Logging ───────────────────────────────────────────────────────────────────
mkdir -p /var/log/nixpanel mkdir -p /var/log/nixpanel
+1 -1
View File
@@ -73,7 +73,7 @@ export async function buildApp() {
fastify.get('/api/health', async () => ({ fastify.get('/api/health', async () => ({
status: 'ok', status: 'ok',
version: '0.6.2', version: '0.6.6',
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
})) }))
+8 -13
View File
@@ -7,19 +7,14 @@ const prisma = new PrismaClient()
async function main() { async function main() {
console.log('Seeding database...') console.log('Seeding database...')
// Admin user // Admin user — upsert so re-runs always sync the password from .env
const existing = await prisma.adminUser.findUnique({ where: { username: config.admin.username } }) const hash = await bcrypt.hash(config.admin.password, 12)
if (!existing) { await prisma.adminUser.upsert({
const hash = await bcrypt.hash(config.admin.password, 12) where: { username: config.admin.username },
await prisma.adminUser.create({ update: { passwordHash: hash, email: config.admin.email },
data: { create: { username: config.admin.username, passwordHash: hash, email: config.admin.email },
username: config.admin.username, })
passwordHash: hash, console.log(`Admin user ready: ${config.admin.username}`)
email: config.admin.email,
},
})
console.log(`Created admin user: ${config.admin.username}`)
}
// Default packages // Default packages
const packages = [ const packages = [