|
|
|
@@ -0,0 +1,44 @@ |
|
|
|
// Bootstrap "stato di fabbrica" automatico all'avvio. |
|
|
|
// |
|
|
|
// Se all'avvio del server NON ci sono card in data/cards.txt (file mancante o `[]`) |
|
|
|
// E esiste factory/preset.zip, il preset viene estratto sopra a data/. |
|
|
|
// È quello che permette a una macchina appena clonata/distribuita di partire con |
|
|
|
// lo stato standard senza interventi manuali. |
|
|
|
|
|
|
|
import { readFile, access } from 'node:fs/promises'; |
|
|
|
import path from 'node:path'; |
|
|
|
import { restoreFromZipFile } from './restore-zip'; |
|
|
|
|
|
|
|
const PROJECT_ROOT = process.cwd(); |
|
|
|
const CARDS_FILE = path.join(PROJECT_ROOT, 'data', 'cards.txt'); |
|
|
|
const PRESET_PATH = path.join(PROJECT_ROOT, 'factory', 'preset.zip'); |
|
|
|
|
|
|
|
async function hasCards(): Promise<boolean> { |
|
|
|
try { |
|
|
|
const raw = await readFile(CARDS_FILE, 'utf-8'); |
|
|
|
const parsed = JSON.parse(raw || '[]'); |
|
|
|
return Array.isArray(parsed) && parsed.length > 0; |
|
|
|
} catch { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
export async function bootstrapFromFactoryPresetIfEmpty(): Promise<void> { |
|
|
|
// Niente preset di fabbrica → niente da fare, sezione opzionale. |
|
|
|
try { |
|
|
|
await access(PRESET_PATH); |
|
|
|
} catch { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Stato non vuoto → l'admin ha già contenuti, non sovrascriviamo. |
|
|
|
if (await hasCards()) return; |
|
|
|
|
|
|
|
console.log('[bootstrap] No cards found; restoring factory preset from factory/preset.zip'); |
|
|
|
const result = await restoreFromZipFile(PRESET_PATH); |
|
|
|
if (result.ok) { |
|
|
|
console.log(`[bootstrap] Restored ${result.cards} cards, ${result.portals} portals from factory preset`); |
|
|
|
} else { |
|
|
|
console.warn(`[bootstrap] Factory restore failed: ${result.error}${result.detail ? ` (${result.detail})` : ''}`); |
|
|
|
} |
|
|
|
} |