@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,243 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _s3provideroptional = require("./s3-provider.optional");
6
- const _imagecompressorutil = require("../utils/image-compressor.util");
7
- function _define_property(obj, key, value) {
8
- if (key in obj) {
9
- Object.defineProperty(obj, key, {
10
- value: value,
11
- enumerable: true,
12
- configurable: true,
13
- writable: true
14
- });
15
- } else {
16
- obj[key] = value;
17
- }
18
- return obj;
19
- }
20
- const mockS3ClientSend = jest.fn();
21
- const mockS3ClientCtor = jest.fn().mockImplementation(()=>({
22
- send: mockS3ClientSend
23
- }));
24
- let MockDeleteObjectCommand = class MockDeleteObjectCommand {
25
- constructor(input){
26
- _define_property(this, "input", void 0);
27
- this.input = input;
28
- }
29
- };
30
- let MockDeleteObjectsCommand = class MockDeleteObjectsCommand {
31
- constructor(input){
32
- _define_property(this, "input", void 0);
33
- this.input = input;
34
- }
35
- };
36
- let MockGetObjectCommand = class MockGetObjectCommand {
37
- constructor(input){
38
- _define_property(this, "input", void 0);
39
- this.input = input;
40
- }
41
- };
42
- let MockHeadBucketCommand = class MockHeadBucketCommand {
43
- constructor(input){
44
- _define_property(this, "input", void 0);
45
- this.input = input;
46
- }
47
- };
48
- jest.mock('@aws-sdk/client-s3', ()=>({
49
- S3Client: mockS3ClientCtor,
50
- DeleteObjectCommand: MockDeleteObjectCommand,
51
- DeleteObjectsCommand: MockDeleteObjectsCommand,
52
- GetObjectCommand: MockGetObjectCommand,
53
- HeadBucketCommand: MockHeadBucketCommand
54
- }));
55
- const mockUploadDone = jest.fn();
56
- const mockUploadCtor = jest.fn().mockImplementation(()=>({
57
- done: mockUploadDone
58
- }));
59
- jest.mock('@aws-sdk/lib-storage', ()=>({
60
- Upload: mockUploadCtor
61
- }));
62
- const mockGetSignedUrl = jest.fn();
63
- jest.mock('@aws-sdk/s3-request-presigner', ()=>({
64
- getSignedUrl: (...args)=>mockGetSignedUrl(...args)
65
- }));
66
- jest.mock('../utils/image-compressor.util', ()=>({
67
- ImageCompressor: {
68
- compress: jest.fn()
69
- }
70
- }));
71
- function buildMulterFile(overrides = {}) {
72
- return {
73
- fieldname: 'file',
74
- originalname: 'photo.jpg',
75
- encoding: '7bit',
76
- mimetype: 'image/jpeg',
77
- buffer: Buffer.from('file-bytes'),
78
- size: 10,
79
- stream: undefined,
80
- destination: '',
81
- filename: '',
82
- path: '',
83
- ...overrides
84
- };
85
- }
86
- describe('S3Provider', ()=>{
87
- let provider;
88
- beforeEach(async ()=>{
89
- jest.clearAllMocks();
90
- mockUploadDone.mockResolvedValue(undefined);
91
- provider = new _s3provideroptional.S3Provider();
92
- await provider.initialize({
93
- region: 'us-east-1',
94
- bucket: 'my-bucket'
95
- });
96
- });
97
- describe('initialize', ()=>{
98
- it('creates an S3Client with region/endpoint/credentials', async ()=>{
99
- jest.clearAllMocks();
100
- const p = new _s3provideroptional.S3Provider();
101
- await p.initialize({
102
- region: 'eu-west-1',
103
- bucket: 'bucket-2',
104
- accessKeyId: 'AKIA...',
105
- secretAccessKey: 'secret',
106
- endpoint: 'https://s3.custom.example.com'
107
- });
108
- expect(mockS3ClientCtor).toHaveBeenCalledWith(expect.objectContaining({
109
- region: 'eu-west-1',
110
- endpoint: 'https://s3.custom.example.com',
111
- credentials: {
112
- accessKeyId: 'AKIA...',
113
- secretAccessKey: 'secret'
114
- }
115
- }));
116
- });
117
- it('omits credentials when access key / secret are not provided', async ()=>{
118
- jest.clearAllMocks();
119
- const p = new _s3provideroptional.S3Provider();
120
- await p.initialize({
121
- region: 'us-east-1',
122
- bucket: 'bucket-3'
123
- });
124
- expect(mockS3ClientCtor).toHaveBeenCalledWith(expect.objectContaining({
125
- credentials: undefined
126
- }));
127
- });
128
- it('throws InternalServerErrorException when the AWS SDK cannot be initialized', async ()=>{
129
- mockS3ClientCtor.mockImplementationOnce(()=>{
130
- throw new Error('module not found');
131
- });
132
- const brokenProvider = new _s3provideroptional.S3Provider();
133
- await expect(brokenProvider.initialize({
134
- region: 'us-east-1',
135
- bucket: 'x'
136
- })).rejects.toThrow('AWS SDK not found');
137
- });
138
- });
139
- describe('uploadFile', ()=>{
140
- it('uploads via the S3 Upload helper and returns file metadata', async ()=>{
141
- const file = buildMulterFile();
142
- const result = await provider.uploadFile(file, {});
143
- expect(mockUploadCtor).toHaveBeenCalledWith(expect.objectContaining({
144
- params: expect.objectContaining({
145
- Bucket: 'my-bucket',
146
- ContentType: 'image/jpeg'
147
- })
148
- }));
149
- expect(mockUploadDone).toHaveBeenCalled();
150
- expect(result.name).toMatch(/photo\.jpg$/);
151
- expect(result.key).toBe(result.name);
152
- });
153
- it('prefixes the key with folderPath when provided', async ()=>{
154
- const file = buildMulterFile();
155
- const result = await provider.uploadFile(file, {
156
- folderPath: 'avatars'
157
- });
158
- expect(result.key).toMatch(/^avatars\//);
159
- });
160
- it('compresses image files before upload when options.compress is true', async ()=>{
161
- _imagecompressorutil.ImageCompressor.compress.mockResolvedValue({
162
- buffer: Buffer.from('compressed'),
163
- format: 'image/webp'
164
- });
165
- const file = buildMulterFile();
166
- const result = await provider.uploadFile(file, {
167
- compress: true
168
- });
169
- expect(_imagecompressorutil.ImageCompressor.compress).toHaveBeenCalled();
170
- expect(result.contentType).toBe('image/webp');
171
- });
172
- });
173
- describe('uploadMultipleFiles', ()=>{
174
- it('uploads each file and returns metadata for all', async ()=>{
175
- const files = [
176
- buildMulterFile({
177
- originalname: 'a.jpg'
178
- }),
179
- buildMulterFile({
180
- originalname: 'b.jpg'
181
- })
182
- ];
183
- const results = await provider.uploadMultipleFiles(files, {});
184
- expect(results).toHaveLength(2);
185
- expect(mockUploadCtor).toHaveBeenCalledTimes(2);
186
- });
187
- });
188
- describe('deleteFile', ()=>{
189
- it('sends a DeleteObjectCommand with bucket and key', async ()=>{
190
- await provider.deleteFile('some/key.jpg');
191
- expect(mockS3ClientSend).toHaveBeenCalledWith(expect.any(MockDeleteObjectCommand));
192
- const sentCommand = mockS3ClientSend.mock.calls[0][0];
193
- expect(sentCommand.input).toEqual({
194
- Bucket: 'my-bucket',
195
- Key: 'some/key.jpg'
196
- });
197
- });
198
- });
199
- describe('deleteMultipleFiles', ()=>{
200
- it('sends a DeleteObjectsCommand containing all keys', async ()=>{
201
- await provider.deleteMultipleFiles([
202
- 'a.jpg',
203
- 'b.jpg'
204
- ]);
205
- const sentCommand = mockS3ClientSend.mock.calls[0][0];
206
- expect(sentCommand.input.Delete.Objects).toEqual([
207
- {
208
- Key: 'a.jpg'
209
- },
210
- {
211
- Key: 'b.jpg'
212
- }
213
- ]);
214
- });
215
- });
216
- describe('generatePresignedUrl', ()=>{
217
- it('delegates to getSignedUrl with the configured expiry', async ()=>{
218
- mockGetSignedUrl.mockResolvedValue('https://signed.example.com/some/key.jpg');
219
- const url = await provider.generatePresignedUrl('some/key.jpg', 900);
220
- expect(mockGetSignedUrl).toHaveBeenCalledWith(expect.anything(), expect.any(MockGetObjectCommand), {
221
- expiresIn: 900
222
- });
223
- expect(url).toBe('https://signed.example.com/some/key.jpg');
224
- });
225
- it('defaults expiry to 3600 seconds when not provided', async ()=>{
226
- mockGetSignedUrl.mockResolvedValue('https://signed.example.com/x');
227
- await provider.generatePresignedUrl('x');
228
- expect(mockGetSignedUrl).toHaveBeenCalledWith(expect.anything(), expect.anything(), {
229
- expiresIn: 3600
230
- });
231
- });
232
- });
233
- describe('healthCheck', ()=>{
234
- it('returns true when HeadBucketCommand succeeds', async ()=>{
235
- mockS3ClientSend.mockResolvedValue({});
236
- await expect(provider.healthCheck()).resolves.toBe(true);
237
- });
238
- it('returns false when HeadBucketCommand rejects (bucket missing/unauthorized)', async ()=>{
239
- mockS3ClientSend.mockRejectedValue(new Error('Forbidden'));
240
- await expect(provider.healthCheck()).resolves.toBe(false);
241
- });
242
- });
243
- });
@@ -1,203 +0,0 @@
1
- /**
2
- * OPTIONAL SFTP Provider
3
- *
4
- * This provider requires ssh2-sftp-client package to be installed.
5
- * Only import this if you need SFTP storage.
6
- *
7
- * Installation:
8
- * npm install ssh2-sftp-client
9
- * npm install -D @types/ssh2-sftp-client
10
- *
11
- * Usage:
12
- * import { SftpProvider } from '@flusys/nestjs-storage/providers/sftp-provider.optional';
13
- * import { StorageProviderRegistry, FileLocationEnum } from '@flusys/nestjs-storage';
14
- *
15
- * StorageProviderRegistry.register(FileLocationEnum.SFTP, SftpProvider);
16
- */ "use strict";
17
- Object.defineProperty(exports, "__esModule", {
18
- value: true
19
- });
20
- Object.defineProperty(exports, "SftpProvider", {
21
- enumerable: true,
22
- get: function() {
23
- return SftpProvider;
24
- }
25
- });
26
- const _common = require("@nestjs/common");
27
- const _constants = require("@flusys/nestjs-shared/constants");
28
- const _imagecompressorutil = require("../utils/image-compressor.util");
29
- const _path = /*#__PURE__*/ _interop_require_wildcard(require("path"));
30
- const _uuid = require("uuid");
31
- function _define_property(obj, key, value) {
32
- if (key in obj) {
33
- Object.defineProperty(obj, key, {
34
- value: value,
35
- enumerable: true,
36
- configurable: true,
37
- writable: true
38
- });
39
- } else {
40
- obj[key] = value;
41
- }
42
- return obj;
43
- }
44
- function _getRequireWildcardCache(nodeInterop) {
45
- if (typeof WeakMap !== "function") return null;
46
- var cacheBabelInterop = new WeakMap();
47
- var cacheNodeInterop = new WeakMap();
48
- return (_getRequireWildcardCache = function(nodeInterop) {
49
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
50
- })(nodeInterop);
51
- }
52
- function _interop_require_wildcard(obj, nodeInterop) {
53
- if (!nodeInterop && obj && obj.__esModule) {
54
- return obj;
55
- }
56
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
57
- return {
58
- default: obj
59
- };
60
- }
61
- var cache = _getRequireWildcardCache(nodeInterop);
62
- if (cache && cache.has(obj)) {
63
- return cache.get(obj);
64
- }
65
- var newObj = {
66
- __proto__: null
67
- };
68
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
69
- for(var key in obj){
70
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
71
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
72
- if (desc && (desc.get || desc.set)) {
73
- Object.defineProperty(newObj, key, desc);
74
- } else {
75
- newObj[key] = obj[key];
76
- }
77
- }
78
- }
79
- newObj.default = obj;
80
- if (cache) {
81
- cache.set(obj, newObj);
82
- }
83
- return newObj;
84
- }
85
- let SftpProvider = class SftpProvider {
86
- /**
87
- * Initialize SFTP provider with configuration
88
- */ async initialize(config) {
89
- try {
90
- // Dynamic import - only loads SFTP SDK if this provider is used
91
- const sftp = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("ssh2-sftp-client")));
92
- const SftpClient = sftp.default || sftp;
93
- this.sftp = new SftpClient();
94
- this.config = {
95
- host: config.host,
96
- port: config.port || 22,
97
- username: config.username,
98
- password: config.password,
99
- privateKey: config.privateKey,
100
- basePath: config.basePath || '/uploads'
101
- };
102
- // Connect
103
- await this.connect();
104
- // Ensure base directory exists
105
- await this.ensureDirectory(this.config.basePath);
106
- } catch {
107
- throw new _common.InternalServerErrorException({
108
- message: 'SFTP client not found',
109
- messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
110
- messageVariables: {
111
- sdk: 'ssh2-sftp-client'
112
- }
113
- });
114
- }
115
- }
116
- async connect() {
117
- if (!this.connected) {
118
- await this.sftp.connect({
119
- host: this.config.host,
120
- port: this.config.port,
121
- username: this.config.username,
122
- password: this.config.password,
123
- privateKey: this.config.privateKey
124
- });
125
- this.connected = true;
126
- }
127
- }
128
- async ensureDirectory(dirPath) {
129
- try {
130
- await this.sftp.mkdir(dirPath, true);
131
- } catch {
132
- // Directory might already exist
133
- }
134
- }
135
- async uploadFile(file, options) {
136
- await this.connect();
137
- let processedBuffer = file.buffer;
138
- let contentType = file.mimetype;
139
- const fileName = `${(0, _uuid.v4)()}-${file.originalname}`;
140
- // Compress image if needed
141
- if (options.compress && file.mimetype.startsWith('image/')) {
142
- const result = await _imagecompressorutil.ImageCompressor.compress(file.buffer, file.mimetype, {
143
- maxWidth: options.maxWidth,
144
- maxHeight: options.maxHeight,
145
- quality: options.quality,
146
- format: options.format
147
- });
148
- processedBuffer = result.buffer;
149
- contentType = result.format;
150
- }
151
- const remotePath = options.folderPath ? _path.join(this.config.basePath, options.folderPath, fileName) : _path.join(this.config.basePath, fileName);
152
- // Ensure parent directory exists
153
- const remoteDir = _path.dirname(remotePath);
154
- await this.ensureDirectory(remoteDir);
155
- // Upload file
156
- await this.sftp.put(processedBuffer, remotePath);
157
- return {
158
- name: fileName,
159
- key: remotePath,
160
- size: processedBuffer.length,
161
- contentType
162
- };
163
- }
164
- async uploadMultipleFiles(files, options) {
165
- return Promise.all(files.map((file)=>this.uploadFile(file, options)));
166
- }
167
- async deleteFile(key) {
168
- await this.connect();
169
- try {
170
- await this.sftp.delete(key);
171
- } catch {
172
- // Silent failure
173
- }
174
- }
175
- async deleteMultipleFiles(keys) {
176
- await Promise.all(keys.map((key)=>this.deleteFile(key)));
177
- }
178
- async generatePresignedUrl(key, _expiresInSeconds) {
179
- // SFTP doesn't support presigned URLs, return the key
180
- return key;
181
- }
182
- async healthCheck() {
183
- try {
184
- await this.connect();
185
- return this.connected;
186
- } catch {
187
- return false;
188
- }
189
- }
190
- /**
191
- * Close SFTP connection
192
- */ async close() {
193
- if (this.connected) {
194
- await this.sftp.end();
195
- this.connected = false;
196
- }
197
- }
198
- constructor(){
199
- _define_property(this, "sftp", void 0); // SftpClient
200
- _define_property(this, "config", void 0);
201
- _define_property(this, "connected", false);
202
- }
203
- };
@@ -1,217 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _sftpprovideroptional = require("./sftp-provider.optional");
6
- const _imagecompressorutil = require("../utils/image-compressor.util");
7
- function _define_property(obj, key, value) {
8
- if (key in obj) {
9
- Object.defineProperty(obj, key, {
10
- value: value,
11
- enumerable: true,
12
- configurable: true,
13
- writable: true
14
- });
15
- } else {
16
- obj[key] = value;
17
- }
18
- return obj;
19
- }
20
- const mockConnect = jest.fn();
21
- const mockMkdir = jest.fn();
22
- const mockPut = jest.fn();
23
- const mockDelete = jest.fn();
24
- const mockEnd = jest.fn();
25
- let MockSftpClient = class MockSftpClient {
26
- constructor(){
27
- _define_property(this, "connect", mockConnect);
28
- _define_property(this, "mkdir", mockMkdir);
29
- _define_property(this, "put", mockPut);
30
- _define_property(this, "delete", mockDelete);
31
- _define_property(this, "end", mockEnd);
32
- }
33
- };
34
- jest.mock('ssh2-sftp-client', ()=>({
35
- __esModule: true,
36
- default: MockSftpClient
37
- }), {
38
- virtual: true
39
- });
40
- jest.mock('../utils/image-compressor.util', ()=>({
41
- ImageCompressor: {
42
- compress: jest.fn()
43
- }
44
- }));
45
- function buildMulterFile(overrides = {}) {
46
- return {
47
- fieldname: 'file',
48
- originalname: 'photo.jpg',
49
- encoding: '7bit',
50
- mimetype: 'image/jpeg',
51
- buffer: Buffer.from('file-bytes'),
52
- size: 10,
53
- stream: undefined,
54
- destination: '',
55
- filename: '',
56
- path: '',
57
- ...overrides
58
- };
59
- }
60
- describe('SftpProvider', ()=>{
61
- let provider;
62
- beforeEach(async ()=>{
63
- jest.clearAllMocks();
64
- mockConnect.mockResolvedValue(undefined);
65
- mockMkdir.mockResolvedValue(undefined);
66
- mockPut.mockResolvedValue(undefined);
67
- mockDelete.mockResolvedValue(undefined);
68
- mockEnd.mockResolvedValue(undefined);
69
- provider = new _sftpprovideroptional.SftpProvider();
70
- await provider.initialize({
71
- host: 'sftp.example.com',
72
- username: 'deploy',
73
- password: 'secret',
74
- basePath: '/uploads'
75
- });
76
- });
77
- describe('initialize', ()=>{
78
- it('connects and ensures the base directory exists', ()=>{
79
- expect(mockConnect).toHaveBeenCalledWith(expect.objectContaining({
80
- host: 'sftp.example.com',
81
- username: 'deploy',
82
- password: 'secret'
83
- }));
84
- expect(mockMkdir).toHaveBeenCalledWith('/uploads', true);
85
- });
86
- it('defaults port to 22 and basePath to /uploads when not provided', async ()=>{
87
- jest.clearAllMocks();
88
- mockConnect.mockResolvedValue(undefined);
89
- mockMkdir.mockResolvedValue(undefined);
90
- const p = new _sftpprovideroptional.SftpProvider();
91
- await p.initialize({
92
- host: 'h',
93
- username: 'u'
94
- });
95
- expect(mockConnect).toHaveBeenCalledWith(expect.objectContaining({
96
- port: 22
97
- }));
98
- expect(mockMkdir).toHaveBeenCalledWith('/uploads', true);
99
- });
100
- it('swallows mkdir errors (directory might already exist)', async ()=>{
101
- jest.clearAllMocks();
102
- mockConnect.mockResolvedValue(undefined);
103
- mockMkdir.mockRejectedValue(new Error('EEXIST'));
104
- const p = new _sftpprovideroptional.SftpProvider();
105
- await expect(p.initialize({
106
- host: 'h',
107
- username: 'u',
108
- basePath: '/data'
109
- })).resolves.toBeUndefined();
110
- });
111
- it('throws InternalServerErrorException when the SFTP client cannot connect during initialize', async ()=>{
112
- mockConnect.mockRejectedValueOnce(new Error('ECONNREFUSED'));
113
- const brokenProvider = new _sftpprovideroptional.SftpProvider();
114
- await expect(brokenProvider.initialize({
115
- host: 'unreachable',
116
- username: 'u'
117
- })).rejects.toThrow('SFTP client not found');
118
- });
119
- });
120
- describe('uploadFile', ()=>{
121
- it('uploads the file under basePath and returns metadata', async ()=>{
122
- const file = buildMulterFile();
123
- const result = await provider.uploadFile(file, {});
124
- expect(mockPut).toHaveBeenCalledWith(file.buffer, expect.stringContaining('/uploads/'));
125
- expect(result.name).toMatch(/photo\.jpg$/);
126
- expect(result.key).toContain('/uploads/');
127
- });
128
- it('nests the remote path under folderPath when provided', async ()=>{
129
- const file = buildMulterFile();
130
- const result = await provider.uploadFile(file, {
131
- folderPath: 'images'
132
- });
133
- expect(result.key).toContain('/uploads/images/');
134
- });
135
- it('compresses image files when options.compress is true', async ()=>{
136
- _imagecompressorutil.ImageCompressor.compress.mockResolvedValue({
137
- buffer: Buffer.from('small'),
138
- format: 'image/webp'
139
- });
140
- const file = buildMulterFile();
141
- const result = await provider.uploadFile(file, {
142
- compress: true
143
- });
144
- expect(_imagecompressorutil.ImageCompressor.compress).toHaveBeenCalled();
145
- expect(result.contentType).toBe('image/webp');
146
- });
147
- it('reconnects if not already connected before uploading', async ()=>{
148
- const file = buildMulterFile();
149
- mockConnect.mockClear();
150
- await provider.uploadFile(file, {});
151
- // already connected from initialize(); connect() should be a no-op guarded by `connected` flag
152
- expect(mockConnect).not.toHaveBeenCalled();
153
- });
154
- });
155
- describe('uploadMultipleFiles', ()=>{
156
- it('uploads all files', async ()=>{
157
- const files = [
158
- buildMulterFile({
159
- originalname: 'a.jpg'
160
- }),
161
- buildMulterFile({
162
- originalname: 'b.jpg'
163
- })
164
- ];
165
- const results = await provider.uploadMultipleFiles(files, {});
166
- expect(results).toHaveLength(2);
167
- expect(mockPut).toHaveBeenCalledTimes(2);
168
- });
169
- });
170
- describe('deleteFile', ()=>{
171
- it('deletes the file at the given remote path', async ()=>{
172
- await provider.deleteFile('/uploads/photo.jpg');
173
- expect(mockDelete).toHaveBeenCalledWith('/uploads/photo.jpg');
174
- });
175
- it('silently swallows delete errors', async ()=>{
176
- mockDelete.mockRejectedValue(new Error('not found'));
177
- await expect(provider.deleteFile('/uploads/missing.jpg')).resolves.toBeUndefined();
178
- });
179
- });
180
- describe('deleteMultipleFiles', ()=>{
181
- it('deletes every provided key', async ()=>{
182
- await provider.deleteMultipleFiles([
183
- '/uploads/a.jpg',
184
- '/uploads/b.jpg'
185
- ]);
186
- expect(mockDelete).toHaveBeenCalledTimes(2);
187
- });
188
- });
189
- describe('generatePresignedUrl', ()=>{
190
- it('returns the key unchanged since SFTP has no presigned URL support', async ()=>{
191
- const url = await provider.generatePresignedUrl('/uploads/photo.jpg', 3600);
192
- expect(url).toBe('/uploads/photo.jpg');
193
- });
194
- });
195
- describe('healthCheck', ()=>{
196
- it('returns true when connected', async ()=>{
197
- await expect(provider.healthCheck()).resolves.toBe(true);
198
- });
199
- it('returns false when reconnecting fails', async ()=>{
200
- // Disconnect first so healthCheck() must attempt to reconnect via this.connect()
201
- await provider.close();
202
- mockConnect.mockRejectedValueOnce(new Error('unreachable'));
203
- await expect(provider.healthCheck()).resolves.toBe(false);
204
- });
205
- });
206
- describe('close', ()=>{
207
- it('ends the connection when connected', async ()=>{
208
- await provider.close();
209
- expect(mockEnd).toHaveBeenCalled();
210
- });
211
- it('does nothing when not connected', async ()=>{
212
- const freshProvider = new _sftpprovideroptional.SftpProvider();
213
- await expect(freshProvider.close()).resolves.toBeUndefined();
214
- expect(mockEnd).not.toHaveBeenCalled();
215
- });
216
- });
217
- });