@flusys/nestjs-storage 7.0.2 → 8.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,162 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "ImageCompressor", {
6
- enumerable: true,
7
- get: function() {
8
- return ImageCompressor;
9
- }
10
- });
11
- const _sharp = /*#__PURE__*/ _interop_require_wildcard(require("sharp"));
12
- function _getRequireWildcardCache(nodeInterop) {
13
- if (typeof WeakMap !== "function") return null;
14
- var cacheBabelInterop = new WeakMap();
15
- var cacheNodeInterop = new WeakMap();
16
- return (_getRequireWildcardCache = function(nodeInterop) {
17
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
18
- })(nodeInterop);
19
- }
20
- function _interop_require_wildcard(obj, nodeInterop) {
21
- if (!nodeInterop && obj && obj.__esModule) {
22
- return obj;
23
- }
24
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
25
- return {
26
- default: obj
27
- };
28
- }
29
- var cache = _getRequireWildcardCache(nodeInterop);
30
- if (cache && cache.has(obj)) {
31
- return cache.get(obj);
32
- }
33
- var newObj = {
34
- __proto__: null
35
- };
36
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
37
- for(var key in obj){
38
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
39
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
40
- if (desc && (desc.get || desc.set)) {
41
- Object.defineProperty(newObj, key, desc);
42
- } else {
43
- newObj[key] = obj[key];
44
- }
45
- }
46
- }
47
- newObj.default = obj;
48
- if (cache) {
49
- cache.set(obj, newObj);
50
- }
51
- return newObj;
52
- }
53
- // Handle ESM/CJS interop - sharp exports differently in each module system
54
- const sharp = _sharp.default || _sharp;
55
- let ImageCompressor = class ImageCompressor {
56
- /**
57
- * Dynamically compresses an image based on its format and provided options.
58
- * - Preserves original format if not overridden
59
- * - Adjusts compression settings for each codec
60
- */ static async compress(buffer, mimetype, options = {}) {
61
- const { maxWidth = 1280, maxHeight = 1280, quality = 85, format = 'original' } = options;
62
- // Skip processing for SVG
63
- if (mimetype === 'image/svg+xml') {
64
- return {
65
- buffer,
66
- format: mimetype
67
- };
68
- }
69
- // Initialize sharp with improved error handling
70
- const image = sharp(buffer, {
71
- failOnError: false,
72
- density: 300
73
- });
74
- // Apply initial resize
75
- image.resize({
76
- width: maxWidth,
77
- height: maxHeight,
78
- fit: 'inside',
79
- withoutEnlargement: true
80
- });
81
- // Determine target format
82
- let targetFormat = format !== 'original' ? format : mimetype.split('/')[1];
83
- // Format-specific optimizations
84
- switch(targetFormat.toLowerCase()){
85
- case 'jpeg':
86
- case 'jpg':
87
- image.jpeg({
88
- quality,
89
- mozjpeg: true,
90
- chromaSubsampling: '4:4:4'
91
- });
92
- break;
93
- case 'png':
94
- image.png({
95
- compressionLevel: 9,
96
- adaptiveFiltering: true,
97
- palette: true,
98
- quality,
99
- colors: 256,
100
- dither: 1.0
101
- });
102
- break;
103
- case 'webp':
104
- image.webp({
105
- quality,
106
- smartSubsample: true,
107
- effort: 6,
108
- lossless: quality === 100
109
- });
110
- break;
111
- case 'avif':
112
- image.avif({
113
- quality,
114
- effort: 6,
115
- chromaSubsampling: '4:4:4'
116
- });
117
- break;
118
- case 'tiff':
119
- image.tiff({
120
- quality,
121
- compression: 'lzw',
122
- predictor: 'horizontal',
123
- pyramid: true
124
- });
125
- break;
126
- case 'gif':
127
- image.gif({
128
- colours: 256,
129
- effort: 10,
130
- dither: 1
131
- });
132
- break;
133
- case 'jp2':
134
- image.jp2({
135
- quality,
136
- lossless: quality === 100
137
- });
138
- break;
139
- default:
140
- // Fallback to WebP for best compression/quality ratio
141
- targetFormat = 'webp';
142
- image.webp({
143
- quality,
144
- smartSubsample: true,
145
- effort: 6
146
- });
147
- break;
148
- }
149
- try {
150
- const compressedBuffer = await image.toBuffer();
151
- return {
152
- buffer: compressedBuffer,
153
- format: `image/${targetFormat}`
154
- };
155
- } catch {
156
- return {
157
- buffer,
158
- format: mimetype
159
- };
160
- }
161
- }
162
- };
@@ -1,166 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _imagecompressorutil = require("./image-compressor.util");
6
- const mockToBuffer = jest.fn();
7
- const mockJpeg = jest.fn();
8
- const mockPng = jest.fn();
9
- const mockWebp = jest.fn();
10
- const mockAvif = jest.fn();
11
- const mockTiff = jest.fn();
12
- const mockGif = jest.fn();
13
- const mockJp2 = jest.fn();
14
- const mockResize = jest.fn();
15
- function buildChainableImage() {
16
- const image = {};
17
- image.resize = mockResize.mockReturnValue(image);
18
- image.jpeg = mockJpeg.mockReturnValue(image);
19
- image.png = mockPng.mockReturnValue(image);
20
- image.webp = mockWebp.mockReturnValue(image);
21
- image.avif = mockAvif.mockReturnValue(image);
22
- image.tiff = mockTiff.mockReturnValue(image);
23
- image.gif = mockGif.mockReturnValue(image);
24
- image.jp2 = mockJp2.mockReturnValue(image);
25
- image.toBuffer = mockToBuffer;
26
- return image;
27
- }
28
- const mockSharpFactory = jest.fn();
29
- jest.mock('sharp', ()=>{
30
- const factory = (...args)=>mockSharpFactory(...args);
31
- return {
32
- __esModule: true,
33
- default: factory
34
- };
35
- });
36
- describe('ImageCompressor', ()=>{
37
- beforeEach(()=>{
38
- jest.clearAllMocks();
39
- mockSharpFactory.mockImplementation(()=>buildChainableImage());
40
- mockToBuffer.mockResolvedValue(Buffer.from('compressed-image-data'));
41
- });
42
- it('returns the buffer unchanged for image/svg+xml without invoking sharp', async ()=>{
43
- const buffer = Buffer.from('<svg></svg>');
44
- const result = await _imagecompressorutil.ImageCompressor.compress(buffer, 'image/svg+xml');
45
- expect(result.buffer).toBe(buffer);
46
- expect(result.format).toBe('image/svg+xml');
47
- expect(mockSharpFactory).not.toHaveBeenCalled();
48
- });
49
- it('resizes using default maxWidth/maxHeight when no options are provided', async ()=>{
50
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('jpeg-bytes'), 'image/jpeg');
51
- expect(mockResize).toHaveBeenCalledWith(expect.objectContaining({
52
- width: 1280,
53
- height: 1280,
54
- fit: 'inside',
55
- withoutEnlargement: true
56
- }));
57
- });
58
- it('resizes using custom maxWidth/maxHeight when provided', async ()=>{
59
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('jpeg-bytes'), 'image/jpeg', {
60
- maxWidth: 500,
61
- maxHeight: 600
62
- });
63
- expect(mockResize).toHaveBeenCalledWith(expect.objectContaining({
64
- width: 500,
65
- height: 600
66
- }));
67
- });
68
- it('preserves the original format (derived from mimetype) when format is "original"', async ()=>{
69
- const result = await _imagecompressorutil.ImageCompressor.compress(Buffer.from('png-bytes'), 'image/png', {
70
- format: 'original'
71
- });
72
- expect(mockPng).toHaveBeenCalled();
73
- expect(result.format).toBe('image/png');
74
- });
75
- it('applies jpeg-specific compression options with quality', async ()=>{
76
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/jpeg', {
77
- quality: 70
78
- });
79
- expect(mockJpeg).toHaveBeenCalledWith(expect.objectContaining({
80
- quality: 70,
81
- mozjpeg: true
82
- }));
83
- });
84
- it('applies png-specific compression options', async ()=>{
85
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/png', {
86
- quality: 90
87
- });
88
- expect(mockPng).toHaveBeenCalledWith(expect.objectContaining({
89
- quality: 90,
90
- colors: 256
91
- }));
92
- });
93
- it('applies webp-specific options and sets lossless=true only when quality is 100', async ()=>{
94
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/webp', {
95
- quality: 100,
96
- format: 'webp'
97
- });
98
- expect(mockWebp).toHaveBeenCalledWith(expect.objectContaining({
99
- quality: 100,
100
- lossless: true
101
- }));
102
- });
103
- it('applies webp-specific options with lossless=false for quality < 100', async ()=>{
104
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/webp', {
105
- quality: 80,
106
- format: 'webp'
107
- });
108
- expect(mockWebp).toHaveBeenCalledWith(expect.objectContaining({
109
- quality: 80,
110
- lossless: false
111
- }));
112
- });
113
- it('applies avif-specific compression options', async ()=>{
114
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/avif', {
115
- format: 'avif'
116
- });
117
- expect(mockAvif).toHaveBeenCalled();
118
- });
119
- it('applies tiff-specific compression options', async ()=>{
120
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/tiff', {
121
- format: 'tiff'
122
- });
123
- expect(mockTiff).toHaveBeenCalled();
124
- });
125
- it('applies gif-specific compression options', async ()=>{
126
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/gif', {
127
- format: 'gif'
128
- });
129
- expect(mockGif).toHaveBeenCalled();
130
- });
131
- it('applies jp2-specific compression options', async ()=>{
132
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/jp2', {
133
- format: 'jp2'
134
- });
135
- expect(mockJp2).toHaveBeenCalled();
136
- });
137
- it('falls back to webp for an unrecognized target format', async ()=>{
138
- const result = await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/unknownformat', {
139
- format: 'original'
140
- });
141
- expect(mockWebp).toHaveBeenCalled();
142
- expect(result.format).toBe('image/webp');
143
- });
144
- it('returns the compressed buffer and content-type prefixed format on success', async ()=>{
145
- mockToBuffer.mockResolvedValue(Buffer.from('final-bytes'));
146
- const result = await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/jpeg', {
147
- format: 'jpeg'
148
- });
149
- expect(result.buffer).toEqual(Buffer.from('final-bytes'));
150
- expect(result.format).toBe('image/jpeg');
151
- });
152
- it('falls back to the original buffer and mimetype when sharp processing throws', async ()=>{
153
- const originalBuffer = Buffer.from('original-bytes');
154
- mockToBuffer.mockRejectedValue(new Error('corrupt image'));
155
- const result = await _imagecompressorutil.ImageCompressor.compress(originalBuffer, 'image/png');
156
- expect(result.buffer).toBe(originalBuffer);
157
- expect(result.format).toBe('image/png');
158
- });
159
- it('initializes sharp with failOnError=false and a density hint', async ()=>{
160
- await _imagecompressorutil.ImageCompressor.compress(Buffer.from('bytes'), 'image/jpeg');
161
- expect(mockSharpFactory).toHaveBeenCalledWith(expect.any(Buffer), expect.objectContaining({
162
- failOnError: false,
163
- density: 300
164
- }));
165
- });
166
- });
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- _export_star(require("./image-compressor.util"), exports);
6
- function _export_star(from, to) {
7
- Object.keys(from).forEach(function(k) {
8
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
9
- Object.defineProperty(to, k, {
10
- enumerable: true,
11
- get: function() {
12
- return from[k];
13
- }
14
- });
15
- }
16
- });
17
- return from;
18
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Domain event actions published by the storage module, alongside the CRUD
3
- * lifecycle actions every ApiService emits.
4
- */ export const STORAGE_EVENT_ACTIONS = {
5
- UPLOADED: 'uploaded',
6
- REMOVED: 'removed'
7
- };
8
- /** Every entity the storage module publishes under, ApiService backed or not */ export const STORAGE_EVENT_ENTITIES = {
9
- FILE: 'file_manager',
10
- FOLDER: 'folder',
11
- STORAGE_CONFIG: 'storageConfig'
12
- };
13
- export const STORAGE_EVENT_MODULE = 'storage';
@@ -1,22 +0,0 @@
1
- // ==================== STORAGE MODULE MESSAGE KEYS ====================
2
- export const FILE_MESSAGES = {
3
- GET_ALL_SUCCESS: 'file.get.all.success',
4
- DELETE_SUCCESS: 'file.delete.success',
5
- NOT_FOUND: 'file.not.found'
6
- };
7
- export const STORAGE_CONFIG_MESSAGES = {
8
- DEFAULT_DELETE_FORBIDDEN: 'storage.config.default.delete.forbidden'
9
- };
10
- export const FOLDER_MESSAGES = {
11
- NOT_FOUND: 'folder.not.found'
12
- };
13
- export const UPLOAD_MESSAGES = {
14
- SUCCESS: 'upload.success',
15
- MANY_SUCCESS: 'upload.many.success',
16
- FILE_TOO_LARGE: 'upload.file.too.large',
17
- INVALID_TYPE: 'upload.invalid.type',
18
- NO_FILES_PROVIDED: 'upload.no.files.provided',
19
- NO_FILE_PATH: 'upload.no.file.path',
20
- INVALID_FILE_PATH: 'upload.invalid.file.path',
21
- CONFIG_NOT_FOUND: 'upload.config.not.found'
22
- };
@@ -1,7 +0,0 @@
1
- /**
2
- * Storage Module Constants
3
- */ export const STORAGE_MODULE_OPTIONS = 'STORAGE_MODULE_OPTIONS';
4
- export const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
5
- export const DEFAULT_ALLOWED_FILE_TYPES = [
6
- '*/*'
7
- ]; // All file types
@@ -1,142 +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 { BadRequestException, Body, Controller, HttpCode, Inject, Post, Req, UseGuards } from '@nestjs/common';
29
- import { createApiController, FILE_PERMISSIONS } from '@flusys/nestjs-shared/classes';
30
- import { FILE_MESSAGES, UPLOAD_MESSAGES } from '../config';
31
- import { CurrentUser } from '@flusys/nestjs-shared/decorators';
32
- import { SingleResponseDto } from '@flusys/nestjs-shared/dtos';
33
- import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
34
- import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
35
- import { CreateFileManagerDto, FileManagerResponseDto, GetFilesRequestDto, UpdateFileManagerDto } from '../dtos';
36
- import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
37
- import { Request } from 'express';
38
- import { FileManagerService } from '../services/file-manager.service';
39
- export class FileManagerController extends createApiController(CreateFileManagerDto, UpdateFileManagerDto, FileManagerResponseDto, {
40
- entityName: 'file',
41
- security: {
42
- insert: {
43
- level: 'permission',
44
- permissions: [
45
- FILE_PERMISSIONS.CREATE
46
- ]
47
- },
48
- insertMany: {
49
- level: 'permission',
50
- permissions: [
51
- FILE_PERMISSIONS.CREATE
52
- ]
53
- },
54
- getById: {
55
- level: 'permission',
56
- permissions: [
57
- FILE_PERMISSIONS.READ
58
- ]
59
- },
60
- getAll: {
61
- level: 'permission',
62
- permissions: [
63
- FILE_PERMISSIONS.READ
64
- ]
65
- },
66
- update: {
67
- level: 'permission',
68
- permissions: [
69
- FILE_PERMISSIONS.UPDATE
70
- ]
71
- },
72
- updateMany: {
73
- level: 'permission',
74
- permissions: [
75
- FILE_PERMISSIONS.UPDATE
76
- ]
77
- },
78
- delete: {
79
- level: 'permission',
80
- permissions: [
81
- FILE_PERMISSIONS.DELETE
82
- ]
83
- }
84
- }
85
- }) {
86
- async getFiles(dto, req, user) {
87
- if (!dto || !dto.length) {
88
- throw new BadRequestException({
89
- message: 'No files provided',
90
- messageKey: UPLOAD_MESSAGES.NO_FILES_PROVIDED
91
- });
92
- }
93
- // Fetch files from service
94
- const files = await this.fileService.getFiles(dto, req.protocol, req.get('host') || req.hostname, user);
95
- return {
96
- success: true,
97
- message: 'Files retrieved successfully',
98
- messageKey: FILE_MESSAGES.GET_ALL_SUCCESS,
99
- data: files
100
- };
101
- }
102
- constructor(fileService){
103
- super(fileService), _define_property(this, "fileService", void 0), this.fileService = fileService;
104
- }
105
- }
106
- _ts_decorate([
107
- Post('get-files'),
108
- UseGuards(JwtAuthGuard),
109
- ApiBearerAuth(),
110
- HttpCode(200),
111
- ApiBody({
112
- type: GetFilesRequestDto,
113
- isArray: true
114
- }),
115
- ApiOperation({
116
- summary: 'Get multiple files by IDs with authentication (local or S3)'
117
- }),
118
- ApiResponse({
119
- status: 200,
120
- description: 'Files retrieved successfully',
121
- type: SingleResponseDto
122
- }),
123
- _ts_param(0, Body()),
124
- _ts_param(1, Req()),
125
- _ts_param(2, CurrentUser()),
126
- _ts_metadata("design:type", Function),
127
- _ts_metadata("design:paramtypes", [
128
- typeof Array === "undefined" ? Object : Array,
129
- typeof Request === "undefined" ? Object : Request,
130
- typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
131
- ]),
132
- _ts_metadata("design:returntype", Promise)
133
- ], FileManagerController.prototype, "getFiles", null);
134
- FileManagerController = _ts_decorate([
135
- ApiTags('Files'),
136
- Controller('storage/file-manager'),
137
- _ts_param(0, Inject(FileManagerService)),
138
- _ts_metadata("design:type", Function),
139
- _ts_metadata("design:paramtypes", [
140
- typeof FileManagerService === "undefined" ? Object : FileManagerService
141
- ])
142
- ], FileManagerController);
@@ -1,131 +0,0 @@
1
- import { BadRequestException } from '@nestjs/common';
2
- import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
3
- import { FileManagerController } from './file-manager.controller';
4
- function buildFile(overrides = {}) {
5
- return {
6
- id: 'file-1',
7
- name: 'report.pdf',
8
- key: 'files/report.pdf',
9
- size: 1024,
10
- contentType: 'application/pdf',
11
- isActive: true,
12
- readOnly: false,
13
- createdAt: new Date(),
14
- updatedAt: new Date(),
15
- ...overrides
16
- };
17
- }
18
- describe('FileManagerController', ()=>{
19
- let controller;
20
- let mockFileService;
21
- beforeEach(()=>{
22
- mockFileService = {
23
- insert: jest.fn(),
24
- findById: jest.fn(),
25
- getAll: jest.fn(),
26
- update: jest.fn(),
27
- delete: jest.fn(),
28
- getFiles: jest.fn()
29
- };
30
- controller = new FileManagerController(mockFileService);
31
- });
32
- describe('insert', ()=>{
33
- it('creates a file record and returns the mapped response', async ()=>{
34
- const user = buildMockUser();
35
- mockFileService.insert.mockResolvedValue(buildFile());
36
- const result = await controller.insert({
37
- name: 'report.pdf'
38
- }, user);
39
- expect(mockFileService.insert).toHaveBeenCalledWith({
40
- name: 'report.pdf'
41
- }, user);
42
- expect(result.success).toBe(true);
43
- expect(result.data).toEqual(expect.objectContaining({
44
- id: 'file-1'
45
- }));
46
- });
47
- });
48
- describe('getAll', ()=>{
49
- it('paginates files and maps the response list', async ()=>{
50
- mockFileService.getAll.mockResolvedValue({
51
- data: [
52
- buildFile()
53
- ],
54
- total: 1
55
- });
56
- const result = await controller.getAll({}, buildMockUser(), '');
57
- expect(mockFileService.getAll).toHaveBeenCalledWith('', {}, buildMockUser());
58
- expect(result.data).toHaveLength(1);
59
- });
60
- });
61
- describe('getFiles', ()=>{
62
- it('resolves signed/public URLs for the requested files using the request protocol and host', async ()=>{
63
- const user = buildMockUser();
64
- const req = {
65
- protocol: 'https',
66
- hostname: 'app.example.com',
67
- get: jest.fn().mockReturnValue('app.example.com')
68
- };
69
- mockFileService.getFiles.mockResolvedValue([
70
- {
71
- id: 'file-1',
72
- url: 'https://app.example.com/storage/upload/file/report.pdf'
73
- }
74
- ]);
75
- const result = await controller.getFiles([
76
- {
77
- id: 'file-1'
78
- }
79
- ], req, user);
80
- expect(mockFileService.getFiles).toHaveBeenCalledWith([
81
- {
82
- id: 'file-1'
83
- }
84
- ], 'https', 'app.example.com', user);
85
- expect(result.success).toBe(true);
86
- expect(result.data).toEqual([
87
- {
88
- id: 'file-1',
89
- url: 'https://app.example.com/storage/upload/file/report.pdf'
90
- }
91
- ]);
92
- });
93
- it('falls back to req.hostname when the host header is absent', async ()=>{
94
- const user = buildMockUser();
95
- const req = {
96
- protocol: 'http',
97
- hostname: 'localhost',
98
- get: jest.fn().mockReturnValue(undefined)
99
- };
100
- mockFileService.getFiles.mockResolvedValue([]);
101
- await controller.getFiles([
102
- {
103
- id: 'file-1'
104
- }
105
- ], req, user);
106
- expect(mockFileService.getFiles).toHaveBeenCalledWith([
107
- {
108
- id: 'file-1'
109
- }
110
- ], 'http', 'localhost', user);
111
- });
112
- it('rejects an empty file id list without calling the service', async ()=>{
113
- const user = buildMockUser();
114
- const req = {
115
- protocol: 'https',
116
- get: jest.fn()
117
- };
118
- await expect(controller.getFiles([], req, user)).rejects.toThrow(BadRequestException);
119
- expect(mockFileService.getFiles).not.toHaveBeenCalled();
120
- });
121
- it('rejects a null/undefined dto without calling the service', async ()=>{
122
- const user = buildMockUser();
123
- const req = {
124
- protocol: 'https',
125
- get: jest.fn()
126
- };
127
- await expect(controller.getFiles(undefined, req, user)).rejects.toThrow(BadRequestException);
128
- expect(mockFileService.getFiles).not.toHaveBeenCalled();
129
- });
130
- });
131
- });