@allanfsouza/aether-sdk 2.0.0 → 2.2.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 +55 -21
- package/dist/auth.js +87 -29
- package/dist/database.d.ts +95 -3
- package/dist/database.js +123 -1
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +42 -0
- package/dist/functions.d.ts +0 -6
- package/dist/functions.js +0 -8
- package/dist/http-client.d.ts +3 -5
- package/dist/http-client.js +11 -7
- package/dist/index.d.ts +14 -8
- package/dist/index.js +13 -10
- package/dist/push.d.ts +72 -0
- package/dist/push.js +53 -0
- package/errors.ts +46 -0
- package/package.json +10 -8
- package/src/auth.ts +125 -33
- package/src/database.ts +160 -7
- package/src/errors.ts +50 -0
- package/src/functions.ts +1 -11
- package/src/http-client.ts +17 -9
- package/src/index.ts +39 -16
- package/src/push.ts +157 -0
- package/tsconfig.json +16 -9
package/src/database.ts
CHANGED
|
@@ -12,15 +12,130 @@ type WebSocketMessage<T = any> = {
|
|
|
12
12
|
|
|
13
13
|
// [NOVO] Opções de Listagem Avançada
|
|
14
14
|
export type ListOptions<T> = {
|
|
15
|
-
|
|
16
|
-
filter?: Partial<T>;
|
|
17
|
-
// Ordenação
|
|
15
|
+
filter?: Partial<T> | Record<string, any>; // Suporta operadores avançados
|
|
18
16
|
sort?: {
|
|
19
|
-
field: keyof T & string;
|
|
17
|
+
field: keyof T & string;
|
|
20
18
|
order: "ASC" | "DESC";
|
|
21
19
|
};
|
|
20
|
+
limit?: number;
|
|
21
|
+
offset?: number;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Builder para construção fluente de queries.
|
|
26
|
+
*/
|
|
27
|
+
export class QueryBuilder<T> {
|
|
28
|
+
private collectionRef: CollectionReference<T>;
|
|
29
|
+
private filter: Record<string, any> = {};
|
|
30
|
+
private sort?: { field: string; order: "ASC" | "DESC" };
|
|
31
|
+
private limitVal?: number;
|
|
32
|
+
private offsetVal?: number;
|
|
33
|
+
|
|
34
|
+
constructor(collectionRef: CollectionReference<T>) {
|
|
35
|
+
this.collectionRef = collectionRef;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Adiciona um filtro de igualdade.
|
|
40
|
+
*/
|
|
41
|
+
eq(column: keyof T & string, value: any): this {
|
|
42
|
+
this.filter[column] = value;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Adiciona um filtro de desigualdade ($ne).
|
|
48
|
+
*/
|
|
49
|
+
neq(column: keyof T & string, value: any): this {
|
|
50
|
+
this.filter[column] = { ...this.filter[column], $ne: value };
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Adiciona um filtro maior que ($gt).
|
|
56
|
+
*/
|
|
57
|
+
gt(column: keyof T & string, value: number | string): this {
|
|
58
|
+
this.filter[column] = { ...this.filter[column], $gt: value };
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Adiciona um filtro maior ou igual ($gte).
|
|
64
|
+
*/
|
|
65
|
+
gte(column: keyof T & string, value: number | string): this {
|
|
66
|
+
this.filter[column] = { ...this.filter[column], $gte: value };
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Adiciona um filtro menor que ($lt).
|
|
72
|
+
*/
|
|
73
|
+
lt(column: keyof T & string, value: number | string): this {
|
|
74
|
+
this.filter[column] = { ...this.filter[column], $lt: value };
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Adiciona um filtro menor ou igual ($lte).
|
|
80
|
+
*/
|
|
81
|
+
lte(column: keyof T & string, value: number | string): this {
|
|
82
|
+
this.filter[column] = { ...this.filter[column], $lte: value };
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Adiciona um filtro LIKE ($like).
|
|
88
|
+
*/
|
|
89
|
+
like(column: keyof T & string, value: string): this {
|
|
90
|
+
this.filter[column] = { ...this.filter[column], $like: value };
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Define a ordenação.
|
|
96
|
+
*/
|
|
97
|
+
order(column: keyof T & string, direction: "ASC" | "DESC" = "ASC"): this {
|
|
98
|
+
this.sort = { field: column, order: direction };
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Define o limite de registros.
|
|
104
|
+
*/
|
|
105
|
+
limit(count: number): this {
|
|
106
|
+
this.limitVal = count;
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Define o deslocamento (paginação).
|
|
112
|
+
*/
|
|
113
|
+
offset(count: number): this {
|
|
114
|
+
this.offsetVal = count;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Executa a query e retorna os resultados.
|
|
120
|
+
*/
|
|
121
|
+
async get(): Promise<T[]> {
|
|
122
|
+
return this.collectionRef.list({
|
|
123
|
+
filter: this.filter,
|
|
124
|
+
sort: this.sort as any,
|
|
125
|
+
limit: this.limitVal,
|
|
126
|
+
offset: this.offsetVal,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Operação em lote.
|
|
133
|
+
*/
|
|
134
|
+
export type BatchOperation =
|
|
135
|
+
| { type: "create"; collection: string; data: any }
|
|
136
|
+
| { type: "update"; collection: string; id: string; data: any }
|
|
137
|
+
| { type: "delete"; collection: string; id: string };
|
|
138
|
+
|
|
24
139
|
/**
|
|
25
140
|
* Módulo de Banco de Dados
|
|
26
141
|
*/
|
|
@@ -41,13 +156,22 @@ export class DatabaseModule {
|
|
|
41
156
|
collection<T = any>(collectionName: string) {
|
|
42
157
|
return new CollectionReference<T>(this.client, this.http, collectionName);
|
|
43
158
|
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Executa múltiplas operações em uma única transação.
|
|
162
|
+
* Se uma falhar, todas são revertidas.
|
|
163
|
+
*/
|
|
164
|
+
async batch(operations: BatchOperation[]): Promise<any[]> {
|
|
165
|
+
const { data } = await this.http.post("/db/batch", { operations });
|
|
166
|
+
return data.results;
|
|
167
|
+
}
|
|
44
168
|
}
|
|
45
169
|
|
|
46
170
|
/**
|
|
47
171
|
* Referência a uma coleção específica.
|
|
48
172
|
* O <T> define o formato dos dados (ex: interface User).
|
|
49
173
|
*/
|
|
50
|
-
class CollectionReference<T> {
|
|
174
|
+
export class CollectionReference<T> {
|
|
51
175
|
private client: PlataformaClient;
|
|
52
176
|
private http: AxiosInstance;
|
|
53
177
|
private collectionName: string;
|
|
@@ -62,6 +186,31 @@ class CollectionReference<T> {
|
|
|
62
186
|
this.wsUrl = client.apiUrl.replace(/^https?/, protocol);
|
|
63
187
|
}
|
|
64
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Inicia o QueryBuilder.
|
|
191
|
+
* Atalho para .eq()
|
|
192
|
+
*/
|
|
193
|
+
eq(column: keyof T & string, value: any): QueryBuilder<T> {
|
|
194
|
+
return new QueryBuilder<T>(this).eq(column, value);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Inicia o QueryBuilder.
|
|
199
|
+
* Atalho para .gt()
|
|
200
|
+
*/
|
|
201
|
+
gt(column: keyof T & string, value: number | string): QueryBuilder<T> {
|
|
202
|
+
return new QueryBuilder<T>(this).gt(column, value);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ... Outros atalhos podem ser adicionados conforme necessidade ...
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Retorna uma nova instância do QueryBuilder.
|
|
209
|
+
*/
|
|
210
|
+
query(): QueryBuilder<T> {
|
|
211
|
+
return new QueryBuilder<T>(this);
|
|
212
|
+
}
|
|
213
|
+
|
|
65
214
|
/**
|
|
66
215
|
* Lista documentos da coleção com filtros opcionais.
|
|
67
216
|
* @param options Filtros e Ordenação
|
|
@@ -79,6 +228,10 @@ class CollectionReference<T> {
|
|
|
79
228
|
params.sort = JSON.stringify([options.sort.field, options.sort.order]);
|
|
80
229
|
}
|
|
81
230
|
|
|
231
|
+
// TODO: Backend precisa implementar limit/offset na rota GET
|
|
232
|
+
// if (options?.limit) params.limit = options.limit;
|
|
233
|
+
// if (options?.offset) params.offset = options.offset;
|
|
234
|
+
|
|
82
235
|
const { data } = await this.http.get(`/db/${this.collectionName}`, {
|
|
83
236
|
params,
|
|
84
237
|
});
|
|
@@ -136,7 +289,7 @@ class CollectionReference<T> {
|
|
|
136
289
|
|
|
137
290
|
if (!token || !projectId) {
|
|
138
291
|
console.warn("[SDK] Realtime falhou: Token ou ProjectId ausentes.");
|
|
139
|
-
return () => {};
|
|
292
|
+
return () => { };
|
|
140
293
|
}
|
|
141
294
|
|
|
142
295
|
const url = `${this.wsUrl}/v1/db/subscribe/${this.collectionName}?token=${token}&projectId=${projectId}`;
|
|
@@ -173,7 +326,7 @@ class CollectionReference<T> {
|
|
|
173
326
|
};
|
|
174
327
|
} catch (err) {
|
|
175
328
|
console.error("[SDK] Erro WS:", err);
|
|
176
|
-
return () => {};
|
|
329
|
+
return () => { };
|
|
177
330
|
}
|
|
178
331
|
}
|
|
179
332
|
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
export class AetherError extends Error {
|
|
3
|
+
constructor(
|
|
4
|
+
public code: string,
|
|
5
|
+
public message: string,
|
|
6
|
+
public status?: number,
|
|
7
|
+
public details?: any
|
|
8
|
+
) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "AetherError";
|
|
11
|
+
// Garante que instanceof AetherError funcione mesmo em cenários com transpile/bundler
|
|
12
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Converte qualquer erro vindo do Axios em um AetherError padronizado.
|
|
18
|
+
* Essa função é pensada para ser usada no interceptor de responses.
|
|
19
|
+
*/
|
|
20
|
+
export function handleAxiosError(error: any): never {
|
|
21
|
+
// Erro com resposta do servidor (4xx, 5xx)
|
|
22
|
+
if (error && error.response) {
|
|
23
|
+
const data = error.response.data;
|
|
24
|
+
const message =
|
|
25
|
+
data?.error || data?.message || "Erro desconhecido na API";
|
|
26
|
+
const status: number = error.response.status;
|
|
27
|
+
|
|
28
|
+
let code = "api_error";
|
|
29
|
+
if (status === 401) code = "unauthorized";
|
|
30
|
+
if (status === 403) code = "permission_denied";
|
|
31
|
+
if (status === 404) code = "not_found";
|
|
32
|
+
if (status === 429) code = "rate_limit_exceeded";
|
|
33
|
+
|
|
34
|
+
throw new AetherError(code, message, status, data);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Erro de rede (sem resposta do servidor)
|
|
38
|
+
if (error && error.request && !error.response) {
|
|
39
|
+
throw new AetherError(
|
|
40
|
+
"network_error",
|
|
41
|
+
"Não foi possível conectar ao servidor Aether.",
|
|
42
|
+
0
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Erro de configuração / código do cliente
|
|
47
|
+
const fallbackMessage =
|
|
48
|
+
(error && error.message) || "Erro interno no cliente SDK.";
|
|
49
|
+
throw new AetherError("client_error", fallbackMessage);
|
|
50
|
+
}
|
package/src/functions.ts
CHANGED
|
@@ -11,23 +11,13 @@ export class FunctionsModule {
|
|
|
11
11
|
this.http = http;
|
|
12
12
|
}
|
|
13
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
14
|
async invoke<T = any>(
|
|
21
15
|
functionName: string,
|
|
22
16
|
body?: any,
|
|
23
17
|
method?: "GET" | "POST" | "PUT" | "DELETE"
|
|
24
18
|
) {
|
|
25
19
|
const projectId = this.client.projectId;
|
|
26
|
-
|
|
27
|
-
// Remove barras iniciais para evitar URL malformada
|
|
28
20
|
const cleanName = functionName.replace(/^\//, "");
|
|
29
|
-
|
|
30
|
-
// Define método automaticamente se não informado
|
|
31
21
|
const finalMethod = method || (body ? "POST" : "GET");
|
|
32
22
|
|
|
33
23
|
const response = await this.http.request<T>({
|
|
@@ -38,4 +28,4 @@ export class FunctionsModule {
|
|
|
38
28
|
|
|
39
29
|
return response.data;
|
|
40
30
|
}
|
|
41
|
-
}
|
|
31
|
+
}
|
package/src/http-client.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
// src/http-client.ts
|
|
2
2
|
import axios, { type AxiosInstance } from "axios";
|
|
3
|
-
import { PlataformaClient } from "./index.js";
|
|
3
|
+
import type { PlataformaClient } from "./index.js";
|
|
4
|
+
import { handleAxiosError } from "./errors.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Cria uma instância do Axios pré-configurada.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* * @param client A instância principal do PlataformaClient
|
|
10
|
-
* @returns Uma instância configurada do Axios
|
|
8
|
+
* - Injeta automaticamente headers de Auth e Projeto.
|
|
9
|
+
* - Converte erros em AetherError.
|
|
11
10
|
*/
|
|
12
11
|
export function createHttpClient(client: PlataformaClient): AxiosInstance {
|
|
13
12
|
const http = axios.create({
|
|
14
|
-
|
|
13
|
+
// Adiciona o /v1 automaticamente em todas as chamadas do SDK
|
|
14
|
+
baseURL: `${client.apiUrl}/v1`,
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
},
|
|
15
18
|
});
|
|
16
19
|
|
|
20
|
+
// Interceptor de REQUEST
|
|
17
21
|
http.interceptors.request.use((config) => {
|
|
18
|
-
// 1. Pega o token atual do cliente
|
|
19
22
|
const token = client.getToken();
|
|
20
23
|
if (token) {
|
|
21
24
|
config.headers.Authorization = `Bearer ${token}`;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
// 2. Pega o ID do projeto
|
|
25
27
|
if (client.projectId) {
|
|
26
28
|
config.headers["X-Project-ID"] = client.projectId;
|
|
27
29
|
}
|
|
@@ -29,5 +31,11 @@ export function createHttpClient(client: PlataformaClient): AxiosInstance {
|
|
|
29
31
|
return config;
|
|
30
32
|
});
|
|
31
33
|
|
|
34
|
+
// Interceptor de RESPONSE
|
|
35
|
+
http.interceptors.response.use(
|
|
36
|
+
(response) => response,
|
|
37
|
+
(error) => handleAxiosError(error)
|
|
38
|
+
);
|
|
39
|
+
|
|
32
40
|
return http;
|
|
33
|
-
}
|
|
41
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,55 +4,62 @@ 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";
|
|
7
|
+
import { FunctionsModule } from "./functions.js";
|
|
8
|
+
import { PushModule } from "./push.js";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Configuração usada para criar o cliente principal da plataforma.
|
|
12
|
+
*/
|
|
13
|
+
export type ClientConfig = {
|
|
10
14
|
apiUrl: string;
|
|
11
15
|
projectId: string;
|
|
12
16
|
};
|
|
13
17
|
|
|
14
18
|
/**
|
|
15
|
-
* O cliente principal da Plataforma API.
|
|
16
|
-
* Ponto de entrada para todos os módulos (Auth, DB, Storage, Functions).
|
|
19
|
+
* O cliente principal da Plataforma API (Aether).
|
|
20
|
+
* Ponto de entrada para todos os módulos (Auth, DB, Storage, Functions, Push).
|
|
17
21
|
*/
|
|
18
22
|
export class PlataformaClient {
|
|
19
|
-
//
|
|
23
|
+
// Módulos públicos disponíveis para o usuário do SDK
|
|
20
24
|
public auth: AuthModule;
|
|
21
25
|
public db: DatabaseModule;
|
|
22
26
|
public storage: StorageModule;
|
|
23
|
-
public functions: FunctionsModule;
|
|
27
|
+
public functions: FunctionsModule;
|
|
28
|
+
public push: PushModule;
|
|
24
29
|
|
|
25
|
-
//
|
|
30
|
+
// Configurações imutáveis da instância
|
|
26
31
|
public apiUrl: string;
|
|
27
32
|
public projectId: string;
|
|
28
33
|
|
|
29
|
-
//
|
|
30
|
-
|
|
34
|
+
// Infra interna
|
|
35
|
+
public http: AxiosInstance;
|
|
31
36
|
private _token: string | null = null;
|
|
32
37
|
|
|
33
38
|
constructor(config: ClientConfig) {
|
|
34
39
|
if (!config.apiUrl || !config.projectId) {
|
|
35
40
|
throw new Error("apiUrl e projectId são obrigatórios.");
|
|
36
41
|
}
|
|
37
|
-
|
|
42
|
+
|
|
43
|
+
// Normaliza apiUrl removendo barras finais, se houver
|
|
44
|
+
this.apiUrl = config.apiUrl.replace(/\/+$/, "");
|
|
38
45
|
this.projectId = config.projectId;
|
|
39
46
|
|
|
40
|
-
// Inicializa o cliente HTTP (passando
|
|
47
|
+
// Inicializa o cliente HTTP (passando a própria instância)
|
|
41
48
|
this.http = createHttpClient(this);
|
|
42
49
|
|
|
43
|
-
// Inicializa os módulos
|
|
50
|
+
// Inicializa os módulos de alto nível
|
|
44
51
|
this.auth = new AuthModule(this, this.http);
|
|
45
52
|
this.db = new DatabaseModule(this, this.http);
|
|
46
53
|
this.storage = new StorageModule(this, this.http);
|
|
47
|
-
this.functions = new FunctionsModule(this, this.http);
|
|
54
|
+
this.functions = new FunctionsModule(this, this.http);
|
|
55
|
+
this.push = new PushModule(this, this.http);
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
// --- Gerenciamento de Token ---
|
|
51
59
|
|
|
52
60
|
/**
|
|
53
61
|
* Armazena o token de autenticação em memória.
|
|
54
|
-
* Chamado automaticamente pelo AuthModule após login.
|
|
55
|
-
* @param token O JWT (ou null para logout)
|
|
62
|
+
* Chamado automaticamente pelo AuthModule após login/registro.
|
|
56
63
|
*/
|
|
57
64
|
setToken(token: string | null) {
|
|
58
65
|
this._token = token;
|
|
@@ -61,9 +68,25 @@ export class PlataformaClient {
|
|
|
61
68
|
/**
|
|
62
69
|
* Recupera o token de autenticação atual.
|
|
63
70
|
* Usado pelo http-client para injetar o header Authorization.
|
|
64
|
-
* @returns O JWT ou null
|
|
65
71
|
*/
|
|
66
72
|
getToken(): string | null {
|
|
67
73
|
return this._token;
|
|
68
74
|
}
|
|
69
75
|
}
|
|
76
|
+
|
|
77
|
+
// Re-exports convenientes para quem consome o SDK
|
|
78
|
+
export { AetherError } from "./errors.js";
|
|
79
|
+
export type { ListOptions } from "./database.js";
|
|
80
|
+
|
|
81
|
+
// Tipos relacionados a Push
|
|
82
|
+
export type {
|
|
83
|
+
PushPlatform,
|
|
84
|
+
PushEnvironment,
|
|
85
|
+
PushDevice,
|
|
86
|
+
RegisterDeviceParams,
|
|
87
|
+
SendPushResponse,
|
|
88
|
+
PushStatus,
|
|
89
|
+
PushLogEntry,
|
|
90
|
+
ListPushLogsOptions,
|
|
91
|
+
PushStats,
|
|
92
|
+
} from "./push.js";
|
package/src/push.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// src/push.ts
|
|
2
|
+
import type { AxiosInstance } from "axios";
|
|
3
|
+
import type { PlataformaClient } from "./index.js";
|
|
4
|
+
|
|
5
|
+
export type PushPlatform = "android" | "ios" | "web";
|
|
6
|
+
export type PushEnvironment = "dev" | "staging" | "prod";
|
|
7
|
+
|
|
8
|
+
export interface RegisterDeviceParams {
|
|
9
|
+
platform: PushPlatform;
|
|
10
|
+
token: string;
|
|
11
|
+
environment?: PushEnvironment;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface PushDevice {
|
|
15
|
+
id: string;
|
|
16
|
+
projectId: string;
|
|
17
|
+
userId?: string | null;
|
|
18
|
+
platform: PushPlatform;
|
|
19
|
+
token: string;
|
|
20
|
+
environment: PushEnvironment;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
lastSeenAt: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RegisterDeviceResponse {
|
|
26
|
+
device: PushDevice;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SendPushResponse {
|
|
30
|
+
sent: number;
|
|
31
|
+
total: number;
|
|
32
|
+
message: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type PushStatus = "sent" | "failed";
|
|
36
|
+
|
|
37
|
+
export interface PushLogEntry {
|
|
38
|
+
id: string;
|
|
39
|
+
projectId: string;
|
|
40
|
+
userId?: string | null;
|
|
41
|
+
deviceId?: string | null;
|
|
42
|
+
title: string;
|
|
43
|
+
body: string;
|
|
44
|
+
data: Record<string, string>;
|
|
45
|
+
status: PushStatus;
|
|
46
|
+
errorMessage?: string | null;
|
|
47
|
+
createdAt: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ListPushLogsOptions {
|
|
51
|
+
limit?: number;
|
|
52
|
+
offset?: number;
|
|
53
|
+
status?: PushStatus;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface PushStats {
|
|
57
|
+
totalDevices: number;
|
|
58
|
+
sent24h: number;
|
|
59
|
+
successRate: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class PushModule {
|
|
63
|
+
constructor(
|
|
64
|
+
private client: PlataformaClient,
|
|
65
|
+
private http: AxiosInstance
|
|
66
|
+
) { }
|
|
67
|
+
|
|
68
|
+
async registerDevice(params: RegisterDeviceParams): Promise<PushDevice> {
|
|
69
|
+
const projectId = this.client.projectId;
|
|
70
|
+
|
|
71
|
+
const { data } = await this.http.post<RegisterDeviceResponse>(
|
|
72
|
+
`/projects/${projectId}/push/devices`,
|
|
73
|
+
{
|
|
74
|
+
platform: params.platform,
|
|
75
|
+
token: params.token,
|
|
76
|
+
environment: params.environment ?? "prod",
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return data.device;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async sendToToken(params: {
|
|
84
|
+
token: string;
|
|
85
|
+
title: string;
|
|
86
|
+
body: string;
|
|
87
|
+
data?: Record<string, string>;
|
|
88
|
+
environment?: PushEnvironment;
|
|
89
|
+
}): Promise<SendPushResponse> {
|
|
90
|
+
const projectId = this.client.projectId;
|
|
91
|
+
|
|
92
|
+
const { data } = await this.http.post<SendPushResponse>(
|
|
93
|
+
`/projects/${projectId}/push/send`,
|
|
94
|
+
{
|
|
95
|
+
token: params.token,
|
|
96
|
+
title: params.title,
|
|
97
|
+
body: params.body,
|
|
98
|
+
data: params.data ?? {},
|
|
99
|
+
environment: params.environment ?? "prod",
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return data;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async sendToUser(params: {
|
|
107
|
+
userId: string;
|
|
108
|
+
title: string;
|
|
109
|
+
body: string;
|
|
110
|
+
data?: Record<string, string>;
|
|
111
|
+
environment?: PushEnvironment;
|
|
112
|
+
}): Promise<SendPushResponse> {
|
|
113
|
+
const projectId = this.client.projectId;
|
|
114
|
+
|
|
115
|
+
const { data } = await this.http.post<SendPushResponse>(
|
|
116
|
+
`/projects/${projectId}/push/send`,
|
|
117
|
+
{
|
|
118
|
+
userId: params.userId,
|
|
119
|
+
title: params.title,
|
|
120
|
+
body: params.body,
|
|
121
|
+
data: params.data ?? {},
|
|
122
|
+
environment: params.environment ?? "prod",
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async listLogs(
|
|
130
|
+
options: ListPushLogsOptions = {}
|
|
131
|
+
): Promise<PushLogEntry[]> {
|
|
132
|
+
const projectId = this.client.projectId;
|
|
133
|
+
|
|
134
|
+
const { data } = await this.http.get<{ data: PushLogEntry[] }>(
|
|
135
|
+
`/projects/${projectId}/push/logs`,
|
|
136
|
+
{
|
|
137
|
+
params: {
|
|
138
|
+
limit: options.limit,
|
|
139
|
+
offset: options.offset,
|
|
140
|
+
status: options.status,
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
return data.data;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async getStats(): Promise<PushStats> {
|
|
149
|
+
const projectId = this.client.projectId;
|
|
150
|
+
|
|
151
|
+
const { data } = await this.http.get<PushStats>(
|
|
152
|
+
`/projects/${projectId}/push/stats`
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return data;
|
|
156
|
+
}
|
|
157
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
9
10
|
"skipLibCheck": true,
|
|
10
11
|
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
|
|
12
|
+
// Adicionado DOM para reconhecer 'File', 'Blob' e 'WebSocket' nativos
|
|
13
|
+
"lib": [
|
|
14
|
+
"ES2020",
|
|
15
|
+
"DOM"
|
|
16
|
+
]
|
|
12
17
|
},
|
|
13
|
-
"include": [
|
|
14
|
-
|
|
18
|
+
"include": [
|
|
19
|
+
"src"
|
|
20
|
+
]
|
|
21
|
+
}
|