A very performant and light (2mb in memory) link shortener and tracker. Written in Rust and React and uses Postgres/SQLite.

fix session expiration

Changed files
+39 -12
frontend
+1 -1
README.md
··· 30 30 ### From Docker 31 31 ```bash 32 32 docker build --build-arg API_URL=http://localhost:8080 -t simplelink . 33 - docker run simplelink -p 8080:8080 \ 33 + docker run -p 8080:8080 \ 34 34 -e JWT_SECRET=change-me-in-production \ 35 35 -e DATABASE_URL=postgres://user:password@host:port/database \ 36 36 simplelink
+14 -11
frontend/index.html
··· 1 1 <!doctype html> 2 2 <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8" /> 5 - <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 - <title>Vite + React + TS</title> 8 - </head> 9 - <body> 10 - <div id="root"></div> 11 - <script type="module" src="/src/main.tsx"></script> 12 - </body> 13 - </html> 3 + 4 + <head> 5 + <meta charset="UTF-8" /> 6 + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 7 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 8 + <title>SimpleLink</title> 9 + </head> 10 + 11 + <body> 12 + <div id="root"></div> 13 + <script type="module" src="/src/main.tsx"></script> 14 + </body> 15 + 16 + </html>
+14
frontend/src/api/client.ts
··· 15 15 return config; 16 16 }); 17 17 18 + api.interceptors.response.use( 19 + (response) => response, 20 + (error) => { 21 + if (error.response?.status === 401) { 22 + localStorage.removeItem('token'); 23 + localStorage.removeItem('user'); 24 + 25 + window.dispatchEvent(new Event('unauthorized')); 26 + } 27 + return Promise.reject(error); 28 + } 29 + ); 30 + 31 + 18 32 // Auth endpoints 19 33 export const login = async (email: string, password: string) => { 20 34 const response = await api.post<AuthResponse>('/auth/login', {
+10
frontend/src/context/AuthContext.tsx
··· 23 23 setUser(userData); 24 24 } 25 25 setIsLoading(false); 26 + 27 + const handleUnauthorized = () => { 28 + setUser(null); 29 + }; 30 + 31 + window.addEventListener('unauthorized', handleUnauthorized); 32 + 33 + return () => { 34 + window.removeEventListener('unauthorized', handleUnauthorized); 35 + }; 26 36 }, []); 27 37 28 38 const login = async (email: string, password: string) => {