fix: remove "type" field from package.json + improve setup.sh

- Remove "type": "commonjs" from package.json — fixes Turbopack
  ESM/CommonJS conflict causing white screen in dev mode
- setup.sh: auto-generate passwords (PostgreSQL, MinIO, auth secret)
- setup.sh: auto-install Docker/Node.js if missing (apt/nvm/brew)
- setup.sh: backup existing .env before overwrite
- setup.sh: create MinIO bucket via curl if mc not installed
- setup.sh: add timeout errors for service readiness checks
- setup.sh: include pgbouncer in local dev docker compose up

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 02:21:40 +03:00
parent cb589b540a
commit 7f9c521fed
2 changed files with 176 additions and 39 deletions

214
setup.sh
View File

@@ -64,6 +64,12 @@ generate_secret() {
openssl rand -base64 32 2>/dev/null || head -c 32 /dev/urandom | base64 | tr -d '=/+' | head -c 32
}
generate_password() {
# 20 символов: буквы + цифры (безопасно для URL и CLI)
openssl rand -base64 24 2>/dev/null | tr -d '=/+' | head -c 20 || \
head -c 24 /dev/urandom | base64 | tr -d '=/+' | head -c 20
}
check_command() {
if command -v "$1" &>/dev/null; then
log_ok "$1 найден: $(command -v "$1")"
@@ -74,21 +80,87 @@ check_command() {
fi
}
install_if_missing() {
local cmd="$1" install_hint="$2"
if command -v "$cmd" &>/dev/null; then
log_ok "$cmd найден: $(command -v "$cmd")"
return 0
fi
log_warn "$cmd не найден"
# Попытка автоустановки через системные менеджеры
if [[ "$cmd" == "node" || "$cmd" == "npm" || "$cmd" == "npx" ]]; then
if command -v nvm &>/dev/null; then
echo -e " Установка Node.js через nvm..."
nvm install --lts 2>&1 | tail -3
if command -v "$cmd" &>/dev/null; then
log_ok "$cmd установлен через nvm"
return 0
fi
fi
fi
# Автоустановка через apt/yum/brew если доступно
case "$cmd" in
docker)
if command -v apt-get &>/dev/null; then
if ask_yn "Установить Docker автоматически (apt)?" "y"; then
echo -e " Установка Docker..."
curl -fsSL https://get.docker.com | sh 2>&1 | tail -5
sudo usermod -aG docker "$USER" 2>/dev/null || true
if command -v docker &>/dev/null; then
log_ok "Docker установлен"
return 0
fi
fi
fi
;;
node|npm|npx)
if command -v apt-get &>/dev/null; then
if ask_yn "Установить Node.js 22 автоматически (apt)?" "y"; then
echo -e " Установка Node.js..."
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - 2>&1 | tail -3
sudo apt-get install -y nodejs 2>&1 | tail -3
if command -v "$cmd" &>/dev/null; then
log_ok "$cmd установлен"
return 0
fi
fi
elif command -v brew &>/dev/null; then
if ask_yn "Установить Node.js через Homebrew?" "y"; then
brew install node 2>&1 | tail -3
if command -v "$cmd" &>/dev/null; then
log_ok "$cmd установлен"
return 0
fi
fi
fi
;;
esac
log_err "$cmd не удалось установить автоматически"
echo -e " ${YELLOW}Установи вручную:${NC} $install_hint"
return 1
}
# ============================================================
# Main
# ============================================================
print_banner
# --- Step 1: Check dependencies ---
log_step "Шаг 1/6 — Проверка зависимостей"
# --- Step 1: Check & install dependencies ---
log_step "Шаг 1/6 — Проверка и установка зависимостей"
MISSING=0
check_command docker || MISSING=1
check_command "docker compose" 2>/dev/null || check_command docker-compose || MISSING=1
check_command node || MISSING=1
check_command npm || MISSING=1
check_command npx || MISSING=1
install_if_missing docker "https://docs.docker.com/get-docker/" || MISSING=1
check_command "docker compose" 2>/dev/null || check_command docker-compose 2>/dev/null || {
log_err "docker compose не найден (нужен Docker Compose V2)"
MISSING=1
}
install_if_missing node "https://nodejs.org/" || MISSING=1
install_if_missing npm "https://nodejs.org/" || MISSING=1
if [[ "$MISSING" -eq 1 ]]; then
log_err "Установи недостающие зависимости и запусти скрипт снова."
@@ -137,39 +209,66 @@ fi
# --- Step 3: Configure environment ---
log_step "Шаг 3/6 — Настройка окружения"
echo ""
echo -e " ${BOLD}PostgreSQL${NC}"
ask "Пароль PostgreSQL" "postgres" PG_PASSWORD
# Автогенерация паролей
PG_PASSWORD=$(generate_password)
MINIO_USER="minio-$(head -c 4 /dev/urandom | xxd -p)"
MINIO_PASS=$(generate_password)
AUTH_SECRET=$(generate_secret)
DEV_ACCESS_KEY=$(generate_password | head -c 16)
S3_BUCKET="liveserver"
echo ""
echo -e " ${BOLD}MinIO (S3 Storage)${NC}"
ask "MinIO root user" "minioadmin" MINIO_USER
ask_secret "MinIO root password" "minioadmin" MINIO_PASS
ask "Название S3 bucket" "liveserver" S3_BUCKET
echo -e " ${GREEN}${BOLD}Пароли сгенерированы автоматически:${NC}"
echo -e " ${CYAN}PostgreSQL:${NC} ${PG_PASSWORD}"
echo -e " ${CYAN}MinIO user:${NC} ${MINIO_USER}"
echo -e " ${CYAN}MinIO password:${NC} ${MINIO_PASS}"
echo -e " ${CYAN}Auth secret:${NC} ${AUTH_SECRET:0:16}..."
if [[ "$MODE" == "1" ]]; then
echo -e " ${CYAN}DEV_ACCESS_KEY:${NC} ${DEV_ACCESS_KEY}"
fi
echo ""
echo -e " ${YELLOW}Все пароли сохранены в .env — можешь изменить позже${NC}"
if ask_yn "Хочешь задать свои пароли вместо сгенерированных?" "n"; then
echo ""
echo -e " ${BOLD}PostgreSQL${NC}"
ask "Пароль PostgreSQL" "$PG_PASSWORD" PG_PASSWORD
echo ""
echo -e " ${BOLD}MinIO (S3 Storage)${NC}"
ask "MinIO root user" "$MINIO_USER" MINIO_USER
ask_secret "MinIO root password" "$MINIO_PASS" MINIO_PASS
ask "Название S3 bucket" "$S3_BUCKET" S3_BUCKET
if [[ "$MODE" == "1" ]]; then
echo ""
echo -e " ${BOLD}Защита локалки${NC}"
ask "Ключ доступа (DEV_ACCESS_KEY)" "$DEV_ACCESS_KEY" DEV_ACCESS_KEY
fi
fi
echo ""
echo -e " ${BOLD}LiveKit${NC}"
echo -e " ${BOLD}LiveKit${NC} (Enter чтобы пропустить, настроишь позже)"
ask "LiveKit URL (wss://...)" "" LK_URL
ask "LiveKit API Key" "" LK_KEY
ask_secret "LiveKit API Secret" "" LK_SECRET
ask_secret "LiveKit Webhook Secret (Enter чтобы пропустить)" "" LK_WEBHOOK
LK_KEY=""
LK_SECRET=""
LK_WEBHOOK=""
if [[ -n "$LK_URL" ]]; then
ask "LiveKit API Key" "" LK_KEY
ask_secret "LiveKit API Secret" "" LK_SECRET
ask_secret "LiveKit Webhook Secret (Enter = пропустить)" "" LK_WEBHOOK
fi
echo ""
echo -e " ${BOLD}AI Agent (Enter чтобы пропустить, настроишь позже)${NC}"
echo -e " ${BOLD}AI Agent${NC} (Enter чтобы пропустить, настроишь позже)"
ask_secret "Deepgram API Key" "" DG_KEY
ask_secret "OpenAI API Key" "" OAI_KEY
echo ""
echo -e " ${BOLD}Аутентификация${NC}"
AUTH_SECRET=$(generate_secret)
log_ok "Сгенерирован BETTER_AUTH_SECRET"
if [[ "$MODE" == "1" ]]; then
DEV_KEY=$(generate_secret | head -c 16)
echo ""
echo -e " ${BOLD}Защита локалки${NC}"
ask "Ключ доступа (DEV_ACCESS_KEY)" "$DEV_KEY" DEV_ACCESS_KEY
ask "Разрешённые IP (через запятую, Enter = все)" "" ALLOWED_IPS
ALLOWED_IPS=""
if ask_yn "Ограничить доступ по IP? (кроме localhost)" "n"; then
ask "Разрешённые IP (через запятую)" "" ALLOWED_IPS
fi
fi
# --- Step 4: Generate .env ---
@@ -183,8 +282,15 @@ else
S3_ENDPOINT="http://localhost:9000"
fi
# Бэкап существующего .env
if [[ -f .env ]]; then
cp .env ".env.backup.$(date +%Y%m%d_%H%M%S)"
log_ok "Бэкап старого .env создан"
fi
cat > .env << ENVEOF
# === Generated by setup.sh at $(date) ===
# Все пароли сгенерированы автоматически — можешь заменить на свои.
# Domain & SSL
DOMAIN=${DOMAIN}
@@ -195,8 +301,8 @@ DATABASE_URL=postgresql://postgres:${PG_PASSWORD}@localhost:5432/liveserver
POSTGRES_PASSWORD=${PG_PASSWORD}
# Redis
# For Docker containers: redis://redis:6379
# For local npm run dev: redis://localhost:6379
# Для Docker контейнеров: redis://redis:6379
# Для локального npm run dev: redis://localhost:6379
REDIS_URL=redis://localhost:6379
# LiveKit
@@ -232,13 +338,17 @@ log_ok ".env создан"
# --- Step 5: Install & setup ---
log_step "Шаг 5/6 — Установка и настройка"
# npm install
# npm install — автоматически если нет node_modules или package-lock изменился
if [[ ! -d "node_modules" ]]; then
echo -e " Установка npm зависимостей..."
npm install --silent 2>&1 | tail -3
log_ok "npm install"
npm install 2>&1 | tail -5
log_ok "npm install завершён"
elif [[ "package.json" -nt "node_modules/.package-lock.json" ]] 2>/dev/null; then
echo -e " package.json обновлён, переустановка зависимостей..."
npm install 2>&1 | tail -5
log_ok "npm install завершён (обновление)"
else
log_ok "node_modules уже существует"
log_ok "node_modules актуален"
fi
# Prisma generate
@@ -251,7 +361,7 @@ echo -e " Запуск Docker контейнеров..."
if [[ "$MODE" == "2" ]]; then
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build 2>&1 | tail -5
else
docker compose up -d postgres minio redis 2>&1 | tail -5
docker compose up -d postgres minio redis pgbouncer 2>&1 | tail -5
fi
log_ok "Docker контейнеры запущены"
@@ -261,6 +371,10 @@ for i in $(seq 1 30); do
if docker compose exec -T postgres pg_isready -U postgres &>/dev/null; then
break
fi
if [[ "$i" -eq 30 ]]; then
log_err "PostgreSQL не запустился за 30 секунд"
exit 1
fi
sleep 1
done
log_ok "PostgreSQL готов"
@@ -271,6 +385,10 @@ for i in $(seq 1 15); do
if docker compose exec -T redis redis-cli ping 2>/dev/null | grep -q PONG; then
break
fi
if [[ "$i" -eq 15 ]]; then
log_err "Redis не запустился за 15 секунд"
exit 1
fi
sleep 1
done
log_ok "Redis готов"
@@ -281,6 +399,9 @@ for i in $(seq 1 15); do
if docker compose exec -T pgbouncer pg_isready -h 127.0.0.1 -p 6432 &>/dev/null; then
break
fi
if [[ "$i" -eq 15 ]]; then
log_warn "PgBouncer не отвечает — продолжаем без него"
fi
sleep 1
done
log_ok "PgBouncer готов"
@@ -290,7 +411,7 @@ echo -e " Применение миграций..."
npx prisma db push --skip-generate 2>&1 | tail -3
log_ok "Схема БД синхронизирована"
# Create MinIO bucket
# Create MinIO bucket (через docker exec если mc не установлен)
echo -e " Создание S3 bucket..."
sleep 2
if command -v mc &>/dev/null; then
@@ -298,7 +419,15 @@ if command -v mc &>/dev/null; then
mc mb "local/${S3_BUCKET}" 2>/dev/null || true
log_ok "Bucket '${S3_BUCKET}' создан"
else
log_warn "MinIO Client (mc) не найден — создай bucket '${S3_BUCKET}' вручную через http://localhost:9001"
# Создание через curl (MinIO S3 API)
if curl -sf -o /dev/null -X PUT "http://localhost:9000/${S3_BUCKET}" \
-u "${MINIO_USER}:${MINIO_PASS}" 2>/dev/null; then
log_ok "Bucket '${S3_BUCKET}' создан через API"
else
log_warn "Не удалось создать bucket автоматически"
echo -e " Создай вручную: ${CYAN}http://localhost:9001${NC} → Buckets → Create"
echo -e " Логин: ${CYAN}${MINIO_USER}${NC} / пароль в .env"
fi
fi
# --- Step 6: Done ---
@@ -326,6 +455,15 @@ else
fi
fi
echo ""
echo -e " ${BOLD}Сгенерированные пароли (сохранены в .env):${NC}"
echo -e " ${CYAN}PostgreSQL:${NC} ${PG_PASSWORD}"
echo -e " ${CYAN}MinIO:${NC} ${MINIO_USER} / ${MINIO_PASS}"
if [[ "$MODE" == "1" && -n "${DEV_ACCESS_KEY:-}" ]]; then
echo -e " ${CYAN}DEV_ACCESS_KEY:${NC} ${DEV_ACCESS_KEY}"
fi
echo -e " ${YELLOW}Изменить пароли: отредактируй .env и перезапусти docker compose${NC}"
if [[ -z "$LK_URL" ]]; then
echo ""
log_warn "LiveKit не настроен — видеозвонки не будут работать."