diff --git a/src/app.tsx b/src/app.tsx index 1d7cf23..ac6aff0 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -114,7 +114,6 @@ function AppLayout(props: { children: any }) { if (Math.abs(deltaX) > Math.abs(deltaY)) { // Mobile: Only left bar if (currentIsMobile) { - // Swipe right anywhere - reveal left bar if (deltaX > SWIPE_THRESHOLD) { setLeftBarVisible(true); } @@ -124,7 +123,6 @@ function AppLayout(props: { children: any }) { } } else { // Desktop: Both bars - // Swipe right anywhere - reveal left bar if (deltaX > SWIPE_THRESHOLD) { setLeftBarVisible(true); } diff --git a/src/components/DeletionForm.tsx b/src/components/DeletionForm.tsx index e4983fc..18d9a20 100644 --- a/src/components/DeletionForm.tsx +++ b/src/components/DeletionForm.tsx @@ -4,7 +4,6 @@ import LoadingSpinner from "~/components/LoadingSpinner"; import { getClientCookie } from "~/lib/cookies.client"; export default function DeletionForm() { - // State management const [countDown, setCountDown] = createSignal(0); const [emailSent, setEmailSent] = createSignal(false); const [error, setError] = createSignal(""); @@ -30,7 +29,6 @@ export default function DeletionForm() { } }; - // Check for existing timer on mount createEffect(() => { const timer = getClientCookie("deletionRequestSent"); if (timer) { @@ -46,7 +44,6 @@ export default function DeletionForm() { } }); - // Form submission handler const sendEmailTrigger = async (e: Event) => { e.preventDefault(); setLoading(true); diff --git a/src/components/blog/CommentBlock.tsx b/src/components/blog/CommentBlock.tsx index 4a86b98..23b488a 100644 --- a/src/components/blog/CommentBlock.tsx +++ b/src/components/blog/CommentBlock.tsx @@ -25,7 +25,6 @@ import ReactionBar from "./ReactionBar"; export default function CommentBlock(props: CommentBlockProps) { const location = useLocation(); - // State signals const [commentCollapsed, setCommentCollapsed] = createSignal(false); const [showingReactionOptions, setShowingReactionOptions] = createSignal(false); diff --git a/src/components/blog/CommentSectionWrapper.tsx b/src/components/blog/CommentSectionWrapper.tsx index c724898..516ae3e 100644 --- a/src/components/blog/CommentSectionWrapper.tsx +++ b/src/components/blog/CommentSectionWrapper.tsx @@ -22,7 +22,6 @@ const RETRY_INTERVAL = 5000; export default function CommentSectionWrapper( props: CommentSectionWrapperProps ) { - // State signals const [allComments, setAllComments] = createSignal( props.allComments ); @@ -57,14 +56,12 @@ export default function CommentSectionWrapper( const [commentBodyForModification, setCommentBodyForModification] = createSignal(""); - // Non-reactive refs (store without triggering reactivity) let userCommentMap: Map = props.userCommentMap; let deletePromptRef: HTMLDivElement | undefined; let modificationPromptRef: HTMLDivElement | undefined; let retryCount = 0; let socket: WebSocket | undefined; - // WebSocket connection effect createEffect(() => { const connect = () => { if (socket) return; @@ -121,7 +118,6 @@ export default function CommentSectionWrapper( connect(); - // Cleanup on unmount onCleanup(() => { if (socket?.readyState === WebSocket.OPEN) { socket.close(); @@ -130,7 +126,6 @@ export default function CommentSectionWrapper( }); }); - // Helper functions const updateChannel = () => { if (!socket || socket.readyState !== WebSocket.OPEN) { return; @@ -155,7 +150,6 @@ export default function CommentSectionWrapper( } }; - // Comment creation const newComment = async (commentBody: string, parentCommentID?: number) => { setCommentSubmitLoading(true); @@ -179,11 +173,9 @@ export default function CommentSectionWrapper( ); } catch (error) { console.error("Error sending comment creation:", error); - // Fallback to HTTP API on WebSocket error await fallbackCommentCreation(commentBody, parentCommentID); } } else { - // Fallback to HTTP API if WebSocket unavailable await fallbackCommentCreation(commentBody, parentCommentID); } }; @@ -254,7 +246,6 @@ export default function CommentSectionWrapper( } setAllComments((prevComments) => [...(prevComments || []), newComment]); - // Update user comment map const existingIDs = Array.from(userCommentMap.entries()).find( ([key, _]) => key.email === userData.email && @@ -272,7 +263,6 @@ export default function CommentSectionWrapper( setCommentSubmitLoading(false); }; - // Comment updating const editComment = async (body: string, comment_id: number) => { setCommentEditLoading(true); @@ -375,14 +365,12 @@ export default function CommentSectionWrapper( "[deleteComment] WebSocket error, falling back to HTTP:", error ); - // Fallback to HTTP API on WebSocket error await fallbackCommentDeletion(commentID, commenterID, deletionType); } } else { console.log( "[deleteComment] WebSocket not available, using HTTP fallback" ); - // Fallback to HTTP API if WebSocket unavailable await fallbackCommentDeletion(commentID, commenterID, deletionType); } }; @@ -407,7 +395,6 @@ export default function CommentSectionWrapper( console.log("[fallbackCommentDeletion] Success:", result); - // Handle the deletion response deleteCommentHandler({ action: "commentDeletionBroadcast", commentID: commentID, diff --git a/src/components/blog/PostBodyClient.tsx b/src/components/blog/PostBodyClient.tsx index 4da78ad..6d4c0c6 100644 --- a/src/components/blog/PostBodyClient.tsx +++ b/src/components/blog/PostBodyClient.tsx @@ -84,7 +84,6 @@ async function loadHighlightJS(): Promise { hljs.registerLanguage("diff", diff.default); hljs.registerLanguage("toml", toml.default); - // Also register common aliases hljs.registerLanguage("js", javascript.default); hljs.registerLanguage("ts", typescript.default); hljs.registerLanguage("jsx", javascript.default); @@ -97,18 +96,15 @@ export default function PostBodyClient(props: PostBodyClientProps) { let contentRef: HTMLDivElement | undefined; const [hljs, setHljs] = createSignal(null); - // Process superscript references and enhance the References section const processReferences = () => { if (!contentRef) return; const foundRefs = new Map(); - // Find all elements with [n] pattern const supElements = contentRef.querySelectorAll("sup"); supElements.forEach((sup) => { const text = sup.textContent?.trim() || ""; - // Match patterns like [1], [2], [a], [*], etc. const match = text.match(/^\[(.+?)\]$/); if (match) { @@ -116,10 +112,8 @@ export default function PostBodyClient(props: PostBodyClientProps) { const refId = `ref-${refNumber}`; const refBackId = `ref-${refNumber}-back`; - // Add ID to the sup element itself for back navigation sup.id = refBackId; - // Replace sup content with a clickable link sup.innerHTML = ""; const link = document.createElement("a"); link.href = `#${refId}`; @@ -129,13 +123,11 @@ export default function PostBodyClient(props: PostBodyClientProps) { link.style.cssText = "text-decoration: none; font-size: 0.75em; vertical-align: super;"; - // Add smooth scroll behavior link.onclick = (e) => { e.preventDefault(); const target = document.getElementById(refId); if (target) { target.scrollIntoView({ behavior: "smooth", block: "center" }); - // Highlight the reference briefly target.style.backgroundColor = "rgba(137, 180, 250, 0.2)"; setTimeout(() => { target.style.backgroundColor = ""; @@ -147,7 +139,6 @@ export default function PostBodyClient(props: PostBodyClientProps) { } }); - // Find and enhance the References section const headings = contentRef.querySelectorAll("h2"); let referencesSection: HTMLElement | null = null; @@ -158,7 +149,6 @@ export default function PostBodyClient(props: PostBodyClientProps) { }); if (referencesSection) { - // Style the References heading referencesSection.className = "text-2xl font-bold mb-4 text-text"; // Find the parent container and add styling diff --git a/src/components/blog/TextEditor.tsx b/src/components/blog/TextEditor.tsx index b7f2e27..dd39d16 100644 --- a/src/components/blog/TextEditor.tsx +++ b/src/components/blog/TextEditor.tsx @@ -44,10 +44,8 @@ import swift from "highlight.js/lib/languages/swift"; import kotlin from "highlight.js/lib/languages/kotlin"; import dockerfile from "highlight.js/lib/languages/dockerfile"; -// Create lowlight instance with common languages const lowlight = createLowlight(common); -// Register existing languages lowlight.register("css", css); lowlight.register("js", js); lowlight.register("javascript", js); @@ -56,7 +54,6 @@ lowlight.register("typescript", ts); lowlight.register("ocaml", ocaml); lowlight.register("rust", rust); -// Register new languages lowlight.register("python", python); lowlight.register("py", python); lowlight.register("java", java); @@ -87,7 +84,6 @@ lowlight.register("kt", kotlin); lowlight.register("dockerfile", dockerfile); lowlight.register("docker", dockerfile); -// Available languages for selector const AVAILABLE_LANGUAGES = [ { value: null, label: "Plain Text" }, { value: "bash", label: "Bash/Shell" }, @@ -115,7 +111,6 @@ const AVAILABLE_LANGUAGES = [ { value: "yaml", label: "YAML" } ] as const; -// Mermaid diagram templates const MERMAID_TEMPLATES = [ { name: "Flowchart", @@ -183,7 +178,6 @@ const MERMAID_TEMPLATES = [ } ]; -// Keyboard shortcuts data interface ShortcutCategory { name: string; shortcuts: Array<{ @@ -271,7 +265,6 @@ const isMac = () => { ); }; -// IFrame extension interface IframeOptions { allowFullscreen: boolean; HTMLAttributes: { @@ -472,19 +465,16 @@ export default function TextEditor(props: TextEditorProps) { handleClickOn(view, pos, node, nodePos, event) { const target = event.target as HTMLElement; - // Check if click is on a summary element inside details const summary = target.closest("summary"); if (summary) { const details = summary.closest('[data-type="details"]'); if (details) { - // Toggle the open attribute const isOpen = details.hasAttribute("open"); if (isOpen) { details.removeAttribute("open"); } else { details.setAttribute("open", ""); } - // Also toggle hidden attribute on details content const content = details.querySelector( '[data-type="detailsContent"]' ); @@ -504,7 +494,6 @@ export default function TextEditor(props: TextEditorProps) { onUpdate: ({ editor }) => { untrack(() => { props.updateContent(editor.getHTML()); - // Auto-manage references section setTimeout(() => updateReferencesSection(editor), 100); }); }, @@ -515,7 +504,6 @@ export default function TextEditor(props: TextEditorProps) { if (hasSelection && !editor.state.selection.empty) { setShowBubbleMenu(true); - // Position the bubble menu const { view } = editor; const start = view.coordsAtPos(from); const end = view.coordsAtPos(to); @@ -530,7 +518,6 @@ export default function TextEditor(props: TextEditorProps) { } })); - // Update editor content when preSet changes (e.g., when data loads), but only if editor exists and content is different createEffect( on( () => props.preSet, @@ -544,14 +531,12 @@ export default function TextEditor(props: TextEditorProps) { ) ); - // Auto-manage references section const updateReferencesSection = (editorInstance: any) => { if (!editorInstance) return; const doc = editorInstance.state.doc; const foundRefs = new Set(); - // Scan document for superscript marks containing [n] patterns doc.descendants((node: any) => { if (node.isText && node.marks) { const hasSuperscript = node.marks.some( @@ -567,7 +552,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // If no references found, remove references section if it exists if (foundRefs.size === 0) { let hasReferencesSection = false; let hrPos = -1; @@ -581,7 +565,6 @@ export default function TextEditor(props: TextEditorProps) { }); if (hasReferencesSection && sectionStartPos > 0) { - // Find the HR before References heading doc.nodesBetween( Math.max(0, sectionStartPos - 50), sectionStartPos, @@ -592,7 +575,6 @@ export default function TextEditor(props: TextEditorProps) { } ); - // Delete from HR to end of document if (hrPos >= 0) { const tr = editorInstance.state.tr; tr.delete(hrPos, doc.content.size); @@ -602,7 +584,6 @@ export default function TextEditor(props: TextEditorProps) { return; } - // Convert Set to sorted array const refNumbers = Array.from(foundRefs).sort((a, b) => { const numA = parseInt(a); const numB = parseInt(b); @@ -612,7 +593,6 @@ export default function TextEditor(props: TextEditorProps) { return a.localeCompare(b); }); - // Check if References section already exists let referencesHeadingPos = -1; let existingRefs = new Set(); @@ -620,7 +600,6 @@ export default function TextEditor(props: TextEditorProps) { if (node.type.name === "heading" && node.textContent === "References") { referencesHeadingPos = pos; } - // Check for existing reference list items if (referencesHeadingPos >= 0 && node.type.name === "paragraph") { const match = node.textContent.match(/^\[(.+?)\]/); if (match) { @@ -629,7 +608,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // If references section doesn't exist, create it if (referencesHeadingPos === -1) { const content: any[] = [ { type: "horizontalRule" }, @@ -640,7 +618,6 @@ export default function TextEditor(props: TextEditorProps) { } ]; - // Add each reference as a paragraph refNumbers.forEach((refNum) => { content.push({ type: "paragraph", @@ -658,7 +635,6 @@ export default function TextEditor(props: TextEditorProps) { }); }); - // Insert at the end const tr = editorInstance.state.tr; tr.insert( doc.content.size, @@ -666,11 +642,9 @@ export default function TextEditor(props: TextEditorProps) { ); editorInstance.view.dispatch(tr); } else { - // Update existing references section - add missing refs const newRefs = refNumbers.filter((ref) => !existingRefs.has(ref)); if (newRefs.length > 0) { - // Find position after References heading to insert new refs let insertPos = referencesHeadingPos; doc.nodesBetween( referencesHeadingPos, @@ -781,17 +755,12 @@ export default function TextEditor(props: TextEditorProps) { const { from } = instance.state.selection; instance.chain().focus().insertContent(content).run(); - // Move cursor to the paragraph inside detailsContent - // Structure: details (from+1) > detailsSummary > detailsContent > paragraph - // We need to position inside the paragraph which is roughly from + title.length + 3 nodes deep setTimeout(() => { const { state } = instance; let targetPos = from; - // Navigate through the document to find the paragraph inside detailsContent state.doc.nodesBetween(from, from + 200, (node, pos) => { if (node.type.name === "detailsContent") { - // Position cursor at the start of the first child (paragraph) targetPos = pos + 1; return false; // Stop iteration } @@ -811,7 +780,6 @@ export default function TextEditor(props: TextEditorProps) { instance.chain().focus().toggleCodeBlock().run(); - // If language specified, update the node attributes if (language) { instance.chain().updateAttributes("codeBlock", { language }).run(); } @@ -869,7 +837,6 @@ export default function TextEditor(props: TextEditorProps) { const { state } = instance; const { selection } = state; - // Find the row node let rowNode = null; let depth = 0; for (let d = selection.$anchor.depth; d > 0; d--) { @@ -908,10 +875,8 @@ export default function TextEditor(props: TextEditorProps) { const { state } = instance; const { selection } = state; - // Get the current cell position const cellPos = selection.$anchor; - // Find table and column index let tableNode = null; let tableDepth = 0; for (let d = cellPos.depth; d > 0; d--) { @@ -924,7 +889,6 @@ export default function TextEditor(props: TextEditorProps) { } if (tableNode) { - // Find which column we're in let colIndex = 0; const cellNode = cellPos.node(cellPos.depth); const rowNode = cellPos.node(cellPos.depth - 1); @@ -939,7 +903,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // Check if this column has content let hasContent = false; tableNode.descendants((node, pos, parent) => { if (parent && parent.type.name === "tableRow") { @@ -964,7 +927,6 @@ export default function TextEditor(props: TextEditorProps) { instance.chain().focus().deleteColumn().run(); }; - // Close language selector on outside click createEffect(() => { if (showLanguageSelector()) { const handleClickOutside = (e: MouseEvent) => { @@ -985,7 +947,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // Close table menu on outside click createEffect(() => { if (showTableMenu()) { const handleClickOutside = (e: MouseEvent) => { @@ -1006,7 +967,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // Close mermaid menu on outside click createEffect(() => { if (showMermaidTemplates()) { const handleClickOutside = (e: MouseEvent) => { @@ -1027,7 +987,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // Close conditional config on outside click createEffect(() => { if (showConditionalConfig()) { const handleClickOutside = (e: MouseEvent) => { @@ -1065,7 +1024,6 @@ export default function TextEditor(props: TextEditorProps) { setShowMermaidTemplates(false); }; - // Conditional block functions const showConditionalConfigurator = (e: MouseEvent) => { const buttonRect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setConditionalConfigPosition({ @@ -1073,7 +1031,6 @@ export default function TextEditor(props: TextEditorProps) { left: buttonRect.left }); - // If cursor is in existing conditional, load its values const instance = editor(); if (instance?.isActive("conditionalBlock")) { const attrs = instance.getAttributes("conditionalBlock"); @@ -1092,7 +1049,6 @@ export default function TextEditor(props: TextEditorProps) { inline: true }); } else { - // Reset to defaults for new conditional setConditionalForm({ conditionType: "auth", conditionValue: "authenticated", @@ -1112,9 +1068,7 @@ export default function TextEditor(props: TextEditorProps) { conditionalForm(); if (inline) { - // Handle inline conditionals (Mark) if (instance.isActive("conditionalInline")) { - // Update existing inline conditional instance .chain() .focus() @@ -1126,7 +1080,6 @@ export default function TextEditor(props: TextEditorProps) { }) .run(); } else { - // Apply inline conditional to selection instance .chain() .focus() @@ -1138,9 +1091,7 @@ export default function TextEditor(props: TextEditorProps) { .run(); } } else { - // Handle block conditionals (Node) if (instance.isActive("conditionalBlock")) { - // Update existing conditional instance .chain() .focus() @@ -1151,7 +1102,6 @@ export default function TextEditor(props: TextEditorProps) { }) .run(); } else { - // Wrap selection in new conditional instance .chain() .focus() @@ -1167,12 +1117,10 @@ export default function TextEditor(props: TextEditorProps) { setShowConditionalConfig(false); }; - // Toggle fullscreen mode const toggleFullscreen = () => { setIsFullscreen(!isFullscreen()); }; - // ESC key to exit fullscreen createEffect(() => { if (isFullscreen()) { const handleKeyDown = (e: KeyboardEvent) => { @@ -1187,7 +1135,6 @@ export default function TextEditor(props: TextEditorProps) { } }); - // Detect mobile keyboard visibility createEffect(() => { if (typeof window === "undefined" || !window.visualViewport) return; @@ -1198,7 +1145,6 @@ export default function TextEditor(props: TextEditorProps) { const currentHeight = viewport.height; const heightDiff = initialHeight - currentHeight; - // If viewport height decreased by more than 150px, keyboard is likely open if (heightDiff > 150) { setKeyboardVisible(true); setKeyboardHeight(heightDiff); @@ -1217,7 +1163,6 @@ export default function TextEditor(props: TextEditorProps) { }; }); - // Table Grid Selector Component const TableGridSelector = () => { const [hoverCell, setHoverCell] = createSignal({ row: 0, col: 0 }); const maxRows = 10; @@ -1268,7 +1213,6 @@ export default function TextEditor(props: TextEditorProps) { ); }; - // Conditional Configurator Component const ConditionalConfigurator = () => { return (
diff --git a/src/context/darkMode.tsx b/src/context/darkMode.tsx index de608ce..08c31bd 100644 --- a/src/context/darkMode.tsx +++ b/src/context/darkMode.tsx @@ -30,7 +30,6 @@ export const DarkModeProvider: ParentComponent = (props) => { const [isDark, setIsDark] = createSignal(false); onMount(() => { - // Check system preference const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); setIsDark(mediaQuery.matches); diff --git a/src/env/client.ts b/src/env/client.ts index e9972b0..142a2cc 100644 --- a/src/env/client.ts +++ b/src/env/client.ts @@ -70,7 +70,6 @@ export const validateClientEnv = ( }; // Validate and export environment variables directly -// This happens once at module load time on the client const validateAndExportEnv = (): ClientEnv => { try { const validated = validateClientEnv(import.meta.env); @@ -84,12 +83,10 @@ const validateAndExportEnv = (): ClientEnv => { export const env = validateAndExportEnv(); -// Helper function to check if a variable is missing export const isMissingEnvVar = (varName: string): boolean => { return !import.meta.env[varName] || import.meta.env[varName]?.trim() === ""; }; -// Helper function to get all missing client environment variables export const getMissingEnvVars = (): string[] => { const requiredClientVars = [ "VITE_DOMAIN", diff --git a/src/env/server.ts b/src/env/server.ts index 0ee4477..43564f8 100644 --- a/src/env/server.ts +++ b/src/env/server.ts @@ -90,7 +90,6 @@ export const validateServerEnv = ( }; // Validate and export environment variables directly -// This happens once at module load time on the server const validateAndExportEnv = (): ServerEnv => { try { const validated = validateServerEnv(process.env); @@ -104,12 +103,10 @@ const validateAndExportEnv = (): ServerEnv => { export const env = validateAndExportEnv(); -// Helper function to check if a variable is missing export const isMissingEnvVar = (varName: string): boolean => { return !process.env[varName] || process.env[varName]?.trim() === ""; }; -// Helper function to get all missing server environment variables export const getMissingEnvVars = (): string[] => { const requiredServerVars = [ "NODE_ENV", diff --git a/src/routes/account.tsx b/src/routes/account.tsx index 3a2759e..4ff2c9d 100644 --- a/src/routes/account.tsx +++ b/src/routes/account.tsx @@ -38,7 +38,6 @@ const getUserProfile = query(async (): Promise => { const user = res.rows[0] as any; - // Transform database User to UserProfile return { id: user.id, email: user.email ?? undefined, @@ -63,10 +62,8 @@ export default function AccountPage() { const userData = createAsync(() => getUserProfile(), { deferStream: true }); - // Local user state for client-side updates const [user, setUser] = createSignal(null); - // Form loading states const [emailButtonLoading, setEmailButtonLoading] = createSignal(false); const [displayNameButtonLoading, setDisplayNameButtonLoading] = createSignal(false); @@ -76,7 +73,6 @@ export default function AccountPage() { const [profileImageSetLoading, setProfileImageSetLoading] = createSignal(false); - // Password state const [passwordsMatch, setPasswordsMatch] = createSignal(false); const [showPasswordLengthWarning, setShowPasswordLengthWarning] = createSignal(false); @@ -86,19 +82,16 @@ export default function AccountPage() { const [passwordError, setPasswordError] = createSignal(false); const [passwordDeletionError, setPasswordDeletionError] = createSignal(false); - // Show/hide password toggles const [showOldPasswordInput, setShowOldPasswordInput] = createSignal(false); const [showPasswordInput, setShowPasswordInput] = createSignal(false); const [showPasswordConfInput, setShowPasswordConfInput] = createSignal(false); - // Success messages const [showImageSuccess, setShowImageSuccess] = createSignal(false); const [showEmailSuccess, setShowEmailSuccess] = createSignal(false); const [showDisplayNameSuccess, setShowDisplayNameSuccess] = createSignal(false); const [showPasswordSuccess, setShowPasswordSuccess] = createSignal(false); - // Profile image state const [profileImage, setProfileImage] = createSignal( undefined ); @@ -109,7 +102,6 @@ export default function AccountPage() { createSignal(false); const [preSetHolder, setPreSetHolder] = createSignal(null); - // Form refs let oldPasswordRef: HTMLInputElement | undefined; let newPasswordRef: HTMLInputElement | undefined; let newPasswordConfRef: HTMLInputElement | undefined; @@ -117,10 +109,8 @@ export default function AccountPage() { let displayNameRef: HTMLInputElement | undefined; let deleteAccountPasswordRef: HTMLInputElement | undefined; - // Helper to get current user (from SSR data or local state) const currentUser = () => user() || userData(); - // Initialize preSetHolder when userData loads createEffect(() => { const userProfile = userData(); if (userProfile?.image && !preSetHolder()) { @@ -308,7 +298,6 @@ export default function AccountPage() { if (response.ok && result.result?.data?.success) { setShowPasswordSuccess(true); setTimeout(() => setShowPasswordSuccess(false), 3000); - // Clear form if (oldPasswordRef) oldPasswordRef.value = ""; if (newPasswordRef) newPasswordRef.value = ""; if (newPasswordConfRef) newPasswordConfRef.value = ""; @@ -362,7 +351,6 @@ export default function AccountPage() { } setShowPasswordSuccess(true); setTimeout(() => setShowPasswordSuccess(false), 3000); - // Clear form if (newPasswordRef) newPasswordRef.value = ""; if (newPasswordConfRef) newPasswordConfRef.value = ""; } else { @@ -395,7 +383,6 @@ export default function AccountPage() { const result = await response.json(); if (response.ok && result.result?.data?.success) { - // Redirect to login navigate("/login"); } else { setPasswordDeletionError(true); @@ -425,7 +412,6 @@ export default function AccountPage() { } }; - // Password validation helpers const checkPasswordLength = (password: string) => { if (password.length >= 8) { setPasswordLengthSufficient(true); diff --git a/src/routes/api/auth/callback/github.ts b/src/routes/api/auth/callback/github.ts index b59f43e..087e703 100644 --- a/src/routes/api/auth/callback/github.ts +++ b/src/routes/api/auth/callback/github.ts @@ -7,7 +7,6 @@ export async function GET(event: APIEvent) { const code = url.searchParams.get("code"); const error = url.searchParams.get("error"); - // Handle OAuth error (user denied access, etc.) if (error) { return new Response(null, { status: 302, @@ -15,7 +14,6 @@ export async function GET(event: APIEvent) { }); } - // Missing authorization code if (!code) { return new Response(null, { status: 302, @@ -32,13 +30,11 @@ export async function GET(event: APIEvent) { const result = await caller.auth.githubCallback({ code }); if (result.success) { - // Redirect to account page on success return new Response(null, { status: 302, headers: { Location: result.redirectTo || "/account" } }); } else { - // Redirect to login with error return new Response(null, { status: 302, headers: { Location: "/login?error=auth_failed" } @@ -47,7 +43,6 @@ export async function GET(event: APIEvent) { } catch (error) { console.error("GitHub OAuth callback error:", error); - // Handle specific TRPC errors if (error && typeof error === "object" && "code" in error) { const trpcError = error as { code: string; message?: string }; diff --git a/src/routes/api/auth/callback/google.ts b/src/routes/api/auth/callback/google.ts index d044650..02a7272 100644 --- a/src/routes/api/auth/callback/google.ts +++ b/src/routes/api/auth/callback/google.ts @@ -7,7 +7,6 @@ export async function GET(event: APIEvent) { const code = url.searchParams.get("code"); const error = url.searchParams.get("error"); - // Handle OAuth error (user denied access, etc.) if (error) { return new Response(null, { status: 302, @@ -15,7 +14,6 @@ export async function GET(event: APIEvent) { }); } - // Missing authorization code if (!code) { return new Response(null, { status: 302, @@ -32,13 +30,11 @@ export async function GET(event: APIEvent) { const result = await caller.auth.googleCallback({ code }); if (result.success) { - // Redirect to account page on success return new Response(null, { status: 302, headers: { Location: result.redirectTo || "/account" } }); } else { - // Redirect to login with error return new Response(null, { status: 302, headers: { Location: "/login?error=auth_failed" } @@ -47,7 +43,6 @@ export async function GET(event: APIEvent) { } catch (error) { console.error("Google OAuth callback error:", error); - // Handle specific TRPC errors if (error && typeof error === "object" && "code" in error) { const trpcError = error as { code: string; message?: string }; diff --git a/src/routes/api/auth/email-login-callback.ts b/src/routes/api/auth/email-login-callback.ts index c1c5cb0..2d2e22f 100644 --- a/src/routes/api/auth/email-login-callback.ts +++ b/src/routes/api/auth/email-login-callback.ts @@ -11,7 +11,6 @@ export async function GET(event: APIEvent) { // Parse rememberMe parameter const rememberMe = rememberMeParam === "true"; - // Missing required parameters if (!email || !token) { return new Response(null, { status: 302, @@ -32,13 +31,11 @@ export async function GET(event: APIEvent) { }); if (result.success) { - // Redirect to account page on success return new Response(null, { status: 302, headers: { Location: result.redirectTo || "/account" }, }); } else { - // Redirect to login with error return new Response(null, { status: 302, headers: { Location: "/login?error=auth_failed" }, diff --git a/src/routes/api/auth/email-verification-callback.ts b/src/routes/api/auth/email-verification-callback.ts index 72f02c1..e70e197 100644 --- a/src/routes/api/auth/email-verification-callback.ts +++ b/src/routes/api/auth/email-verification-callback.ts @@ -7,7 +7,6 @@ export async function GET(event: APIEvent) { const email = url.searchParams.get("email"); const token = url.searchParams.get("token"); - // Missing required parameters if (!email || !token) { return new Response( ` diff --git a/src/routes/api/auth/signout.ts b/src/routes/api/auth/signout.ts index 113ea16..c0e8aa7 100644 --- a/src/routes/api/auth/signout.ts +++ b/src/routes/api/auth/signout.ts @@ -15,7 +15,6 @@ export async function POST() { expires: new Date(0) // Set expiry to past date }); - // Redirect to home page return new Response(null, { status: 302, headers: { diff --git a/src/routes/blog/[title]/index.tsx b/src/routes/blog/[title]/index.tsx index 8ecddca..b24acbe 100644 --- a/src/routes/blog/[title]/index.tsx +++ b/src/routes/blog/[title]/index.tsx @@ -18,7 +18,6 @@ import type { Comment, CommentReaction, UserPublicData } from "~/types/comment"; import { TerminalSplash } from "~/components/TerminalSplash"; import { api } from "~/lib/api"; -// Server function to fetch post by title const getPostByTitle = query( async ( title: string, @@ -48,7 +47,6 @@ const getPostByTitle = query( const post = postResults.rows[0] as any; if (!post) { - // Check if post exists but is unpublished const existQuery = "SELECT id FROM Post WHERE title = ?"; const existRes = await conn.execute({ sql: existQuery, diff --git a/src/routes/blog/index.tsx b/src/routes/blog/index.tsx index 1b62a11..25dac44 100644 --- a/src/routes/blog/index.tsx +++ b/src/routes/blog/index.tsx @@ -8,7 +8,6 @@ import TagSelector from "~/components/blog/TagSelector"; import PostSorting from "~/components/blog/PostSorting"; import { TerminalSplash } from "~/components/TerminalSplash"; -// Server function to fetch all posts const getPosts = query(async () => { "use server"; const { ConnectionFactory, getPrivilegeLevel } = diff --git a/src/routes/contact.tsx b/src/routes/contact.tsx index b35ad6c..15ad2ef 100644 --- a/src/routes/contact.tsx +++ b/src/routes/contact.tsx @@ -40,7 +40,6 @@ const getContactData = query(async () => { return { remainingTime }; }, "contact-data"); -// Server action for form submission const sendContactEmail = action(async (formData: FormData) => { "use server"; const name = formData.get("name") as string; @@ -65,7 +64,6 @@ const sendContactEmail = action(async (formData: FormData) => { ); } - // Check rate limit const contactExp = getCookie("contactRequestSent"); if (contactExp) { const expires = new Date(contactExp); @@ -189,7 +187,6 @@ export default function ContactPage() { setCountDown(serverData.remainingTime); } - // Check for existing timer const timer = getClientCookie("contactRequestSent"); if (timer) { timerIdRef = setInterval(() => calcRemainder(timer), 1000); diff --git a/src/routes/login/index.tsx b/src/routes/login/index.tsx index a6089dd..c4f38e8 100644 --- a/src/routes/login/index.tsx +++ b/src/routes/login/index.tsx @@ -42,7 +42,6 @@ export default function LoginPage() { const register = () => searchParams.mode === "register"; const usePassword = () => searchParams.auth === "password"; - // State management const [error, setError] = createSignal(""); const [loading, setLoading] = createSignal(false); const [countDown, setCountDown] = createSignal(0); @@ -58,7 +57,6 @@ export default function LoginPage() { createSignal(false); const [passwordBlurred, setPasswordBlurred] = createSignal(false); - // Form refs let emailRef: HTMLInputElement | undefined; let passwordRef: HTMLInputElement | undefined; let passwordConfRef: HTMLInputElement | undefined; @@ -70,7 +68,6 @@ export default function LoginPage() { const githubClientId = env.VITE_GITHUB_CLIENT_ID; const domain = env.VITE_DOMAIN || "https://www.freno.me"; - // Calculate remaining time from cookie const calcRemainder = (timer: string) => { const expires = new Date(timer); const remaining = expires.getTime() - Date.now(); @@ -86,7 +83,6 @@ export default function LoginPage() { } }; - // Check for existing timer on mount createEffect(() => { const timer = getClientCookie("emailLoginLinkRequested"); if (timer) { @@ -103,7 +99,6 @@ export default function LoginPage() { }); }); - // Check for OAuth/callback errors in URL createEffect(() => { const errorParam = searchParams.error; if (errorParam) { @@ -121,7 +116,6 @@ export default function LoginPage() { } }); - // Form submission handler const formHandler = async (e: Event) => { e.preventDefault(); setLoading(true); @@ -273,7 +267,6 @@ export default function LoginPage() { } }; - // Countdown timer render function const renderTime = ({ remainingTime }: { remainingTime: number }) => { return (
@@ -282,7 +275,6 @@ export default function LoginPage() { ); }; - // Password validation helpers const checkForMatch = (newPassword: string, newPasswordConf: string) => { setPasswordsMatch(newPassword === newPasswordConf); }; diff --git a/src/routes/login/password-reset.tsx b/src/routes/login/password-reset.tsx index a88414c..bbacc4d 100644 --- a/src/routes/login/password-reset.tsx +++ b/src/routes/login/password-reset.tsx @@ -11,7 +11,6 @@ export default function PasswordResetPage() { const navigate = useNavigate(); const [searchParams] = useSearchParams(); - // State management const [passwordBlurred, setPasswordBlurred] = createSignal(false); const [passwordChangeLoading, setPasswordChangeLoading] = createSignal(false); const [passwordsMatch, setPasswordsMatch] = createSignal(false); @@ -25,21 +24,18 @@ export default function PasswordResetPage() { const [showPasswordInput, setShowPasswordInput] = createSignal(false); const [showPasswordConfInput, setShowPasswordConfInput] = createSignal(false); - // Form refs let newPasswordRef: HTMLInputElement | undefined; let newPasswordConfRef: HTMLInputElement | undefined; // Get token from URL const token = searchParams.token; - // Redirect to request page if no token createEffect(() => { if (!token) { navigate("/login/request-password-reset"); } }); - // Form submission handler const setNewPasswordTrigger = async (e: Event) => { e.preventDefault(); setShowRequestNewEmail(false); @@ -93,7 +89,6 @@ export default function PasswordResetPage() { } }; - // Check if passwords match const checkForMatch = (newPassword: string, newPasswordConf: string) => { if (newPassword === newPasswordConf) { setPasswordsMatch(true); @@ -102,7 +97,6 @@ export default function PasswordResetPage() { } }; - // Check password length const checkPasswordLength = (password: string) => { if (password.length >= 8) { setPasswordLengthSufficient(true); @@ -115,7 +109,6 @@ export default function PasswordResetPage() { } }; - // Handle password blur const passwordLengthBlurCheck = () => { if ( !passwordLengthSufficient() && @@ -127,7 +120,6 @@ export default function PasswordResetPage() { setPasswordBlurred(true); }; - // Handle new password change const handleNewPasswordChange = (e: Event) => { const target = e.target as HTMLInputElement; checkPasswordLength(target.value); @@ -136,7 +128,6 @@ export default function PasswordResetPage() { } }; - // Handle password confirmation change const handlePasswordConfChange = (e: Event) => { const target = e.target as HTMLInputElement; if (newPasswordRef) { @@ -144,7 +135,6 @@ export default function PasswordResetPage() { } }; - // Handle password blur const handlePasswordBlur = () => { passwordLengthBlurCheck(); }; diff --git a/src/routes/login/request-password-reset.tsx b/src/routes/login/request-password-reset.tsx index 571fce5..2078bd5 100644 --- a/src/routes/login/request-password-reset.tsx +++ b/src/routes/login/request-password-reset.tsx @@ -8,17 +8,14 @@ import { getClientCookie } from "~/lib/cookies.client"; export default function RequestPasswordResetPage() { const navigate = useNavigate(); - // State management const [loading, setLoading] = createSignal(false); const [countDown, setCountDown] = createSignal(0); const [showSuccessMessage, setShowSuccessMessage] = createSignal(false); const [error, setError] = createSignal(""); - // Form refs let emailRef: HTMLInputElement | undefined; let timerInterval: number | undefined; - // Calculate remaining time from cookie const calcRemainder = (timer: string) => { const expires = new Date(timer); const remaining = expires.getTime() - Date.now(); @@ -34,7 +31,6 @@ export default function RequestPasswordResetPage() { } }; - // Check for existing timer on mount createEffect(() => { const timer = getClientCookie("passwordResetRequested"); if (timer) { @@ -51,7 +47,6 @@ export default function RequestPasswordResetPage() { }); }); - // Form submission handler const requestPasswordResetTrigger = async (e: Event) => { e.preventDefault(); setError(""); diff --git a/src/server/api/routers/auth.ts b/src/server/api/routers/auth.ts index 634be22..598ca65 100644 --- a/src/server/api/routers/auth.ts +++ b/src/server/api/routers/auth.ts @@ -432,9 +432,8 @@ export const authRouter = createTRPCRouter({ }; if (rememberMe) { - cookieOptions.maxAge = 60 * 60 * 24 * 14; // 14 days + cookieOptions.maxAge = 60 * 60 * 24 * 14; } - // If rememberMe is false, cookie will be session-only (no maxAge) setCookie( ctx.event.nativeEvent, @@ -591,7 +590,6 @@ export const authRouter = createTRPCRouter({ }); } - // If provider is unknown/null, update it to "email" since they're logging in with password if ( !user.provider || !["email", "google", "github", "apple"].includes(user.provider) @@ -669,7 +667,6 @@ export const authRouter = createTRPCRouter({ .setExpirationTime("15m") .sign(secret); - // Send email const domain = env.VITE_DOMAIN || "https://freno.me"; const htmlContent = ` @@ -754,7 +751,6 @@ export const authRouter = createTRPCRouter({ const { email } = input; try { - // Check rate limiting const requested = getCookie( ctx.event.nativeEvent, "passwordResetRequested" @@ -777,20 +773,16 @@ export const authRouter = createTRPCRouter({ }); if (res.rows.length === 0) { - // Don't reveal if user exists return { success: true, message: "email sent" }; } const user = res.rows[0] as unknown as User; - // Create JWT token with user ID (15min expiry) const secret = new TextEncoder().encode(env.JWT_SECRET_KEY); const token = await new SignJWT({ id: user.id }) .setProtectedHeader({ alg: "HS256" }) .setExpirationTime("15m") .sign(secret); - - // Send email const domain = env.VITE_DOMAIN || "https://freno.me"; const htmlContent = ` @@ -832,7 +824,6 @@ export const authRouter = createTRPCRouter({ await sendEmail(email, "password reset", htmlContent); - // Set rate limit cookie (5 minutes) const exp = new Date(Date.now() + 5 * 60 * 1000); setCookie( ctx.event.nativeEvent, @@ -870,7 +861,6 @@ export const authRouter = createTRPCRouter({ } }), - // Reset password with token resetPassword: publicProcedure .input( z.object({ @@ -890,7 +880,6 @@ export const authRouter = createTRPCRouter({ } try { - // Verify JWT token const secret = new TextEncoder().encode(env.JWT_SECRET_KEY); const { payload } = await jwtVerify(token, secret); @@ -904,7 +893,6 @@ export const authRouter = createTRPCRouter({ const conn = ConnectionFactory(); const passwordHash = await hashPassword(newPassword); - // Get user to check current provider const userRes = await conn.execute({ sql: "SELECT provider FROM User WHERE id = ?", args: [payload.id] @@ -919,7 +907,6 @@ export const authRouter = createTRPCRouter({ const currentProvider = (userRes.rows[0] as any).provider; - // Only update provider to "email" if it's null, undefined, or not a known OAuth provider if ( !currentProvider || !["google", "github", "apple"].includes(currentProvider) @@ -929,14 +916,12 @@ export const authRouter = createTRPCRouter({ args: [passwordHash, "email", payload.id] }); } else { - // Keep existing OAuth provider, just update password await conn.execute({ sql: "UPDATE User SET password_hash = ? WHERE id = ?", args: [passwordHash, payload.id] }); } - // Clear any session cookies setCookie(ctx.event.nativeEvent, "emailToken", "", { maxAge: 0, path: "/" @@ -959,14 +944,12 @@ export const authRouter = createTRPCRouter({ } }), - // Resend email verification resendEmailVerification: publicProcedure .input(z.object({ email: z.string().email() })) .mutation(async ({ input, ctx }) => { const { email } = input; try { - // Check rate limiting const requested = getCookie( ctx.event.nativeEvent, "emailVerificationRequested" @@ -998,14 +981,12 @@ export const authRouter = createTRPCRouter({ }); } - // Create JWT token (15min expiry) const secret = new TextEncoder().encode(env.JWT_SECRET_KEY); const token = await new SignJWT({ email }) .setProtectedHeader({ alg: "HS256" }) .setExpirationTime("15m") .sign(secret); - // Send email const domain = env.VITE_DOMAIN || "https://freno.me"; const htmlContent = ` @@ -1044,7 +1025,6 @@ export const authRouter = createTRPCRouter({ await sendEmail(email, "freno.me email verification", htmlContent); - // Set rate limit cookie setCookie( ctx.event.nativeEvent, "emailVerificationRequested", @@ -1081,7 +1061,6 @@ export const authRouter = createTRPCRouter({ } }), - // Sign out signOut: publicProcedure.mutation(async ({ ctx }) => { setCookie(ctx.event.nativeEvent, "userIDToken", "", { maxAge: 0, diff --git a/src/server/api/routers/database.ts b/src/server/api/routers/database.ts index 5fca1a5..c613c97 100644 --- a/src/server/api/routers/database.ts +++ b/src/server/api/routers/database.ts @@ -162,7 +162,6 @@ export const databaseRouter = createTRPCRouter({ requestingUser: ctx.userId }); - // User can only delete their own comments with "user" type if (input.deletionType === "user" && !isOwner && !isAdmin) { throw new TRPCError({ code: "FORBIDDEN", @@ -170,7 +169,6 @@ export const databaseRouter = createTRPCRouter({ }); } - // Only admins can do admin or database deletion if ( (input.deletionType === "admin" || input.deletionType === "database") && @@ -184,14 +182,11 @@ export const databaseRouter = createTRPCRouter({ if (input.deletionType === "database") { console.log("[deleteComment] Performing database deletion"); - // Full deletion - remove from database - // First delete reactions await conn.execute({ sql: "DELETE FROM CommentReaction WHERE comment_id = ?", args: [input.commentID] }); - // Then delete the comment await conn.execute({ sql: "DELETE FROM Comment WHERE id = ?", args: [input.commentID] @@ -205,7 +200,6 @@ export const databaseRouter = createTRPCRouter({ }; } else if (input.deletionType === "admin") { console.log("[deleteComment] Performing admin deletion"); - // Admin delete - replace body with admin message await conn.execute({ sql: "UPDATE Comment SET body = ?, commenter_id = ? WHERE id = ?", args: ["[deleted by admin]", "", input.commentID] @@ -219,7 +213,6 @@ export const databaseRouter = createTRPCRouter({ }; } else { console.log("[deleteComment] Performing user deletion"); - // User delete - replace body with user message await conn.execute({ sql: "UPDATE Comment SET body = ?, commenter_id = ? WHERE id = ?", args: ["[deleted]", "", input.commentID] @@ -249,7 +242,6 @@ export const databaseRouter = createTRPCRouter({ .query(async ({ input }) => { try { const conn = ConnectionFactory(); - // Join with Post table to get post titles along with comments const query = ` SELECT c.*, p.title as post_title FROM Comment c @@ -270,10 +262,6 @@ export const databaseRouter = createTRPCRouter({ } }), - // ============================================================ - // Post Routes - // ============================================================ - getPostById: publicProcedure .input( z.object({ @@ -288,7 +276,6 @@ export const databaseRouter = createTRPCRouter({ async () => { try { const conn = ConnectionFactory(); - // Single query with JOIN to get post and tags in one go const query = ` SELECT p.*, t.value as tag_value FROM Post p @@ -301,7 +288,6 @@ export const databaseRouter = createTRPCRouter({ }); if (results.rows[0]) { - // Group tags by post ID const post = results.rows[0]; const tags = results.rows .filter((row) => row.tag_value) @@ -339,7 +325,6 @@ export const databaseRouter = createTRPCRouter({ try { const conn = ConnectionFactory(); - // Get post by title with JOINs to get all related data in one query const postQuery = ` SELECT p.*, @@ -364,7 +349,6 @@ export const databaseRouter = createTRPCRouter({ const postRow = postResults.rows[0]; - // Return structured data with proper formatting return { post: postRow, comments: [], // Comments are not included in this optimized query - would need separate call if needed @@ -426,7 +410,6 @@ export const databaseRouter = createTRPCRouter({ await conn.execute(tagQuery); } - // Invalidate blog cache cache.deleteByPrefix("blog-"); return { data: results.lastInsertRowid }; @@ -502,7 +485,6 @@ export const databaseRouter = createTRPCRouter({ const results = await conn.execute({ sql: query, args: params }); - // Handle tags const deleteTagsQuery = `DELETE FROM Tag WHERE post_id = ?`; await conn.execute({ sql: deleteTagsQuery, @@ -516,7 +498,6 @@ export const databaseRouter = createTRPCRouter({ await conn.execute(tagQuery); } - // Invalidate blog cache cache.deleteByPrefix("blog-"); return { data: results.lastInsertRowid }; @@ -535,31 +516,26 @@ export const databaseRouter = createTRPCRouter({ try { const conn = ConnectionFactory(); - // Delete associated tags first await conn.execute({ sql: "DELETE FROM Tag WHERE post_id = ?", args: [input.id.toString()] }); - // Delete associated likes await conn.execute({ sql: "DELETE FROM PostLike WHERE post_id = ?", args: [input.id.toString()] }); - // Delete associated comments await conn.execute({ sql: "DELETE FROM Comment WHERE post_id = ?", args: [input.id] }); - // Finally delete the post await conn.execute({ sql: "DELETE FROM Post WHERE id = ?", args: [input.id] }); - // Invalidate blog cache cache.deleteByPrefix("blog-"); return { success: true }; diff --git a/src/server/api/routers/git-activity.ts b/src/server/api/routers/git-activity.ts index a6d983b..507da13 100644 --- a/src/server/api/routers/git-activity.ts +++ b/src/server/api/routers/git-activity.ts @@ -10,7 +10,6 @@ import { APIError } from "~/server/fetch-utils"; -// Types for commits interface GitCommit { sha: string; message: string; @@ -26,7 +25,6 @@ interface ContributionDay { } export const gitActivityRouter = createTRPCRouter({ - // Get recent commits from GitHub getGitHubCommits: publicProcedure .input(z.object({ limit: z.number().default(3) })) .query(async ({ input }) => { @@ -34,7 +32,6 @@ export const gitActivityRouter = createTRPCRouter({ `github-commits-${input.limit}`, 10 * 60 * 1000, // 10 minutes async () => { - // Get user's repositories sorted by most recently pushed const reposResponse = await fetchWithTimeout( `https://api.github.com/users/MikeFreno/repos?sort=pushed&per_page=10`, { @@ -50,7 +47,6 @@ export const gitActivityRouter = createTRPCRouter({ const repos = await reposResponse.json(); const allCommits: GitCommit[] = []; - // Fetch recent commits from each repo for (const repo of repos) { if (allCommits.length >= input.limit * 3) break; // Get extra to sort later @@ -69,7 +65,6 @@ export const gitActivityRouter = createTRPCRouter({ if (commitsResponse.ok) { const commits = await commitsResponse.json(); for (const commit of commits) { - // Filter for commits by the authenticated user if ( commit.author?.login === "MikeFreno" || commit.commit?.author?.email?.includes("mike") @@ -91,7 +86,6 @@ export const gitActivityRouter = createTRPCRouter({ } } } catch (error) { - // Log individual repo failures but continue with others if ( error instanceof NetworkError || error instanceof TimeoutError @@ -108,7 +102,6 @@ export const gitActivityRouter = createTRPCRouter({ } } - // Sort by date and return the most recent allCommits.sort( (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime() ); @@ -117,7 +110,6 @@ export const gitActivityRouter = createTRPCRouter({ }, { maxStaleMs: 24 * 60 * 60 * 1000 } // Accept stale data up to 24 hours old ).catch((error) => { - // Final fallback - return empty array if everything fails if (error instanceof NetworkError) { console.error("GitHub API unavailable (network error)"); } else if (error instanceof TimeoutError) { @@ -133,7 +125,6 @@ export const gitActivityRouter = createTRPCRouter({ }); }), - // Get recent commits from Gitea getGiteaCommits: publicProcedure .input(z.object({ limit: z.number().default(3) })) .query(async ({ input }) => { @@ -141,7 +132,6 @@ export const gitActivityRouter = createTRPCRouter({ `gitea-commits-${input.limit}`, 10 * 60 * 1000, // 10 minutes async () => { - // First, get user's repositories const reposResponse = await fetchWithTimeout( `${env.GITEA_URL}/api/v1/users/Mike/repos?limit=100`, { @@ -157,7 +147,6 @@ export const gitActivityRouter = createTRPCRouter({ const repos = await reposResponse.json(); const allCommits: GitCommit[] = []; - // Fetch recent commits from each repo for (const repo of repos) { if (allCommits.length >= input.limit * 3) break; // Get extra to sort later @@ -199,7 +188,6 @@ export const gitActivityRouter = createTRPCRouter({ } } } catch (error) { - // Log individual repo failures but continue with others if ( error instanceof NetworkError || error instanceof TimeoutError @@ -216,7 +204,6 @@ export const gitActivityRouter = createTRPCRouter({ } } - // Sort by date and return the most recent allCommits.sort( (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime() ); @@ -225,7 +212,6 @@ export const gitActivityRouter = createTRPCRouter({ }, { maxStaleMs: 24 * 60 * 60 * 1000 } ).catch((error) => { - // Final fallback - return empty array if everything fails if (error instanceof NetworkError) { console.error("Gitea API unavailable (network error)"); } else if (error instanceof TimeoutError) { @@ -245,7 +231,6 @@ export const gitActivityRouter = createTRPCRouter({ "github-activity", 10 * 60 * 1000, async () => { - // Use GitHub GraphQL API for contribution data const query = ` query($userName: String!) { user(login: $userName) { @@ -287,7 +272,6 @@ export const gitActivityRouter = createTRPCRouter({ throw new APIError("GraphQL query failed", 500, "GraphQL Error"); } - // Extract contribution days from the response const contributions: ContributionDay[] = []; const weeks = data.data?.user?.contributionsCollection?.contributionCalendar @@ -327,7 +311,6 @@ export const gitActivityRouter = createTRPCRouter({ "gitea-activity", 10 * 60 * 1000, async () => { - // Get user's repositories const reposResponse = await fetchWithTimeout( `${env.GITEA_URL}/api/v1/user/repos?limit=100`, { @@ -343,7 +326,6 @@ export const gitActivityRouter = createTRPCRouter({ const repos = await reposResponse.json(); const contributionsByDay = new Map(); - // Get commits from each repo (last 3 months to avoid too many API calls) const threeMonthsAgo = new Date(); threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3); @@ -373,7 +355,6 @@ export const gitActivityRouter = createTRPCRouter({ } } } catch (error) { - // Log individual repo failures but continue with others if ( error instanceof NetworkError || error instanceof TimeoutError @@ -387,7 +368,6 @@ export const gitActivityRouter = createTRPCRouter({ } } - // Convert to array format const contributions: ContributionDay[] = Array.from( contributionsByDay.entries() ).map(([date, count]) => ({ date, count })); diff --git a/src/server/api/routers/lineage/json-service.ts b/src/server/api/routers/lineage/json-service.ts index 3b7fcc1..2f8ed30 100644 --- a/src/server/api/routers/lineage/json-service.ts +++ b/src/server/api/routers/lineage/json-service.ts @@ -47,7 +47,6 @@ import potions from "~/lineage-json/item-route/potions.json"; import poison from "~/lineage-json/item-route/poison.json"; import staves from "~/lineage-json/item-route/staves.json"; -// Misc data imports import activities from "~/lineage-json/misc-route/activities.json"; import investments from "~/lineage-json/misc-route/investments.json"; import jobs from "~/lineage-json/misc-route/jobs.json"; diff --git a/src/server/api/routers/misc.ts b/src/server/api/routers/misc.ts index 7099638..204c8d4 100644 --- a/src/server/api/routers/misc.ts +++ b/src/server/api/routers/misc.ts @@ -96,7 +96,6 @@ export const miscRouter = createTRPCRouter({ credentials: credentials }); - // Sanitize the title and filename for S3 key (replace spaces with hyphens, remove special chars) const sanitizeForS3 = (str: string) => { return str .replace(/\s+/g, "-") // Replace spaces with hyphens @@ -262,7 +261,6 @@ export const miscRouter = createTRPCRouter({ }) ) .mutation(async ({ input }) => { - // Check if contact request was recently sent const contactExp = getCookie("contactRequestSent"); let remaining = 0; @@ -314,7 +312,6 @@ export const miscRouter = createTRPCRouter({ } ); - // Set cookie to prevent spam (60 second cooldown) const exp = new Date(Date.now() + 1 * 60 * 1000); setCookie("contactRequestSent", exp.toUTCString(), { expires: exp, @@ -365,7 +362,6 @@ export const miscRouter = createTRPCRouter({ sendDeletionRequestEmail: publicProcedure .input(z.object({ email: z.string().email() })) .mutation(async ({ input }) => { - // Check if deletion request was recently sent const deletionExp = getCookie("deletionRequestSent"); let remaining = 0; @@ -445,7 +441,6 @@ export const miscRouter = createTRPCRouter({ ) ]); - // Set cookie to prevent spam (60 second cooldown) const exp = new Date(Date.now() + 1 * 60 * 1000); setCookie("deletionRequestSent", exp.toUTCString(), { expires: exp, diff --git a/src/server/api/routers/user.ts b/src/server/api/routers/user.ts index 1625e11..b341a59 100644 --- a/src/server/api/routers/user.ts +++ b/src/server/api/routers/user.ts @@ -13,7 +13,6 @@ import type { User } from "~/types/user"; import { toUserProfile } from "~/types/user"; export const userRouter = createTRPCRouter({ - // Get current user profile getProfile: publicProcedure.query(async ({ ctx }) => { const userId = await getUserID(ctx.event.nativeEvent); @@ -41,7 +40,6 @@ export const userRouter = createTRPCRouter({ return toUserProfile(user); }), - // Update email updateEmail: publicProcedure .input(z.object({ email: z.string().email() })) .mutation(async ({ input, ctx }) => { @@ -62,7 +60,6 @@ export const userRouter = createTRPCRouter({ args: [email, 0, userId] }); - // Fetch updated user const res = await conn.execute({ sql: "SELECT * FROM User WHERE id = ?", args: [userId] @@ -70,7 +67,6 @@ export const userRouter = createTRPCRouter({ const user = res.rows[0] as unknown as User; - // Set email cookie for verification flow setCookie(ctx.event.nativeEvent, "emailToken", email, { path: "/" }); @@ -78,7 +74,6 @@ export const userRouter = createTRPCRouter({ return toUserProfile(user); }), - // Update display name updateDisplayName: publicProcedure .input(z.object({ displayName: z.string().min(1).max(50) })) .mutation(async ({ input, ctx }) => { @@ -99,7 +94,6 @@ export const userRouter = createTRPCRouter({ args: [displayName, userId] }); - // Fetch updated user const res = await conn.execute({ sql: "SELECT * FROM User WHERE id = ?", args: [userId] @@ -109,7 +103,6 @@ export const userRouter = createTRPCRouter({ return toUserProfile(user); }), - // Update profile image updateProfileImage: publicProcedure .input(z.object({ imageUrl: z.string() })) .mutation(async ({ input, ctx }) => { @@ -130,7 +123,6 @@ export const userRouter = createTRPCRouter({ args: [imageUrl, userId] }); - // Fetch updated user const res = await conn.execute({ sql: "SELECT * FROM User WHERE id = ?", args: [userId] @@ -140,7 +132,6 @@ export const userRouter = createTRPCRouter({ return toUserProfile(user); }), - // Change password (requires old password) changePassword: publicProcedure .input( z.object({ @@ -202,14 +193,12 @@ export const userRouter = createTRPCRouter({ }); } - // Update password const newPasswordHash = await hashPassword(newPassword); await conn.execute({ sql: "UPDATE User SET password_hash = ? WHERE id = ?", args: [newPasswordHash, userId] }); - // Clear session cookies (force re-login) setCookie(ctx.event.nativeEvent, "emailToken", "", { maxAge: 0, path: "/" @@ -222,7 +211,6 @@ export const userRouter = createTRPCRouter({ return { success: true, message: "success" }; }), - // Set password (for OAuth users who don't have password) setPassword: publicProcedure .input( z.object({ @@ -271,14 +259,12 @@ export const userRouter = createTRPCRouter({ }); } - // Set password const passwordHash = await hashPassword(newPassword); await conn.execute({ sql: "UPDATE User SET password_hash = ? WHERE id = ?", args: [passwordHash, userId] }); - // Clear session cookies (force re-login) setCookie(ctx.event.nativeEvent, "emailToken", "", { maxAge: 0, path: "/" @@ -291,7 +277,6 @@ export const userRouter = createTRPCRouter({ return { success: true, message: "success" }; }), - // Delete account (anonymize data) deleteAccount: publicProcedure .input(z.object({ password: z.string() })) .mutation(async ({ input, ctx }) => { @@ -337,7 +322,6 @@ export const userRouter = createTRPCRouter({ }); } - // Anonymize user data (don't hard delete) await conn.execute({ sql: `UPDATE User SET email = ?, @@ -350,7 +334,6 @@ export const userRouter = createTRPCRouter({ args: [null, 0, null, "user deleted", null, null, userId] }); - // Clear session cookies setCookie(ctx.event.nativeEvent, "emailToken", "", { maxAge: 0, path: "/" diff --git a/src/server/api/utils.ts b/src/server/api/utils.ts index 56c970c..ba03af6 100644 --- a/src/server/api/utils.ts +++ b/src/server/api/utils.ts @@ -50,7 +50,6 @@ export const t = initTRPC.context().create(); export const createTRPCRouter = t.router; export const publicProcedure = t.procedure; -// Middleware to enforce authentication const enforceUserIsAuthed = t.middleware(({ ctx, next }) => { if (!ctx.userId || ctx.privilegeLevel === "anonymous") { throw new TRPCError({ code: "UNAUTHORIZED", message: "Not authenticated" }); @@ -63,7 +62,6 @@ const enforceUserIsAuthed = t.middleware(({ ctx, next }) => { }); }); -// Middleware to enforce admin access const enforceUserIsAdmin = t.middleware(({ ctx, next }) => { if (ctx.privilegeLevel !== "admin") { throw new TRPCError({ diff --git a/src/server/fetch-utils.test.ts b/src/server/fetch-utils.test.ts index cfc6a3a..4085dfe 100644 --- a/src/server/fetch-utils.test.ts +++ b/src/server/fetch-utils.test.ts @@ -1,5 +1,4 @@ // Manual test file for fetch-utils error handling -// Run with: bun run src/server/fetch-utils.test.ts import { fetchWithTimeout,