@ackplus/nest-file-storage 1.1.10 → 1.1.12

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 (62) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +658 -6
  3. package/{src → dist}/index.d.ts +0 -1
  4. package/dist/index.js +21 -0
  5. package/dist/index.js.map +1 -0
  6. package/{src → dist}/lib/constants.d.ts +0 -1
  7. package/{src → dist}/lib/constants.js +1 -0
  8. package/dist/lib/constants.js.map +1 -0
  9. package/{src → dist}/lib/file-storage.service.d.ts +0 -1
  10. package/{src → dist}/lib/file-storage.service.js +2 -2
  11. package/dist/lib/file-storage.service.js.map +1 -0
  12. package/{src → dist}/lib/index.d.ts +0 -1
  13. package/dist/lib/index.js +22 -0
  14. package/dist/lib/index.js.map +1 -0
  15. package/{src → dist}/lib/interceptor/file-storage.interceptor.d.ts +0 -4
  16. package/{src → dist}/lib/interceptor/file-storage.interceptor.js +5 -17
  17. package/dist/lib/interceptor/file-storage.interceptor.js.map +1 -0
  18. package/{src → dist}/lib/nest-file-storage.module.d.ts +0 -1
  19. package/{src → dist}/lib/nest-file-storage.module.js +9 -3
  20. package/dist/lib/nest-file-storage.module.js.map +1 -0
  21. package/{src → dist}/lib/storage/azure.storage.d.ts +0 -1
  22. package/{src → dist}/lib/storage/azure.storage.js +49 -10
  23. package/dist/lib/storage/azure.storage.js.map +1 -0
  24. package/{src → dist}/lib/storage/local.storage.d.ts +0 -15
  25. package/{src → dist}/lib/storage/local.storage.js +44 -32
  26. package/dist/lib/storage/local.storage.js.map +1 -0
  27. package/{src → dist}/lib/storage/s3.storage.d.ts +0 -1
  28. package/{src → dist}/lib/storage/s3.storage.js +43 -8
  29. package/dist/lib/storage/s3.storage.js.map +1 -0
  30. package/{src → dist}/lib/storage.factory.d.ts +0 -1
  31. package/dist/lib/storage.factory.js +46 -0
  32. package/dist/lib/storage.factory.js.map +1 -0
  33. package/{src → dist}/lib/types.d.ts +0 -14
  34. package/{src → dist}/lib/types.js +1 -0
  35. package/dist/lib/types.js.map +1 -0
  36. package/dist/tsconfig.build.tsbuildinfo +1 -0
  37. package/examples/1-basic-local-storage.example.ts +22 -0
  38. package/examples/10-testing.example.ts +233 -0
  39. package/examples/2-s3-storage.example.ts +40 -0
  40. package/examples/3-azure-storage.example.ts +35 -0
  41. package/examples/4-upload-controller.example.ts +117 -0
  42. package/examples/5-custom-configuration.example.ts +75 -0
  43. package/examples/6-file-service.example.ts +124 -0
  44. package/examples/7-user-avatar.example.ts +139 -0
  45. package/examples/8-document-management.example.ts +265 -0
  46. package/examples/9-dynamic-storage.example.ts +175 -0
  47. package/examples/README.md +122 -0
  48. package/package.json +86 -6
  49. package/src/index.d.ts.map +0 -1
  50. package/src/index.js +0 -7
  51. package/src/lib/constants.d.ts.map +0 -1
  52. package/src/lib/file-storage.service.d.ts.map +0 -1
  53. package/src/lib/index.d.ts.map +0 -1
  54. package/src/lib/index.js +0 -8
  55. package/src/lib/interceptor/file-storage.interceptor.d.ts.map +0 -1
  56. package/src/lib/nest-file-storage.module.d.ts.map +0 -1
  57. package/src/lib/storage/azure.storage.d.ts.map +0 -1
  58. package/src/lib/storage/local.storage.d.ts.map +0 -1
  59. package/src/lib/storage/s3.storage.d.ts.map +0 -1
  60. package/src/lib/storage.factory.d.ts.map +0 -1
  61. package/src/lib/storage.factory.js +0 -81
  62. package/src/lib/types.d.ts.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 AckPlus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md CHANGED
@@ -1,11 +1,663 @@
1
- # nest-auth
1
+ # @ackplus/nest-file-storage
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ A flexible and feature-rich file storage solution for NestJS applications with support for Local, AWS S3, and Azure Blob Storage.
4
4
 
5
- ## Building
5
+ ## ✨ Features
6
6
 
7
- Run `nx build nest-auth` to build the library.
7
+ - 📦 **Multiple Storage Providers** - Local, AWS S3, and Azure Blob Storage support
8
+ - 🔄 **Easy Switching** - Switch between storage providers with minimal configuration
9
+ - 🎯 **NestJS Integration** - Seamless integration with NestJS decorators and interceptors
10
+ - 📁 **File Operations** - Upload, download, delete, copy files with ease
11
+ - 🔐 **Signed URLs** - Generate presigned URLs for secure file access (S3)
12
+ - 🎨 **Customizable** - Custom file naming, directory structure, and transformations
13
+ - 📝 **TypeScript** - Full TypeScript support with type safety
14
+ - 🧪 **Test-Friendly** - Easy to mock and test
8
15
 
9
- ## Running unit tests
16
+ ## 📦 Installation
10
17
 
11
- Run `nx test nest-auth` to execute the unit tests via [Jest](https://jestjs.io).
18
+ ```bash
19
+ npm install @ackplus/nest-file-storage
20
+ # or
21
+ pnpm add @ackplus/nest-file-storage
22
+ # or
23
+ yarn add @ackplus/nest-file-storage
24
+ ```
25
+
26
+ **For AWS S3 support:**
27
+
28
+ ```bash
29
+ npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
30
+ ```
31
+
32
+ **For Azure Blob Storage support:**
33
+
34
+ ```bash
35
+ npm install @azure/storage-blob
36
+ ```
37
+
38
+ ## 🚀 Quick Start
39
+
40
+ ### Step 1: Configure Module
41
+
42
+ Choose your storage provider and configure the module:
43
+
44
+ #### Local Storage
45
+
46
+ ```typescript
47
+ // app.module.ts
48
+ import { Module } from '@nestjs/common';
49
+ import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
50
+
51
+ @Module({
52
+ imports: [
53
+ NestFileStorageModule.forRoot({
54
+ storage: FileStorageEnum.LOCAL,
55
+ localConfig: {
56
+ rootPath: './uploads',
57
+ baseUrl: 'http://localhost:3000/uploads',
58
+ },
59
+ }),
60
+ ],
61
+ })
62
+ export class AppModule {}
63
+ ```
64
+
65
+ #### AWS S3
66
+
67
+ ```typescript
68
+ // app.module.ts
69
+ import { Module } from '@nestjs/common';
70
+ import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
71
+
72
+ @Module({
73
+ imports: [
74
+ NestFileStorageModule.forRoot({
75
+ storage: FileStorageEnum.S3,
76
+ s3Config: {
77
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
78
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
79
+ region: process.env.AWS_REGION,
80
+ bucket: process.env.AWS_BUCKET,
81
+ },
82
+ }),
83
+ ],
84
+ })
85
+ export class AppModule {}
86
+ ```
87
+
88
+ #### Azure Blob Storage
89
+
90
+ ```typescript
91
+ // app.module.ts
92
+ import { Module } from '@nestjs/common';
93
+ import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
94
+
95
+ @Module({
96
+ imports: [
97
+ NestFileStorageModule.forRoot({
98
+ storage: FileStorageEnum.AZURE,
99
+ azureConfig: {
100
+ account: process.env.AZURE_STORAGE_ACCOUNT,
101
+ accountKey: process.env.AZURE_STORAGE_KEY,
102
+ container: process.env.AZURE_CONTAINER,
103
+ },
104
+ }),
105
+ ],
106
+ })
107
+ export class AppModule {}
108
+ ```
109
+
110
+ ### Step 2: Upload Files in Controller
111
+
112
+ ```typescript
113
+ // upload.controller.ts
114
+ import { Controller, Post, UseInterceptors } from '@nestjs/common';
115
+ import { FileStorageInterceptor } from '@ackplus/nest-file-storage';
116
+
117
+ @Controller('upload')
118
+ export class UploadController {
119
+ // Single file upload
120
+ @Post('single')
121
+ @UseInterceptors(FileStorageInterceptor('file'))
122
+ uploadSingle(@Body() body: any) {
123
+ // File key is automatically added to body.file
124
+ return {
125
+ message: 'File uploaded successfully',
126
+ fileKey: body.file,
127
+ };
128
+ }
129
+
130
+ // Multiple files upload
131
+ @Post('multiple')
132
+ @UseInterceptors(
133
+ FileStorageInterceptor({
134
+ type: 'array',
135
+ fieldName: 'files',
136
+ maxCount: 10,
137
+ })
138
+ )
139
+ uploadMultiple(@Body() body: any) {
140
+ // File keys are automatically added to body.files as array
141
+ return {
142
+ message: 'Files uploaded successfully',
143
+ fileKeys: body.files,
144
+ };
145
+ }
146
+
147
+ // Multiple fields
148
+ @Post('fields')
149
+ @UseInterceptors(
150
+ FileStorageInterceptor({
151
+ type: 'fields',
152
+ fields: [
153
+ { name: 'avatar', maxCount: 1 },
154
+ { name: 'photos', maxCount: 5 },
155
+ ],
156
+ })
157
+ )
158
+ uploadFields(@Body() body: any) {
159
+ return {
160
+ message: 'Files uploaded successfully',
161
+ avatar: body.avatar,
162
+ photos: body.photos,
163
+ };
164
+ }
165
+ }
166
+ ```
167
+
168
+ ### Step 3: Use File Storage Service
169
+
170
+ ```typescript
171
+ // file.service.ts
172
+ import { Injectable } from '@nestjs/common';
173
+ import { FileStorageService } from '@ackplus/nest-file-storage';
174
+
175
+ @Injectable()
176
+ export class FileService {
177
+ // Get file
178
+ async getFile(key: string): Promise<Buffer> {
179
+ const storage = await FileStorageService.getStorage();
180
+ return await storage.getFile(key);
181
+ }
182
+
183
+ // Delete file
184
+ async deleteFile(key: string): Promise<void> {
185
+ const storage = await FileStorageService.getStorage();
186
+ await storage.deleteFile(key);
187
+ }
188
+
189
+ // Copy file
190
+ async copyFile(oldKey: string, newKey: string) {
191
+ const storage = await FileStorageService.getStorage();
192
+ return await storage.copyFile(oldKey, newKey);
193
+ }
194
+
195
+ // Get public URL
196
+ async getFileUrl(key: string): Promise<string> {
197
+ const storage = await FileStorageService.getStorage();
198
+ return storage.getUrl(key);
199
+ }
200
+
201
+ // Get signed URL (S3 only)
202
+ async getSignedUrl(key: string): Promise<string> {
203
+ const storage = await FileStorageService.getStorage();
204
+ if ('getSignedUrl' in storage) {
205
+ return await storage.getSignedUrl(key, { expiresIn: 3600 });
206
+ }
207
+ return storage.getUrl(key);
208
+ }
209
+ }
210
+ ```
211
+
212
+ ## 📚 Configuration Options
213
+
214
+ ### Local Storage Options
215
+
216
+ ```typescript
217
+ interface LocalStorageOptions {
218
+ rootPath: string; // Directory to store files
219
+ baseUrl: string; // Base URL for file access
220
+ prefix?: string; // Optional prefix for file keys
221
+ fileName?: (file: any, req: Request) => string; // Custom file naming
222
+ fileDist?: (file: any, req: Request) => string; // Custom directory structure
223
+ transformUploadedFileObject?: (file: any) => any; // Transform uploaded file object
224
+ }
225
+ ```
226
+
227
+ ### S3 Storage Options
228
+
229
+ ```typescript
230
+ interface S3StorageOptions {
231
+ accessKeyId: string; // AWS access key
232
+ secretAccessKey: string; // AWS secret key
233
+ region: string; // AWS region
234
+ bucket: string; // S3 bucket name
235
+ endpoint?: string; // Custom S3 endpoint (for S3-compatible services)
236
+ cloudFrontUrl?: string; // CloudFront distribution URL
237
+ prefix?: string; // Optional prefix for file keys
238
+ fileName?: (file: any, req: Request) => string; // Custom file naming
239
+ fileDist?: (file: any, req: Request) => string; // Custom directory structure
240
+ transformUploadedFileObject?: (file: any) => any; // Transform uploaded file object
241
+ }
242
+ ```
243
+
244
+ ### Azure Storage Options
245
+
246
+ ```typescript
247
+ interface AzureStorageOptions {
248
+ account: string; // Azure storage account name
249
+ accountKey: string; // Azure storage account key
250
+ container: string; // Container name
251
+ prefix?: string; // Optional prefix for file keys
252
+ fileName?: (file: any, req: Request) => string; // Custom file naming
253
+ fileDist?: (file: any, req: Request) => string; // Custom directory structure
254
+ transformUploadedFileObject?: (file: any) => any; // Transform uploaded file object
255
+ }
256
+ ```
257
+
258
+ ## 🎨 Advanced Usage
259
+
260
+ ### Custom File Naming
261
+
262
+ ```typescript
263
+ NestFileStorageModule.forRoot({
264
+ storage: FileStorageEnum.LOCAL,
265
+ localConfig: {
266
+ rootPath: './uploads',
267
+ baseUrl: 'http://localhost:3000/uploads',
268
+ fileName: (file, req) => {
269
+ // Custom file name with timestamp
270
+ const timestamp = Date.now();
271
+ const ext = file.originalname.split('.').pop();
272
+ return `${timestamp}-${file.originalname}`;
273
+ },
274
+ },
275
+ })
276
+ ```
277
+
278
+ ### Custom Directory Structure
279
+
280
+ ```typescript
281
+ NestFileStorageModule.forRoot({
282
+ storage: FileStorageEnum.LOCAL,
283
+ localConfig: {
284
+ rootPath: './uploads',
285
+ baseUrl: 'http://localhost:3000/uploads',
286
+ fileDist: (file, req) => {
287
+ // Organize by year/month/day
288
+ const date = new Date();
289
+ return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
290
+ },
291
+ },
292
+ })
293
+ ```
294
+
295
+ ### Transform Uploaded File Object
296
+
297
+ ```typescript
298
+ NestFileStorageModule.forRoot({
299
+ storage: FileStorageEnum.S3,
300
+ s3Config: {
301
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
302
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
303
+ region: process.env.AWS_REGION,
304
+ bucket: process.env.AWS_BUCKET,
305
+ transformUploadedFileObject: (file) => {
306
+ // Return only specific fields
307
+ return {
308
+ key: file.key,
309
+ url: file.url,
310
+ size: file.size,
311
+ mimetype: file.mimetype,
312
+ };
313
+ },
314
+ },
315
+ })
316
+ ```
317
+
318
+ ### Custom File Mapping in Interceptor
319
+
320
+ ```typescript
321
+ @Post('upload')
322
+ @UseInterceptors(
323
+ FileStorageInterceptor('file', {
324
+ mapToRequestBody: (file, fieldName, req) => {
325
+ // Return full file object instead of just key
326
+ return file;
327
+ },
328
+ })
329
+ )
330
+ uploadFile(@Body() body: any) {
331
+ // body.file now contains the full file object
332
+ return {
333
+ message: 'File uploaded',
334
+ file: body.file,
335
+ };
336
+ }
337
+ ```
338
+
339
+ ### Async Configuration
340
+
341
+ ```typescript
342
+ // app.module.ts
343
+ NestFileStorageModule.forRootAsync({
344
+ imports: [ConfigModule],
345
+ useFactory: async (configService: ConfigService) => ({
346
+ storage: FileStorageEnum.S3,
347
+ s3Config: {
348
+ accessKeyId: configService.get('AWS_ACCESS_KEY_ID'),
349
+ secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY'),
350
+ region: configService.get('AWS_REGION'),
351
+ bucket: configService.get('AWS_BUCKET'),
352
+ },
353
+ }),
354
+ inject: [ConfigService],
355
+ })
356
+ ```
357
+
358
+ ### Dynamic Storage Type
359
+
360
+ ```typescript
361
+ // Override storage type per route
362
+ @Post('upload-to-s3')
363
+ @UseInterceptors(
364
+ FileStorageInterceptor('file', {
365
+ storageType: FileStorageEnum.S3,
366
+ })
367
+ )
368
+ uploadToS3(@Body() body: any) {
369
+ return { fileKey: body.file };
370
+ }
371
+ ```
372
+
373
+ ## 🔥 Complete Examples
374
+
375
+ ### Image Upload with Validation
376
+
377
+ ```typescript
378
+ import { Controller, Post, UseInterceptors, BadRequestException } from '@nestjs/common';
379
+ import { FileStorageInterceptor } from '@ackplus/nest-file-storage';
380
+
381
+ @Controller('images')
382
+ export class ImageController {
383
+ @Post('upload')
384
+ @UseInterceptors(
385
+ FileStorageInterceptor('image', {
386
+ fileName: (file, req) => {
387
+ // Validate image type
388
+ const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
389
+ if (!allowedTypes.includes(file.mimetype)) {
390
+ throw new BadRequestException('Only image files are allowed');
391
+ }
392
+
393
+ // Generate unique filename
394
+ const timestamp = Date.now();
395
+ const ext = file.originalname.split('.').pop();
396
+ return `image-${timestamp}.${ext}`;
397
+ },
398
+ fileDist: (file, req) => {
399
+ // Organize by year/month
400
+ const date = new Date();
401
+ return `images/${date.getFullYear()}/${date.getMonth() + 1}`;
402
+ },
403
+ })
404
+ )
405
+ async uploadImage(@Body() body: any) {
406
+ return {
407
+ message: 'Image uploaded successfully',
408
+ imageKey: body.image,
409
+ };
410
+ }
411
+ }
412
+ ```
413
+
414
+ ### User Avatar Upload
415
+
416
+ ```typescript
417
+ import { Controller, Post, UseInterceptors, Body } from '@nestjs/common';
418
+ import { FileStorageInterceptor, FileStorageService } from '@ackplus/nest-file-storage';
419
+
420
+ @Controller('users')
421
+ export class UserController {
422
+ constructor(private readonly userService: UserService) {}
423
+
424
+ @Post('avatar')
425
+ @UseInterceptors(
426
+ FileStorageInterceptor('avatar', {
427
+ fileName: (file, req) => {
428
+ const userId = req.user.id; // Assuming user from auth guard
429
+ const ext = file.originalname.split('.').pop();
430
+ return `avatar-${userId}.${ext}`;
431
+ },
432
+ fileDist: () => 'avatars',
433
+ })
434
+ )
435
+ async uploadAvatar(@Body() body: any, @Request() req) {
436
+ // Delete old avatar if exists
437
+ const user = await this.userService.findById(req.user.id);
438
+ if (user.avatarKey) {
439
+ const storage = await FileStorageService.getStorage();
440
+ await storage.deleteFile(user.avatarKey);
441
+ }
442
+
443
+ // Update user with new avatar
444
+ await this.userService.updateAvatar(req.user.id, body.avatar);
445
+
446
+ return {
447
+ message: 'Avatar updated successfully',
448
+ avatarKey: body.avatar,
449
+ };
450
+ }
451
+ }
452
+ ```
453
+
454
+ ### Document Management
455
+
456
+ ```typescript
457
+ import { Controller, Get, Post, Delete, Param, UseInterceptors, Body } from '@nestjs/common';
458
+ import { FileStorageInterceptor, FileStorageService } from '@ackplus/nest-file-storage';
459
+
460
+ @Controller('documents')
461
+ export class DocumentController {
462
+ @Post('upload')
463
+ @UseInterceptors(
464
+ FileStorageInterceptor({
465
+ type: 'array',
466
+ fieldName: 'documents',
467
+ maxCount: 10,
468
+ }, {
469
+ fileDist: () => 'documents',
470
+ mapToRequestBody: (files, fieldName) => {
471
+ // Return detailed file info
472
+ return files;
473
+ },
474
+ })
475
+ )
476
+ async uploadDocuments(@Body() body: any) {
477
+ return {
478
+ message: `${body.documents.length} documents uploaded`,
479
+ documents: body.documents,
480
+ };
481
+ }
482
+
483
+ @Get(':key/download')
484
+ async downloadDocument(@Param('key') key: string, @Res() res) {
485
+ const storage = await FileStorageService.getStorage();
486
+ const file = await storage.getFile(key);
487
+
488
+ res.setHeader('Content-Type', 'application/octet-stream');
489
+ res.setHeader('Content-Disposition', `attachment; filename="${key}"`);
490
+ res.send(file);
491
+ }
492
+
493
+ @Delete(':key')
494
+ async deleteDocument(@Param('key') key: string) {
495
+ const storage = await FileStorageService.getStorage();
496
+ await storage.deleteFile(key);
497
+
498
+ return { message: 'Document deleted successfully' };
499
+ }
500
+
501
+ @Get(':key/url')
502
+ async getDocumentUrl(@Param('key') key: string) {
503
+ const storage = await FileStorageService.getStorage();
504
+ const url = storage.getUrl(key);
505
+
506
+ return { url };
507
+ }
508
+ }
509
+ ```
510
+
511
+ ## 📚 API Reference
512
+
513
+ ### FileStorageService
514
+
515
+ ```typescript
516
+ class FileStorageService {
517
+ // Get storage instance
518
+ static async getStorage(storageType?: FileStorageEnum): Promise<Storage>
519
+
520
+ // Get module options
521
+ static getOptions(): FileStorageModuleOptions
522
+
523
+ // Set module options
524
+ static setOptions(options: FileStorageModuleOptions): void
525
+ }
526
+ ```
527
+
528
+ ### Storage Interface
529
+
530
+ ```typescript
531
+ interface Storage {
532
+ // Get file content as Buffer
533
+ getFile(key: string): Promise<Buffer> | Buffer
534
+
535
+ // Delete file
536
+ deleteFile(key: string): Promise<void> | void
537
+
538
+ // Upload file
539
+ putFile(fileContent: Buffer, key: string): Promise<UploadedFile> | UploadedFile
540
+
541
+ // Copy file
542
+ copyFile(oldKey: string, newKey: string): Promise<UploadedFile>
543
+
544
+ // Get file URL
545
+ getUrl(key: string): Promise<string> | string
546
+
547
+ // Get signed URL (S3 only)
548
+ getSignedUrl?(key: string, options: any): Promise<string> | string
549
+
550
+ // Get file path (Local only)
551
+ path?(filePath: string): Promise<string> | string
552
+ }
553
+ ```
554
+
555
+ ### FileStorageInterceptor
556
+
557
+ ```typescript
558
+ // Single file upload
559
+ FileStorageInterceptor(
560
+ fieldName: string,
561
+ options?: FileStorageInterceptorOptions
562
+ )
563
+
564
+ // Multiple files or fields
565
+ FileStorageInterceptor(
566
+ config: {
567
+ type: 'single' | 'array' | 'fields';
568
+ fieldName?: string;
569
+ maxCount?: number;
570
+ fields?: { name: string; maxCount?: number }[];
571
+ },
572
+ options?: FileStorageInterceptorOptions
573
+ )
574
+ ```
575
+
576
+ ### UploadedFile Interface
577
+
578
+ ```typescript
579
+ interface UploadedFile {
580
+ fieldName?: string; // Form field name
581
+ fileName: string; // Generated file name
582
+ originalName: string; // Original file name
583
+ size: number; // File size in bytes
584
+ mimetype?: string; // MIME type
585
+ buffer?: Buffer; // File buffer (optional)
586
+ key: string; // Storage key/path
587
+ url: string; // Public URL
588
+ fullPath: string; // Full storage path
589
+ encoding?: string; // File encoding
590
+ }
591
+ ```
592
+
593
+ ## 🧪 Testing
594
+
595
+ ```typescript
596
+ import { Test, TestingModule } from '@nestjs/testing';
597
+ import { NestFileStorageModule, FileStorageService, FileStorageEnum } from '@ackplus/nest-file-storage';
598
+
599
+ describe('FileService', () => {
600
+ let service: FileService;
601
+ let storage: Storage;
602
+
603
+ beforeEach(async () => {
604
+ const module: TestingModule = await Test.createTestingModule({
605
+ imports: [
606
+ NestFileStorageModule.forRoot({
607
+ storage: FileStorageEnum.LOCAL,
608
+ localConfig: {
609
+ rootPath: './test-uploads',
610
+ baseUrl: 'http://localhost:3000/test-uploads',
611
+ },
612
+ }),
613
+ ],
614
+ providers: [FileService],
615
+ }).compile();
616
+
617
+ service = module.get<FileService>(FileService);
618
+ storage = await FileStorageService.getStorage();
619
+ });
620
+
621
+ it('should upload file', async () => {
622
+ const buffer = Buffer.from('test content');
623
+ const result = await storage.putFile(buffer, 'test/file.txt');
624
+
625
+ expect(result.key).toBe('test/file.txt');
626
+ expect(result.size).toBeGreaterThan(0);
627
+ });
628
+
629
+ it('should delete file', async () => {
630
+ const buffer = Buffer.from('test content');
631
+ await storage.putFile(buffer, 'test/file.txt');
632
+
633
+ await storage.deleteFile('test/file.txt');
634
+
635
+ await expect(storage.getFile('test/file.txt')).rejects.toThrow();
636
+ });
637
+ });
638
+ ```
639
+
640
+ ## 🤝 Contributing
641
+
642
+ Contributions are welcome! Please feel free to submit a Pull Request.
643
+
644
+ ## 📄 License
645
+
646
+ This project is licensed under the MIT License.
647
+
648
+ ## 🙏 Acknowledgments
649
+
650
+ - Built with [NestJS](https://nestjs.com/)
651
+ - Uses [Multer](https://github.com/expressjs/multer) for file handling
652
+ - AWS S3 support via [@aws-sdk/client-s3](https://www.npmjs.com/package/@aws-sdk/client-s3)
653
+ - Azure support via [@azure/storage-blob](https://www.npmjs.com/package/@azure/storage-blob)
654
+
655
+ ## 📮 Support
656
+
657
+ If you have any questions or need help:
658
+ - Open an issue on [GitHub](https://github.com/ack-solutions/nest-file-storage/issues)
659
+ - Check the [examples](./examples/) directory
660
+
661
+ ---
662
+
663
+ Made with ❤️ for the NestJS community
@@ -2,4 +2,3 @@ export * from './lib/nest-file-storage.module';
2
2
  export * from './lib/file-storage.service';
3
3
  export * from './lib/interceptor/file-storage.interceptor';
4
4
  export * from './lib/types';
5
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./lib/nest-file-storage.module"), exports);
18
+ __exportStar(require("./lib/file-storage.service"), exports);
19
+ __exportStar(require("./lib/interceptor/file-storage.interceptor"), exports);
20
+ __exportStar(require("./lib/types"), exports);
21
+ //# sourceMappingURL=index.js.map