auth.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // Store de autenticação: token + perfil do usuário, com persistência.
  2. //
  3. // Fluxo:
  4. // - `login(email, password)` → POST /v1/login, grava token + user;
  5. // - `loadMe()` → GET /v1/me para reidratar a sessão no refresh;
  6. // - `logout()` → limpa token e user.
  7. //
  8. // O perfil é guardado no localStorage só para evitar "flash" sem nome no header
  9. // durante o reload; a fonte de verdade continua sendo o /v1/me.
  10. import { writable, derived } from 'svelte/store';
  11. import { browser } from '$app/environment';
  12. import { api } from '../api/client.js';
  13. import { getToken, setToken, clearToken } from '../api/token.js';
  14. const USER_KEY = 'nettown_user';
  15. function readStoredUser() {
  16. if (!browser) return null;
  17. try {
  18. const raw = localStorage.getItem(USER_KEY);
  19. return raw ? JSON.parse(raw) : null;
  20. } catch {
  21. return null;
  22. }
  23. }
  24. function persistUser(user) {
  25. if (!browser) return;
  26. if (user) localStorage.setItem(USER_KEY, JSON.stringify(user));
  27. else localStorage.removeItem(USER_KEY);
  28. }
  29. function createAuthStore() {
  30. const { subscribe, set } = writable({
  31. user: readStoredUser(),
  32. token: getToken(),
  33. // `initialized` indica que já tentamos reidratar a sessão (evita piscar o guard).
  34. initialized: false
  35. });
  36. return {
  37. subscribe,
  38. /** Autentica e persiste a sessão. Retorna o user em caso de sucesso. */
  39. async login(email, password) {
  40. const data = await api.post('/v1/login', { body: { email, password }, auth: false });
  41. setToken(data.token);
  42. persistUser(data.user);
  43. set({ user: data.user, token: data.token, initialized: true });
  44. return data.user;
  45. },
  46. /** Reidrata a sessão a partir do token salvo. Retorna o perfil ou null. */
  47. async loadMe() {
  48. const token = getToken();
  49. if (!token) {
  50. set({ user: null, token: null, initialized: true });
  51. return null;
  52. }
  53. try {
  54. const profile = await api.get('/v1/me');
  55. persistUser(profile);
  56. set({ user: profile, token, initialized: true });
  57. return profile;
  58. } catch {
  59. // 401 já limpou o token no client; aqui só normalizamos o estado.
  60. persistUser(null);
  61. set({ user: null, token: null, initialized: true });
  62. return null;
  63. }
  64. },
  65. /** Encerra a sessão local. */
  66. logout() {
  67. clearToken();
  68. persistUser(null);
  69. set({ user: null, token: null, initialized: true });
  70. }
  71. };
  72. }
  73. export const auth = createAuthStore();
  74. /** `true` quando há token (sessão presumivelmente ativa). */
  75. export const isAuthenticated = derived(auth, ($auth) => Boolean($auth.token));