@flusys/nestjs-storage 7.1.0 → 8.0.0
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/config/index.d.ts +3 -3
- package/controllers/file-manager.controller.d.ts +4 -4
- package/controllers/folder.controller.d.ts +2 -2
- package/controllers/index.d.ts +4 -4
- package/controllers/storage-config.controller.d.ts +2 -2
- package/controllers/upload.controller.d.ts +3 -3
- package/docs/index.d.ts +1 -1
- package/docs/storage-swagger.config.d.ts +2 -2
- package/dtos/index.d.ts +4 -4
- package/entities/file-manager-with-company.entity.d.ts +2 -2
- package/entities/file-manager.entity.d.ts +1 -1
- package/entities/folder-with-company.entity.d.ts +1 -1
- package/entities/index.d.ts +15 -15
- package/entities/storage-config-with-company.entity.d.ts +1 -1
- package/enums/index.d.ts +1 -1
- package/fesm/493.js +2768 -0
- package/fesm/537.js +1157 -0
- package/fesm/562.js +786 -0
- package/fesm/{providers/azure-provider.optional.js → chunks/190.js} +33 -30
- package/fesm/chunks/252.js +12 -0
- package/fesm/chunks/327.js +12 -0
- package/fesm/chunks/385.js +12 -0
- package/fesm/{providers/s3-provider.optional.js → chunks/591.js} +37 -34
- package/fesm/chunks/746.js +12 -0
- package/fesm/chunks/798.js +12 -0
- package/fesm/{providers/sftp-provider.optional.js → chunks/918.js} +35 -31
- package/fesm/config/index.js +119 -3
- package/fesm/controllers/index.js +16 -4
- package/fesm/docs/index.js +206 -1
- package/fesm/dtos/index.js +879 -4
- package/fesm/entities/index.js +463 -18
- package/fesm/enums/index.js +36 -1
- package/fesm/index.js +398 -12
- package/fesm/interfaces/index.js +19 -5
- package/fesm/modules/index.js +16 -1
- package/fesm/providers/index.js +364 -3
- package/fesm/runtime.js +252 -0
- package/fesm/services/index.js +16 -6
- package/fesm/utils/index.js +149 -1
- package/index.d.ts +11 -11
- package/interfaces/file-manager.interface.d.ts +1 -1
- package/interfaces/folder.interface.d.ts +1 -1
- package/interfaces/index.d.ts +5 -5
- package/interfaces/storage-config.interface.d.ts +1 -1
- package/interfaces/storage-module-options.interface.d.ts +3 -3
- package/interfaces/storage-provider.interface.d.ts +1 -1
- package/middlewares/file-serve.middleware.d.ts +4 -3
- package/middlewares/index.d.ts +1 -1
- package/modules/index.d.ts +1 -1
- package/modules/storage.module.d.ts +2 -2
- package/package.json +30 -41
- package/providers/azure-provider.optional.d.ts +2 -2
- package/providers/index.d.ts +3 -3
- package/providers/local-provider.d.ts +2 -2
- package/providers/s3-provider.optional.d.ts +2 -2
- package/providers/sftp-provider.optional.d.ts +2 -2
- package/providers/storage-factory.service.d.ts +3 -3
- package/providers/storage-provider.registry.d.ts +2 -2
- package/services/file-manager.service.d.ts +9 -8
- package/services/folder.service.d.ts +6 -6
- package/services/index.d.ts +6 -6
- package/services/storage-config.service.d.ts +3 -3
- package/services/storage-datasource.provider.d.ts +3 -3
- package/services/storage-provider-config.service.d.ts +7 -7
- package/services/upload.service.d.ts +6 -6
- package/utils/image-compressor.util.d.ts +1 -1
- package/utils/index.d.ts +1 -1
- package/cjs/config/event-actions.js +0 -34
- package/cjs/config/index.js +0 -20
- package/cjs/config/message-keys.js +0 -46
- package/cjs/config/storage.constants.js +0 -28
- package/cjs/controllers/file-manager.controller.js +0 -152
- package/cjs/controllers/file-manager.controller.spec.js +0 -135
- package/cjs/controllers/folder.controller.js +0 -102
- package/cjs/controllers/folder.controller.spec.js +0 -86
- package/cjs/controllers/index.js +0 -21
- package/cjs/controllers/storage-config.controller.js +0 -102
- package/cjs/controllers/storage-config.controller.spec.js +0 -85
- package/cjs/controllers/upload.controller.js +0 -234
- package/cjs/controllers/upload.controller.spec.js +0 -132
- package/cjs/docs/index.js +0 -11
- package/cjs/docs/storage-swagger.config.js +0 -188
- package/cjs/docs/storage-swagger.config.spec.js +0 -72
- package/cjs/dtos/file-manager.dto.js +0 -327
- package/cjs/dtos/folder.dto.js +0 -105
- package/cjs/dtos/index.js +0 -21
- package/cjs/dtos/storage-config.dto.js +0 -170
- package/cjs/dtos/upload.dto.js +0 -272
- package/cjs/entities/file-manager-with-company.entity.js +0 -61
- package/cjs/entities/file-manager.entity.js +0 -122
- package/cjs/entities/folder-with-company.entity.js +0 -55
- package/cjs/entities/folder.entity.js +0 -64
- package/cjs/entities/index.js +0 -63
- package/cjs/entities/index.spec.js +0 -18
- package/cjs/entities/storage-config-with-company.entity.js +0 -51
- package/cjs/entities/storage-config.entity.js +0 -96
- package/cjs/enums/file-location.enum.js +0 -17
- package/cjs/enums/index.js +0 -18
- package/cjs/index.js +0 -29
- package/cjs/interfaces/file-manager.interface.js +0 -4
- package/cjs/interfaces/folder.interface.js +0 -4
- package/cjs/interfaces/index.js +0 -22
- package/cjs/interfaces/storage-config.interface.js +0 -4
- package/cjs/interfaces/storage-module-options.interface.js +0 -4
- package/cjs/interfaces/storage-provider.interface.js +0 -4
- package/cjs/middlewares/file-serve.middleware.js +0 -241
- package/cjs/middlewares/file-serve.middleware.spec.js +0 -211
- package/cjs/middlewares/index.js +0 -18
- package/cjs/modules/index.js +0 -18
- package/cjs/modules/storage.module.js +0 -165
- package/cjs/modules/storage.module.spec.js +0 -184
- package/cjs/providers/azure-provider.optional.js +0 -155
- package/cjs/providers/azure-provider.optional.spec.js +0 -228
- package/cjs/providers/index.js +0 -26
- package/cjs/providers/local-provider.js +0 -230
- package/cjs/providers/local-provider.spec.js +0 -239
- package/cjs/providers/s3-provider.optional.js +0 -175
- package/cjs/providers/s3-provider.optional.spec.js +0 -243
- package/cjs/providers/sftp-provider.optional.js +0 -203
- package/cjs/providers/sftp-provider.optional.spec.js +0 -217
- package/cjs/providers/storage-factory.service.js +0 -175
- package/cjs/providers/storage-factory.service.spec.js +0 -253
- package/cjs/providers/storage-provider.registry.js +0 -41
- package/cjs/providers/storage-provider.registry.spec.js +0 -67
- package/cjs/services/file-manager.service.js +0 -387
- package/cjs/services/file-manager.service.spec.js +0 -580
- package/cjs/services/folder.service.js +0 -101
- package/cjs/services/folder.service.spec.js +0 -167
- package/cjs/services/index.js +0 -23
- package/cjs/services/storage-config.service.js +0 -129
- package/cjs/services/storage-config.service.spec.js +0 -257
- package/cjs/services/storage-datasource.provider.js +0 -137
- package/cjs/services/storage-datasource.provider.spec.js +0 -217
- package/cjs/services/storage-provider-config.service.js +0 -171
- package/cjs/services/storage-provider-config.service.spec.js +0 -265
- package/cjs/services/upload.service.js +0 -376
- package/cjs/services/upload.service.spec.js +0 -426
- package/cjs/utils/file-validator.util.js +0 -440
- package/cjs/utils/file-validator.util.spec.js +0 -259
- package/cjs/utils/image-compressor.util.js +0 -162
- package/cjs/utils/image-compressor.util.spec.js +0 -166
- package/cjs/utils/index.js +0 -18
- package/fesm/config/event-actions.js +0 -13
- package/fesm/config/message-keys.js +0 -22
- package/fesm/config/storage.constants.js +0 -7
- package/fesm/controllers/file-manager.controller.js +0 -142
- package/fesm/controllers/file-manager.controller.spec.js +0 -131
- package/fesm/controllers/folder.controller.js +0 -92
- package/fesm/controllers/folder.controller.spec.js +0 -82
- package/fesm/controllers/storage-config.controller.js +0 -92
- package/fesm/controllers/storage-config.controller.spec.js +0 -81
- package/fesm/controllers/upload.controller.js +0 -224
- package/fesm/controllers/upload.controller.spec.js +0 -128
- package/fesm/docs/storage-swagger.config.js +0 -181
- package/fesm/docs/storage-swagger.config.spec.js +0 -68
- package/fesm/dtos/file-manager.dto.js +0 -300
- package/fesm/dtos/folder.dto.js +0 -84
- package/fesm/dtos/storage-config.dto.js +0 -149
- package/fesm/dtos/upload.dto.js +0 -245
- package/fesm/entities/file-manager-with-company.entity.js +0 -51
- package/fesm/entities/file-manager.entity.js +0 -112
- package/fesm/entities/folder-with-company.entity.js +0 -45
- package/fesm/entities/folder.entity.js +0 -54
- package/fesm/entities/index.spec.js +0 -14
- package/fesm/entities/storage-config-with-company.entity.js +0 -41
- package/fesm/entities/storage-config.entity.js +0 -86
- package/fesm/enums/file-location.enum.js +0 -7
- package/fesm/interfaces/file-manager.interface.js +0 -1
- package/fesm/interfaces/folder.interface.js +0 -1
- package/fesm/interfaces/storage-config.interface.js +0 -1
- package/fesm/interfaces/storage-module-options.interface.js +0 -3
- package/fesm/interfaces/storage-provider.interface.js +0 -4
- package/fesm/middlewares/file-serve.middleware.js +0 -190
- package/fesm/middlewares/file-serve.middleware.spec.js +0 -207
- package/fesm/middlewares/index.js +0 -1
- package/fesm/modules/storage.module.js +0 -156
- package/fesm/modules/storage.module.spec.js +0 -180
- package/fesm/providers/azure-provider.optional.spec.js +0 -224
- package/fesm/providers/local-provider.js +0 -182
- package/fesm/providers/local-provider.spec.js +0 -194
- package/fesm/providers/s3-provider.optional.spec.js +0 -239
- package/fesm/providers/sftp-provider.optional.spec.js +0 -213
- package/fesm/providers/storage-factory.service.js +0 -124
- package/fesm/providers/storage-factory.service.spec.js +0 -249
- package/fesm/providers/storage-provider.registry.js +0 -34
- package/fesm/providers/storage-provider.registry.spec.js +0 -63
- package/fesm/services/file-manager.service.js +0 -336
- package/fesm/services/file-manager.service.spec.js +0 -576
- package/fesm/services/folder.service.js +0 -91
- package/fesm/services/folder.service.spec.js +0 -163
- package/fesm/services/storage-config.service.js +0 -119
- package/fesm/services/storage-config.service.spec.js +0 -253
- package/fesm/services/storage-datasource.provider.js +0 -86
- package/fesm/services/storage-datasource.provider.spec.js +0 -172
- package/fesm/services/storage-provider-config.service.js +0 -161
- package/fesm/services/storage-provider-config.service.spec.js +0 -261
- package/fesm/services/upload.service.js +0 -366
- package/fesm/services/upload.service.spec.js +0 -422
- package/fesm/utils/file-validator.util.js +0 -433
- package/fesm/utils/file-validator.util.spec.js +0 -255
- package/fesm/utils/image-compressor.util.js +0 -114
- package/fesm/utils/image-compressor.util.spec.js +0 -162
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
import { CacheModule, UtilsModule, createModuleEventsProvider } from '@flusys/nestjs-shared/modules';
|
|
8
|
-
import { Logger, Module, RequestMethod } from '@nestjs/common';
|
|
9
|
-
import { FileServeMiddleware } from '../middlewares';
|
|
10
|
-
import { StorageConfigService } from '../services';
|
|
11
|
-
import { STORAGE_MODULE_OPTIONS } from '../config/storage.constants';
|
|
12
|
-
import { FileManagerController, FolderController, StorageConfigController, UploadController } from '../controllers';
|
|
13
|
-
import { FileLocationEnum } from '../enums/file-location.enum';
|
|
14
|
-
import { StorageFactoryService, StorageProviderRegistry } from '../providers';
|
|
15
|
-
import { LocalProvider } from '../providers/local-provider';
|
|
16
|
-
import { FileManagerService, FolderService, StorageDataSourceProvider, UploadService } from '../services';
|
|
17
|
-
import { StorageProviderConfigService } from '../services/storage-provider-config.service';
|
|
18
|
-
const logger = new Logger('StorageModule');
|
|
19
|
-
const CONTROLLERS = [
|
|
20
|
-
FileManagerController,
|
|
21
|
-
FolderController,
|
|
22
|
-
StorageConfigController,
|
|
23
|
-
UploadController
|
|
24
|
-
];
|
|
25
|
-
const EXPORTED_SERVICES = [
|
|
26
|
-
StorageConfigService,
|
|
27
|
-
StorageDataSourceProvider,
|
|
28
|
-
FileManagerService,
|
|
29
|
-
FolderService,
|
|
30
|
-
StorageProviderConfigService,
|
|
31
|
-
UploadService,
|
|
32
|
-
StorageFactoryService
|
|
33
|
-
];
|
|
34
|
-
// Register built-in provider
|
|
35
|
-
StorageProviderRegistry.register(FileLocationEnum.LOCAL, LocalProvider);
|
|
36
|
-
logger.log('Registered LocalProvider');
|
|
37
|
-
// Register optional providers (skip if dependencies not installed)
|
|
38
|
-
const OPTIONAL_PROVIDERS = [
|
|
39
|
-
{
|
|
40
|
-
location: FileLocationEnum.AWS,
|
|
41
|
-
path: '../providers/s3-provider.optional',
|
|
42
|
-
name: 'S3Provider',
|
|
43
|
-
dep: '@aws-sdk/client-s3'
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
location: FileLocationEnum.AZURE,
|
|
47
|
-
path: '../providers/azure-provider.optional',
|
|
48
|
-
name: 'AzureProvider',
|
|
49
|
-
dep: '@azure/storage-blob'
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
location: FileLocationEnum.SFTP,
|
|
53
|
-
path: '../providers/sftp-provider.optional',
|
|
54
|
-
name: 'SftpProvider',
|
|
55
|
-
dep: 'ssh2-sftp-client'
|
|
56
|
-
}
|
|
57
|
-
];
|
|
58
|
-
for (const { location, path, name, dep } of OPTIONAL_PROVIDERS){
|
|
59
|
-
try {
|
|
60
|
-
StorageProviderRegistry.register(location, require(path)[name]);
|
|
61
|
-
logger.log(`Registered ${name}`);
|
|
62
|
-
} catch {
|
|
63
|
-
logger.debug(`${name} not available (install ${dep} to enable)`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
export class StorageModule {
|
|
67
|
-
configure(consumer) {
|
|
68
|
-
consumer.apply(FileServeMiddleware).forRoutes({
|
|
69
|
-
path: 'storage/upload/file/*',
|
|
70
|
-
method: RequestMethod.GET
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
static forRoot(options) {
|
|
74
|
-
return {
|
|
75
|
-
module: StorageModule,
|
|
76
|
-
global: options.global ?? false,
|
|
77
|
-
imports: [
|
|
78
|
-
CacheModule,
|
|
79
|
-
UtilsModule
|
|
80
|
-
],
|
|
81
|
-
controllers: options.includeController !== false ? CONTROLLERS : [],
|
|
82
|
-
providers: this.buildProviders(options),
|
|
83
|
-
exports: EXPORTED_SERVICES
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
static forRootAsync(options) {
|
|
87
|
-
return {
|
|
88
|
-
module: StorageModule,
|
|
89
|
-
global: options.global ?? false,
|
|
90
|
-
imports: [
|
|
91
|
-
...options.imports || [],
|
|
92
|
-
CacheModule,
|
|
93
|
-
UtilsModule
|
|
94
|
-
],
|
|
95
|
-
controllers: options.includeController !== false ? CONTROLLERS : [],
|
|
96
|
-
providers: [
|
|
97
|
-
...this.createAsyncProviders(options),
|
|
98
|
-
...this.buildProviders()
|
|
99
|
-
],
|
|
100
|
-
exports: EXPORTED_SERVICES
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
// ─── Private Helpers ──────────────────────────────────────────────────────────
|
|
104
|
-
static buildProviders(options) {
|
|
105
|
-
const providers = [
|
|
106
|
-
...EXPORTED_SERVICES,
|
|
107
|
-
FileServeMiddleware
|
|
108
|
-
];
|
|
109
|
-
if (options) {
|
|
110
|
-
providers.unshift({
|
|
111
|
-
provide: STORAGE_MODULE_OPTIONS,
|
|
112
|
-
useValue: options
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
providers.push(createModuleEventsProvider('storage', STORAGE_MODULE_OPTIONS));
|
|
116
|
-
return providers;
|
|
117
|
-
}
|
|
118
|
-
static createAsyncProviders(options) {
|
|
119
|
-
if (options.useFactory) {
|
|
120
|
-
return [
|
|
121
|
-
{
|
|
122
|
-
provide: STORAGE_MODULE_OPTIONS,
|
|
123
|
-
useFactory: async (...args)=>({
|
|
124
|
-
...options,
|
|
125
|
-
config: await options.useFactory(...args)
|
|
126
|
-
}),
|
|
127
|
-
inject: options.inject || []
|
|
128
|
-
}
|
|
129
|
-
];
|
|
130
|
-
}
|
|
131
|
-
const factoryClass = options.useClass || options.useExisting;
|
|
132
|
-
if (!factoryClass) return [];
|
|
133
|
-
const providers = [
|
|
134
|
-
{
|
|
135
|
-
provide: STORAGE_MODULE_OPTIONS,
|
|
136
|
-
useFactory: async (factory)=>({
|
|
137
|
-
...options,
|
|
138
|
-
config: await factory.createStorageOptions()
|
|
139
|
-
}),
|
|
140
|
-
inject: [
|
|
141
|
-
factoryClass
|
|
142
|
-
]
|
|
143
|
-
}
|
|
144
|
-
];
|
|
145
|
-
if (options.useClass) {
|
|
146
|
-
providers.push({
|
|
147
|
-
provide: options.useClass,
|
|
148
|
-
useClass: options.useClass
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
return providers;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
StorageModule = _ts_decorate([
|
|
155
|
-
Module({})
|
|
156
|
-
], StorageModule);
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
function _define_property(obj, key, value) {
|
|
2
|
-
if (key in obj) {
|
|
3
|
-
Object.defineProperty(obj, key, {
|
|
4
|
-
value: value,
|
|
5
|
-
enumerable: true,
|
|
6
|
-
configurable: true,
|
|
7
|
-
writable: true
|
|
8
|
-
});
|
|
9
|
-
} else {
|
|
10
|
-
obj[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
import { StorageModule } from './storage.module';
|
|
15
|
-
import { STORAGE_MODULE_OPTIONS } from '../config/storage.constants';
|
|
16
|
-
import { FileManagerController, FolderController, StorageConfigController, UploadController } from '../controllers';
|
|
17
|
-
import { FileServeMiddleware } from '../middlewares';
|
|
18
|
-
function providerTokens(providers) {
|
|
19
|
-
return providers.map((p)=>typeof p === 'function' ? p : p.provide);
|
|
20
|
-
}
|
|
21
|
-
describe('StorageModule', ()=>{
|
|
22
|
-
describe('forRoot', ()=>{
|
|
23
|
-
it('should default to a non-global module with all controllers registered', ()=>{
|
|
24
|
-
const dynamicModule = StorageModule.forRoot({});
|
|
25
|
-
expect(dynamicModule.module).toBe(StorageModule);
|
|
26
|
-
expect(dynamicModule.global).toBe(false);
|
|
27
|
-
expect(dynamicModule.controllers).toEqual([
|
|
28
|
-
FileManagerController,
|
|
29
|
-
FolderController,
|
|
30
|
-
StorageConfigController,
|
|
31
|
-
UploadController
|
|
32
|
-
]);
|
|
33
|
-
});
|
|
34
|
-
it('should respect global: true', ()=>{
|
|
35
|
-
expect(StorageModule.forRoot({
|
|
36
|
-
global: true
|
|
37
|
-
}).global).toBe(true);
|
|
38
|
-
});
|
|
39
|
-
it('should register no controllers when includeController is false', ()=>{
|
|
40
|
-
expect(StorageModule.forRoot({
|
|
41
|
-
includeController: false
|
|
42
|
-
}).controllers).toEqual([]);
|
|
43
|
-
});
|
|
44
|
-
it('should register controllers when includeController is anything other than exactly false', ()=>{
|
|
45
|
-
expect(StorageModule.forRoot({
|
|
46
|
-
includeController: true
|
|
47
|
-
}).controllers).toHaveLength(4);
|
|
48
|
-
expect(StorageModule.forRoot({}).controllers).toHaveLength(4);
|
|
49
|
-
});
|
|
50
|
-
it('should register a STORAGE_MODULE_OPTIONS provider carrying the given options', ()=>{
|
|
51
|
-
const options = {
|
|
52
|
-
bootstrapAppConfig: {
|
|
53
|
-
enableCompanyFeature: true
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
const dynamicModule = StorageModule.forRoot(options);
|
|
57
|
-
const provider = dynamicModule.providers.find((p)=>p.provide === STORAGE_MODULE_OPTIONS);
|
|
58
|
-
expect(provider.useValue).toBe(options);
|
|
59
|
-
});
|
|
60
|
-
it('should always export the same fixed set of services', ()=>{
|
|
61
|
-
const dynamicModule = StorageModule.forRoot({});
|
|
62
|
-
expect(dynamicModule.exports).toHaveLength(7);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('forRootAsync', ()=>{
|
|
66
|
-
it('should forward external imports alongside CacheModule/UtilsModule', ()=>{
|
|
67
|
-
let FakeImportedModule = class FakeImportedModule {
|
|
68
|
-
};
|
|
69
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
70
|
-
bootstrapAppConfig: {},
|
|
71
|
-
imports: [
|
|
72
|
-
FakeImportedModule
|
|
73
|
-
]
|
|
74
|
-
});
|
|
75
|
-
expect(dynamicModule.imports).toEqual(expect.arrayContaining([
|
|
76
|
-
FakeImportedModule
|
|
77
|
-
]));
|
|
78
|
-
});
|
|
79
|
-
it('should register no controllers when includeController is false', ()=>{
|
|
80
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
81
|
-
bootstrapAppConfig: {},
|
|
82
|
-
includeController: false
|
|
83
|
-
});
|
|
84
|
-
expect(dynamicModule.controllers).toEqual([]);
|
|
85
|
-
});
|
|
86
|
-
it('useFactory: builds a STORAGE_MODULE_OPTIONS provider that merges resolved config into the static options', async ()=>{
|
|
87
|
-
const useFactory = jest.fn().mockResolvedValue({
|
|
88
|
-
maxFileSize: 1024
|
|
89
|
-
});
|
|
90
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
91
|
-
bootstrapAppConfig: {},
|
|
92
|
-
useFactory,
|
|
93
|
-
inject: [
|
|
94
|
-
'SOME_TOKEN'
|
|
95
|
-
]
|
|
96
|
-
});
|
|
97
|
-
const provider = dynamicModule.providers.find((p)=>p.provide === STORAGE_MODULE_OPTIONS);
|
|
98
|
-
expect(provider.inject).toEqual([
|
|
99
|
-
'SOME_TOKEN'
|
|
100
|
-
]);
|
|
101
|
-
const resolved = await provider.useFactory('injected');
|
|
102
|
-
expect(useFactory).toHaveBeenCalledWith('injected');
|
|
103
|
-
expect(resolved.config).toEqual({
|
|
104
|
-
maxFileSize: 1024
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
it('useClass: registers both the class provider and an options provider calling createStorageOptions()', async ()=>{
|
|
108
|
-
let MyOptionsFactory = class MyOptionsFactory {
|
|
109
|
-
constructor(){
|
|
110
|
-
_define_property(this, "createStorageOptions", jest.fn().mockResolvedValue({
|
|
111
|
-
maxFileSize: 2048
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
116
|
-
bootstrapAppConfig: {},
|
|
117
|
-
useClass: MyOptionsFactory
|
|
118
|
-
});
|
|
119
|
-
const classProvider = dynamicModule.providers.find((p)=>p.provide === MyOptionsFactory);
|
|
120
|
-
expect(classProvider.useClass).toBe(MyOptionsFactory);
|
|
121
|
-
const optionsProvider = dynamicModule.providers.find((p)=>p.provide === STORAGE_MODULE_OPTIONS);
|
|
122
|
-
const instance = new MyOptionsFactory();
|
|
123
|
-
const resolved = await optionsProvider.useFactory(instance);
|
|
124
|
-
expect(instance.createStorageOptions).toHaveBeenCalled();
|
|
125
|
-
expect(resolved.config).toEqual({
|
|
126
|
-
maxFileSize: 2048
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
it('useExisting: registers a single options provider without a duplicate class registration', async ()=>{
|
|
130
|
-
let MyOptionsFactory = class MyOptionsFactory {
|
|
131
|
-
constructor(){
|
|
132
|
-
_define_property(this, "createStorageOptions", jest.fn().mockResolvedValue({
|
|
133
|
-
maxFileSize: 4096
|
|
134
|
-
}));
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
138
|
-
bootstrapAppConfig: {},
|
|
139
|
-
useExisting: MyOptionsFactory
|
|
140
|
-
});
|
|
141
|
-
expect(dynamicModule.providers.filter((p)=>p.provide === MyOptionsFactory)).toHaveLength(0);
|
|
142
|
-
const optionsProvider = dynamicModule.providers.find((p)=>p.provide === STORAGE_MODULE_OPTIONS);
|
|
143
|
-
expect(optionsProvider.inject).toEqual([
|
|
144
|
-
MyOptionsFactory
|
|
145
|
-
]);
|
|
146
|
-
});
|
|
147
|
-
it('should register no STORAGE_MODULE_OPTIONS provider when neither useFactory, useClass, nor useExisting is given', ()=>{
|
|
148
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
149
|
-
bootstrapAppConfig: {}
|
|
150
|
-
});
|
|
151
|
-
expect(providerTokens(dynamicModule.providers)).not.toContain(STORAGE_MODULE_OPTIONS);
|
|
152
|
-
});
|
|
153
|
-
it('should still register the fixed exported services as providers alongside async options', ()=>{
|
|
154
|
-
const dynamicModule = StorageModule.forRootAsync({
|
|
155
|
-
bootstrapAppConfig: {},
|
|
156
|
-
useFactory: jest.fn()
|
|
157
|
-
});
|
|
158
|
-
expect(dynamicModule.providers).toEqual(expect.arrayContaining([
|
|
159
|
-
...dynamicModule.exports
|
|
160
|
-
]));
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
describe('configure (NestModule)', ()=>{
|
|
164
|
-
it('should wire FileServeMiddleware to the file GET route', ()=>{
|
|
165
|
-
const forRoutes = jest.fn();
|
|
166
|
-
const apply = jest.fn().mockReturnValue({
|
|
167
|
-
forRoutes
|
|
168
|
-
});
|
|
169
|
-
const consumer = {
|
|
170
|
-
apply
|
|
171
|
-
};
|
|
172
|
-
new StorageModule().configure(consumer);
|
|
173
|
-
expect(apply).toHaveBeenCalledWith(FileServeMiddleware);
|
|
174
|
-
expect(forRoutes).toHaveBeenCalledWith({
|
|
175
|
-
path: 'storage/upload/file/*',
|
|
176
|
-
method: expect.anything()
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
function _define_property(obj, key, value) {
|
|
2
|
-
if (key in obj) {
|
|
3
|
-
Object.defineProperty(obj, key, {
|
|
4
|
-
value: value,
|
|
5
|
-
enumerable: true,
|
|
6
|
-
configurable: true,
|
|
7
|
-
writable: true
|
|
8
|
-
});
|
|
9
|
-
} else {
|
|
10
|
-
obj[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
const mockCreateIfNotExists = jest.fn();
|
|
15
|
-
const mockBlockBlobUpload = jest.fn();
|
|
16
|
-
const mockDeleteIfExists = jest.fn();
|
|
17
|
-
const mockContainerExists = jest.fn();
|
|
18
|
-
function buildBlockBlobClient() {
|
|
19
|
-
return {
|
|
20
|
-
upload: mockBlockBlobUpload,
|
|
21
|
-
deleteIfExists: mockDeleteIfExists,
|
|
22
|
-
url: 'https://account.blob.core.windows.net/container/blob-key.jpg',
|
|
23
|
-
credential: 'shared-key-credential'
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const mockGetBlockBlobClient = jest.fn().mockImplementation(()=>buildBlockBlobClient());
|
|
27
|
-
const mockGetContainerClient = jest.fn().mockImplementation(()=>({
|
|
28
|
-
createIfNotExists: mockCreateIfNotExists,
|
|
29
|
-
getBlockBlobClient: mockGetBlockBlobClient,
|
|
30
|
-
exists: mockContainerExists
|
|
31
|
-
}));
|
|
32
|
-
const mockFromConnectionString = jest.fn().mockImplementation(()=>({
|
|
33
|
-
getContainerClient: mockGetContainerClient
|
|
34
|
-
}));
|
|
35
|
-
const mockBlobServiceClientCtor = jest.fn().mockImplementation(()=>({
|
|
36
|
-
getContainerClient: mockGetContainerClient
|
|
37
|
-
}));
|
|
38
|
-
mockBlobServiceClientCtor.fromConnectionString = mockFromConnectionString;
|
|
39
|
-
const mockGenerateBlobSASQueryParameters = jest.fn().mockReturnValue({
|
|
40
|
-
toString: ()=>'sv=2022&sig=abc123'
|
|
41
|
-
});
|
|
42
|
-
let MockStorageSharedKeyCredential = class MockStorageSharedKeyCredential {
|
|
43
|
-
constructor(accountName, accountKey){
|
|
44
|
-
_define_property(this, "accountName", void 0);
|
|
45
|
-
_define_property(this, "accountKey", void 0);
|
|
46
|
-
this.accountName = accountName;
|
|
47
|
-
this.accountKey = accountKey;
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
let MockBlobSASPermissions = class MockBlobSASPermissions {
|
|
51
|
-
static parse(input) {
|
|
52
|
-
return {
|
|
53
|
-
permissions: input
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
jest.mock('@azure/storage-blob', ()=>({
|
|
58
|
-
BlobServiceClient: mockBlobServiceClientCtor,
|
|
59
|
-
StorageSharedKeyCredential: MockStorageSharedKeyCredential,
|
|
60
|
-
BlobSASPermissions: MockBlobSASPermissions,
|
|
61
|
-
generateBlobSASQueryParameters: (...args)=>mockGenerateBlobSASQueryParameters(...args)
|
|
62
|
-
}));
|
|
63
|
-
jest.mock('../utils/image-compressor.util', ()=>({
|
|
64
|
-
ImageCompressor: {
|
|
65
|
-
compress: jest.fn()
|
|
66
|
-
}
|
|
67
|
-
}));
|
|
68
|
-
import { AzureProvider } from './azure-provider.optional';
|
|
69
|
-
import { ImageCompressor } from '../utils/image-compressor.util';
|
|
70
|
-
function buildMulterFile(overrides = {}) {
|
|
71
|
-
return {
|
|
72
|
-
fieldname: 'file',
|
|
73
|
-
originalname: 'photo.jpg',
|
|
74
|
-
encoding: '7bit',
|
|
75
|
-
mimetype: 'image/jpeg',
|
|
76
|
-
buffer: Buffer.from('file-bytes'),
|
|
77
|
-
size: 10,
|
|
78
|
-
stream: undefined,
|
|
79
|
-
destination: '',
|
|
80
|
-
filename: '',
|
|
81
|
-
path: '',
|
|
82
|
-
...overrides
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
describe('AzureProvider', ()=>{
|
|
86
|
-
let provider;
|
|
87
|
-
beforeEach(async ()=>{
|
|
88
|
-
jest.clearAllMocks();
|
|
89
|
-
mockCreateIfNotExists.mockResolvedValue(undefined);
|
|
90
|
-
mockBlockBlobUpload.mockResolvedValue(undefined);
|
|
91
|
-
mockDeleteIfExists.mockResolvedValue(undefined);
|
|
92
|
-
mockContainerExists.mockResolvedValue(true);
|
|
93
|
-
mockGetBlockBlobClient.mockImplementation(()=>buildBlockBlobClient());
|
|
94
|
-
mockGetContainerClient.mockImplementation(()=>({
|
|
95
|
-
createIfNotExists: mockCreateIfNotExists,
|
|
96
|
-
getBlockBlobClient: mockGetBlockBlobClient,
|
|
97
|
-
exists: mockContainerExists
|
|
98
|
-
}));
|
|
99
|
-
provider = new AzureProvider();
|
|
100
|
-
await provider.initialize({
|
|
101
|
-
accountName: 'myaccount',
|
|
102
|
-
accountKey: 'key123',
|
|
103
|
-
containerName: 'my-container'
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
describe('initialize', ()=>{
|
|
107
|
-
it('builds a BlobServiceClient using an account key credential when no connection string is given', ()=>{
|
|
108
|
-
expect(mockBlobServiceClientCtor).toHaveBeenCalledWith('https://myaccount.blob.core.windows.net', expect.any(MockStorageSharedKeyCredential));
|
|
109
|
-
expect(mockCreateIfNotExists).toHaveBeenCalled();
|
|
110
|
-
});
|
|
111
|
-
it('builds a BlobServiceClient from a connection string when provided', async ()=>{
|
|
112
|
-
jest.clearAllMocks();
|
|
113
|
-
mockCreateIfNotExists.mockResolvedValue(undefined);
|
|
114
|
-
const p = new AzureProvider();
|
|
115
|
-
await p.initialize({
|
|
116
|
-
accountName: 'acct2',
|
|
117
|
-
accountKey: 'key2',
|
|
118
|
-
containerName: 'container2',
|
|
119
|
-
connectionString: 'DefaultEndpointsProtocol=https;AccountName=acct2;AccountKey=key2'
|
|
120
|
-
});
|
|
121
|
-
expect(mockFromConnectionString).toHaveBeenCalledWith('DefaultEndpointsProtocol=https;AccountName=acct2;AccountKey=key2');
|
|
122
|
-
});
|
|
123
|
-
it('throws InternalServerErrorException when the Azure SDK cannot be initialized', async ()=>{
|
|
124
|
-
mockBlobServiceClientCtor.mockImplementationOnce(()=>{
|
|
125
|
-
throw new Error('boom');
|
|
126
|
-
});
|
|
127
|
-
const brokenProvider = new AzureProvider();
|
|
128
|
-
await expect(brokenProvider.initialize({
|
|
129
|
-
accountName: 'a',
|
|
130
|
-
accountKey: 'b',
|
|
131
|
-
containerName: 'c'
|
|
132
|
-
})).rejects.toThrow('Azure Storage SDK not found');
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
describe('uploadFile', ()=>{
|
|
136
|
-
it('uploads the blob and returns file metadata', async ()=>{
|
|
137
|
-
const file = buildMulterFile();
|
|
138
|
-
const result = await provider.uploadFile(file, {});
|
|
139
|
-
expect(mockBlockBlobUpload).toHaveBeenCalledWith(file.buffer, file.buffer.length, expect.objectContaining({
|
|
140
|
-
blobHTTPHeaders: {
|
|
141
|
-
blobContentType: 'image/jpeg'
|
|
142
|
-
}
|
|
143
|
-
}));
|
|
144
|
-
expect(result.name).toMatch(/photo\.jpg$/);
|
|
145
|
-
expect(result.key).toBe(result.name);
|
|
146
|
-
});
|
|
147
|
-
it('prefixes blob name with folderPath when provided', async ()=>{
|
|
148
|
-
const file = buildMulterFile();
|
|
149
|
-
const result = await provider.uploadFile(file, {
|
|
150
|
-
folderPath: 'docs'
|
|
151
|
-
});
|
|
152
|
-
expect(result.key).toMatch(/^docs\//);
|
|
153
|
-
});
|
|
154
|
-
it('compresses image files when options.compress is true', async ()=>{
|
|
155
|
-
ImageCompressor.compress.mockResolvedValue({
|
|
156
|
-
buffer: Buffer.from('small'),
|
|
157
|
-
format: 'image/webp'
|
|
158
|
-
});
|
|
159
|
-
const file = buildMulterFile();
|
|
160
|
-
const result = await provider.uploadFile(file, {
|
|
161
|
-
compress: true
|
|
162
|
-
});
|
|
163
|
-
expect(ImageCompressor.compress).toHaveBeenCalled();
|
|
164
|
-
expect(result.contentType).toBe('image/webp');
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
describe('uploadMultipleFiles', ()=>{
|
|
168
|
-
it('uploads all files', async ()=>{
|
|
169
|
-
const files = [
|
|
170
|
-
buildMulterFile({
|
|
171
|
-
originalname: 'a.jpg'
|
|
172
|
-
}),
|
|
173
|
-
buildMulterFile({
|
|
174
|
-
originalname: 'b.jpg'
|
|
175
|
-
})
|
|
176
|
-
];
|
|
177
|
-
const results = await provider.uploadMultipleFiles(files, {});
|
|
178
|
-
expect(results).toHaveLength(2);
|
|
179
|
-
expect(mockBlockBlobUpload).toHaveBeenCalledTimes(2);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
describe('deleteFile', ()=>{
|
|
183
|
-
it('calls deleteIfExists on the block blob client for the given key', async ()=>{
|
|
184
|
-
await provider.deleteFile('blob-key.jpg');
|
|
185
|
-
expect(mockGetBlockBlobClient).toHaveBeenCalledWith('blob-key.jpg');
|
|
186
|
-
expect(mockDeleteIfExists).toHaveBeenCalled();
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
describe('deleteMultipleFiles', ()=>{
|
|
190
|
-
it('deletes every provided key', async ()=>{
|
|
191
|
-
await provider.deleteMultipleFiles([
|
|
192
|
-
'a.jpg',
|
|
193
|
-
'b.jpg'
|
|
194
|
-
]);
|
|
195
|
-
expect(mockDeleteIfExists).toHaveBeenCalledTimes(2);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
describe('generatePresignedUrl', ()=>{
|
|
199
|
-
it('generates a SAS URL appended with the query string', async ()=>{
|
|
200
|
-
const url = await provider.generatePresignedUrl('blob-key.jpg', 1800);
|
|
201
|
-
expect(mockGenerateBlobSASQueryParameters).toHaveBeenCalledWith(expect.objectContaining({
|
|
202
|
-
containerName: 'my-container',
|
|
203
|
-
blobName: 'blob-key.jpg'
|
|
204
|
-
}), 'shared-key-credential');
|
|
205
|
-
expect(url).toBe('https://account.blob.core.windows.net/container/blob-key.jpg?sv=2022&sig=abc123');
|
|
206
|
-
});
|
|
207
|
-
it('defaults the expiry window to 3600 seconds', async ()=>{
|
|
208
|
-
await provider.generatePresignedUrl('blob-key.jpg');
|
|
209
|
-
const call = mockGenerateBlobSASQueryParameters.mock.calls[0][0];
|
|
210
|
-
const diffSeconds = (call.expiresOn.getTime() - call.startsOn.getTime()) / 1000;
|
|
211
|
-
expect(diffSeconds).toBeCloseTo(3600, 0);
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
describe('healthCheck', ()=>{
|
|
215
|
-
it('returns true when the container exists', async ()=>{
|
|
216
|
-
mockContainerExists.mockResolvedValue(true);
|
|
217
|
-
await expect(provider.healthCheck()).resolves.toBe(true);
|
|
218
|
-
});
|
|
219
|
-
it('returns false when checking existence throws', async ()=>{
|
|
220
|
-
mockContainerExists.mockRejectedValue(new Error('network error'));
|
|
221
|
-
await expect(provider.healthCheck()).resolves.toBe(false);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
});
|