@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.
Files changed (202) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/file-manager.controller.d.ts +4 -4
  3. package/controllers/folder.controller.d.ts +2 -2
  4. package/controllers/index.d.ts +4 -4
  5. package/controllers/storage-config.controller.d.ts +2 -2
  6. package/controllers/upload.controller.d.ts +3 -3
  7. package/docs/index.d.ts +1 -1
  8. package/docs/storage-swagger.config.d.ts +2 -2
  9. package/dtos/index.d.ts +4 -4
  10. package/entities/file-manager-with-company.entity.d.ts +2 -2
  11. package/entities/file-manager.entity.d.ts +1 -1
  12. package/entities/folder-with-company.entity.d.ts +1 -1
  13. package/entities/index.d.ts +15 -15
  14. package/entities/storage-config-with-company.entity.d.ts +1 -1
  15. package/enums/index.d.ts +1 -1
  16. package/fesm/493.js +2768 -0
  17. package/fesm/537.js +1157 -0
  18. package/fesm/562.js +786 -0
  19. package/fesm/{providers/azure-provider.optional.js → chunks/190.js} +33 -30
  20. package/fesm/chunks/252.js +12 -0
  21. package/fesm/chunks/327.js +12 -0
  22. package/fesm/chunks/385.js +12 -0
  23. package/fesm/{providers/s3-provider.optional.js → chunks/591.js} +37 -34
  24. package/fesm/chunks/746.js +12 -0
  25. package/fesm/chunks/798.js +12 -0
  26. package/fesm/{providers/sftp-provider.optional.js → chunks/918.js} +35 -31
  27. package/fesm/config/index.js +119 -3
  28. package/fesm/controllers/index.js +16 -4
  29. package/fesm/docs/index.js +206 -1
  30. package/fesm/dtos/index.js +879 -4
  31. package/fesm/entities/index.js +463 -18
  32. package/fesm/enums/index.js +36 -1
  33. package/fesm/index.js +398 -12
  34. package/fesm/interfaces/index.js +19 -5
  35. package/fesm/modules/index.js +16 -1
  36. package/fesm/providers/index.js +364 -3
  37. package/fesm/runtime.js +252 -0
  38. package/fesm/services/index.js +16 -6
  39. package/fesm/utils/index.js +149 -1
  40. package/index.d.ts +11 -11
  41. package/interfaces/file-manager.interface.d.ts +1 -1
  42. package/interfaces/folder.interface.d.ts +1 -1
  43. package/interfaces/index.d.ts +5 -5
  44. package/interfaces/storage-config.interface.d.ts +1 -1
  45. package/interfaces/storage-module-options.interface.d.ts +3 -3
  46. package/interfaces/storage-provider.interface.d.ts +1 -1
  47. package/middlewares/file-serve.middleware.d.ts +4 -3
  48. package/middlewares/index.d.ts +1 -1
  49. package/modules/index.d.ts +1 -1
  50. package/modules/storage.module.d.ts +2 -2
  51. package/package.json +30 -41
  52. package/providers/azure-provider.optional.d.ts +2 -2
  53. package/providers/index.d.ts +3 -3
  54. package/providers/local-provider.d.ts +2 -2
  55. package/providers/s3-provider.optional.d.ts +2 -2
  56. package/providers/sftp-provider.optional.d.ts +2 -2
  57. package/providers/storage-factory.service.d.ts +3 -3
  58. package/providers/storage-provider.registry.d.ts +2 -2
  59. package/services/file-manager.service.d.ts +9 -8
  60. package/services/folder.service.d.ts +6 -6
  61. package/services/index.d.ts +6 -6
  62. package/services/storage-config.service.d.ts +3 -3
  63. package/services/storage-datasource.provider.d.ts +3 -3
  64. package/services/storage-provider-config.service.d.ts +7 -7
  65. package/services/upload.service.d.ts +6 -6
  66. package/utils/image-compressor.util.d.ts +1 -1
  67. package/utils/index.d.ts +1 -1
  68. package/cjs/config/event-actions.js +0 -34
  69. package/cjs/config/index.js +0 -20
  70. package/cjs/config/message-keys.js +0 -46
  71. package/cjs/config/storage.constants.js +0 -28
  72. package/cjs/controllers/file-manager.controller.js +0 -152
  73. package/cjs/controllers/file-manager.controller.spec.js +0 -135
  74. package/cjs/controllers/folder.controller.js +0 -102
  75. package/cjs/controllers/folder.controller.spec.js +0 -86
  76. package/cjs/controllers/index.js +0 -21
  77. package/cjs/controllers/storage-config.controller.js +0 -102
  78. package/cjs/controllers/storage-config.controller.spec.js +0 -85
  79. package/cjs/controllers/upload.controller.js +0 -234
  80. package/cjs/controllers/upload.controller.spec.js +0 -132
  81. package/cjs/docs/index.js +0 -11
  82. package/cjs/docs/storage-swagger.config.js +0 -188
  83. package/cjs/docs/storage-swagger.config.spec.js +0 -72
  84. package/cjs/dtos/file-manager.dto.js +0 -327
  85. package/cjs/dtos/folder.dto.js +0 -105
  86. package/cjs/dtos/index.js +0 -21
  87. package/cjs/dtos/storage-config.dto.js +0 -170
  88. package/cjs/dtos/upload.dto.js +0 -272
  89. package/cjs/entities/file-manager-with-company.entity.js +0 -61
  90. package/cjs/entities/file-manager.entity.js +0 -122
  91. package/cjs/entities/folder-with-company.entity.js +0 -55
  92. package/cjs/entities/folder.entity.js +0 -64
  93. package/cjs/entities/index.js +0 -63
  94. package/cjs/entities/index.spec.js +0 -18
  95. package/cjs/entities/storage-config-with-company.entity.js +0 -51
  96. package/cjs/entities/storage-config.entity.js +0 -96
  97. package/cjs/enums/file-location.enum.js +0 -17
  98. package/cjs/enums/index.js +0 -18
  99. package/cjs/index.js +0 -29
  100. package/cjs/interfaces/file-manager.interface.js +0 -4
  101. package/cjs/interfaces/folder.interface.js +0 -4
  102. package/cjs/interfaces/index.js +0 -22
  103. package/cjs/interfaces/storage-config.interface.js +0 -4
  104. package/cjs/interfaces/storage-module-options.interface.js +0 -4
  105. package/cjs/interfaces/storage-provider.interface.js +0 -4
  106. package/cjs/middlewares/file-serve.middleware.js +0 -241
  107. package/cjs/middlewares/file-serve.middleware.spec.js +0 -211
  108. package/cjs/middlewares/index.js +0 -18
  109. package/cjs/modules/index.js +0 -18
  110. package/cjs/modules/storage.module.js +0 -165
  111. package/cjs/modules/storage.module.spec.js +0 -184
  112. package/cjs/providers/azure-provider.optional.js +0 -155
  113. package/cjs/providers/azure-provider.optional.spec.js +0 -228
  114. package/cjs/providers/index.js +0 -26
  115. package/cjs/providers/local-provider.js +0 -230
  116. package/cjs/providers/local-provider.spec.js +0 -239
  117. package/cjs/providers/s3-provider.optional.js +0 -175
  118. package/cjs/providers/s3-provider.optional.spec.js +0 -243
  119. package/cjs/providers/sftp-provider.optional.js +0 -203
  120. package/cjs/providers/sftp-provider.optional.spec.js +0 -217
  121. package/cjs/providers/storage-factory.service.js +0 -175
  122. package/cjs/providers/storage-factory.service.spec.js +0 -253
  123. package/cjs/providers/storage-provider.registry.js +0 -41
  124. package/cjs/providers/storage-provider.registry.spec.js +0 -67
  125. package/cjs/services/file-manager.service.js +0 -387
  126. package/cjs/services/file-manager.service.spec.js +0 -580
  127. package/cjs/services/folder.service.js +0 -101
  128. package/cjs/services/folder.service.spec.js +0 -167
  129. package/cjs/services/index.js +0 -23
  130. package/cjs/services/storage-config.service.js +0 -129
  131. package/cjs/services/storage-config.service.spec.js +0 -257
  132. package/cjs/services/storage-datasource.provider.js +0 -137
  133. package/cjs/services/storage-datasource.provider.spec.js +0 -217
  134. package/cjs/services/storage-provider-config.service.js +0 -171
  135. package/cjs/services/storage-provider-config.service.spec.js +0 -265
  136. package/cjs/services/upload.service.js +0 -376
  137. package/cjs/services/upload.service.spec.js +0 -426
  138. package/cjs/utils/file-validator.util.js +0 -440
  139. package/cjs/utils/file-validator.util.spec.js +0 -259
  140. package/cjs/utils/image-compressor.util.js +0 -162
  141. package/cjs/utils/image-compressor.util.spec.js +0 -166
  142. package/cjs/utils/index.js +0 -18
  143. package/fesm/config/event-actions.js +0 -13
  144. package/fesm/config/message-keys.js +0 -22
  145. package/fesm/config/storage.constants.js +0 -7
  146. package/fesm/controllers/file-manager.controller.js +0 -142
  147. package/fesm/controllers/file-manager.controller.spec.js +0 -131
  148. package/fesm/controllers/folder.controller.js +0 -92
  149. package/fesm/controllers/folder.controller.spec.js +0 -82
  150. package/fesm/controllers/storage-config.controller.js +0 -92
  151. package/fesm/controllers/storage-config.controller.spec.js +0 -81
  152. package/fesm/controllers/upload.controller.js +0 -224
  153. package/fesm/controllers/upload.controller.spec.js +0 -128
  154. package/fesm/docs/storage-swagger.config.js +0 -181
  155. package/fesm/docs/storage-swagger.config.spec.js +0 -68
  156. package/fesm/dtos/file-manager.dto.js +0 -300
  157. package/fesm/dtos/folder.dto.js +0 -84
  158. package/fesm/dtos/storage-config.dto.js +0 -149
  159. package/fesm/dtos/upload.dto.js +0 -245
  160. package/fesm/entities/file-manager-with-company.entity.js +0 -51
  161. package/fesm/entities/file-manager.entity.js +0 -112
  162. package/fesm/entities/folder-with-company.entity.js +0 -45
  163. package/fesm/entities/folder.entity.js +0 -54
  164. package/fesm/entities/index.spec.js +0 -14
  165. package/fesm/entities/storage-config-with-company.entity.js +0 -41
  166. package/fesm/entities/storage-config.entity.js +0 -86
  167. package/fesm/enums/file-location.enum.js +0 -7
  168. package/fesm/interfaces/file-manager.interface.js +0 -1
  169. package/fesm/interfaces/folder.interface.js +0 -1
  170. package/fesm/interfaces/storage-config.interface.js +0 -1
  171. package/fesm/interfaces/storage-module-options.interface.js +0 -3
  172. package/fesm/interfaces/storage-provider.interface.js +0 -4
  173. package/fesm/middlewares/file-serve.middleware.js +0 -190
  174. package/fesm/middlewares/file-serve.middleware.spec.js +0 -207
  175. package/fesm/middlewares/index.js +0 -1
  176. package/fesm/modules/storage.module.js +0 -156
  177. package/fesm/modules/storage.module.spec.js +0 -180
  178. package/fesm/providers/azure-provider.optional.spec.js +0 -224
  179. package/fesm/providers/local-provider.js +0 -182
  180. package/fesm/providers/local-provider.spec.js +0 -194
  181. package/fesm/providers/s3-provider.optional.spec.js +0 -239
  182. package/fesm/providers/sftp-provider.optional.spec.js +0 -213
  183. package/fesm/providers/storage-factory.service.js +0 -124
  184. package/fesm/providers/storage-factory.service.spec.js +0 -249
  185. package/fesm/providers/storage-provider.registry.js +0 -34
  186. package/fesm/providers/storage-provider.registry.spec.js +0 -63
  187. package/fesm/services/file-manager.service.js +0 -336
  188. package/fesm/services/file-manager.service.spec.js +0 -576
  189. package/fesm/services/folder.service.js +0 -91
  190. package/fesm/services/folder.service.spec.js +0 -163
  191. package/fesm/services/storage-config.service.js +0 -119
  192. package/fesm/services/storage-config.service.spec.js +0 -253
  193. package/fesm/services/storage-datasource.provider.js +0 -86
  194. package/fesm/services/storage-datasource.provider.spec.js +0 -172
  195. package/fesm/services/storage-provider-config.service.js +0 -161
  196. package/fesm/services/storage-provider-config.service.spec.js +0 -261
  197. package/fesm/services/upload.service.js +0 -366
  198. package/fesm/services/upload.service.spec.js +0 -422
  199. package/fesm/utils/file-validator.util.js +0 -433
  200. package/fesm/utils/file-validator.util.spec.js +0 -255
  201. package/fesm/utils/image-compressor.util.js +0 -114
  202. package/fesm/utils/image-compressor.util.spec.js +0 -162
@@ -1,163 +0,0 @@
1
- import { Test } from '@nestjs/testing';
2
- import { UtilsService } from '@flusys/nestjs-shared/modules';
3
- import { createMockDataSourceProvider, createMockRepository } from '@test-utils/mocks/repository.mock';
4
- import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
5
- import { FolderService } from './folder.service';
6
- import { StorageConfigService } from './storage-config.service';
7
- import { StorageDataSourceProvider } from './storage-datasource.provider';
8
- import { Folder, FolderWithCompany } from '../entities';
9
- describe('FolderService', ()=>{
10
- let service;
11
- let module;
12
- let mockRepo;
13
- let mockStorageConfig;
14
- beforeEach(async ()=>{
15
- mockRepo = createMockRepository();
16
- const mockDataSourceProvider = createMockDataSourceProvider(mockRepo);
17
- mockStorageConfig = {
18
- isCompanyFeatureEnabled: jest.fn().mockReturnValue(false)
19
- };
20
- module = await Test.createTestingModule({
21
- providers: [
22
- FolderService,
23
- {
24
- provide: 'CACHE_INSTANCE',
25
- useValue: {}
26
- },
27
- {
28
- provide: UtilsService,
29
- useValue: {}
30
- },
31
- {
32
- provide: StorageConfigService,
33
- useValue: mockStorageConfig
34
- },
35
- {
36
- provide: StorageDataSourceProvider,
37
- useValue: mockDataSourceProvider
38
- }
39
- ]
40
- }).compile();
41
- service = await module.resolve(FolderService);
42
- });
43
- describe('entity selection', ()=>{
44
- it('uses Folder when the company feature is disabled', async ()=>{
45
- mockStorageConfig.isCompanyFeatureEnabled.mockReturnValue(false);
46
- const built = await module.resolve(FolderService);
47
- expect(built['_entity']).toBe(Folder);
48
- });
49
- it('uses FolderWithCompany when the company feature is enabled', async ()=>{
50
- mockStorageConfig.isCompanyFeatureEnabled.mockReturnValue(true);
51
- const built = await module.resolve(FolderService);
52
- expect(built['_entity']).toBe(FolderWithCompany);
53
- });
54
- });
55
- describe('convertSingleDtoToEntity', ()=>{
56
- beforeEach(async ()=>{
57
- mockRepo.create.mockReturnValue({});
58
- await service.ensureDataSourceRepository();
59
- });
60
- it('does not attach companyId when the company feature is disabled', async ()=>{
61
- const entity = await service.convertSingleDtoToEntity({
62
- name: 'Invoices'
63
- }, buildMockUser());
64
- expect(entity.companyId).toBeUndefined();
65
- });
66
- it('attaches the current user companyId when the company feature is enabled', async ()=>{
67
- mockStorageConfig.isCompanyFeatureEnabled.mockReturnValue(true);
68
- const entity = await service.convertSingleDtoToEntity({
69
- name: 'Invoices'
70
- }, buildMockUser({
71
- companyId: 'company-7'
72
- }));
73
- expect(entity.companyId).toBe('company-7');
74
- });
75
- it('defaults companyId to null when company feature is enabled but user has none', async ()=>{
76
- mockStorageConfig.isCompanyFeatureEnabled.mockReturnValue(true);
77
- const entity = await service.convertSingleDtoToEntity({
78
- name: 'Invoices'
79
- }, null);
80
- expect(entity.companyId).toBeNull();
81
- });
82
- it('loads and merges the existing entity when updating (dto has an id)', async ()=>{
83
- const existing = {
84
- id: 'folder-1',
85
- name: 'Old Name'
86
- };
87
- mockRepo.findOne.mockResolvedValue(existing);
88
- const entity = await service.convertSingleDtoToEntity({
89
- id: 'folder-1',
90
- name: 'New Name'
91
- }, buildMockUser());
92
- expect(mockRepo.findOne).toHaveBeenCalledWith({
93
- where: {
94
- id: 'folder-1'
95
- }
96
- });
97
- expect(entity.name).toBe('New Name');
98
- });
99
- it('throws NotFoundException when updating a folder that does not exist', async ()=>{
100
- mockRepo.findOne.mockResolvedValue(null);
101
- await expect(service.convertSingleDtoToEntity({
102
- id: 'missing-id',
103
- name: 'x'
104
- }, buildMockUser())).rejects.toThrow();
105
- });
106
- });
107
- describe('getSelectQuery', ()=>{
108
- it('selects the default field set (id, name, slug, createdAt, deletedAt) when none is provided', async ()=>{
109
- const query = {
110
- select: jest.fn().mockReturnThis()
111
- };
112
- await service.getSelectQuery(query, buildMockUser());
113
- expect(query.select).toHaveBeenCalledWith([
114
- 'folder.id',
115
- 'folder.name',
116
- 'folder.slug',
117
- 'folder.createdAt',
118
- 'folder.deletedAt'
119
- ]);
120
- });
121
- it('adds companyId to the default select list when company feature is enabled', async ()=>{
122
- mockStorageConfig.isCompanyFeatureEnabled.mockReturnValue(true);
123
- const query = {
124
- select: jest.fn().mockReturnThis()
125
- };
126
- await service.getSelectQuery(query, buildMockUser());
127
- const selected = query.select.mock.calls[0][0];
128
- expect(selected).toContain('folder.companyId');
129
- });
130
- it('respects an explicitly provided select list', async ()=>{
131
- const query = {
132
- select: jest.fn().mockReturnThis()
133
- };
134
- await service.getSelectQuery(query, buildMockUser(), [
135
- 'id'
136
- ]);
137
- expect(query.select).toHaveBeenCalledWith([
138
- 'folder.id'
139
- ]);
140
- });
141
- });
142
- describe('getExtraManipulateQuery', ()=>{
143
- it('applies the company filter when company feature is enabled', async ()=>{
144
- mockStorageConfig.isCompanyFeatureEnabled.mockReturnValue(true);
145
- const query = {
146
- andWhere: jest.fn().mockReturnThis()
147
- };
148
- await service.getExtraManipulateQuery(query, {}, buildMockUser({
149
- companyId: 'company-3'
150
- }));
151
- expect(query.andWhere).toHaveBeenCalledWith('folder.companyId = :companyId', {
152
- companyId: 'company-3'
153
- });
154
- });
155
- it('does not apply a company filter when company feature is disabled', async ()=>{
156
- const query = {
157
- andWhere: jest.fn().mockReturnThis()
158
- };
159
- await service.getExtraManipulateQuery(query, {}, buildMockUser());
160
- expect(query.andWhere).not.toHaveBeenCalled();
161
- });
162
- });
163
- });
@@ -1,119 +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
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- 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;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { Inject, Injectable } from '@nestjs/common';
29
- import { UPLOAD_MESSAGES } from '../config';
30
- import { DEFAULT_ALLOWED_FILE_TYPES, DEFAULT_MAX_FILE_SIZE, STORAGE_MODULE_OPTIONS } from '../config/storage.constants';
31
- import { StorageModuleOptions } from '../interfaces';
32
- const BYTES_PER_MB = 1024 * 1024;
33
- const DEFAULT_LOCAL_PATH = './uploads';
34
- const DEFAULT_PORT = '3000';
35
- export class StorageConfigService {
36
- // ─── IModuleConfigService Implementation ────────────────────────────────────
37
- isCompanyFeatureEnabled() {
38
- return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
39
- }
40
- getDatabaseMode() {
41
- return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
42
- }
43
- isMultiTenant() {
44
- return this.getDatabaseMode() === 'multi-tenant';
45
- }
46
- // ─── Config Getters ─────────────────────────────────────────────────────────
47
- getMaxFileSize() {
48
- return this.options.config?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
49
- }
50
- getAllowedFileTypes() {
51
- return this.options.config?.allowedFileTypes ?? DEFAULT_ALLOWED_FILE_TYPES;
52
- }
53
- getOptions() {
54
- return this.options;
55
- }
56
- getDefaultLocalStoragePath() {
57
- return this.options.config?.localStoragePath ?? DEFAULT_LOCAL_PATH;
58
- }
59
- getAppUrl() {
60
- return this.options.config?.appUrl ?? process.env.APP_URL ?? `http://localhost:${process.env.PORT ?? DEFAULT_PORT}`;
61
- }
62
- // ─── Validation Methods ─────────────────────────────────────────────────────
63
- isFileTypeAllowed(mimeType) {
64
- const allowedTypes = this.getAllowedFileTypes();
65
- if (allowedTypes.includes('*/*')) {
66
- return true;
67
- }
68
- return allowedTypes.some((type)=>type.endsWith('/*') ? mimeType.startsWith(type.slice(0, -2)) : type === mimeType);
69
- }
70
- validateFileSize(fileSize) {
71
- const maxSize = this.getMaxFileSize();
72
- if (fileSize > maxSize) {
73
- return {
74
- valid: false,
75
- message: `File size (${this.toMB(fileSize)}MB) exceeds maximum ${this.toMB(maxSize)}MB`,
76
- messageKey: UPLOAD_MESSAGES.FILE_TOO_LARGE,
77
- messageVariables: {
78
- fileSize: this.toMB(fileSize),
79
- maxSize: this.toMB(maxSize)
80
- }
81
- };
82
- }
83
- return {
84
- valid: true
85
- };
86
- }
87
- validateFileType(mimeType) {
88
- if (!this.isFileTypeAllowed(mimeType)) {
89
- return {
90
- valid: false,
91
- message: `File type "${mimeType}" not allowed. Allowed: ${this.getAllowedFileTypes().join(', ')}`,
92
- messageKey: UPLOAD_MESSAGES.INVALID_TYPE,
93
- messageVariables: {
94
- mimeType,
95
- allowedTypes: this.getAllowedFileTypes().join(', ')
96
- }
97
- };
98
- }
99
- return {
100
- valid: true
101
- };
102
- }
103
- // ─── Private Helpers ────────────────────────────────────────────────────────
104
- toMB(bytes) {
105
- return (bytes / BYTES_PER_MB).toFixed(2);
106
- }
107
- constructor(options){
108
- _define_property(this, "options", void 0);
109
- this.options = options;
110
- }
111
- }
112
- StorageConfigService = _ts_decorate([
113
- Injectable(),
114
- _ts_param(0, Inject(STORAGE_MODULE_OPTIONS)),
115
- _ts_metadata("design:type", Function),
116
- _ts_metadata("design:paramtypes", [
117
- typeof StorageModuleOptions === "undefined" ? Object : StorageModuleOptions
118
- ])
119
- ], StorageConfigService);
@@ -1,253 +0,0 @@
1
- import { StorageConfigService } from './storage-config.service';
2
- import { UPLOAD_MESSAGES } from '../config';
3
- function buildOptions(overrides = {}) {
4
- return {
5
- bootstrapAppConfig: {
6
- databaseMode: 'single',
7
- enableCompanyFeature: false
8
- },
9
- config: {},
10
- ...overrides
11
- };
12
- }
13
- describe('StorageConfigService', ()=>{
14
- describe('bootstrap config getters', ()=>{
15
- it('reflects enableCompanyFeature from bootstrap config', ()=>{
16
- const service = new StorageConfigService(buildOptions({
17
- bootstrapAppConfig: {
18
- databaseMode: 'single',
19
- enableCompanyFeature: true
20
- }
21
- }));
22
- expect(service.isCompanyFeatureEnabled()).toBe(true);
23
- });
24
- it('defaults enableCompanyFeature to false when bootstrapAppConfig is absent', ()=>{
25
- const service = new StorageConfigService(buildOptions({
26
- bootstrapAppConfig: undefined
27
- }));
28
- expect(service.isCompanyFeatureEnabled()).toBe(false);
29
- });
30
- it('defaults databaseMode to single when bootstrapAppConfig is absent', ()=>{
31
- const service = new StorageConfigService(buildOptions({
32
- bootstrapAppConfig: undefined
33
- }));
34
- expect(service.getDatabaseMode()).toBe('single');
35
- });
36
- it('reports isMultiTenant() true only in multi-tenant mode', ()=>{
37
- const service = new StorageConfigService(buildOptions({
38
- bootstrapAppConfig: {
39
- databaseMode: 'multi-tenant',
40
- enableCompanyFeature: true
41
- }
42
- }));
43
- expect(service.isMultiTenant()).toBe(true);
44
- });
45
- it('reports isMultiTenant() false in single mode', ()=>{
46
- const service = new StorageConfigService(buildOptions());
47
- expect(service.isMultiTenant()).toBe(false);
48
- });
49
- });
50
- describe('getMaxFileSize', ()=>{
51
- it('returns the configured max file size', ()=>{
52
- const service = new StorageConfigService(buildOptions({
53
- config: {
54
- maxFileSize: 5000
55
- }
56
- }));
57
- expect(service.getMaxFileSize()).toBe(5000);
58
- });
59
- it('falls back to the default max file size (100MB) when not configured', ()=>{
60
- const service = new StorageConfigService(buildOptions({
61
- config: {}
62
- }));
63
- expect(service.getMaxFileSize()).toBe(100 * 1024 * 1024);
64
- });
65
- });
66
- describe('getAllowedFileTypes', ()=>{
67
- it('returns configured allowed types', ()=>{
68
- const service = new StorageConfigService(buildOptions({
69
- config: {
70
- allowedFileTypes: [
71
- 'image/png'
72
- ]
73
- }
74
- }));
75
- expect(service.getAllowedFileTypes()).toEqual([
76
- 'image/png'
77
- ]);
78
- });
79
- it('defaults to */* when not configured', ()=>{
80
- const service = new StorageConfigService(buildOptions({
81
- config: {}
82
- }));
83
- expect(service.getAllowedFileTypes()).toEqual([
84
- '*/*'
85
- ]);
86
- });
87
- });
88
- describe('getDefaultLocalStoragePath', ()=>{
89
- it('returns the configured local storage path', ()=>{
90
- const service = new StorageConfigService(buildOptions({
91
- config: {
92
- localStoragePath: './custom-uploads'
93
- }
94
- }));
95
- expect(service.getDefaultLocalStoragePath()).toBe('./custom-uploads');
96
- });
97
- it('defaults to ./uploads when not configured', ()=>{
98
- const service = new StorageConfigService(buildOptions({
99
- config: {}
100
- }));
101
- expect(service.getDefaultLocalStoragePath()).toBe('./uploads');
102
- });
103
- });
104
- describe('getAppUrl', ()=>{
105
- const originalAppUrl = process.env.APP_URL;
106
- const originalPort = process.env.PORT;
107
- afterEach(()=>{
108
- process.env.APP_URL = originalAppUrl;
109
- process.env.PORT = originalPort;
110
- });
111
- it('returns the explicitly configured appUrl', ()=>{
112
- const service = new StorageConfigService(buildOptions({
113
- config: {
114
- appUrl: 'https://files.example.com'
115
- }
116
- }));
117
- expect(service.getAppUrl()).toBe('https://files.example.com');
118
- });
119
- it('falls back to process.env.APP_URL when config.appUrl is absent', ()=>{
120
- delete process.env.APP_URL;
121
- process.env.APP_URL = 'https://env.example.com';
122
- const service = new StorageConfigService(buildOptions({
123
- config: {}
124
- }));
125
- expect(service.getAppUrl()).toBe('https://env.example.com');
126
- });
127
- it('falls back to localhost with PORT when neither config nor env var is set', ()=>{
128
- delete process.env.APP_URL;
129
- process.env.PORT = '4000';
130
- const service = new StorageConfigService(buildOptions({
131
- config: {}
132
- }));
133
- expect(service.getAppUrl()).toBe('http://localhost:4000');
134
- });
135
- });
136
- describe('isFileTypeAllowed', ()=>{
137
- it('allows any type when */* is configured', ()=>{
138
- const service = new StorageConfigService(buildOptions({
139
- config: {
140
- allowedFileTypes: [
141
- '*/*'
142
- ]
143
- }
144
- }));
145
- expect(service.isFileTypeAllowed('application/pdf')).toBe(true);
146
- });
147
- it('allows types matching a category wildcard', ()=>{
148
- const service = new StorageConfigService(buildOptions({
149
- config: {
150
- allowedFileTypes: [
151
- 'image/*'
152
- ]
153
- }
154
- }));
155
- expect(service.isFileTypeAllowed('image/png')).toBe(true);
156
- });
157
- it('rejects types outside the allow-list', ()=>{
158
- const service = new StorageConfigService(buildOptions({
159
- config: {
160
- allowedFileTypes: [
161
- 'image/*'
162
- ]
163
- }
164
- }));
165
- expect(service.isFileTypeAllowed('application/pdf')).toBe(false);
166
- });
167
- it('allows an exact MIME type match', ()=>{
168
- const service = new StorageConfigService(buildOptions({
169
- config: {
170
- allowedFileTypes: [
171
- 'application/pdf'
172
- ]
173
- }
174
- }));
175
- expect(service.isFileTypeAllowed('application/pdf')).toBe(true);
176
- });
177
- });
178
- describe('validateFileSize', ()=>{
179
- it('passes when file size is within the limit', ()=>{
180
- const service = new StorageConfigService(buildOptions({
181
- config: {
182
- maxFileSize: 1000
183
- }
184
- }));
185
- expect(service.validateFileSize(500)).toEqual({
186
- valid: true
187
- });
188
- });
189
- it('passes at the exact boundary size', ()=>{
190
- const service = new StorageConfigService(buildOptions({
191
- config: {
192
- maxFileSize: 1000
193
- }
194
- }));
195
- expect(service.validateFileSize(1000).valid).toBe(true);
196
- });
197
- it('fails when file size exceeds the limit by one byte', ()=>{
198
- const service = new StorageConfigService(buildOptions({
199
- config: {
200
- maxFileSize: 1000
201
- }
202
- }));
203
- const result = service.validateFileSize(1001);
204
- expect(result.valid).toBe(false);
205
- expect(result.messageKey).toBe(UPLOAD_MESSAGES.FILE_TOO_LARGE);
206
- expect(result.messageVariables).toEqual({
207
- fileSize: '0.00',
208
- maxSize: '0.00'
209
- });
210
- });
211
- it('reports MB-converted size values in the failure message', ()=>{
212
- const service = new StorageConfigService(buildOptions({
213
- config: {
214
- maxFileSize: 1 * 1024 * 1024
215
- }
216
- }));
217
- const result = service.validateFileSize(2 * 1024 * 1024);
218
- expect(result.message).toContain('2.00MB');
219
- expect(result.message).toContain('1.00MB');
220
- });
221
- });
222
- describe('validateFileType', ()=>{
223
- it('passes for an allowed type', ()=>{
224
- const service = new StorageConfigService(buildOptions({
225
- config: {
226
- allowedFileTypes: [
227
- 'image/*'
228
- ]
229
- }
230
- }));
231
- expect(service.validateFileType('image/png')).toEqual({
232
- valid: true
233
- });
234
- });
235
- it('fails for a disallowed type with a descriptive message and messageKey', ()=>{
236
- const service = new StorageConfigService(buildOptions({
237
- config: {
238
- allowedFileTypes: [
239
- 'image/*'
240
- ]
241
- }
242
- }));
243
- const result = service.validateFileType('application/pdf');
244
- expect(result.valid).toBe(false);
245
- expect(result.messageKey).toBe(UPLOAD_MESSAGES.INVALID_TYPE);
246
- expect(result.message).toContain('application/pdf');
247
- expect(result.messageVariables).toEqual({
248
- mimeType: 'application/pdf',
249
- allowedTypes: 'image/*'
250
- });
251
- });
252
- });
253
- });
@@ -1,86 +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
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- 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;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
29
- import { Inject, Injectable, Optional, Scope } from '@nestjs/common';
30
- import { REQUEST } from '@nestjs/core';
31
- import { Request } from 'express';
32
- import { StorageConfigService } from './storage-config.service';
33
- export class StorageDataSourceProvider extends MultiTenantDataSourceService {
34
- static buildParentOptions(options) {
35
- return {
36
- bootstrapAppConfig: options.bootstrapAppConfig,
37
- defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
38
- tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
39
- tenants: options.config?.tenants
40
- };
41
- }
42
- getEnableCompanyFeatureForTenant(tenant) {
43
- return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
44
- }
45
- async getStorageEntities(enableCompanyFeature) {
46
- const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
47
- const entities = await import('../entities');
48
- return enable ? [
49
- entities.FileManagerWithCompany,
50
- entities.FolderWithCompany,
51
- entities.StorageConfigWithCompany
52
- ] : [
53
- entities.FileManager,
54
- entities.Folder,
55
- entities.StorageConfig
56
- ];
57
- }
58
- async createDataSourceFromConfig(config) {
59
- const currentTenant = this.getCurrentTenant();
60
- const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
61
- const entities = await this.getStorageEntities(enableCompanyFeature);
62
- return super.createDataSourceFromConfig(config, entities);
63
- }
64
- constructor(configService, request){
65
- super(StorageDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
66
- }
67
- }
68
- _define_property(StorageDataSourceProvider, "tenantConnections", new Map());
69
- _define_property(StorageDataSourceProvider, "singleDataSource", null);
70
- _define_property(StorageDataSourceProvider, "tenantsRegistry", new Map());
71
- _define_property(StorageDataSourceProvider, "initialized", false);
72
- _define_property(StorageDataSourceProvider, "connectionLocks", new Map());
73
- _define_property(StorageDataSourceProvider, "singleConnectionLock", null);
74
- StorageDataSourceProvider = _ts_decorate([
75
- Injectable({
76
- scope: Scope.REQUEST
77
- }),
78
- _ts_param(0, Inject(StorageConfigService)),
79
- _ts_param(1, Optional()),
80
- _ts_param(1, Inject(REQUEST)),
81
- _ts_metadata("design:type", Function),
82
- _ts_metadata("design:paramtypes", [
83
- typeof StorageConfigService === "undefined" ? Object : StorageConfigService,
84
- typeof Request === "undefined" ? Object : Request
85
- ])
86
- ], StorageDataSourceProvider);