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.
Files changed (54) hide show
  1. package/README.md +484 -0
  2. package/dist/client/index.d.ts +3 -0
  3. package/dist/client/index.d.ts.map +1 -0
  4. package/dist/client/index.js +6 -0
  5. package/dist/client/index.js.map +1 -0
  6. package/dist/client/storage-client.d.ts +26 -0
  7. package/dist/client/storage-client.d.ts.map +1 -0
  8. package/dist/client/storage-client.js +237 -0
  9. package/dist/client/storage-client.js.map +1 -0
  10. package/dist/core/storage-core.d.ts +20 -0
  11. package/dist/core/storage-core.d.ts.map +1 -0
  12. package/dist/core/storage-core.js +192 -0
  13. package/dist/core/storage-core.js.map +1 -0
  14. package/dist/errors/storage-errors.d.ts +29 -0
  15. package/dist/errors/storage-errors.d.ts.map +1 -0
  16. package/dist/errors/storage-errors.js +78 -0
  17. package/dist/errors/storage-errors.js.map +1 -0
  18. package/dist/helpers/mime-validator.d.ts +2 -0
  19. package/dist/helpers/mime-validator.d.ts.map +1 -0
  20. package/dist/helpers/mime-validator.js +18 -0
  21. package/dist/helpers/mime-validator.js.map +1 -0
  22. package/dist/helpers/path-sanitizer.d.ts +8 -0
  23. package/dist/helpers/path-sanitizer.d.ts.map +1 -0
  24. package/dist/helpers/path-sanitizer.js +23 -0
  25. package/dist/helpers/path-sanitizer.js.map +1 -0
  26. package/dist/helpers/path-validator.d.ts +27 -0
  27. package/dist/helpers/path-validator.d.ts.map +1 -0
  28. package/dist/helpers/path-validator.js +66 -0
  29. package/dist/helpers/path-validator.js.map +1 -0
  30. package/dist/helpers/size-parser.d.ts +2 -0
  31. package/dist/helpers/size-parser.d.ts.map +1 -0
  32. package/dist/helpers/size-parser.js +22 -0
  33. package/dist/helpers/size-parser.js.map +1 -0
  34. package/dist/index.d.ts +12 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +31 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/nestjs/index.d.ts +4 -0
  39. package/dist/nestjs/index.d.ts.map +1 -0
  40. package/dist/nestjs/index.js +8 -0
  41. package/dist/nestjs/index.js.map +1 -0
  42. package/dist/nestjs/storage.module.d.ts +13 -0
  43. package/dist/nestjs/storage.module.d.ts.map +1 -0
  44. package/dist/nestjs/storage.module.js +86 -0
  45. package/dist/nestjs/storage.module.js.map +1 -0
  46. package/dist/nestjs/storage.service.d.ts +17 -0
  47. package/dist/nestjs/storage.service.d.ts.map +1 -0
  48. package/dist/nestjs/storage.service.js +106 -0
  49. package/dist/nestjs/storage.service.js.map +1 -0
  50. package/dist/types/index.d.ts +20 -0
  51. package/dist/types/index.d.ts.map +1 -0
  52. package/dist/types/index.js +3 -0
  53. package/dist/types/index.js.map +1 -0
  54. 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,3 @@
1
+ export { StorageClient } from './storage-client';
2
+ export type { StorageClientOptions } from './storage-client';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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"}