s3-storage-dtb 0.0.1
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 +484 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +6 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/storage-client.d.ts +26 -0
- package/dist/client/storage-client.d.ts.map +1 -0
- package/dist/client/storage-client.js +237 -0
- package/dist/client/storage-client.js.map +1 -0
- package/dist/core/storage-core.d.ts +20 -0
- package/dist/core/storage-core.d.ts.map +1 -0
- package/dist/core/storage-core.js +192 -0
- package/dist/core/storage-core.js.map +1 -0
- package/dist/errors/storage-errors.d.ts +29 -0
- package/dist/errors/storage-errors.d.ts.map +1 -0
- package/dist/errors/storage-errors.js +78 -0
- package/dist/errors/storage-errors.js.map +1 -0
- package/dist/helpers/mime-validator.d.ts +2 -0
- package/dist/helpers/mime-validator.d.ts.map +1 -0
- package/dist/helpers/mime-validator.js +18 -0
- package/dist/helpers/mime-validator.js.map +1 -0
- package/dist/helpers/path-sanitizer.d.ts +8 -0
- package/dist/helpers/path-sanitizer.d.ts.map +1 -0
- package/dist/helpers/path-sanitizer.js +23 -0
- package/dist/helpers/path-sanitizer.js.map +1 -0
- package/dist/helpers/path-validator.d.ts +27 -0
- package/dist/helpers/path-validator.d.ts.map +1 -0
- package/dist/helpers/path-validator.js +66 -0
- package/dist/helpers/path-validator.js.map +1 -0
- package/dist/helpers/size-parser.d.ts +2 -0
- package/dist/helpers/size-parser.d.ts.map +1 -0
- package/dist/helpers/size-parser.js +22 -0
- package/dist/helpers/size-parser.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/nestjs/index.d.ts +4 -0
- package/dist/nestjs/index.d.ts.map +1 -0
- package/dist/nestjs/index.js +8 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/nestjs/storage.module.d.ts +13 -0
- package/dist/nestjs/storage.module.d.ts.map +1 -0
- package/dist/nestjs/storage.module.js +86 -0
- package/dist/nestjs/storage.module.js.map +1 -0
- package/dist/nestjs/storage.service.d.ts +17 -0
- package/dist/nestjs/storage.service.d.ts.map +1 -0
- package/dist/nestjs/storage.service.js +106 -0
- package/dist/nestjs/storage.service.js.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# s3-storage-dtb
|
|
2
|
+
|
|
3
|
+
Paquete de almacenamiento de archivos para Node.js y NestJS.
|
|
4
|
+
|
|
5
|
+
## 🎯 Dos Modos de Uso
|
|
6
|
+
|
|
7
|
+
El paquete ofrece **dos modos** que puedes elegir según tus necesidades:
|
|
8
|
+
|
|
9
|
+
### 📁 Modo Local (StorageCore)
|
|
10
|
+
Almacena archivos directamente en el sistema de archivos de tu servidor. **Ideal para:**
|
|
11
|
+
- Desarrollo local
|
|
12
|
+
- Aplicaciones que corren en el mismo servidor
|
|
13
|
+
- Cuando no necesitas un backend separado
|
|
14
|
+
|
|
15
|
+
### 🌐 Modo Cliente (StorageClient)
|
|
16
|
+
Se conecta a un backend remoto mediante HTTP. **Ideal para:
|
|
17
|
+
- Producción con backend separado
|
|
18
|
+
- Múltiples aplicaciones compartiendo almacenamiento
|
|
19
|
+
- Escalabilidad y distribución
|
|
20
|
+
|
|
21
|
+
## Características
|
|
22
|
+
|
|
23
|
+
- ✅ Almacenamiento local de archivos (StorageCore)
|
|
24
|
+
- ✅ Cliente HTTP para backend remoto (StorageClient)
|
|
25
|
+
- ✅ Autenticación con API keys
|
|
26
|
+
- ✅ Validación de tipos MIME
|
|
27
|
+
- ✅ Límites de tamaño de archivo
|
|
28
|
+
- ✅ Sanitización de rutas (protección contra path traversal)
|
|
29
|
+
- ✅ Metadata de archivos
|
|
30
|
+
- ✅ Listado y paginación
|
|
31
|
+
- ✅ Compatible con Node.js puro y NestJS
|
|
32
|
+
- ✅ TypeScript con tipos completos
|
|
33
|
+
|
|
34
|
+
## Instalación
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install s3-storage-dtb
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Para uso con NestJS, también necesitas:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install @nestjs/common
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🚀 Inicio Rápido
|
|
47
|
+
|
|
48
|
+
### Elegir el Modo Correcto
|
|
49
|
+
|
|
50
|
+
**¿Necesitas almacenar archivos localmente?** → Usa `StorageCore`
|
|
51
|
+
**¿Necesitas conectarte a un backend remoto?** → Usa `StorageClient`
|
|
52
|
+
|
|
53
|
+
Ambos tienen la **misma API**, solo cambia la inicialización.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📁 Modo Local (StorageCore)
|
|
58
|
+
|
|
59
|
+
### Configuración
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { StorageCore } from 's3-storage-dtb';
|
|
63
|
+
|
|
64
|
+
// ✅ Configuración simple - Solo necesitas la ruta
|
|
65
|
+
const storage = new StorageCore({
|
|
66
|
+
rootPath: './uploads', // Donde se guardarán los archivos
|
|
67
|
+
maxFileSize: '50mb', // Opcional: límite de tamaño
|
|
68
|
+
allowedMimeTypes: ['image/*', 'video/*'] // Opcional: tipos permitidos
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Uso Completo
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { StorageCore } from 's3-storage-dtb';
|
|
76
|
+
import { readFileSync } from 'fs';
|
|
77
|
+
|
|
78
|
+
const storage = new StorageCore({
|
|
79
|
+
rootPath: './uploads',
|
|
80
|
+
maxFileSize: '50mb',
|
|
81
|
+
allowedMimeTypes: ['image/*', 'video/*']
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Todas las operaciones son iguales
|
|
85
|
+
const buffer = readFileSync('./mi-imagen.jpg');
|
|
86
|
+
const path = await storage.uploadFile('images/photo.jpg', buffer, 'image/jpeg');
|
|
87
|
+
const stream = await storage.downloadFile(path);
|
|
88
|
+
const metadata = await storage.getFileMetadata(path);
|
|
89
|
+
const { files, total } = await storage.listFiles('images');
|
|
90
|
+
await storage.deleteFile(path);
|
|
91
|
+
const exists = await storage.fileExists(path);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🌐 Modo Cliente (StorageClient)
|
|
97
|
+
|
|
98
|
+
### Configuración
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { StorageClient } from 's3-storage-dtb';
|
|
102
|
+
|
|
103
|
+
// ✅ Configuración simple - Solo necesitas URL y API key
|
|
104
|
+
const client = new StorageClient({
|
|
105
|
+
baseUrl: 'https://api.midominio.com', // URL del backend
|
|
106
|
+
apiKey: 'sk_live_xxx', // Tu API key
|
|
107
|
+
timeout: 30000 // Opcional: timeout en ms
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Ejemplos de baseUrl
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// Con dominio
|
|
115
|
+
new StorageClient({ baseUrl: 'https://api.midominio.com', apiKey: 'sk_xxx' });
|
|
116
|
+
|
|
117
|
+
// Con IP directa
|
|
118
|
+
new StorageClient({ baseUrl: 'http://192.168.1.100:3000', apiKey: 'sk_xxx' });
|
|
119
|
+
|
|
120
|
+
// Con puerto personalizado
|
|
121
|
+
new StorageClient({ baseUrl: 'http://localhost:8080', apiKey: 'sk_xxx' });
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Uso Completo
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { StorageClient } from 's3-storage-dtb';
|
|
128
|
+
import { readFileSync } from 'fs';
|
|
129
|
+
|
|
130
|
+
const client = new StorageClient({
|
|
131
|
+
baseUrl: 'https://api.midominio.com',
|
|
132
|
+
apiKey: 'sk_live_xxx'
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ⚠️ IMPORTANTE: La API es IDÉNTICA a StorageCore
|
|
136
|
+
const buffer = readFileSync('./mi-imagen.jpg');
|
|
137
|
+
const path = await client.uploadFile('images/photo.jpg', buffer, 'image/jpeg');
|
|
138
|
+
const stream = await client.downloadFile(path);
|
|
139
|
+
const metadata = await client.getFileMetadata(path);
|
|
140
|
+
const { files, total } = await client.listFiles('images');
|
|
141
|
+
await client.deleteFile(path);
|
|
142
|
+
const exists = await client.fileExists(path);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 🔄 Cambiar Entre Modos
|
|
148
|
+
|
|
149
|
+
Como ambos tienen la misma API, cambiar de modo es **súper simple**:
|
|
150
|
+
|
|
151
|
+
### Opción 1: Variable de Entorno
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { StorageCore, StorageClient } from 's3-storage-dtb';
|
|
155
|
+
|
|
156
|
+
// Usar variable de entorno para decidir el modo
|
|
157
|
+
const useRemote = process.env.STORAGE_MODE === 'remote';
|
|
158
|
+
|
|
159
|
+
const storage = useRemote
|
|
160
|
+
? new StorageClient({
|
|
161
|
+
baseUrl: process.env.STORAGE_URL!,
|
|
162
|
+
apiKey: process.env.STORAGE_API_KEY!
|
|
163
|
+
})
|
|
164
|
+
: new StorageCore({
|
|
165
|
+
rootPath: process.env.STORAGE_PATH || './uploads'
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// El resto del código es idéntico
|
|
169
|
+
await storage.uploadFile('images/photo.jpg', buffer, 'image/jpeg');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Opción 2: Factory Function
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { StorageCore, StorageClient } from 's3-storage-dtb';
|
|
176
|
+
|
|
177
|
+
function createStorage() {
|
|
178
|
+
if (process.env.STORAGE_URL && process.env.STORAGE_API_KEY) {
|
|
179
|
+
// Modo remoto
|
|
180
|
+
return new StorageClient({
|
|
181
|
+
baseUrl: process.env.STORAGE_URL,
|
|
182
|
+
apiKey: process.env.STORAGE_API_KEY
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Modo local (por defecto)
|
|
187
|
+
return new StorageCore({
|
|
188
|
+
rootPath: process.env.STORAGE_PATH || './uploads'
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const storage = createStorage();
|
|
193
|
+
// Usar normalmente
|
|
194
|
+
await storage.uploadFile('images/photo.jpg', buffer, 'image/jpeg');
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Opción 3: TypeScript con Interfaz Común
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { StorageCore, StorageClient } from 's3-storage-dtb';
|
|
201
|
+
import type { FileMetadata, ListFilesOptions } from 's3-storage-dtb';
|
|
202
|
+
|
|
203
|
+
// Interfaz común para ambos modos
|
|
204
|
+
interface Storage {
|
|
205
|
+
uploadFile(path: string, buffer: Buffer, mimeType: string, prefix?: string): Promise<string>;
|
|
206
|
+
downloadFile(path: string): Promise<Readable>;
|
|
207
|
+
deleteFile(path: string): Promise<void>;
|
|
208
|
+
getFileMetadata(path: string): Promise<FileMetadata>;
|
|
209
|
+
listFiles(directoryPath?: string, options?: ListFilesOptions): Promise<{files: FileMetadata[], total: number}>;
|
|
210
|
+
fileExists(path: string): Promise<boolean>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Crear instancia según configuración
|
|
214
|
+
const storage: Storage = process.env.STORAGE_MODE === 'remote'
|
|
215
|
+
? new StorageClient({ baseUrl: process.env.STORAGE_URL!, apiKey: process.env.STORAGE_API_KEY! })
|
|
216
|
+
: new StorageCore({ rootPath: './uploads' });
|
|
217
|
+
|
|
218
|
+
// Código tipo-seguro
|
|
219
|
+
await storage.uploadFile('images/photo.jpg', buffer, 'image/jpeg');
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Uso desde NestJS
|
|
223
|
+
|
|
224
|
+
### Configuración básica
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { Module } from '@nestjs/common';
|
|
228
|
+
import { StorageModule } from 's3-storage-dtb/nestjs';
|
|
229
|
+
|
|
230
|
+
@Module({
|
|
231
|
+
imports: [
|
|
232
|
+
StorageModule.forRoot({
|
|
233
|
+
rootPath: './uploads',
|
|
234
|
+
maxFileSize: '50mb',
|
|
235
|
+
allowedMimeTypes: ['image/*', 'video/*']
|
|
236
|
+
})
|
|
237
|
+
]
|
|
238
|
+
})
|
|
239
|
+
export class AppModule {}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Configuración asíncrona
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { Module } from '@nestjs/common';
|
|
246
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
247
|
+
import { StorageModule } from 's3-storage-dtb/nestjs';
|
|
248
|
+
|
|
249
|
+
@Module({
|
|
250
|
+
imports: [
|
|
251
|
+
ConfigModule.forRoot(),
|
|
252
|
+
StorageModule.forRootAsync({
|
|
253
|
+
useFactory: (config: ConfigService) => ({
|
|
254
|
+
rootPath: config.get('STORAGE_ROOT_PATH', './uploads'),
|
|
255
|
+
maxFileSize: config.get('STORAGE_MAX_SIZE', '50mb'),
|
|
256
|
+
allowedMimeTypes: config.get('STORAGE_ALLOWED_TYPES', ['image/*'])
|
|
257
|
+
}),
|
|
258
|
+
inject: [ConfigService]
|
|
259
|
+
})
|
|
260
|
+
]
|
|
261
|
+
})
|
|
262
|
+
export class AppModule {}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Usar en un servicio
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { Injectable } from '@nestjs/common';
|
|
269
|
+
import { StorageService } from 's3-storage-dtb/nestjs';
|
|
270
|
+
|
|
271
|
+
@Injectable()
|
|
272
|
+
export class FilesService {
|
|
273
|
+
constructor(private readonly storage: StorageService) {}
|
|
274
|
+
|
|
275
|
+
async uploadFile(filePath: string, buffer: Buffer, mimeType: string) {
|
|
276
|
+
return this.storage.uploadFile(filePath, buffer, mimeType);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async downloadFile(path: string) {
|
|
280
|
+
return this.storage.downloadFile(path);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## 📖 API Completa
|
|
286
|
+
|
|
287
|
+
### ⚡ Métodos Comunes (Ambos Modos)
|
|
288
|
+
|
|
289
|
+
Ambos `StorageCore` y `StorageClient` tienen **exactamente la misma API**:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// Subir archivo
|
|
293
|
+
uploadFile(path: string, buffer: Buffer, mimeType: string, prefix?: string): Promise<string>
|
|
294
|
+
|
|
295
|
+
// Descargar archivo (retorna stream)
|
|
296
|
+
downloadFile(path: string): Promise<Readable>
|
|
297
|
+
|
|
298
|
+
// Eliminar archivo
|
|
299
|
+
deleteFile(path: string): Promise<void>
|
|
300
|
+
|
|
301
|
+
// Obtener metadata
|
|
302
|
+
getFileMetadata(path: string): Promise<FileMetadata>
|
|
303
|
+
|
|
304
|
+
// Listar archivos
|
|
305
|
+
listFiles(directoryPath?: string, options?: ListFilesOptions): Promise<{files: FileMetadata[], total: number}>
|
|
306
|
+
|
|
307
|
+
// Verificar existencia
|
|
308
|
+
fileExists(path: string): Promise<boolean>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 🔧 Configuración
|
|
312
|
+
|
|
313
|
+
#### StorageCore (Modo Local)
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
new StorageCore(options: StorageCoreOptions)
|
|
317
|
+
|
|
318
|
+
interface StorageCoreOptions {
|
|
319
|
+
rootPath: string; // Ruta donde se guardan archivos
|
|
320
|
+
maxFileSize?: string; // Opcional: "50mb", "1gb", etc.
|
|
321
|
+
allowedMimeTypes?: string[]; // Opcional: ["image/*", "video/*"]
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### StorageClient (Modo Remoto)
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
new StorageClient(options: StorageClientOptions)
|
|
329
|
+
|
|
330
|
+
interface StorageClientOptions {
|
|
331
|
+
baseUrl: string; // URL del backend: "https://api.com" o "http://192.168.1.100:3000"
|
|
332
|
+
apiKey: string; // API key: "sk_live_xxx"
|
|
333
|
+
timeout?: number; // Opcional: timeout en ms (default: 30000)
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Nota:** El cliente automáticamente agrega el prefijo `/apifiles` a las URLs y maneja la autenticación con API keys.
|
|
338
|
+
|
|
339
|
+
#### Constructor
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
new StorageCore(options: StorageCoreOptions)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Opciones:**
|
|
346
|
+
- `rootPath` (string, requerido): Ruta raíz donde se almacenarán los archivos
|
|
347
|
+
- `maxFileSize` (string, opcional): Tamaño máximo de archivo (ej: "50mb", "1gb"). Por defecto: "50mb"
|
|
348
|
+
- `allowedMimeTypes` (string[], opcional): Tipos MIME permitidos (ej: ["image/*", "video/*"]). Por defecto: ["*"]
|
|
349
|
+
|
|
350
|
+
#### Métodos
|
|
351
|
+
|
|
352
|
+
##### `uploadFile(path, buffer, mimeType, prefix?)`
|
|
353
|
+
|
|
354
|
+
Sube un archivo al almacenamiento.
|
|
355
|
+
|
|
356
|
+
- `path` (string): Ruta relativa donde se guardará el archivo
|
|
357
|
+
- `buffer` (Buffer): Contenido del archivo
|
|
358
|
+
- `mimeType` (string): Tipo MIME del archivo
|
|
359
|
+
- `prefix` (string, opcional): Prefijo para el nombre del archivo (se genera un UUID)
|
|
360
|
+
|
|
361
|
+
**Retorna:** `Promise<string>` - Ruta relativa del archivo guardado
|
|
362
|
+
|
|
363
|
+
##### `downloadFile(path)`
|
|
364
|
+
|
|
365
|
+
Descarga un archivo como stream.
|
|
366
|
+
|
|
367
|
+
- `path` (string): Ruta relativa del archivo
|
|
368
|
+
|
|
369
|
+
**Retorna:** `Promise<Readable>` - Stream de Node.js
|
|
370
|
+
|
|
371
|
+
##### `deleteFile(path)`
|
|
372
|
+
|
|
373
|
+
Elimina un archivo.
|
|
374
|
+
|
|
375
|
+
- `path` (string): Ruta relativa del archivo
|
|
376
|
+
|
|
377
|
+
**Retorna:** `Promise<void>`
|
|
378
|
+
|
|
379
|
+
##### `getFileMetadata(path)`
|
|
380
|
+
|
|
381
|
+
Obtiene metadata de un archivo.
|
|
382
|
+
|
|
383
|
+
- `path` (string): Ruta relativa del archivo
|
|
384
|
+
|
|
385
|
+
**Retorna:** `Promise<FileMetadata>`
|
|
386
|
+
|
|
387
|
+
##### `listFiles(directoryPath?, options?)`
|
|
388
|
+
|
|
389
|
+
Lista archivos en un directorio.
|
|
390
|
+
|
|
391
|
+
- `directoryPath` (string, opcional): Ruta del directorio (vacío para raíz)
|
|
392
|
+
- `options` (ListFilesOptions, opcional):
|
|
393
|
+
- `limit` (number): Número máximo de archivos
|
|
394
|
+
- `offset` (number): Offset para paginación
|
|
395
|
+
- `prefix` (string): Filtrar por prefijo en el nombre
|
|
396
|
+
|
|
397
|
+
**Retorna:** `Promise<{ files: FileMetadata[], total: number }>`
|
|
398
|
+
|
|
399
|
+
##### `fileExists(path)`
|
|
400
|
+
|
|
401
|
+
Verifica si un archivo existe.
|
|
402
|
+
|
|
403
|
+
- `path` (string): Ruta relativa del archivo
|
|
404
|
+
|
|
405
|
+
**Retorna:** `Promise<boolean>`
|
|
406
|
+
|
|
407
|
+
## Tipos
|
|
408
|
+
|
|
409
|
+
### FileMetadata
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
interface FileMetadata {
|
|
413
|
+
name: string;
|
|
414
|
+
path: string;
|
|
415
|
+
size: number;
|
|
416
|
+
mimeType: string;
|
|
417
|
+
createdAt: Date;
|
|
418
|
+
modifiedAt: Date;
|
|
419
|
+
checksum?: string;
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## 📋 Comparación Rápida
|
|
424
|
+
|
|
425
|
+
| Característica | StorageCore (Local) | StorageClient (Remoto) |
|
|
426
|
+
|---------------|---------------------|------------------------|
|
|
427
|
+
| **Inicialización** | `new StorageCore({ rootPath })` | `new StorageClient({ baseUrl, apiKey })` |
|
|
428
|
+
| **Almacenamiento** | Sistema de archivos local | Backend remoto vía HTTP |
|
|
429
|
+
| **API** | ✅ Idéntica | ✅ Idéntica |
|
|
430
|
+
| **Autenticación** | ❌ No requiere | ✅ Requiere API key |
|
|
431
|
+
| **Ideal para** | Desarrollo, mismo servidor | Producción, múltiples apps |
|
|
432
|
+
| **Configuración** | Solo ruta | URL + API key |
|
|
433
|
+
|
|
434
|
+
## 💡 Recomendaciones
|
|
435
|
+
|
|
436
|
+
- **Desarrollo**: Usa `StorageCore` con `rootPath: './uploads'`
|
|
437
|
+
- **Producción**: Usa `StorageClient` con variables de entorno
|
|
438
|
+
- **Cambio fácil**: Ambos tienen la misma API, solo cambia la inicialización
|
|
439
|
+
|
|
440
|
+
### ListFilesOptions
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
interface ListFilesOptions {
|
|
444
|
+
limit?: number;
|
|
445
|
+
offset?: number;
|
|
446
|
+
prefix?: string;
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Errores
|
|
451
|
+
|
|
452
|
+
El paquete lanza errores personalizados que extienden `StorageError`:
|
|
453
|
+
|
|
454
|
+
- `FileNotFoundError`: El archivo no existe
|
|
455
|
+
- `InvalidMimeTypeError`: Tipo MIME no permitido
|
|
456
|
+
- `FileTooLargeError`: El archivo excede el tamaño máximo
|
|
457
|
+
- `UploadError`: Error al subir archivo
|
|
458
|
+
- `DownloadError`: Error al descargar archivo
|
|
459
|
+
- `DeleteError`: Error al eliminar archivo
|
|
460
|
+
- `MetadataError`: Error al obtener metadata
|
|
461
|
+
- `ListError`: Error al listar archivos
|
|
462
|
+
|
|
463
|
+
Todos los errores tienen una propiedad `code` para identificación:
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
try {
|
|
467
|
+
await storage.uploadFile('path', buffer, 'image/jpeg');
|
|
468
|
+
} catch (error) {
|
|
469
|
+
if (error instanceof FileNotFoundError) {
|
|
470
|
+
console.error('Código:', error.code); // 'FILE_NOT_FOUND'
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Seguridad
|
|
476
|
+
|
|
477
|
+
- **Sanitización de rutas**: Protección contra path traversal (`..`)
|
|
478
|
+
- **Validación de caracteres**: Solo permite caracteres seguros en rutas
|
|
479
|
+
- **Validación de MIME types**: Verifica tipos de archivo permitidos
|
|
480
|
+
- **Límites de tamaño**: Previene archivos demasiado grandes
|
|
481
|
+
|
|
482
|
+
## Licencia
|
|
483
|
+
|
|
484
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StorageClient = void 0;
|
|
4
|
+
var storage_client_1 = require("./storage-client");
|
|
5
|
+
Object.defineProperty(exports, "StorageClient", { enumerable: true, get: function () { return storage_client_1.StorageClient; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAAA,mDAAiD;AAAxC,+GAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
|
+
import type { FileMetadata, ListFilesOptions } from '../types';
|
|
3
|
+
export interface StorageClientOptions {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class StorageClient {
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
private readonly apiKey;
|
|
11
|
+
private readonly timeout;
|
|
12
|
+
private readonly apiPrefix;
|
|
13
|
+
constructor(options: StorageClientOptions);
|
|
14
|
+
private getHeaders;
|
|
15
|
+
private request;
|
|
16
|
+
uploadFile(filePath: string, buffer: Buffer, mimeType: string, prefix?: string): Promise<string>;
|
|
17
|
+
downloadFile(path: string): Promise<Readable>;
|
|
18
|
+
deleteFile(path: string): Promise<void>;
|
|
19
|
+
getFileMetadata(path: string): Promise<FileMetadata>;
|
|
20
|
+
listFiles(directoryPath?: string, options?: ListFilesOptions): Promise<{
|
|
21
|
+
files: FileMetadata[];
|
|
22
|
+
total: number;
|
|
23
|
+
}>;
|
|
24
|
+
fileExists(path: string): Promise<boolean>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=storage-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-client.d.ts","sourceRoot":"","sources":["../../src/client/storage-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAa/D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAWD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;gBAErC,OAAO,EAAE,oBAAoB;IAczC,OAAO,CAAC,UAAU;YAQJ,OAAO;IA6Ff,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;IA4BZ,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAe7C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA8CpD,SAAS,CACb,aAAa,GAAE,MAAW,EAC1B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC;QAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAkC9C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAWjD"}
|