Spaces:
Sleeping
Sleeping
| import 'dotenv/config'; | |
| export const config = { | |
| // Supabase | |
| supabaseUrl: process.env.SUPABASE_URL || '', | |
| supabaseServiceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY || '', | |
| // Worker | |
| workerId: process.env.WORKER_ID || `worker-${process.pid}`, | |
| maxWorkers: parseInt(process.env.MAX_WORKERS || '2', 10), | |
| pollIntervalMs: parseInt(process.env.POLL_INTERVAL_MS || '3000', 10), | |
| // Turnitin | |
| turnitinSharedPassword: process.env.TURNITIN_SHARED_PASSWORD || '', | |
| credentialEncryptionKey: process.env.TURNITIN_CREDENTIAL_ENCRYPTION_KEY || '', | |
| turnitinTargetUrl: | |
| process.env.TARGET_URL || | |
| 'https://www.turnitin.com/login_page.asp?lang=en_us', | |
| turnitinClassTitle: process.env.CLASS_TITLE || 'Summer Reading 2026', | |
| turnitinAssignmentTitle: process.env.ASSIGNMENT_TITLE || 'HTLLP notes', | |
| // Playwright | |
| headless: process.env.PLAYWRIGHT_HEADLESS !== 'false', | |
| // Storage buckets | |
| inputBucket: process.env.INPUT_BUCKET || 'turnitin-inputs', | |
| reportBucket: process.env.REPORT_BUCKET || 'turnitin-reports', | |
| diagnosticsBucket: process.env.DIAGNOSTICS_BUCKET || 'turnitin-diagnostics', | |
| sessionBucket: process.env.SESSION_BUCKET || 'turnitin-sessions', | |
| // Cron intervals (minutes) | |
| quotaCheckInterval: parseInt(process.env.QUOTA_CHECK_INTERVAL || '30', 10), | |
| quotaCheckAccountDelayMs: parseInt( | |
| process.env.QUOTA_CHECK_ACCOUNT_DELAY_MS || String(5 * 60 * 1000), | |
| 10, | |
| ), | |
| quotaCheckOrder: process.env.QUOTA_CHECK_ORDER === 'newest' ? 'newest' : 'oldest', | |
| cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '15', 10), | |
| staleRecoveryInterval: parseInt(process.env.STALE_RECOVERY_INTERVAL || '5', 10), | |
| // Report | |
| reportRetentionHours: parseInt(process.env.REPORT_RETENTION_HOURS || '24', 10), | |
| // Server | |
| port: parseInt(process.env.PORT || '7860', 10), | |
| internalSecret: process.env.INTERNAL_SECRET || '', | |
| allowedOrigins: (process.env.ALLOWED_ORIGINS || process.env.FRONTEND_ORIGIN || '') | |
| .split(',') | |
| .map((origin) => origin.trim()) | |
| .filter(Boolean), | |
| enableWorker: process.env.ENABLE_WORKER !== 'false', | |
| enableCron: process.env.ENABLE_CRON !== 'false', | |
| // Timeouts | |
| similarityTimeoutMs: parseInt(process.env.SIMILARITY_TIMEOUT_MS || '180000', 10), | |
| similarityPollMs: parseInt(process.env.SIMILARITY_POLL_MS || '5000', 10), | |
| similarityRefreshAfterMs: parseInt(process.env.SIMILARITY_REFRESH_AFTER_MS || '90000', 10), | |
| // BUG-10 FIX: leaseMinutes was hardcoded to 20 min — shorter than the combined | |
| // time for login + navigate + similarity wait (up to 30+ min). Stale recovery | |
| // could reset an account that is still being actively used. | |
| leaseMinutes: parseInt(process.env.LEASE_MINUTES || '35', 10), | |
| } as const; | |
| /** Validate required environment variables at startup */ | |
| export function validateConfig(): void { | |
| const required: (keyof typeof config)[] = [ | |
| 'supabaseUrl', | |
| 'supabaseServiceRoleKey', | |
| 'turnitinSharedPassword', | |
| ]; | |
| const missing = required.filter((key) => !config[key]); | |
| if (missing.length > 0) { | |
| throw new Error(`Missing required environment variables: ${missing.join(', ')}`); | |
| } | |
| } | |