perf: bound SWR cache, clean stale storage, cap annotations
Add LRU cache provider (200 entries) to prevent unbounded SWR memory growth. Clean up stale PKCE localStorage keys on app init. Cap chart annotations to 20 visible reference lines with overflow indicator.
This commit is contained in:
@@ -7,6 +7,7 @@ import { LoadingOverlay, useSessionSync, SessionExpiryWarning } from '@ciphera-n
|
||||
import { logoutAction, getSessionAction, setSessionAction } from '@/app/actions/auth'
|
||||
import { getUserOrganizations, switchContext } from '@/lib/api/organization'
|
||||
import { logger } from '@/lib/utils/logger'
|
||||
import { cleanupStaleStorage } from '@/lib/utils/storage-cleanup'
|
||||
|
||||
interface User {
|
||||
id: string
|
||||
@@ -131,6 +132,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
// Initial load
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
cleanupStaleStorage()
|
||||
|
||||
// * 1. Check server-side session (cookies)
|
||||
let session: Awaited<ReturnType<typeof getSessionAction>> = null
|
||||
try {
|
||||
|
||||
42
lib/swr/cache-provider.ts
Normal file
42
lib/swr/cache-provider.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// * Bounded LRU cache provider for SWR
|
||||
// * Prevents unbounded memory growth during long sessions across many sites
|
||||
|
||||
const MAX_CACHE_ENTRIES = 200
|
||||
|
||||
export function boundedCacheProvider() {
|
||||
const map = new Map()
|
||||
const accessOrder: string[] = []
|
||||
|
||||
const touch = (key: string) => {
|
||||
const idx = accessOrder.indexOf(key)
|
||||
if (idx > -1) accessOrder.splice(idx, 1)
|
||||
accessOrder.push(key)
|
||||
}
|
||||
|
||||
const evict = () => {
|
||||
while (map.size > MAX_CACHE_ENTRIES && accessOrder.length > 0) {
|
||||
const oldest = accessOrder.shift()!
|
||||
map.delete(oldest)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
get(key: string) {
|
||||
if (map.has(key)) touch(key)
|
||||
return map.get(key)
|
||||
},
|
||||
set(key: string, value: any) {
|
||||
map.set(key, value)
|
||||
touch(key)
|
||||
evict()
|
||||
},
|
||||
delete(key: string) {
|
||||
map.delete(key)
|
||||
const idx = accessOrder.indexOf(key)
|
||||
if (idx > -1) accessOrder.splice(idx, 1)
|
||||
},
|
||||
keys() {
|
||||
return map.keys()
|
||||
},
|
||||
}
|
||||
}
|
||||
17
lib/utils/storage-cleanup.ts
Normal file
17
lib/utils/storage-cleanup.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// * Cleans up stale localStorage entries on app initialization
|
||||
// * Prevents accumulation from abandoned OAuth flows
|
||||
|
||||
export function cleanupStaleStorage() {
|
||||
if (typeof window === 'undefined') return
|
||||
|
||||
try {
|
||||
// * PKCE keys are only needed during the OAuth callback
|
||||
// * If we're not on the callback page, they're stale leftovers
|
||||
if (!window.location.pathname.includes('/auth/callback')) {
|
||||
localStorage.removeItem('oauth_state')
|
||||
localStorage.removeItem('oauth_code_verifier')
|
||||
}
|
||||
} catch {
|
||||
// * Ignore errors (private browsing, storage disabled, etc.)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user