From 40c022c420a840241ebda5ffabde6dfa827da2bd Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Sat, 3 Jan 2026 09:49:50 -0500 Subject: [PATCH] config cleanup --- src/components/blog/TextEditor.tsx | 37 +++---- src/config.ts | 167 ++++------------------------- 2 files changed, 41 insertions(+), 163 deletions(-) diff --git a/src/components/blog/TextEditor.tsx b/src/components/blog/TextEditor.tsx index 55d554f..141345b 100644 --- a/src/components/blog/TextEditor.tsx +++ b/src/components/blog/TextEditor.tsx @@ -436,7 +436,7 @@ const SuggestionDecoration = Extension.create({ const interval = setInterval(() => { charIndex = (charIndex + 1) % spinnerChars.length; spinner.textContent = spinnerChars[charIndex]; - }, 50); + }, TEXT_EDITOR_CONFIG.SPINNER_INTERVAL_MS); // Store interval on element for cleanup (spinner as any)._spinnerInterval = interval; @@ -834,7 +834,6 @@ export default function TextEditor(props: TextEditorProps) { createSignal(-1); const [showHistoryModal, setShowHistoryModal] = createSignal(false); const [isLoadingHistory, setIsLoadingHistory] = createSignal(false); - const MAX_HISTORY_SIZE = 100; // Match database pruning limit let historyDebounceTimer: ReturnType | null = null; let isInitialLoad = true; // Flag to prevent capturing history on initial load let hasAttemptedHistoryLoad = false; // Flag to prevent repeated load attempts @@ -934,8 +933,8 @@ export default function TextEditor(props: TextEditorProps) { const requestBody = { input_prefix: context.prefix, input_suffix: context.suffix, - n_predict: 100, - temperature: 0.3, + n_predict: TEXT_EDITOR_CONFIG.INFILL_MAX_TOKENS, + temperature: TEXT_EDITOR_CONFIG.INFILL_TEMPERATURE, stop: ["\n\n", "", "<|endoftext|>"], stream: false }; @@ -1101,7 +1100,7 @@ export default function TextEditor(props: TextEditorProps) { mermaidValidationTimer = setTimeout(() => { validateAndPreviewMermaid(content); - }, 500); + }, TEXT_EDITOR_CONFIG.MERMAID_VALIDATION_DEBOUNCE_MS); }); // Capture history snapshot @@ -1139,8 +1138,10 @@ export default function TextEditor(props: TextEditorProps) { // Limit history size const limitedHistory = - updatedHistory.length > MAX_HISTORY_SIZE - ? updatedHistory.slice(updatedHistory.length - MAX_HISTORY_SIZE) + updatedHistory.length > TEXT_EDITOR_CONFIG.MAX_HISTORY_SIZE + ? updatedHistory.slice( + updatedHistory.length - TEXT_EDITOR_CONFIG.MAX_HISTORY_SIZE + ) : updatedHistory; setHistory(limitedHistory); @@ -1234,7 +1235,7 @@ export default function TextEditor(props: TextEditorProps) { // Scroll to first change after a brief delay to allow content to render setTimeout(() => { scrollToFirstChange(instance, oldContent, node.content); - }, 100); + }, TEXT_EDITOR_CONFIG.SCROLL_TO_CHANGE_DELAY_MS); }; // Find and scroll to the first difference between old and new content @@ -1359,11 +1360,11 @@ export default function TextEditor(props: TextEditorProps) { // Fade out and remove setTimeout(() => { highlight.style.opacity = "0"; - }, 100); + }, TEXT_EDITOR_CONFIG.HIGHLIGHT_FADE_DELAY_MS); setTimeout(() => { highlight.remove(); - }, 700); + }, TEXT_EDITOR_CONFIG.HIGHLIGHT_REMOVE_DELAY_MS); }; // Load history from database @@ -1570,7 +1571,7 @@ export default function TextEditor(props: TextEditorProps) { // This ensures infill works regardless of how content was loaded setTimeout(() => { isInitialLoad = false; - }, 1000); + }, TEXT_EDITOR_CONFIG.INITIAL_LOAD_DELAY_MS); // Listen for mermaid edit events editor.view.dom.addEventListener("edit-mermaid", ((e: CustomEvent) => { @@ -1719,9 +1720,9 @@ export default function TextEditor(props: TextEditorProps) { setTimeout(() => { renumberAllReferences(editor); updateReferencesSection(editor); - }, 100); + }, TEXT_EDITOR_CONFIG.REFERENCE_UPDATE_DELAY_MS); - // Debounced history capture (capture after 2 seconds of inactivity) + // Debounced history capture // Skip during initial load if (!isInitialLoad) { if (historyDebounceTimer) { @@ -1729,7 +1730,7 @@ export default function TextEditor(props: TextEditorProps) { } historyDebounceTimer = setTimeout(() => { captureHistory(editor); - }, 2000); + }, TEXT_EDITOR_CONFIG.HISTORY_DEBOUNCE_MS); } if (infillConfig() && !isInitialLoad && infillEnabled()) { @@ -1745,7 +1746,7 @@ export default function TextEditor(props: TextEditorProps) { } infillDebounceTimer = setTimeout(() => { requestInfill(); - }, 500); + }, TEXT_EDITOR_CONFIG.INFILL_DEBOUNCE_MS); } } }); @@ -1812,7 +1813,7 @@ export default function TextEditor(props: TextEditorProps) { setTimeout(() => { migrateLegacyReferences(instance); migrateLegacyMermaidBlocks(instance); - }, 50); + }, TEXT_EDITOR_CONFIG.LEGACY_MIGRATION_DELAY_MS); // Capture initial state in history only if no history was loaded setTimeout(() => { @@ -1829,12 +1830,12 @@ export default function TextEditor(props: TextEditorProps) { ); } isInitialLoad = false; - }, 200); + }, TEXT_EDITOR_CONFIG.INITIAL_HISTORY_CAPTURE_DELAY_MS); } else { // Content already matches - this is the initial load case setTimeout(() => { isInitialLoad = false; - }, 500); + }, TEXT_EDITOR_CONFIG.INITIAL_LOAD_FALLBACK_DELAY_MS); } } }, diff --git a/src/config.ts b/src/config.ts index 87ffaf5..e79c07b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,21 +8,13 @@ // ============================================================ export const AUTH_CONFIG = { - /** JWT token expiration for regular sessions (with remember me) */ JWT_EXPIRY: "14d" as const, - /** JWT token expiration for sessions without remember me */ JWT_EXPIRY_SHORT: "12h" as const, - /** Session cookie max age in seconds (14 days) */ SESSION_COOKIE_MAX_AGE: 60 * 60 * 24 * 14, // 14 days - /** Remember me cookie max age in seconds */ REMEMBER_ME_MAX_AGE: 60 * 60 * 24 * 14, // 14 days - /** CSRF token cookie max age in seconds (14 days) */ CSRF_TOKEN_MAX_AGE: 60 * 60 * 24 * 14, // 14 days - /** Email login link JWT expiration (15 minutes - provides reasonable time to check email without being too permissive) */ EMAIL_LOGIN_LINK_EXPIRY: "15m" as const, - /** Email verification link JWT expiration (15 minutes) */ EMAIL_VERIFICATION_LINK_EXPIRY: "15m" as const, - /** Lineage JWT expiration for mobile game */ LINEAGE_JWT_EXPIRY: "14d" as const } as const; @@ -31,15 +23,10 @@ export const AUTH_CONFIG = { // ============================================================ export const RATE_LIMITS = { - /** Login: 5 attempts per 15 minutes per IP */ LOGIN_IP: { maxAttempts: 5, windowMs: 15 * 60 * 1000 }, - /** Login: 5 attempts per hour per email */ LOGIN_EMAIL: { maxAttempts: 5, windowMs: 60 * 60 * 1000 }, - /** Password reset: 3 attempts per hour per IP */ PASSWORD_RESET_IP: { maxAttempts: 3, windowMs: 60 * 60 * 1000 }, - /** Registration: 3 attempts per hour per IP */ REGISTRATION_IP: { maxAttempts: 3, windowMs: 60 * 60 * 1000 }, - /** Email verification: 5 attempts per 15 minutes per IP */ EMAIL_VERIFICATION_IP: { maxAttempts: 5, windowMs: 15 * 60 * 1000 } } as const; @@ -51,14 +38,11 @@ export const RATE_LIMIT_CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // ============================================================ export const ACCOUNT_LOCKOUT = { - /** Maximum failed login attempts before account lockout */ MAX_FAILED_ATTEMPTS: 5, - /** Account lockout duration in milliseconds (5 minutes) */ LOCKOUT_DURATION_MS: 5 * 60 * 1000 } as const; export const PASSWORD_RESET_CONFIG = { - /** Password reset token expiry (1 hour) */ TOKEN_EXPIRY_MS: 60 * 60 * 1000 } as const; @@ -67,21 +51,14 @@ export const PASSWORD_RESET_CONFIG = { // ============================================================ export const COOLDOWN_TIMERS = { - /** Email login link cooldown (2 minutes) */ + // those without * 1000 are in seconds EMAIL_LOGIN_LINK_MS: 2 * 60 * 1000, - /** Email login link cookie max age in seconds */ EMAIL_LOGIN_LINK_COOKIE_MAX_AGE: 2 * 60, - /** Password reset request cooldown (5 minutes) */ PASSWORD_RESET_REQUEST_MS: 5 * 60 * 1000, - /** Password reset request cookie max age in seconds */ PASSWORD_RESET_REQUEST_COOKIE_MAX_AGE: 5 * 60, - /** Contact form request cooldown (1 minute) */ CONTACT_REQUEST_MS: 1 * 60 * 1000, - /** Contact form request cookie max age in seconds */ CONTACT_REQUEST_COOKIE_MAX_AGE: 1 * 60, - /** Email verification cooldown (15 minutes) */ EMAIL_VERIFICATION_MS: 15 * 60 * 1000, - /** Email verification cookie max age in seconds */ EMAIL_VERIFICATION_COOKIE_MAX_AGE: 15 * 60 } as const; @@ -90,15 +67,10 @@ export const COOLDOWN_TIMERS = { // ============================================================ export const CACHE_CONFIG = { - /** Blog cache TTL (24 hours) */ BLOG_CACHE_TTL_MS: 24 * 60 * 60 * 1000, - /** Git activity cache TTL (10 minutes) */ GIT_ACTIVITY_CACHE_TTL_MS: 10 * 60 * 1000, - /** Blog posts list cache TTL (5 minutes) */ BLOG_POSTS_LIST_CACHE_TTL_MS: 5 * 60 * 1000, - /** Maximum stale data age (7 days) */ MAX_STALE_DATA_MS: 7 * 24 * 60 * 60 * 1000, - /** Git activity max stale age (24 hours) */ GIT_ACTIVITY_MAX_STALE_MS: 24 * 60 * 60 * 1000 } as const; @@ -107,15 +79,10 @@ export const CACHE_CONFIG = { // ============================================================ export const NETWORK_CONFIG = { - /** Default API timeout for email service (15 seconds) */ - EMAIL_API_TIMEOUT_MS: 15000, - /** Default API timeout for GitHub OAuth (15 seconds) */ - GITHUB_API_TIMEOUT_MS: 15000, - /** Default API timeout for Google OAuth (15 seconds) */ - GOOGLE_API_TIMEOUT_MS: 15000, - /** Maximum retry attempts for failed requests */ + EMAIL_API_TIMEOUT_MS: 15 * 1000, + GITHUB_API_TIMEOUT_MS: 15 * 1000, + GOOGLE_API_TIMEOUT_MS: 15 * 1000, MAX_RETRIES: 2, - /** Retry delay between attempts (1 second) */ RETRY_DELAY_MS: 1000 } as const; @@ -124,23 +91,14 @@ export const NETWORK_CONFIG = { // ============================================================ export const TYPEWRITER_CONFIG = { - /** Default typing speed (characters per second) */ DEFAULT_SPEED: 30, - /** Fast typing speed */ FAST_SPEED: 80, - /** Slow typing speed */ SLOW_SPEED: 10, - /** Very slow typing speed */ VERY_SLOW_SPEED: 100, - /** Extra slow typing speed */ EXTRA_SLOW_SPEED: 120, - /** Default keep alive duration (ms) */ DEFAULT_KEEP_ALIVE_MS: 2000, - /** Long keep alive duration (ms) */ LONG_KEEP_ALIVE_MS: 10000, - /** Default initial delay (ms) */ DEFAULT_DELAY_MS: 500, - /** Cursor fade delay after completion (1 second) */ CURSOR_FADE_DELAY_MS: 1000 } as const; @@ -149,21 +107,14 @@ export const TYPEWRITER_CONFIG = { // ============================================================ export const COUNTDOWN_CONFIG = { - /** Email login link countdown duration (2 minutes) */ + // these are in seconds EMAIL_LOGIN_LINK_DURATION_S: 120, - /** Password reset countdown duration (5 minutes) */ PASSWORD_RESET_DURATION_S: 300, - /** Contact form countdown duration (1 minute) */ CONTACT_FORM_DURATION_S: 60, - /** Password reset success redirect countdown (5 seconds) */ PASSWORD_RESET_SUCCESS_DURATION_S: 5, - /** Default timer size (pixels) */ DEFAULT_TIMER_SIZE_PX: 48, - /** Large timer size (pixels) */ LARGE_TIMER_SIZE_PX: 200, - /** Default stroke width */ DEFAULT_STROKE_WIDTH: 6, - /** Large stroke width */ LARGE_STROKE_WIDTH: 12 } as const; @@ -172,11 +123,8 @@ export const COUNTDOWN_CONFIG = { // ============================================================ export const BREAKPOINTS = { - /** Mobile breakpoint (pixels) */ MOBILE_MAX_WIDTH: 768, - /** Tablet breakpoint (pixels) */ TABLET_MAX_WIDTH: 1024, - /** Desktop minimum width (pixels) */ DESKTOP_MIN_WIDTH: 1025 } as const; @@ -185,25 +133,15 @@ export const BREAKPOINTS = { // ============================================================ export const ANIMATION_CONFIG = { - /** Standard transition duration (ms) */ TRANSITION_DURATION_MS: 300, - /** Fast transition duration (ms) */ FAST_TRANSITION_MS: 200, - /** Slow transition duration (ms) */ SLOW_TRANSITION_MS: 500, - /** Extra slow transition duration (ms) */ EXTRA_SLOW_TRANSITION_MS: 600, - /** Sidebar toggle duration (ms) */ SIDEBAR_DURATION_MS: 500, - /** Menu typing effect delay (ms) */ MENU_TYPING_DELAY_MS: 140, - /** Menu initial delay (ms) */ MENU_INITIAL_DELAY_MS: 500, - /** Success message auto-hide duration (ms) */ SUCCESS_MESSAGE_DURATION_MS: 3000, - /** Error message auto-hide duration (ms) */ ERROR_MESSAGE_DURATION_MS: 5000, - /** Redirect delay after successful action (ms) */ REDIRECT_DELAY_MS: 500 } as const; @@ -212,7 +150,6 @@ export const ANIMATION_CONFIG = { // ============================================================ export const PDF_CONFIG = { - /** PDF rendering scale */ RENDER_SCALE: 1.5 } as const; @@ -221,11 +158,8 @@ export const PDF_CONFIG = { // ============================================================ export const ERROR_PAGE_CONFIG = { - /** Glitch effect interval (ms) */ GLITCH_INTERVAL_MS: 300, - /** Glitch effect duration (ms) */ GLITCH_DURATION_MS: 100, - /** Number of particles for background animation */ PARTICLE_COUNT: 45 } as const; @@ -243,7 +177,22 @@ export const MOBILE_CONFIG = { // ============================================================ export const TEXT_EDITOR_CONFIG = { - CONTEXT_SIZE: 256 + CONTEXT_SIZE: 256, + MAX_HISTORY_SIZE: 100, + HISTORY_DEBOUNCE_MS: 2000, + INFILL_DEBOUNCE_MS: 500, + INFILL_MAX_TOKENS: 100, + INFILL_TEMPERATURE: 0.3, + MERMAID_VALIDATION_DEBOUNCE_MS: 500, + LEGACY_MIGRATION_DELAY_MS: 50, + INITIAL_HISTORY_CAPTURE_DELAY_MS: 200, + INITIAL_LOAD_FALLBACK_DELAY_MS: 500, + INITIAL_LOAD_DELAY_MS: 1000, + SPINNER_INTERVAL_MS: 50, + HIGHLIGHT_FADE_DELAY_MS: 100, + HIGHLIGHT_REMOVE_DELAY_MS: 700, + REFERENCE_UPDATE_DELAY_MS: 100, + SCROLL_TO_CHANGE_DELAY_MS: 100 } as const; // ============================================================ @@ -251,17 +200,12 @@ export const TEXT_EDITOR_CONFIG = { // ============================================================ export const VALIDATION_CONFIG = { - /** Minimum password length (must match securePasswordSchema in schemas/user.ts) */ MIN_PASSWORD_LENGTH: 8, - /** Require at least one uppercase letter in password */ PASSWORD_REQUIRE_UPPERCASE: true, - /** Require at least one number in password */ PASSWORD_REQUIRE_NUMBER: true, - /** Require at least one special character in password (false = optional but recommended) */ + // changed to just recommended, may change again in future PASSWORD_REQUIRE_SPECIAL: false, - /** Maximum message length for contact form */ MAX_CONTACT_MESSAGE_LENGTH: 500, - /** Minimum password confirmation match length before showing error */ MIN_PASSWORD_CONF_LENGTH_FOR_ERROR: 6 } as const; @@ -270,9 +214,7 @@ export const VALIDATION_CONFIG = { // ============================================================ export const LINEAGE_CONFIG = { - /** Database deletion grace period (24 hours) */ DELETION_GRACE_PERIOD_MS: 24 * 60 * 60 * 1000, - /** PvP opponents returned per query */ PVP_OPPONENTS_COUNT: 3 } as const; @@ -281,71 +223,6 @@ export const LINEAGE_CONFIG = { // ============================================================ export const AUDIT_CONFIG = { - /** Default query limit for audit logs */ DEFAULT_QUERY_LIMIT: 100, - /** Maximum audit log retention (90 days) */ MAX_RETENTION_DAYS: 90 } as const; - -// ============================================================ -// HELPER FUNCTIONS -// ============================================================ - -/** - * Convert milliseconds to seconds - */ -export function msToSeconds(ms: number): number { - return Math.floor(ms / 1000); -} - -/** - * Convert seconds to milliseconds - */ -export function secondsToMs(seconds: number): number { - return seconds * 1000; -} - -/** - * Convert minutes to milliseconds - */ -export function minutesToMs(minutes: number): number { - return minutes * 60 * 1000; -} - -/** - * Convert hours to milliseconds - */ -export function hoursToMs(hours: number): number { - return hours * 60 * 60 * 1000; -} - -/** - * Convert days to milliseconds - */ -export function daysToMs(days: number): number { - return days * 24 * 60 * 60 * 1000; -} - -/** - * Check if screen width is mobile - */ -export function isMobileWidth(width: number): boolean { - return width < BREAKPOINTS.MOBILE_MAX_WIDTH; -} - -/** - * Check if screen width is tablet - */ -export function isTabletWidth(width: number): boolean { - return ( - width >= BREAKPOINTS.MOBILE_MAX_WIDTH && - width <= BREAKPOINTS.TABLET_MAX_WIDTH - ); -} - -/** - * Check if screen width is desktop - */ -export function isDesktopWidth(width: number): boolean { - return width >= BREAKPOINTS.DESKTOP_MIN_WIDTH; -}