polgo-upload-kit 1.2.1 → 1.2.4

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,36 @@
1
1
  {
2
2
  "name": "polgo-upload-kit",
3
- "version": "1.2.1",
3
+ "version": "1.2.4",
4
4
  "type": "module",
5
5
  "main": "src/polgoUploadClient.js",
6
+ "exports": {
7
+ ".": "./src/polgoUploadClient.js",
8
+ "./src/polgoUploadClient": "./src/polgoUploadClient.js",
9
+ "./src/polgoUploadClient.js": "./src/polgoUploadClient.js"
10
+ },
11
+ "files": [
12
+ "src"
13
+ ],
6
14
  "scripts": {
7
15
  "build": "webpack"
8
16
  },
9
- "keywords": [],
10
- "author": "",
17
+ "keywords": [
18
+ "upload",
19
+ "s3",
20
+ "polgo",
21
+ "file-upload"
22
+ ],
23
+ "author": "Grupo NSC",
11
24
  "license": "ISC",
12
- "description": "",
25
+ "description": "Cliente para upload de arquivos para o servico Polgo",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/Grupo-NSC/polgo-upload-kit.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/Grupo-NSC/polgo-upload-kit/issues"
32
+ },
33
+ "homepage": "https://github.com/Grupo-NSC/polgo-upload-kit#readme",
13
34
  "dependencies": {
14
35
  "axios": "^1.7.7",
15
36
  "form-data": "^4.0.1",
@@ -1,32 +1,32 @@
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|boolean} configOrIsProd - Configurações do cliente OU isProd (retrocompatibilidade)
11
- * @param {boolean} [configOrIsProd.isProd=false] - Define se está em ambiente de produção
12
- * @param {string} configOrIsProd.token - Token de autorização Bearer
13
- * @param {string} configOrIsProd.stack - Nome da stack/aplicação
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
14
  * @param {string} [configOrIsProd.baseUrl] - URL base personalizada para a API
15
+ * @param {number} [configOrIsProd.timeout=30000] - Timeout das requisicoes em ms (padrao: 30s)
15
16
  * @param {Object} [configOrIsProd.endpoints] - Endpoints personalizados
16
17
  * @param {string} [configOrIsProd.endpoints.upload] - Endpoint de upload personalizado
17
- * @param {string} [configOrIsProd.endpoints.recuperar] - Endpoint de recuperação personalizado
18
+ * @param {string} [configOrIsProd.endpoints.recuperar] - Endpoint de recuperacao personalizado
18
19
  * @param {string} [configOrIsProd.endpoints.listar] - Endpoint de listagem personalizado
19
- * @param {string} [token] - Token de autorização (usado na assinatura antiga)
20
+ * @param {string} [token] - Token de autorizacao (usado na assinatura antiga)
20
21
  * @param {string} [stack] - Nome da stack (usado na assinatura antiga)
21
- *
22
22
  */
23
23
  constructor(configOrIsProd = {}, token, stack) {
24
24
  let config;
25
-
26
- // Verifica se está usando a assinatura antiga (isProd, token, stack)
27
- if (typeof configOrIsProd === 'boolean' || (typeof configOrIsProd !== 'object' || Array.isArray(configOrIsProd))) {
25
+
26
+ // Verifica se esta usando a assinatura antiga (isProd, token, stack)
27
+ if (typeof configOrIsProd === "boolean" || (typeof configOrIsProd !== "object" || Array.isArray(configOrIsProd))) {
28
28
  // Assinatura antiga: constructor(isProd, token, stack)
29
- console.warn('⚠️ A assinatura PolgoUploadClient(isProd, token, stack) está deprecated. Use: new PolgoUploadClient({ isProd, token, stack })');
29
+ console.warn("Aviso: a assinatura PolgoUploadClient(isProd, token, stack) esta deprecated. Use: new PolgoUploadClient({ isProd, token, stack })");
30
30
  config = {
31
31
  isProd: configOrIsProd,
32
32
  token: token,
@@ -37,24 +37,25 @@ class PolgoUploadClient {
37
37
  config = configOrIsProd;
38
38
  }
39
39
 
40
- // Validação de parâmetros obrigatórios
40
+ // Validacao de parametros obrigatorios
41
41
  if (!config.token) {
42
- throw new Error('Token de autorização é obrigatório');
42
+ throw new Error("Token de autorizacao e obrigatorio");
43
43
  }
44
44
  if (!config.stack) {
45
- throw new Error('Stack é obrigatória');
45
+ throw new Error("Stack e obrigatoria");
46
46
  }
47
47
 
48
- // Configurações principais
48
+ // Configuracoes principais
49
49
  this.isProd = config.isProd || false;
50
50
  this.ambiente = this.isProd ? "producao" : "dev";
51
51
  this.token = config.token;
52
52
  this.stack = config.stack;
53
+ this.timeout = config.timeout || 30000;
53
54
 
54
- // URL base configurável
55
+ // URL base configuravel
55
56
  this.baseUrl = config.baseUrl || "https://mkgplyz3tc.execute-api.us-east-1.amazonaws.com/lambdaUploadProducao";
56
57
 
57
- // Endpoints configuráveis
58
+ // Endpoints configuraveis
58
59
  this.endpoints = {
59
60
  upload: config.endpoints?.upload || "/arquivo/upload",
60
61
  recuperar: config.endpoints?.recuperar || "/arquivo/recuperar",
@@ -70,7 +71,67 @@ class PolgoUploadClient {
70
71
  };
71
72
  }
72
73
 
74
+ /**
75
+ * Valida se o bucket foi informado
76
+ * @param {string} bucket - Nome do bucket
77
+ * @private
78
+ */
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
+ }
116
+ }
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
+ */
73
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
+
74
135
  const queryParams = new URLSearchParams({
75
136
  bucket,
76
137
  key,
@@ -83,17 +144,32 @@ class PolgoUploadClient {
83
144
  headers: {
84
145
  Authorization: `Bearer ${this.token}`,
85
146
  },
147
+ timeout: this.timeout,
86
148
  });
87
149
 
88
150
  return response.data;
89
151
  } catch (error) {
90
- console.error("Erro ao recuperar arquivo:", error.message);
91
-
92
- throw new Error(`Falha ao recuperar o arquivo: ${error.message}`);
152
+ this._handleError(error, "recuperar arquivo");
93
153
  }
94
154
  }
95
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
+ */
96
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
+
97
173
  const queryParams = new URLSearchParams({
98
174
  bucket,
99
175
  key,
@@ -106,12 +182,12 @@ class PolgoUploadClient {
106
182
  headers: {
107
183
  Authorization: `Bearer ${this.token}`,
108
184
  },
185
+ timeout: this.timeout,
109
186
  });
110
- console.log("Arquivos listados com sucesso:", response.data);
187
+
111
188
  return response.data.arquivos || [];
112
189
  } catch (error) {
113
- console.error("Erro ao listar arquivos:", error.message);
114
- throw new Error(`Falha ao listar arquivos: ${error.message}`);
190
+ this._handleError(error, "listar arquivos");
115
191
  }
116
192
  }
117
193
 
@@ -119,40 +195,64 @@ class PolgoUploadClient {
119
195
  * Faz upload de um arquivo para o bucket especificado
120
196
  * @param {File|Buffer} bufferArquivo - O arquivo a ser enviado
121
197
  * @param {string} bucket - Nome do bucket de destino
122
- * @param {Object} options - Opções do upload
123
- * @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
124
200
  * @param {string} [options.nomeArquivo] - Nome personalizado para o arquivo
125
- * @param {Object} [options.otimizacao] - Parâmetros de otimização de imagem
126
- * @param {number} [options.otimizacao.qualidade] - Qualidade da imagem (0-100, padrão: 85)
127
- * @param {number} [options.otimizacao.largura] - Largura desejada em pixels
128
- * @param {number} [options.otimizacao.altura] - Altura desejada em pixels
129
- * @param {string} [options.otimizacao.formato] - Formato de saída (jpeg, png, webp)
130
- * @param {number} [options.otimizacao.compressao] - Nível de compressão (0-9)
131
- * @param {boolean} [options.otimizacao.manterProporcao] - Manter proporção ao redimensionar (padrão: true)
132
- * @param {Function} [onProgress] - Callback para acompanhar progresso do upload
133
- * @returns {Promise<Object>} Dados de resposta do upload
134
- *
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
+ *
135
217
  * @example
136
218
  * // Upload simples
137
219
  * await client.uploadFile(file, 'meu-bucket');
138
- *
220
+ *
139
221
  * @example
140
- * // Upload com otimização de imagem
222
+ * // Upload com otimizacao de imagem
141
223
  * await client.uploadFile(file, 'meu-bucket', {
142
224
  * diretorio: 'imagens/perfil',
143
225
  * nomeArquivo: 'avatar.jpg',
144
- * otimizacao: {
145
- * qualidade: 80,
146
- * largura: 800,
147
- * altura: 600,
148
- * formato: 'webp',
149
- * manterProporcao: true
150
- * }
226
+ * otimizacao: 'webp'
151
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
+ * });
152
247
  */
153
248
  async uploadFile(bufferArquivo, bucket, options = {}, onProgress) {
154
- const mimeType = bufferArquivo.type;
249
+ this._validarBucket(bucket);
155
250
 
251
+ if (!bufferArquivo) {
252
+ throw new Error("Arquivo e obrigatorio");
253
+ }
254
+
255
+ const mimeType = bufferArquivo.type;
156
256
  const fileBlob = new Blob([bufferArquivo], { type: mimeType });
157
257
 
158
258
  const queryParams = new URLSearchParams({
@@ -162,22 +262,33 @@ class PolgoUploadClient {
162
262
 
163
263
  if (options.diretorio) queryParams.append("diretorio", options.diretorio);
164
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
+ }
165
268
 
166
- // Parâmetro de otimização simplificado conforme esperado pela lambda
167
- if (options.otimizacao) {
168
- const { formato } = options.otimizacao;
169
- if (formato === 'avif') {
170
- queryParams.append("otimizacao", "avif");
171
- } else if (formato === 'webp') {
172
- queryParams.append("otimizacao", "webp");
173
- } else if (formato === 'none' || formato === false) {
174
- queryParams.append("otimizacao", "false");
175
- } else {
176
- 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";
177
282
  }
178
- } else {
179
- queryParams.append("otimizacao", "webp"); // padrão quando não especificado
180
- }
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));
181
292
 
182
293
  const finalUrl = `${this.urls.upload}?${queryParams.toString()}`;
183
294
  const form = new FormData();
@@ -189,11 +300,10 @@ class PolgoUploadClient {
189
300
  headers: {
190
301
  Authorization: `Bearer ${this.token}`,
191
302
  },
303
+ timeout: this.timeout,
192
304
  onUploadProgress: (progressEvent) => {
193
- const percentCompleted = Math.round(
194
- (progressEvent.loaded * 100) / progressEvent.total
195
- );
196
- if (typeof onProgress === "function") {
305
+ if (typeof onProgress === "function" && progressEvent.total) {
306
+ const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
197
307
  onProgress(percentCompleted);
198
308
  }
199
309
  },
@@ -201,12 +311,9 @@ class PolgoUploadClient {
201
311
 
202
312
  return response.data;
203
313
  } catch (error) {
204
- console.error("Erro ao fazer upload do arquivo:", error.message);
205
- throw new Error(
206
- `Falha ao realizar o upload do arquivo: ${error.message}`
207
- );
314
+ this._handleError(error, "fazer upload");
208
315
  }
209
316
  }
210
317
  }
211
318
 
212
- export { PolgoUploadClient };
319
+ export { PolgoUploadClient };