@ackplus/nest-file-storage 1.0.1 → 1.1.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 +6 -404
- package/eslint.config.mjs +22 -0
- package/jest.config.ts +10 -0
- package/package.json +5 -62
- package/project.json +38 -0
- package/{dist/index.d.ts → src/index.ts} +0 -1
- package/src/lib/constants.ts +1 -0
- package/src/lib/file-storage.service.ts +36 -0
- package/{dist/lib/index.d.ts → src/lib/index.ts} +0 -1
- package/{dist/lib/interceptor/file-storage.interceptor.js → src/lib/interceptor/file-storage.interceptor.ts} +70 -37
- package/src/lib/nest-file-storage.module.ts +78 -0
- package/src/lib/storage/azure.storage.ts +214 -0
- package/{dist/lib/storage/local.storage.js → src/lib/storage/local.storage.ts} +96 -82
- package/{dist/lib/storage/s3.storage.js → src/lib/storage/s3.storage.ts} +107 -96
- package/src/lib/storage.factory.ts +58 -0
- package/{dist/lib/types.d.ts → src/lib/types.ts} +35 -23
- package/tsconfig.json +17 -0
- package/tsconfig.lib.json +14 -0
- package/tsconfig.spec.json +15 -0
- package/LICENSE +0 -21
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -21
- package/dist/index.js.map +0 -1
- package/dist/lib/constants.d.ts +0 -2
- package/dist/lib/constants.d.ts.map +0 -1
- package/dist/lib/constants.js +0 -5
- package/dist/lib/constants.js.map +0 -1
- package/dist/lib/file-storage.service.d.ts +0 -8
- package/dist/lib/file-storage.service.d.ts.map +0 -1
- package/dist/lib/file-storage.service.js +0 -30
- package/dist/lib/file-storage.service.js.map +0 -1
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js +0 -22
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/interceptor/file-storage.interceptor.d.ts +0 -25
- package/dist/lib/interceptor/file-storage.interceptor.d.ts.map +0 -1
- package/dist/lib/interceptor/file-storage.interceptor.js.map +0 -1
- package/dist/lib/nest-file-storage.module.d.ts +0 -9
- package/dist/lib/nest-file-storage.module.d.ts.map +0 -1
- package/dist/lib/nest-file-storage.module.js +0 -80
- package/dist/lib/nest-file-storage.module.js.map +0 -1
- package/dist/lib/storage/azure.storage.d.ts +0 -19
- package/dist/lib/storage/azure.storage.d.ts.map +0 -1
- package/dist/lib/storage/azure.storage.js +0 -189
- package/dist/lib/storage/azure.storage.js.map +0 -1
- package/dist/lib/storage/local.storage.d.ts +0 -35
- package/dist/lib/storage/local.storage.d.ts.map +0 -1
- package/dist/lib/storage/local.storage.js.map +0 -1
- package/dist/lib/storage/s3.storage.d.ts +0 -20
- package/dist/lib/storage/s3.storage.d.ts.map +0 -1
- package/dist/lib/storage/s3.storage.js.map +0 -1
- package/dist/lib/storage.factory.d.ts +0 -9
- package/dist/lib/storage.factory.d.ts.map +0 -1
- package/dist/lib/storage.factory.js +0 -82
- package/dist/lib/storage.factory.js.map +0 -1
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js +0 -10
- package/dist/lib/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,409 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# nest-auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This library was generated with [Nx](https://nx.dev).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Building
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
npm install @ackplus/nest-file-storage
|
|
9
|
-
```
|
|
7
|
+
Run `nx build nest-auth` to build the library.
|
|
10
8
|
|
|
11
|
-
##
|
|
9
|
+
## Running unit tests
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### Local Storage
|
|
16
|
-
|
|
17
|
-
No additional dependencies required. Works out of the box.
|
|
18
|
-
|
|
19
|
-
### Azure Blob Storage
|
|
20
|
-
|
|
21
|
-
To use Azure Blob Storage, install the Azure SDK:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install @azure/storage-blob
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### AWS S3 Storage
|
|
28
|
-
|
|
29
|
-
To use AWS S3 Storage, install the AWS SDK:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Usage
|
|
36
|
-
|
|
37
|
-
The library supports two approaches: **Configuration-based** and **Class Factory**.
|
|
38
|
-
|
|
39
|
-
### Configuration-based Approach (Recommended)
|
|
40
|
-
|
|
41
|
-
This approach uses lazy loading and only loads the storage provider when needed.
|
|
42
|
-
|
|
43
|
-
#### Local Storage
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
|
|
47
|
-
|
|
48
|
-
@Module({
|
|
49
|
-
imports: [
|
|
50
|
-
NestFileStorageModule.forRoot({
|
|
51
|
-
storage: FileStorageEnum.LOCAL,
|
|
52
|
-
localConfig: {
|
|
53
|
-
destination: './uploads'
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
]
|
|
57
|
-
})
|
|
58
|
-
export class AppModule {}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
#### Azure Blob Storage
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
|
|
65
|
-
|
|
66
|
-
@Module({
|
|
67
|
-
imports: [
|
|
68
|
-
NestFileStorageModule.forRoot({
|
|
69
|
-
storage: FileStorageEnum.AZURE,
|
|
70
|
-
azureConfig: {
|
|
71
|
-
account: 'your-storage-account',
|
|
72
|
-
accountKey: 'your-account-key',
|
|
73
|
-
container: 'your-container'
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
]
|
|
77
|
-
})
|
|
78
|
-
export class AppModule {}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
#### AWS S3 Storage
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
|
|
85
|
-
|
|
86
|
-
@Module({
|
|
87
|
-
imports: [
|
|
88
|
-
NestFileStorageModule.forRoot({
|
|
89
|
-
storage: FileStorageEnum.S3,
|
|
90
|
-
s3Config: {
|
|
91
|
-
region: 'us-east-1',
|
|
92
|
-
bucket: 'your-bucket',
|
|
93
|
-
accessKeyId: 'your-access-key',
|
|
94
|
-
secretAccessKey: 'your-secret-key'
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
]
|
|
98
|
-
})
|
|
99
|
-
export class AppModule {}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Class Factory Approach
|
|
103
|
-
|
|
104
|
-
This approach allows you to provide your own storage class directly.
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
import { NestFileStorageModule } from '@ackplus/nest-file-storage';
|
|
108
|
-
|
|
109
|
-
@Module({
|
|
110
|
-
imports: [
|
|
111
|
-
NestFileStorageModule.forRoot({
|
|
112
|
-
storageFactory: async () => {
|
|
113
|
-
// Lazy load the storage class
|
|
114
|
-
const { AzureStorage } = await import('@ackplus/nest-file-storage/lib/storage/azure.storage');
|
|
115
|
-
return AzureStorage;
|
|
116
|
-
},
|
|
117
|
-
options: {
|
|
118
|
-
account: 'your-storage-account',
|
|
119
|
-
accountKey: 'your-account-key',
|
|
120
|
-
container: 'your-container'
|
|
121
|
-
}
|
|
122
|
-
})
|
|
123
|
-
]
|
|
124
|
-
})
|
|
125
|
-
export class AppModule {}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
#### Custom Storage Class
|
|
129
|
-
|
|
130
|
-
You can also provide your own custom storage implementation:
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
import { NestFileStorageModule, Storage } from '@ackplus/nest-file-storage';
|
|
134
|
-
|
|
135
|
-
class CustomStorage implements Storage {
|
|
136
|
-
// Implement your custom storage logic
|
|
137
|
-
async getFile(key: string): Promise<Buffer> { /* ... */ }
|
|
138
|
-
async deleteFile(key: string): Promise<void> { /* ... */ }
|
|
139
|
-
async putFile(fileContent: Buffer, key: string): Promise<UploadedFile> { /* ... */ }
|
|
140
|
-
getUrl(key: string): string { /* ... */ }
|
|
141
|
-
async copyFile(oldKey: string, newKey: string): Promise<UploadedFile> { /* ... */ }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
@Module({
|
|
145
|
-
imports: [
|
|
146
|
-
NestFileStorageModule.forRoot({
|
|
147
|
-
storageFactory: () => CustomStorage,
|
|
148
|
-
options: {
|
|
149
|
-
// Your custom options
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
]
|
|
153
|
-
})
|
|
154
|
-
export class AppModule {}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### When to Use Each Approach
|
|
158
|
-
|
|
159
|
-
**Configuration-based Approach:**
|
|
160
|
-
- ✅ Recommended for most use cases
|
|
161
|
-
- ✅ Automatic lazy loading
|
|
162
|
-
- ✅ Built-in error handling for missing dependencies
|
|
163
|
-
- ✅ Simpler configuration
|
|
164
|
-
- ✅ Better for switching between providers
|
|
165
|
-
- ✅ Supports async configuration with dependency injection
|
|
166
|
-
|
|
167
|
-
**Class Factory Approach:**
|
|
168
|
-
- ✅ More control over storage instantiation
|
|
169
|
-
- ✅ Custom storage implementations
|
|
170
|
-
- ✅ Advanced use cases
|
|
171
|
-
- ✅ Still supports lazy loading if implemented correctly
|
|
172
|
-
- ⚠️ More complex configuration
|
|
173
|
-
- ⚠️ Manual dependency management
|
|
174
|
-
|
|
175
|
-
**Async Configuration (forRootAsync):**
|
|
176
|
-
- ✅ Full dependency injection support
|
|
177
|
-
- ✅ `useFactory`, `useClass`, and `useExisting` patterns
|
|
178
|
-
- ✅ Integration with ConfigService and other providers
|
|
179
|
-
- ✅ Environment-based configuration
|
|
180
|
-
- ✅ Perfect for complex application setups
|
|
181
|
-
|
|
182
|
-
### Async Configuration (forRootAsync)
|
|
183
|
-
|
|
184
|
-
For more advanced scenarios, you can use `forRootAsync` with dependency injection:
|
|
185
|
-
|
|
186
|
-
#### Using useFactory
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
import { NestFileStorageModule, FileStorageEnum } from '@ackplus/nest-file-storage';
|
|
190
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
191
|
-
|
|
192
|
-
@Module({
|
|
193
|
-
imports: [
|
|
194
|
-
ConfigModule,
|
|
195
|
-
NestFileStorageModule.forRootAsync({
|
|
196
|
-
imports: [ConfigModule],
|
|
197
|
-
useFactory: async (configService: ConfigService) => ({
|
|
198
|
-
storage: FileStorageEnum.S3,
|
|
199
|
-
s3Config: {
|
|
200
|
-
region: configService.get('AWS_REGION'),
|
|
201
|
-
bucket: configService.get('AWS_BUCKET'),
|
|
202
|
-
accessKeyId: configService.get('AWS_ACCESS_KEY_ID'),
|
|
203
|
-
secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY'),
|
|
204
|
-
}
|
|
205
|
-
}),
|
|
206
|
-
inject: [ConfigService],
|
|
207
|
-
})
|
|
208
|
-
]
|
|
209
|
-
})
|
|
210
|
-
export class AppModule {}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
#### Using useClass
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
import { Injectable } from '@nestjs/common';
|
|
217
|
-
import { NestFileStorageModule, FileStorageOptionsFactory, FileStorageModuleOptions, FileStorageEnum } from '@ackplus/nest-file-storage';
|
|
218
|
-
import { ConfigService } from '@nestjs/config';
|
|
219
|
-
|
|
220
|
-
@Injectable()
|
|
221
|
-
export class FileStorageConfigService implements FileStorageOptionsFactory {
|
|
222
|
-
constructor(private configService: ConfigService) {}
|
|
223
|
-
|
|
224
|
-
createFileStorageOptions(): FileStorageModuleOptions {
|
|
225
|
-
return {
|
|
226
|
-
storage: FileStorageEnum.AZURE,
|
|
227
|
-
azureConfig: {
|
|
228
|
-
account: this.configService.get('AZURE_STORAGE_ACCOUNT'),
|
|
229
|
-
accountKey: this.configService.get('AZURE_STORAGE_KEY'),
|
|
230
|
-
container: this.configService.get('AZURE_STORAGE_CONTAINER'),
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
@Module({
|
|
237
|
-
imports: [
|
|
238
|
-
ConfigModule,
|
|
239
|
-
NestFileStorageModule.forRootAsync({
|
|
240
|
-
imports: [ConfigModule],
|
|
241
|
-
useClass: FileStorageConfigService,
|
|
242
|
-
})
|
|
243
|
-
]
|
|
244
|
-
})
|
|
245
|
-
export class AppModule {}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
#### Using useExisting
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
@Module({
|
|
252
|
-
imports: [
|
|
253
|
-
ConfigModule,
|
|
254
|
-
NestFileStorageModule.forRootAsync({
|
|
255
|
-
imports: [ConfigModule],
|
|
256
|
-
useExisting: FileStorageConfigService,
|
|
257
|
-
})
|
|
258
|
-
],
|
|
259
|
-
providers: [FileStorageConfigService]
|
|
260
|
-
})
|
|
261
|
-
export class AppModule {}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Direct Usage with Storage Factory
|
|
265
|
-
|
|
266
|
-
You can also use the storage factory directly for more control:
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
import { StorageFactory, FileStorageEnum } from '@ackplus/nest-file-storage';
|
|
270
|
-
|
|
271
|
-
// This will lazy load only the Azure storage provider
|
|
272
|
-
const azureStorage = await StorageFactory.createStorage(FileStorageEnum.AZURE, {
|
|
273
|
-
account: 'your-storage-account',
|
|
274
|
-
accountKey: 'your-account-key',
|
|
275
|
-
container: 'your-container'
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// Use the storage instance
|
|
279
|
-
const uploadedFile = await azureStorage.putFile(buffer, 'path/to/file.jpg');
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## Flexible File Mapping
|
|
283
|
-
|
|
284
|
-
The library includes flexible file mapping functionality that allows you to define custom logic for how uploaded files are transformed and stored in the request body.
|
|
285
|
-
|
|
286
|
-
**Default Behavior**: Without any configuration, uploaded files are automatically mapped to their storage key (path) in the request body.
|
|
287
|
-
|
|
288
|
-
### Default Behavior (No Configuration)
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
import { FileStorageInterceptor } from '@ackplus/nest-file-storage';
|
|
292
|
-
|
|
293
|
-
@Controller('upload')
|
|
294
|
-
export class UploadController {
|
|
295
|
-
@Post('document')
|
|
296
|
-
@UseInterceptors(FileStorageInterceptor('document'))
|
|
297
|
-
async uploadDocument(@Body() body: any) {
|
|
298
|
-
// body.document will contain the file key (storage path)
|
|
299
|
-
console.log(body.document); // "documents/2024/1/1234567890-resume.pdf"
|
|
300
|
-
return { message: 'Document uploaded', data: body };
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Return File URL String (Custom Logic)
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
@Post('avatar')
|
|
309
|
-
@UseInterceptors(FileStorageInterceptor('avatar', {
|
|
310
|
-
mapToRequestBody: (file, fieldName, req) => {
|
|
311
|
-
// Return just the URL string for direct DB storage
|
|
312
|
-
return file.url;
|
|
313
|
-
}
|
|
314
|
-
}))
|
|
315
|
-
async uploadAvatar(@Body() body: any) {
|
|
316
|
-
// body.avatar will be a string URL
|
|
317
|
-
console.log(body.avatar); // "http://localhost:3000/uploads/images/avatar.jpg"
|
|
318
|
-
return { message: 'Avatar uploaded', data: body };
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Return Custom Object with Business Logic
|
|
323
|
-
|
|
324
|
-
```typescript
|
|
325
|
-
@Post('document')
|
|
326
|
-
@UseInterceptors(FileStorageInterceptor('document', {
|
|
327
|
-
mapToRequestBody: (file, fieldName, req) => {
|
|
328
|
-
// Return custom object with business logic
|
|
329
|
-
return {
|
|
330
|
-
fileId: `file_${Date.now()}`,
|
|
331
|
-
url: file.url,
|
|
332
|
-
originalName: file.originalName,
|
|
333
|
-
uploadedBy: req.user?.id || 'anonymous',
|
|
334
|
-
uploadedAt: new Date().toISOString(),
|
|
335
|
-
isPublic: req.body.isPublic === 'true'
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
}))
|
|
339
|
-
async uploadDocument(@Body() body: any) {
|
|
340
|
-
// body.document will be a custom object
|
|
341
|
-
console.log(body.document);
|
|
342
|
-
return { message: 'Document uploaded', data: body };
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
### Multiple Files with Custom Logic
|
|
347
|
-
|
|
348
|
-
```typescript
|
|
349
|
-
@Post('gallery')
|
|
350
|
-
@UseInterceptors(FileStorageInterceptor({
|
|
351
|
-
type: 'array',
|
|
352
|
-
fieldName: 'images',
|
|
353
|
-
maxCount: 5
|
|
354
|
-
}, {
|
|
355
|
-
mapToRequestBody: (files, fieldName, req) => {
|
|
356
|
-
// Return array of custom objects
|
|
357
|
-
return files.map((file, index) => ({
|
|
358
|
-
id: `img_${Date.now()}_${index}`,
|
|
359
|
-
url: file.url,
|
|
360
|
-
isPrimary: index === 0,
|
|
361
|
-
alt: req.body.imageAlts?.[index] || `Image ${index + 1}`
|
|
362
|
-
}));
|
|
363
|
-
}
|
|
364
|
-
}))
|
|
365
|
-
async uploadGallery(@Body() body: any) {
|
|
366
|
-
// body.images will be an array of custom objects
|
|
367
|
-
console.log(body.images);
|
|
368
|
-
return { message: 'Gallery uploaded', data: body };
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
**Key Features**:
|
|
373
|
-
- **Return anything**: String, object, array, or custom structure
|
|
374
|
-
- **Access request data**: Use `req` parameter for user info, body data, etc.
|
|
375
|
-
- **Field-specific logic**: Use `fieldName` to handle different fields differently
|
|
376
|
-
- **Business logic**: Implement any custom transformation you need
|
|
377
|
-
|
|
378
|
-
For detailed examples, see [FILE_KEY_MAPPING.md](./docs/FILE_KEY_MAPPING.md).
|
|
379
|
-
|
|
380
|
-
## Error Handling
|
|
381
|
-
|
|
382
|
-
If you try to use a storage provider without installing its required dependencies, you'll get a clear error message:
|
|
383
|
-
|
|
384
|
-
- **Azure Storage**: `Azure Storage SDK (@azure/storage-blob) is required when using AzureStorage. Please install it: npm install @azure/storage-blob`
|
|
385
|
-
- **S3 Storage**: `AWS SDK (@aws-sdk/client-s3 and @aws-sdk/s3-request-presigner) is required when using S3Storage. Please install them: npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner`
|
|
386
|
-
|
|
387
|
-
## How Lazy Loading Works
|
|
388
|
-
|
|
389
|
-
The library uses dynamic imports to load storage providers only when they're actually needed:
|
|
390
|
-
|
|
391
|
-
1. **At build time**: Only the storage factory and types are bundled
|
|
392
|
-
2. **At runtime**: When you use a storage provider, it's dynamically imported
|
|
393
|
-
3. **Caching**: Once loaded, storage instances are cached for reuse
|
|
394
|
-
4. **Error handling**: Missing dependencies are caught and provide clear error messages
|
|
395
|
-
|
|
396
|
-
This means:
|
|
397
|
-
- If you only use local storage, Azure/S3 code is never loaded
|
|
398
|
-
- If you only use Azure storage, S3 code is never loaded
|
|
399
|
-
- Your bundle size stays minimal regardless of how many storage providers are available
|
|
400
|
-
|
|
401
|
-
## Benefits
|
|
402
|
-
|
|
403
|
-
- **Lazy Loading**: Storage providers are only loaded when actually used
|
|
404
|
-
- **Smaller bundle size**: Only install the dependencies you need
|
|
405
|
-
- **Flexible**: Switch between storage providers easily
|
|
406
|
-
- **Clear error messages**: Know exactly what to install if a dependency is missing
|
|
407
|
-
- **TypeScript support**: Full type safety for all storage providers
|
|
408
|
-
- **Caching**: Storage instances are cached to avoid repeated initialization
|
|
409
|
-
- **Zero overhead**: Unused storage providers don't affect your application
|
|
11
|
+
Run `nx test nest-auth` to execute the unit tests via [Jest](https://jestjs.io).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import baseConfig from '../../eslint.base.config';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
...baseConfig,
|
|
5
|
+
{
|
|
6
|
+
files: ['**/*.json'],
|
|
7
|
+
rules: {
|
|
8
|
+
'@nx/dependency-checks': [
|
|
9
|
+
'error',
|
|
10
|
+
{
|
|
11
|
+
ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}'],
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
languageOptions: {
|
|
16
|
+
parser: await import('jsonc-eslint-parser'),
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
ignores: ['**/out-tsc'],
|
|
21
|
+
},
|
|
22
|
+
];
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
displayName: 'nest-file-storage',
|
|
3
|
+
preset: '../../jest.preset.js',
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
transform: {
|
|
6
|
+
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
7
|
+
},
|
|
8
|
+
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
9
|
+
coverageDirectory: '../../coverage/packages/nest-file-storage',
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,67 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ackplus/nest-file-storage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"type": "commonjs",
|
|
5
|
-
"main": "./
|
|
6
|
-
"types": "./
|
|
7
|
-
"files": [
|
|
8
|
-
"dist"
|
|
9
|
-
],
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "https://github.com/ack-solutions/packages.git"
|
|
14
|
-
},
|
|
15
|
-
"publishConfig": {
|
|
16
|
-
"access": "public"
|
|
17
|
-
},
|
|
18
|
-
"homepage": "https://github.com/ack-solutions/packages.git#readme",
|
|
19
|
-
"peerDependencies": {
|
|
20
|
-
"typeorm": "^0.3.23",
|
|
21
|
-
"@nestjs/typeorm": "^11.0.0",
|
|
22
|
-
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
23
|
-
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
24
|
-
"@azure/storage-blob": "^12.0.0",
|
|
25
|
-
"@aws-sdk/client-s3": "^3.0.0",
|
|
26
|
-
"@aws-sdk/s3-request-presigner": "^3.0.0"
|
|
27
|
-
},
|
|
28
|
-
"peerDependenciesMeta": {
|
|
29
|
-
"@azure/storage-blob": {
|
|
30
|
-
"optional": true
|
|
31
|
-
},
|
|
32
|
-
"@aws-sdk/client-s3": {
|
|
33
|
-
"optional": true
|
|
34
|
-
},
|
|
35
|
-
"@aws-sdk/s3-request-presigner": {
|
|
36
|
-
"optional": true
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"typeorm": "^0.3.23",
|
|
41
|
-
"@nestjs/typeorm": "^11.0.0",
|
|
42
|
-
"@nestjs/common": "^11.1.3",
|
|
43
|
-
"@nestjs/core": "^11.1.3",
|
|
44
|
-
"@types/multer": "^2.0.0",
|
|
45
|
-
"@types/node": "^20.0.0",
|
|
46
|
-
"@types/uuid": "^9.0.0",
|
|
47
|
-
"@types/concat-stream": "^2.0.0"
|
|
48
|
-
},
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
49
7
|
"dependencies": {
|
|
50
|
-
"tslib": "^2.3.0"
|
|
51
|
-
"deepmerge": "4.3.1",
|
|
52
|
-
"class-transformer": "^0.5.1",
|
|
53
|
-
"class-validator": "^0.14.1",
|
|
54
|
-
"pluralize": "8.0.0",
|
|
55
|
-
"lodash": "^4.17.21",
|
|
56
|
-
"rxjs": "^7.8.0",
|
|
57
|
-
"multer": "^2.0.1",
|
|
58
|
-
"moment": "^2.30.1",
|
|
59
|
-
"uuid": "^9.0.0",
|
|
60
|
-
"concat-stream": "^2.0.0"
|
|
61
|
-
},
|
|
62
|
-
"scripts": {
|
|
63
|
-
"build": "pnpm run clean && tsc -p tsconfig.lib.json",
|
|
64
|
-
"clean": "rimraf dist",
|
|
65
|
-
"dev": "tsc -p tsconfig.lib.json --watch --preserveWatchOutput"
|
|
8
|
+
"tslib": "^2.3.0"
|
|
66
9
|
}
|
|
67
|
-
}
|
|
10
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nest-file-storage",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/nest-file-storage/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"release": {
|
|
7
|
+
"version": {
|
|
8
|
+
"manifestRootsToUpdate": [
|
|
9
|
+
"dist/{projectRoot}"
|
|
10
|
+
],
|
|
11
|
+
"currentVersionResolver": "git-tag",
|
|
12
|
+
"fallbackCurrentVersionResolver": "disk"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"tags": [],
|
|
16
|
+
"targets": {
|
|
17
|
+
"build": {
|
|
18
|
+
"executor": "@nx/js:tsc",
|
|
19
|
+
"outputs": [
|
|
20
|
+
"{options.outputPath}"
|
|
21
|
+
],
|
|
22
|
+
"options": {
|
|
23
|
+
"outputPath": "dist/packages/nest-file-storage",
|
|
24
|
+
"tsConfig": "packages/nest-file-storage/tsconfig.lib.json",
|
|
25
|
+
"packageJson": "packages/nest-file-storage/package.json",
|
|
26
|
+
"main": "packages/nest-file-storage/src/index.ts",
|
|
27
|
+
"assets": [
|
|
28
|
+
"packages/nest-file-storage/*.md"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"nx-release-publish": {
|
|
33
|
+
"options": {
|
|
34
|
+
"packageRoot": "dist/{projectRoot}"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const FILE_STORAGE_OPTIONS = 'FileStorageOptions';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { StorageFactory } from './storage.factory';
|
|
2
|
+
import { FileStorageEnum, FileStorageModuleOptions, FileStorageConfigOptions, FileStorageClassOptions } from './types';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class FileStorageService {
|
|
6
|
+
|
|
7
|
+
private static options: FileStorageModuleOptions; // ✅ Static global property
|
|
8
|
+
|
|
9
|
+
static setOptions(options: FileStorageModuleOptions) {
|
|
10
|
+
FileStorageService.options = options;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static getOptions(): FileStorageModuleOptions {
|
|
14
|
+
return FileStorageService.options;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static async getStorage(storageType?: FileStorageEnum) {
|
|
18
|
+
const options = this.getOptions();
|
|
19
|
+
|
|
20
|
+
// Check if it's a class factory approach
|
|
21
|
+
if ('storageFactory' in options) {
|
|
22
|
+
const classOptions = options as FileStorageClassOptions;
|
|
23
|
+
const StorageClass = await classOptions.storageFactory();
|
|
24
|
+
return new StorageClass(classOptions.options);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Configuration-based approach
|
|
28
|
+
const configOptions = options as FileStorageConfigOptions;
|
|
29
|
+
if (!storageType) {
|
|
30
|
+
storageType = configOptions.storage;
|
|
31
|
+
}
|
|
32
|
+
const config = (configOptions as any)[`Config`];
|
|
33
|
+
return await StorageFactory.createStorage(storageType, config);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|