@ackplus/nest-file-storage 1.1.1 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/{index.ts → index.d.ts} +1 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +7 -0
- package/src/lib/constants.d.ts +2 -0
- package/src/lib/constants.d.ts.map +1 -0
- package/src/lib/constants.js +4 -0
- package/src/lib/file-storage.service.d.ts +8 -0
- package/src/lib/file-storage.service.d.ts.map +1 -0
- package/src/lib/file-storage.service.js +29 -0
- package/src/lib/{index.ts → index.d.ts} +1 -0
- package/src/lib/index.d.ts.map +1 -0
- package/src/lib/index.js +8 -0
- package/src/lib/interceptor/file-storage.interceptor.d.ts +25 -0
- package/src/lib/interceptor/file-storage.interceptor.d.ts.map +1 -0
- package/src/lib/interceptor/{file-storage.interceptor.ts → file-storage.interceptor.js} +35 -71
- package/src/lib/nest-file-storage.module.d.ts +9 -0
- package/src/lib/nest-file-storage.module.d.ts.map +1 -0
- package/src/lib/nest-file-storage.module.js +74 -0
- package/src/lib/storage/azure.storage.d.ts +19 -0
- package/src/lib/storage/azure.storage.d.ts.map +1 -0
- package/src/lib/storage/{azure.storage.ts → azure.storage.js} +57 -118
- package/src/lib/storage/local.storage.d.ts +35 -0
- package/src/lib/storage/local.storage.d.ts.map +1 -0
- package/src/lib/storage/{local.storage.ts → local.storage.js} +44 -94
- package/src/lib/storage/s3.storage.d.ts +20 -0
- package/src/lib/storage/s3.storage.d.ts.map +1 -0
- package/src/lib/storage/{s3.storage.ts → s3.storage.js} +58 -105
- package/src/lib/storage.factory.d.ts +9 -0
- package/src/lib/storage.factory.d.ts.map +1 -0
- package/src/lib/storage.factory.js +81 -0
- package/src/lib/{types.ts → types.d.ts} +23 -35
- package/src/lib/types.d.ts.map +1 -0
- package/src/lib/types.js +9 -0
- package/eslint.config.mjs +0 -22
- package/jest.config.ts +0 -10
- package/project.json +0 -38
- package/src/lib/constants.ts +0 -1
- package/src/lib/file-storage.service.ts +0 -36
- package/src/lib/nest-file-storage.module.ts +0 -78
- package/src/lib/storage.factory.ts +0 -58
- package/tsconfig.json +0 -17
- package/tsconfig.lib.json +0 -14
- package/tsconfig.spec.json +0 -15
|
@@ -1,32 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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) {
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3Storage = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
6
|
+
const client_s3_2 = require("@aws-sdk/client-s3");
|
|
7
|
+
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
|
8
|
+
const moment_1 = tslib_1.__importDefault(require("moment"));
|
|
9
|
+
const path_1 = tslib_1.__importStar(require("path"));
|
|
10
|
+
const stream_1 = require("stream");
|
|
11
|
+
const uuid_1 = require("uuid");
|
|
12
|
+
class S3Storage {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
21
15
|
this.fileNameFunction = options.fileName || ((file, _req) => {
|
|
22
|
-
return `${
|
|
16
|
+
return `${(0, uuid_1.v4)()}-${file.originalname}`;
|
|
23
17
|
});
|
|
24
|
-
|
|
25
18
|
this.fileDistFunction = options.fileDist || ((_file, _req) => {
|
|
26
|
-
return
|
|
19
|
+
return path_1.default.join('uploads', (0, moment_1.default)().format('YYYY'), (0, moment_1.default)().format('MM'), (0, moment_1.default)().format('DD'));
|
|
27
20
|
});
|
|
28
|
-
|
|
29
|
-
this.s3 = new S3({
|
|
21
|
+
this.s3 = new client_s3_1.S3({
|
|
30
22
|
...(this.options.endpoint ? { endpoint: this.options.endpoint } : {}),
|
|
31
23
|
region: this.options.region,
|
|
32
24
|
credentials: {
|
|
@@ -35,118 +27,90 @@ export class S3Storage implements StorageEngine, Storage {
|
|
|
35
27
|
},
|
|
36
28
|
});
|
|
37
29
|
}
|
|
38
|
-
|
|
39
|
-
async _handleFile(
|
|
40
|
-
req: any,
|
|
41
|
-
file: Express.Multer.File,
|
|
42
|
-
cb: (error?: any, info?: any) => void,
|
|
43
|
-
): Promise<void> {
|
|
30
|
+
async _handleFile(req, file, cb) {
|
|
44
31
|
// Collect file chunks to determine size
|
|
45
|
-
const chunks
|
|
32
|
+
const chunks = [];
|
|
46
33
|
file.stream.on('data', (chunk) => chunks.push(chunk));
|
|
47
34
|
file.stream.on('end', async () => {
|
|
48
35
|
const buffer = Buffer.concat(chunks);
|
|
49
|
-
|
|
50
36
|
try {
|
|
51
37
|
const dist = await this.fileDistFunction(file, req);
|
|
52
38
|
const key = await this.fileNameFunction(file, req);
|
|
53
|
-
const filePath = join(dist, key);
|
|
54
|
-
|
|
39
|
+
const filePath = (0, path_1.join)(dist, key);
|
|
55
40
|
const uploadedFile = await this.putFile(buffer, filePath);
|
|
56
|
-
|
|
57
|
-
const fileInfo: UploadedFile = {
|
|
41
|
+
const fileInfo = {
|
|
58
42
|
...uploadedFile,
|
|
59
43
|
fieldName: file.fieldname,
|
|
60
44
|
originalName: file.originalname,
|
|
61
45
|
mimetype: file.mimetype,
|
|
62
46
|
};
|
|
63
47
|
let transformData = fileInfo;
|
|
64
|
-
|
|
65
48
|
if (this.options?.transformUploadedFileObject) {
|
|
66
49
|
transformData = await this.options.transformUploadedFileObject(fileInfo);
|
|
67
50
|
}
|
|
68
51
|
cb(null, transformData);
|
|
69
|
-
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
70
54
|
cb(err);
|
|
71
55
|
}
|
|
72
56
|
});
|
|
73
|
-
|
|
74
57
|
file.stream.on('error', (err) => cb(err));
|
|
75
58
|
}
|
|
76
|
-
|
|
77
|
-
_removeFile(
|
|
78
|
-
_req: any,
|
|
79
|
-
file: any,
|
|
80
|
-
cb: (error: Error | null) => void,
|
|
81
|
-
): void {
|
|
59
|
+
_removeFile(_req, file, cb) {
|
|
82
60
|
const params = {
|
|
83
61
|
Bucket: this.options.bucket,
|
|
84
62
|
Key: file.key,
|
|
85
63
|
};
|
|
86
|
-
|
|
87
64
|
this.s3
|
|
88
65
|
.deleteObject(params)
|
|
89
66
|
.then(() => cb(null))
|
|
90
67
|
.catch((err) => cb(err));
|
|
91
68
|
}
|
|
92
|
-
|
|
93
|
-
getUrl(key: string) {
|
|
69
|
+
getUrl(key) {
|
|
94
70
|
if (this.options?.cloudFrontUrl) {
|
|
95
71
|
return `${this.options.cloudFrontUrl}/${key}`;
|
|
96
72
|
}
|
|
97
73
|
return `https://${this.options.bucket}.s3.amazonaws.com/${key}`;
|
|
98
74
|
}
|
|
99
|
-
|
|
100
|
-
async getSignedUrl(key: string, objectConfig?: Partial<GetObjectCommandInput>): Promise<string> {
|
|
75
|
+
async getSignedUrl(key, objectConfig) {
|
|
101
76
|
if (key) {
|
|
102
|
-
const url = await getSignedUrl(
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
...(objectConfig && { ...objectConfig }),
|
|
108
|
-
}),
|
|
109
|
-
);
|
|
77
|
+
const url = await (0, s3_request_presigner_1.getSignedUrl)(this.s3, new client_s3_2.GetObjectCommand({
|
|
78
|
+
Bucket: this.options.bucket,
|
|
79
|
+
Key: key,
|
|
80
|
+
...(objectConfig && { ...objectConfig }),
|
|
81
|
+
}));
|
|
110
82
|
return url;
|
|
111
83
|
}
|
|
112
84
|
return '';
|
|
113
85
|
}
|
|
114
|
-
|
|
115
|
-
async getFile(key: string): Promise<Buffer> {
|
|
86
|
+
async getFile(key) {
|
|
116
87
|
if (!key) {
|
|
117
88
|
throw new Error('Key is required to fetch the file from S3.');
|
|
118
89
|
}
|
|
119
|
-
|
|
120
90
|
try {
|
|
121
|
-
const command = new GetObjectCommand({
|
|
91
|
+
const command = new client_s3_2.GetObjectCommand({
|
|
122
92
|
Bucket: this.options.bucket,
|
|
123
93
|
Key: key,
|
|
124
94
|
});
|
|
125
|
-
|
|
126
|
-
const data: GetObjectCommandOutput = await this.s3.send(command);
|
|
127
|
-
|
|
95
|
+
const data = await this.s3.send(command);
|
|
128
96
|
if (!data.Body) {
|
|
129
97
|
throw new Error('Empty response received from S3.');
|
|
130
98
|
}
|
|
131
|
-
|
|
132
99
|
// Handle both Buffer and Readable Stream responses
|
|
133
|
-
if (data.Body instanceof Readable) {
|
|
100
|
+
if (data.Body instanceof stream_1.Readable) {
|
|
134
101
|
return await this.streamToBuffer(data.Body);
|
|
135
102
|
}
|
|
136
|
-
|
|
137
103
|
throw new Error('Unexpected data.Body type received from S3.');
|
|
138
|
-
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
139
106
|
console.error(`Error fetching file (${key}) from S3:`, error);
|
|
140
107
|
throw error;
|
|
141
108
|
}
|
|
142
109
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
async putFile(fileContent: Buffer, key: string): Promise<any> {
|
|
110
|
+
async putFile(fileContent, key) {
|
|
146
111
|
try {
|
|
147
|
-
const fileName = basename(key);
|
|
112
|
+
const fileName = (0, path_1.basename)(key);
|
|
148
113
|
const fileKey = key || (Math.random() + 1).toString(36).substring(12);
|
|
149
|
-
|
|
150
114
|
// Upload the file
|
|
151
115
|
const putParams = {
|
|
152
116
|
Bucket: this.options.bucket,
|
|
@@ -154,20 +118,16 @@ export class S3Storage implements StorageEngine, Storage {
|
|
|
154
118
|
Body: fileContent,
|
|
155
119
|
ContentDisposition: `inline; ${fileName}`,
|
|
156
120
|
};
|
|
157
|
-
|
|
158
|
-
await this.s3.send(new PutObjectCommand(putParams));
|
|
159
|
-
|
|
121
|
+
await this.s3.send(new client_s3_2.PutObjectCommand(putParams));
|
|
160
122
|
// Fetch file metadata to get size
|
|
161
123
|
const headParams = {
|
|
162
124
|
Bucket: this.options.bucket,
|
|
163
125
|
Key: fileKey,
|
|
164
126
|
};
|
|
165
|
-
|
|
166
|
-
const headObject = await this.s3.send(new HeadObjectCommand(headParams));
|
|
127
|
+
const headObject = await this.s3.send(new client_s3_2.HeadObjectCommand(headParams));
|
|
167
128
|
const fileSize = headObject.ContentLength || 0;
|
|
168
|
-
|
|
169
129
|
// Construct response object
|
|
170
|
-
const fileData
|
|
130
|
+
const fileData = {
|
|
171
131
|
originalName: fileName,
|
|
172
132
|
fileName: fileName,
|
|
173
133
|
size: fileSize,
|
|
@@ -177,66 +137,59 @@ export class S3Storage implements StorageEngine, Storage {
|
|
|
177
137
|
url: this.getUrl(fileKey),
|
|
178
138
|
};
|
|
179
139
|
return fileData;
|
|
180
|
-
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
181
142
|
console.error('Error uploading file to S3:', error);
|
|
182
143
|
throw error;
|
|
183
144
|
}
|
|
184
145
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
async deleteFile(key: string): Promise<void> {
|
|
146
|
+
async deleteFile(key) {
|
|
188
147
|
if (!key) {
|
|
189
148
|
throw new Error('File key is required for deletion.');
|
|
190
149
|
}
|
|
191
|
-
|
|
192
150
|
try {
|
|
193
151
|
const deleteParams = {
|
|
194
152
|
Bucket: this.options.bucket,
|
|
195
153
|
Key: key,
|
|
196
154
|
};
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
155
|
+
await this.s3.send(new client_s3_2.DeleteObjectCommand(deleteParams));
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
200
158
|
console.error(`Error deleting file (${key}) from S3:`, error);
|
|
201
159
|
throw error;
|
|
202
160
|
}
|
|
203
161
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
private async streamToBuffer(stream: Readable): Promise<Buffer> {
|
|
207
|
-
const chunks: Uint8Array[] = [];
|
|
162
|
+
async streamToBuffer(stream) {
|
|
163
|
+
const chunks = [];
|
|
208
164
|
for await (const chunk of stream) {
|
|
209
165
|
chunks.push(chunk);
|
|
210
166
|
}
|
|
211
167
|
return Buffer.concat(chunks);
|
|
212
168
|
}
|
|
213
|
-
|
|
214
|
-
async copyFile(oldKey: string, newKey: string): Promise<UploadedFile> {
|
|
169
|
+
async copyFile(oldKey, newKey) {
|
|
215
170
|
try {
|
|
216
|
-
await this.s3.send(new CopyObjectCommand({
|
|
171
|
+
await this.s3.send(new client_s3_1.CopyObjectCommand({
|
|
217
172
|
Bucket: this.options.bucket,
|
|
218
173
|
CopySource: `/${this.options.bucket}/${oldKey}`,
|
|
219
174
|
Key: newKey,
|
|
220
175
|
}));
|
|
221
|
-
|
|
222
|
-
const headObject = await this.s3.send(new HeadObjectCommand({
|
|
176
|
+
const headObject = await this.s3.send(new client_s3_2.HeadObjectCommand({
|
|
223
177
|
Bucket: this.options.bucket,
|
|
224
178
|
Key: newKey,
|
|
225
179
|
}));
|
|
226
|
-
|
|
227
180
|
return {
|
|
228
|
-
originalName: basename(newKey),
|
|
181
|
+
originalName: (0, path_1.basename)(newKey),
|
|
229
182
|
size: headObject.ContentLength || 0,
|
|
230
|
-
fileName: basename(newKey),
|
|
183
|
+
fileName: (0, path_1.basename)(newKey),
|
|
231
184
|
key: newKey,
|
|
232
185
|
fullPath: newKey,
|
|
233
186
|
url: this.getUrl(newKey),
|
|
234
187
|
};
|
|
235
|
-
}
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
236
190
|
console.error('Error copying file in S3:', error);
|
|
237
191
|
throw error;
|
|
238
192
|
}
|
|
239
193
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
194
|
}
|
|
195
|
+
exports.S3Storage = S3Storage;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FileStorageEnum, StorageOptions } from './types';
|
|
2
|
+
import { StorageEngine } from 'multer';
|
|
3
|
+
import { Storage } from './types';
|
|
4
|
+
export declare class StorageFactory {
|
|
5
|
+
private static storageInstances;
|
|
6
|
+
static createStorage(storageType: FileStorageEnum, options: StorageOptions): Promise<StorageEngine & Storage>;
|
|
7
|
+
static clearCache(): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=storage.factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.factory.d.ts","sourceRoot":"","sources":["../../../../../packages/nest-file-storage/src/lib/storage.factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,eAAe,EAAyC,cAAc,EAAE,MAAM,SAAS,CAAC;AACtH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAA8C;WAEhE,aAAa,CAAC,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC;IA+CnH,MAAM,CAAC,UAAU;CAGpB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.StorageFactory = void 0;
|
|
37
|
+
const types_1 = require("./types");
|
|
38
|
+
class StorageFactory {
|
|
39
|
+
static async createStorage(storageType, options) {
|
|
40
|
+
const cacheKey = `${storageType}-${JSON.stringify(options)}`;
|
|
41
|
+
// if (this.storageInstances.has(cacheKey)) {
|
|
42
|
+
// return this.storageInstances.get(cacheKey)!;
|
|
43
|
+
// }
|
|
44
|
+
let storageInstance;
|
|
45
|
+
switch (storageType) {
|
|
46
|
+
case types_1.FileStorageEnum.LOCAL:
|
|
47
|
+
const { LocalStorage } = await Promise.resolve().then(() => __importStar(require('./storage/local.storage')));
|
|
48
|
+
storageInstance = new LocalStorage(options);
|
|
49
|
+
break;
|
|
50
|
+
case types_1.FileStorageEnum.AZURE:
|
|
51
|
+
try {
|
|
52
|
+
const { AzureStorage } = await Promise.resolve().then(() => __importStar(require('./storage/azure.storage')));
|
|
53
|
+
storageInstance = new AzureStorage(options);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw new Error('Azure Storage SDK (@azure/storage-blob) is required when using AzureStorage. ' +
|
|
57
|
+
'Please install it: npm install @azure/storage-blob');
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
case types_1.FileStorageEnum.S3:
|
|
61
|
+
try {
|
|
62
|
+
const { S3Storage } = await Promise.resolve().then(() => __importStar(require('./storage/s3.storage')));
|
|
63
|
+
storageInstance = new S3Storage(options);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw new Error('AWS SDK (@aws-sdk/client-s3 and @aws-sdk/s3-request-presigner) is required when using S3Storage. ' +
|
|
67
|
+
'Please install them: npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner');
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unsupported storage type: ${storageType}`);
|
|
72
|
+
}
|
|
73
|
+
this.storageInstances.set(cacheKey, storageInstance);
|
|
74
|
+
return storageInstance;
|
|
75
|
+
}
|
|
76
|
+
static clearCache() {
|
|
77
|
+
this.storageInstances.clear();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.StorageFactory = StorageFactory;
|
|
81
|
+
StorageFactory.storageInstances = new Map();
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import { ModuleMetadata, Type } from '@nestjs/common';
|
|
2
2
|
import { Request } from 'express';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
S3 = 's3',
|
|
8
|
-
AZURE = 'azure',
|
|
3
|
+
export declare enum FileStorageEnum {
|
|
4
|
+
LOCAL = "local",
|
|
5
|
+
S3 = "s3",
|
|
6
|
+
AZURE = "azure"
|
|
9
7
|
}
|
|
10
|
-
|
|
11
8
|
export interface FileStorageOptions {
|
|
12
9
|
prefix?: string;
|
|
13
|
-
fileName?: (file: any, req: Request) => string;
|
|
14
|
-
fileDist?: (file: any, req: Request) => string;
|
|
10
|
+
fileName?: (file: any, req: Request) => string;
|
|
11
|
+
fileDist?: (file: any, req: Request) => string;
|
|
15
12
|
transformUploadedFileObject?: (file: any) => any;
|
|
16
13
|
}
|
|
17
|
-
|
|
18
14
|
export interface S3StorageOptions extends FileStorageOptions {
|
|
19
15
|
accessKeyId: string;
|
|
20
16
|
secretAccessKey: string;
|
|
@@ -23,36 +19,31 @@ export interface S3StorageOptions extends FileStorageOptions {
|
|
|
23
19
|
endpoint?: string;
|
|
24
20
|
cloudFrontUrl?: string;
|
|
25
21
|
}
|
|
26
|
-
|
|
27
22
|
export interface LocalStorageOptions extends FileStorageOptions {
|
|
28
23
|
rootPath: string;
|
|
29
24
|
baseUrl: string;
|
|
30
25
|
}
|
|
31
|
-
|
|
32
26
|
export interface AzureStorageOptions extends FileStorageOptions {
|
|
33
27
|
account: string;
|
|
34
28
|
accountKey: string;
|
|
35
29
|
container: string;
|
|
36
30
|
}
|
|
37
|
-
|
|
38
31
|
export type StorageOptions = S3StorageOptions | AzureStorageOptions | LocalStorageOptions;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
export type FileStorageConfigOptions = {
|
|
33
|
+
storage: FileStorageEnum.LOCAL;
|
|
34
|
+
localConfig: LocalStorageOptions;
|
|
35
|
+
} | {
|
|
36
|
+
storage: FileStorageEnum.S3;
|
|
37
|
+
s3Config: S3StorageOptions;
|
|
38
|
+
} | {
|
|
39
|
+
storage: FileStorageEnum.AZURE;
|
|
40
|
+
azureConfig: AzureStorageOptions;
|
|
41
|
+
};
|
|
47
42
|
export interface FileStorageClassOptions {
|
|
48
43
|
storageFactory: () => Promise<new (...args: any[]) => Storage> | (new (...args: any[]) => Storage);
|
|
49
44
|
options?: any;
|
|
50
45
|
}
|
|
51
|
-
|
|
52
|
-
// Combined module options
|
|
53
46
|
export type FileStorageModuleOptions = FileStorageConfigOptions | FileStorageClassOptions;
|
|
54
|
-
|
|
55
|
-
|
|
56
47
|
export interface FileStorageAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
57
48
|
/**
|
|
58
49
|
* The `useExisting` syntax allows you to create aliases for existing providers.
|
|
@@ -72,26 +63,22 @@ export interface FileStorageAsyncOptions extends Pick<ModuleMetadata, 'imports'>
|
|
|
72
63
|
*/
|
|
73
64
|
inject?: any[];
|
|
74
65
|
}
|
|
75
|
-
|
|
76
66
|
export interface FileStorageOptionsFactory {
|
|
77
67
|
createFileStorageOptions(): Promise<FileStorageModuleOptions> | FileStorageModuleOptions;
|
|
78
68
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
69
|
export interface UploadedFile {
|
|
82
70
|
fieldName?: string;
|
|
83
71
|
fieldname?: string;
|
|
84
72
|
fileName: string;
|
|
85
|
-
originalName: string;
|
|
86
|
-
size: number;
|
|
73
|
+
originalName: string;
|
|
74
|
+
size: number;
|
|
87
75
|
mimetype?: string;
|
|
88
76
|
buffer?: Buffer;
|
|
89
|
-
key: string;
|
|
90
|
-
url: string;
|
|
91
|
-
fullPath: string;
|
|
77
|
+
key: string;
|
|
78
|
+
url: string;
|
|
79
|
+
fullPath: string;
|
|
92
80
|
encoding?: string;
|
|
93
81
|
}
|
|
94
|
-
|
|
95
82
|
export interface Storage {
|
|
96
83
|
getFile(key: string): Promise<Buffer> | Buffer;
|
|
97
84
|
deleteFile(key: string): Promise<void> | void;
|
|
@@ -99,5 +86,6 @@ export interface Storage {
|
|
|
99
86
|
path?(filePath: string): Promise<string> | string;
|
|
100
87
|
getUrl(key: string): Promise<string> | string;
|
|
101
88
|
getSignedUrl?(key: string, options: any): Promise<string> | string;
|
|
102
|
-
copyFile(oldKey: string, newKey: string): Promise<UploadedFile
|
|
89
|
+
copyFile(oldKey: string, newKey: string): Promise<UploadedFile>;
|
|
103
90
|
}
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../packages/nest-file-storage/src/lib/types.ts"],"names":[],"mappings":"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"}
|
package/src/lib/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FileStorageEnum = void 0;
|
|
4
|
+
var FileStorageEnum;
|
|
5
|
+
(function (FileStorageEnum) {
|
|
6
|
+
FileStorageEnum["LOCAL"] = "local";
|
|
7
|
+
FileStorageEnum["S3"] = "s3";
|
|
8
|
+
FileStorageEnum["AZURE"] = "azure";
|
|
9
|
+
})(FileStorageEnum || (exports.FileStorageEnum = FileStorageEnum = {}));
|
package/eslint.config.mjs
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import baseConfig from '../../eslint.base.config';
|
|
2
|
-
|
|
3
|
-
export default [
|
|
4
|
-
...baseConfig,
|
|
5
|
-
{
|
|
6
|
-
files: ['**/*.json'],
|
|
7
|
-
rules: {
|
|
8
|
-
'@nx/dependency-checks': [
|
|
9
|
-
'error',
|
|
10
|
-
{
|
|
11
|
-
ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}'],
|
|
12
|
-
},
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
|
-
languageOptions: {
|
|
16
|
-
parser: await import('jsonc-eslint-parser'),
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
ignores: ['**/out-tsc'],
|
|
21
|
-
},
|
|
22
|
-
];
|
package/jest.config.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
displayName: 'nest-file-storage',
|
|
3
|
-
preset: '../../jest.preset.js',
|
|
4
|
-
testEnvironment: 'node',
|
|
5
|
-
transform: {
|
|
6
|
-
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
7
|
-
},
|
|
8
|
-
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
9
|
-
coverageDirectory: '../../coverage/packages/nest-file-storage',
|
|
10
|
-
};
|
package/project.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "nest-file-storage",
|
|
3
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "packages/nest-file-storage/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"release": {
|
|
7
|
-
"version": {
|
|
8
|
-
"manifestRootsToUpdate": [
|
|
9
|
-
"dist/{projectRoot}"
|
|
10
|
-
],
|
|
11
|
-
"currentVersionResolver": "git-tag",
|
|
12
|
-
"fallbackCurrentVersionResolver": "disk"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"tags": [],
|
|
16
|
-
"targets": {
|
|
17
|
-
"build": {
|
|
18
|
-
"executor": "@nx/js:tsc",
|
|
19
|
-
"outputs": [
|
|
20
|
-
"{options.outputPath}"
|
|
21
|
-
],
|
|
22
|
-
"options": {
|
|
23
|
-
"outputPath": "dist/packages/nest-file-storage",
|
|
24
|
-
"tsConfig": "packages/nest-file-storage/tsconfig.lib.json",
|
|
25
|
-
"packageJson": "packages/nest-file-storage/package.json",
|
|
26
|
-
"main": "packages/nest-file-storage/src/index.ts",
|
|
27
|
-
"assets": [
|
|
28
|
-
"packages/nest-file-storage/*.md"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"nx-release-publish": {
|
|
33
|
-
"options": {
|
|
34
|
-
"packageRoot": "dist/{projectRoot}"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
package/src/lib/constants.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const FILE_STORAGE_OPTIONS = 'FileStorageOptions';
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { StorageFactory } from './storage.factory';
|
|
2
|
-
import { FileStorageEnum, FileStorageModuleOptions, FileStorageConfigOptions, FileStorageClassOptions } from './types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export class FileStorageService {
|
|
6
|
-
|
|
7
|
-
private static options: FileStorageModuleOptions; // ✅ Static global property
|
|
8
|
-
|
|
9
|
-
static setOptions(options: FileStorageModuleOptions) {
|
|
10
|
-
FileStorageService.options = options;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
static getOptions(): FileStorageModuleOptions {
|
|
14
|
-
return FileStorageService.options;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
static async getStorage(storageType?: FileStorageEnum) {
|
|
18
|
-
const options = this.getOptions();
|
|
19
|
-
|
|
20
|
-
// Check if it's a class factory approach
|
|
21
|
-
if ('storageFactory' in options) {
|
|
22
|
-
const classOptions = options as FileStorageClassOptions;
|
|
23
|
-
const StorageClass = await classOptions.storageFactory();
|
|
24
|
-
return new StorageClass(classOptions.options);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Configuration-based approach
|
|
28
|
-
const configOptions = options as FileStorageConfigOptions;
|
|
29
|
-
if (!storageType) {
|
|
30
|
-
storageType = configOptions.storage;
|
|
31
|
-
}
|
|
32
|
-
const config = (configOptions as any)[`Config`];
|
|
33
|
-
return await StorageFactory.createStorage(storageType, config);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
}
|