Files
Haven/src/paths.js
T
ancsemi 5a11a910b3 feat: move all user data to external directory (%APPDATA%\Haven or ~/.haven)
- Database, .env, certs, and uploads now stored outside the code directory
- Auto-migration moves existing data from old locations on first launch
- SSL certs auto-detected in data dir (no .env config needed)
- New src/paths.js module as single source of truth for all data paths
- HAVEN_DATA_DIR env var for custom data location override
- Updated Start Haven.bat, start.sh, README, GUIDE, .env.example
- Bumped version to 1.1.0
2026-02-11 16:52:46 -05:00

94 lines
3.0 KiB
JavaScript

/**
* Haven — Centralised data-directory resolution
*
* All user data (database, .env, certs, uploads) lives OUTSIDE the
* application folder so the code directory can never accidentally
* leak personal data — even if someone copies the whole folder,
* force-adds files, or pushes to a public repo.
*
* Locations:
* Windows : %APPDATA%\Haven\ (e.g. C:\Users\you\AppData\Roaming\Haven)
* Linux : ~/.haven/
* macOS : ~/.haven/
*
* Override : set HAVEN_DATA_DIR env var to any absolute path.
*/
const path = require('path');
const fs = require('fs');
const os = require('os');
function getDataDir() {
// Allow explicit override via environment variable
if (process.env.HAVEN_DATA_DIR) {
const custom = path.resolve(process.env.HAVEN_DATA_DIR);
fs.mkdirSync(custom, { recursive: true });
return custom;
}
let base;
if (process.platform === 'win32') {
// %APPDATA% → C:\Users\<user>\AppData\Roaming
base = path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Haven');
} else {
// Linux / macOS → ~/.haven
base = path.join(os.homedir(), '.haven');
}
fs.mkdirSync(base, { recursive: true });
return base;
}
// Pre-computed paths for convenience
const DATA_DIR = getDataDir();
const DB_PATH = path.join(DATA_DIR, 'haven.db');
const ENV_PATH = path.join(DATA_DIR, '.env');
const CERTS_DIR = path.join(DATA_DIR, 'certs');
const UPLOADS_DIR = path.join(DATA_DIR, 'uploads');
// Ensure sub-directories exist
fs.mkdirSync(CERTS_DIR, { recursive: true });
fs.mkdirSync(UPLOADS_DIR, { recursive: true });
// ── One-time migration: move data from old project-dir locations ─────
const PROJECT_ROOT = path.join(__dirname, '..');
function migrateFile(oldRel, newAbs) {
const oldAbs = path.join(PROJECT_ROOT, oldRel);
if (fs.existsSync(oldAbs) && !fs.existsSync(newAbs)) {
try {
fs.copyFileSync(oldAbs, newAbs);
fs.unlinkSync(oldAbs);
console.log(`📦 Migrated ${oldRel} → ${newAbs}`);
} catch { /* silent — might lack permissions */ }
}
}
function migrateDir(oldRel, newDir) {
const oldAbs = path.join(PROJECT_ROOT, oldRel);
if (fs.existsSync(oldAbs)) {
try {
const entries = fs.readdirSync(oldAbs);
for (const entry of entries) {
if (entry === '.gitkeep') continue;
const src = path.join(oldAbs, entry);
const dst = path.join(newDir, entry);
if (!fs.existsSync(dst) && fs.statSync(src).isFile()) {
fs.copyFileSync(src, dst);
fs.unlinkSync(src);
console.log(`📦 Migrated ${oldRel}/${entry} → ${dst}`);
}
}
} catch { /* silent */ }
}
}
migrateFile('haven.db', DB_PATH);
migrateFile('haven.db-shm', DB_PATH + '-shm');
migrateFile('haven.db-wal', DB_PATH + '-wal');
migrateFile('.env', ENV_PATH);
migrateDir('certs', CERTS_DIR);
migrateDir('public/uploads', UPLOADS_DIR);
module.exports = { getDataDir, DATA_DIR, DB_PATH, ENV_PATH, CERTS_DIR, UPLOADS_DIR };