diff --git a/frontend/apps/artcraft-dashboard/src/components/BanUserDialog.tsx b/frontend/apps/artcraft-dashboard/src/components/BanUserDialog.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/BanUserDialog.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/BanUserDialog.tsx
@@ -194,7 +194,7 @@ export function BanUserDialog({
               disabled={isSubmitting}
               onClick={(e) => {
                 e.preventDefault();
-                handleConfirm();
+                void handleConfirm();
               }}
             >
               {isSubmitting ? (
diff --git a/frontend/apps/artcraft-dashboard/src/components/BulkBanUsersDialog.tsx b/frontend/apps/artcraft-dashboard/src/components/BulkBanUsersDialog.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/BulkBanUsersDialog.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/BulkBanUsersDialog.tsx
@@ -204,7 +204,7 @@ export function BulkBanUsersDialog({
               disabled={isSubmitting}
               onClick={(e) => {
                 e.preventDefault();
-                handleConfirm();
+                void handleConfirm();
               }}
             >
               {isSubmitting ? (
diff --git a/frontend/apps/artcraft-dashboard/src/components/ChangeUserEmailDialog.tsx b/frontend/apps/artcraft-dashboard/src/components/ChangeUserEmailDialog.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/ChangeUserEmailDialog.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/ChangeUserEmailDialog.tsx
@@ -189,7 +189,7 @@ export function ChangeUserEmailDialog({
               disabled={isSubmitting}
               onClick={(e) => {
                 e.preventDefault();
-                handleConfirm();
+                void handleConfirm();
               }}
             >
               {isSubmitting ? (
diff --git a/frontend/apps/artcraft-dashboard/src/components/GiveCreditsDialog.tsx b/frontend/apps/artcraft-dashboard/src/components/GiveCreditsDialog.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/GiveCreditsDialog.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/GiveCreditsDialog.tsx
@@ -156,7 +156,7 @@ export function GiveCreditsDialog({
               disabled={isSubmitting}
               onClick={(e) => {
                 e.preventDefault();
-                handleConfirm();
+                void handleConfirm();
               }}
             >
               {isSubmitting ? (
diff --git a/frontend/apps/artcraft-dashboard/src/components/ImpersonateUserDialog.tsx b/frontend/apps/artcraft-dashboard/src/components/ImpersonateUserDialog.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/ImpersonateUserDialog.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/ImpersonateUserDialog.tsx
@@ -55,7 +55,7 @@ export function ImpersonateUserDialog({
     setImpersonationToken(null);
 
     const modApi = new ModerationApi();
-    modApi.ImpersonateUser({ user_token: userToken }).then((resp) => {
+    void modApi.ImpersonateUser({ user_token: userToken }).then((resp) => {
       if (cancelled) return;
       if (resp.success && resp.data) {
         setImpersonationToken(resp.data.password_token);
@@ -71,7 +71,7 @@ export function ImpersonateUserDialog({
   }, [open, userToken]);
 
   const copy = (text: string, field: string) => {
-    navigator.clipboard.writeText(text).then(() => {
+    void navigator.clipboard.writeText(text).then(() => {
       setCopiedField(field);
       setTimeout(() => setCopiedField(null), 2000);
     });
diff --git a/frontend/apps/artcraft-dashboard/src/components/JobsTable.tsx b/frontend/apps/artcraft-dashboard/src/components/JobsTable.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/JobsTable.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/JobsTable.tsx
@@ -71,7 +71,7 @@ export function JobsTable({
   const [copiedToken, setCopiedToken] = useState<string | null>(null);
 
   const copyToClipboard = (text: string) => {
-    navigator.clipboard.writeText(text).then(() => {
+    void navigator.clipboard.writeText(text).then(() => {
       setCopiedToken(text);
       setTimeout(() => setCopiedToken(null), 2000);
     });
diff --git a/frontend/apps/artcraft-dashboard/src/components/MediaDetailModal.tsx b/frontend/apps/artcraft-dashboard/src/components/MediaDetailModal.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/MediaDetailModal.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/MediaDetailModal.tsx
@@ -130,14 +130,14 @@ export function MediaDetailModal({
     if (!open || !item) return;
     let cancelled = false;
     const api = new MediaApi();
-    api.GetMediaFile(item.token).then((res) => {
+    void api.GetMediaFile(item.token).then((res) => {
       if (cancelled) return;
       const promptToken = res.data?.maybe_prompt_token;
       if (!promptToken) {
         setPromptFailed(true);
         return;
       }
-      api.GetPrompt(promptToken).then((promptRes) => {
+      void api.GetPrompt(promptToken).then((promptRes) => {
         if (cancelled) return;
         if (promptRes.success && promptRes.data) {
           setPromptInfo(promptRes.data);
diff --git a/frontend/apps/artcraft-dashboard/src/components/UserBillingSection.tsx b/frontend/apps/artcraft-dashboard/src/components/UserBillingSection.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/UserBillingSection.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/UserBillingSection.tsx
@@ -47,7 +47,7 @@ export function UserBillingSection({ userToken }: { userToken: string }) {
   }, [userToken]);
 
   const copyToClipboard = (text: string, id: string) => {
-    navigator.clipboard.writeText(text).then(() => {
+    void navigator.clipboard.writeText(text).then(() => {
       setCopiedStates((prev) => ({ ...prev, [id]: true }));
       setTimeout(() => {
         setCopiedStates((prev) => ({ ...prev, [id]: false }));
diff --git a/frontend/apps/artcraft-dashboard/src/components/UserFeatureFlagsDialog.tsx b/frontend/apps/artcraft-dashboard/src/components/UserFeatureFlagsDialog.tsx
--- a/frontend/apps/artcraft-dashboard/src/components/UserFeatureFlagsDialog.tsx
+++ b/frontend/apps/artcraft-dashboard/src/components/UserFeatureFlagsDialog.tsx
@@ -80,7 +80,7 @@ export function UserFeatureFlagsDialog({
     setSelectedFlags(new Set());
 
     const api = new ModerationApi();
-    Promise.all([
+    void Promise.all([
       api.ListAvailableFeatureFlags(),
       api.ListUserFeatureFlags(usernameOrToken),
     ])
@@ -360,7 +360,7 @@ export function UserFeatureFlagsDialog({
               disabled={isSubmitting}
               onClick={(e) => {
                 e.preventDefault();
-                handleClearAll();
+                void handleClearAll();
               }}
             >
               {isSubmitting ? (
diff --git a/frontend/apps/artcraft-dashboard/src/context/AuthContext.tsx b/frontend/apps/artcraft-dashboard/src/context/AuthContext.tsx
--- a/frontend/apps/artcraft-dashboard/src/context/AuthContext.tsx
+++ b/frontend/apps/artcraft-dashboard/src/context/AuthContext.tsx
@@ -59,7 +59,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
   };
 
   useEffect(() => {
-    checkSession();
+    void checkSession();
   }, []);
 
   const loginState = (userData: UserInfo) => {
diff --git a/frontend/apps/artcraft-dashboard/src/hooks/useInfiniteScroll.ts b/frontend/apps/artcraft-dashboard/src/hooks/useInfiniteScroll.ts
new file mode 100644
--- /dev/null
+++ b/frontend/apps/artcraft-dashboard/src/hooks/useInfiniteScroll.ts
@@ -0,0 +1,26 @@
+import { useEffect, useRef } from "react";
+
+/**
+ * Calls `onLoadMore` when the element the returned ref is attached to (at the end of a list)
+ * scrolls into view.
+ */
+export function useInfiniteScroll<T extends Element>(onLoadMore: () => void) {
+  const sentinelRef = useRef<T | null>(null);
+
+  useEffect(() => {
+    const observer = new IntersectionObserver(
+      (entries) => {
+        if (entries[0].isIntersecting) onLoadMore();
+      },
+      { threshold: 0.1 },
+    );
+
+    if (sentinelRef.current) {
+      observer.observe(sentinelRef.current);
+    }
+
+    return () => observer.disconnect();
+  }, [onLoadMore]);
+
+  return sentinelRef;
+}
diff --git a/frontend/apps/artcraft-dashboard/src/pages/DashboardHome.tsx b/frontend/apps/artcraft-dashboard/src/pages/DashboardHome.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/DashboardHome.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/DashboardHome.tsx
@@ -16,7 +16,7 @@ export function DashboardHome() {
   useEffect(() => {
     let cancelled = false;
     const api = new ModerationApi();
-    api.ListDataboxDashboards().then((resp) => {
+    void api.ListDataboxDashboards().then((resp) => {
       if (cancelled) return;
       setDataboards(resp.success && resp.data ? resp.data : []);
       setIsLoading(false);
diff --git a/frontend/apps/artcraft-dashboard/src/pages/DebugLogs.tsx b/frontend/apps/artcraft-dashboard/src/pages/DebugLogs.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/DebugLogs.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/DebugLogs.tsx
@@ -32,7 +32,7 @@ export function DebugLogs() {
   const [filter, setFilter] = useState("");
 
   const copy = (value: string, id: string) => {
-    navigator.clipboard.writeText(value).then(() => {
+    void navigator.clipboard.writeText(value).then(() => {
       setCopiedId(id);
       setTimeout(() => setCopiedId((c) => (c === id ? null : c)), 2000);
     });
@@ -59,7 +59,7 @@ export function DebugLogs() {
   };
 
   useEffect(() => {
-    loadLogs();
+    void loadLogs();
   }, [eventToken]);
 
   const filteredLogs = useMemo(() => {
diff --git a/frontend/apps/artcraft-dashboard/src/pages/DebugLogsAll.tsx b/frontend/apps/artcraft-dashboard/src/pages/DebugLogsAll.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/DebugLogsAll.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/DebugLogsAll.tsx
@@ -53,7 +53,7 @@ export function DebugLogsAll() {
   const loadingRef = useRef(false);
 
   const copy = (value: string, id: string) => {
-    navigator.clipboard.writeText(value).then(() => {
+    void navigator.clipboard.writeText(value).then(() => {
       setCopiedId(id);
       setTimeout(() => setCopiedId((c) => (c === id ? null : c)), 2000);
     });
diff --git a/frontend/apps/artcraft-dashboard/src/pages/ExploreMedia.tsx b/frontend/apps/artcraft-dashboard/src/pages/ExploreMedia.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/ExploreMedia.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/ExploreMedia.tsx
@@ -21,6 +21,7 @@ import {
   IconPhoto,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 const MEDIA_CLASS_OPTIONS = [
   { value: "", label: "All" },
@@ -52,9 +53,7 @@ export function ExploreMedia() {
   const [selectedItem, setSelectedItem] = useState<ExploreMediaFile | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLDivElement | null>(null);
-
+  
   // Stable filter key to detect changes
   const filterKey = useMemo(
     () => `${filterMediaClasses}|${filterMediaType}|${includeUserUploads}`,
@@ -122,22 +121,7 @@ export function ExploreMedia() {
   }, [nextCursor, isLoadingMore, loadData]);
 
   // IntersectionObserver for infinite scroll
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLDivElement>(loadMore);
 
   // Sync URL mediaToken → selectedItem
   useEffect(() => {
@@ -152,7 +136,7 @@ export function ExploreMedia() {
     } else {
       // Fetch single media file for direct URL access
       const api = new MediaApi();
-      api.GetMediaFile(mediaToken).then((res) => {
+      void api.GetMediaFile(mediaToken).then((res) => {
         if (res.success && res.data) {
           setSelectedItem(res.data as unknown as ExploreMediaFile);
         }
diff --git a/frontend/apps/artcraft-dashboard/src/pages/FeatureFlags.tsx b/frontend/apps/artcraft-dashboard/src/pages/FeatureFlags.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/FeatureFlags.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/FeatureFlags.tsx
@@ -49,7 +49,7 @@ export function FeatureFlags() {
   useEffect(() => {
     let cancelled = false;
     const api = new ModerationApi();
-    api
+    void api
       .ListAvailableFeatureFlags()
       .then((resp) => {
         if (cancelled) return;
diff --git a/frontend/apps/artcraft-dashboard/src/pages/Impersonation.tsx b/frontend/apps/artcraft-dashboard/src/pages/Impersonation.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/Impersonation.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/Impersonation.tsx
@@ -23,6 +23,7 @@ import {
   IconArrowRight,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 export function Impersonation() {
   usePageTitle("Impersonation Logs");
@@ -33,9 +34,7 @@ export function Impersonation() {
   const [nextCursor, setNextCursor] = useState<string | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (cursor?: string | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -74,12 +73,12 @@ export function Impersonation() {
   const handleRefresh = () => {
     setRequests([]);
     setNextCursor(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -87,26 +86,11 @@ export function Impersonation() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextCursor != null) {
-      loadData(nextCursor, true);
+      void loadData(nextCursor, true);
     }
   }, [nextCursor, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/JobHistory.tsx b/frontend/apps/artcraft-dashboard/src/pages/JobHistory.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/JobHistory.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/JobHistory.tsx
@@ -64,7 +64,7 @@ export function JobHistory() {
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
diff --git a/frontend/apps/artcraft-dashboard/src/pages/JobInfo.tsx b/frontend/apps/artcraft-dashboard/src/pages/JobInfo.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/JobInfo.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/JobInfo.tsx
@@ -162,7 +162,7 @@ export function JobInfo() {
   const [copiedId, setCopiedId] = useState<string | null>(null);
 
   const copy = (value: string, id: string) => {
-    navigator.clipboard.writeText(value).then(() => {
+    void navigator.clipboard.writeText(value).then(() => {
       setCopiedId(id);
       setTimeout(() => setCopiedId((c) => (c === id ? null : c)), 2000);
     });
@@ -189,7 +189,7 @@ export function JobInfo() {
   };
 
   useEffect(() => {
-    loadJob();
+    void loadJob();
   }, [jobToken]);
 
   const badge = job ? getJobStatusBadgeProps(job.status) : null;
diff --git a/frontend/apps/artcraft-dashboard/src/pages/ReengagementList.tsx b/frontend/apps/artcraft-dashboard/src/pages/ReengagementList.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/ReengagementList.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/ReengagementList.tsx
@@ -23,6 +23,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 const COLUMN_COUNT = 7;
 
@@ -53,9 +54,7 @@ export function ReengagementList() {
   const [nextOffset, setNextOffset] = useState<number | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (offset?: number | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -90,12 +89,12 @@ export function ReengagementList() {
   const handleRefresh = () => {
     setCandidates([]);
     setNextOffset(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -103,21 +102,11 @@ export function ReengagementList() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextOffset != null) {
-      loadData(nextOffset, true);
+      void loadData(nextOffset, true);
     }
   }, [nextOffset, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-    if (sentinelRef.current) observerRef.current.observe(sentinelRef.current);
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/ReferralsAnalytics.tsx b/frontend/apps/artcraft-dashboard/src/pages/ReferralsAnalytics.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/ReferralsAnalytics.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/ReferralsAnalytics.tsx
@@ -24,6 +24,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 function formatDate(iso: string) {
   return new Date(iso).toLocaleString("en-US", {
@@ -48,9 +49,7 @@ export function ReferralsAnalytics() {
   const [nextCursor, setNextCursor] = useState<string | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (cursor?: string | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -87,12 +86,12 @@ export function ReferralsAnalytics() {
   const handleRefresh = () => {
     setReferrals([]);
     setNextCursor(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -100,26 +99,11 @@ export function ReferralsAnalytics() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextCursor != null) {
-      loadData(nextCursor, true);
+      void loadData(nextCursor, true);
     }
   }, [nextCursor, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/SendPager.tsx b/frontend/apps/artcraft-dashboard/src/pages/SendPager.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/SendPager.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/SendPager.tsx
@@ -232,7 +232,7 @@ export function SendPager() {
               disabled={isSubmitting}
               onClick={(e) => {
                 e.preventDefault();
-                handleConfirm();
+                void handleConfirm();
               }}
             >
               {isSubmitting ? (
diff --git a/frontend/apps/artcraft-dashboard/src/pages/SpendEvents.tsx b/frontend/apps/artcraft-dashboard/src/pages/SpendEvents.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/SpendEvents.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/SpendEvents.tsx
@@ -24,6 +24,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 const COLUMN_COUNT = 8;
 
@@ -84,9 +85,7 @@ export function SpendEvents() {
   const [nextOffset, setNextOffset] = useState<number | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (offset?: number | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -123,12 +122,12 @@ export function SpendEvents() {
   const handleRefresh = () => {
     setEvents([]);
     setNextOffset(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -136,26 +135,11 @@ export function SpendEvents() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextOffset != null) {
-      loadData(nextOffset, true);
+      void loadData(nextOffset, true);
     }
   }, [nextOffset, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/StaffAuditLogs.tsx b/frontend/apps/artcraft-dashboard/src/pages/StaffAuditLogs.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/StaffAuditLogs.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/StaffAuditLogs.tsx
@@ -22,6 +22,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 export function StaffAuditLogs() {
   usePageTitle("Staff Audit Logs");
@@ -32,9 +33,7 @@ export function StaffAuditLogs() {
   const [nextCursor, setNextCursor] = useState<string | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (cursor?: string | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -71,12 +70,12 @@ export function StaffAuditLogs() {
   const handleRefresh = () => {
     setLogs([]);
     setNextCursor(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -84,26 +83,11 @@ export function StaffAuditLogs() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextCursor != null) {
-      loadData(nextCursor, true);
+      void loadData(nextCursor, true);
     }
   }, [nextCursor, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/SubscriberSignups.tsx b/frontend/apps/artcraft-dashboard/src/pages/SubscriberSignups.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/SubscriberSignups.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/SubscriberSignups.tsx
@@ -23,6 +23,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 function getSubscriptionStatusBadge(status: string | null) {
   if (!status) return { className: "text-muted-foreground", label: "Unknown" };
@@ -49,9 +50,7 @@ export function SubscriberSignups() {
   const [nextCursor, setNextCursor] = useState<number | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (cursor?: number | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -86,12 +85,12 @@ export function SubscriberSignups() {
   const handleRefresh = () => {
     setUsers([]);
     setNextCursor(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -99,26 +98,11 @@ export function SubscriberSignups() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextCursor != null) {
-      loadData(nextCursor, true);
+      void loadData(nextCursor, true);
     }
   }, [nextCursor, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/TopSpenders.tsx b/frontend/apps/artcraft-dashboard/src/pages/TopSpenders.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/TopSpenders.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/TopSpenders.tsx
@@ -23,6 +23,7 @@ import {
   IconTrophy,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 const COLUMN_COUNT = 7;
 
@@ -58,9 +59,7 @@ export function TopSpenders() {
   const [nextOffset, setNextOffset] = useState<number | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (
     timeWindow: string,
     offset?: number | null,
@@ -102,18 +101,18 @@ export function TopSpenders() {
     setWindow(value);
     setSpenders([]);
     setNextOffset(null);
-    loadData(value);
+    void loadData(value);
   };
 
   const handleRefresh = () => {
     setSpenders([]);
     setNextOffset(null);
-    loadData(window);
+    void loadData(window);
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData(DEFAULT_WINDOW);
+    void loadData(DEFAULT_WINDOW);
     return () => {
       cancelledRef.current = true;
     };
@@ -121,26 +120,11 @@ export function TopSpenders() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextOffset != null) {
-      loadData(window, nextOffset, true);
+      void loadData(window, nextOffset, true);
     }
   }, [window, nextOffset, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserCreations.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserCreations.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserCreations.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserCreations.tsx
@@ -110,7 +110,7 @@ export function UserCreations() {
       setIsLoading(false);
     }
 
-    init();
+    void init();
     return () => {
       cancelledRef.current = true;
     };
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserDebugLogs.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserDebugLogs.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserDebugLogs.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserDebugLogs.tsx
@@ -51,7 +51,7 @@ export function UserDebugLogs() {
   const loadingRef = useRef(false);
 
   const copy = (value: string, id: string) => {
-    navigator.clipboard.writeText(value).then(() => {
+    void navigator.clipboard.writeText(value).then(() => {
       setCopiedId(id);
       setTimeout(() => setCopiedId((c) => (c === id ? null : c)), 2000);
     });
@@ -102,7 +102,7 @@ export function UserDebugLogs() {
 
     if (userToken) {
       const api = new ModerationApi();
-      api.UserLookup(userToken).then((resp) => {
+      void api.UserLookup(userToken).then((resp) => {
         if (resp.success && resp.data?.maybe_user) {
           setUser({
             display_name: resp.data.maybe_user.display_name,
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserEmailChanges.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserEmailChanges.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserEmailChanges.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserEmailChanges.tsx
@@ -32,6 +32,7 @@ import {
   IconLoader2,
   IconPencil,
 } from "@tabler/icons-react";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 function gravatarUrl(hash?: string): string | undefined {
   return hash ? `https://gravatar.com/avatar/${hash}?s=48&d=404` : undefined;
@@ -80,9 +81,7 @@ export function UserEmailChanges() {
   const [nextCursor, setNextCursor] = useState<string | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadHistory = async (
     username: string,
     cursor?: string | null,
@@ -123,40 +122,25 @@ export function UserEmailChanges() {
 
   const loadMore = useCallback(() => {
     if (user && !isLoadingMore && nextCursor != null) {
-      loadHistory(user.username, nextCursor, true);
+      void loadHistory(user.username, nextCursor, true);
     }
   }, [user, nextCursor, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const handleSelect = (next: ModeratorUserLookupResponse | null) => {
     setUser(next);
     setCurrentEmail(next?.email_address ?? null);
     setChanges([]);
     setNextCursor(null);
-    if (next) loadHistory(next.username);
+    if (next) void loadHistory(next.username);
   };
 
   const handleChangeSuccess = (newEmail: string) => {
     setCurrentEmail(newEmail);
     setUser((prev) => (prev ? { ...prev, email_address: newEmail } : prev));
     toast.success("Email address changed");
-    if (user) loadHistory(user.username);
+    if (user) void loadHistory(user.username);
   };
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserProfile.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserProfile.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserProfile.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserProfile.tsx
@@ -150,7 +150,7 @@ export function UserProfile() {
   );
 
   const copyToClipboard = (text: string, id: string) => {
-    navigator.clipboard.writeText(text).then(() => {
+    void navigator.clipboard.writeText(text).then(() => {
       setCopiedStates((prev) => ({ ...prev, [id]: true }));
       setTimeout(() => {
         setCopiedStates((prev) => ({ ...prev, [id]: false }));
@@ -185,7 +185,7 @@ export function UserProfile() {
           setUser(fetchedUser);
 
           setIsWalletsLoading(true);
-          modApi.ListUserWallets(fetchedUser.token).then((resp) => {
+          void modApi.ListUserWallets(fetchedUser.token).then((resp) => {
             if (cancelled) return;
             if (resp.success && resp.data) {
               setWallets(resp.data.wallets);
@@ -194,7 +194,7 @@ export function UserProfile() {
           });
 
           setIsJobsLoading(true);
-          modApi.ListUserJobs(fetchedUser.token).then((resp) => {
+          void modApi.ListUserJobs(fetchedUser.token).then((resp) => {
             if (cancelled) return;
             if (resp.success && resp.data) {
               setJobs(resp.data.jobs);
@@ -220,7 +220,7 @@ export function UserProfile() {
       }
     }
 
-    loadData();
+    void loadData();
     return () => {
       cancelled = true;
     };
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserReferrals.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserReferrals.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserReferrals.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserReferrals.tsx
@@ -25,6 +25,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 function formatDate(iso: string) {
   return new Date(iso).toLocaleString("en-US", {
@@ -52,9 +53,7 @@ export function UserReferrals() {
   const [nextCursor, setNextCursor] = useState<string | null>(null);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (cursor?: string | null, append = false) => {
     if (!username) return;
     if (!append) {
@@ -92,12 +91,12 @@ export function UserReferrals() {
   const handleRefresh = () => {
     setReferrals([]);
     setNextCursor(null);
-    loadData();
+    void loadData();
   };
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -105,26 +104,11 @@ export function UserReferrals() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextCursor != null) {
-      loadData(nextCursor, true);
+      void loadData(nextCursor, true);
     }
   }, [nextCursor, isLoadingMore, username]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserSearch.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserSearch.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserSearch.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserSearch.tsx
@@ -104,7 +104,7 @@ export function UserSearch() {
         setSearchResult(foundUser);
 
         setIsWalletsLoading(true);
-        api.ListUserWallets(foundUser.token).then((walletResp) => {
+        void api.ListUserWallets(foundUser.token).then((walletResp) => {
           if (walletResp.success && walletResp.data) {
             setWallets(walletResp.data.wallets);
           }
@@ -122,7 +122,7 @@ export function UserSearch() {
 
   useEffect(() => {
     if (queryParam) {
-      performSearch(queryParam);
+      void performSearch(queryParam);
     }
   }, []);
 
@@ -137,7 +137,7 @@ export function UserSearch() {
   const copyProfileLink = () => {
     if (!searchResult) return;
     const profileUrl = `${window.location.origin}/user/profile/${searchResult.username}`;
-    navigator.clipboard.writeText(profileUrl).then(() => {
+    void navigator.clipboard.writeText(profileUrl).then(() => {
       setIsCopied(true);
       setTimeout(() => setIsCopied(false), 2000);
     });
@@ -382,7 +382,7 @@ export function UserSearch() {
             onOpenChange={setGiveCreditsOpen}
             onSuccess={() => {
               const api = new ModerationApi();
-              api.ListUserWallets(searchResult.token).then((resp) => {
+              void api.ListUserWallets(searchResult.token).then((resp) => {
                 if (resp.success && resp.data) {
                   setWallets(resp.data.wallets);
                 }
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserSignups.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserSignups.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserSignups.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserSignups.tsx
@@ -27,6 +27,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 export function UserSignups() {
   usePageTitle("User Signups");
@@ -41,9 +42,7 @@ export function UserSignups() {
   const [banDialogOpen, setBanDialogOpen] = useState(false);
 
   const cancelledRef = useRef(false);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadData = async (cursor?: number | null, append = false) => {
     if (!append) {
       setIsLoading(true);
@@ -81,7 +80,7 @@ export function UserSignups() {
     setUsers([]);
     setNextCursor(null);
     setSelectedUsernames(new Set());
-    loadData();
+    void loadData();
   };
 
   const toggleUser = (username: string, checked: boolean) => {
@@ -112,7 +111,7 @@ export function UserSignups() {
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
@@ -120,26 +119,11 @@ export function UserSignups() {
 
   const loadMore = useCallback(() => {
     if (!isLoadingMore && nextCursor != null) {
-      loadData(nextCursor, true);
+      void loadData(nextCursor, true);
     }
   }, [nextCursor, isLoadingMore]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-
-    if (sentinelRef.current) {
-      observerRef.current.observe(sentinelRef.current);
-    }
-
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserSpendHistory.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserSpendHistory.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserSpendHistory.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserSpendHistory.tsx
@@ -26,6 +26,7 @@ import {
   IconLoader2,
 } from "@tabler/icons-react";
 import { usePageTitle } from "@/hooks/usePageTitle";
+import { useInfiniteScroll } from "@/hooks/useInfiniteScroll";
 
 const PAGE_SIZE = 200;
 const COLUMN_COUNT = 8;
@@ -62,9 +63,7 @@ export function UserSpendHistory() {
 
   const cancelledRef = useRef(false);
   const tokenRef = useRef<string | null>(null);
-  const observerRef = useRef<IntersectionObserver | null>(null);
-  const sentinelRef = useRef<HTMLTableRowElement | null>(null);
-
+  
   const loadPage = useCallback(async (offset: number, append: boolean) => {
     const token = tokenRef.current;
     if (!token) return;
@@ -94,7 +93,7 @@ export function UserSpendHistory() {
     if (!username) return;
     cancelledRef.current = false;
 
-    (async () => {
+    void (async () => {
       setIsLoading(true);
       setError(null);
       setRows([]);
@@ -130,17 +129,7 @@ export function UserSpendHistory() {
     }
   }, [nextOffset, isLoadingMore, loadPage]);
 
-  useEffect(() => {
-    if (observerRef.current) observerRef.current.disconnect();
-    observerRef.current = new IntersectionObserver(
-      (entries) => {
-        if (entries[0].isIntersecting) loadMore();
-      },
-      { threshold: 0.1 },
-    );
-    if (sentinelRef.current) observerRef.current.observe(sentinelRef.current);
-    return () => observerRef.current?.disconnect();
-  }, [loadMore]);
+  const sentinelRef = useInfiniteScroll<HTMLTableRowElement>(loadMore);
 
   const { ref: tableRef, height: tableHeight } = useTableHeight();
 
diff --git a/frontend/apps/artcraft-dashboard/src/pages/UserSpendSummary.tsx b/frontend/apps/artcraft-dashboard/src/pages/UserSpendSummary.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/UserSpendSummary.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/UserSpendSummary.tsx
@@ -108,7 +108,7 @@ export function UserSpendSummary() {
     if (!username) return;
     cancelledRef.current = false;
 
-    (async () => {
+    void (async () => {
       setIsLoading(true);
       setError(null);
       try {
diff --git a/frontend/apps/artcraft-dashboard/src/pages/WalletHistory.tsx b/frontend/apps/artcraft-dashboard/src/pages/WalletHistory.tsx
--- a/frontend/apps/artcraft-dashboard/src/pages/WalletHistory.tsx
+++ b/frontend/apps/artcraft-dashboard/src/pages/WalletHistory.tsx
@@ -105,7 +105,7 @@ export function WalletHistory() {
   const totalCredits = totalMonthly + totalBanked;
 
   const copyToClipboard = (text: string) => {
-    navigator.clipboard.writeText(text).then(() => {
+    void navigator.clipboard.writeText(text).then(() => {
       setCopiedToken(text);
       setTimeout(() => setCopiedToken(null), 2000);
     });
@@ -170,7 +170,7 @@ export function WalletHistory() {
 
   useEffect(() => {
     cancelledRef.current = false;
-    loadData();
+    void loadData();
     return () => {
       cancelledRef.current = true;
     };
diff --git a/frontend/apps/artcraft-webapp/src/components/auth/signup-form.tsx b/frontend/apps/artcraft-webapp/src/components/auth/signup-form.tsx
--- a/frontend/apps/artcraft-webapp/src/components/auth/signup-form.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/auth/signup-form.tsx
@@ -110,7 +110,7 @@ export const SignupForm = ({
         className="space-y-4"
         onSubmit={(e) => {
           e.preventDefault();
-          handleSignup();
+          void handleSignup();
         }}
       >
         {error && (
diff --git a/frontend/apps/artcraft-webapp/src/components/lightbox/LightboxDetails.tsx b/frontend/apps/artcraft-webapp/src/components/lightbox/LightboxDetails.tsx
--- a/frontend/apps/artcraft-webapp/src/components/lightbox/LightboxDetails.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/lightbox/LightboxDetails.tsx
@@ -120,7 +120,7 @@ export function LightboxDetails({
           audioPlayerRef.current = null;
         };
         audioPlayerRef.current = audio;
-        audio.play();
+        void audio.play();
         setPlayingAudioToken(token);
       }
     },
diff --git a/frontend/apps/artcraft-webapp/src/components/prompt-box/MediaReferenceRow.tsx b/frontend/apps/artcraft-webapp/src/components/prompt-box/MediaReferenceRow.tsx
--- a/frontend/apps/artcraft-webapp/src/components/prompt-box/MediaReferenceRow.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/prompt-box/MediaReferenceRow.tsx
@@ -381,7 +381,7 @@ const AudioRefTile = ({
         el.volume = 0.2;
         audioElRef.current = el;
         el.onended = () => setIsPlaying(false);
-        el.play();
+        void el.play();
         setIsPlaying(true);
       }
     },
diff --git a/frontend/apps/artcraft-webapp/src/components/settings-modal/ApiKeySection.tsx b/frontend/apps/artcraft-webapp/src/components/settings-modal/ApiKeySection.tsx
--- a/frontend/apps/artcraft-webapp/src/components/settings-modal/ApiKeySection.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/settings-modal/ApiKeySection.tsx
@@ -73,7 +73,7 @@ export function ApiKeySection(_props: ApiKeySectionProps) {
   };
 
   useEffect(() => {
-    load(true);
+    void load(true);
     // Load once on mount; pagination drives subsequent loads explicitly.
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);
@@ -82,7 +82,7 @@ export function ApiKeySection(_props: ApiKeySectionProps) {
     setCreating(false);
     // Reveal the full secret once; the truncated key then appears in the list.
     setCreatedKey(created);
-    load(true);
+    void load(true);
   };
 
   const handleDeleteConfirmed = async () => {
diff --git a/frontend/apps/artcraft-webapp/src/components/settings-modal/BillingSection.tsx b/frontend/apps/artcraft-webapp/src/components/settings-modal/BillingSection.tsx
--- a/frontend/apps/artcraft-webapp/src/components/settings-modal/BillingSection.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/settings-modal/BillingSection.tsx
@@ -36,7 +36,7 @@ export function BillingSection({ onCloseModal }: BillingSectionProps) {
         if (!cancelled) setIsLoading(false);
       }
     };
-    fetchSubscription();
+    void fetchSubscription();
     return () => {
       cancelled = true;
     };
diff --git a/frontend/apps/artcraft-webapp/src/components/topbar/TopBarActions.tsx b/frontend/apps/artcraft-webapp/src/components/topbar/TopBarActions.tsx
--- a/frontend/apps/artcraft-webapp/src/components/topbar/TopBarActions.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/topbar/TopBarActions.tsx
@@ -73,8 +73,8 @@ export function TopBarActions({ className }: { className?: string }) {
 
   useEffect(() => {
     if (user) {
-      fetchCredits().then(setCredits);
-      fetchHasPaidPlan().then(setHasPaidPlan);
+      void fetchCredits().then(setCredits);
+      void fetchHasPaidPlan().then(setHasPaidPlan);
     } else {
       setCredits(null);
       setHasPaidPlan(null);
@@ -83,7 +83,7 @@ export function TopBarActions({ className }: { className?: string }) {
 
   useEffect(() => {
     const handler = () => {
-      fetchCredits().then(setCredits);
+      void fetchCredits().then(setCredits);
     };
     window.addEventListener("credits-change", handler);
     return () => window.removeEventListener("credits-change", handler);
diff --git a/frontend/apps/artcraft-webapp/src/components/topbar/task-queue.tsx b/frontend/apps/artcraft-webapp/src/components/topbar/task-queue.tsx
--- a/frontend/apps/artcraft-webapp/src/components/topbar/task-queue.tsx
+++ b/frontend/apps/artcraft-webapp/src/components/topbar/task-queue.tsx
@@ -195,7 +195,7 @@ const CopyPromptButton = ({ prompt }: { prompt: string }) => {
         aria-label="Copy prompt"
         onClick={(e) => {
           e.stopPropagation();
-          navigator.clipboard.writeText(prompt);
+          void navigator.clipboard.writeText(prompt);
           setCopied(true);
           setTimeout(() => setCopied(false), 3000);
         }}
@@ -930,11 +930,11 @@ export const TaskQueue = () => {
       }
     };
 
-    load();
+    void load();
     const intervalId = setInterval(load, 5000);
 
     const handleTaskUpdate = () => {
-      if (!cancelled) load();
+      if (!cancelled) void load();
     };
     window.addEventListener("task-queue-update", handleTaskUpdate);
 
diff --git a/frontend/apps/artcraft-webapp/src/lib/session.ts b/frontend/apps/artcraft-webapp/src/lib/session.ts
--- a/frontend/apps/artcraft-webapp/src/lib/session.ts
+++ b/frontend/apps/artcraft-webapp/src/lib/session.ts
@@ -90,7 +90,7 @@ function ensureAuthChangeListener(): void {
   listenerAttached = true;
   window.addEventListener("auth-change", () => {
     invalidateSession();
-    refreshSession(true);
+    void refreshSession(true);
   });
 }
 
@@ -114,7 +114,7 @@ export function useSession(): UseSessionResult {
     ensureAuthChangeListener();
     if (!bootRequested) {
       bootRequested = true;
-      refreshSession();
+      void refreshSession();
     }
   }, []);
 
diff --git a/frontend/apps/artcraft-webapp/src/pages/checkout/success.tsx b/frontend/apps/artcraft-webapp/src/pages/checkout/success.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/checkout/success.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/checkout/success.tsx
@@ -64,7 +64,7 @@ const CheckoutSuccess = () => {
       setIsCheckingOnboarding(false);
     };
 
-    checkOnboarding();
+    void checkOnboarding();
   }, [searchParams]);
 
   if (isCheckingOnboarding) {
diff --git a/frontend/apps/artcraft-webapp/src/pages/create-object/components/mesh-upload.ts b/frontend/apps/artcraft-webapp/src/pages/create-object/components/mesh-upload.ts
--- a/frontend/apps/artcraft-webapp/src/pages/create-object/components/mesh-upload.ts
+++ b/frontend/apps/artcraft-webapp/src/pages/create-object/components/mesh-upload.ts
@@ -25,7 +25,7 @@ export async function uploadViewImage(
 ): Promise<RefImage | null> {
   const url = await readAsDataUrl(file);
   return new Promise((resolve) => {
-    uploadImage({
+    void uploadImage({
       title: `${label.toLowerCase()}-view-${Math.random().toString(36).substring(2, 10)}`,
       assetFile: file,
       progressCallback: (state) => {
diff --git a/frontend/apps/artcraft-webapp/src/pages/create-vfx/create-vfx.tsx b/frontend/apps/artcraft-webapp/src/pages/create-vfx/create-vfx.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/create-vfx/create-vfx.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/create-vfx/create-vfx.tsx
@@ -88,7 +88,7 @@ export default function CreateVFX() {
       pollers.set(resultId, cancel);
     };
 
-    (async () => {
+    void (async () => {
       try {
         const sessionJobs = await listSessionBackgroundChangeJobs();
         if (cancelled) return;
diff --git a/frontend/apps/artcraft-webapp/src/pages/forgot-password/forgot-password.tsx b/frontend/apps/artcraft-webapp/src/pages/forgot-password/forgot-password.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/forgot-password/forgot-password.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/forgot-password/forgot-password.tsx
@@ -63,7 +63,7 @@ const ForgotPassword = () => {
                 className="space-y-4"
                 onSubmit={(e) => {
                   e.preventDefault();
-                  handleRequestReset();
+                  void handleRequestReset();
                 }}
               >
                 {error && (
diff --git a/frontend/apps/artcraft-webapp/src/pages/forgot-password/verify-reset.tsx b/frontend/apps/artcraft-webapp/src/pages/forgot-password/verify-reset.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/forgot-password/verify-reset.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/forgot-password/verify-reset.tsx
@@ -130,7 +130,7 @@ const VerifyReset = () => {
                 className="space-y-4"
                 onSubmit={(e) => {
                   e.preventDefault();
-                  handleRedeemReset();
+                  void handleRedeemReset();
                 }}
               >
                 {error && (
diff --git a/frontend/apps/artcraft-webapp/src/pages/frame-extractor/frame-extractor.tsx b/frontend/apps/artcraft-webapp/src/pages/frame-extractor/frame-extractor.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/frame-extractor/frame-extractor.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/frame-extractor/frame-extractor.tsx
@@ -133,7 +133,7 @@ export default function FrameExtractor() {
     if (!token) return;
     setSearchParams({}, { replace: true });
 
-    (async () => {
+    void (async () => {
       try {
         const response = await new MediaFilesApi().GetMediaFileByToken({
           mediaFileToken: token,
diff --git a/frontend/apps/artcraft-webapp/src/pages/library/library.tsx b/frontend/apps/artcraft-webapp/src/pages/library/library.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/library/library.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/library/library.tsx
@@ -348,7 +348,7 @@ export default function Library() {
 
   // ── Auth ──────────────────────────────────────────────────────────────────
   useEffect(() => {
-    (async () => {
+    void (async () => {
       const usersApi = new UsersApi();
       const response = await usersApi.GetSession();
       if (response.success && response.data?.loggedIn && response.data.user) {
diff --git a/frontend/apps/artcraft-webapp/src/pages/login/login.tsx b/frontend/apps/artcraft-webapp/src/pages/login/login.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/login/login.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/login/login.tsx
@@ -82,7 +82,7 @@ const Login = () => {
         className="space-y-4"
         onSubmit={(e) => {
           e.preventDefault();
-          handleLogin();
+          void handleLogin();
         }}
       >
         {error && (
diff --git a/frontend/apps/artcraft-webapp/src/pages/onboarding/onboarding.tsx b/frontend/apps/artcraft-webapp/src/pages/onboarding/onboarding.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/onboarding/onboarding.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/onboarding/onboarding.tsx
@@ -36,7 +36,7 @@ const Onboarding = () => {
   const [error, setError] = useState("");
 
   useEffect(() => {
-    checkOnboardingStatus();
+    void checkOnboardingStatus();
   }, []);
 
   const getSuccessUrl = (afterUsernameStep = false) => {
diff --git a/frontend/apps/artcraft-webapp/src/pages/pagescene/demo-output-overlay.tsx b/frontend/apps/artcraft-webapp/src/pages/pagescene/demo-output-overlay.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/pagescene/demo-output-overlay.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/pagescene/demo-output-overlay.tsx
@@ -72,7 +72,7 @@ export function DemoOutputOverlay({
     setVideo(null);
     setView(videoToken ? "video" : "image");
 
-    (async () => {
+    void (async () => {
       const [imageResult, videoResult] = await Promise.all([
         imageToken ? resolveAsset(imageToken) : Promise.resolve(null),
         videoToken ? resolveAsset(videoToken) : Promise.resolve(null),
diff --git a/frontend/apps/artcraft-webapp/src/pages/pagescene/splash/SceneSplashCard.tsx b/frontend/apps/artcraft-webapp/src/pages/pagescene/splash/SceneSplashCard.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/pagescene/splash/SceneSplashCard.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/pagescene/splash/SceneSplashCard.tsx
@@ -135,7 +135,7 @@ function useSceneCardImages(outputToken: string): {
     setPreviewUrl(null);
     setHoverUrl(null);
 
-    (async () => {
+    void (async () => {
       try {
         const mediaResp = await new MediaFilesApi().GetMediaFileByToken({
           mediaFileToken: outputToken,
diff --git a/frontend/apps/artcraft-webapp/src/pages/pagescene/use-prompt-prefill-from-output.ts b/frontend/apps/artcraft-webapp/src/pages/pagescene/use-prompt-prefill-from-output.ts
--- a/frontend/apps/artcraft-webapp/src/pages/pagescene/use-prompt-prefill-from-output.ts
+++ b/frontend/apps/artcraft-webapp/src/pages/pagescene/use-prompt-prefill-from-output.ts
@@ -36,7 +36,7 @@ export function usePromptPrefillFromOutput(
     if (!outputToken) return;
     let cancelled = false;
 
-    (async () => {
+    void (async () => {
       try {
         const mediaResp = await new MediaFilesApi().GetMediaFileByToken({
           mediaFileToken: outputToken,
diff --git a/frontend/apps/artcraft-webapp/src/pages/pricing/pricing.tsx b/frontend/apps/artcraft-webapp/src/pages/pricing/pricing.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/pricing/pricing.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/pricing/pricing.tsx
@@ -35,7 +35,7 @@ const Pricing = () => {
         // not logged in
       }
     };
-    check();
+    void check();
   }, []);
 
   return (
diff --git a/frontend/apps/artcraft-webapp/src/pages/set-password/set-password.tsx b/frontend/apps/artcraft-webapp/src/pages/set-password/set-password.tsx
--- a/frontend/apps/artcraft-webapp/src/pages/set-password/set-password.tsx
+++ b/frontend/apps/artcraft-webapp/src/pages/set-password/set-password.tsx
@@ -83,7 +83,7 @@ const SetPassword = () => {
             className="space-y-4"
             onSubmit={(e) => {
               e.preventDefault();
-              handleSetPassword();
+              void handleSetPassword();
             }}
           >
             {error && (
diff --git a/frontend/apps/artcraft-website-next/src/components/media/media-details.tsx b/frontend/apps/artcraft-website-next/src/components/media/media-details.tsx
--- a/frontend/apps/artcraft-website-next/src/components/media/media-details.tsx
+++ b/frontend/apps/artcraft-website-next/src/components/media/media-details.tsx
@@ -105,7 +105,7 @@ export default function MediaDetails({ media, prompt, promptLoading, dimensions
             {prompt?.maybe_positive_prompt && (
               <button type="button" className="text-muted hover:text-ink" aria-label={copied === "prompt" ? "Prompt copied" : "Copy prompt"}
                 onClick={() => {
-                  copy(prompt.maybe_positive_prompt!, "prompt");
+                  void copy(prompt.maybe_positive_prompt!, "prompt");
                   trackEvent("copy_prompt", { media_type: kind });
                 }}>
                 {copied === "prompt" ? <CheckIcon className="h-4 w-4" /> : <CopyIcon className="h-4 w-4" />}
@@ -149,7 +149,7 @@ export default function MediaDetails({ media, prompt, promptLoading, dimensions
           <ArrowDownToLineIcon aria-hidden className="h-4 w-4" />{downloading ? "Downloading" : "Download file"}
         </Button>
         <Button variant="secondary" className="w-full" onClick={() => {
-          copy(`${SHARE_URL_BASE}${encodeURIComponent(media.token)}`, "link");
+          void copy(`${SHARE_URL_BASE}${encodeURIComponent(media.token)}`, "link");
           trackEvent("share", { method: "copy_link", content_type: kind, item_id: media.token });
         }}>
           {copied === "link" ? <CheckIcon aria-hidden className="h-4 w-4" /> : <CopyIcon aria-hidden className="h-4 w-4" />}
diff --git a/frontend/apps/artcraft-website-next/src/lib/use-account.ts b/frontend/apps/artcraft-website-next/src/lib/use-account.ts
--- a/frontend/apps/artcraft-website-next/src/lib/use-account.ts
+++ b/frontend/apps/artcraft-website-next/src/lib/use-account.ts
@@ -50,7 +50,7 @@ export function useAccount(): Account {
 
   useEffect(() => {
     let live = true;
-    loadAccount().then((a) => {
+    void loadAccount().then((a) => {
       if (live) setAccount(a);
     });
     return () => {
diff --git a/frontend/apps/genhub/src/components/feed/media-detail.tsx b/frontend/apps/genhub/src/components/feed/media-detail.tsx
--- a/frontend/apps/genhub/src/components/feed/media-detail.tsx
+++ b/frontend/apps/genhub/src/components/feed/media-detail.tsx
@@ -39,7 +39,7 @@ export function MediaDetail({ item }: MediaDetailProps) {
   const likeCount = liked ? item.likes + 1 : item.likes;
 
   function handleCopy() {
-    navigator.clipboard.writeText(item.prompt);
+    void navigator.clipboard.writeText(item.prompt);
     setCopied(true);
     setTimeout(() => setCopied(false), 2000);
   }
diff --git a/frontend/apps/genhub/src/components/layout/navbar.tsx b/frontend/apps/genhub/src/components/layout/navbar.tsx
--- a/frontend/apps/genhub/src/components/layout/navbar.tsx
+++ b/frontend/apps/genhub/src/components/layout/navbar.tsx
@@ -126,7 +126,7 @@ export function Navbar() {
                 variant="ghost"
                 className="justify-start"
                 onClick={() => {
-                  logout();
+                  void logout();
                   setMobileOpen(false);
                 }}
               >
diff --git a/frontend/libs/components/create-3d-modal/src/lib/create-3d-modal.tsx b/frontend/libs/components/create-3d-modal/src/lib/create-3d-modal.tsx
--- a/frontend/libs/components/create-3d-modal/src/lib/create-3d-modal.tsx
+++ b/frontend/libs/components/create-3d-modal/src/lib/create-3d-modal.tsx
@@ -94,16 +94,16 @@ export const Create3dModal = ({ onModelComplete }: Create3dModalProps = {}) => {
       });
 
       if (isUnmounted) {
-        unlisten.then((f) => f()); // Unsubscribe if unmounted early.
+        void unlisten.then((f) => f()); // Unsubscribe if unmounted early.
       }
     };
 
-    setup();
+    void setup();
 
     return () => {
       isUnmounted = true;
       if (unlisten) {
-        unlisten.then((f) => f());
+        void unlisten.then((f) => f());
       }
     };
   }, []);
diff --git a/frontend/libs/components/gallery-modal/src/lib/gallery-modal.tsx b/frontend/libs/components/gallery-modal/src/lib/gallery-modal.tsx
--- a/frontend/libs/components/gallery-modal/src/lib/gallery-modal.tsx
+++ b/frontend/libs/components/gallery-modal/src/lib/gallery-modal.tsx
@@ -948,7 +948,7 @@ export const GalleryModal = React.memo(
       // couldn't see it — making the library button appear broken.
       galleryModalDraggingUnder.value = false;
       let cancelled = false;
-      (async () => {
+      void (async () => {
         setUsernameError(false);
         const name = await fetchCurrentUsername();
         if (cancelled) return;
diff --git a/frontend/libs/components/generation-list/src/lib/media-prompt-token-cache.ts b/frontend/libs/components/generation-list/src/lib/media-prompt-token-cache.ts
--- a/frontend/libs/components/generation-list/src/lib/media-prompt-token-cache.ts
+++ b/frontend/libs/components/generation-list/src/lib/media-prompt-token-cache.ts
@@ -90,7 +90,7 @@ export function useMediaPromptTokens(
   const key = [...new Set(cleaned)].sort().join(",");
 
   useEffect(() => {
-    if (key.length > 0) fetchMissing(key.split(","));
+    if (key.length > 0) void fetchMissing(key.split(","));
   }, [key]);
 
   const result = new Map<string, string>();
diff --git a/frontend/libs/components/generation-list/src/lib/prompts-cache.ts b/frontend/libs/components/generation-list/src/lib/prompts-cache.ts
--- a/frontend/libs/components/generation-list/src/lib/prompts-cache.ts
+++ b/frontend/libs/components/generation-list/src/lib/prompts-cache.ts
@@ -63,7 +63,7 @@ export function usePrompts(
   const key = [...new Set(cleaned)].sort().join(",");
 
   useEffect(() => {
-    if (key.length > 0) fetchMissing(key.split(","));
+    if (key.length > 0) void fetchMissing(key.split(","));
   }, [key]);
 
   const result = new Map<string, Prompts>();
diff --git a/frontend/libs/components/help-menu/src/lib/help-menu.tsx b/frontend/libs/components/help-menu/src/lib/help-menu.tsx
--- a/frontend/libs/components/help-menu/src/lib/help-menu.tsx
+++ b/frontend/libs/components/help-menu/src/lib/help-menu.tsx
@@ -42,7 +42,7 @@ const NewsView = ({ onBack }: { onBack: () => void }) => {
         console.warn("Failed to fetch news feed, using bundled content.", e);
       }
     };
-    fetchNews();
+    void fetchNews();
   }, []);
 
   const selectedPost = useMemo(
@@ -312,7 +312,7 @@ export function HelpMenuButton({
       });
     };
 
-    run();
+    void run();
 
     return () => {
       if (progressTimerRef.current) {
diff --git a/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx b/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx
--- a/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx
+++ b/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx
@@ -179,7 +179,7 @@ export function LightboxModal({
           audioPlayerRef.current = null;
         };
         audioPlayerRef.current = audio;
-        audio.play();
+        void audio.play();
         setPlayingAudioToken(token);
       }
     },
diff --git a/frontend/libs/components/lightbox-modal/src/lib/tags/TagsSection.tsx b/frontend/libs/components/lightbox-modal/src/lib/tags/TagsSection.tsx
--- a/frontend/libs/components/lightbox-modal/src/lib/tags/TagsSection.tsx
+++ b/frontend/libs/components/lightbox-modal/src/lib/tags/TagsSection.tsx
@@ -83,7 +83,7 @@ export function TagsSection({
   useEffect(() => {
     if (currentUsername !== undefined) return;
     let cancelled = false;
-    resolveSessionUsername().then((username) => {
+    void resolveSessionUsername().then((username) => {
       if (!cancelled) setResolvedUsername(username);
     });
     return () => {
@@ -133,7 +133,7 @@ export function TagsSection({
     }
     ownTagsLoadedRef.current = true;
     let cancelled = false;
-    (async () => {
+    void (async () => {
       const all: TagDetails[] = [];
       let cursor: string | undefined = undefined;
       for (let page = 0; page < 50; page++) {
diff --git a/frontend/libs/components/pagedraw/src/lib/PageDraw.tsx b/frontend/libs/components/pagedraw/src/lib/PageDraw.tsx
--- a/frontend/libs/components/pagedraw/src/lib/PageDraw.tsx
+++ b/frontend/libs/components/pagedraw/src/lib/PageDraw.tsx
@@ -1040,7 +1040,7 @@ const PageDraw = ({
       await tryFit();
     };
 
-    autoFitCanvas();
+    void autoFitCanvas();
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [baseImageBitmap, baseImageInfo?.isBlankCanvas]);
 
diff --git a/frontend/libs/components/pagedraw/src/lib/PaintSurface.tsx b/frontend/libs/components/pagedraw/src/lib/PaintSurface.tsx
--- a/frontend/libs/components/pagedraw/src/lib/PaintSurface.tsx
+++ b/frontend/libs/components/pagedraw/src/lib/PaintSurface.tsx
@@ -1501,7 +1501,7 @@ export const PaintSurface = ({
 
   // Load the checkboard image for transparency background
   useEffect(() => {
-    loadImageFromUrl(checkerboard).then(setCheckerImage);
+    void loadImageFromUrl(checkerboard).then(setCheckerImage);
   }, []);
 
   // Separate function to render transformers on their own layer
diff --git a/frontend/libs/components/pagedraw/src/lib/stores/SceneState.ts b/frontend/libs/components/pagedraw/src/lib/stores/SceneState.ts
--- a/frontend/libs/components/pagedraw/src/lib/stores/SceneState.ts
+++ b/frontend/libs/components/pagedraw/src/lib/stores/SceneState.ts
@@ -1167,7 +1167,7 @@ export const useSceneStore = create<SceneState>((set, get, store) => ({
                 console.error("Failed to restore image:", error);
               }
             };
-            loadImage();
+            void loadImage();
           }
 
           return node;
diff --git a/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx b/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
--- a/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
+++ b/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
@@ -386,7 +386,7 @@ export const Stage3DBody = ({
   useEffect(() => {
     const handler = onImageDrop(
       (item: GalleryItem, position: { x: number; y: number }) => {
-        (async () => {
+        void (async () => {
           if (!editor) {
             console.warn("Cannot drop asset: editor engine not ready");
             return;
diff --git a/frontend/libs/components/pagescene/src/lib/actions/toggleObjectVisibility.ts b/frontend/libs/components/pagescene/src/lib/actions/toggleObjectVisibility.ts
--- a/frontend/libs/components/pagescene/src/lib/actions/toggleObjectVisibility.ts
+++ b/frontend/libs/components/pagescene/src/lib/actions/toggleObjectVisibility.ts
@@ -14,7 +14,7 @@ export function toggleObjectVisibility(editor: Editor, uuid: string): void {
   if (!obj) return;
   const before = obj.visible;
   editor.bus.emit(new OutlinerItemVisibilityToggledEvent(uuid));
-  editor.sceneManager?.hideObject(uuid);
+  void editor.sceneManager?.hideObject(uuid);
   editor.history.record(
     new VisibilityAction(editor, uuid, before, !before),
   );
diff --git a/frontend/libs/components/pagescene/src/lib/engine/editor.ts b/frontend/libs/components/pagescene/src/lib/engine/editor.ts
--- a/frontend/libs/components/pagescene/src/lib/engine/editor.ts
+++ b/frontend/libs/components/pagescene/src/lib/engine/editor.ts
@@ -190,7 +190,7 @@ class Editor {
     // Ammo.js WASM is a global side-effect script the physics path
     // depends on. The singleton ensures it's appended to document.body
     // exactly once, even across Editor re-construction.
-    ensureAmmoLoaded();
+    void ensureAmmoLoaded();
 
     // Version and name.
     this.version = 2.0;
@@ -667,9 +667,9 @@ class Editor {
     };
 
     if (!this.utils.isEmpty(cacheJson)) {
-      this.save_manager.loadCache(cacheJson).then(applyIfLoaded);
+      void this.save_manager.loadCache(cacheJson).then(applyIfLoaded);
     } else if (!this.utils.isEmpty(sceneToken)) {
-      this.save_manager.loadScene(sceneToken).then(applyIfLoaded);
+      void this.save_manager.loadScene(sceneToken).then(applyIfLoaded);
     } else {
       this.adapter.onSceneTitleChange?.({
         title: "Untitled New Scene",
@@ -1065,7 +1065,7 @@ class Editor {
     }
 
     this.lastFrameTime = frameTime;
-    this.renderSingleFrame();
+    void this.renderSingleFrame();
   }
 
   startRenderLoop() {
diff --git a/frontend/libs/components/pagescene/src/lib/engine/editor/ModalTransformController.ts b/frontend/libs/components/pagescene/src/lib/engine/editor/ModalTransformController.ts
--- a/frontend/libs/components/pagescene/src/lib/engine/editor/ModalTransformController.ts
+++ b/frontend/libs/components/pagescene/src/lib/engine/editor/ModalTransformController.ts
@@ -151,7 +151,7 @@ export class ModalTransformController {
       }
     }
     this.target.position.copy(this.startPos).add(delta);
-    this.editor.renderScene();
+    void this.editor.renderScene();
   }
 
   private axisVector(axis: "x" | "y" | "z"): THREE.Vector3 {
@@ -190,7 +190,7 @@ export class ModalTransformController {
 
   private cancel() {
     if (this.target) this.target.position.copy(this.startPos);
-    this.editor.renderScene();
+    void this.editor.renderScene();
     this.cleanup();
   }
 
diff --git a/frontend/libs/components/pagescene/src/lib/engine/placeholder_manager.ts b/frontend/libs/components/pagescene/src/lib/engine/placeholder_manager.ts
--- a/frontend/libs/components/pagescene/src/lib/engine/placeholder_manager.ts
+++ b/frontend/libs/components/pagescene/src/lib/engine/placeholder_manager.ts
@@ -77,7 +77,7 @@ export class LoadingPlaceHolderManager {
     if (result === undefined) {
       return;
     }
-    result.destroyWithScene(this.scene);
+    void result.destroyWithScene(this.scene);
     this.messages.delete(id);
   }
 
diff --git a/frontend/libs/components/pagescene/src/lib/engine/scene.ts b/frontend/libs/components/pagescene/src/lib/engine/scene.ts
--- a/frontend/libs/components/pagescene/src/lib/engine/scene.ts
+++ b/frontend/libs/components/pagescene/src/lib/engine/scene.ts
@@ -112,7 +112,7 @@ class Scene {
   initialize() {
     this.scene = new THREE.Scene();
     this.placeholder_manager = new LoadingPlaceHolderManager(this.scene);
-    this.placeholder_manager.initialize();
+    void this.placeholder_manager.initialize();
 
     this._createGrid();
     this._create_base_lighting();
diff --git a/frontend/libs/components/pricing-modal/src/lib/use-currency.ts b/frontend/libs/components/pricing-modal/src/lib/use-currency.ts
--- a/frontend/libs/components/pricing-modal/src/lib/use-currency.ts
+++ b/frontend/libs/components/pricing-modal/src/lib/use-currency.ts
@@ -170,7 +170,7 @@ export function useCurrency(): UseCurrencyResult {
 
   useEffect(() => {
     let cancelled = false;
-    fetchRates().then((r) => {
+    void fetchRates().then((r) => {
       if (!cancelled) {
         setRates(r);
         setRatesLoaded(true);
diff --git a/frontend/libs/components/pricing-table/src/lib/pricing-table.tsx b/frontend/libs/components/pricing-table/src/lib/pricing-table.tsx
--- a/frontend/libs/components/pricing-table/src/lib/pricing-table.tsx
+++ b/frontend/libs/components/pricing-table/src/lib/pricing-table.tsx
@@ -130,7 +130,7 @@ const PricingTable = ({
       }
     };
 
-    fetchUserData();
+    void fetchUserData();
   }, []);
 
   const plans = includeFree
diff --git a/frontend/libs/components/promptbox/src/lib/ImagePromptRow.tsx b/frontend/libs/components/promptbox/src/lib/ImagePromptRow.tsx
--- a/frontend/libs/components/promptbox/src/lib/ImagePromptRow.tsx
+++ b/frontend/libs/components/promptbox/src/lib/ImagePromptRow.tsx
@@ -102,7 +102,7 @@ const AudioRefTile = ({
         el.volume = 0.2;
         audioRef.current = el;
         el.onended = () => setIsPlaying(false);
-        el.play();
+        void el.play();
         setIsPlaying(true);
       }
     },
diff --git a/frontend/libs/components/promptbox/src/lib/PromptBox2D.tsx b/frontend/libs/components/promptbox/src/lib/PromptBox2D.tsx
--- a/frontend/libs/components/promptbox/src/lib/PromptBox2D.tsx
+++ b/frontend/libs/components/promptbox/src/lib/PromptBox2D.tsx
@@ -347,7 +347,7 @@ export const PromptBox2D = ({
     const isSubmitCombo = enterToGenerate && !e.shiftKey;
     if (isSubmitCombo) {
       e.preventDefault();
-      handleGenerate();
+      void handleGenerate();
     }
   };
 
diff --git a/frontend/libs/components/promptbox/src/lib/PromptBox3D.tsx b/frontend/libs/components/promptbox/src/lib/PromptBox3D.tsx
--- a/frontend/libs/components/promptbox/src/lib/PromptBox3D.tsx
+++ b/frontend/libs/components/promptbox/src/lib/PromptBox3D.tsx
@@ -543,7 +543,7 @@ export const PromptBox3D = ({
     const isSubmitCombo = enterToGenerate && !e.shiftKey;
     if (isSubmitCombo) {
       e.preventDefault();
-      handleEnqueue();
+      void handleEnqueue();
     }
   };
 
diff --git a/frontend/libs/components/promptbox/src/lib/PromptBoxAudio.tsx b/frontend/libs/components/promptbox/src/lib/PromptBoxAudio.tsx
--- a/frontend/libs/components/promptbox/src/lib/PromptBoxAudio.tsx
+++ b/frontend/libs/components/promptbox/src/lib/PromptBoxAudio.tsx
@@ -352,7 +352,7 @@ export const PromptBoxAudio = ({
     if (e.key !== "Enter") return;
     if (enterToGenerate && !e.shiftKey) {
       e.preventDefault();
-      handleEnqueue();
+      void handleEnqueue();
     }
   };
 
diff --git a/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx b/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx
--- a/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx
+++ b/frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx
@@ -454,7 +454,7 @@ export const PromptBoxImage = ({
     const isSubmitCombo = enterToGenerate && !e.shiftKey;
     if (isSubmitCombo) {
       e.preventDefault();
-      handleEnqueue();
+      void handleEnqueue();
     }
   };
 
diff --git a/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx b/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx
--- a/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx
+++ b/frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx
@@ -1211,7 +1211,7 @@ export const PromptBoxVideo = ({
       console.error("PromptBoxVideo - enqueue failed", failure.reason);
       toast.error(commandErrorMessage(failure.reason, "Failed to start video generation. Please try again."));
     }
-    if (acceptedIds.length) onEnqueuePressed?.(prompt, acceptedIds);
+    if (acceptedIds.length) void onEnqueuePressed?.(prompt, acceptedIds);
 
     setIsEnqueueing(false);
   };
@@ -1262,7 +1262,7 @@ export const PromptBoxVideo = ({
         return;
       }
 
-      handleEnqueue();
+      void handleEnqueue();
     }
   };
 
@@ -1374,7 +1374,7 @@ export const PromptBoxVideo = ({
                       )
                         return;
                       if (!prompt.trim()) return;
-                      handleEnqueue();
+                      void handleEnqueue();
                     }
                   }}
                   onFocus={() => setIsFocused(true)}
diff --git a/frontend/libs/components/promptbox/src/lib/deck/DeckCard.tsx b/frontend/libs/components/promptbox/src/lib/deck/DeckCard.tsx
--- a/frontend/libs/components/promptbox/src/lib/deck/DeckCard.tsx
+++ b/frontend/libs/components/promptbox/src/lib/deck/DeckCard.tsx
@@ -68,7 +68,7 @@ export const DeckCard = ({
       el.volume = 0.2;
       audioRef.current = el;
       el.onended = () => setIsPlaying(false);
-      el.play();
+      void el.play();
       setIsPlaying(true);
     }
   }, [isPlaying, item.url, stopAudio]);
diff --git a/frontend/libs/components/promptbox/src/lib/deck/useDeckMedia.tsx b/frontend/libs/components/promptbox/src/lib/deck/useDeckMedia.tsx
--- a/frontend/libs/components/promptbox/src/lib/deck/useDeckMedia.tsx
+++ b/frontend/libs/components/promptbox/src/lib/deck/useDeckMedia.tsx
@@ -524,8 +524,8 @@ export function useDeckMedia<
     );
 
     if (images.length > 0) processImageFiles(images, "start");
-    if (videos.length > 0 && setReferenceVideos) processVideoFiles(videos);
-    if (audios.length > 0 && setReferenceAudios) processAudioFiles(audios);
+    if (videos.length > 0 && setReferenceVideos) void processVideoFiles(videos);
+    if (audios.length > 0 && setReferenceAudios) void processAudioFiles(audios);
   };
 
   // maxImages of 0 means the page's model takes no image refs at all.
diff --git a/frontend/libs/components/upload-modal/src/lib/UploadModal3D/UploadFiles3D.tsx b/frontend/libs/components/upload-modal/src/lib/UploadModal3D/UploadFiles3D.tsx
--- a/frontend/libs/components/upload-modal/src/lib/UploadModal3D/UploadFiles3D.tsx
+++ b/frontend/libs/components/upload-modal/src/lib/UploadModal3D/UploadFiles3D.tsx
@@ -270,7 +270,7 @@ export const UploadFiles3D = ({
   // B's key.
   useEffect(() => {
     if (previewStatus.type === "OK" && canvasRef.current) {
-      snapshotCanvasAsThumbnail({
+      void snapshotCanvasAsThumbnail({
         targetNode: canvasRef.current,
         resultCallback: (blob) => {
           const currentFile = fileEntries[previewIndex]?.file;
@@ -503,7 +503,7 @@ export const UploadFiles3D = ({
     // can only ever be a clean single-file submission; the excludedCount
     // check makes that invariant explicit rather than incidental.
     if (excludedCount === 0 && files.length === 1 && fileEntries.length === 1) {
-      upload3DObjects({
+      void upload3DObjects({
         title: files[0].name.slice(0, files[0].name.lastIndexOf(".")),
         assetFile: files[0],
         engineCategory,
@@ -521,7 +521,7 @@ export const UploadFiles3D = ({
     setIsUploading(true);
     setOverallProgress({ current: 0, total: files.length });
 
-    upload3DObjectsBatch({
+    void upload3DObjectsBatch({
       files,
       thumbnails: pendingThumbnails,
       engineCategory,
@@ -581,7 +581,7 @@ export const UploadFiles3D = ({
     setIsUploading(true);
     setOverallProgress({ current: 0, total: failedFiles.length });
 
-    upload3DObjectsBatch({
+    void upload3DObjectsBatch({
       files: failedFiles,
       thumbnails: failedThumbnails,
       engineCategory,
@@ -742,7 +742,7 @@ export const UploadFiles3D = ({
                         className="hidden items-center text-xs text-white/60 transition-colors hover:text-white group-hover:inline-flex"
                         onClick={(e) => {
                           e.stopPropagation();
-                          retrySingleFile(i);
+                          void retrySingleFile(i);
                         }}
                         title="Retry"
                       >
diff --git a/frontend/libs/components/upload-modal/src/lib/UploadModalImage/UploadFilesImage.tsx b/frontend/libs/components/upload-modal/src/lib/UploadModalImage/UploadFilesImage.tsx
--- a/frontend/libs/components/upload-modal/src/lib/UploadModalImage/UploadFilesImage.tsx
+++ b/frontend/libs/components/upload-modal/src/lib/UploadModalImage/UploadFilesImage.tsx
@@ -117,7 +117,7 @@ export const UploadFilesImage = ({
       .filter((i) => i !== -1);
 
     if (files.length === 1 && fileEntries.length === 1) {
-      uploadImage({
+      void uploadImage({
         title: files[0].name.slice(0, files[0].name.lastIndexOf(".")),
         assetFile: files[0],
         progressCallback: onUploadProgress,
@@ -128,7 +128,7 @@ export const UploadFilesImage = ({
     setIsUploading(true);
     setOverallProgress({ current: 0, total: files.length });
 
-    uploadImagesBatch({
+    void uploadImagesBatch({
       files,
       onFileStatusChange: (batchIndex, status, errorMessage) =>
         updateFileStatus(originalIndices[batchIndex], status, errorMessage),
@@ -159,7 +159,7 @@ export const UploadFilesImage = ({
     setIsUploading(true);
     setOverallProgress({ current: 0, total: failedFiles.length });
 
-    uploadImagesBatch({
+    void uploadImagesBatch({
       files: failedFiles,
       onFileStatusChange: (batchIndex, status, errorMessage) =>
         updateFileStatus(failedIndices[batchIndex], status, errorMessage),
@@ -248,7 +248,7 @@ export const UploadFilesImage = ({
                           className="hidden group-hover:inline-flex items-center text-xs text-white/60 hover:text-white transition-colors"
                           onClick={(e) => {
                             e.stopPropagation();
-                            retrySingleFile(i);
+                            void retrySingleFile(i);
                           }}
                           title="Retry"
                         >
diff --git a/frontend/libs/components/upload-modal/src/lib/UploadModalSplat/UploadFilesSplat.tsx b/frontend/libs/components/upload-modal/src/lib/UploadModalSplat/UploadFilesSplat.tsx
--- a/frontend/libs/components/upload-modal/src/lib/UploadModalSplat/UploadFilesSplat.tsx
+++ b/frontend/libs/components/upload-modal/src/lib/UploadModalSplat/UploadFilesSplat.tsx
@@ -127,7 +127,7 @@ export const UploadFilesSplat = ({
       const canvas = canvasRef.current;
       const currentFile = fileEntries[previewIndex]?.file;
       const rafId = requestAnimationFrame(() => {
-        snapshotCanvasAsThumbnail({
+        void snapshotCanvasAsThumbnail({
           targetNode: canvas,
           resultCallback: (blob) => {
             if (blob && currentFile) {
@@ -222,7 +222,7 @@ export const UploadFilesSplat = ({
     );
 
     if (files.length === 1 && fileEntries.length === 1) {
-      upload3DObjects({
+      void upload3DObjects({
         title: files[0].name.slice(0, files[0].name.lastIndexOf(".")),
         assetFile: files[0],
         engineCategory,
@@ -236,7 +236,7 @@ export const UploadFilesSplat = ({
     setIsUploading(true);
     setOverallProgress({ current: 0, total: files.length });
 
-    upload3DObjectsBatch({
+    void upload3DObjectsBatch({
       files,
       thumbnails: pendingThumbnails,
       engineCategory,
@@ -277,7 +277,7 @@ export const UploadFilesSplat = ({
     setIsUploading(true);
     setOverallProgress({ current: 0, total: failedFiles.length });
 
-    upload3DObjectsBatch({
+    void upload3DObjectsBatch({
       files: failedFiles,
       thumbnails: failedThumbnails,
       engineCategory,
@@ -375,7 +375,7 @@ export const UploadFilesSplat = ({
                         className="hidden group-hover:inline-flex items-center text-xs text-white/60 hover:text-white transition-colors"
                         onClick={(e) => {
                           e.stopPropagation();
-                          retrySingleFile(i);
+                          void retrySingleFile(i);
                         }}
                         title="Retry"
                       >
diff --git a/frontend/libs/components/video-editor/src/lib/actions/use-editor-actions.ts b/frontend/libs/components/video-editor/src/lib/actions/use-editor-actions.ts
--- a/frontend/libs/components/video-editor/src/lib/actions/use-editor-actions.ts
+++ b/frontend/libs/components/video-editor/src/lib/actions/use-editor-actions.ts
@@ -441,7 +441,7 @@ export function useEditorActions() {
   useActionHandler(
     "toggle-bookmark",
     () => {
-      editor.scenes.toggleBookmark({ time: editor.playback.getCurrentTime() });
+      void editor.scenes.toggleBookmark({ time: editor.playback.getCurrentTime() });
     },
     undefined,
   );
diff --git a/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts b/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts
--- a/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts
+++ b/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts
@@ -21,7 +21,7 @@ export function useFontAtlas({ open }: { open: boolean }) {
     if (!open || atlas) return;
 
     setStatus("loading");
-    loadFontAtlas().then((data) => {
+    void loadFontAtlas().then((data) => {
       if (data) {
         setAtlas(data);
         setStatus("idle");
@@ -34,7 +34,7 @@ export function useFontAtlas({ open }: { open: boolean }) {
   const retry = useCallback(() => {
     clearFontAtlasCache();
     setStatus("loading");
-    loadFontAtlas().then((data) => {
+    void loadFontAtlas().then((data) => {
       if (data) {
         setAtlas(data);
         setStatus("idle");
diff --git a/frontend/libs/components/video-editor/src/lib/hooks/use-fullscreen.ts b/frontend/libs/components/video-editor/src/lib/hooks/use-fullscreen.ts
--- a/frontend/libs/components/video-editor/src/lib/hooks/use-fullscreen.ts
+++ b/frontend/libs/components/video-editor/src/lib/hooks/use-fullscreen.ts
@@ -20,7 +20,7 @@ export function useFullscreen({
   const toggleFullscreen = useCallback(() => {
     if (!containerRef.current) return;
     if (document.fullscreenElement) {
-      document.exitFullscreen();
+      void document.exitFullscreen();
     } else {
       containerRef.current.requestFullscreen();
     }
diff --git a/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/components/bookmarks.tsx b/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/components/bookmarks.tsx
--- a/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/components/bookmarks.tsx
+++ b/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/components/bookmarks.tsx
@@ -313,7 +313,7 @@ function BookmarkPopoverContent({
   }, [bookmark.color]);
 
   const handleRemove = () => {
-    editor.scenes.removeBookmark({ time });
+    void editor.scenes.removeBookmark({ time });
     onPopoverClose();
   };
 
@@ -334,7 +334,7 @@ function BookmarkPopoverContent({
       updates.duration = duration;
     }
     if (Object.keys(updates).length === 0) return;
-    editor.scenes.updateBookmark({ time, updates });
+    void editor.scenes.updateBookmark({ time, updates });
   };
   const maxDuration = mediaTimeToSeconds({
     time:
diff --git a/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/hooks/use-bookmark-drag.ts b/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/hooks/use-bookmark-drag.ts
--- a/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/hooks/use-bookmark-drag.ts
+++ b/frontend/libs/components/video-editor/src/lib/timeline/bookmarks/hooks/use-bookmark-drag.ts
@@ -240,7 +240,7 @@ export function useBookmarkDrag({
       const clampedTime =
         dragState.currentTime > duration ? duration : dragState.currentTime;
 
-      editor.scenes.moveBookmark({
+      void editor.scenes.moveBookmark({
         fromTime: dragState.bookmarkTime,
         toTime: clampedTime,
       });
diff --git a/frontend/libs/tauri-api/src/lib/events/CanvasBgRemovedEvent.ts b/frontend/libs/tauri-api/src/lib/events/CanvasBgRemovedEvent.ts
--- a/frontend/libs/tauri-api/src/lib/events/CanvasBgRemovedEvent.ts
+++ b/frontend/libs/tauri-api/src/lib/events/CanvasBgRemovedEvent.ts
@@ -22,15 +22,15 @@ export const useCanvasBgRemovedEvent = (asyncCallback: (event: CanvasBgRemovedEv
       });
 
       if (isUnmounted) {
-        unlisten.then(f => f()); // Unsubscribe if unmounted early.
+        void unlisten.then(f => f()); // Unsubscribe if unmounted early.
       }
     };
 
-    setup();
+    void setup();
     
     return () => {
       isUnmounted = true;
-      unlisten.then(f => f());
+      void unlisten.then(f => f());
     };
 
   }, []);
diff --git a/frontend/libs/tauri-api/src/lib/sora/useSoraLoginListener.ts b/frontend/libs/tauri-api/src/lib/sora/useSoraLoginListener.ts
--- a/frontend/libs/tauri-api/src/lib/sora/useSoraLoginListener.ts
+++ b/frontend/libs/tauri-api/src/lib/sora/useSoraLoginListener.ts
@@ -21,7 +21,7 @@ export function useSoraLoginListener(
       unlisten = stop;
     };
 
-    setupListener();
+    void setupListener();
 
     return () => {
       if (unlisten) unlisten();
diff --git a/frontend/libs/tauri-utils/src/lib/useWindowControls.ts b/frontend/libs/tauri-utils/src/lib/useWindowControls.ts
--- a/frontend/libs/tauri-utils/src/lib/useWindowControls.ts
+++ b/frontend/libs/tauri-utils/src/lib/useWindowControls.ts
@@ -16,7 +16,7 @@ export function useTauriWindowControls() {
     let unlistenUnmax: (() => void) | undefined;
     let unlistenResize: (() => void) | undefined;
 
-    (async () => {
+    void (async () => {
       try {
         const win = await getCurrentWindowSafe();
         setIsMaximized(await win.isMaximized());
