import path from 'node:path' import { fileURLToPath } from 'node:url' import { validateAdminPasswordSetup } from './auth.js' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) // server/config.js is inside server/, so the project root is one level up export const ROOT_DIR = path.resolve(__dirname, '..') const DEFAULT_DATA_DIR = path.join(ROOT_DIR, 'data') const configuredDataDir = typeof process.env.SITEFORGE_DATA_DIR === 'string' ? process.env.SITEFORGE_DATA_DIR.trim() : '' export const DATA_DIR = configuredDataDir ? (path.isAbsolute(configuredDataDir) ? configuredDataDir : path.resolve(ROOT_DIR, configuredDataDir)) : DEFAULT_DATA_DIR export const DATA_FILE = path.join(DATA_DIR, 'admin-content.json') export const DRAFT_DATA_FILE = path.join(DATA_DIR, 'admin-content-draft.json') export const HIT_STATS_FILE = path.join(DATA_DIR, 'hit-stats.json') export const VISITOR_STATS_FILE = path.join(DATA_DIR, 'visitor-stats.json') export const CONTACT_SUBMISSIONS_FILE = path.join(DATA_DIR, 'contact-submissions.json') export const QUESTIONS_FILE = path.join(DATA_DIR, 'questions.json') export const DRAFT_QUESTIONS_FILE = path.join(DATA_DIR, 'questions-draft.json') export const STUDY_USERS_FILE = path.join(DATA_DIR, 'study-users.json') export const STUDY_NOTES_FILE = path.join(DATA_DIR, 'study-notes.json') // legacy — kept only for one-time migration export const STUDY_NOTES_DIR = path.join(DATA_DIR, 'study-notes') export const STUDY_PROGRESS_DIR = path.join(DATA_DIR, 'study-progress') export const STUDY_COMMUNITY_FILE = path.join(DATA_DIR, 'study-community.json') export const REPLY_TEMPLATES_FILE = path.join(DATA_DIR, 'admin-reply-templates.json') export const REPLY_HISTORY_FILE = path.join(DATA_DIR, 'admin-reply-history.json') export const PODCAST_CHECKLIST_FILE = path.join(DATA_DIR, 'podcast-checklist.json') export const BACKUP_DIR = path.join(DATA_DIR, 'backups') export const UPLOADS_DIR = path.join(DATA_DIR, 'uploads') export const UPLOADS_META_FILE = path.join(DATA_DIR, 'uploads-meta.json') export const DOWNLOAD_COUNTS_FILE = path.join(DATA_DIR, 'download-counts.json') export const STUDY_REMINDERS_FILE = path.join(DATA_DIR, 'study-reminders.json') export const STUDY_COMMENTS_FILE = path.join(DATA_DIR, 'study-section-comments.json') export const STUDY_CERTIFICATES_FILE = path.join(DATA_DIR, 'study-certificates.json') export const EPISODE_SCRIPTS_FILE = path.join(DATA_DIR, 'episode-scripts.json') export const QR_CODES_FILE = path.join(DATA_DIR, 'qr-codes.json') export const EPISODE_PLAYS_FILE = path.join(DATA_DIR, 'episode-plays.json') export const ANALYTICS_EVENTS_FILE = path.join(DATA_DIR, 'analytics-events.json') export const MAX_EPISODE_SCRIPT_LENGTH = 200_000 // ~150k words, well beyond any sermon export const DIST_DIR = path.join(ROOT_DIR, 'dist') export const INDEX_FILE = path.join(DIST_DIR, 'index.html') export const DIST_IMAGES_DIR = path.join(DIST_DIR, 'images') export const PUBLIC_IMAGES_DIR = path.join(ROOT_DIR, 'public', 'images') validateAdminPasswordSetup() export const TITUS_STUDY_FILE = process.env.TITUS_STUDY_FILE ? path.resolve(ROOT_DIR, process.env.TITUS_STUDY_FILE) : path.join(ROOT_DIR, 'A_Study_of_Titus.pdf') export const TITUS_STUDY_DOWNLOAD_NAME = process.env.TITUS_STUDY_DOWNLOAD_NAME ?? 'A_Study_of_Titus.pdf' // Rate limit / timing constants export const VISITOR_COOKIE = 'vbn_vid' export const CONSENT_COOKIE = 'vbn_analytics_consent' export const MAX_RECENT_VISITS = 1000 export const VISITOR_RETENTION_DAYS_DEFAULT = 180 export const BACKUP_RETENTION_DAYS = 30 export const BACKUP_INTERVAL_MS = 24 * 60 * 60 * 1000 export const ADMIN_SESSION_TTL_MS = 7 * 24 * 60 * 60 * 1000 export const MAX_CONTACT_SUBMISSIONS = 5000 export const CONTACT_EMAIL_COOLDOWN_MS = Math.max(10 * 1000, Number(process.env.CONTACT_EMAIL_COOLDOWN_MS ?? 60 * 1000) || 60 * 1000) export const DOWNLOAD_TOKEN_TTL_MS = 10 * 60 * 1000 export const MAX_QUESTIONS = 1000 export const MAX_STUDY_COMMENTS = 10000 export const MAX_STUDY_COMMENT_LENGTH = 2000 export const MAX_STUDY_USERS = 5000 export const MAX_STUDY_ENROLLMENTS_PER_USER = 100 export const MAX_STUDY_NOTES_PER_USER = 500 export const MAX_STUDY_NOTE_LENGTH = 12000 export const EMAIL_CHANGE_TOKEN_TTL_MS = 24 * 60 * 60 * 1000 export const STUDY_SESSION_COOKIE = 'vbn_study_session' export const STUDY_SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000 export const STUDY_TOTP_PENDING_TTL_MS = 5 * 60 * 1000 export const EMAIL_OTP_TTL_MS = 10 * 60 * 1000 export const EMAIL_OTP_MAX_ATTEMPTS = 5 export const USE_RESEND_AUTOMATION_WELCOME = process.env.RESEND_AUTOMATION_WELCOME === 'true' export const DEFAULT_RESEND_FROM = 'Verse by Verse with Nate ' export const DEFAULT_RESEND_TO = 'hello@versebyversewithnate.us' export const DEFAULT_RESEND_REPLY_TO = 'hello@versebyversewithnate.us' export const ADMIN_REPLY_FROM = DEFAULT_RESEND_FROM export const NATE_RESEND_FROM = 'Verse by Verse with Nate ' // Addresses an admin may send a reply from — must stay in sync with the