polgo-upload-kit 1.2.0 → 1.2.3

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 ADDED
@@ -0,0 +1,110 @@
1
+ # polgo-upload-kit
2
+
3
+ Cliente JavaScript para upload de arquivos para o servico Polgo (S3).
4
+
5
+ ## Instalacao
6
+
7
+ ```bash
8
+ npm install polgo-upload-kit
9
+ ```
10
+
11
+ ## Uso
12
+
13
+ ```javascript
14
+ import { PolgoUploadClient } from 'polgo-upload-kit';
15
+
16
+ const client = new PolgoUploadClient({
17
+ token: 'seu-token-bearer',
18
+ stack: 'nome-da-sua-stack',
19
+ isProd: true // false para ambiente dev
20
+ });
21
+ ```
22
+
23
+ ## Metodos
24
+
25
+ ### uploadFile
26
+
27
+ Faz upload de um arquivo para o bucket S3.
28
+
29
+ ```javascript
30
+ const resultado = await client.uploadFile(arquivo, 'nome-do-bucket', {
31
+ diretorio: 'caminho/no/bucket',
32
+ nomeArquivo: 'arquivo.jpg',
33
+ otimizacao: 'webp', // 'jpeg' | 'webp' | 'avif' | false
34
+ forcarConversao: false
35
+ }, (progresso) => {
36
+ console.log(`Progresso: ${progresso}%`);
37
+ });
38
+
39
+ // Retorno:
40
+ // {
41
+ // id: 'id-unico',
42
+ // endereco: 'url-do-arquivo',
43
+ // tamanhoOriginal: 1024,
44
+ // tamanhoOtimizado: 512,
45
+ // otimizado: true,
46
+ // formatoOriginal: 'image/jpeg',
47
+ // formatoOtimizado: 'image/webp',
48
+ // economiaPercentual: 50
49
+ // }
50
+ ```
51
+
52
+ ### recuperarArquivos
53
+
54
+ Recupera um arquivo do bucket.
55
+
56
+ ```javascript
57
+ const arquivo = await client.recuperarArquivos('nome-do-bucket', 'caminho/arquivo.jpg');
58
+ ```
59
+
60
+ ### listarArquivos
61
+
62
+ Lista arquivos de um diretorio no bucket.
63
+
64
+ ```javascript
65
+ const arquivos = await client.listarArquivos('nome-do-bucket', 'caminho/diretorio');
66
+ ```
67
+
68
+ ## Configuracao Avancada
69
+
70
+ Voce pode customizar a URL base, timeout e os endpoints:
71
+
72
+ ```javascript
73
+ const client = new PolgoUploadClient({
74
+ token: 'seu-token',
75
+ stack: 'sua-stack',
76
+ isProd: true,
77
+ timeout: 60000, // 60 segundos (padrao: 30000)
78
+ baseUrl: 'https://sua-api.com',
79
+ endpoints: {
80
+ upload: '/custom/upload',
81
+ recuperar: '/custom/recuperar',
82
+ listar: '/custom/listar'
83
+ }
84
+ });
85
+ ```
86
+
87
+ ## Otimizacao de Imagens
88
+
89
+ O servico otimiza imagens automaticamente. Opcoes disponiveis:
90
+
91
+ | Valor | Descricao |
92
+ |-------|-----------|
93
+ | `'webp'` | Converte para WebP (padrao) |
94
+ | `'jpeg'` | Converte para JPEG |
95
+ | `'avif'` | Converte para AVIF |
96
+ | `false` | Desabilita otimizacao |
97
+
98
+ Para forcar a conversao mesmo quando o arquivo resultante for maior:
99
+
100
+ ```javascript
101
+ await client.uploadFile(arquivo, bucket, {
102
+ otimizacao: 'avif',
103
+ forcarConversao: true
104
+ });
105
+ ```
106
+
107
+ ## Licenca
108
+
109
+ ISC
110
+
package/package.json CHANGED
@@ -1,15 +1,34 @@
1
1
  {
2
2
  "name": "polgo-upload-kit",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "type": "module",
5
5
  "main": "src/polgoUploadClient.js",
6
+ "exports": {
7
+ ".": "./src/polgoUploadClient.js"
8
+ },
9
+ "files": [
10
+ "src"
11
+ ],
6
12
  "scripts": {
7
13
  "build": "webpack"
8
14
  },
9
- "keywords": [],
10
- "author": "",
15
+ "keywords": [
16
+ "upload",
17
+ "s3",
18
+ "polgo",
19
+ "file-upload"
20
+ ],
21
+ "author": "Grupo NSC",
11
22
  "license": "ISC",
12
- "description": "",
23
+ "description": "Cliente para upload de arquivos para o servico Polgo",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/Grupo-NSC/polgo-upload-kit.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/Grupo-NSC/polgo-upload-kit/issues"
30
+ },
31
+ "homepage": "https://github.com/Grupo-NSC/polgo-upload-kit#readme",
13
32
  "dependencies": {
14
33
  "axios": "^1.7.7",
15
34
  "form-data": "^4.0.1",
@@ -1,42 +1,61 @@
1
1
  import axios from "axios";
2
2
 
3
3
  /**
4
- * Cliente para upload de arquivos para o serviço Polgo
4
+ * Cliente para upload de arquivos para o servico Polgo
5
5
  * @class PolgoUploadClient
6
6
  */
7
7
  class PolgoUploadClient {
8
8
  /**
9
9
  * Inicializa o cliente de upload
10
- * @param {Object} config - Configurações do cliente
11
- * @param {boolean} [config.isProd=false] - Define se está em ambiente de produção
12
- * @param {string} config.token - Token de autorização Bearer
13
- * @param {string} config.stack - Nome da stack/aplicação
14
- * @param {string} [config.baseUrl] - URL base personalizada para a API
15
- * @param {Object} [config.endpoints] - Endpoints personalizados
16
- * @param {string} [config.endpoints.upload] - Endpoint de upload personalizado
17
- * @param {string} [config.endpoints.recuperar] - Endpoint de recuperação personalizado
18
- * @param {string} [config.endpoints.listar] - Endpoint de listagem personalizado
19
- *
10
+ * @param {Object|boolean} configOrIsProd - Configuracoes do cliente OU isProd (retrocompatibilidade)
11
+ * @param {boolean} [configOrIsProd.isProd=false] - Define se esta em ambiente de producao
12
+ * @param {string} configOrIsProd.token - Token de autorizacao Bearer
13
+ * @param {string} configOrIsProd.stack - Nome da stack/aplicacao
14
+ * @param {string} [configOrIsProd.baseUrl] - URL base personalizada para a API
15
+ * @param {number} [configOrIsProd.timeout=30000] - Timeout das requisicoes em ms (padrao: 30s)
16
+ * @param {Object} [configOrIsProd.endpoints] - Endpoints personalizados
17
+ * @param {string} [configOrIsProd.endpoints.upload] - Endpoint de upload personalizado
18
+ * @param {string} [configOrIsProd.endpoints.recuperar] - Endpoint de recuperacao personalizado
19
+ * @param {string} [configOrIsProd.endpoints.listar] - Endpoint de listagem personalizado
20
+ * @param {string} [token] - Token de autorizacao (usado na assinatura antiga)
21
+ * @param {string} [stack] - Nome da stack (usado na assinatura antiga)
20
22
  */
21
- constructor(config = {}) {
22
- // Validação de parâmetros obrigatórios
23
+ constructor(configOrIsProd = {}, token, stack) {
24
+ let config;
25
+
26
+ // Verifica se esta usando a assinatura antiga (isProd, token, stack)
27
+ if (typeof configOrIsProd === "boolean" || (typeof configOrIsProd !== "object" || Array.isArray(configOrIsProd))) {
28
+ // Assinatura antiga: constructor(isProd, token, stack)
29
+ console.warn("Aviso: a assinatura PolgoUploadClient(isProd, token, stack) esta deprecated. Use: new PolgoUploadClient({ isProd, token, stack })");
30
+ config = {
31
+ isProd: configOrIsProd,
32
+ token: token,
33
+ stack: stack
34
+ };
35
+ } else {
36
+ // Nova assinatura: constructor(config)
37
+ config = configOrIsProd;
38
+ }
39
+
40
+ // Validacao de parametros obrigatorios
23
41
  if (!config.token) {
24
- throw new Error('Token de autorização é obrigatório');
42
+ throw new Error("Token de autorizacao e obrigatorio");
25
43
  }
26
44
  if (!config.stack) {
27
- throw new Error('Stack é obrigatória');
45
+ throw new Error("Stack e obrigatoria");
28
46
  }
29
47
 
30
- // Configurações principais
48
+ // Configuracoes principais
31
49
  this.isProd = config.isProd || false;
32
50
  this.ambiente = this.isProd ? "producao" : "dev";
33
51
  this.token = config.token;
34
52
  this.stack = config.stack;
53
+ this.timeout = config.timeout || 30000;
35
54
 
36
- // URL base configurável
55
+ // URL base configuravel
37
56
  this.baseUrl = config.baseUrl || "https://mkgplyz3tc.execute-api.us-east-1.amazonaws.com/lambdaUploadProducao";
38
57
 
39
- // Endpoints configuráveis
58
+ // Endpoints configuraveis
40
59
  this.endpoints = {
41
60
  upload: config.endpoints?.upload || "/arquivo/upload",
42
61
  recuperar: config.endpoints?.recuperar || "/arquivo/recuperar",
@@ -53,23 +72,66 @@ class PolgoUploadClient {
53
72
  }
54
73
 
55
74
  /**
56
- * Método estático para manter retrocompatibilidade com a assinatura antiga
57
- * @deprecated Use o constructor com objeto de configuração
58
- * @param {boolean} isProd - Define se está em ambiente de produção
59
- * @param {string} token - Token de autorização
60
- * @param {string} stack - Nome da stack
61
- * @returns {PolgoUploadClient} Nova instância do cliente
75
+ * Valida se o bucket foi informado
76
+ * @param {string} bucket - Nome do bucket
77
+ * @private
62
78
  */
63
- static createLegacy(isProd, token, stack) {
64
- console.warn('⚠️ PolgoUploadClient.createLegacy() está deprecated. Use o constructor com objeto de configuração.');
65
- return new PolgoUploadClient({
66
- isProd,
67
- token,
68
- stack
69
- });
79
+ _validarBucket(bucket) {
80
+ if (!bucket || typeof bucket !== "string" || bucket.trim() === "") {
81
+ throw new Error("Bucket e obrigatorio");
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Trata erros das requisicoes HTTP
87
+ * @param {Error} error - Erro capturado
88
+ * @param {string} operacao - Nome da operacao que falhou
89
+ * @private
90
+ */
91
+ _handleError(error, operacao) {
92
+ if (error.response) {
93
+ const status = error.response.status;
94
+ const data = error.response.data;
95
+
96
+ if (status === 401) {
97
+ throw new Error("Nao autorizado. Verifique seu token de acesso.");
98
+ } else if (status === 400) {
99
+ throw new Error(data?.message || "Requisicao invalida. Verifique os parametros enviados.");
100
+ } else if (status === 404) {
101
+ throw new Error(data?.message || "Recurso nao encontrado.");
102
+ } else if (status === 413) {
103
+ throw new Error("Arquivo muito grande. Tamanho maximo excedido.");
104
+ } else if (status >= 500) {
105
+ throw new Error("Erro interno do servidor. Tente novamente mais tarde.");
106
+ } else {
107
+ throw new Error(data?.message || `Falha ao ${operacao}: ${error.message}`);
108
+ }
109
+ } else if (error.code === "ECONNABORTED") {
110
+ throw new Error(`Timeout: a requisicao excedeu o tempo limite de ${this.timeout}ms.`);
111
+ } else if (error.request) {
112
+ throw new Error("Nao foi possivel conectar ao servidor. Verifique sua conexao.");
113
+ } else {
114
+ throw new Error(`Falha ao ${operacao}: ${error.message}`);
115
+ }
70
116
  }
71
117
 
118
+ /**
119
+ * Recupera um arquivo do bucket especificado
120
+ * @param {string} bucket - Nome do bucket
121
+ * @param {string} key - Chave (caminho) do arquivo no bucket
122
+ * @returns {Promise<Object>} Dados do arquivo recuperado
123
+ * @throws {Error} Se houver erro na requisicao ou arquivo nao encontrado
124
+ *
125
+ * @example
126
+ * const arquivo = await client.recuperarArquivos('meu-bucket', 'imagens/avatar.jpg');
127
+ */
72
128
  async recuperarArquivos(bucket, key) {
129
+ this._validarBucket(bucket);
130
+
131
+ if (!key || typeof key !== "string" || key.trim() === "") {
132
+ throw new Error("Key e obrigatoria");
133
+ }
134
+
73
135
  const queryParams = new URLSearchParams({
74
136
  bucket,
75
137
  key,
@@ -82,17 +144,32 @@ class PolgoUploadClient {
82
144
  headers: {
83
145
  Authorization: `Bearer ${this.token}`,
84
146
  },
147
+ timeout: this.timeout,
85
148
  });
86
149
 
87
150
  return response.data;
88
151
  } catch (error) {
89
- console.error("Erro ao recuperar arquivo:", error.message);
90
-
91
- throw new Error(`Falha ao recuperar o arquivo: ${error.message}`);
152
+ this._handleError(error, "recuperar arquivo");
92
153
  }
93
154
  }
94
155
 
156
+ /**
157
+ * Lista arquivos de um diretorio no bucket
158
+ * @param {string} bucket - Nome do bucket
159
+ * @param {string} key - Chave (caminho) do diretorio no bucket
160
+ * @returns {Promise<Array>} Lista de arquivos encontrados
161
+ * @throws {Error} Se houver erro na requisicao ou diretorio nao encontrado
162
+ *
163
+ * @example
164
+ * const arquivos = await client.listarArquivos('meu-bucket', 'imagens/perfil');
165
+ */
95
166
  async listarArquivos(bucket, key) {
167
+ this._validarBucket(bucket);
168
+
169
+ if (!key || typeof key !== "string" || key.trim() === "") {
170
+ throw new Error("Key e obrigatoria");
171
+ }
172
+
96
173
  const queryParams = new URLSearchParams({
97
174
  bucket,
98
175
  key,
@@ -105,12 +182,12 @@ class PolgoUploadClient {
105
182
  headers: {
106
183
  Authorization: `Bearer ${this.token}`,
107
184
  },
185
+ timeout: this.timeout,
108
186
  });
109
- console.log("Arquivos listados com sucesso:", response.data);
187
+
110
188
  return response.data.arquivos || [];
111
189
  } catch (error) {
112
- console.error("Erro ao listar arquivos:", error.message);
113
- throw new Error(`Falha ao listar arquivos: ${error.message}`);
190
+ this._handleError(error, "listar arquivos");
114
191
  }
115
192
  }
116
193
 
@@ -118,40 +195,64 @@ class PolgoUploadClient {
118
195
  * Faz upload de um arquivo para o bucket especificado
119
196
  * @param {File|Buffer} bufferArquivo - O arquivo a ser enviado
120
197
  * @param {string} bucket - Nome do bucket de destino
121
- * @param {Object} options - Opções do upload
122
- * @param {string} [options.diretorio] - Diretório de destino no bucket
198
+ * @param {Object} options - Opcoes do upload
199
+ * @param {string} [options.diretorio] - Diretorio de destino no bucket
123
200
  * @param {string} [options.nomeArquivo] - Nome personalizado para o arquivo
124
- * @param {Object} [options.otimizacao] - Parâmetros de otimização de imagem
125
- * @param {number} [options.otimizacao.qualidade] - Qualidade da imagem (0-100, padrão: 85)
126
- * @param {number} [options.otimizacao.largura] - Largura desejada em pixels
127
- * @param {number} [options.otimizacao.altura] - Altura desejada em pixels
128
- * @param {string} [options.otimizacao.formato] - Formato de saída (jpeg, png, webp)
129
- * @param {number} [options.otimizacao.compressao] - Nível de compressão (0-9)
130
- * @param {boolean} [options.otimizacao.manterProporcao] - Manter proporção ao redimensionar (padrão: true)
131
- * @param {Function} [onProgress] - Callback para acompanhar progresso do upload
132
- * @returns {Promise<Object>} Dados de resposta do upload
133
- *
201
+ * @param {false|"jpeg"|"webp"|"avif"|Object} [options.otimizacao] - Otimizacao conforme a lambda espera:
202
+ * - false: desabilita otimizacao
203
+ * - "jpeg" | "webp" | "avif": formato desejado (padrao: "webp")
204
+ * - { formato }: compatibilidade com versoes antigas (aceita "none" para desabilitar)
205
+ * @param {boolean} [options.forcarConversao=false] - Forca conversao mesmo se o arquivo resultante for maior que o original
206
+ * @param {Function} [onProgress] - Callback para acompanhar progresso do upload (recebe percentual 0-100)
207
+ * @returns {Promise<Object>} Dados de resposta do upload contendo:
208
+ * - {string} id - ID unico do arquivo
209
+ * - {string} endereco - URL do arquivo no bucket
210
+ * - {number} tamanhoOriginal - Tamanho original do arquivo em bytes
211
+ * - {number} tamanhoOtimizado - Tamanho do arquivo apos otimizacao em bytes
212
+ * - {boolean} otimizado - Indica se o arquivo foi otimizado
213
+ * - {string} formatoOriginal - Formato MIME original do arquivo
214
+ * - {string} formatoOtimizado - Formato MIME apos otimizacao
215
+ * - {number} economiaPercentual - Percentual de economia de espaco (pode ser negativo se forcar conversao)
216
+ *
134
217
  * @example
135
218
  * // Upload simples
136
219
  * await client.uploadFile(file, 'meu-bucket');
137
- *
220
+ *
138
221
  * @example
139
- * // Upload com otimização de imagem
222
+ * // Upload com otimizacao de imagem
140
223
  * await client.uploadFile(file, 'meu-bucket', {
141
224
  * diretorio: 'imagens/perfil',
142
225
  * nomeArquivo: 'avatar.jpg',
143
- * otimizacao: {
144
- * qualidade: 80,
145
- * largura: 800,
146
- * altura: 600,
147
- * formato: 'webp',
148
- * manterProporcao: true
149
- * }
226
+ * otimizacao: 'webp'
150
227
  * }, (progress) => console.log(`Progress: ${progress}%`));
228
+ *
229
+ * @example
230
+ * // Upload com conversao forcada (mantem formato mesmo se maior)
231
+ * await client.uploadFile(file, 'meu-bucket', {
232
+ * otimizacao: 'avif',
233
+ * forcarConversao: true
234
+ * });
235
+ *
236
+ * @example
237
+ * // Upload sem otimizacao
238
+ * await client.uploadFile(file, 'meu-bucket', {
239
+ * otimizacao: false
240
+ * });
241
+ *
242
+ * @example
243
+ * // Upload com compatibilidade de formato antigo
244
+ * await client.uploadFile(file, 'meu-bucket', {
245
+ * otimizacao: { formato: 'webp' }
246
+ * });
151
247
  */
152
248
  async uploadFile(bufferArquivo, bucket, options = {}, onProgress) {
153
- const mimeType = bufferArquivo.type;
249
+ this._validarBucket(bucket);
154
250
 
251
+ if (!bufferArquivo) {
252
+ throw new Error("Arquivo e obrigatorio");
253
+ }
254
+
255
+ const mimeType = bufferArquivo.type;
155
256
  const fileBlob = new Blob([bufferArquivo], { type: mimeType });
156
257
 
157
258
  const queryParams = new URLSearchParams({
@@ -161,22 +262,33 @@ class PolgoUploadClient {
161
262
 
162
263
  if (options.diretorio) queryParams.append("diretorio", options.diretorio);
163
264
  if (options.nomeArquivo) queryParams.append("nomeArquivo", options.nomeArquivo);
265
+ if (options.forcarConversao === true || options.forcarConversao === "true" || options.forcarConversao === 1 || options.forcarConversao === "1") {
266
+ queryParams.append("forcarConversao", "true");
267
+ }
164
268
 
165
- // Parâmetro de otimização simplificado conforme esperado pela lambda
166
- if (options.otimizacao) {
167
- const { formato } = options.otimizacao;
168
- if (formato === 'avif') {
169
- queryParams.append("otimizacao", "avif");
170
- } else if (formato === 'webp') {
171
- queryParams.append("otimizacao", "webp");
172
- } else if (formato === 'none' || formato === false) {
173
- queryParams.append("otimizacao", "false");
174
- } else {
175
- queryParams.append("otimizacao", "webp"); // padrão
269
+ // Parametro de otimizacao conforme a lambda espera (false|0|jpeg|webp|avif; padrao: webp)
270
+ const normalizarOtimizacao = (otimizacao) => {
271
+ if (otimizacao === undefined || otimizacao === null) return "webp";
272
+ if (otimizacao === false || otimizacao === 0 || otimizacao === "0") return "false";
273
+
274
+ // Compatibilidade com a forma antiga: { formato: 'webp' }
275
+ if (typeof otimizacao === "object") {
276
+ const formato = otimizacao?.formato;
277
+ if (formato === undefined || formato === null) return "webp";
278
+ if (formato === false || formato === "false" || formato === "0" || formato === "none") return "false";
279
+ if (formato === "jpg") return "jpeg";
280
+ if (formato === "jpeg" || formato === "webp" || formato === "avif") return formato;
281
+ return "webp";
176
282
  }
177
- } else {
178
- queryParams.append("otimizacao", "webp"); // padrão quando não especificado
179
- }
283
+
284
+ if (otimizacao === "false") return "false";
285
+ if (otimizacao === "none") return "false";
286
+ if (otimizacao === "jpg") return "jpeg";
287
+ if (otimizacao === "jpeg" || otimizacao === "webp" || otimizacao === "avif") return otimizacao;
288
+ return "webp";
289
+ };
290
+
291
+ queryParams.append("otimizacao", normalizarOtimizacao(options.otimizacao));
180
292
 
181
293
  const finalUrl = `${this.urls.upload}?${queryParams.toString()}`;
182
294
  const form = new FormData();
@@ -188,11 +300,10 @@ class PolgoUploadClient {
188
300
  headers: {
189
301
  Authorization: `Bearer ${this.token}`,
190
302
  },
303
+ timeout: this.timeout,
191
304
  onUploadProgress: (progressEvent) => {
192
- const percentCompleted = Math.round(
193
- (progressEvent.loaded * 100) / progressEvent.total
194
- );
195
- if (typeof onProgress === "function") {
305
+ if (typeof onProgress === "function" && progressEvent.total) {
306
+ const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
196
307
  onProgress(percentCompleted);
197
308
  }
198
309
  },
@@ -200,12 +311,9 @@ class PolgoUploadClient {
200
311
 
201
312
  return response.data;
202
313
  } catch (error) {
203
- console.error("Erro ao fazer upload do arquivo:", error.message);
204
- throw new Error(
205
- `Falha ao realizar o upload do arquivo: ${error.message}`
206
- );
314
+ this._handleError(error, "fazer upload");
207
315
  }
208
316
  }
209
317
  }
210
318
 
211
- export { PolgoUploadClient };
319
+ export { PolgoUploadClient };