@ackplus/nest-file-storage 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +6 -404
  2. package/eslint.config.mjs +22 -0
  3. package/jest.config.ts +10 -0
  4. package/package.json +5 -62
  5. package/project.json +38 -0
  6. package/{dist/index.d.ts → src/index.ts} +0 -1
  7. package/src/lib/constants.ts +1 -0
  8. package/src/lib/file-storage.service.ts +36 -0
  9. package/{dist/lib/index.d.ts → src/lib/index.ts} +0 -1
  10. package/{dist/lib/interceptor/file-storage.interceptor.js → src/lib/interceptor/file-storage.interceptor.ts} +70 -37
  11. package/src/lib/nest-file-storage.module.ts +78 -0
  12. package/src/lib/storage/azure.storage.ts +214 -0
  13. package/{dist/lib/storage/local.storage.js → src/lib/storage/local.storage.ts} +96 -82
  14. package/{dist/lib/storage/s3.storage.js → src/lib/storage/s3.storage.ts} +107 -96
  15. package/src/lib/storage.factory.ts +58 -0
  16. package/{dist/lib/types.d.ts → src/lib/types.ts} +35 -23
  17. package/tsconfig.json +17 -0
  18. package/tsconfig.lib.json +14 -0
  19. package/tsconfig.spec.json +15 -0
  20. package/LICENSE +0 -21
  21. package/dist/index.d.ts.map +0 -1
  22. package/dist/index.js +0 -21
  23. package/dist/index.js.map +0 -1
  24. package/dist/lib/constants.d.ts +0 -2
  25. package/dist/lib/constants.d.ts.map +0 -1
  26. package/dist/lib/constants.js +0 -5
  27. package/dist/lib/constants.js.map +0 -1
  28. package/dist/lib/file-storage.service.d.ts +0 -8
  29. package/dist/lib/file-storage.service.d.ts.map +0 -1
  30. package/dist/lib/file-storage.service.js +0 -30
  31. package/dist/lib/file-storage.service.js.map +0 -1
  32. package/dist/lib/index.d.ts.map +0 -1
  33. package/dist/lib/index.js +0 -22
  34. package/dist/lib/index.js.map +0 -1
  35. package/dist/lib/interceptor/file-storage.interceptor.d.ts +0 -25
  36. package/dist/lib/interceptor/file-storage.interceptor.d.ts.map +0 -1
  37. package/dist/lib/interceptor/file-storage.interceptor.js.map +0 -1
  38. package/dist/lib/nest-file-storage.module.d.ts +0 -9
  39. package/dist/lib/nest-file-storage.module.d.ts.map +0 -1
  40. package/dist/lib/nest-file-storage.module.js +0 -80
  41. package/dist/lib/nest-file-storage.module.js.map +0 -1
  42. package/dist/lib/storage/azure.storage.d.ts +0 -19
  43. package/dist/lib/storage/azure.storage.d.ts.map +0 -1
  44. package/dist/lib/storage/azure.storage.js +0 -189
  45. package/dist/lib/storage/azure.storage.js.map +0 -1
  46. package/dist/lib/storage/local.storage.d.ts +0 -35
  47. package/dist/lib/storage/local.storage.d.ts.map +0 -1
  48. package/dist/lib/storage/local.storage.js.map +0 -1
  49. package/dist/lib/storage/s3.storage.d.ts +0 -20
  50. package/dist/lib/storage/s3.storage.d.ts.map +0 -1
  51. package/dist/lib/storage/s3.storage.js.map +0 -1
  52. package/dist/lib/storage.factory.d.ts +0 -9
  53. package/dist/lib/storage.factory.d.ts.map +0 -1
  54. package/dist/lib/storage.factory.js +0 -82
  55. package/dist/lib/storage.factory.js.map +0 -1
  56. package/dist/lib/types.d.ts.map +0 -1
  57. package/dist/lib/types.js +0 -10
  58. package/dist/lib/types.js.map +0 -1
@@ -1,175 +1,182 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.LocalStorage = void 0;
40
- const concat_stream_1 = __importDefault(require("concat-stream"));
41
- const fs = __importStar(require("fs"));
42
- const moment_1 = __importDefault(require("moment"));
43
- const path_1 = require("path");
44
- const uuid_1 = require("uuid");
45
- class LocalStorage {
1
+ import concat from 'concat-stream';
2
+ import * as fs from 'fs';
3
+ import moment from 'moment';
4
+ import { StorageEngine } from 'multer';
5
+ import * as path from 'path';
6
+ import { basename, dirname, join, normalize, sep } from 'path';
7
+ import { join as posixJoin } from 'path/posix';
8
+ import { v4 as uuidv4 } from 'uuid';
9
+
10
+ import { LocalStorageOptions, Storage, UploadedFile } from '../types';
11
+
12
+
13
+ export class LocalStorage implements StorageEngine, Storage {
14
+
15
+ private rootPath: string;
16
+ private fileNameFunction: (file: Express.Multer.File, req?: any) => string | Promise<string>;
17
+ private fileDistFunction: (file: Express.Multer.File, req?: any) => string | Promise<string>;
18
+
46
19
  /**
47
20
  * Convert OS-specific file path to URL-friendly key
48
21
  * This ensures keys are consistent across all platforms
49
22
  * Windows: C:\uploads\2024\01\file.jpg -> 2024/01/file.jpg
50
23
  * Unix: /uploads/2024/01/file.jpg -> 2024/01/file.jpg
51
24
  */
52
- pathToUrl(filePath) {
53
- if (!filePath)
54
- return '';
25
+ private pathToUrl(filePath: string): string {
26
+ if (!filePath) return '';
27
+
55
28
  // Remove rootPath if present
56
29
  let relativePath = filePath;
57
30
  if (filePath.startsWith(this.rootPath)) {
58
31
  relativePath = filePath.substring(this.rootPath.length);
59
32
  }
33
+
60
34
  // Convert backslashes to forward slashes and remove leading slash
61
35
  return relativePath.replace(/\\/g, '/').replace(/^\/+/, '');
62
36
  }
37
+
63
38
  /**
64
39
  * Convert URL-friendly key to OS-specific file path
65
40
  * This converts stored keys back to valid file system paths
66
41
  * 2024/01/file.jpg -> Windows: 2024\01\file.jpg, Unix: 2024/01/file.jpg
67
42
  */
68
- urlToPath(urlKey) {
69
- if (!urlKey)
70
- return '';
43
+ private urlToPath(urlKey: string): string {
44
+ if (!urlKey) return '';
45
+
71
46
  // Split by forward slashes and rejoin with OS-specific separator
72
47
  const parts = urlKey.split('/').filter(part => part.length > 0);
73
- return parts.join(path_1.sep);
48
+ return parts.join(sep);
74
49
  }
50
+
75
51
  /**
76
52
  * Get full file system path from URL-friendly key
77
53
  */
78
- getFullPath(urlKey) {
54
+ private getFullPath(urlKey: string): string {
79
55
  const osPath = this.urlToPath(urlKey);
80
- return (0, path_1.join)(this.rootPath, osPath);
56
+ return join(this.rootPath, osPath);
81
57
  }
82
- constructor(options) {
83
- this.options = options;
58
+
59
+ constructor(private options: LocalStorageOptions) {
84
60
  // Normalize path for the current OS
85
- this.rootPath = (0, path_1.normalize)(options.rootPath || (0, path_1.join)(process.cwd(), 'public'));
61
+ this.rootPath = normalize(options.rootPath || join(process.cwd(), 'public'));
62
+
86
63
  this.fileNameFunction = options.fileName || ((file, _req) => {
87
- return `${(0, uuid_1.v4)()}-${file.originalname}`;
64
+ return `${uuidv4()}-${file.originalname}`;
88
65
  });
66
+
89
67
  this.fileDistFunction = options.fileDist || ((_file, _req) => {
90
- return (0, path_1.join)(this.rootPath, (0, moment_1.default)().format('YYYY'), (0, moment_1.default)().format('MM'), (0, moment_1.default)().format('DD'));
68
+ return join(this.rootPath, moment().format('YYYY'), moment().format('MM'), moment().format('DD'));
91
69
  });
70
+
71
+
92
72
  // Ensure the rootPath directory exists
93
73
  if (!fs.existsSync(this.rootPath)) {
94
74
  fs.mkdirSync(this.rootPath, { recursive: true });
95
75
  }
96
76
  }
97
- async _handleFile(req, file, cb) {
77
+
78
+ async _handleFile(
79
+ req: any,
80
+ file: Express.Multer.File,
81
+ cb: (error?: any, info?: any) => void,
82
+ ) {
98
83
  try {
99
84
  const dist = await this.fileDistFunction(file, req);
100
85
  const fileName = await this.fileNameFunction(file, req);
101
- const filePath = (0, path_1.join)(dist, fileName);
86
+
87
+ const filePath = join(dist, fileName);
102
88
  // Convert to URL-friendly key for storage
103
89
  const urlKey = this.pathToUrl(filePath);
104
- file.stream.pipe((0, concat_stream_1.default)({ encoding: 'buffer' }, async (buffer) => {
90
+
91
+ file.stream.pipe(concat({ encoding: 'buffer' }, async (buffer) => {
105
92
  const uploadedFile = await this.putFile(buffer, urlKey);
106
- const fileInfo = {
93
+
94
+ const fileInfo: UploadedFile = {
107
95
  ...uploadedFile,
108
96
  fieldName: file.fieldname,
109
97
  originalName: file.originalname,
110
98
  mimetype: file.mimetype,
111
99
  };
112
100
  let transformData = fileInfo;
101
+
113
102
  if (this.options?.transformUploadedFileObject) {
114
103
  transformData = await this.options.transformUploadedFileObject(fileInfo);
115
104
  }
116
105
  cb(null, transformData);
117
106
  }));
118
- }
119
- catch (error) {
107
+ } catch (error) {
120
108
  console.error('error', error);
121
109
  cb(error);
122
110
  }
123
111
  }
124
- _removeFile(_req, file, cb) {
112
+
113
+ _removeFile(
114
+ _req: any,
115
+ file: any,
116
+ cb: (error: Error | null) => void,
117
+ ) {
125
118
  const filePath = file.path;
119
+
126
120
  fs.unlink(filePath, (err) => {
127
121
  if (err) {
128
122
  cb(err);
129
- }
130
- else {
123
+ } else {
131
124
  cb(null);
132
125
  }
133
126
  });
134
127
  }
135
- getUrl(urlKey) {
128
+
129
+ getUrl(urlKey: string): string {
136
130
  if (urlKey && urlKey.startsWith('http')) {
137
131
  return urlKey;
138
132
  }
139
133
  if (!urlKey) {
140
- return null;
134
+ return '';
141
135
  }
136
+
142
137
  // Key is already in URL format (forward slashes)
143
138
  // Ensure baseUrl doesn't end with slash and key doesn't start with slash
144
139
  const baseUrl = this.options.baseUrl.replace(/\/$/, '');
145
140
  const cleanKey = urlKey.replace(/^\//, '');
141
+
146
142
  return `${baseUrl}/${cleanKey}`;
147
143
  }
148
- async getFile(urlKey) {
144
+
145
+ async getFile(urlKey: string): Promise<Buffer> {
149
146
  // Convert URL key to OS-specific path
150
147
  const fullPath = this.getFullPath(urlKey);
151
148
  return fs.promises.readFile(fullPath);
152
149
  }
153
- async deleteFile(urlKey) {
150
+
151
+ async deleteFile(urlKey: string): Promise<void> {
154
152
  // Convert URL key to OS-specific path
155
153
  const fullPath = this.getFullPath(urlKey);
156
154
  return fs.promises.unlink(fullPath);
157
155
  }
158
- async putFile(fileContent, urlKey) {
156
+
157
+ async putFile(
158
+ fileContent: Buffer,
159
+ urlKey: string,
160
+ ): Promise<UploadedFile> {
159
161
  return new Promise((putFileResolve, reject) => {
160
162
  // Convert URL key to OS-specific path
161
163
  const filePath = this.getFullPath(urlKey);
162
- const directoryPath = (0, path_1.dirname)(filePath);
164
+
165
+ const directoryPath = dirname(filePath);
166
+
163
167
  // Create the directory if it doesn't exist
164
168
  fs.mkdirSync(directoryPath, { recursive: true });
169
+
165
170
  fs.writeFile(filePath, fileContent, (err) => {
166
171
  if (err) {
167
172
  reject(err);
168
173
  return;
169
174
  }
175
+
170
176
  const stats = fs.statSync(filePath);
171
177
  const fileName = urlKey.split('/').pop() || urlKey;
172
- const fileInfo = {
178
+
179
+ const fileInfo: UploadedFile = {
173
180
  originalName: fileName,
174
181
  size: stats.size,
175
182
  fileName: fileName,
@@ -181,28 +188,35 @@ class LocalStorage {
181
188
  });
182
189
  });
183
190
  }
184
- path(urlKey) {
191
+
192
+
193
+ path(urlKey: string): string {
185
194
  if (!urlKey) {
186
- return null;
195
+ return '';
187
196
  }
188
197
  // Convert URL key to full OS-specific path
189
198
  return this.getFullPath(urlKey);
190
199
  }
191
- async copyFile(oldUrlKey, newUrlKey) {
200
+
201
+ async copyFile(oldUrlKey: string, newUrlKey: string): Promise<UploadedFile> {
192
202
  return new Promise((resolve, reject) => {
193
203
  // Convert URL keys to OS-specific paths
194
204
  const oldPath = this.getFullPath(oldUrlKey);
195
205
  const newPath = this.getFullPath(newUrlKey);
196
- const directoryPath = (0, path_1.dirname)(newPath);
206
+
207
+ const directoryPath = dirname(newPath);
197
208
  fs.mkdirSync(directoryPath, { recursive: true });
209
+
198
210
  fs.copyFile(oldPath, newPath, (err) => {
199
211
  if (err) {
200
212
  reject(err);
201
213
  return;
202
214
  }
215
+
203
216
  const stats = fs.statSync(newPath);
204
217
  const fileName = newUrlKey.split('/').pop() || newUrlKey;
205
- const fileInfo = {
218
+
219
+ const fileInfo: UploadedFile = {
206
220
  originalName: fileName,
207
221
  size: stats.size,
208
222
  fileName: fileName,
@@ -214,6 +228,6 @@ class LocalStorage {
214
228
  });
215
229
  });
216
230
  }
231
+
232
+
217
233
  }
218
- exports.LocalStorage = LocalStorage;
219
- //# sourceMappingURL=local.storage.js.map
@@ -1,60 +1,33 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.S3Storage = void 0;
40
- const client_s3_1 = require("@aws-sdk/client-s3");
41
- const client_s3_2 = require("@aws-sdk/client-s3");
42
- const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
43
- const moment_1 = __importDefault(require("moment"));
44
- const path_1 = __importStar(require("path"));
45
- const stream_1 = require("stream");
46
- const uuid_1 = require("uuid");
47
- class S3Storage {
48
- constructor(options) {
49
- this.options = options;
1
+ import { CopyObjectCommand, GetObjectCommandInput, S3 } from '@aws-sdk/client-s3';
2
+ import { DeleteObjectCommand, GetObjectCommand, GetObjectCommandOutput, HeadObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
3
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
4
+ import moment from 'moment';
5
+ import { StorageEngine } from 'multer';
6
+ import path, { basename, join } from 'path';
7
+ import { Readable } from 'stream';
8
+ import { v4 as uuidv4 } from 'uuid';
9
+
10
+
11
+ import { S3StorageOptions, Storage, UploadedFile } from '../types';
12
+
13
+
14
+ export class S3Storage implements StorageEngine, Storage {
15
+
16
+ private s3: S3;
17
+ private fileNameFunction: (file: Express.Multer.File, req?: any) => string | Promise<string>;
18
+ private fileDistFunction: (file: Express.Multer.File, req?: any) => string | Promise<string>;
19
+
20
+ constructor(private options: S3StorageOptions) {
50
21
  this.fileNameFunction = options.fileName || ((file, _req) => {
51
- return `${(0, uuid_1.v4)()}-${file.originalname}`;
22
+ return `${uuidv4()}-${file.originalname}`;
52
23
  });
24
+
53
25
  this.fileDistFunction = options.fileDist || ((_file, _req) => {
54
- return path_1.default.join('uploads', (0, moment_1.default)().format('YYYY'), (0, moment_1.default)().format('MM'), (0, moment_1.default)().format('DD'));
26
+ return path.join('uploads', moment().format('YYYY'), moment().format('MM'), moment().format('DD'));
55
27
  });
56
- this.s3 = new client_s3_1.S3({
57
- endpoint: this.options.endpoint || null,
28
+
29
+ this.s3 = new S3({
30
+ ...(this.options.endpoint ? { endpoint: this.options.endpoint } : {}),
58
31
  region: this.options.region,
59
32
  credentials: {
60
33
  accessKeyId: this.options.accessKeyId,
@@ -62,90 +35,118 @@ class S3Storage {
62
35
  },
63
36
  });
64
37
  }
65
- async _handleFile(req, file, cb) {
38
+
39
+ async _handleFile(
40
+ req: any,
41
+ file: Express.Multer.File,
42
+ cb: (error?: any, info?: any) => void,
43
+ ): Promise<void> {
66
44
  // Collect file chunks to determine size
67
- const chunks = [];
45
+ const chunks: Uint8Array[] = [];
68
46
  file.stream.on('data', (chunk) => chunks.push(chunk));
69
47
  file.stream.on('end', async () => {
70
48
  const buffer = Buffer.concat(chunks);
49
+
71
50
  try {
72
51
  const dist = await this.fileDistFunction(file, req);
73
52
  const key = await this.fileNameFunction(file, req);
74
- const filePath = (0, path_1.join)(dist, key);
53
+ const filePath = join(dist, key);
54
+
75
55
  const uploadedFile = await this.putFile(buffer, filePath);
76
- const fileInfo = {
56
+
57
+ const fileInfo: UploadedFile = {
77
58
  ...uploadedFile,
78
59
  fieldName: file.fieldname,
79
60
  originalName: file.originalname,
80
61
  mimetype: file.mimetype,
81
62
  };
82
63
  let transformData = fileInfo;
64
+
83
65
  if (this.options?.transformUploadedFileObject) {
84
66
  transformData = await this.options.transformUploadedFileObject(fileInfo);
85
67
  }
86
68
  cb(null, transformData);
87
- }
88
- catch (err) {
69
+ } catch (err) {
89
70
  cb(err);
90
71
  }
91
72
  });
73
+
92
74
  file.stream.on('error', (err) => cb(err));
93
75
  }
94
- _removeFile(_req, file, cb) {
76
+
77
+ _removeFile(
78
+ _req: any,
79
+ file: any,
80
+ cb: (error: Error | null) => void,
81
+ ): void {
95
82
  const params = {
96
83
  Bucket: this.options.bucket,
97
84
  Key: file.key,
98
85
  };
86
+
99
87
  this.s3
100
88
  .deleteObject(params)
101
89
  .then(() => cb(null))
102
90
  .catch((err) => cb(err));
103
91
  }
104
- getUrl(key) {
92
+
93
+ getUrl(key: string) {
105
94
  if (this.options?.cloudFrontUrl) {
106
95
  return `${this.options.cloudFrontUrl}/${key}`;
107
96
  }
108
97
  return `https://${this.options.bucket}.s3.amazonaws.com/${key}`;
109
98
  }
110
- async getSignedUrl(key, objectConfig) {
99
+
100
+ async getSignedUrl(key: string, objectConfig?: Partial<GetObjectCommandInput>): Promise<string> {
111
101
  if (key) {
112
- const url = await (0, s3_request_presigner_1.getSignedUrl)(this.s3, new client_s3_2.GetObjectCommand({
113
- Bucket: this.options.bucket,
114
- Key: key,
115
- ...(objectConfig && { ...objectConfig }),
116
- }));
102
+ const url = await getSignedUrl(
103
+ this.s3 as any,
104
+ new GetObjectCommand({
105
+ Bucket: this.options.bucket,
106
+ Key: key,
107
+ ...(objectConfig && { ...objectConfig }),
108
+ }),
109
+ );
117
110
  return url;
118
111
  }
119
- return null;
112
+ return '';
120
113
  }
121
- async getFile(key) {
114
+
115
+ async getFile(key: string): Promise<Buffer> {
122
116
  if (!key) {
123
117
  throw new Error('Key is required to fetch the file from S3.');
124
118
  }
119
+
125
120
  try {
126
- const command = new client_s3_2.GetObjectCommand({
121
+ const command = new GetObjectCommand({
127
122
  Bucket: this.options.bucket,
128
123
  Key: key,
129
124
  });
130
- const data = await this.s3.send(command);
125
+
126
+ const data: GetObjectCommandOutput = await this.s3.send(command);
127
+
131
128
  if (!data.Body) {
132
129
  throw new Error('Empty response received from S3.');
133
130
  }
131
+
134
132
  // Handle both Buffer and Readable Stream responses
135
- if (data.Body instanceof stream_1.Readable) {
133
+ if (data.Body instanceof Readable) {
136
134
  return await this.streamToBuffer(data.Body);
137
135
  }
136
+
138
137
  throw new Error('Unexpected data.Body type received from S3.');
139
- }
140
- catch (error) {
138
+ } catch (error) {
141
139
  console.error(`Error fetching file (${key}) from S3:`, error);
142
140
  throw error;
143
141
  }
144
142
  }
145
- async putFile(fileContent, key) {
143
+
144
+
145
+ async putFile(fileContent: Buffer, key: string): Promise<any> {
146
146
  try {
147
- const fileName = (0, path_1.basename)(key);
147
+ const fileName = basename(key);
148
148
  const fileKey = key || (Math.random() + 1).toString(36).substring(12);
149
+
149
150
  // Upload the file
150
151
  const putParams = {
151
152
  Bucket: this.options.bucket,
@@ -153,16 +154,20 @@ class S3Storage {
153
154
  Body: fileContent,
154
155
  ContentDisposition: `inline; ${fileName}`,
155
156
  };
156
- await this.s3.send(new client_s3_2.PutObjectCommand(putParams));
157
+
158
+ await this.s3.send(new PutObjectCommand(putParams));
159
+
157
160
  // Fetch file metadata to get size
158
161
  const headParams = {
159
162
  Bucket: this.options.bucket,
160
163
  Key: fileKey,
161
164
  };
162
- const headObject = await this.s3.send(new client_s3_2.HeadObjectCommand(headParams));
165
+
166
+ const headObject = await this.s3.send(new HeadObjectCommand(headParams));
163
167
  const fileSize = headObject.ContentLength || 0;
168
+
164
169
  // Construct response object
165
- const fileData = {
170
+ const fileData: UploadedFile = {
166
171
  originalName: fileName,
167
172
  fileName: fileName,
168
173
  size: fileSize,
@@ -172,60 +177,66 @@ class S3Storage {
172
177
  url: this.getUrl(fileKey),
173
178
  };
174
179
  return fileData;
175
- }
176
- catch (error) {
180
+ } catch (error) {
177
181
  console.error('Error uploading file to S3:', error);
178
182
  throw error;
179
183
  }
180
184
  }
181
- async deleteFile(key) {
185
+
186
+
187
+ async deleteFile(key: string): Promise<void> {
182
188
  if (!key) {
183
189
  throw new Error('File key is required for deletion.');
184
190
  }
191
+
185
192
  try {
186
193
  const deleteParams = {
187
194
  Bucket: this.options.bucket,
188
195
  Key: key,
189
196
  };
190
- await this.s3.send(new client_s3_2.DeleteObjectCommand(deleteParams));
191
- }
192
- catch (error) {
197
+
198
+ await this.s3.send(new DeleteObjectCommand(deleteParams));
199
+ } catch (error) {
193
200
  console.error(`Error deleting file (${key}) from S3:`, error);
194
201
  throw error;
195
202
  }
196
203
  }
197
- async streamToBuffer(stream) {
198
- const chunks = [];
204
+
205
+
206
+ private async streamToBuffer(stream: Readable): Promise<Buffer> {
207
+ const chunks: Uint8Array[] = [];
199
208
  for await (const chunk of stream) {
200
209
  chunks.push(chunk);
201
210
  }
202
211
  return Buffer.concat(chunks);
203
212
  }
204
- async copyFile(oldKey, newKey) {
213
+
214
+ async copyFile(oldKey: string, newKey: string): Promise<UploadedFile> {
205
215
  try {
206
- await this.s3.send(new client_s3_1.CopyObjectCommand({
216
+ await this.s3.send(new CopyObjectCommand({
207
217
  Bucket: this.options.bucket,
208
218
  CopySource: `/${this.options.bucket}/${oldKey}`,
209
219
  Key: newKey,
210
220
  }));
211
- const headObject = await this.s3.send(new client_s3_2.HeadObjectCommand({
221
+
222
+ const headObject = await this.s3.send(new HeadObjectCommand({
212
223
  Bucket: this.options.bucket,
213
224
  Key: newKey,
214
225
  }));
226
+
215
227
  return {
216
- originalName: (0, path_1.basename)(newKey),
228
+ originalName: basename(newKey),
217
229
  size: headObject.ContentLength || 0,
218
- fileName: (0, path_1.basename)(newKey),
230
+ fileName: basename(newKey),
219
231
  key: newKey,
220
232
  fullPath: newKey,
221
233
  url: this.getUrl(newKey),
222
234
  };
223
- }
224
- catch (error) {
235
+ } catch (error) {
225
236
  console.error('Error copying file in S3:', error);
226
237
  throw error;
227
238
  }
228
239
  }
240
+
241
+
229
242
  }
230
- exports.S3Storage = S3Storage;
231
- //# sourceMappingURL=s3.storage.js.map