express-storage 2.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +366 -34
- package/dist/cjs/config/index.d.ts +10 -0
- package/dist/cjs/config/index.d.ts.map +1 -0
- package/dist/cjs/config/index.js +19 -0
- package/dist/cjs/config/index.js.map +1 -0
- package/dist/cjs/drivers/azure.driver.d.ts +73 -0
- package/dist/cjs/drivers/azure.driver.d.ts.map +1 -0
- package/dist/cjs/drivers/azure.driver.js +390 -0
- package/dist/cjs/drivers/azure.driver.js.map +1 -0
- package/dist/cjs/drivers/base.driver.d.ts +136 -0
- package/dist/cjs/drivers/base.driver.d.ts.map +1 -0
- package/dist/cjs/drivers/base.driver.js +357 -0
- package/dist/cjs/drivers/base.driver.js.map +1 -0
- package/dist/{drivers → cjs/drivers}/gcs.driver.d.ts +20 -38
- package/dist/cjs/drivers/gcs.driver.d.ts.map +1 -0
- package/dist/cjs/drivers/gcs.driver.js +343 -0
- package/dist/cjs/drivers/gcs.driver.js.map +1 -0
- package/dist/cjs/drivers/index.d.ts +15 -0
- package/dist/cjs/drivers/index.d.ts.map +1 -0
- package/dist/cjs/drivers/index.js +26 -0
- package/dist/cjs/drivers/index.js.map +1 -0
- package/dist/cjs/drivers/local.driver.d.ts +86 -0
- package/dist/cjs/drivers/local.driver.d.ts.map +1 -0
- package/dist/cjs/drivers/local.driver.js +556 -0
- package/dist/cjs/drivers/local.driver.js.map +1 -0
- package/dist/{drivers → cjs/drivers}/s3.driver.d.ts +19 -39
- package/dist/cjs/drivers/s3.driver.d.ts.map +1 -0
- package/dist/cjs/drivers/s3.driver.js +400 -0
- package/dist/cjs/drivers/s3.driver.js.map +1 -0
- package/dist/cjs/factory/driver.factory.d.ts +43 -0
- package/dist/cjs/factory/driver.factory.d.ts.map +1 -0
- package/dist/cjs/factory/driver.factory.js +101 -0
- package/dist/cjs/factory/driver.factory.js.map +1 -0
- package/dist/cjs/index.d.ts +26 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +31 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/storage-manager.d.ts +210 -0
- package/dist/cjs/storage-manager.d.ts.map +1 -0
- package/dist/cjs/storage-manager.js +649 -0
- package/dist/cjs/storage-manager.js.map +1 -0
- package/dist/cjs/types/storage.types.d.ts +438 -0
- package/dist/cjs/types/storage.types.d.ts.map +1 -0
- package/dist/cjs/types/storage.types.js +3 -0
- package/dist/cjs/types/storage.types.js.map +1 -0
- package/dist/cjs/utils/config.utils.d.ts.map +1 -0
- package/dist/cjs/utils/config.utils.js +213 -0
- package/dist/cjs/utils/config.utils.js.map +1 -0
- package/dist/{utils → cjs/utils}/file.utils.d.ts +62 -8
- package/dist/cjs/utils/file.utils.d.ts.map +1 -0
- package/dist/cjs/utils/file.utils.js +464 -0
- package/dist/cjs/utils/file.utils.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +12 -0
- package/dist/cjs/utils/index.d.ts.map +1 -0
- package/dist/cjs/utils/index.js +36 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils/rate-limiter.d.ts +40 -0
- package/dist/cjs/utils/rate-limiter.d.ts.map +1 -0
- package/dist/cjs/utils/rate-limiter.js +87 -0
- package/dist/cjs/utils/rate-limiter.js.map +1 -0
- package/dist/esm/config/index.d.ts +10 -0
- package/dist/esm/config/index.d.ts.map +1 -0
- package/dist/esm/config/index.js +10 -0
- package/dist/esm/config/index.js.map +1 -0
- package/dist/esm/drivers/azure.driver.d.ts +73 -0
- package/dist/esm/drivers/azure.driver.d.ts.map +1 -0
- package/dist/esm/drivers/azure.driver.js +353 -0
- package/dist/esm/drivers/azure.driver.js.map +1 -0
- package/dist/esm/drivers/base.driver.d.ts +136 -0
- package/dist/esm/drivers/base.driver.d.ts.map +1 -0
- package/dist/esm/drivers/base.driver.js +350 -0
- package/dist/esm/drivers/base.driver.js.map +1 -0
- package/dist/esm/drivers/gcs.driver.d.ts +68 -0
- package/dist/esm/drivers/gcs.driver.d.ts.map +1 -0
- package/dist/esm/drivers/gcs.driver.js +306 -0
- package/dist/esm/drivers/gcs.driver.js.map +1 -0
- package/dist/esm/drivers/index.d.ts +15 -0
- package/dist/esm/drivers/index.d.ts.map +1 -0
- package/dist/esm/drivers/index.js +15 -0
- package/dist/esm/drivers/index.js.map +1 -0
- package/dist/esm/drivers/local.driver.d.ts +86 -0
- package/dist/esm/drivers/local.driver.d.ts.map +1 -0
- package/dist/esm/drivers/local.driver.js +549 -0
- package/dist/esm/drivers/local.driver.js.map +1 -0
- package/dist/esm/drivers/s3.driver.d.ts +69 -0
- package/dist/esm/drivers/s3.driver.d.ts.map +1 -0
- package/dist/esm/drivers/s3.driver.js +363 -0
- package/dist/esm/drivers/s3.driver.js.map +1 -0
- package/dist/esm/factory/driver.factory.d.ts +43 -0
- package/dist/esm/factory/driver.factory.d.ts.map +1 -0
- package/dist/esm/factory/driver.factory.js +92 -0
- package/dist/esm/factory/driver.factory.js.map +1 -0
- package/dist/esm/index.d.ts +26 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/storage-manager.d.ts +210 -0
- package/dist/esm/storage-manager.d.ts.map +1 -0
- package/dist/esm/storage-manager.js +645 -0
- package/dist/esm/storage-manager.js.map +1 -0
- package/dist/esm/types/storage.types.d.ts +438 -0
- package/dist/esm/types/storage.types.d.ts.map +1 -0
- package/dist/esm/types/storage.types.js.map +1 -0
- package/dist/esm/utils/config.utils.d.ts +45 -0
- package/dist/esm/utils/config.utils.d.ts.map +1 -0
- package/dist/esm/utils/config.utils.js.map +1 -0
- package/dist/esm/utils/file.utils.d.ts +196 -0
- package/dist/esm/utils/file.utils.d.ts.map +1 -0
- package/dist/esm/utils/file.utils.js +439 -0
- package/dist/esm/utils/file.utils.js.map +1 -0
- package/dist/esm/utils/index.d.ts +12 -0
- package/dist/esm/utils/index.d.ts.map +1 -0
- package/dist/esm/utils/index.js +11 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/rate-limiter.d.ts +40 -0
- package/dist/esm/utils/rate-limiter.d.ts.map +1 -0
- package/dist/esm/utils/rate-limiter.js +82 -0
- package/dist/esm/utils/rate-limiter.js.map +1 -0
- package/package.json +90 -52
- package/src/config/index.ts +17 -0
- package/src/drivers/azure.driver.ts +434 -0
- package/src/drivers/base.driver.ts +436 -0
- package/src/drivers/gcs.driver.ts +366 -0
- package/src/drivers/index.ts +15 -0
- package/src/drivers/local.driver.ts +626 -0
- package/src/drivers/s3.driver.ts +459 -0
- package/src/factory/driver.factory.ts +101 -0
- package/src/index.ts +72 -0
- package/src/storage-manager.ts +801 -0
- package/src/types/storage.types.ts +561 -0
- package/src/utils/config.utils.ts +229 -0
- package/src/utils/file.utils.ts +536 -0
- package/src/utils/index.ts +35 -0
- package/src/utils/rate-limiter.ts +94 -0
- package/dist/drivers/azure.driver.d.ts +0 -88
- package/dist/drivers/azure.driver.d.ts.map +0 -1
- package/dist/drivers/azure.driver.js +0 -391
- package/dist/drivers/azure.driver.js.map +0 -1
- package/dist/drivers/base.driver.d.ts +0 -170
- package/dist/drivers/base.driver.d.ts.map +0 -1
- package/dist/drivers/base.driver.js +0 -347
- package/dist/drivers/base.driver.js.map +0 -1
- package/dist/drivers/gcs.driver.d.ts.map +0 -1
- package/dist/drivers/gcs.driver.js +0 -354
- package/dist/drivers/gcs.driver.js.map +0 -1
- package/dist/drivers/local.driver.d.ts +0 -107
- package/dist/drivers/local.driver.d.ts.map +0 -1
- package/dist/drivers/local.driver.js +0 -621
- package/dist/drivers/local.driver.js.map +0 -1
- package/dist/drivers/s3.driver.d.ts.map +0 -1
- package/dist/drivers/s3.driver.js +0 -387
- package/dist/drivers/s3.driver.js.map +0 -1
- package/dist/factory/driver.factory.d.ts +0 -62
- package/dist/factory/driver.factory.d.ts.map +0 -1
- package/dist/factory/driver.factory.js +0 -177
- package/dist/factory/driver.factory.js.map +0 -1
- package/dist/index.d.ts +0 -30
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -33
- package/dist/index.js.map +0 -1
- package/dist/storage-manager.d.ts +0 -228
- package/dist/storage-manager.d.ts.map +0 -1
- package/dist/storage-manager.js +0 -715
- package/dist/storage-manager.js.map +0 -1
- package/dist/types/storage.types.d.ts +0 -295
- package/dist/types/storage.types.d.ts.map +0 -1
- package/dist/types/storage.types.js.map +0 -1
- package/dist/utils/config.utils.d.ts.map +0 -1
- package/dist/utils/config.utils.js.map +0 -1
- package/dist/utils/file.utils.d.ts.map +0 -1
- package/dist/utils/file.utils.js +0 -278
- package/dist/utils/file.utils.js.map +0 -1
- /package/dist/{utils → cjs/utils}/config.utils.d.ts +0 -0
- /package/dist/{types → esm/types}/storage.types.js +0 -0
- /package/dist/{utils → esm/utils}/config.utils.js +0 -0
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';
|
|
2
|
-
import { Upload } from '@aws-sdk/lib-storage';
|
|
3
|
-
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
4
|
-
import { BaseStorageDriver } from './base.driver.js';
|
|
5
|
-
/**
|
|
6
|
-
* S3StorageDriver - Handles file operations with Amazon S3.
|
|
7
|
-
*
|
|
8
|
-
* Supports two authentication methods:
|
|
9
|
-
* 1. Explicit credentials (AWS_ACCESS_KEY + AWS_SECRET_KEY)
|
|
10
|
-
* 2. IAM roles (when running on AWS infrastructure)
|
|
11
|
-
*
|
|
12
|
-
* If you don't provide credentials, the AWS SDK automatically uses
|
|
13
|
-
* IAM roles, environment variables, or the shared credentials file.
|
|
14
|
-
*/
|
|
15
|
-
export class S3StorageDriver extends BaseStorageDriver {
|
|
16
|
-
constructor(config) {
|
|
17
|
-
super(config);
|
|
18
|
-
this.bucketName = config.bucketName;
|
|
19
|
-
this.region = config.awsRegion;
|
|
20
|
-
const s3Options = {
|
|
21
|
-
region: this.region,
|
|
22
|
-
};
|
|
23
|
-
// Only set explicit credentials if provided — otherwise use IAM/default chain
|
|
24
|
-
if (config.awsAccessKey && config.awsSecretKey) {
|
|
25
|
-
s3Options.credentials = {
|
|
26
|
-
accessKeyId: config.awsAccessKey,
|
|
27
|
-
secretAccessKey: config.awsSecretKey,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
this.s3Client = new S3Client(s3Options);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Uploads a file directly to S3.
|
|
34
|
-
* Handles both memory and disk storage from Multer.
|
|
35
|
-
*
|
|
36
|
-
* For large files (>100MB), uses streaming multipart upload to reduce
|
|
37
|
-
* memory usage and improve reliability.
|
|
38
|
-
*/
|
|
39
|
-
async upload(file, options) {
|
|
40
|
-
try {
|
|
41
|
-
const validationErrors = this.validateFile(file);
|
|
42
|
-
if (validationErrors.length > 0) {
|
|
43
|
-
return this.createErrorResult(validationErrors.join(', '));
|
|
44
|
-
}
|
|
45
|
-
const fileName = this.generateFileName(file.originalname);
|
|
46
|
-
const fileKey = this.buildFilePath(fileName);
|
|
47
|
-
const fileSize = this.getFileSize(file);
|
|
48
|
-
// Use streaming upload for large files to reduce memory usage
|
|
49
|
-
if (this.shouldUseStreaming(file)) {
|
|
50
|
-
return this.uploadWithStream(file, fileKey, fileSize, options);
|
|
51
|
-
}
|
|
52
|
-
// Standard upload for smaller files
|
|
53
|
-
const fileContent = this.getFileContent(file);
|
|
54
|
-
const commandInput = {
|
|
55
|
-
Bucket: this.bucketName,
|
|
56
|
-
Key: fileKey,
|
|
57
|
-
Body: fileContent,
|
|
58
|
-
ContentType: options?.contentType || file.mimetype,
|
|
59
|
-
ContentLength: fileContent.length,
|
|
60
|
-
};
|
|
61
|
-
if (options?.cacheControl) {
|
|
62
|
-
commandInput.CacheControl = options.cacheControl;
|
|
63
|
-
}
|
|
64
|
-
if (options?.contentDisposition) {
|
|
65
|
-
commandInput.ContentDisposition = options.contentDisposition;
|
|
66
|
-
}
|
|
67
|
-
if (options?.metadata) {
|
|
68
|
-
commandInput.Metadata = options.metadata;
|
|
69
|
-
}
|
|
70
|
-
const uploadCommand = new PutObjectCommand(commandInput);
|
|
71
|
-
await this.s3Client.send(uploadCommand);
|
|
72
|
-
// Build the public URL with proper encoding
|
|
73
|
-
const encodedKey = fileKey.split('/').map(segment => encodeURIComponent(segment)).join('/');
|
|
74
|
-
const fileUrl = `https://${this.bucketName}.s3.${this.region}.amazonaws.com/${encodedKey}`;
|
|
75
|
-
return this.createSuccessResult(fileKey, fileUrl);
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
return this.createErrorResult(error instanceof Error ? error.message : 'Failed to upload file to S3');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Uploads a large file using streaming multipart upload.
|
|
83
|
-
*
|
|
84
|
-
* This method uses the @aws-sdk/lib-storage Upload class which handles
|
|
85
|
-
* multipart uploads automatically. It's more memory-efficient for large
|
|
86
|
-
* files as it streams data in chunks rather than loading everything into memory.
|
|
87
|
-
*/
|
|
88
|
-
async uploadWithStream(file, fileKey, fileSize, options) {
|
|
89
|
-
const fileStream = this.getFileStream(file);
|
|
90
|
-
const uploadParams = {
|
|
91
|
-
Bucket: this.bucketName,
|
|
92
|
-
Key: fileKey,
|
|
93
|
-
Body: fileStream,
|
|
94
|
-
ContentType: options?.contentType || file.mimetype,
|
|
95
|
-
};
|
|
96
|
-
// Include content length if known (helps with progress tracking)
|
|
97
|
-
if (fileSize > 0) {
|
|
98
|
-
uploadParams.ContentLength = fileSize;
|
|
99
|
-
}
|
|
100
|
-
if (options?.cacheControl) {
|
|
101
|
-
uploadParams.CacheControl = options.cacheControl;
|
|
102
|
-
}
|
|
103
|
-
if (options?.contentDisposition) {
|
|
104
|
-
uploadParams.ContentDisposition = options.contentDisposition;
|
|
105
|
-
}
|
|
106
|
-
if (options?.metadata) {
|
|
107
|
-
uploadParams.Metadata = options.metadata;
|
|
108
|
-
}
|
|
109
|
-
const upload = new Upload({
|
|
110
|
-
client: this.s3Client,
|
|
111
|
-
params: uploadParams,
|
|
112
|
-
// Use 10MB parts for multipart upload (minimum is 5MB)
|
|
113
|
-
partSize: 10 * 1024 * 1024,
|
|
114
|
-
// Upload up to 4 parts concurrently
|
|
115
|
-
queueSize: 4,
|
|
116
|
-
});
|
|
117
|
-
await upload.done();
|
|
118
|
-
// Build the public URL with proper encoding
|
|
119
|
-
const encodedKey = fileKey.split('/').map(segment => encodeURIComponent(segment)).join('/');
|
|
120
|
-
const fileUrl = `https://${this.bucketName}.s3.${this.region}.amazonaws.com/${encodedKey}`;
|
|
121
|
-
return this.createSuccessResult(fileKey, fileUrl);
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Creates a presigned URL for uploading directly to S3.
|
|
125
|
-
*
|
|
126
|
-
* The URL enforces:
|
|
127
|
-
* - Exact content type (baked into the signature)
|
|
128
|
-
* - Exact file size (if provided)
|
|
129
|
-
*
|
|
130
|
-
* Clients that try to upload different content will get a 403.
|
|
131
|
-
*/
|
|
132
|
-
async generateUploadUrl(fileName, contentType, fileSize) {
|
|
133
|
-
// Security: Defense-in-depth validation (StorageManager also validates)
|
|
134
|
-
// Decode URL-encoded characters first to catch encoded traversal attempts like %2e%2e%2f
|
|
135
|
-
let decodedFileName;
|
|
136
|
-
try {
|
|
137
|
-
decodedFileName = decodeURIComponent(fileName);
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return this.createPresignedErrorResult('Invalid fileName: malformed URL encoding');
|
|
141
|
-
}
|
|
142
|
-
if (decodedFileName.includes('..') || decodedFileName.includes('\0')) {
|
|
143
|
-
return this.createPresignedErrorResult('Invalid fileName: path traversal sequences are not allowed');
|
|
144
|
-
}
|
|
145
|
-
try {
|
|
146
|
-
const resolvedContentType = contentType || 'application/octet-stream';
|
|
147
|
-
const commandInput = {
|
|
148
|
-
Bucket: this.bucketName,
|
|
149
|
-
Key: decodedFileName,
|
|
150
|
-
ContentType: resolvedContentType,
|
|
151
|
-
};
|
|
152
|
-
if (fileSize !== undefined) {
|
|
153
|
-
commandInput.ContentLength = fileSize;
|
|
154
|
-
}
|
|
155
|
-
const uploadCommand = new PutObjectCommand(commandInput);
|
|
156
|
-
const uploadUrl = await getSignedUrl(this.s3Client, uploadCommand, {
|
|
157
|
-
expiresIn: this.getPresignedUrlExpiry(),
|
|
158
|
-
signableHeaders: new Set(['content-type', 'content-length']),
|
|
159
|
-
});
|
|
160
|
-
return this.createPresignedSuccessResult(uploadUrl);
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
return this.createPresignedErrorResult(error instanceof Error ? error.message : 'Failed to generate upload URL');
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Creates a presigned URL for downloading/viewing a file.
|
|
168
|
-
*/
|
|
169
|
-
async generateViewUrl(fileName) {
|
|
170
|
-
// Security: Defense-in-depth validation
|
|
171
|
-
// Decode URL-encoded characters first to catch encoded traversal attempts like %2e%2e%2f
|
|
172
|
-
let decodedFileName;
|
|
173
|
-
try {
|
|
174
|
-
decodedFileName = decodeURIComponent(fileName);
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
return this.createPresignedErrorResult('Invalid fileName: malformed URL encoding');
|
|
178
|
-
}
|
|
179
|
-
if (decodedFileName.includes('..') || decodedFileName.includes('\0')) {
|
|
180
|
-
return this.createPresignedErrorResult('Invalid fileName: path traversal sequences are not allowed');
|
|
181
|
-
}
|
|
182
|
-
try {
|
|
183
|
-
const getCommand = new GetObjectCommand({
|
|
184
|
-
Bucket: this.bucketName,
|
|
185
|
-
Key: decodedFileName,
|
|
186
|
-
});
|
|
187
|
-
const viewUrl = await getSignedUrl(this.s3Client, getCommand, {
|
|
188
|
-
expiresIn: this.getPresignedUrlExpiry(),
|
|
189
|
-
});
|
|
190
|
-
return this.createPresignedSuccessResult(undefined, viewUrl);
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
return this.createPresignedErrorResult(error instanceof Error ? error.message : 'Failed to generate view URL');
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Deletes a file from S3.
|
|
198
|
-
* Returns false if the file doesn't exist, throws on real errors.
|
|
199
|
-
*/
|
|
200
|
-
async delete(fileName) {
|
|
201
|
-
// Security: Defense-in-depth validation
|
|
202
|
-
// Decode URL-encoded characters first to catch encoded traversal attempts like %2e%2e%2f
|
|
203
|
-
let decodedFileName;
|
|
204
|
-
try {
|
|
205
|
-
decodedFileName = decodeURIComponent(fileName);
|
|
206
|
-
}
|
|
207
|
-
catch {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
if (decodedFileName.includes('..') || decodedFileName.includes('\0')) {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
const headCommand = new HeadObjectCommand({
|
|
214
|
-
Bucket: this.bucketName,
|
|
215
|
-
Key: decodedFileName,
|
|
216
|
-
});
|
|
217
|
-
try {
|
|
218
|
-
await this.s3Client.send(headCommand);
|
|
219
|
-
}
|
|
220
|
-
catch (error) {
|
|
221
|
-
const errorName = error?.name;
|
|
222
|
-
const httpStatusCode = error?.$metadata?.httpStatusCode;
|
|
223
|
-
if (httpStatusCode === 404 || errorName === 'NotFound' || errorName === 'NoSuchKey') {
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
throw error;
|
|
227
|
-
}
|
|
228
|
-
const deleteCommand = new DeleteObjectCommand({
|
|
229
|
-
Bucket: this.bucketName,
|
|
230
|
-
Key: decodedFileName,
|
|
231
|
-
});
|
|
232
|
-
await this.s3Client.send(deleteCommand);
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Confirms an upload and optionally validates the file.
|
|
237
|
-
*
|
|
238
|
-
* For S3, validation is optional since constraints are enforced at URL level.
|
|
239
|
-
* But you can still use this to verify the file matches expectations.
|
|
240
|
-
*/
|
|
241
|
-
async validateAndConfirmUpload(reference, options) {
|
|
242
|
-
const deleteOnFailure = options?.deleteOnFailure !== false;
|
|
243
|
-
try {
|
|
244
|
-
const headCommand = new HeadObjectCommand({
|
|
245
|
-
Bucket: this.bucketName,
|
|
246
|
-
Key: reference,
|
|
247
|
-
});
|
|
248
|
-
const headResult = await this.s3Client.send(headCommand);
|
|
249
|
-
const actualContentType = headResult.ContentType;
|
|
250
|
-
const actualFileSize = headResult.ContentLength;
|
|
251
|
-
// Validate content type if expected
|
|
252
|
-
if (options?.expectedContentType && actualContentType !== options.expectedContentType) {
|
|
253
|
-
if (deleteOnFailure) {
|
|
254
|
-
await this.delete(reference);
|
|
255
|
-
}
|
|
256
|
-
const errorResult = {
|
|
257
|
-
success: false,
|
|
258
|
-
error: `Content type mismatch: expected '${options.expectedContentType}', got '${actualContentType}'${deleteOnFailure ? ' (file deleted)' : ' (file kept for inspection)'}`,
|
|
259
|
-
};
|
|
260
|
-
if (actualContentType)
|
|
261
|
-
errorResult.actualContentType = actualContentType;
|
|
262
|
-
if (actualFileSize !== undefined)
|
|
263
|
-
errorResult.actualFileSize = actualFileSize;
|
|
264
|
-
return errorResult;
|
|
265
|
-
}
|
|
266
|
-
// Validate file size if expected
|
|
267
|
-
if (options?.expectedFileSize !== undefined && actualFileSize !== options.expectedFileSize) {
|
|
268
|
-
if (deleteOnFailure) {
|
|
269
|
-
await this.delete(reference);
|
|
270
|
-
}
|
|
271
|
-
const errorResult = {
|
|
272
|
-
success: false,
|
|
273
|
-
error: `File size mismatch: expected ${options.expectedFileSize} bytes, got ${actualFileSize} bytes${deleteOnFailure ? ' (file deleted)' : ' (file kept for inspection)'}`,
|
|
274
|
-
};
|
|
275
|
-
if (actualContentType)
|
|
276
|
-
errorResult.actualContentType = actualContentType;
|
|
277
|
-
if (actualFileSize !== undefined)
|
|
278
|
-
errorResult.actualFileSize = actualFileSize;
|
|
279
|
-
return errorResult;
|
|
280
|
-
}
|
|
281
|
-
const viewResult = await this.generateViewUrl(reference);
|
|
282
|
-
const result = {
|
|
283
|
-
success: true,
|
|
284
|
-
reference,
|
|
285
|
-
expiresIn: this.getPresignedUrlExpiry(),
|
|
286
|
-
};
|
|
287
|
-
if (viewResult.viewUrl) {
|
|
288
|
-
result.viewUrl = viewResult.viewUrl;
|
|
289
|
-
}
|
|
290
|
-
if (actualContentType) {
|
|
291
|
-
result.actualContentType = actualContentType;
|
|
292
|
-
}
|
|
293
|
-
if (actualFileSize !== undefined) {
|
|
294
|
-
result.actualFileSize = actualFileSize;
|
|
295
|
-
}
|
|
296
|
-
return result;
|
|
297
|
-
}
|
|
298
|
-
catch (error) {
|
|
299
|
-
const errorMessage = error instanceof Error ? error.message : 'File not found or access denied';
|
|
300
|
-
return {
|
|
301
|
-
success: false,
|
|
302
|
-
error: errorMessage,
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Lists files in the bucket with optional prefix filtering and pagination.
|
|
308
|
-
*
|
|
309
|
-
* Note: S3's list API doesn't return content types. Use validateAndConfirmUpload()
|
|
310
|
-
* if you need content type information for specific files.
|
|
311
|
-
*/
|
|
312
|
-
async listFiles(prefix, maxResults = 1000, continuationToken) {
|
|
313
|
-
try {
|
|
314
|
-
const validatedMaxResults = Math.floor(Math.max(1, Math.min(Number.isNaN(maxResults) ? 1000 : maxResults, 1000)));
|
|
315
|
-
const command = new ListObjectsV2Command({
|
|
316
|
-
Bucket: this.bucketName,
|
|
317
|
-
Prefix: prefix || undefined,
|
|
318
|
-
MaxKeys: validatedMaxResults,
|
|
319
|
-
ContinuationToken: continuationToken || undefined,
|
|
320
|
-
});
|
|
321
|
-
const response = await this.s3Client.send(command);
|
|
322
|
-
const files = (response.Contents || []).map(item => {
|
|
323
|
-
const fileInfo = { name: item.Key || '' };
|
|
324
|
-
if (item.Size !== undefined)
|
|
325
|
-
fileInfo.size = item.Size;
|
|
326
|
-
if (item.LastModified)
|
|
327
|
-
fileInfo.lastModified = item.LastModified;
|
|
328
|
-
return fileInfo;
|
|
329
|
-
});
|
|
330
|
-
const result = {
|
|
331
|
-
success: true,
|
|
332
|
-
files,
|
|
333
|
-
};
|
|
334
|
-
if (response.NextContinuationToken) {
|
|
335
|
-
result.nextToken = response.NextContinuationToken;
|
|
336
|
-
}
|
|
337
|
-
return result;
|
|
338
|
-
}
|
|
339
|
-
catch (error) {
|
|
340
|
-
return {
|
|
341
|
-
success: false,
|
|
342
|
-
error: error instanceof Error ? error.message : 'Failed to list files',
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* S3PresignedStorageDriver - S3 driver that returns presigned URLs from upload().
|
|
349
|
-
*
|
|
350
|
-
* Use this when you want clients to upload directly to S3 without
|
|
351
|
-
* the file passing through your server.
|
|
352
|
-
*/
|
|
353
|
-
export class S3PresignedStorageDriver extends S3StorageDriver {
|
|
354
|
-
constructor(config) {
|
|
355
|
-
super(config);
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Instead of uploading the file, returns a presigned URL for the client to use.
|
|
359
|
-
*
|
|
360
|
-
* The returned fileUrl is the presigned upload URL.
|
|
361
|
-
* After the client uploads, use validateAndConfirmUpload() to get a view URL.
|
|
362
|
-
*
|
|
363
|
-
* Note: The `options` parameter (metadata, cacheControl, etc.) is NOT applied
|
|
364
|
-
* when using presigned uploads. These options must be set by the client when
|
|
365
|
-
* making the actual upload request to S3, or configured via bucket policies.
|
|
366
|
-
* For server-side uploads with full options support, use the regular 's3' driver.
|
|
367
|
-
*/
|
|
368
|
-
async upload(file, _options) {
|
|
369
|
-
try {
|
|
370
|
-
const validationErrors = this.validateFile(file);
|
|
371
|
-
if (validationErrors.length > 0) {
|
|
372
|
-
return this.createErrorResult(validationErrors.join(', '));
|
|
373
|
-
}
|
|
374
|
-
const fileName = this.generateFileName(file.originalname);
|
|
375
|
-
const filePath = this.buildFilePath(fileName);
|
|
376
|
-
const presignedResult = await this.generateUploadUrl(filePath, file.mimetype, file.size);
|
|
377
|
-
if (!presignedResult.success) {
|
|
378
|
-
return this.createErrorResult(presignedResult.error || 'Failed to generate presigned URL');
|
|
379
|
-
}
|
|
380
|
-
return this.createSuccessResult(filePath, presignedResult.uploadUrl);
|
|
381
|
-
}
|
|
382
|
-
catch (error) {
|
|
383
|
-
return this.createErrorResult(error instanceof Error ? error.message : 'Failed to generate presigned URL');
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
//# sourceMappingURL=s3.driver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"s3.driver.js","sourceRoot":"","sources":["../../src/drivers/s3.driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { StorageConfig, IStorageDriver } from '../types/storage.types.js';
|
|
2
|
-
/**
|
|
3
|
-
* StorageDriverFactory - Creates and caches storage driver instances.
|
|
4
|
-
*
|
|
5
|
-
* Drivers are cached to avoid recreating connections for the same configuration.
|
|
6
|
-
* The cache is limited to 100 drivers to prevent memory issues in long-running apps.
|
|
7
|
-
*
|
|
8
|
-
* When the cache is full, the least recently used driver gets evicted.
|
|
9
|
-
*/
|
|
10
|
-
export declare class StorageDriverFactory {
|
|
11
|
-
private static drivers;
|
|
12
|
-
/**
|
|
13
|
-
* Gets or creates a driver for the given configuration.
|
|
14
|
-
*
|
|
15
|
-
* If a driver for this exact configuration already exists, it's reused.
|
|
16
|
-
* Otherwise, a new driver is created and cached.
|
|
17
|
-
*/
|
|
18
|
-
static createDriver(config: StorageConfig): IStorageDriver;
|
|
19
|
-
/**
|
|
20
|
-
* Removes the oldest (least recently accessed) driver from the cache.
|
|
21
|
-
*/
|
|
22
|
-
private static evictLRU;
|
|
23
|
-
/**
|
|
24
|
-
* Creates a new driver instance based on the config's driver type.
|
|
25
|
-
*/
|
|
26
|
-
private static createNewDriver;
|
|
27
|
-
/**
|
|
28
|
-
* Creates a fingerprint of a string for cache key comparison.
|
|
29
|
-
* Uses triple hash approach (length + two FNV-1a hashes + checksum) for maximum collision resistance.
|
|
30
|
-
*
|
|
31
|
-
* The triple hash approach with length and checksum significantly reduces collision probability:
|
|
32
|
-
* - Single 32-bit hash: ~77k items for 50% collision probability
|
|
33
|
-
* - This approach: effectively ~128+ bits of entropy, negligible collision probability
|
|
34
|
-
*
|
|
35
|
-
* For credentials, we also include a prefix checksum to detect similar keys early.
|
|
36
|
-
*/
|
|
37
|
-
private static secureHash;
|
|
38
|
-
/**
|
|
39
|
-
* Generates a unique cache key for a configuration.
|
|
40
|
-
* Includes all properties that affect driver behavior.
|
|
41
|
-
*/
|
|
42
|
-
private static getDriverKey;
|
|
43
|
-
/**
|
|
44
|
-
* Clears all cached drivers.
|
|
45
|
-
* Useful in tests or when you've rotated credentials.
|
|
46
|
-
*/
|
|
47
|
-
static clearCache(): void;
|
|
48
|
-
/**
|
|
49
|
-
* Returns the number of cached drivers.
|
|
50
|
-
*/
|
|
51
|
-
static getCacheSize(): number;
|
|
52
|
-
/**
|
|
53
|
-
* Removes a specific driver from the cache.
|
|
54
|
-
* Useful when credentials have changed for a specific configuration.
|
|
55
|
-
*/
|
|
56
|
-
static removeFromCache(config: StorageConfig): boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Returns a list of all supported driver types.
|
|
59
|
-
*/
|
|
60
|
-
static getAvailableDrivers(): string[];
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=driver.factory.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"driver.factory.d.ts","sourceRoot":"","sources":["../../src/factory/driver.factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAa1E;;;;;;;GAOG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAC,OAAO,CAAsC;IAE5D;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc;IAuB1D;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ;IAgBvB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAqB9B;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;IAmCzB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAsB3B;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,IAAI;IAIzB;;OAEG;IACH,MAAM,CAAC,YAAY,IAAI,MAAM;IAI7B;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO;IAKtD;;OAEG;IACH,MAAM,CAAC,mBAAmB,IAAI,MAAM,EAAE;CAWvC"}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { LocalStorageDriver } from '../drivers/local.driver.js';
|
|
2
|
-
import { S3StorageDriver, S3PresignedStorageDriver } from '../drivers/s3.driver.js';
|
|
3
|
-
import { GCSStorageDriver, GCSPresignedStorageDriver } from '../drivers/gcs.driver.js';
|
|
4
|
-
import { AzureStorageDriver, AzurePresignedStorageDriver } from '../drivers/azure.driver.js';
|
|
5
|
-
const MAX_CACHED_DRIVERS = 100;
|
|
6
|
-
/**
|
|
7
|
-
* StorageDriverFactory - Creates and caches storage driver instances.
|
|
8
|
-
*
|
|
9
|
-
* Drivers are cached to avoid recreating connections for the same configuration.
|
|
10
|
-
* The cache is limited to 100 drivers to prevent memory issues in long-running apps.
|
|
11
|
-
*
|
|
12
|
-
* When the cache is full, the least recently used driver gets evicted.
|
|
13
|
-
*/
|
|
14
|
-
export class StorageDriverFactory {
|
|
15
|
-
/**
|
|
16
|
-
* Gets or creates a driver for the given configuration.
|
|
17
|
-
*
|
|
18
|
-
* If a driver for this exact configuration already exists, it's reused.
|
|
19
|
-
* Otherwise, a new driver is created and cached.
|
|
20
|
-
*/
|
|
21
|
-
static createDriver(config) {
|
|
22
|
-
const driverKey = this.getDriverKey(config);
|
|
23
|
-
const existing = this.drivers.get(driverKey);
|
|
24
|
-
if (existing) {
|
|
25
|
-
existing.lastAccess = Date.now();
|
|
26
|
-
return existing.driver;
|
|
27
|
-
}
|
|
28
|
-
if (this.drivers.size >= MAX_CACHED_DRIVERS) {
|
|
29
|
-
this.evictLRU();
|
|
30
|
-
}
|
|
31
|
-
const driver = this.createNewDriver(config);
|
|
32
|
-
this.drivers.set(driverKey, {
|
|
33
|
-
driver,
|
|
34
|
-
lastAccess: Date.now(),
|
|
35
|
-
});
|
|
36
|
-
return driver;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Removes the oldest (least recently accessed) driver from the cache.
|
|
40
|
-
*/
|
|
41
|
-
static evictLRU() {
|
|
42
|
-
let oldestKey = null;
|
|
43
|
-
let oldestTime = Infinity;
|
|
44
|
-
for (const [key, entry] of this.drivers.entries()) {
|
|
45
|
-
if (entry.lastAccess < oldestTime) {
|
|
46
|
-
oldestTime = entry.lastAccess;
|
|
47
|
-
oldestKey = key;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (oldestKey) {
|
|
51
|
-
this.drivers.delete(oldestKey);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Creates a new driver instance based on the config's driver type.
|
|
56
|
-
*/
|
|
57
|
-
static createNewDriver(config) {
|
|
58
|
-
switch (config.driver) {
|
|
59
|
-
case 'local':
|
|
60
|
-
return new LocalStorageDriver(config);
|
|
61
|
-
case 's3':
|
|
62
|
-
return new S3StorageDriver(config);
|
|
63
|
-
case 's3-presigned':
|
|
64
|
-
return new S3PresignedStorageDriver(config);
|
|
65
|
-
case 'gcs':
|
|
66
|
-
return new GCSStorageDriver(config);
|
|
67
|
-
case 'gcs-presigned':
|
|
68
|
-
return new GCSPresignedStorageDriver(config);
|
|
69
|
-
case 'azure':
|
|
70
|
-
return new AzureStorageDriver(config);
|
|
71
|
-
case 'azure-presigned':
|
|
72
|
-
return new AzurePresignedStorageDriver(config);
|
|
73
|
-
default:
|
|
74
|
-
throw new Error(`Unsupported storage driver: ${config.driver}`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Creates a fingerprint of a string for cache key comparison.
|
|
79
|
-
* Uses triple hash approach (length + two FNV-1a hashes + checksum) for maximum collision resistance.
|
|
80
|
-
*
|
|
81
|
-
* The triple hash approach with length and checksum significantly reduces collision probability:
|
|
82
|
-
* - Single 32-bit hash: ~77k items for 50% collision probability
|
|
83
|
-
* - This approach: effectively ~128+ bits of entropy, negligible collision probability
|
|
84
|
-
*
|
|
85
|
-
* For credentials, we also include a prefix checksum to detect similar keys early.
|
|
86
|
-
*/
|
|
87
|
-
static secureHash(str) {
|
|
88
|
-
if (!str)
|
|
89
|
-
return '0:0:0:0';
|
|
90
|
-
const length = str.length;
|
|
91
|
-
// First hash with standard FNV-1a offset basis
|
|
92
|
-
const FNV_OFFSET_BASIS_1 = 2166136261;
|
|
93
|
-
const FNV_PRIME = 16777619;
|
|
94
|
-
let hash1 = FNV_OFFSET_BASIS_1;
|
|
95
|
-
for (let i = 0; i < str.length; i++) {
|
|
96
|
-
hash1 ^= str.charCodeAt(i);
|
|
97
|
-
hash1 = Math.imul(hash1, FNV_PRIME);
|
|
98
|
-
}
|
|
99
|
-
// Second hash with different seed (XOR first hash into offset basis)
|
|
100
|
-
// This creates a completely different hash even for similar strings
|
|
101
|
-
const FNV_OFFSET_BASIS_2 = 0x811c9dc5 ^ (hash1 >>> 0);
|
|
102
|
-
let hash2 = FNV_OFFSET_BASIS_2;
|
|
103
|
-
for (let i = str.length - 1; i >= 0; i--) { // Reverse direction for different bit mixing
|
|
104
|
-
hash2 ^= str.charCodeAt(i);
|
|
105
|
-
hash2 = Math.imul(hash2, FNV_PRIME);
|
|
106
|
-
}
|
|
107
|
-
// Third component: simple additive checksum of character codes
|
|
108
|
-
// Provides additional collision resistance with minimal computation
|
|
109
|
-
let checksum = 0;
|
|
110
|
-
for (let i = 0; i < str.length; i++) {
|
|
111
|
-
checksum = (checksum + str.charCodeAt(i) * (i + 1)) >>> 0;
|
|
112
|
-
}
|
|
113
|
-
// Return length:hash1:hash2:checksum format - collision requires matching all four
|
|
114
|
-
return `${length}:${(hash1 >>> 0).toString(16)}:${(hash2 >>> 0).toString(16)}:${(checksum >>> 0).toString(16)}`;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Generates a unique cache key for a configuration.
|
|
118
|
-
* Includes all properties that affect driver behavior.
|
|
119
|
-
*/
|
|
120
|
-
static getDriverKey(config) {
|
|
121
|
-
const keyParts = [
|
|
122
|
-
config.driver,
|
|
123
|
-
config.bucketName || 'local',
|
|
124
|
-
config.localPath || 'default',
|
|
125
|
-
config.bucketPath || '',
|
|
126
|
-
(config.presignedUrlExpiry || 600).toString(),
|
|
127
|
-
(config.maxFileSize || 5368709120).toString(),
|
|
128
|
-
config.awsRegion || '',
|
|
129
|
-
this.secureHash(config.awsAccessKey || ''),
|
|
130
|
-
this.secureHash(config.awsSecretKey || ''),
|
|
131
|
-
config.gcsProjectId || '',
|
|
132
|
-
this.secureHash(config.gcsCredentials || ''),
|
|
133
|
-
config.azureAccountName || '',
|
|
134
|
-
config.azureContainerName || '',
|
|
135
|
-
this.secureHash(config.azureConnectionString || ''),
|
|
136
|
-
this.secureHash(config.azureAccountKey || ''),
|
|
137
|
-
];
|
|
138
|
-
return keyParts.join('_');
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Clears all cached drivers.
|
|
142
|
-
* Useful in tests or when you've rotated credentials.
|
|
143
|
-
*/
|
|
144
|
-
static clearCache() {
|
|
145
|
-
this.drivers.clear();
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Returns the number of cached drivers.
|
|
149
|
-
*/
|
|
150
|
-
static getCacheSize() {
|
|
151
|
-
return this.drivers.size;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Removes a specific driver from the cache.
|
|
155
|
-
* Useful when credentials have changed for a specific configuration.
|
|
156
|
-
*/
|
|
157
|
-
static removeFromCache(config) {
|
|
158
|
-
const driverKey = this.getDriverKey(config);
|
|
159
|
-
return this.drivers.delete(driverKey);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Returns a list of all supported driver types.
|
|
163
|
-
*/
|
|
164
|
-
static getAvailableDrivers() {
|
|
165
|
-
return [
|
|
166
|
-
'local',
|
|
167
|
-
's3',
|
|
168
|
-
's3-presigned',
|
|
169
|
-
'gcs',
|
|
170
|
-
'gcs-presigned',
|
|
171
|
-
'azure',
|
|
172
|
-
'azure-presigned'
|
|
173
|
-
];
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
StorageDriverFactory.drivers = new Map();
|
|
177
|
-
//# sourceMappingURL=driver.factory.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"driver.factory.js","sourceRoot":"","sources":["../../src/factory/driver.factory.ts"],"names":[],"mappings":"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"}
|