@allanfsouza/aether-sdk 1.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/README.md +9 -0
- package/dist/auth.d.ts +32 -0
- package/dist/auth.js +50 -0
- package/dist/database.d.ts +59 -0
- package/dist/database.js +106 -0
- package/dist/http-client.d.ts +10 -0
- package/dist/http-client.js +27 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +39 -0
- package/dist/storage.d.ts +20 -0
- package/dist/storage.js +40 -0
- package/package.json +29 -0
- package/src/auth.ts +62 -0
- package/src/database.ts +149 -0
- package/src/http-client.ts +33 -0
- package/src/index.ts +64 -0
- package/src/storage.ts +52 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Plataforma SDK (Cliente JS/TS)
|
|
2
|
+
|
|
3
|
+
Este é o SDK oficial para interagir com a sua "Plataforma BaaS" (clone do Firebase). Ele gerencia autenticação, banco de dados genérico (com tempo real) e storage.
|
|
4
|
+
|
|
5
|
+
## Instalação
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @seu-username/plataforma-sdk
|
|
9
|
+
```
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { PlataformaClient } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Módulo de Autenticação
|
|
5
|
+
* Lida com login, registro e gerenciamento de token.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AuthModule {
|
|
8
|
+
private client;
|
|
9
|
+
private http;
|
|
10
|
+
constructor(client: PlataformaClient, http: AxiosInstance);
|
|
11
|
+
/**
|
|
12
|
+
* Autentica um usuário e armazena o token no SDK.
|
|
13
|
+
* @param email O e-mail do usuário
|
|
14
|
+
* @param password A senha do usuário
|
|
15
|
+
* @returns O objeto do usuário e o token
|
|
16
|
+
*/
|
|
17
|
+
login(email: string, password: string): Promise<any>;
|
|
18
|
+
/**
|
|
19
|
+
* Registra um novo usuário e já o loga.
|
|
20
|
+
* @param credentials Nome, email e senha
|
|
21
|
+
* @returns O objeto do usuário e o token
|
|
22
|
+
*/
|
|
23
|
+
register(credentials: {
|
|
24
|
+
name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
password: string;
|
|
27
|
+
}): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* Desconecta o usuário limpando o token do SDK.
|
|
30
|
+
*/
|
|
31
|
+
logout(): void;
|
|
32
|
+
}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Módulo de Autenticação
|
|
3
|
+
* Lida com login, registro e gerenciamento de token.
|
|
4
|
+
*/
|
|
5
|
+
export class AuthModule {
|
|
6
|
+
constructor(client, http) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
this.http = http;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Autentica um usuário e armazena o token no SDK.
|
|
12
|
+
* @param email O e-mail do usuário
|
|
13
|
+
* @param password A senha do usuário
|
|
14
|
+
* @returns O objeto do usuário e o token
|
|
15
|
+
*/
|
|
16
|
+
async login(email, password) {
|
|
17
|
+
try {
|
|
18
|
+
const { data } = await this.http.post("/auth/login", { email, password });
|
|
19
|
+
// Salva o token DENTRO da instância do SDK
|
|
20
|
+
this.client.setToken(data.token);
|
|
21
|
+
return data; // Retorna { user, token }
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
this.client.setToken(null); // Limpa o token em caso de falha
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Registra um novo usuário e já o loga.
|
|
30
|
+
* @param credentials Nome, email e senha
|
|
31
|
+
* @returns O objeto do usuário e o token
|
|
32
|
+
*/
|
|
33
|
+
async register(credentials) {
|
|
34
|
+
try {
|
|
35
|
+
const { data } = await this.http.post("/auth/register", credentials);
|
|
36
|
+
this.client.setToken(data.token);
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
this.client.setToken(null);
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Desconecta o usuário limpando o token do SDK.
|
|
46
|
+
*/
|
|
47
|
+
logout() {
|
|
48
|
+
this.client.setToken(null);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { PlataformaClient } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Módulo de Banco de Dados (Firestore-like)
|
|
5
|
+
* Ponto de entrada para acessar as coleções.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DatabaseModule {
|
|
8
|
+
private client;
|
|
9
|
+
private http;
|
|
10
|
+
constructor(client: PlataformaClient, http: AxiosInstance);
|
|
11
|
+
/**
|
|
12
|
+
* Seleciona uma coleção de dados (ex: 'tasks' ou 'posts').
|
|
13
|
+
* @param collectionName O nome da coleção (ex: "tasks")
|
|
14
|
+
* @returns Uma instância de CollectionReference para operar nela
|
|
15
|
+
*/
|
|
16
|
+
collection(collectionName: string): CollectionReference;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Representa uma referência a uma coleção específica no banco.
|
|
20
|
+
* Contém os métodos CRUD (create, list, update, delete) e subscribe.
|
|
21
|
+
*/
|
|
22
|
+
declare class CollectionReference {
|
|
23
|
+
private client;
|
|
24
|
+
private http;
|
|
25
|
+
private collectionName;
|
|
26
|
+
private wsUrl;
|
|
27
|
+
constructor(client: PlataformaClient, http: AxiosInstance, name: string);
|
|
28
|
+
/**
|
|
29
|
+
* Lista todos os documentos da coleção.
|
|
30
|
+
* (GET /v1/db/tasks)
|
|
31
|
+
*/
|
|
32
|
+
list(): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Cria um novo documento na coleção.
|
|
35
|
+
* (POST /v1/db/tasks)
|
|
36
|
+
* @param newData O objeto de dados a ser criado
|
|
37
|
+
*/
|
|
38
|
+
create(newData: Record<string, any>): Promise<any>;
|
|
39
|
+
/**
|
|
40
|
+
* 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
|
+
*/
|
|
45
|
+
update(id: string, updates: Record<string, any>): Promise<any>;
|
|
46
|
+
/**
|
|
47
|
+
* Deleta um documento.
|
|
48
|
+
* (DELETE /v1/db/tasks/:id)
|
|
49
|
+
* @param id O ID do documento
|
|
50
|
+
*/
|
|
51
|
+
delete(id: string): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* Inscreve-se para mudanças em tempo real na coleção.
|
|
54
|
+
* @param callback A função que será chamada com (action, data)
|
|
55
|
+
* @returns Uma função 'unsubscribe' para fechar a conexão
|
|
56
|
+
*/
|
|
57
|
+
subscribe(callback: (action: "create" | "update" | "delete", data: any) => void): () => void;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
package/dist/database.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import WebSocket from "ws";
|
|
2
|
+
/**
|
|
3
|
+
* Módulo de Banco de Dados (Firestore-like)
|
|
4
|
+
* Ponto de entrada para acessar as coleções.
|
|
5
|
+
*/
|
|
6
|
+
export class DatabaseModule {
|
|
7
|
+
constructor(client, http) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
this.http = http;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Seleciona uma coleção de dados (ex: 'tasks' ou 'posts').
|
|
13
|
+
* @param collectionName O nome da coleção (ex: "tasks")
|
|
14
|
+
* @returns Uma instância de CollectionReference para operar nela
|
|
15
|
+
*/
|
|
16
|
+
collection(collectionName) {
|
|
17
|
+
return new CollectionReference(this.client, this.http, collectionName);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Representa uma referência a uma coleção específica no banco.
|
|
22
|
+
* Contém os métodos CRUD (create, list, update, delete) e subscribe.
|
|
23
|
+
*/
|
|
24
|
+
class CollectionReference {
|
|
25
|
+
constructor(client, http, name) {
|
|
26
|
+
this.client = client;
|
|
27
|
+
this.http = http;
|
|
28
|
+
this.collectionName = name;
|
|
29
|
+
// Constrói a URL do WebSocket (substituindo http por ws)
|
|
30
|
+
this.wsUrl = client.apiUrl.replace(/^http/, "ws");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Lista todos os documentos da coleção.
|
|
34
|
+
* (GET /v1/db/tasks)
|
|
35
|
+
*/
|
|
36
|
+
async list() {
|
|
37
|
+
const { data } = await this.http.get(`/db/${this.collectionName}`);
|
|
38
|
+
return data.data; // Retorna o array de documentos
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Cria um novo documento na coleção.
|
|
42
|
+
* (POST /v1/db/tasks)
|
|
43
|
+
* @param newData O objeto de dados a ser criado
|
|
44
|
+
*/
|
|
45
|
+
async create(newData) {
|
|
46
|
+
const { data } = await this.http.post(`/db/${this.collectionName}`, newData);
|
|
47
|
+
return data.data; // Retorna o documento criado
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 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
|
+
*/
|
|
55
|
+
async update(id, updates) {
|
|
56
|
+
const { data } = await this.http.put(`/db/${this.collectionName}/${id}`, updates);
|
|
57
|
+
return data.data; // Retorna o documento atualizado
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deleta um documento.
|
|
61
|
+
* (DELETE /v1/db/tasks/:id)
|
|
62
|
+
* @param id O ID do documento
|
|
63
|
+
*/
|
|
64
|
+
async delete(id) {
|
|
65
|
+
const { data } = await this.http.delete(`/db/${this.collectionName}/${id}`);
|
|
66
|
+
return data; // Retorna { ok: true, ... }
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Inscreve-se para mudanças em tempo real na coleção.
|
|
70
|
+
* @param callback A função que será chamada com (action, data)
|
|
71
|
+
* @returns Uma função 'unsubscribe' para fechar a conexão
|
|
72
|
+
*/
|
|
73
|
+
subscribe(callback) {
|
|
74
|
+
const token = this.client.getToken();
|
|
75
|
+
const projectId = this.client.projectId;
|
|
76
|
+
if (!token || !projectId) {
|
|
77
|
+
throw new Error("Não é possível se inscrever sem um token e projectId.");
|
|
78
|
+
}
|
|
79
|
+
// Constrói a URL: ws://localhost:3000/v1/db/subscribe/tasks?token=...&projectId=...
|
|
80
|
+
const url = `${this.wsUrl}/v1/db/subscribe/${this.collectionName}?token=${token}&projectId=${projectId}`;
|
|
81
|
+
const ws = new WebSocket(url);
|
|
82
|
+
ws.on("open", () => {
|
|
83
|
+
console.log(`[SDK] Inscrito em tempo real na coleção '${this.collectionName}'`);
|
|
84
|
+
});
|
|
85
|
+
ws.on("message", (message) => {
|
|
86
|
+
try {
|
|
87
|
+
const payload = JSON.parse(message);
|
|
88
|
+
// Chama o callback do usuário
|
|
89
|
+
callback(payload.action, payload.data);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
console.error("[SDK] Erro ao processar mensagem WS:", e);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
ws.on("close", () => {
|
|
96
|
+
console.log(`[SDK] Desconectado da coleção '${this.collectionName}'`);
|
|
97
|
+
});
|
|
98
|
+
ws.on("error", (err) => {
|
|
99
|
+
console.error("[SDK] Erro no WebSocket:", err.message);
|
|
100
|
+
});
|
|
101
|
+
// Retorna uma função que o usuário pode chamar para parar de "ouvir"
|
|
102
|
+
return () => {
|
|
103
|
+
ws.close();
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type AxiosInstance } from "axios";
|
|
2
|
+
import { PlataformaClient } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Cria uma instância do Axios pré-configurada.
|
|
5
|
+
* Ela usa um interceptor para adicionar dinamicamente os
|
|
6
|
+
* headers 'Authorization' e 'X-Project-ID' em cada requisição.
|
|
7
|
+
* * @param client A instância principal do PlataformaClient
|
|
8
|
+
* @returns Uma instância configurada do Axios
|
|
9
|
+
*/
|
|
10
|
+
export declare function createHttpClient(client: PlataformaClient): AxiosInstance;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/http-client.ts
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
/**
|
|
4
|
+
* Cria uma instância do Axios pré-configurada.
|
|
5
|
+
* Ela usa um interceptor para adicionar dinamicamente os
|
|
6
|
+
* headers 'Authorization' e 'X-Project-ID' em cada requisição.
|
|
7
|
+
* * @param client A instância principal do PlataformaClient
|
|
8
|
+
* @returns Uma instância configurada do Axios
|
|
9
|
+
*/
|
|
10
|
+
export function createHttpClient(client) {
|
|
11
|
+
const http = axios.create({
|
|
12
|
+
baseURL: `${client.apiUrl}/v1`, // Adiciona o /v1 automaticamente
|
|
13
|
+
});
|
|
14
|
+
http.interceptors.request.use((config) => {
|
|
15
|
+
// 1. Pega o token atual do cliente
|
|
16
|
+
const token = client.getToken();
|
|
17
|
+
if (token) {
|
|
18
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
19
|
+
}
|
|
20
|
+
// 2. Pega o ID do projeto
|
|
21
|
+
if (client.projectId) {
|
|
22
|
+
config.headers["X-Project-ID"] = client.projectId;
|
|
23
|
+
}
|
|
24
|
+
return config;
|
|
25
|
+
});
|
|
26
|
+
return http;
|
|
27
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AuthModule } from "./auth.js";
|
|
2
|
+
import { DatabaseModule } from "./database.js";
|
|
3
|
+
import { StorageModule } from "./storage.js";
|
|
4
|
+
type ClientConfig = {
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
projectId: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* O cliente principal da Plataforma API.
|
|
10
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage).
|
|
11
|
+
*/
|
|
12
|
+
export declare class PlataformaClient {
|
|
13
|
+
auth: AuthModule;
|
|
14
|
+
db: DatabaseModule;
|
|
15
|
+
storage: StorageModule;
|
|
16
|
+
apiUrl: string;
|
|
17
|
+
projectId: string;
|
|
18
|
+
private http;
|
|
19
|
+
private _token;
|
|
20
|
+
constructor(config: ClientConfig);
|
|
21
|
+
/**
|
|
22
|
+
* Armazena o token de autenticação em memória.
|
|
23
|
+
* @param token O JWT (ou null para logout)
|
|
24
|
+
*/
|
|
25
|
+
setToken(token: string | null): void;
|
|
26
|
+
/**
|
|
27
|
+
* Recupera o token de autenticação atual.
|
|
28
|
+
* @returns O JWT ou null
|
|
29
|
+
*/
|
|
30
|
+
getToken(): string | null;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createHttpClient } from "./http-client.js";
|
|
2
|
+
import { AuthModule } from "./auth.js";
|
|
3
|
+
import { DatabaseModule } from "./database.js";
|
|
4
|
+
import { StorageModule } from "./storage.js";
|
|
5
|
+
/**
|
|
6
|
+
* O cliente principal da Plataforma API.
|
|
7
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage).
|
|
8
|
+
*/
|
|
9
|
+
export class PlataformaClient {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this._token = null;
|
|
12
|
+
if (!config.apiUrl || !config.projectId) {
|
|
13
|
+
throw new Error("apiUrl e projectId são obrigatórios.");
|
|
14
|
+
}
|
|
15
|
+
this.apiUrl = config.apiUrl.replace(/\/$/, ""); // Remove barra final
|
|
16
|
+
this.projectId = config.projectId;
|
|
17
|
+
// Inicializa o cliente HTTP (passando 'this', a própria instância)
|
|
18
|
+
this.http = createHttpClient(this);
|
|
19
|
+
// Inicializa os módulos
|
|
20
|
+
this.auth = new AuthModule(this, this.http);
|
|
21
|
+
this.db = new DatabaseModule(this, this.http);
|
|
22
|
+
this.storage = new StorageModule(this, this.http);
|
|
23
|
+
}
|
|
24
|
+
// --- Gerenciamento de Token ---
|
|
25
|
+
/**
|
|
26
|
+
* Armazena o token de autenticação em memória.
|
|
27
|
+
* @param token O JWT (ou null para logout)
|
|
28
|
+
*/
|
|
29
|
+
setToken(token) {
|
|
30
|
+
this._token = token;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Recupera o token de autenticação atual.
|
|
34
|
+
* @returns O JWT ou null
|
|
35
|
+
*/
|
|
36
|
+
getToken() {
|
|
37
|
+
return this._token;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import type { PlataformaClient } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Módulo de Storage
|
|
5
|
+
* Lida com upload e download de arquivos.
|
|
6
|
+
*/
|
|
7
|
+
export declare class StorageModule {
|
|
8
|
+
private client;
|
|
9
|
+
private http;
|
|
10
|
+
constructor(client: PlataformaClient, http: AxiosInstance);
|
|
11
|
+
/**
|
|
12
|
+
* Faz o upload de um arquivo para o Storage do projeto.
|
|
13
|
+
* Isso lida com o fluxo de "presign" (URL assinada) automaticamente.
|
|
14
|
+
* @param file O objeto 'File' (do navegador) ou um Buffer (do Node.js)
|
|
15
|
+
* @param fileName O nome do arquivo (ex: "imagem.png")
|
|
16
|
+
* @param contentType O tipo (ex: "image/png")
|
|
17
|
+
* @returns O objeto do arquivo criado no banco
|
|
18
|
+
*/
|
|
19
|
+
upload(file: File | Buffer, fileName: string, contentType: string): Promise<any>;
|
|
20
|
+
}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import axios from "axios"; // [A CORREÇÃO ESTÁ AQUI]
|
|
2
|
+
/**
|
|
3
|
+
* Módulo de Storage
|
|
4
|
+
* Lida com upload e download de arquivos.
|
|
5
|
+
*/
|
|
6
|
+
export class StorageModule {
|
|
7
|
+
constructor(client, http) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
this.http = http;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Faz o upload de um arquivo para o Storage do projeto.
|
|
13
|
+
* Isso lida com o fluxo de "presign" (URL assinada) automaticamente.
|
|
14
|
+
* @param file O objeto 'File' (do navegador) ou um Buffer (do Node.js)
|
|
15
|
+
* @param fileName O nome do arquivo (ex: "imagem.png")
|
|
16
|
+
* @param contentType O tipo (ex: "image/png")
|
|
17
|
+
* @returns O objeto do arquivo criado no banco
|
|
18
|
+
*/
|
|
19
|
+
async upload(file, fileName, contentType) {
|
|
20
|
+
const size = file.size || file.length;
|
|
21
|
+
// 1. Pedir a URL de upload para nossa API
|
|
22
|
+
const { data: presignData } = await this.http.post("/storage/presign", {
|
|
23
|
+
fileName: fileName,
|
|
24
|
+
contentType: contentType,
|
|
25
|
+
size: size,
|
|
26
|
+
});
|
|
27
|
+
// O 'presign' vem dentro de 'data'
|
|
28
|
+
const presign = presignData.data;
|
|
29
|
+
if (!presign?.url) {
|
|
30
|
+
throw new Error("API não retornou uma URL de upload assinada.");
|
|
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)
|
|
34
|
+
await axios.put(presign.url, file, {
|
|
35
|
+
headers: { "Content-Type": contentType },
|
|
36
|
+
});
|
|
37
|
+
// 3. Retorna os detalhes do objeto (downloadUrl, objectId, etc.)
|
|
38
|
+
return presign;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@allanfsouza/aether-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SDK do Cliente para a Plataforma API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "npx tsc",
|
|
16
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"axios": "^1.13.2",
|
|
23
|
+
"ws": "^8.18.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/ws": "^8.5.11",
|
|
27
|
+
"typescript": "^5.9.3"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/auth.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// src/auth.ts
|
|
2
|
+
import type { AxiosInstance } from "axios";
|
|
3
|
+
import type { PlataformaClient } from "./index.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Módulo de Autenticação
|
|
7
|
+
* Lida com login, registro e gerenciamento de token.
|
|
8
|
+
*/
|
|
9
|
+
export class AuthModule {
|
|
10
|
+
private client: PlataformaClient;
|
|
11
|
+
private http: AxiosInstance;
|
|
12
|
+
|
|
13
|
+
constructor(client: PlataformaClient, http: AxiosInstance) {
|
|
14
|
+
this.client = client;
|
|
15
|
+
this.http = http;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Autentica um usuário e armazena o token no SDK.
|
|
20
|
+
* @param email O e-mail do usuário
|
|
21
|
+
* @param password A senha do usuário
|
|
22
|
+
* @returns O objeto do usuário e o token
|
|
23
|
+
*/
|
|
24
|
+
async login(email: string, password: string) {
|
|
25
|
+
try {
|
|
26
|
+
const { data } = await this.http.post("/auth/login", { email, password });
|
|
27
|
+
// Salva o token DENTRO da instância do SDK
|
|
28
|
+
this.client.setToken(data.token);
|
|
29
|
+
return data; // Retorna { user, token }
|
|
30
|
+
} catch (e: unknown) {
|
|
31
|
+
this.client.setToken(null); // Limpa o token em caso de falha
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Registra um novo usuário e já o loga.
|
|
38
|
+
* @param credentials Nome, email e senha
|
|
39
|
+
* @returns O objeto do usuário e o token
|
|
40
|
+
*/
|
|
41
|
+
async register(credentials: {
|
|
42
|
+
name: string;
|
|
43
|
+
email: string;
|
|
44
|
+
password: string;
|
|
45
|
+
}) {
|
|
46
|
+
try {
|
|
47
|
+
const { data } = await this.http.post("/auth/register", credentials);
|
|
48
|
+
this.client.setToken(data.token);
|
|
49
|
+
return data;
|
|
50
|
+
} catch (e: unknown) {
|
|
51
|
+
this.client.setToken(null);
|
|
52
|
+
throw e;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Desconecta o usuário limpando o token do SDK.
|
|
58
|
+
*/
|
|
59
|
+
logout() {
|
|
60
|
+
this.client.setToken(null);
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/database.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// src/database.ts
|
|
2
|
+
import type { AxiosInstance } from "axios";
|
|
3
|
+
import type { PlataformaClient } from "./index.js";
|
|
4
|
+
import WebSocket from "ws";
|
|
5
|
+
|
|
6
|
+
// Tipo para a mensagem que recebemos do WebSocket
|
|
7
|
+
type WebSocketMessage = {
|
|
8
|
+
action: "create" | "update" | "delete";
|
|
9
|
+
collection: string;
|
|
10
|
+
data: any;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Módulo de Banco de Dados (Firestore-like)
|
|
15
|
+
* Ponto de entrada para acessar as coleções.
|
|
16
|
+
*/
|
|
17
|
+
export class DatabaseModule {
|
|
18
|
+
private client: PlataformaClient;
|
|
19
|
+
private http: AxiosInstance;
|
|
20
|
+
|
|
21
|
+
constructor(client: PlataformaClient, http: AxiosInstance) {
|
|
22
|
+
this.client = client;
|
|
23
|
+
this.http = http;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Seleciona uma coleção de dados (ex: 'tasks' ou 'posts').
|
|
28
|
+
* @param collectionName O nome da coleção (ex: "tasks")
|
|
29
|
+
* @returns Uma instância de CollectionReference para operar nela
|
|
30
|
+
*/
|
|
31
|
+
collection(collectionName: string) {
|
|
32
|
+
return new CollectionReference(this.client, this.http, collectionName);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Representa uma referência a uma coleção específica no banco.
|
|
38
|
+
* Contém os métodos CRUD (create, list, update, delete) e subscribe.
|
|
39
|
+
*/
|
|
40
|
+
class CollectionReference {
|
|
41
|
+
private client: PlataformaClient;
|
|
42
|
+
private http: AxiosInstance;
|
|
43
|
+
private collectionName: string;
|
|
44
|
+
private wsUrl: string;
|
|
45
|
+
|
|
46
|
+
constructor(client: PlataformaClient, http: AxiosInstance, name: string) {
|
|
47
|
+
this.client = client;
|
|
48
|
+
this.http = http;
|
|
49
|
+
this.collectionName = name;
|
|
50
|
+
// Constrói a URL do WebSocket (substituindo http por ws)
|
|
51
|
+
this.wsUrl = client.apiUrl.replace(/^http/, "ws");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Lista todos os documentos da coleção.
|
|
56
|
+
* (GET /v1/db/tasks)
|
|
57
|
+
*/
|
|
58
|
+
async list() {
|
|
59
|
+
const { data } = await this.http.get(`/db/${this.collectionName}`);
|
|
60
|
+
return data.data; // Retorna o array de documentos
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Cria um novo documento na coleção.
|
|
65
|
+
* (POST /v1/db/tasks)
|
|
66
|
+
* @param newData O objeto de dados a ser criado
|
|
67
|
+
*/
|
|
68
|
+
async create(newData: Record<string, any>) {
|
|
69
|
+
const { data } = await this.http.post(
|
|
70
|
+
`/db/${this.collectionName}`,
|
|
71
|
+
newData
|
|
72
|
+
);
|
|
73
|
+
return data.data; // Retorna o documento criado
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 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
|
+
*/
|
|
82
|
+
async update(id: string, updates: Record<string, any>) {
|
|
83
|
+
const { data } = await this.http.put(
|
|
84
|
+
`/db/${this.collectionName}/${id}`,
|
|
85
|
+
updates
|
|
86
|
+
);
|
|
87
|
+
return data.data; // Retorna o documento atualizado
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Deleta um documento.
|
|
92
|
+
* (DELETE /v1/db/tasks/:id)
|
|
93
|
+
* @param id O ID do documento
|
|
94
|
+
*/
|
|
95
|
+
async delete(id: string) {
|
|
96
|
+
const { data } = await this.http.delete(`/db/${this.collectionName}/${id}`);
|
|
97
|
+
return data; // Retorna { ok: true, ... }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Inscreve-se para mudanças em tempo real na coleção.
|
|
102
|
+
* @param callback A função que será chamada com (action, data)
|
|
103
|
+
* @returns Uma função 'unsubscribe' para fechar a conexão
|
|
104
|
+
*/
|
|
105
|
+
subscribe(
|
|
106
|
+
callback: (action: "create" | "update" | "delete", data: any) => void
|
|
107
|
+
) {
|
|
108
|
+
const token = this.client.getToken();
|
|
109
|
+
const projectId = this.client.projectId;
|
|
110
|
+
|
|
111
|
+
if (!token || !projectId) {
|
|
112
|
+
throw new Error("Não é possível se inscrever sem um token e projectId.");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Constrói a URL: ws://localhost:3000/v1/db/subscribe/tasks?token=...&projectId=...
|
|
116
|
+
const url = `${this.wsUrl}/v1/db/subscribe/${this.collectionName}?token=${token}&projectId=${projectId}`;
|
|
117
|
+
|
|
118
|
+
const ws = new WebSocket(url);
|
|
119
|
+
|
|
120
|
+
ws.on("open", () => {
|
|
121
|
+
console.log(
|
|
122
|
+
`[SDK] Inscrito em tempo real na coleção '${this.collectionName}'`
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
ws.on("message", (message: string) => {
|
|
127
|
+
try {
|
|
128
|
+
const payload = JSON.parse(message) as WebSocketMessage;
|
|
129
|
+
// Chama o callback do usuário
|
|
130
|
+
callback(payload.action, payload.data);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
console.error("[SDK] Erro ao processar mensagem WS:", e);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
ws.on("close", () => {
|
|
137
|
+
console.log(`[SDK] Desconectado da coleção '${this.collectionName}'`);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
ws.on("error", (err) => {
|
|
141
|
+
console.error("[SDK] Erro no WebSocket:", err.message);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Retorna uma função que o usuário pode chamar para parar de "ouvir"
|
|
145
|
+
return () => {
|
|
146
|
+
ws.close();
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/http-client.ts
|
|
2
|
+
import axios, { type AxiosInstance } from "axios";
|
|
3
|
+
import { PlataformaClient } from "./index.js"; // Importa o tipo da classe principal
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cria uma instância do Axios pré-configurada.
|
|
7
|
+
* Ela usa um interceptor para adicionar dinamicamente os
|
|
8
|
+
* headers 'Authorization' e 'X-Project-ID' em cada requisição.
|
|
9
|
+
* * @param client A instância principal do PlataformaClient
|
|
10
|
+
* @returns Uma instância configurada do Axios
|
|
11
|
+
*/
|
|
12
|
+
export function createHttpClient(client: PlataformaClient): AxiosInstance {
|
|
13
|
+
const http = axios.create({
|
|
14
|
+
baseURL: `${client.apiUrl}/v1`, // Adiciona o /v1 automaticamente
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
http.interceptors.request.use((config) => {
|
|
18
|
+
// 1. Pega o token atual do cliente
|
|
19
|
+
const token = client.getToken();
|
|
20
|
+
if (token) {
|
|
21
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 2. Pega o ID do projeto
|
|
25
|
+
if (client.projectId) {
|
|
26
|
+
config.headers["X-Project-ID"] = client.projectId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return config;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return http;
|
|
33
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import type { AxiosInstance } from "axios";
|
|
3
|
+
import { createHttpClient } from "./http-client.js";
|
|
4
|
+
import { AuthModule } from "./auth.js";
|
|
5
|
+
import { DatabaseModule } from "./database.js";
|
|
6
|
+
import { StorageModule } from "./storage.js";
|
|
7
|
+
|
|
8
|
+
type ClientConfig = {
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
projectId: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* O cliente principal da Plataforma API.
|
|
15
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage).
|
|
16
|
+
*/
|
|
17
|
+
export class PlataformaClient {
|
|
18
|
+
// Propriedades públicas (os "módulos")
|
|
19
|
+
public auth: AuthModule;
|
|
20
|
+
public db: DatabaseModule;
|
|
21
|
+
public storage: StorageModule;
|
|
22
|
+
|
|
23
|
+
// Propriedades de configuração
|
|
24
|
+
public apiUrl: string;
|
|
25
|
+
public projectId: string;
|
|
26
|
+
|
|
27
|
+
// Propriedades internas
|
|
28
|
+
private http: AxiosInstance;
|
|
29
|
+
private _token: string | null = null;
|
|
30
|
+
|
|
31
|
+
constructor(config: ClientConfig) {
|
|
32
|
+
if (!config.apiUrl || !config.projectId) {
|
|
33
|
+
throw new Error("apiUrl e projectId são obrigatórios.");
|
|
34
|
+
}
|
|
35
|
+
this.apiUrl = config.apiUrl.replace(/\/$/, ""); // Remove barra final
|
|
36
|
+
this.projectId = config.projectId;
|
|
37
|
+
|
|
38
|
+
// Inicializa o cliente HTTP (passando 'this', a própria instância)
|
|
39
|
+
this.http = createHttpClient(this);
|
|
40
|
+
|
|
41
|
+
// Inicializa os módulos
|
|
42
|
+
this.auth = new AuthModule(this, this.http);
|
|
43
|
+
this.db = new DatabaseModule(this, this.http);
|
|
44
|
+
this.storage = new StorageModule(this, this.http);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- Gerenciamento de Token ---
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Armazena o token de autenticação em memória.
|
|
51
|
+
* @param token O JWT (ou null para logout)
|
|
52
|
+
*/
|
|
53
|
+
setToken(token: string | null) {
|
|
54
|
+
this._token = token;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Recupera o token de autenticação atual.
|
|
59
|
+
* @returns O JWT ou null
|
|
60
|
+
*/
|
|
61
|
+
getToken(): string | null {
|
|
62
|
+
return this._token;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/storage.ts
|
|
2
|
+
import type { AxiosInstance } from "axios";
|
|
3
|
+
import type { PlataformaClient } from "./index.js";
|
|
4
|
+
import axios from "axios"; // [A CORREÇÃO ESTÁ AQUI]
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Módulo de Storage
|
|
8
|
+
* Lida com upload e download de arquivos.
|
|
9
|
+
*/
|
|
10
|
+
export class StorageModule {
|
|
11
|
+
private client: PlataformaClient;
|
|
12
|
+
private http: AxiosInstance;
|
|
13
|
+
|
|
14
|
+
constructor(client: PlataformaClient, http: AxiosInstance) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
this.http = http;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Faz o upload de um arquivo para o Storage do projeto.
|
|
21
|
+
* Isso lida com o fluxo de "presign" (URL assinada) automaticamente.
|
|
22
|
+
* @param file O objeto 'File' (do navegador) ou um Buffer (do Node.js)
|
|
23
|
+
* @param fileName O nome do arquivo (ex: "imagem.png")
|
|
24
|
+
* @param contentType O tipo (ex: "image/png")
|
|
25
|
+
* @returns O objeto do arquivo criado no banco
|
|
26
|
+
*/
|
|
27
|
+
async upload(file: File | Buffer, fileName: string, contentType: string) {
|
|
28
|
+
const size = (file as File).size || (file as Buffer).length;
|
|
29
|
+
|
|
30
|
+
// 1. Pedir a URL de upload para nossa API
|
|
31
|
+
const { data: presignData } = await this.http.post("/storage/presign", {
|
|
32
|
+
fileName: fileName,
|
|
33
|
+
contentType: contentType,
|
|
34
|
+
size: size,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// O 'presign' vem dentro de 'data'
|
|
38
|
+
const presign = presignData.data;
|
|
39
|
+
if (!presign?.url) {
|
|
40
|
+
throw new Error("API não retornou uma URL de upload assinada.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 2. Enviar o arquivo diretamente para o Minio/S3 (sem auth)
|
|
44
|
+
// Usamos o 'axios' global aqui, não o 'this.http' (que adicionaria auth)
|
|
45
|
+
await axios.put(presign.url, file, {
|
|
46
|
+
headers: { "Content-Type": contentType },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 3. Retorna os detalhes do objeto (downloadUrl, objectId, etc.)
|
|
50
|
+
return presign;
|
|
51
|
+
}
|
|
52
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020", // Moderno, mas compatível
|
|
4
|
+
"module": "NodeNext", // Suporta tanto 'require' (CJS) quanto 'import' (ESM)
|
|
5
|
+
"declaration": true, // [IMPORTANTE] Gera arquivos .d.ts (para autocompletar)
|
|
6
|
+
"outDir": "./dist", // Onde o JavaScript compilado irá
|
|
7
|
+
"rootDir": "./src", // Onde nosso código TypeScript está
|
|
8
|
+
"strict": true, // Força boas práticas
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"moduleResolution": "NodeNext"
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"] // Só compila o que está na pasta 'src'
|
|
14
|
+
}
|