@allanfsouza/aether-sdk 2.4.3 → 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 +13 -2
- package/dist/auth.js +82 -34
- package/dist/database.d.ts +35 -68
- package/dist/database.js +72 -78
- package/dist/index.d.ts +45 -1
- package/dist/index.js +136 -1
- package/package.json +1 -1
- package/src/auth.ts +96 -35
- package/src/database.ts +80 -81
- package/src/index.ts +162 -6
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
|
-
*
|
|
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
|
-
|
|
4
|
-
//
|
|
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
|
|
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.
|
|
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
|
-
|
|
27
|
-
this.
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
61
|
-
this.
|
|
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
|
-
|
|
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
|
|
76
|
-
// Ignora erro de logout
|
|
87
|
+
catch {
|
|
88
|
+
// Ignora erro de logout no servidor
|
|
77
89
|
}
|
|
78
90
|
}
|
|
79
|
-
|
|
80
|
-
this.
|
|
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.
|
|
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.
|
|
123
|
+
return this.client.getRefreshToken();
|
|
110
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* @deprecated Use client.setRefreshToken() - mantido para compatibilidade
|
|
127
|
+
*/
|
|
111
128
|
setRefreshToken(token) {
|
|
112
|
-
this.
|
|
129
|
+
this.client.setRefreshToken(token);
|
|
113
130
|
}
|
|
114
|
-
//
|
|
115
|
-
//
|
|
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(
|
|
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
|
-
*
|
|
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
|
-
//
|
|
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
|
-
|
|
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/database.d.ts
CHANGED
|
@@ -19,49 +19,16 @@ export declare class QueryBuilder<T> {
|
|
|
19
19
|
private limitVal?;
|
|
20
20
|
private offsetVal?;
|
|
21
21
|
constructor(collectionRef: CollectionReference<T>);
|
|
22
|
-
/**
|
|
23
|
-
* Adiciona um filtro de igualdade.
|
|
24
|
-
*/
|
|
25
22
|
eq(column: keyof T & string, value: any): this;
|
|
26
|
-
/**
|
|
27
|
-
* Adiciona um filtro de desigualdade ($ne).
|
|
28
|
-
*/
|
|
29
23
|
neq(column: keyof T & string, value: any): this;
|
|
30
|
-
/**
|
|
31
|
-
* Adiciona um filtro maior que ($gt).
|
|
32
|
-
*/
|
|
33
24
|
gt(column: keyof T & string, value: number | string): this;
|
|
34
|
-
/**
|
|
35
|
-
* Adiciona um filtro maior ou igual ($gte).
|
|
36
|
-
*/
|
|
37
25
|
gte(column: keyof T & string, value: number | string): this;
|
|
38
|
-
/**
|
|
39
|
-
* Adiciona um filtro menor que ($lt).
|
|
40
|
-
*/
|
|
41
26
|
lt(column: keyof T & string, value: number | string): this;
|
|
42
|
-
/**
|
|
43
|
-
* Adiciona um filtro menor ou igual ($lte).
|
|
44
|
-
*/
|
|
45
27
|
lte(column: keyof T & string, value: number | string): this;
|
|
46
|
-
/**
|
|
47
|
-
* Adiciona um filtro LIKE ($like).
|
|
48
|
-
*/
|
|
49
28
|
like(column: keyof T & string, value: string): this;
|
|
50
|
-
/**
|
|
51
|
-
* Define a ordenação.
|
|
52
|
-
*/
|
|
53
29
|
order(column: keyof T & string, direction?: "ASC" | "DESC"): this;
|
|
54
|
-
/**
|
|
55
|
-
* Define o limite de registros.
|
|
56
|
-
*/
|
|
57
30
|
limit(count: number): this;
|
|
58
|
-
/**
|
|
59
|
-
* Define o deslocamento (paginação).
|
|
60
|
-
*/
|
|
61
31
|
offset(count: number): this;
|
|
62
|
-
/**
|
|
63
|
-
* Executa a query e retorna os resultados.
|
|
64
|
-
*/
|
|
65
32
|
get(): Promise<T[]>;
|
|
66
33
|
}
|
|
67
34
|
/**
|
|
@@ -91,18 +58,50 @@ export declare class DatabaseModule {
|
|
|
91
58
|
/**
|
|
92
59
|
* Seleciona uma coleção de dados.
|
|
93
60
|
* [PREMIUM] Suporta Generics <T> para tipagem forte.
|
|
94
|
-
*
|
|
61
|
+
* @example client.db.collection<Product>('products')
|
|
95
62
|
*/
|
|
96
63
|
collection<T = any>(collectionName: string): CollectionReference<T>;
|
|
64
|
+
/**
|
|
65
|
+
* [NOVO] Método compatível com estilo 'Supabase/Drizzle'.
|
|
66
|
+
* É um alias para .collection() mas retorna interface compatível com o Showcase.
|
|
67
|
+
* @example client.db.from('posts').select('*')
|
|
68
|
+
*/
|
|
69
|
+
from<T = any>(tableName: string): {
|
|
70
|
+
select: (columns?: string) => Promise<{
|
|
71
|
+
data: T[];
|
|
72
|
+
error: null;
|
|
73
|
+
} | {
|
|
74
|
+
data: null;
|
|
75
|
+
error: any;
|
|
76
|
+
}>;
|
|
77
|
+
insert: (data: T) => Promise<{
|
|
78
|
+
data: Awaited<T>;
|
|
79
|
+
error: null;
|
|
80
|
+
} | {
|
|
81
|
+
data: null;
|
|
82
|
+
error: any;
|
|
83
|
+
}>;
|
|
84
|
+
update: (data: Partial<T> & {
|
|
85
|
+
id?: string;
|
|
86
|
+
}) => Promise<{
|
|
87
|
+
data: Awaited<T>;
|
|
88
|
+
error: null;
|
|
89
|
+
} | {
|
|
90
|
+
data: null;
|
|
91
|
+
error: any;
|
|
92
|
+
}>;
|
|
93
|
+
delete: () => Promise<{
|
|
94
|
+
data: null;
|
|
95
|
+
error: string;
|
|
96
|
+
}>;
|
|
97
|
+
};
|
|
97
98
|
/**
|
|
98
99
|
* Executa múltiplas operações em uma única transação.
|
|
99
|
-
* Se uma falhar, todas são revertidas.
|
|
100
100
|
*/
|
|
101
101
|
batch(operations: BatchOperation[]): Promise<any[]>;
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
104
|
* Referência a uma coleção específica.
|
|
105
|
-
* O <T> define o formato dos dados (ex: interface User).
|
|
106
105
|
*/
|
|
107
106
|
export declare class CollectionReference<T> {
|
|
108
107
|
private client;
|
|
@@ -110,45 +109,13 @@ export declare class CollectionReference<T> {
|
|
|
110
109
|
private collectionName;
|
|
111
110
|
private wsUrl;
|
|
112
111
|
constructor(client: PlataformaClient, http: AxiosInstance, name: string);
|
|
113
|
-
/**
|
|
114
|
-
* Inicia o QueryBuilder.
|
|
115
|
-
* Atalho para .eq()
|
|
116
|
-
*/
|
|
117
112
|
eq(column: keyof T & string, value: any): QueryBuilder<T>;
|
|
118
|
-
/**
|
|
119
|
-
* Inicia o QueryBuilder.
|
|
120
|
-
* Atalho para .gt()
|
|
121
|
-
*/
|
|
122
113
|
gt(column: keyof T & string, value: number | string): QueryBuilder<T>;
|
|
123
|
-
/**
|
|
124
|
-
* Retorna uma nova instância do QueryBuilder.
|
|
125
|
-
*/
|
|
126
114
|
query(): QueryBuilder<T>;
|
|
127
|
-
/**
|
|
128
|
-
* Lista documentos da coleção com filtros opcionais.
|
|
129
|
-
* @param options Filtros e Ordenação
|
|
130
|
-
*/
|
|
131
115
|
list(options?: ListOptions<T>): Promise<T[]>;
|
|
132
|
-
/**
|
|
133
|
-
* Busca um documento pelo ID.
|
|
134
|
-
*/
|
|
135
116
|
get(id: string): Promise<T>;
|
|
136
|
-
/**
|
|
137
|
-
* Cria um novo documento.
|
|
138
|
-
* O Partial<T> permite criar sem passar campos gerados (como id, createdAt).
|
|
139
|
-
*/
|
|
140
117
|
create(newData: Partial<T>): Promise<T>;
|
|
141
|
-
/**
|
|
142
|
-
* Atualiza um documento existente.
|
|
143
|
-
*/
|
|
144
118
|
update(id: string, updates: Partial<T>): Promise<T>;
|
|
145
|
-
/**
|
|
146
|
-
* Deleta um documento.
|
|
147
|
-
*/
|
|
148
119
|
delete(id: string): Promise<boolean>;
|
|
149
|
-
/**
|
|
150
|
-
* Inscreve-se para mudanças em tempo real.
|
|
151
|
-
* O callback recebe os dados já tipados como T.
|
|
152
|
-
*/
|
|
153
120
|
subscribe(callback: (action: "create" | "update" | "delete", data: T) => void): () => void;
|
|
154
121
|
}
|
package/dist/database.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// Ajuste para WebSocket funcionar no Browser (Vite) e Node
|
|
2
|
+
const WS = typeof window !== "undefined" ? window.WebSocket : global.WebSocket || null;
|
|
2
3
|
/**
|
|
3
4
|
* Builder para construção fluente de queries.
|
|
4
5
|
*/
|
|
@@ -7,79 +8,46 @@ export class QueryBuilder {
|
|
|
7
8
|
this.filter = {};
|
|
8
9
|
this.collectionRef = collectionRef;
|
|
9
10
|
}
|
|
10
|
-
/**
|
|
11
|
-
* Adiciona um filtro de igualdade.
|
|
12
|
-
*/
|
|
13
11
|
eq(column, value) {
|
|
14
12
|
this.filter[column] = value;
|
|
15
13
|
return this;
|
|
16
14
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Adiciona um filtro de desigualdade ($ne).
|
|
19
|
-
*/
|
|
20
15
|
neq(column, value) {
|
|
21
16
|
this.filter[column] = { ...this.filter[column], $ne: value };
|
|
22
17
|
return this;
|
|
23
18
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Adiciona um filtro maior que ($gt).
|
|
26
|
-
*/
|
|
27
19
|
gt(column, value) {
|
|
28
20
|
this.filter[column] = { ...this.filter[column], $gt: value };
|
|
29
21
|
return this;
|
|
30
22
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Adiciona um filtro maior ou igual ($gte).
|
|
33
|
-
*/
|
|
34
23
|
gte(column, value) {
|
|
35
24
|
this.filter[column] = { ...this.filter[column], $gte: value };
|
|
36
25
|
return this;
|
|
37
26
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Adiciona um filtro menor que ($lt).
|
|
40
|
-
*/
|
|
41
27
|
lt(column, value) {
|
|
42
28
|
this.filter[column] = { ...this.filter[column], $lt: value };
|
|
43
29
|
return this;
|
|
44
30
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Adiciona um filtro menor ou igual ($lte).
|
|
47
|
-
*/
|
|
48
31
|
lte(column, value) {
|
|
49
32
|
this.filter[column] = { ...this.filter[column], $lte: value };
|
|
50
33
|
return this;
|
|
51
34
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Adiciona um filtro LIKE ($like).
|
|
54
|
-
*/
|
|
55
35
|
like(column, value) {
|
|
56
36
|
this.filter[column] = { ...this.filter[column], $like: value };
|
|
57
37
|
return this;
|
|
58
38
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Define a ordenação.
|
|
61
|
-
*/
|
|
62
39
|
order(column, direction = "ASC") {
|
|
63
40
|
this.sort = { field: column, order: direction };
|
|
64
41
|
return this;
|
|
65
42
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Define o limite de registros.
|
|
68
|
-
*/
|
|
69
43
|
limit(count) {
|
|
70
44
|
this.limitVal = count;
|
|
71
45
|
return this;
|
|
72
46
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Define o deslocamento (paginação).
|
|
75
|
-
*/
|
|
76
47
|
offset(count) {
|
|
77
48
|
this.offsetVal = count;
|
|
78
49
|
return this;
|
|
79
50
|
}
|
|
80
|
-
/**
|
|
81
|
-
* Executa a query e retorna os resultados.
|
|
82
|
-
*/
|
|
83
51
|
async get() {
|
|
84
52
|
return this.collectionRef.list({
|
|
85
53
|
filter: this.filter,
|
|
@@ -100,14 +68,63 @@ export class DatabaseModule {
|
|
|
100
68
|
/**
|
|
101
69
|
* Seleciona uma coleção de dados.
|
|
102
70
|
* [PREMIUM] Suporta Generics <T> para tipagem forte.
|
|
103
|
-
*
|
|
71
|
+
* @example client.db.collection<Product>('products')
|
|
104
72
|
*/
|
|
105
73
|
collection(collectionName) {
|
|
106
74
|
return new CollectionReference(this.client, this.http, collectionName);
|
|
107
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* [NOVO] Método compatível com estilo 'Supabase/Drizzle'.
|
|
78
|
+
* É um alias para .collection() mas retorna interface compatível com o Showcase.
|
|
79
|
+
* @example client.db.from('posts').select('*')
|
|
80
|
+
*/
|
|
81
|
+
from(tableName) {
|
|
82
|
+
const ref = this.collection(tableName);
|
|
83
|
+
return {
|
|
84
|
+
// Mapeia .select() para .list()
|
|
85
|
+
select: async (columns = "*") => {
|
|
86
|
+
try {
|
|
87
|
+
// Nota: O parametro 'columns' poderia ser enviado ao backend se suportado
|
|
88
|
+
const data = await ref.list();
|
|
89
|
+
return { data, error: null };
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
return { data: null, error: err.response?.data || err.message };
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
// Mapeia .insert() para .create()
|
|
96
|
+
insert: async (data) => {
|
|
97
|
+
try {
|
|
98
|
+
const res = await ref.create(data);
|
|
99
|
+
return { data: res, error: null };
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return { data: null, error: err.response?.data || err.message };
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
// Mapeia .update() para .update() (Requer ID no payload ou logica extra)
|
|
106
|
+
update: async (data) => {
|
|
107
|
+
try {
|
|
108
|
+
if (!data.id)
|
|
109
|
+
throw new Error("ID é obrigatório para update via .from()");
|
|
110
|
+
const { id, ...updates } = data;
|
|
111
|
+
const res = await ref.update(id, updates);
|
|
112
|
+
return { data: res, error: null };
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return { data: null, error: err.response?.data || err.message };
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
// Mapeia .delete()
|
|
119
|
+
delete: async () => {
|
|
120
|
+
// O showcase não passou argumentos no delete, o que é perigoso.
|
|
121
|
+
// Aqui retornamos erro ou implementamos delete por query se suportado.
|
|
122
|
+
return { data: null, error: "Delete via .from() requer implementação de filtros" };
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
108
126
|
/**
|
|
109
127
|
* Executa múltiplas operações em uma única transação.
|
|
110
|
-
* Se uma falhar, todas são revertidas.
|
|
111
128
|
*/
|
|
112
129
|
async batch(operations) {
|
|
113
130
|
const { data } = await this.http.post("/db/batch", { operations });
|
|
@@ -116,7 +133,6 @@ export class DatabaseModule {
|
|
|
116
133
|
}
|
|
117
134
|
/**
|
|
118
135
|
* Referência a uma coleção específica.
|
|
119
|
-
* O <T> define o formato dos dados (ex: interface User).
|
|
120
136
|
*/
|
|
121
137
|
export class CollectionReference {
|
|
122
138
|
constructor(client, http, name) {
|
|
@@ -127,93 +143,69 @@ export class CollectionReference {
|
|
|
127
143
|
const protocol = client.apiUrl.startsWith("https") ? "wss" : "ws";
|
|
128
144
|
this.wsUrl = client.apiUrl.replace(/^https?/, protocol);
|
|
129
145
|
}
|
|
130
|
-
|
|
131
|
-
* Inicia o QueryBuilder.
|
|
132
|
-
* Atalho para .eq()
|
|
133
|
-
*/
|
|
146
|
+
// --- Atalhos de Query ---
|
|
134
147
|
eq(column, value) {
|
|
135
148
|
return new QueryBuilder(this).eq(column, value);
|
|
136
149
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Inicia o QueryBuilder.
|
|
139
|
-
* Atalho para .gt()
|
|
140
|
-
*/
|
|
141
150
|
gt(column, value) {
|
|
142
151
|
return new QueryBuilder(this).gt(column, value);
|
|
143
152
|
}
|
|
144
|
-
// ... Outros atalhos podem ser adicionados conforme necessidade ...
|
|
145
|
-
/**
|
|
146
|
-
* Retorna uma nova instância do QueryBuilder.
|
|
147
|
-
*/
|
|
148
153
|
query() {
|
|
149
154
|
return new QueryBuilder(this);
|
|
150
155
|
}
|
|
151
|
-
|
|
152
|
-
* Lista documentos da coleção com filtros opcionais.
|
|
153
|
-
* @param options Filtros e Ordenação
|
|
154
|
-
*/
|
|
156
|
+
// --- Operações CRUD ---
|
|
155
157
|
async list(options) {
|
|
156
158
|
const params = {};
|
|
157
|
-
// Converte os objetos do SDK para strings que o Backend entende
|
|
158
159
|
if (options?.filter) {
|
|
159
160
|
params.filter = JSON.stringify(options.filter);
|
|
160
161
|
}
|
|
161
162
|
if (options?.sort) {
|
|
162
|
-
// Backend espera formato array: ["campo", "DESC"]
|
|
163
163
|
params.sort = JSON.stringify([options.sort.field, options.sort.order]);
|
|
164
164
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
if (options?.limit)
|
|
166
|
+
params.limit = options.limit;
|
|
167
|
+
if (options?.offset)
|
|
168
|
+
params.offset = options.offset;
|
|
168
169
|
const { data } = await this.http.get(`/db/${this.collectionName}`, {
|
|
169
170
|
params,
|
|
170
171
|
});
|
|
171
172
|
return data.data;
|
|
172
173
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Busca um documento pelo ID.
|
|
175
|
-
*/
|
|
176
174
|
async get(id) {
|
|
177
175
|
const { data } = await this.http.get(`/db/${this.collectionName}/${id}`);
|
|
178
176
|
return data.data;
|
|
179
177
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Cria um novo documento.
|
|
182
|
-
* O Partial<T> permite criar sem passar campos gerados (como id, createdAt).
|
|
183
|
-
*/
|
|
184
178
|
async create(newData) {
|
|
185
179
|
const { data } = await this.http.post(`/db/${this.collectionName}`, newData);
|
|
186
180
|
return data.data;
|
|
187
181
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Atualiza um documento existente.
|
|
190
|
-
*/
|
|
191
182
|
async update(id, updates) {
|
|
192
183
|
const { data } = await this.http.put(`/db/${this.collectionName}/${id}`, updates);
|
|
193
184
|
return data.data;
|
|
194
185
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Deleta um documento.
|
|
197
|
-
*/
|
|
198
186
|
async delete(id) {
|
|
199
187
|
await this.http.delete(`/db/${this.collectionName}/${id}`);
|
|
200
188
|
return true;
|
|
201
189
|
}
|
|
202
|
-
|
|
203
|
-
* Inscreve-se para mudanças em tempo real.
|
|
204
|
-
* O callback recebe os dados já tipados como T.
|
|
205
|
-
*/
|
|
190
|
+
// --- Realtime ---
|
|
206
191
|
subscribe(callback) {
|
|
192
|
+
if (!WS) {
|
|
193
|
+
console.warn("[SDK] WebSocket não disponível neste ambiente.");
|
|
194
|
+
return () => { };
|
|
195
|
+
}
|
|
207
196
|
const token = this.client.getToken();
|
|
208
197
|
const projectId = this.client.projectId;
|
|
209
198
|
if (!token || !projectId) {
|
|
210
199
|
console.warn("[SDK] Realtime falhou: Token ou ProjectId ausentes.");
|
|
211
200
|
return () => { };
|
|
212
201
|
}
|
|
202
|
+
// URL correta de subscribe
|
|
213
203
|
const url = `${this.wsUrl}/v1/db/subscribe/${this.collectionName}?token=${token}&projectId=${projectId}`;
|
|
214
204
|
let ws = null;
|
|
215
205
|
try {
|
|
216
|
-
ws = new
|
|
206
|
+
ws = new WS(url);
|
|
207
|
+
if (!ws)
|
|
208
|
+
return () => { };
|
|
217
209
|
ws.onopen = () => {
|
|
218
210
|
// Conectado
|
|
219
211
|
};
|
|
@@ -229,10 +221,12 @@ export class CollectionReference {
|
|
|
229
221
|
// Erro silencioso de parse
|
|
230
222
|
}
|
|
231
223
|
};
|
|
232
|
-
//
|
|
224
|
+
// Heartbeat
|
|
233
225
|
const pingInterval = setInterval(() => {
|
|
234
|
-
|
|
226
|
+
// [CORREÇÃO] Adicionada verificação explicita 'ws &&' para evitar erro 'possibly null'
|
|
227
|
+
if (ws && ws.readyState === 1) { // 1 = OPEN
|
|
235
228
|
ws.send("ping");
|
|
229
|
+
}
|
|
236
230
|
}, 30000);
|
|
237
231
|
return () => {
|
|
238
232
|
clearInterval(pingInterval);
|