@allanfsouza/aether-sdk 2.4.4 → 2.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/auth.d.ts CHANGED
@@ -25,7 +25,6 @@ export interface Session {
25
25
  export declare class AuthModule {
26
26
  private client;
27
27
  private http;
28
- private refreshToken;
29
28
  private currentUser;
30
29
  constructor(client: PlataformaClient, http: AxiosInstance);
31
30
  login(email: string, password: string): Promise<LoginResponse>;
@@ -43,7 +42,13 @@ export declare class AuthModule {
43
42
  getSessions(): Promise<Session[]>;
44
43
  forgotPassword(email: string): Promise<any>;
45
44
  resetPassword(token: string, newPassword: string): Promise<any>;
45
+ /**
46
+ * @deprecated Use client.getRefreshToken() - mantido para compatibilidade
47
+ */
46
48
  getRefreshToken(): string | null;
49
+ /**
50
+ * @deprecated Use client.setRefreshToken() - mantido para compatibilidade
51
+ */
47
52
  setRefreshToken(token: string | null): void;
48
53
  /**
49
54
  * Alias para login, retornando { user, error } padrão do Showcase
@@ -82,10 +87,16 @@ export declare class AuthModule {
82
87
  }>;
83
88
  /**
84
89
  * Recupera a sessão atual (User + Token).
85
- * Se não tiver logado, retorna null ou tenta validar o token.
90
+ * Primeiro tenta memória, depois localStorage.
91
+ * Se não encontrar, retorna null.
86
92
  */
87
93
  getSession(): Promise<{
88
94
  user: User;
89
95
  access_token: string;
90
96
  } | null>;
97
+ /**
98
+ * Retorna o usuário atual (sem validar token).
99
+ * Útil para acesso síncrono aos dados do usuário.
100
+ */
101
+ getCurrentUser(): User | null;
91
102
  }
package/dist/auth.js CHANGED
@@ -1,14 +1,16 @@
1
1
  export class AuthModule {
2
2
  constructor(client, http) {
3
- this.refreshToken = null;
4
- // Armazena o user localmente para acesso rápido via getSession
3
+ // Armazena o user em memória para acesso rápido
4
+ // Persistência fica no PlataformaClient (localStorage)
5
5
  this.currentUser = null;
6
6
  this.client = client;
7
7
  this.http = http;
8
+ // Restaura user do localStorage se existir
9
+ this.currentUser = this.client.getUser();
8
10
  }
9
- // =================================================================
10
- // MÉTODOS ORIGINAIS (MANTIDOS)
11
- // =================================================================
11
+ // ==========================================================================
12
+ // MÉTODOS PRINCIPAIS
13
+ // ==========================================================================
12
14
  async login(email, password) {
13
15
  try {
14
16
  const { data } = await this.http.post("/auth/login", {
@@ -16,15 +18,17 @@ export class AuthModule {
16
18
  password,
17
19
  });
18
20
  if (data.accessToken) {
21
+ // Persiste automaticamente via PlataformaClient
19
22
  this.client.setToken(data.accessToken);
20
- this.refreshToken = data.refreshToken;
23
+ this.client.setRefreshToken(data.refreshToken);
24
+ this.client.setUser(data.user);
21
25
  this.currentUser = data.user;
22
26
  }
23
27
  return data;
24
28
  }
25
29
  catch (e) {
26
- this.client.setToken(null);
27
- this.refreshToken = null;
30
+ // Limpa tudo em caso de erro
31
+ this.client.clearSession();
28
32
  this.currentUser = null;
29
33
  throw e;
30
34
  }
@@ -32,9 +36,11 @@ export class AuthModule {
32
36
  async register(credentials) {
33
37
  try {
34
38
  const { data } = await this.http.post("/auth/register", credentials);
35
- // Se o register retornar token, configura:
39
+ // Se o register retornar token (auto-login), configura sessão
36
40
  if (data.accessToken) {
37
41
  this.client.setToken(data.accessToken);
42
+ this.client.setRefreshToken(data.refreshToken);
43
+ this.client.setUser(data.user);
38
44
  this.currentUser = data.user;
39
45
  }
40
46
  return data;
@@ -44,21 +50,28 @@ export class AuthModule {
44
50
  }
45
51
  }
46
52
  async refresh() {
47
- if (!this.refreshToken) {
53
+ // Tenta pegar do localStorage primeiro, depois da memória
54
+ const refreshToken = this.client.getRefreshToken() || this.getRefreshToken();
55
+ if (!refreshToken) {
48
56
  throw new Error("Nenhum refresh token disponível");
49
57
  }
50
58
  try {
51
59
  const { data } = await this.http.post("/auth/refresh", {
52
- refreshToken: this.refreshToken,
60
+ refreshToken,
53
61
  });
54
62
  if (data.accessToken) {
55
63
  this.client.setToken(data.accessToken);
64
+ // Se vier novo refresh token, atualiza
65
+ if (data.refreshToken) {
66
+ this.client.setRefreshToken(data.refreshToken);
67
+ }
56
68
  }
57
69
  return data;
58
70
  }
59
71
  catch (e) {
60
- this.client.setToken(null);
61
- this.refreshToken = null;
72
+ // Token expirado - limpa sessão
73
+ this.client.clearSession();
74
+ this.currentUser = null;
62
75
  throw e;
63
76
  }
64
77
  }
@@ -66,18 +79,17 @@ export class AuthModule {
66
79
  return `${this.client.apiUrl}/v1/auth/google`;
67
80
  }
68
81
  async logout() {
69
- if (this.refreshToken) {
82
+ const refreshToken = this.client.getRefreshToken();
83
+ if (refreshToken) {
70
84
  try {
71
- await this.http.post("/auth/logout", {
72
- refreshToken: this.refreshToken,
73
- });
85
+ await this.http.post("/auth/logout", { refreshToken });
74
86
  }
75
- catch (e) {
76
- // Ignora erro de logout
87
+ catch {
88
+ // Ignora erro de logout no servidor
77
89
  }
78
90
  }
79
- this.client.setToken(null);
80
- this.refreshToken = null;
91
+ // Limpa tudo (memória + localStorage)
92
+ this.client.clearSession();
81
93
  this.currentUser = null;
82
94
  }
83
95
  async logoutAll() {
@@ -85,8 +97,7 @@ export class AuthModule {
85
97
  await this.http.post("/auth/logout-all");
86
98
  }
87
99
  finally {
88
- this.client.setToken(null);
89
- this.refreshToken = null;
100
+ this.client.clearSession();
90
101
  this.currentUser = null;
91
102
  }
92
103
  }
@@ -105,15 +116,21 @@ export class AuthModule {
105
116
  });
106
117
  return data;
107
118
  }
119
+ /**
120
+ * @deprecated Use client.getRefreshToken() - mantido para compatibilidade
121
+ */
108
122
  getRefreshToken() {
109
- return this.refreshToken;
123
+ return this.client.getRefreshToken();
110
124
  }
125
+ /**
126
+ * @deprecated Use client.setRefreshToken() - mantido para compatibilidade
127
+ */
111
128
  setRefreshToken(token) {
112
- this.refreshToken = token;
129
+ this.client.setRefreshToken(token);
113
130
  }
114
- // =================================================================
115
- // NOVOS MÉTODOS (COMPATIBILIDADE COM SHOWCASE / SUPABASE STYLE)
116
- // =================================================================
131
+ // ==========================================================================
132
+ // MÉTODOS COMPATÍVEIS COM SUPABASE / SHOWCASE STYLE
133
+ // ==========================================================================
117
134
  /**
118
135
  * Alias para login, retornando { user, error } padrão do Showcase
119
136
  */
@@ -134,7 +151,7 @@ export class AuthModule {
134
151
  const data = await this.register({
135
152
  email: credentials.email,
136
153
  password: credentials.password,
137
- name: credentials.data?.name || credentials.email.split('@')[0],
154
+ name: credentials.data?.name || credentials.email.split("@")[0],
138
155
  });
139
156
  return { user: data.user, error: null };
140
157
  }
@@ -151,20 +168,51 @@ export class AuthModule {
151
168
  }
152
169
  /**
153
170
  * Recupera a sessão atual (User + Token).
154
- * Se não tiver logado, retorna null ou tenta validar o token.
171
+ * Primeiro tenta memória, depois localStorage.
172
+ * Se não encontrar, retorna null.
155
173
  */
156
174
  async getSession() {
157
175
  const token = this.client.getToken();
158
176
  if (!token)
159
177
  return null;
160
- // Se já temos o user em memória, retorna.
161
- // O ideal seria validar o token no backend (/auth/me), mas vamos simplificar.
178
+ // Tenta memória primeiro
162
179
  if (this.currentUser) {
163
180
  return {
164
181
  user: this.currentUser,
165
- access_token: token
182
+ access_token: token,
183
+ };
184
+ }
185
+ // Tenta localStorage
186
+ const savedUser = this.client.getUser();
187
+ if (savedUser) {
188
+ this.currentUser = savedUser;
189
+ return {
190
+ user: savedUser,
191
+ access_token: token,
192
+ };
193
+ }
194
+ // Última opção: valida token no backend
195
+ try {
196
+ const { data } = await this.http.get("/auth/me");
197
+ this.currentUser = data.user;
198
+ this.client.setUser(data.user);
199
+ return {
200
+ user: data.user,
201
+ access_token: token,
166
202
  };
167
203
  }
168
- return null;
204
+ catch {
205
+ // Token inválido/expirado - limpa sessão
206
+ this.client.clearSession();
207
+ this.currentUser = null;
208
+ return null;
209
+ }
210
+ }
211
+ /**
212
+ * Retorna o usuário atual (sem validar token).
213
+ * Útil para acesso síncrono aos dados do usuário.
214
+ */
215
+ getCurrentUser() {
216
+ return this.currentUser || this.client.getUser();
169
217
  }
170
218
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AxiosInstance } from "axios";
2
- import { AuthModule } from "./auth.js";
2
+ import { AuthModule, User } from "./auth.js";
3
3
  import { DatabaseModule } from "./database.js";
4
4
  import { StorageModule } from "./storage.js";
5
5
  import { FunctionsModule } from "./functions.js";
@@ -12,6 +12,11 @@ export type ClientConfig = {
12
12
  baseUrl?: string;
13
13
  projectId?: string;
14
14
  apiKey?: string;
15
+ /**
16
+ * Habilita persistência automática de sessão no localStorage.
17
+ * Padrão: true em browsers, false em Node.js/SSR.
18
+ */
19
+ persistSession?: boolean;
15
20
  };
16
21
  export declare class PlataformaClient {
17
22
  auth: AuthModule;
@@ -24,9 +29,48 @@ export declare class PlataformaClient {
24
29
  projectId: string;
25
30
  http: AxiosInstance;
26
31
  private _token;
32
+ private _persistSession;
27
33
  constructor(config: ClientConfig);
34
+ /**
35
+ * Define o token de acesso (JWT).
36
+ * Se persistSession estiver ativo, salva automaticamente no localStorage.
37
+ */
28
38
  setToken(token: string | null): void;
39
+ /**
40
+ * Retorna o token de acesso atual.
41
+ */
29
42
  getToken(): string | null;
43
+ /**
44
+ * Salva o refresh token.
45
+ * Usado internamente pelo AuthModule após login.
46
+ */
47
+ setRefreshToken(token: string | null): void;
48
+ /**
49
+ * Retorna o refresh token salvo no localStorage.
50
+ */
51
+ getRefreshToken(): string | null;
52
+ /**
53
+ * Salva dados do usuário logado no localStorage.
54
+ */
55
+ setUser(user: User | null): void;
56
+ /**
57
+ * Retorna dados do usuário salvo no localStorage.
58
+ */
59
+ getUser(): User | null;
60
+ /**
61
+ * Limpa toda a sessão (token, refresh, user).
62
+ * Chamado automaticamente no logout.
63
+ */
64
+ clearSession(): void;
65
+ /**
66
+ * Verifica se existe uma sessão salva (token presente).
67
+ */
68
+ hasSession(): boolean;
69
+ /**
70
+ * Restaura sessão do localStorage ao inicializar o client.
71
+ * Executado automaticamente no constructor.
72
+ */
73
+ private _restoreSession;
30
74
  }
31
75
  export { AetherError } from "./errors.js";
32
76
  export type { LoginResponse, Session, User } from "./auth.js";
package/dist/index.js CHANGED
@@ -1,9 +1,26 @@
1
1
  import { createHttpClient } from "./http-client.js";
2
- import { AuthModule } from "./auth.js"; // Importando User
2
+ import { AuthModule } from "./auth.js";
3
3
  import { DatabaseModule } from "./database.js";
4
4
  import { StorageModule } from "./storage.js";
5
5
  import { FunctionsModule } from "./functions.js";
6
6
  import { PushModule } from "./push.js";
7
+ // =============================================================================
8
+ // CONSTANTES DE STORAGE
9
+ // Chaves padronizadas para localStorage - evita conflito com outros SDKs
10
+ // =============================================================================
11
+ const STORAGE_KEYS = {
12
+ TOKEN: "aether_token",
13
+ REFRESH_TOKEN: "aether_refresh_token",
14
+ USER: "aether_user",
15
+ };
16
+ /**
17
+ * Verifica se estamos em ambiente browser com localStorage disponível.
18
+ * Necessário para evitar erros em SSR (Next.js, Nuxt, etc).
19
+ */
20
+ function isBrowser() {
21
+ return (typeof window !== "undefined" &&
22
+ typeof window.localStorage !== "undefined");
23
+ }
7
24
  export class PlataformaClient {
8
25
  constructor(config) {
9
26
  this._token = null;
@@ -15,6 +32,11 @@ export class PlataformaClient {
15
32
  }
16
33
  this.apiUrl = url.replace(/\/+$/, "");
17
34
  this.projectId = project;
35
+ // Persistência habilitada por padrão apenas em browsers
36
+ this._persistSession = config.persistSession ?? isBrowser();
37
+ // Restaura sessão salva ANTES de criar o httpClient
38
+ // Isso garante que requisições iniciais já tenham o token
39
+ this._restoreSession();
18
40
  this.http = createHttpClient(this);
19
41
  // Inicializa módulos
20
42
  this.auth = new AuthModule(this, this.http);
@@ -25,12 +47,125 @@ export class PlataformaClient {
25
47
  // Cria o alias que o Showcase App espera
26
48
  this.database = this.db;
27
49
  }
50
+ // ===========================================================================
51
+ // TOKEN DE ACESSO
52
+ // ===========================================================================
53
+ /**
54
+ * Define o token de acesso (JWT).
55
+ * Se persistSession estiver ativo, salva automaticamente no localStorage.
56
+ */
28
57
  setToken(token) {
29
58
  this._token = token;
59
+ if (this._persistSession && isBrowser()) {
60
+ if (token) {
61
+ localStorage.setItem(STORAGE_KEYS.TOKEN, token);
62
+ }
63
+ else {
64
+ localStorage.removeItem(STORAGE_KEYS.TOKEN);
65
+ }
66
+ }
30
67
  }
68
+ /**
69
+ * Retorna o token de acesso atual.
70
+ */
31
71
  getToken() {
32
72
  return this._token;
33
73
  }
74
+ // ===========================================================================
75
+ // REFRESH TOKEN
76
+ // ===========================================================================
77
+ /**
78
+ * Salva o refresh token.
79
+ * Usado internamente pelo AuthModule após login.
80
+ */
81
+ setRefreshToken(token) {
82
+ if (this._persistSession && isBrowser()) {
83
+ if (token) {
84
+ localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
85
+ }
86
+ else {
87
+ localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Retorna o refresh token salvo no localStorage.
93
+ */
94
+ getRefreshToken() {
95
+ if (this._persistSession && isBrowser()) {
96
+ return localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
97
+ }
98
+ return null;
99
+ }
100
+ // ===========================================================================
101
+ // DADOS DO USUÁRIO
102
+ // ===========================================================================
103
+ /**
104
+ * Salva dados do usuário logado no localStorage.
105
+ */
106
+ setUser(user) {
107
+ if (this._persistSession && isBrowser()) {
108
+ if (user) {
109
+ localStorage.setItem(STORAGE_KEYS.USER, JSON.stringify(user));
110
+ }
111
+ else {
112
+ localStorage.removeItem(STORAGE_KEYS.USER);
113
+ }
114
+ }
115
+ }
116
+ /**
117
+ * Retorna dados do usuário salvo no localStorage.
118
+ */
119
+ getUser() {
120
+ if (this._persistSession && isBrowser()) {
121
+ const saved = localStorage.getItem(STORAGE_KEYS.USER);
122
+ if (saved) {
123
+ try {
124
+ return JSON.parse(saved);
125
+ }
126
+ catch {
127
+ // JSON corrompido - limpa
128
+ localStorage.removeItem(STORAGE_KEYS.USER);
129
+ return null;
130
+ }
131
+ }
132
+ }
133
+ return null;
134
+ }
135
+ // ===========================================================================
136
+ // GERENCIAMENTO DE SESSÃO
137
+ // ===========================================================================
138
+ /**
139
+ * Limpa toda a sessão (token, refresh, user).
140
+ * Chamado automaticamente no logout.
141
+ */
142
+ clearSession() {
143
+ this._token = null;
144
+ if (isBrowser()) {
145
+ localStorage.removeItem(STORAGE_KEYS.TOKEN);
146
+ localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
147
+ localStorage.removeItem(STORAGE_KEYS.USER);
148
+ }
149
+ }
150
+ /**
151
+ * Verifica se existe uma sessão salva (token presente).
152
+ */
153
+ hasSession() {
154
+ return this._token !== null;
155
+ }
156
+ /**
157
+ * Restaura sessão do localStorage ao inicializar o client.
158
+ * Executado automaticamente no constructor.
159
+ */
160
+ _restoreSession() {
161
+ if (!this._persistSession || !isBrowser()) {
162
+ return;
163
+ }
164
+ const savedToken = localStorage.getItem(STORAGE_KEYS.TOKEN);
165
+ if (savedToken) {
166
+ this._token = savedToken;
167
+ }
168
+ }
34
169
  }
35
170
  // ===== EXPORTS =====
36
171
  export { AetherError } from "./errors.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allanfsouza/aether-sdk",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "description": "SDK do Cliente para a Plataforma Aether",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/auth.ts CHANGED
@@ -31,18 +31,22 @@ export interface Session {
31
31
  export class AuthModule {
32
32
  private client: PlataformaClient;
33
33
  private http: AxiosInstance;
34
- private refreshToken: string | null = null;
35
- // Armazena o user localmente para acesso rápido via getSession
34
+
35
+ // Armazena o user em memória para acesso rápido
36
+ // Persistência fica no PlataformaClient (localStorage)
36
37
  private currentUser: User | null = null;
37
38
 
38
39
  constructor(client: PlataformaClient, http: AxiosInstance) {
39
40
  this.client = client;
40
41
  this.http = http;
42
+
43
+ // Restaura user do localStorage se existir
44
+ this.currentUser = this.client.getUser();
41
45
  }
42
46
 
43
- // =================================================================
44
- // MÉTODOS ORIGINAIS (MANTIDOS)
45
- // =================================================================
47
+ // ==========================================================================
48
+ // MÉTODOS PRINCIPAIS
49
+ // ==========================================================================
46
50
 
47
51
  async login(email: string, password: string): Promise<LoginResponse> {
48
52
  try {
@@ -52,15 +56,17 @@ export class AuthModule {
52
56
  });
53
57
 
54
58
  if (data.accessToken) {
59
+ // Persiste automaticamente via PlataformaClient
55
60
  this.client.setToken(data.accessToken);
56
- this.refreshToken = data.refreshToken;
61
+ this.client.setRefreshToken(data.refreshToken);
62
+ this.client.setUser(data.user);
57
63
  this.currentUser = data.user;
58
64
  }
59
65
 
60
66
  return data;
61
67
  } catch (e) {
62
- this.client.setToken(null);
63
- this.refreshToken = null;
68
+ // Limpa tudo em caso de erro
69
+ this.client.clearSession();
64
70
  this.currentUser = null;
65
71
  throw e;
66
72
  }
@@ -73,11 +79,15 @@ export class AuthModule {
73
79
  }) {
74
80
  try {
75
81
  const { data } = await this.http.post("/auth/register", credentials);
76
- // Se o register já retornar token, configura:
82
+
83
+ // Se o register retornar token (auto-login), configura sessão
77
84
  if (data.accessToken) {
78
85
  this.client.setToken(data.accessToken);
86
+ this.client.setRefreshToken(data.refreshToken);
87
+ this.client.setUser(data.user);
79
88
  this.currentUser = data.user;
80
89
  }
90
+
81
91
  return data;
82
92
  } catch (e) {
83
93
  throw e;
@@ -85,23 +95,32 @@ export class AuthModule {
85
95
  }
86
96
 
87
97
  async refresh(): Promise<{ accessToken: string }> {
88
- if (!this.refreshToken) {
98
+ // Tenta pegar do localStorage primeiro, depois da memória
99
+ const refreshToken = this.client.getRefreshToken() || this.getRefreshToken();
100
+
101
+ if (!refreshToken) {
89
102
  throw new Error("Nenhum refresh token disponível");
90
103
  }
91
104
 
92
105
  try {
93
106
  const { data } = await this.http.post("/auth/refresh", {
94
- refreshToken: this.refreshToken,
107
+ refreshToken,
95
108
  });
96
109
 
97
110
  if (data.accessToken) {
98
111
  this.client.setToken(data.accessToken);
112
+
113
+ // Se vier novo refresh token, atualiza
114
+ if (data.refreshToken) {
115
+ this.client.setRefreshToken(data.refreshToken);
116
+ }
99
117
  }
100
118
 
101
119
  return data;
102
120
  } catch (e) {
103
- this.client.setToken(null);
104
- this.refreshToken = null;
121
+ // Token expirado - limpa sessão
122
+ this.client.clearSession();
123
+ this.currentUser = null;
105
124
  throw e;
106
125
  }
107
126
  }
@@ -111,17 +130,18 @@ export class AuthModule {
111
130
  }
112
131
 
113
132
  async logout(): Promise<void> {
114
- if (this.refreshToken) {
133
+ const refreshToken = this.client.getRefreshToken();
134
+
135
+ if (refreshToken) {
115
136
  try {
116
- await this.http.post("/auth/logout", {
117
- refreshToken: this.refreshToken,
118
- });
119
- } catch (e) {
120
- // Ignora erro de logout
137
+ await this.http.post("/auth/logout", { refreshToken });
138
+ } catch {
139
+ // Ignora erro de logout no servidor
121
140
  }
122
141
  }
123
- this.client.setToken(null);
124
- this.refreshToken = null;
142
+
143
+ // Limpa tudo (memória + localStorage)
144
+ this.client.clearSession();
125
145
  this.currentUser = null;
126
146
  }
127
147
 
@@ -129,8 +149,7 @@ export class AuthModule {
129
149
  try {
130
150
  await this.http.post("/auth/logout-all");
131
151
  } finally {
132
- this.client.setToken(null);
133
- this.refreshToken = null;
152
+ this.client.clearSession();
134
153
  this.currentUser = null;
135
154
  }
136
155
  }
@@ -155,17 +174,23 @@ export class AuthModule {
155
174
  return data;
156
175
  }
157
176
 
177
+ /**
178
+ * @deprecated Use client.getRefreshToken() - mantido para compatibilidade
179
+ */
158
180
  getRefreshToken(): string | null {
159
- return this.refreshToken;
181
+ return this.client.getRefreshToken();
160
182
  }
161
183
 
184
+ /**
185
+ * @deprecated Use client.setRefreshToken() - mantido para compatibilidade
186
+ */
162
187
  setRefreshToken(token: string | null) {
163
- this.refreshToken = token;
188
+ this.client.setRefreshToken(token);
164
189
  }
165
190
 
166
- // =================================================================
167
- // NOVOS MÉTODOS (COMPATIBILIDADE COM SHOWCASE / SUPABASE STYLE)
168
- // =================================================================
191
+ // ==========================================================================
192
+ // MÉTODOS COMPATÍVEIS COM SUPABASE / SHOWCASE STYLE
193
+ // ==========================================================================
169
194
 
170
195
  /**
171
196
  * Alias para login, retornando { user, error } padrão do Showcase
@@ -182,12 +207,16 @@ export class AuthModule {
182
207
  /**
183
208
  * Alias para register, retornando { user, error }
184
209
  */
185
- async signUp(credentials: { email: string; password: string; data?: { name: string } }) {
210
+ async signUp(credentials: {
211
+ email: string;
212
+ password: string;
213
+ data?: { name: string };
214
+ }) {
186
215
  try {
187
216
  const data = await this.register({
188
217
  email: credentials.email,
189
218
  password: credentials.password,
190
- name: credentials.data?.name || credentials.email.split('@')[0],
219
+ name: credentials.data?.name || credentials.email.split("@")[0],
191
220
  });
192
221
  return { user: data.user, error: null };
193
222
  } catch (err: any) {
@@ -205,21 +234,53 @@ export class AuthModule {
205
234
 
206
235
  /**
207
236
  * Recupera a sessão atual (User + Token).
208
- * Se não tiver logado, retorna null ou tenta validar o token.
237
+ * Primeiro tenta memória, depois localStorage.
238
+ * Se não encontrar, retorna null.
209
239
  */
210
240
  async getSession() {
211
241
  const token = this.client.getToken();
212
242
  if (!token) return null;
213
243
 
214
- // Se já temos o user em memória, retorna.
215
- // O ideal seria validar o token no backend (/auth/me), mas vamos simplificar.
244
+ // Tenta memória primeiro
216
245
  if (this.currentUser) {
217
246
  return {
218
247
  user: this.currentUser,
219
- access_token: token
248
+ access_token: token,
249
+ };
250
+ }
251
+
252
+ // Tenta localStorage
253
+ const savedUser = this.client.getUser();
254
+ if (savedUser) {
255
+ this.currentUser = savedUser;
256
+ return {
257
+ user: savedUser,
258
+ access_token: token,
259
+ };
260
+ }
261
+
262
+ // Última opção: valida token no backend
263
+ try {
264
+ const { data } = await this.http.get<{ user: User }>("/auth/me");
265
+ this.currentUser = data.user;
266
+ this.client.setUser(data.user);
267
+ return {
268
+ user: data.user,
269
+ access_token: token,
220
270
  };
271
+ } catch {
272
+ // Token inválido/expirado - limpa sessão
273
+ this.client.clearSession();
274
+ this.currentUser = null;
275
+ return null;
221
276
  }
277
+ }
222
278
 
223
- return null;
279
+ /**
280
+ * Retorna o usuário atual (sem validar token).
281
+ * Útil para acesso síncrono aos dados do usuário.
282
+ */
283
+ getCurrentUser(): User | null {
284
+ return this.currentUser || this.client.getUser();
224
285
  }
225
286
  }
package/src/index.ts CHANGED
@@ -1,26 +1,50 @@
1
1
  // src/index.ts
2
2
  import type { AxiosInstance } from "axios";
3
3
  import { createHttpClient } from "./http-client.js";
4
- import { AuthModule, User } from "./auth.js"; // Importando User
4
+ import { AuthModule, User } from "./auth.js";
5
5
  import { DatabaseModule } from "./database.js";
6
6
  import { StorageModule } from "./storage.js";
7
7
  import { FunctionsModule } from "./functions.js";
8
8
  import { PushModule } from "./push.js";
9
9
 
10
+ // =============================================================================
11
+ // CONSTANTES DE STORAGE
12
+ // Chaves padronizadas para localStorage - evita conflito com outros SDKs
13
+ // =============================================================================
14
+ const STORAGE_KEYS = {
15
+ TOKEN: "aether_token",
16
+ REFRESH_TOKEN: "aether_refresh_token",
17
+ USER: "aether_user",
18
+ } as const;
19
+
10
20
  /**
11
21
  * Configuração usada para criar o cliente principal da plataforma.
12
22
  */
13
23
  export type ClientConfig = {
14
24
  // Suporte duplo para compatibilidade:
15
- // apiUrl (nome original) OU baseUrl (nome novo do App)
16
25
  apiUrl?: string;
17
26
  baseUrl?: string;
18
-
19
- // projectId (nome original) OU apiKey (nome novo do App)
20
27
  projectId?: string;
21
28
  apiKey?: string;
29
+
30
+ /**
31
+ * Habilita persistência automática de sessão no localStorage.
32
+ * Padrão: true em browsers, false em Node.js/SSR.
33
+ */
34
+ persistSession?: boolean;
22
35
  };
23
36
 
37
+ /**
38
+ * Verifica se estamos em ambiente browser com localStorage disponível.
39
+ * Necessário para evitar erros em SSR (Next.js, Nuxt, etc).
40
+ */
41
+ function isBrowser(): boolean {
42
+ return (
43
+ typeof window !== "undefined" &&
44
+ typeof window.localStorage !== "undefined"
45
+ );
46
+ }
47
+
24
48
  export class PlataformaClient {
25
49
  public auth: AuthModule;
26
50
  public db: DatabaseModule;
@@ -35,7 +59,9 @@ export class PlataformaClient {
35
59
  public projectId: string;
36
60
 
37
61
  public http: AxiosInstance;
62
+
38
63
  private _token: string | null = null;
64
+ private _persistSession: boolean;
39
65
 
40
66
  constructor(config: ClientConfig) {
41
67
  // Resolve URL (prioridade para baseUrl se existir, senão apiUrl)
@@ -49,6 +75,13 @@ export class PlataformaClient {
49
75
  this.apiUrl = url.replace(/\/+$/, "");
50
76
  this.projectId = project;
51
77
 
78
+ // Persistência habilitada por padrão apenas em browsers
79
+ this._persistSession = config.persistSession ?? isBrowser();
80
+
81
+ // Restaura sessão salva ANTES de criar o httpClient
82
+ // Isso garante que requisições iniciais já tenham o token
83
+ this._restoreSession();
84
+
52
85
  this.http = createHttpClient(this);
53
86
 
54
87
  // Inicializa módulos
@@ -62,18 +95,141 @@ export class PlataformaClient {
62
95
  this.database = this.db;
63
96
  }
64
97
 
65
- setToken(token: string | null) {
98
+ // ===========================================================================
99
+ // TOKEN DE ACESSO
100
+ // ===========================================================================
101
+
102
+ /**
103
+ * Define o token de acesso (JWT).
104
+ * Se persistSession estiver ativo, salva automaticamente no localStorage.
105
+ */
106
+ setToken(token: string | null): void {
66
107
  this._token = token;
108
+
109
+ if (this._persistSession && isBrowser()) {
110
+ if (token) {
111
+ localStorage.setItem(STORAGE_KEYS.TOKEN, token);
112
+ } else {
113
+ localStorage.removeItem(STORAGE_KEYS.TOKEN);
114
+ }
115
+ }
67
116
  }
68
117
 
118
+ /**
119
+ * Retorna o token de acesso atual.
120
+ */
69
121
  getToken(): string | null {
70
122
  return this._token;
71
123
  }
124
+
125
+ // ===========================================================================
126
+ // REFRESH TOKEN
127
+ // ===========================================================================
128
+
129
+ /**
130
+ * Salva o refresh token.
131
+ * Usado internamente pelo AuthModule após login.
132
+ */
133
+ setRefreshToken(token: string | null): void {
134
+ if (this._persistSession && isBrowser()) {
135
+ if (token) {
136
+ localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
137
+ } else {
138
+ localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Retorna o refresh token salvo no localStorage.
145
+ */
146
+ getRefreshToken(): string | null {
147
+ if (this._persistSession && isBrowser()) {
148
+ return localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
149
+ }
150
+ return null;
151
+ }
152
+
153
+ // ===========================================================================
154
+ // DADOS DO USUÁRIO
155
+ // ===========================================================================
156
+
157
+ /**
158
+ * Salva dados do usuário logado no localStorage.
159
+ */
160
+ setUser(user: User | null): void {
161
+ if (this._persistSession && isBrowser()) {
162
+ if (user) {
163
+ localStorage.setItem(STORAGE_KEYS.USER, JSON.stringify(user));
164
+ } else {
165
+ localStorage.removeItem(STORAGE_KEYS.USER);
166
+ }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Retorna dados do usuário salvo no localStorage.
172
+ */
173
+ getUser(): User | null {
174
+ if (this._persistSession && isBrowser()) {
175
+ const saved = localStorage.getItem(STORAGE_KEYS.USER);
176
+ if (saved) {
177
+ try {
178
+ return JSON.parse(saved) as User;
179
+ } catch {
180
+ // JSON corrompido - limpa
181
+ localStorage.removeItem(STORAGE_KEYS.USER);
182
+ return null;
183
+ }
184
+ }
185
+ }
186
+ return null;
187
+ }
188
+
189
+ // ===========================================================================
190
+ // GERENCIAMENTO DE SESSÃO
191
+ // ===========================================================================
192
+
193
+ /**
194
+ * Limpa toda a sessão (token, refresh, user).
195
+ * Chamado automaticamente no logout.
196
+ */
197
+ clearSession(): void {
198
+ this._token = null;
199
+
200
+ if (isBrowser()) {
201
+ localStorage.removeItem(STORAGE_KEYS.TOKEN);
202
+ localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
203
+ localStorage.removeItem(STORAGE_KEYS.USER);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Verifica se existe uma sessão salva (token presente).
209
+ */
210
+ hasSession(): boolean {
211
+ return this._token !== null;
212
+ }
213
+
214
+ /**
215
+ * Restaura sessão do localStorage ao inicializar o client.
216
+ * Executado automaticamente no constructor.
217
+ */
218
+ private _restoreSession(): void {
219
+ if (!this._persistSession || !isBrowser()) {
220
+ return;
221
+ }
222
+
223
+ const savedToken = localStorage.getItem(STORAGE_KEYS.TOKEN);
224
+ if (savedToken) {
225
+ this._token = savedToken;
226
+ }
227
+ }
72
228
  }
73
229
 
74
230
  // ===== EXPORTS =====
75
231
  export { AetherError } from "./errors.js";
76
- export type { LoginResponse, Session, User } from "./auth.js"; // User exportado!
232
+ export type { LoginResponse, Session, User } from "./auth.js";
77
233
  export type { ListOptions } from "./database.js";
78
234
  export type {
79
235
  PushPlatform,