@allanfsouza/aether-sdk 1.0.0 → 2.0.0
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 +16 -3
- package/dist/auth.js +31 -6
- package/dist/database.d.ts +30 -27
- package/dist/database.js +75 -55
- package/dist/functions.d.ts +14 -0
- package/dist/functions.js +25 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +8 -4
- package/dist/storage.d.ts +19 -11
- package/dist/storage.js +50 -25
- package/package.json +1 -1
- package/src/auth.ts +33 -6
- package/src/database.ts +100 -70
- package/src/functions.ts +41 -0
- package/src/index.ts +9 -4
- package/src/storage.ts +53 -25
package/dist/auth.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AxiosInstance } from "axios";
|
|
|
2
2
|
import type { PlataformaClient } from "./index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Módulo de Autenticação
|
|
5
|
-
* Lida com login, registro e
|
|
5
|
+
* Lida com login, registro, gerenciamento de token e recuperação de senha.
|
|
6
6
|
*/
|
|
7
7
|
export declare class AuthModule {
|
|
8
8
|
private client;
|
|
@@ -16,7 +16,7 @@ export declare class AuthModule {
|
|
|
16
16
|
*/
|
|
17
17
|
login(email: string, password: string): Promise<any>;
|
|
18
18
|
/**
|
|
19
|
-
* Registra um novo usuário e já o
|
|
19
|
+
* Registra um novo usuário e já realiza o login automaticamente.
|
|
20
20
|
* @param credentials Nome, email e senha
|
|
21
21
|
* @returns O objeto do usuário e o token
|
|
22
22
|
*/
|
|
@@ -26,7 +26,20 @@ export declare class AuthModule {
|
|
|
26
26
|
password: string;
|
|
27
27
|
}): Promise<any>;
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* Solicita um e-mail de recuperação de senha.
|
|
30
|
+
* @param email O e-mail da conta
|
|
31
|
+
* @returns A resposta da API (mensagem de sucesso)
|
|
32
|
+
*/
|
|
33
|
+
forgotPassword(email: string): Promise<any>;
|
|
34
|
+
/**
|
|
35
|
+
* Redefine a senha usando o token recebido por e-mail.
|
|
36
|
+
* @param token O código/token recebido
|
|
37
|
+
* @param newPassword A nova senha desejada
|
|
38
|
+
* @returns A resposta da API (mensagem de sucesso)
|
|
39
|
+
*/
|
|
40
|
+
resetPassword(token: string, newPassword: string): Promise<any>;
|
|
41
|
+
/**
|
|
42
|
+
* Desconecta o usuário limpando o token da memória do SDK.
|
|
30
43
|
*/
|
|
31
44
|
logout(): void;
|
|
32
45
|
}
|
package/dist/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Módulo de Autenticação
|
|
3
|
-
* Lida com login, registro e
|
|
3
|
+
* Lida com login, registro, gerenciamento de token e recuperação de senha.
|
|
4
4
|
*/
|
|
5
5
|
export class AuthModule {
|
|
6
6
|
constructor(client, http) {
|
|
@@ -16,9 +16,9 @@ export class AuthModule {
|
|
|
16
16
|
async login(email, password) {
|
|
17
17
|
try {
|
|
18
18
|
const { data } = await this.http.post("/auth/login", { email, password });
|
|
19
|
-
// Salva o token DENTRO da instância do SDK
|
|
19
|
+
// Salva o token DENTRO da instância do SDK para uso futuro
|
|
20
20
|
this.client.setToken(data.token);
|
|
21
|
-
return data; // Retorna {
|
|
21
|
+
return data; // Retorna { token, user: { ... } }
|
|
22
22
|
}
|
|
23
23
|
catch (e) {
|
|
24
24
|
this.client.setToken(null); // Limpa o token em caso de falha
|
|
@@ -26,14 +26,17 @@ export class AuthModule {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Registra um novo usuário e já o
|
|
29
|
+
* Registra um novo usuário e já realiza o login automaticamente.
|
|
30
30
|
* @param credentials Nome, email e senha
|
|
31
31
|
* @returns O objeto do usuário e o token
|
|
32
32
|
*/
|
|
33
33
|
async register(credentials) {
|
|
34
34
|
try {
|
|
35
35
|
const { data } = await this.http.post("/auth/register", credentials);
|
|
36
|
-
|
|
36
|
+
// Se o backend retornar o token no registro, já salvamos
|
|
37
|
+
if (data.token) {
|
|
38
|
+
this.client.setToken(data.token);
|
|
39
|
+
}
|
|
37
40
|
return data;
|
|
38
41
|
}
|
|
39
42
|
catch (e) {
|
|
@@ -42,7 +45,29 @@ export class AuthModule {
|
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
/**
|
|
45
|
-
*
|
|
48
|
+
* Solicita um e-mail de recuperação de senha.
|
|
49
|
+
* @param email O e-mail da conta
|
|
50
|
+
* @returns A resposta da API (mensagem de sucesso)
|
|
51
|
+
*/
|
|
52
|
+
async forgotPassword(email) {
|
|
53
|
+
const { data } = await this.http.post("/auth/forgot-password", { email });
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Redefine a senha usando o token recebido por e-mail.
|
|
58
|
+
* @param token O código/token recebido
|
|
59
|
+
* @param newPassword A nova senha desejada
|
|
60
|
+
* @returns A resposta da API (mensagem de sucesso)
|
|
61
|
+
*/
|
|
62
|
+
async resetPassword(token, newPassword) {
|
|
63
|
+
const { data } = await this.http.post("/auth/reset-password", {
|
|
64
|
+
token,
|
|
65
|
+
newPassword,
|
|
66
|
+
});
|
|
67
|
+
return data;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Desconecta o usuário limpando o token da memória do SDK.
|
|
46
71
|
*/
|
|
47
72
|
logout() {
|
|
48
73
|
this.client.setToken(null);
|
package/dist/database.d.ts
CHANGED
|
@@ -1,59 +1,62 @@
|
|
|
1
1
|
import type { AxiosInstance } from "axios";
|
|
2
2
|
import type { PlataformaClient } from "./index.js";
|
|
3
|
+
export type ListOptions<T> = {
|
|
4
|
+
filter?: Partial<T>;
|
|
5
|
+
sort?: {
|
|
6
|
+
field: keyof T & string;
|
|
7
|
+
order: "ASC" | "DESC";
|
|
8
|
+
};
|
|
9
|
+
};
|
|
3
10
|
/**
|
|
4
|
-
* Módulo de Banco de Dados
|
|
5
|
-
* Ponto de entrada para acessar as coleções.
|
|
11
|
+
* Módulo de Banco de Dados
|
|
6
12
|
*/
|
|
7
13
|
export declare class DatabaseModule {
|
|
8
14
|
private client;
|
|
9
15
|
private http;
|
|
10
16
|
constructor(client: PlataformaClient, http: AxiosInstance);
|
|
11
17
|
/**
|
|
12
|
-
* Seleciona uma coleção de dados
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
18
|
+
* Seleciona uma coleção de dados.
|
|
19
|
+
* [PREMIUM] Suporta Generics <T> para tipagem forte.
|
|
20
|
+
* * @example client.db.collection<Product>('products')
|
|
15
21
|
*/
|
|
16
|
-
collection(collectionName: string): CollectionReference
|
|
22
|
+
collection<T = any>(collectionName: string): CollectionReference<T>;
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
25
|
+
* Referência a uma coleção específica.
|
|
26
|
+
* O <T> define o formato dos dados (ex: interface User).
|
|
21
27
|
*/
|
|
22
|
-
declare class CollectionReference {
|
|
28
|
+
declare class CollectionReference<T> {
|
|
23
29
|
private client;
|
|
24
30
|
private http;
|
|
25
31
|
private collectionName;
|
|
26
32
|
private wsUrl;
|
|
27
33
|
constructor(client: PlataformaClient, http: AxiosInstance, name: string);
|
|
28
34
|
/**
|
|
29
|
-
* Lista
|
|
30
|
-
*
|
|
35
|
+
* Lista documentos da coleção com filtros opcionais.
|
|
36
|
+
* @param options Filtros e Ordenação
|
|
31
37
|
*/
|
|
32
|
-
list(): Promise<
|
|
38
|
+
list(options?: ListOptions<T>): Promise<T[]>;
|
|
33
39
|
/**
|
|
34
|
-
*
|
|
35
|
-
* (POST /v1/db/tasks)
|
|
36
|
-
* @param newData O objeto de dados a ser criado
|
|
40
|
+
* Busca um documento pelo ID.
|
|
37
41
|
*/
|
|
38
|
-
|
|
42
|
+
get(id: string): Promise<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Cria um novo documento.
|
|
45
|
+
* O Partial<T> permite criar sem passar campos gerados (como id, createdAt).
|
|
46
|
+
*/
|
|
47
|
+
create(newData: Partial<T>): Promise<T>;
|
|
39
48
|
/**
|
|
40
49
|
* Atualiza um documento existente.
|
|
41
|
-
* (PUT /v1/db/tasks/:id)
|
|
42
|
-
* @param id O ID do documento
|
|
43
|
-
* @param updates Os campos a serem atualizados
|
|
44
50
|
*/
|
|
45
|
-
update(id: string, updates:
|
|
51
|
+
update(id: string, updates: Partial<T>): Promise<T>;
|
|
46
52
|
/**
|
|
47
53
|
* Deleta um documento.
|
|
48
|
-
* (DELETE /v1/db/tasks/:id)
|
|
49
|
-
* @param id O ID do documento
|
|
50
54
|
*/
|
|
51
|
-
delete(id: string): Promise<
|
|
55
|
+
delete(id: string): Promise<boolean>;
|
|
52
56
|
/**
|
|
53
|
-
* Inscreve-se para mudanças em tempo real
|
|
54
|
-
*
|
|
55
|
-
* @returns Uma função 'unsubscribe' para fechar a conexão
|
|
57
|
+
* Inscreve-se para mudanças em tempo real.
|
|
58
|
+
* O callback recebe os dados já tipados como T.
|
|
56
59
|
*/
|
|
57
|
-
subscribe(callback: (action: "create" | "update" | "delete", data:
|
|
60
|
+
subscribe(callback: (action: "create" | "update" | "delete", data: T) => void): () => void;
|
|
58
61
|
}
|
|
59
62
|
export {};
|
package/dist/database.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import WebSocket from "ws";
|
|
2
2
|
/**
|
|
3
|
-
* Módulo de Banco de Dados
|
|
4
|
-
* Ponto de entrada para acessar as coleções.
|
|
3
|
+
* Módulo de Banco de Dados
|
|
5
4
|
*/
|
|
6
5
|
export class DatabaseModule {
|
|
7
6
|
constructor(client, http) {
|
|
@@ -9,98 +8,119 @@ export class DatabaseModule {
|
|
|
9
8
|
this.http = http;
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
|
-
* Seleciona uma coleção de dados
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
11
|
+
* Seleciona uma coleção de dados.
|
|
12
|
+
* [PREMIUM] Suporta Generics <T> para tipagem forte.
|
|
13
|
+
* * @example client.db.collection<Product>('products')
|
|
15
14
|
*/
|
|
16
15
|
collection(collectionName) {
|
|
17
16
|
return new CollectionReference(this.client, this.http, collectionName);
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Referência a uma coleção específica.
|
|
21
|
+
* O <T> define o formato dos dados (ex: interface User).
|
|
23
22
|
*/
|
|
24
23
|
class CollectionReference {
|
|
25
24
|
constructor(client, http, name) {
|
|
26
25
|
this.client = client;
|
|
27
26
|
this.http = http;
|
|
28
27
|
this.collectionName = name;
|
|
29
|
-
//
|
|
30
|
-
|
|
28
|
+
// Ajusta protocolo para WS/WSS
|
|
29
|
+
const protocol = client.apiUrl.startsWith("https") ? "wss" : "ws";
|
|
30
|
+
this.wsUrl = client.apiUrl.replace(/^https?/, protocol);
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Lista
|
|
34
|
-
*
|
|
33
|
+
* Lista documentos da coleção com filtros opcionais.
|
|
34
|
+
* @param options Filtros e Ordenação
|
|
35
35
|
*/
|
|
36
|
-
async list() {
|
|
37
|
-
const
|
|
38
|
-
|
|
36
|
+
async list(options) {
|
|
37
|
+
const params = {};
|
|
38
|
+
// Converte os objetos do SDK para strings que o Backend entende
|
|
39
|
+
if (options?.filter) {
|
|
40
|
+
params.filter = JSON.stringify(options.filter);
|
|
41
|
+
}
|
|
42
|
+
if (options?.sort) {
|
|
43
|
+
// Backend espera formato array: ["campo", "DESC"]
|
|
44
|
+
params.sort = JSON.stringify([options.sort.field, options.sort.order]);
|
|
45
|
+
}
|
|
46
|
+
const { data } = await this.http.get(`/db/${this.collectionName}`, {
|
|
47
|
+
params,
|
|
48
|
+
});
|
|
49
|
+
return data.data;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Busca um documento pelo ID.
|
|
53
|
+
*/
|
|
54
|
+
async get(id) {
|
|
55
|
+
const { data } = await this.http.get(`/db/${this.collectionName}/${id}`);
|
|
56
|
+
return data.data;
|
|
39
57
|
}
|
|
40
58
|
/**
|
|
41
|
-
* Cria um novo documento
|
|
42
|
-
* (
|
|
43
|
-
* @param newData O objeto de dados a ser criado
|
|
59
|
+
* Cria um novo documento.
|
|
60
|
+
* O Partial<T> permite criar sem passar campos gerados (como id, createdAt).
|
|
44
61
|
*/
|
|
45
62
|
async create(newData) {
|
|
46
63
|
const { data } = await this.http.post(`/db/${this.collectionName}`, newData);
|
|
47
|
-
return data.data;
|
|
64
|
+
return data.data;
|
|
48
65
|
}
|
|
49
66
|
/**
|
|
50
67
|
* Atualiza um documento existente.
|
|
51
|
-
* (PUT /v1/db/tasks/:id)
|
|
52
|
-
* @param id O ID do documento
|
|
53
|
-
* @param updates Os campos a serem atualizados
|
|
54
68
|
*/
|
|
55
69
|
async update(id, updates) {
|
|
56
70
|
const { data } = await this.http.put(`/db/${this.collectionName}/${id}`, updates);
|
|
57
|
-
return data.data;
|
|
71
|
+
return data.data;
|
|
58
72
|
}
|
|
59
73
|
/**
|
|
60
74
|
* Deleta um documento.
|
|
61
|
-
* (DELETE /v1/db/tasks/:id)
|
|
62
|
-
* @param id O ID do documento
|
|
63
75
|
*/
|
|
64
76
|
async delete(id) {
|
|
65
|
-
|
|
66
|
-
return
|
|
77
|
+
await this.http.delete(`/db/${this.collectionName}/${id}`);
|
|
78
|
+
return true;
|
|
67
79
|
}
|
|
68
80
|
/**
|
|
69
|
-
* Inscreve-se para mudanças em tempo real
|
|
70
|
-
*
|
|
71
|
-
* @returns Uma função 'unsubscribe' para fechar a conexão
|
|
81
|
+
* Inscreve-se para mudanças em tempo real.
|
|
82
|
+
* O callback recebe os dados já tipados como T.
|
|
72
83
|
*/
|
|
73
84
|
subscribe(callback) {
|
|
74
85
|
const token = this.client.getToken();
|
|
75
86
|
const projectId = this.client.projectId;
|
|
76
87
|
if (!token || !projectId) {
|
|
77
|
-
|
|
88
|
+
console.warn("[SDK] Realtime falhou: Token ou ProjectId ausentes.");
|
|
89
|
+
return () => { };
|
|
78
90
|
}
|
|
79
|
-
// Constrói a URL: ws://localhost:3000/v1/db/subscribe/tasks?token=...&projectId=...
|
|
80
91
|
const url = `${this.wsUrl}/v1/db/subscribe/${this.collectionName}?token=${token}&projectId=${projectId}`;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
let ws = null;
|
|
93
|
+
try {
|
|
94
|
+
ws = new WebSocket(url);
|
|
95
|
+
ws.onopen = () => {
|
|
96
|
+
// Conectado
|
|
97
|
+
};
|
|
98
|
+
ws.onmessage = (event) => {
|
|
99
|
+
try {
|
|
100
|
+
const raw = event.data?.toString() || event.toString();
|
|
101
|
+
if (raw === "pong")
|
|
102
|
+
return;
|
|
103
|
+
const payload = JSON.parse(raw);
|
|
104
|
+
callback(payload.action, payload.data);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
// Erro silencioso de parse
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
// Mantém a conexão viva (Heartbeat)
|
|
111
|
+
const pingInterval = setInterval(() => {
|
|
112
|
+
if (ws?.readyState === WebSocket.OPEN)
|
|
113
|
+
ws.send("ping");
|
|
114
|
+
}, 30000);
|
|
115
|
+
return () => {
|
|
116
|
+
clearInterval(pingInterval);
|
|
117
|
+
if (ws)
|
|
118
|
+
ws.close();
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error("[SDK] Erro WS:", err);
|
|
123
|
+
return () => { };
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
126
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { PlataformaClient } from "./index.js";
|
|
3
|
+
export declare class FunctionsModule {
|
|
4
|
+
private client;
|
|
5
|
+
private http;
|
|
6
|
+
constructor(client: PlataformaClient, http: AxiosInstance);
|
|
7
|
+
/**
|
|
8
|
+
* Chama uma função HTTP Serverless.
|
|
9
|
+
* @param functionName O nome da função (ou rota, ex: 'pedidos/123')
|
|
10
|
+
* @param body (Opcional) Dados para enviar no corpo (POST)
|
|
11
|
+
* @param method (Opcional) Método HTTP (padrão POST se tiver body, GET se não)
|
|
12
|
+
*/
|
|
13
|
+
invoke<T = any>(functionName: string, body?: any, method?: "GET" | "POST" | "PUT" | "DELETE"): Promise<T>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class FunctionsModule {
|
|
2
|
+
constructor(client, http) {
|
|
3
|
+
this.client = client;
|
|
4
|
+
this.http = http;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Chama uma função HTTP Serverless.
|
|
8
|
+
* @param functionName O nome da função (ou rota, ex: 'pedidos/123')
|
|
9
|
+
* @param body (Opcional) Dados para enviar no corpo (POST)
|
|
10
|
+
* @param method (Opcional) Método HTTP (padrão POST se tiver body, GET se não)
|
|
11
|
+
*/
|
|
12
|
+
async invoke(functionName, body, method) {
|
|
13
|
+
const projectId = this.client.projectId;
|
|
14
|
+
// Remove barras iniciais para evitar URL malformada
|
|
15
|
+
const cleanName = functionName.replace(/^\//, "");
|
|
16
|
+
// Define método automaticamente se não informado
|
|
17
|
+
const finalMethod = method || (body ? "POST" : "GET");
|
|
18
|
+
const response = await this.http.request({
|
|
19
|
+
url: `/functions/http/${projectId}/${cleanName}`,
|
|
20
|
+
method: finalMethod,
|
|
21
|
+
data: body,
|
|
22
|
+
});
|
|
23
|
+
return response.data;
|
|
24
|
+
}
|
|
25
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { AuthModule } from "./auth.js";
|
|
2
2
|
import { DatabaseModule } from "./database.js";
|
|
3
3
|
import { StorageModule } from "./storage.js";
|
|
4
|
+
import { FunctionsModule } from "./functions.js";
|
|
4
5
|
type ClientConfig = {
|
|
5
6
|
apiUrl: string;
|
|
6
7
|
projectId: string;
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
10
|
* O cliente principal da Plataforma API.
|
|
10
|
-
* Ponto de entrada para todos os módulos (Auth, DB, Storage).
|
|
11
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage, Functions).
|
|
11
12
|
*/
|
|
12
13
|
export declare class PlataformaClient {
|
|
13
14
|
auth: AuthModule;
|
|
14
15
|
db: DatabaseModule;
|
|
15
16
|
storage: StorageModule;
|
|
17
|
+
functions: FunctionsModule;
|
|
16
18
|
apiUrl: string;
|
|
17
19
|
projectId: string;
|
|
18
20
|
private http;
|
|
@@ -20,11 +22,13 @@ export declare class PlataformaClient {
|
|
|
20
22
|
constructor(config: ClientConfig);
|
|
21
23
|
/**
|
|
22
24
|
* Armazena o token de autenticação em memória.
|
|
25
|
+
* Chamado automaticamente pelo AuthModule após login.
|
|
23
26
|
* @param token O JWT (ou null para logout)
|
|
24
27
|
*/
|
|
25
28
|
setToken(token: string | null): void;
|
|
26
29
|
/**
|
|
27
30
|
* Recupera o token de autenticação atual.
|
|
31
|
+
* Usado pelo http-client para injetar o header Authorization.
|
|
28
32
|
* @returns O JWT ou null
|
|
29
33
|
*/
|
|
30
34
|
getToken(): string | null;
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import { createHttpClient } from "./http-client.js";
|
|
|
2
2
|
import { AuthModule } from "./auth.js";
|
|
3
3
|
import { DatabaseModule } from "./database.js";
|
|
4
4
|
import { StorageModule } from "./storage.js";
|
|
5
|
+
import { FunctionsModule } from "./functions.js"; // [NOVO] Import do módulo
|
|
5
6
|
/**
|
|
6
7
|
* O cliente principal da Plataforma API.
|
|
7
|
-
* Ponto de entrada para todos os módulos (Auth, DB, Storage).
|
|
8
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage, Functions).
|
|
8
9
|
*/
|
|
9
10
|
export class PlataformaClient {
|
|
10
11
|
constructor(config) {
|
|
@@ -12,18 +13,20 @@ export class PlataformaClient {
|
|
|
12
13
|
if (!config.apiUrl || !config.projectId) {
|
|
13
14
|
throw new Error("apiUrl e projectId são obrigatórios.");
|
|
14
15
|
}
|
|
15
|
-
this.apiUrl = config.apiUrl.replace(/\/$/, ""); // Remove barra final
|
|
16
|
+
this.apiUrl = config.apiUrl.replace(/\/$/, ""); // Remove barra final se houver
|
|
16
17
|
this.projectId = config.projectId;
|
|
17
|
-
// Inicializa o cliente HTTP (passando 'this', a própria instância)
|
|
18
|
+
// Inicializa o cliente HTTP (passando 'this', a própria instância para injetar token/ID)
|
|
18
19
|
this.http = createHttpClient(this);
|
|
19
|
-
// Inicializa os módulos
|
|
20
|
+
// Inicializa os módulos passando a referência do cliente e do axios
|
|
20
21
|
this.auth = new AuthModule(this, this.http);
|
|
21
22
|
this.db = new DatabaseModule(this, this.http);
|
|
22
23
|
this.storage = new StorageModule(this, this.http);
|
|
24
|
+
this.functions = new FunctionsModule(this, this.http); // [NOVO] Inicialização
|
|
23
25
|
}
|
|
24
26
|
// --- Gerenciamento de Token ---
|
|
25
27
|
/**
|
|
26
28
|
* Armazena o token de autenticação em memória.
|
|
29
|
+
* Chamado automaticamente pelo AuthModule após login.
|
|
27
30
|
* @param token O JWT (ou null para logout)
|
|
28
31
|
*/
|
|
29
32
|
setToken(token) {
|
|
@@ -31,6 +34,7 @@ export class PlataformaClient {
|
|
|
31
34
|
}
|
|
32
35
|
/**
|
|
33
36
|
* Recupera o token de autenticação atual.
|
|
37
|
+
* Usado pelo http-client para injetar o header Authorization.
|
|
34
38
|
* @returns O JWT ou null
|
|
35
39
|
*/
|
|
36
40
|
getToken() {
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import type { AxiosInstance } from "axios";
|
|
2
2
|
import type { PlataformaClient } from "./index.js";
|
|
3
|
-
/**
|
|
4
|
-
* Módulo de Storage
|
|
5
|
-
* Lida com upload e download de arquivos.
|
|
6
|
-
*/
|
|
7
3
|
export declare class StorageModule {
|
|
8
4
|
private client;
|
|
9
5
|
private http;
|
|
10
6
|
constructor(client: PlataformaClient, http: AxiosInstance);
|
|
11
7
|
/**
|
|
12
|
-
* Faz o upload de um arquivo
|
|
13
|
-
*
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @returns O objeto do arquivo criado no banco
|
|
8
|
+
* Faz o upload de um arquivo.
|
|
9
|
+
* @param file Arquivo (Browser: File, Node: Buffer)
|
|
10
|
+
* @param fileName Nome do arquivo (ex: 'foto.jpg')
|
|
11
|
+
* @param contentType MIME Type (ex: 'image/jpeg')
|
|
12
|
+
* @param folder (Opcional) Pasta de destino (ex: 'usuarios/123/')
|
|
18
13
|
*/
|
|
19
|
-
upload(file: File | Buffer, fileName: string, contentType: string): Promise<
|
|
14
|
+
upload(file: File | Buffer | Blob, fileName: string, contentType: string, folder?: string): Promise<{
|
|
15
|
+
id: any;
|
|
16
|
+
key: any;
|
|
17
|
+
downloadUrl: any;
|
|
18
|
+
url: any;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Lista arquivos de uma pasta.
|
|
22
|
+
*/
|
|
23
|
+
list(folder?: string): Promise<any>;
|
|
24
|
+
/**
|
|
25
|
+
* Deleta um arquivo pelo ID.
|
|
26
|
+
*/
|
|
27
|
+
delete(fileId: string): Promise<boolean>;
|
|
20
28
|
}
|
package/dist/storage.js
CHANGED
|
@@ -1,40 +1,65 @@
|
|
|
1
|
-
import axios from "axios";
|
|
2
|
-
/**
|
|
3
|
-
* Módulo de Storage
|
|
4
|
-
* Lida com upload e download de arquivos.
|
|
5
|
-
*/
|
|
1
|
+
import axios from "axios";
|
|
6
2
|
export class StorageModule {
|
|
7
3
|
constructor(client, http) {
|
|
8
4
|
this.client = client;
|
|
9
5
|
this.http = http;
|
|
10
6
|
}
|
|
11
7
|
/**
|
|
12
|
-
* Faz o upload de um arquivo
|
|
13
|
-
*
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @returns O objeto do arquivo criado no banco
|
|
8
|
+
* Faz o upload de um arquivo.
|
|
9
|
+
* @param file Arquivo (Browser: File, Node: Buffer)
|
|
10
|
+
* @param fileName Nome do arquivo (ex: 'foto.jpg')
|
|
11
|
+
* @param contentType MIME Type (ex: 'image/jpeg')
|
|
12
|
+
* @param folder (Opcional) Pasta de destino (ex: 'usuarios/123/')
|
|
18
13
|
*/
|
|
19
|
-
async upload(file, fileName, contentType
|
|
20
|
-
|
|
21
|
-
//
|
|
14
|
+
async upload(file, fileName, contentType, folder // [NOVO]
|
|
15
|
+
) {
|
|
16
|
+
// Calcula tamanho de forma segura para Browser e Node
|
|
17
|
+
let size = 0;
|
|
18
|
+
if (typeof File !== "undefined" && file instanceof File) {
|
|
19
|
+
size = file.size;
|
|
20
|
+
}
|
|
21
|
+
else if (typeof Blob !== "undefined" && file instanceof Blob) {
|
|
22
|
+
size = file.size;
|
|
23
|
+
}
|
|
24
|
+
else if (file instanceof Buffer) {
|
|
25
|
+
// Node.js
|
|
26
|
+
size = file.length;
|
|
27
|
+
}
|
|
28
|
+
// 1. Pedir URL assinada
|
|
22
29
|
const { data: presignData } = await this.http.post("/storage/presign", {
|
|
23
|
-
fileName
|
|
24
|
-
contentType
|
|
25
|
-
size
|
|
30
|
+
fileName,
|
|
31
|
+
contentType,
|
|
32
|
+
size,
|
|
33
|
+
prefix: folder || "", // [NOVO] Envia o prefixo para o backend
|
|
26
34
|
});
|
|
27
|
-
// O 'presign' vem dentro de 'data'
|
|
28
35
|
const presign = presignData.data;
|
|
29
|
-
if (!presign?.url)
|
|
30
|
-
throw new Error("
|
|
31
|
-
|
|
32
|
-
// 2. Enviar o arquivo diretamente para o Minio/S3 (sem auth)
|
|
33
|
-
// Usamos o 'axios' global aqui, não o 'this.http' (que adicionaria auth)
|
|
36
|
+
if (!presign?.url)
|
|
37
|
+
throw new Error("Falha ao obter URL de upload.");
|
|
38
|
+
// 2. Upload direto para S3
|
|
34
39
|
await axios.put(presign.url, file, {
|
|
35
40
|
headers: { "Content-Type": contentType },
|
|
36
41
|
});
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
return {
|
|
43
|
+
id: presign.objectId,
|
|
44
|
+
key: presign.key,
|
|
45
|
+
downloadUrl: presign.downloadUrl,
|
|
46
|
+
url: presign.downloadUrl, // Alias amigável
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Lista arquivos de uma pasta.
|
|
51
|
+
*/
|
|
52
|
+
async list(folder = "") {
|
|
53
|
+
const { data } = await this.http.get("/storage/list", {
|
|
54
|
+
params: { projectId: this.client.projectId, prefix: folder },
|
|
55
|
+
});
|
|
56
|
+
return data.data; // Retorna { files: [], folders: [] }
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Deleta um arquivo pelo ID.
|
|
60
|
+
*/
|
|
61
|
+
async delete(fileId) {
|
|
62
|
+
await this.http.delete("/storage/delete", { data: { objectId: fileId } });
|
|
63
|
+
return true;
|
|
39
64
|
}
|
|
40
65
|
}
|
package/package.json
CHANGED
package/src/auth.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { PlataformaClient } from "./index.js";
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Módulo de Autenticação
|
|
7
|
-
* Lida com login, registro e
|
|
7
|
+
* Lida com login, registro, gerenciamento de token e recuperação de senha.
|
|
8
8
|
*/
|
|
9
9
|
export class AuthModule {
|
|
10
10
|
private client: PlataformaClient;
|
|
@@ -24,9 +24,9 @@ export class AuthModule {
|
|
|
24
24
|
async login(email: string, password: string) {
|
|
25
25
|
try {
|
|
26
26
|
const { data } = await this.http.post("/auth/login", { email, password });
|
|
27
|
-
// Salva o token DENTRO da instância do SDK
|
|
27
|
+
// Salva o token DENTRO da instância do SDK para uso futuro
|
|
28
28
|
this.client.setToken(data.token);
|
|
29
|
-
return data; // Retorna {
|
|
29
|
+
return data; // Retorna { token, user: { ... } }
|
|
30
30
|
} catch (e: unknown) {
|
|
31
31
|
this.client.setToken(null); // Limpa o token em caso de falha
|
|
32
32
|
throw e;
|
|
@@ -34,7 +34,7 @@ export class AuthModule {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Registra um novo usuário e já o
|
|
37
|
+
* Registra um novo usuário e já realiza o login automaticamente.
|
|
38
38
|
* @param credentials Nome, email e senha
|
|
39
39
|
* @returns O objeto do usuário e o token
|
|
40
40
|
*/
|
|
@@ -45,7 +45,10 @@ export class AuthModule {
|
|
|
45
45
|
}) {
|
|
46
46
|
try {
|
|
47
47
|
const { data } = await this.http.post("/auth/register", credentials);
|
|
48
|
-
|
|
48
|
+
// Se o backend retornar o token no registro, já salvamos
|
|
49
|
+
if (data.token) {
|
|
50
|
+
this.client.setToken(data.token);
|
|
51
|
+
}
|
|
49
52
|
return data;
|
|
50
53
|
} catch (e: unknown) {
|
|
51
54
|
this.client.setToken(null);
|
|
@@ -54,7 +57,31 @@ export class AuthModule {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
/**
|
|
57
|
-
*
|
|
60
|
+
* Solicita um e-mail de recuperação de senha.
|
|
61
|
+
* @param email O e-mail da conta
|
|
62
|
+
* @returns A resposta da API (mensagem de sucesso)
|
|
63
|
+
*/
|
|
64
|
+
async forgotPassword(email: string) {
|
|
65
|
+
const { data } = await this.http.post("/auth/forgot-password", { email });
|
|
66
|
+
return data;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Redefine a senha usando o token recebido por e-mail.
|
|
71
|
+
* @param token O código/token recebido
|
|
72
|
+
* @param newPassword A nova senha desejada
|
|
73
|
+
* @returns A resposta da API (mensagem de sucesso)
|
|
74
|
+
*/
|
|
75
|
+
async resetPassword(token: string, newPassword: string) {
|
|
76
|
+
const { data } = await this.http.post("/auth/reset-password", {
|
|
77
|
+
token,
|
|
78
|
+
newPassword,
|
|
79
|
+
});
|
|
80
|
+
return data;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Desconecta o usuário limpando o token da memória do SDK.
|
|
58
85
|
*/
|
|
59
86
|
logout() {
|
|
60
87
|
this.client.setToken(null);
|
package/src/database.ts
CHANGED
|
@@ -4,15 +4,25 @@ import type { PlataformaClient } from "./index.js";
|
|
|
4
4
|
import WebSocket from "ws";
|
|
5
5
|
|
|
6
6
|
// Tipo para a mensagem que recebemos do WebSocket
|
|
7
|
-
type WebSocketMessage = {
|
|
7
|
+
type WebSocketMessage<T = any> = {
|
|
8
8
|
action: "create" | "update" | "delete";
|
|
9
9
|
collection: string;
|
|
10
|
-
data:
|
|
10
|
+
data: T;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// [NOVO] Opções de Listagem Avançada
|
|
14
|
+
export type ListOptions<T> = {
|
|
15
|
+
// Filtro parcial (ex: { status: 'active' })
|
|
16
|
+
filter?: Partial<T>;
|
|
17
|
+
// Ordenação
|
|
18
|
+
sort?: {
|
|
19
|
+
field: keyof T & string; // Garante que o campo existe no tipo T
|
|
20
|
+
order: "ASC" | "DESC";
|
|
21
|
+
};
|
|
11
22
|
};
|
|
12
23
|
|
|
13
24
|
/**
|
|
14
|
-
* Módulo de Banco de Dados
|
|
15
|
-
* Ponto de entrada para acessar as coleções.
|
|
25
|
+
* Módulo de Banco de Dados
|
|
16
26
|
*/
|
|
17
27
|
export class DatabaseModule {
|
|
18
28
|
private client: PlataformaClient;
|
|
@@ -24,20 +34,20 @@ export class DatabaseModule {
|
|
|
24
34
|
}
|
|
25
35
|
|
|
26
36
|
/**
|
|
27
|
-
* Seleciona uma coleção de dados
|
|
28
|
-
*
|
|
29
|
-
* @
|
|
37
|
+
* Seleciona uma coleção de dados.
|
|
38
|
+
* [PREMIUM] Suporta Generics <T> para tipagem forte.
|
|
39
|
+
* * @example client.db.collection<Product>('products')
|
|
30
40
|
*/
|
|
31
|
-
collection(collectionName: string) {
|
|
32
|
-
return new CollectionReference(this.client, this.http, collectionName);
|
|
41
|
+
collection<T = any>(collectionName: string) {
|
|
42
|
+
return new CollectionReference<T>(this.client, this.http, collectionName);
|
|
33
43
|
}
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
47
|
+
* Referência a uma coleção específica.
|
|
48
|
+
* O <T> define o formato dos dados (ex: interface User).
|
|
39
49
|
*/
|
|
40
|
-
class CollectionReference {
|
|
50
|
+
class CollectionReference<T> {
|
|
41
51
|
private client: PlataformaClient;
|
|
42
52
|
private http: AxiosInstance;
|
|
43
53
|
private collectionName: string;
|
|
@@ -47,103 +57,123 @@ class CollectionReference {
|
|
|
47
57
|
this.client = client;
|
|
48
58
|
this.http = http;
|
|
49
59
|
this.collectionName = name;
|
|
50
|
-
//
|
|
51
|
-
|
|
60
|
+
// Ajusta protocolo para WS/WSS
|
|
61
|
+
const protocol = client.apiUrl.startsWith("https") ? "wss" : "ws";
|
|
62
|
+
this.wsUrl = client.apiUrl.replace(/^https?/, protocol);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Lista documentos da coleção com filtros opcionais.
|
|
67
|
+
* @param options Filtros e Ordenação
|
|
68
|
+
*/
|
|
69
|
+
async list(options?: ListOptions<T>): Promise<T[]> {
|
|
70
|
+
const params: any = {};
|
|
71
|
+
|
|
72
|
+
// Converte os objetos do SDK para strings que o Backend entende
|
|
73
|
+
if (options?.filter) {
|
|
74
|
+
params.filter = JSON.stringify(options.filter);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (options?.sort) {
|
|
78
|
+
// Backend espera formato array: ["campo", "DESC"]
|
|
79
|
+
params.sort = JSON.stringify([options.sort.field, options.sort.order]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const { data } = await this.http.get(`/db/${this.collectionName}`, {
|
|
83
|
+
params,
|
|
84
|
+
});
|
|
85
|
+
return data.data;
|
|
52
86
|
}
|
|
53
87
|
|
|
54
88
|
/**
|
|
55
|
-
*
|
|
56
|
-
* (GET /v1/db/tasks)
|
|
89
|
+
* Busca um documento pelo ID.
|
|
57
90
|
*/
|
|
58
|
-
async
|
|
59
|
-
const { data } = await this.http.get(`/db/${this.collectionName}`);
|
|
60
|
-
return data.data;
|
|
91
|
+
async get(id: string): Promise<T> {
|
|
92
|
+
const { data } = await this.http.get(`/db/${this.collectionName}/${id}`);
|
|
93
|
+
return data.data;
|
|
61
94
|
}
|
|
62
95
|
|
|
63
96
|
/**
|
|
64
|
-
* Cria um novo documento
|
|
65
|
-
* (
|
|
66
|
-
* @param newData O objeto de dados a ser criado
|
|
97
|
+
* Cria um novo documento.
|
|
98
|
+
* O Partial<T> permite criar sem passar campos gerados (como id, createdAt).
|
|
67
99
|
*/
|
|
68
|
-
async create(newData:
|
|
100
|
+
async create(newData: Partial<T>): Promise<T> {
|
|
69
101
|
const { data } = await this.http.post(
|
|
70
102
|
`/db/${this.collectionName}`,
|
|
71
103
|
newData
|
|
72
104
|
);
|
|
73
|
-
return data.data;
|
|
105
|
+
return data.data;
|
|
74
106
|
}
|
|
75
107
|
|
|
76
108
|
/**
|
|
77
109
|
* Atualiza um documento existente.
|
|
78
|
-
* (PUT /v1/db/tasks/:id)
|
|
79
|
-
* @param id O ID do documento
|
|
80
|
-
* @param updates Os campos a serem atualizados
|
|
81
110
|
*/
|
|
82
|
-
async update(id: string, updates:
|
|
111
|
+
async update(id: string, updates: Partial<T>): Promise<T> {
|
|
83
112
|
const { data } = await this.http.put(
|
|
84
113
|
`/db/${this.collectionName}/${id}`,
|
|
85
114
|
updates
|
|
86
115
|
);
|
|
87
|
-
return data.data;
|
|
116
|
+
return data.data;
|
|
88
117
|
}
|
|
89
118
|
|
|
90
119
|
/**
|
|
91
120
|
* Deleta um documento.
|
|
92
|
-
* (DELETE /v1/db/tasks/:id)
|
|
93
|
-
* @param id O ID do documento
|
|
94
121
|
*/
|
|
95
|
-
async delete(id: string) {
|
|
96
|
-
|
|
97
|
-
return
|
|
122
|
+
async delete(id: string): Promise<boolean> {
|
|
123
|
+
await this.http.delete(`/db/${this.collectionName}/${id}`);
|
|
124
|
+
return true;
|
|
98
125
|
}
|
|
99
126
|
|
|
100
127
|
/**
|
|
101
|
-
* Inscreve-se para mudanças em tempo real
|
|
102
|
-
*
|
|
103
|
-
* @returns Uma função 'unsubscribe' para fechar a conexão
|
|
128
|
+
* Inscreve-se para mudanças em tempo real.
|
|
129
|
+
* O callback recebe os dados já tipados como T.
|
|
104
130
|
*/
|
|
105
131
|
subscribe(
|
|
106
|
-
callback: (action: "create" | "update" | "delete", data:
|
|
132
|
+
callback: (action: "create" | "update" | "delete", data: T) => void
|
|
107
133
|
) {
|
|
108
134
|
const token = this.client.getToken();
|
|
109
135
|
const projectId = this.client.projectId;
|
|
110
136
|
|
|
111
137
|
if (!token || !projectId) {
|
|
112
|
-
|
|
138
|
+
console.warn("[SDK] Realtime falhou: Token ou ProjectId ausentes.");
|
|
139
|
+
return () => {};
|
|
113
140
|
}
|
|
114
141
|
|
|
115
|
-
// Constrói a URL: ws://localhost:3000/v1/db/subscribe/tasks?token=...&projectId=...
|
|
116
142
|
const url = `${this.wsUrl}/v1/db/subscribe/${this.collectionName}?token=${token}&projectId=${projectId}`;
|
|
117
143
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
let ws: WebSocket | null = null;
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
ws = new WebSocket(url);
|
|
148
|
+
|
|
149
|
+
ws.onopen = () => {
|
|
150
|
+
// Conectado
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
ws.onmessage = (event: any) => {
|
|
154
|
+
try {
|
|
155
|
+
const raw = event.data?.toString() || event.toString();
|
|
156
|
+
if (raw === "pong") return;
|
|
157
|
+
|
|
158
|
+
const payload = JSON.parse(raw) as WebSocketMessage<T>;
|
|
159
|
+
callback(payload.action, payload.data);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
// Erro silencioso de parse
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Mantém a conexão viva (Heartbeat)
|
|
166
|
+
const pingInterval = setInterval(() => {
|
|
167
|
+
if (ws?.readyState === WebSocket.OPEN) ws.send("ping");
|
|
168
|
+
}, 30000);
|
|
169
|
+
|
|
170
|
+
return () => {
|
|
171
|
+
clearInterval(pingInterval);
|
|
172
|
+
if (ws) ws.close();
|
|
173
|
+
};
|
|
174
|
+
} catch (err) {
|
|
175
|
+
console.error("[SDK] Erro WS:", err);
|
|
176
|
+
return () => {};
|
|
177
|
+
}
|
|
148
178
|
}
|
|
149
179
|
}
|
package/src/functions.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/functions.ts
|
|
2
|
+
import type { AxiosInstance } from "axios";
|
|
3
|
+
import type { PlataformaClient } from "./index.js";
|
|
4
|
+
|
|
5
|
+
export class FunctionsModule {
|
|
6
|
+
private client: PlataformaClient;
|
|
7
|
+
private http: AxiosInstance;
|
|
8
|
+
|
|
9
|
+
constructor(client: PlataformaClient, http: AxiosInstance) {
|
|
10
|
+
this.client = client;
|
|
11
|
+
this.http = http;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Chama uma função HTTP Serverless.
|
|
16
|
+
* @param functionName O nome da função (ou rota, ex: 'pedidos/123')
|
|
17
|
+
* @param body (Opcional) Dados para enviar no corpo (POST)
|
|
18
|
+
* @param method (Opcional) Método HTTP (padrão POST se tiver body, GET se não)
|
|
19
|
+
*/
|
|
20
|
+
async invoke<T = any>(
|
|
21
|
+
functionName: string,
|
|
22
|
+
body?: any,
|
|
23
|
+
method?: "GET" | "POST" | "PUT" | "DELETE"
|
|
24
|
+
) {
|
|
25
|
+
const projectId = this.client.projectId;
|
|
26
|
+
|
|
27
|
+
// Remove barras iniciais para evitar URL malformada
|
|
28
|
+
const cleanName = functionName.replace(/^\//, "");
|
|
29
|
+
|
|
30
|
+
// Define método automaticamente se não informado
|
|
31
|
+
const finalMethod = method || (body ? "POST" : "GET");
|
|
32
|
+
|
|
33
|
+
const response = await this.http.request<T>({
|
|
34
|
+
url: `/functions/http/${projectId}/${cleanName}`,
|
|
35
|
+
method: finalMethod,
|
|
36
|
+
data: body,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return response.data;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createHttpClient } from "./http-client.js";
|
|
|
4
4
|
import { AuthModule } from "./auth.js";
|
|
5
5
|
import { DatabaseModule } from "./database.js";
|
|
6
6
|
import { StorageModule } from "./storage.js";
|
|
7
|
+
import { FunctionsModule } from "./functions.js"; // [NOVO] Import do módulo
|
|
7
8
|
|
|
8
9
|
type ClientConfig = {
|
|
9
10
|
apiUrl: string;
|
|
@@ -12,13 +13,14 @@ type ClientConfig = {
|
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* O cliente principal da Plataforma API.
|
|
15
|
-
* Ponto de entrada para todos os módulos (Auth, DB, Storage).
|
|
16
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage, Functions).
|
|
16
17
|
*/
|
|
17
18
|
export class PlataformaClient {
|
|
18
19
|
// Propriedades públicas (os "módulos")
|
|
19
20
|
public auth: AuthModule;
|
|
20
21
|
public db: DatabaseModule;
|
|
21
22
|
public storage: StorageModule;
|
|
23
|
+
public functions: FunctionsModule; // [NOVO] Propriedade pública
|
|
22
24
|
|
|
23
25
|
// Propriedades de configuração
|
|
24
26
|
public apiUrl: string;
|
|
@@ -32,22 +34,24 @@ export class PlataformaClient {
|
|
|
32
34
|
if (!config.apiUrl || !config.projectId) {
|
|
33
35
|
throw new Error("apiUrl e projectId são obrigatórios.");
|
|
34
36
|
}
|
|
35
|
-
this.apiUrl = config.apiUrl.replace(/\/$/, ""); // Remove barra final
|
|
37
|
+
this.apiUrl = config.apiUrl.replace(/\/$/, ""); // Remove barra final se houver
|
|
36
38
|
this.projectId = config.projectId;
|
|
37
39
|
|
|
38
|
-
// Inicializa o cliente HTTP (passando 'this', a própria instância)
|
|
40
|
+
// Inicializa o cliente HTTP (passando 'this', a própria instância para injetar token/ID)
|
|
39
41
|
this.http = createHttpClient(this);
|
|
40
42
|
|
|
41
|
-
// Inicializa os módulos
|
|
43
|
+
// Inicializa os módulos passando a referência do cliente e do axios
|
|
42
44
|
this.auth = new AuthModule(this, this.http);
|
|
43
45
|
this.db = new DatabaseModule(this, this.http);
|
|
44
46
|
this.storage = new StorageModule(this, this.http);
|
|
47
|
+
this.functions = new FunctionsModule(this, this.http); // [NOVO] Inicialização
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
// --- Gerenciamento de Token ---
|
|
48
51
|
|
|
49
52
|
/**
|
|
50
53
|
* Armazena o token de autenticação em memória.
|
|
54
|
+
* Chamado automaticamente pelo AuthModule após login.
|
|
51
55
|
* @param token O JWT (ou null para logout)
|
|
52
56
|
*/
|
|
53
57
|
setToken(token: string | null) {
|
|
@@ -56,6 +60,7 @@ export class PlataformaClient {
|
|
|
56
60
|
|
|
57
61
|
/**
|
|
58
62
|
* Recupera o token de autenticação atual.
|
|
63
|
+
* Usado pelo http-client para injetar o header Authorization.
|
|
59
64
|
* @returns O JWT ou null
|
|
60
65
|
*/
|
|
61
66
|
getToken(): string | null {
|
package/src/storage.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
// src/storage.ts
|
|
2
2
|
import type { AxiosInstance } from "axios";
|
|
3
3
|
import type { PlataformaClient } from "./index.js";
|
|
4
|
-
import axios from "axios";
|
|
4
|
+
import axios from "axios";
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Módulo de Storage
|
|
8
|
-
* Lida com upload e download de arquivos.
|
|
9
|
-
*/
|
|
10
6
|
export class StorageModule {
|
|
11
7
|
private client: PlataformaClient;
|
|
12
8
|
private http: AxiosInstance;
|
|
@@ -17,36 +13,68 @@ export class StorageModule {
|
|
|
17
13
|
}
|
|
18
14
|
|
|
19
15
|
/**
|
|
20
|
-
* Faz o upload de um arquivo
|
|
21
|
-
*
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* @returns O objeto do arquivo criado no banco
|
|
16
|
+
* Faz o upload de um arquivo.
|
|
17
|
+
* @param file Arquivo (Browser: File, Node: Buffer)
|
|
18
|
+
* @param fileName Nome do arquivo (ex: 'foto.jpg')
|
|
19
|
+
* @param contentType MIME Type (ex: 'image/jpeg')
|
|
20
|
+
* @param folder (Opcional) Pasta de destino (ex: 'usuarios/123/')
|
|
26
21
|
*/
|
|
27
|
-
async upload(
|
|
28
|
-
|
|
22
|
+
async upload(
|
|
23
|
+
file: File | Buffer | Blob,
|
|
24
|
+
fileName: string,
|
|
25
|
+
contentType: string,
|
|
26
|
+
folder?: string // [NOVO]
|
|
27
|
+
) {
|
|
28
|
+
// Calcula tamanho de forma segura para Browser e Node
|
|
29
|
+
let size = 0;
|
|
30
|
+
if (typeof File !== "undefined" && file instanceof File) {
|
|
31
|
+
size = file.size;
|
|
32
|
+
} else if (typeof Blob !== "undefined" && file instanceof Blob) {
|
|
33
|
+
size = file.size;
|
|
34
|
+
} else if (file instanceof Buffer) {
|
|
35
|
+
// Node.js
|
|
36
|
+
size = file.length;
|
|
37
|
+
}
|
|
29
38
|
|
|
30
|
-
// 1. Pedir
|
|
39
|
+
// 1. Pedir URL assinada
|
|
31
40
|
const { data: presignData } = await this.http.post("/storage/presign", {
|
|
32
|
-
fileName
|
|
33
|
-
contentType
|
|
34
|
-
size
|
|
41
|
+
fileName,
|
|
42
|
+
contentType,
|
|
43
|
+
size,
|
|
44
|
+
prefix: folder || "", // [NOVO] Envia o prefixo para o backend
|
|
35
45
|
});
|
|
36
46
|
|
|
37
|
-
// O 'presign' vem dentro de 'data'
|
|
38
47
|
const presign = presignData.data;
|
|
39
|
-
if (!presign?.url)
|
|
40
|
-
throw new Error("API não retornou uma URL de upload assinada.");
|
|
41
|
-
}
|
|
48
|
+
if (!presign?.url) throw new Error("Falha ao obter URL de upload.");
|
|
42
49
|
|
|
43
|
-
// 2.
|
|
44
|
-
// Usamos o 'axios' global aqui, não o 'this.http' (que adicionaria auth)
|
|
50
|
+
// 2. Upload direto para S3
|
|
45
51
|
await axios.put(presign.url, file, {
|
|
46
52
|
headers: { "Content-Type": contentType },
|
|
47
53
|
});
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
return {
|
|
56
|
+
id: presign.objectId,
|
|
57
|
+
key: presign.key,
|
|
58
|
+
downloadUrl: presign.downloadUrl,
|
|
59
|
+
url: presign.downloadUrl, // Alias amigável
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Lista arquivos de uma pasta.
|
|
65
|
+
*/
|
|
66
|
+
async list(folder = "") {
|
|
67
|
+
const { data } = await this.http.get("/storage/list", {
|
|
68
|
+
params: { projectId: this.client.projectId, prefix: folder },
|
|
69
|
+
});
|
|
70
|
+
return data.data; // Retorna { files: [], folders: [] }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Deleta um arquivo pelo ID.
|
|
75
|
+
*/
|
|
76
|
+
async delete(fileId: string) {
|
|
77
|
+
await this.http.delete("/storage/delete", { data: { objectId: fileId } });
|
|
78
|
+
return true;
|
|
51
79
|
}
|
|
52
80
|
}
|