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
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The storage drivers you can use.
|
|
3
|
+
*
|
|
4
|
+
* Direct drivers upload through your server.
|
|
5
|
+
* Presigned drivers give you URLs for client-side uploads.
|
|
6
|
+
*/
|
|
7
|
+
export type StorageDriver = "s3" | "s3-presigned" | "gcs" | "gcs-presigned" | "azure" | "azure-presigned" | "local";
|
|
8
|
+
/**
|
|
9
|
+
* Programmatic error codes for every failure case.
|
|
10
|
+
*
|
|
11
|
+
* Use these to branch on specific error conditions without parsing strings:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* if (!result.success) {
|
|
14
|
+
* switch (result.code) {
|
|
15
|
+
* case 'FILE_TOO_LARGE': showSizeError(); break;
|
|
16
|
+
* case 'INVALID_MIME_TYPE': showTypeError(); break;
|
|
17
|
+
* case 'RATE_LIMITED': retryLater(); break;
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export type StorageErrorCode = "NO_FILE" | "FILE_EMPTY" | "FILE_TOO_LARGE" | "INVALID_MIME_TYPE" | "INVALID_EXTENSION" | "INVALID_FILENAME" | "INVALID_INPUT" | "PATH_TRAVERSAL" | "FILE_NOT_FOUND" | "VALIDATION_FAILED" | "RATE_LIMITED" | "HOOK_ABORTED" | "PRESIGNED_NOT_SUPPORTED" | "PROVIDER_ERROR";
|
|
23
|
+
/**
|
|
24
|
+
* What you get back after uploading a file.
|
|
25
|
+
*
|
|
26
|
+
* Use `result.success` to narrow the type:
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const result = await storage.uploadFile(file);
|
|
29
|
+
* if (result.success) {
|
|
30
|
+
* console.log(result.reference); // TypeScript knows this exists
|
|
31
|
+
* } else {
|
|
32
|
+
* console.log(result.error); // TypeScript knows this exists
|
|
33
|
+
* console.log(result.code); // e.g., 'FILE_TOO_LARGE'
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export type FileUploadResult = FileUploadSuccess | FileUploadError;
|
|
38
|
+
export interface FileUploadSuccess {
|
|
39
|
+
success: true;
|
|
40
|
+
/** The stored file path — pass this to deleteFile(), getMetadata(), generateViewUrl(), etc. */
|
|
41
|
+
reference: string;
|
|
42
|
+
/** URL to access the file */
|
|
43
|
+
fileUrl: string;
|
|
44
|
+
}
|
|
45
|
+
export interface FileUploadError {
|
|
46
|
+
success: false;
|
|
47
|
+
/** What went wrong */
|
|
48
|
+
error: string;
|
|
49
|
+
/** Programmatic error code */
|
|
50
|
+
code: StorageErrorCode;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* What you get back after deleting a file.
|
|
54
|
+
*/
|
|
55
|
+
export type DeleteResult = DeleteSuccess | DeleteError;
|
|
56
|
+
export interface DeleteSuccess {
|
|
57
|
+
success: true;
|
|
58
|
+
/** The file reference that was deleted */
|
|
59
|
+
reference: string;
|
|
60
|
+
}
|
|
61
|
+
export interface DeleteError {
|
|
62
|
+
success: false;
|
|
63
|
+
/** The file reference that failed to delete */
|
|
64
|
+
reference: string;
|
|
65
|
+
/** What went wrong */
|
|
66
|
+
error: string;
|
|
67
|
+
/** Programmatic error code */
|
|
68
|
+
code: StorageErrorCode;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What you get back when generating presigned URLs.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Driver-level presigned URL result. Drivers only set uploadUrl or viewUrl.
|
|
75
|
+
* StorageManager enriches this into PresignedUploadUrlResult / PresignedViewUrlResult
|
|
76
|
+
* with guaranteed fields like fileName, reference, and expiresIn.
|
|
77
|
+
*/
|
|
78
|
+
export type PresignedUrlResult = PresignedUrlSuccess | PresignedUrlError;
|
|
79
|
+
export interface PresignedUrlSuccess {
|
|
80
|
+
success: true;
|
|
81
|
+
/** URL for uploading (set by generateUploadUrl) */
|
|
82
|
+
uploadUrl?: string;
|
|
83
|
+
/** URL for viewing/downloading (set by generateViewUrl) */
|
|
84
|
+
viewUrl?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface PresignedUrlError {
|
|
87
|
+
success: false;
|
|
88
|
+
/** What went wrong */
|
|
89
|
+
error: string;
|
|
90
|
+
/** Programmatic error code */
|
|
91
|
+
code: StorageErrorCode;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Stricter result from StorageManager.generateUploadUrl().
|
|
95
|
+
* On success, fileName, reference, uploadUrl, and expiresIn are guaranteed.
|
|
96
|
+
*/
|
|
97
|
+
export type PresignedUploadUrlResult = PresignedUploadUrlSuccess | PresignedUrlError;
|
|
98
|
+
export interface PresignedUploadUrlSuccess extends PresignedUrlSuccess {
|
|
99
|
+
fileName: string;
|
|
100
|
+
reference: string;
|
|
101
|
+
uploadUrl: string;
|
|
102
|
+
expiresIn: number;
|
|
103
|
+
/** Folder path if any (e.g., "users/123/uploads") */
|
|
104
|
+
filePath?: string;
|
|
105
|
+
/** The content type this URL is restricted to */
|
|
106
|
+
contentType?: string;
|
|
107
|
+
/** The file size this URL is restricted to (S3/GCS enforce this) */
|
|
108
|
+
fileSize?: number;
|
|
109
|
+
/** True for Azure — you must call validateAndConfirmUpload after */
|
|
110
|
+
requiresValidation?: boolean;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Stricter result from StorageManager.generateViewUrl().
|
|
114
|
+
* On success, reference, viewUrl, and expiresIn are guaranteed.
|
|
115
|
+
*/
|
|
116
|
+
export type PresignedViewUrlResult = PresignedViewUrlSuccess | PresignedUrlError;
|
|
117
|
+
export interface PresignedViewUrlSuccess extends PresignedUrlSuccess {
|
|
118
|
+
reference: string;
|
|
119
|
+
viewUrl: string;
|
|
120
|
+
expiresIn: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* What you get back after validating an upload.
|
|
124
|
+
*/
|
|
125
|
+
export type BlobValidationResult = BlobValidationSuccess | BlobValidationError;
|
|
126
|
+
export interface BlobValidationSuccess {
|
|
127
|
+
success: true;
|
|
128
|
+
/** The file reference that was validated */
|
|
129
|
+
reference: string;
|
|
130
|
+
/** URL to view the file */
|
|
131
|
+
viewUrl?: string;
|
|
132
|
+
/** What the file's content type actually is */
|
|
133
|
+
actualContentType?: string;
|
|
134
|
+
/** What the file's size actually is */
|
|
135
|
+
actualFileSize?: number;
|
|
136
|
+
/** How long the view URL is valid */
|
|
137
|
+
expiresIn?: number;
|
|
138
|
+
}
|
|
139
|
+
export interface BlobValidationError {
|
|
140
|
+
success: false;
|
|
141
|
+
/** What went wrong */
|
|
142
|
+
error: string;
|
|
143
|
+
/** Programmatic error code */
|
|
144
|
+
code: StorageErrorCode;
|
|
145
|
+
/** Actual content type (for diagnostic purposes) */
|
|
146
|
+
actualContentType?: string;
|
|
147
|
+
/** Actual file size (for diagnostic purposes) */
|
|
148
|
+
actualFileSize?: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* What you get back when listing files.
|
|
152
|
+
*/
|
|
153
|
+
export type ListFilesResult = ListFilesSuccess | ListFilesError;
|
|
154
|
+
export interface ListFilesSuccess {
|
|
155
|
+
success: true;
|
|
156
|
+
/** The files found */
|
|
157
|
+
files: FileInfo[];
|
|
158
|
+
/** Token for getting the next page of results */
|
|
159
|
+
nextToken?: string;
|
|
160
|
+
}
|
|
161
|
+
export interface ListFilesError {
|
|
162
|
+
success: false;
|
|
163
|
+
/** What went wrong */
|
|
164
|
+
error: string;
|
|
165
|
+
/** Programmatic error code */
|
|
166
|
+
code: StorageErrorCode;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Options for validating uploads (especially important for Azure).
|
|
170
|
+
*/
|
|
171
|
+
export interface BlobValidationOptions {
|
|
172
|
+
/** The content type you're expecting */
|
|
173
|
+
expectedContentType?: string;
|
|
174
|
+
/** The file size you're expecting (in bytes) */
|
|
175
|
+
expectedFileSize?: number;
|
|
176
|
+
/** Delete the file if validation fails (default: true) */
|
|
177
|
+
deleteOnFailure?: boolean;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Options for validating files before upload.
|
|
181
|
+
*/
|
|
182
|
+
export interface FileValidationOptions {
|
|
183
|
+
/** Maximum file size in bytes */
|
|
184
|
+
maxSize?: number;
|
|
185
|
+
/** Allowed MIME types (e.g., ['image/jpeg', 'image/png']) */
|
|
186
|
+
allowedMimeTypes?: string[];
|
|
187
|
+
/** Allowed extensions (e.g., ['.jpg', '.png'] or ['jpg', 'png']) */
|
|
188
|
+
allowedExtensions?: string[];
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Options for customizing how files are uploaded.
|
|
192
|
+
*/
|
|
193
|
+
export interface UploadOptions {
|
|
194
|
+
/** Override the detected content type */
|
|
195
|
+
contentType?: string;
|
|
196
|
+
/** Custom metadata (key-value pairs stored with the file) */
|
|
197
|
+
metadata?: Record<string, string>;
|
|
198
|
+
/** Cache-Control header (e.g., 'max-age=31536000') */
|
|
199
|
+
cacheControl?: string;
|
|
200
|
+
/** Content-Disposition header (e.g., 'attachment; filename="file.pdf"') */
|
|
201
|
+
contentDisposition?: string;
|
|
202
|
+
/** AbortSignal to cancel an in-flight upload */
|
|
203
|
+
signal?: AbortSignal | undefined;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* File metadata for generating multiple presigned URLs at once.
|
|
207
|
+
*/
|
|
208
|
+
export interface FileMetadata {
|
|
209
|
+
/** The filename */
|
|
210
|
+
fileName: string;
|
|
211
|
+
/** MIME type (e.g., 'image/jpeg') */
|
|
212
|
+
contentType?: string;
|
|
213
|
+
/** File size in bytes */
|
|
214
|
+
fileSize?: number;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Context passed to the onError hook.
|
|
218
|
+
*/
|
|
219
|
+
export interface HookErrorContext {
|
|
220
|
+
operation: "upload" | "uploadMultiple" | "delete" | "deleteMultiple" | "generateUploadUrl" | "generateViewUrl" | "validateUpload" | "listFiles";
|
|
221
|
+
file?: Express.Multer.File;
|
|
222
|
+
reference?: string;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Hooks let you tap into the upload/delete lifecycle without modifying drivers.
|
|
226
|
+
*
|
|
227
|
+
* All hooks are optional and async-safe. If a "before" hook throws, the
|
|
228
|
+
* operation is aborted and an error result is returned.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* const storage = new StorageManager({
|
|
232
|
+
* driver: 's3',
|
|
233
|
+
* hooks: {
|
|
234
|
+
* beforeUpload: async (file) => {
|
|
235
|
+
* await virusScan(file.buffer);
|
|
236
|
+
* },
|
|
237
|
+
* afterUpload: (result) => {
|
|
238
|
+
* auditLog('file_uploaded', result);
|
|
239
|
+
* },
|
|
240
|
+
* onError: (error, ctx) => {
|
|
241
|
+
* metrics.increment('storage.error', { operation: ctx.operation });
|
|
242
|
+
* },
|
|
243
|
+
* },
|
|
244
|
+
* });
|
|
245
|
+
*/
|
|
246
|
+
export interface StorageHooks {
|
|
247
|
+
/** Called before each file upload. Throw to abort. */
|
|
248
|
+
beforeUpload?: (file: Express.Multer.File, options?: UploadOptions) => void | Promise<void>;
|
|
249
|
+
/** Called after each file upload (success or failure). */
|
|
250
|
+
afterUpload?: (result: FileUploadResult, file: Express.Multer.File) => void | Promise<void>;
|
|
251
|
+
/** Called before each file deletion. Throw to abort. */
|
|
252
|
+
beforeDelete?: (reference: string) => void | Promise<void>;
|
|
253
|
+
/** Called after each file deletion. */
|
|
254
|
+
afterDelete?: (reference: string, success: boolean) => void | Promise<void>;
|
|
255
|
+
/** Called when any operation encounters an error. */
|
|
256
|
+
onError?: (error: Error, context: HookErrorContext) => void | Promise<void>;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Adapter interface for rate limiting presigned URL generation.
|
|
260
|
+
*
|
|
261
|
+
* The built-in InMemoryRateLimiter works for single-process apps.
|
|
262
|
+
* For multi-process/clustered deployments, implement this interface
|
|
263
|
+
* backed by Redis, Memcached, or another shared store.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* // Custom Redis-backed rate limiter
|
|
267
|
+
* class RedisRateLimiter implements RateLimiterAdapter {
|
|
268
|
+
* async tryAcquire() { ... }
|
|
269
|
+
* async getRemainingRequests() { ... }
|
|
270
|
+
* async getResetTime() { ... }
|
|
271
|
+
* }
|
|
272
|
+
* const storage = new StorageManager({
|
|
273
|
+
* driver: 's3',
|
|
274
|
+
* rateLimiter: new RedisRateLimiter(redis),
|
|
275
|
+
* });
|
|
276
|
+
*/
|
|
277
|
+
export interface RateLimiterAdapter {
|
|
278
|
+
/** Check if a request is allowed and record it if so. */
|
|
279
|
+
tryAcquire(): boolean | Promise<boolean>;
|
|
280
|
+
/** Get the number of remaining requests in the current window. */
|
|
281
|
+
getRemainingRequests(): number | Promise<number>;
|
|
282
|
+
/** Get the time until the rate limit resets (in ms). */
|
|
283
|
+
getResetTime(): number | Promise<number>;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Shorthand options for creating the built-in InMemoryRateLimiter.
|
|
287
|
+
*/
|
|
288
|
+
export interface RateLimitOptions {
|
|
289
|
+
/** Maximum number of presigned URLs that can be generated per window */
|
|
290
|
+
maxRequests: number;
|
|
291
|
+
/** Time window in milliseconds (default: 60000 = 1 minute) */
|
|
292
|
+
windowMs?: number;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Logging interface — pass your own logger if you want debug output.
|
|
296
|
+
*/
|
|
297
|
+
export interface Logger {
|
|
298
|
+
debug: (message: string, ...args: unknown[]) => void;
|
|
299
|
+
info: (message: string, ...args: unknown[]) => void;
|
|
300
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
301
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Credentials and settings for storage configuration.
|
|
305
|
+
*
|
|
306
|
+
* These can be passed programmatically to override environment variables.
|
|
307
|
+
*/
|
|
308
|
+
export interface StorageCredentials {
|
|
309
|
+
/** Bucket or container name (S3/GCS bucket, Azure container) */
|
|
310
|
+
bucketName?: string;
|
|
311
|
+
/** Default folder path (e.g., 'uploads/files') */
|
|
312
|
+
bucketPath?: string;
|
|
313
|
+
/** Local storage directory */
|
|
314
|
+
localPath?: string;
|
|
315
|
+
/** How long presigned URLs stay valid (seconds, default: 600) */
|
|
316
|
+
presignedUrlExpiry?: number;
|
|
317
|
+
/** Maximum file size (bytes, default: 5GB) */
|
|
318
|
+
maxFileSize?: number;
|
|
319
|
+
awsRegion?: string;
|
|
320
|
+
awsAccessKey?: string;
|
|
321
|
+
awsSecretKey?: string;
|
|
322
|
+
gcsProjectId?: string;
|
|
323
|
+
gcsCredentials?: string;
|
|
324
|
+
azureConnectionString?: string;
|
|
325
|
+
azureAccountName?: string;
|
|
326
|
+
azureAccountKey?: string;
|
|
327
|
+
/** Azure container name (overrides bucketName for Azure driver) */
|
|
328
|
+
azureContainerName?: string;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Options for initializing StorageManager.
|
|
332
|
+
*/
|
|
333
|
+
export interface StorageOptions {
|
|
334
|
+
/** Which storage driver to use */
|
|
335
|
+
driver: StorageDriver;
|
|
336
|
+
/** Credentials and settings (optional — can come from env vars) */
|
|
337
|
+
credentials?: StorageCredentials;
|
|
338
|
+
/** Your logger (optional — silent by default) */
|
|
339
|
+
logger?: Logger;
|
|
340
|
+
/**
|
|
341
|
+
* Rate limiting for presigned URL generation.
|
|
342
|
+
* Pass RateLimitOptions for the built-in in-memory limiter,
|
|
343
|
+
* or a RateLimiterAdapter for a custom implementation (e.g., Redis).
|
|
344
|
+
*/
|
|
345
|
+
rateLimiter?: RateLimitOptions | RateLimiterAdapter;
|
|
346
|
+
/** Lifecycle hooks (optional) */
|
|
347
|
+
hooks?: StorageHooks;
|
|
348
|
+
/** Maximum parallel operations for batch methods (default: 10) */
|
|
349
|
+
concurrency?: number;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Options for batch operations (uploadFiles, deleteFiles, etc.).
|
|
353
|
+
*/
|
|
354
|
+
export interface BatchOptions {
|
|
355
|
+
/** AbortSignal to cancel the batch operation mid-flight. */
|
|
356
|
+
signal?: AbortSignal | undefined;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Public configuration — safe to expose via getConfig().
|
|
360
|
+
* Contains non-sensitive settings only.
|
|
361
|
+
*/
|
|
362
|
+
export interface PublicStorageConfig {
|
|
363
|
+
driver: StorageDriver;
|
|
364
|
+
bucketName?: string | undefined;
|
|
365
|
+
bucketPath?: string | undefined;
|
|
366
|
+
localPath?: string | undefined;
|
|
367
|
+
presignedUrlExpiry?: number | undefined;
|
|
368
|
+
maxFileSize?: number | undefined;
|
|
369
|
+
awsRegion?: string | undefined;
|
|
370
|
+
gcsProjectId?: string | undefined;
|
|
371
|
+
azureAccountName?: string | undefined;
|
|
372
|
+
azureContainerName?: string | undefined;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Internal configuration format (used by drivers). Extends the public config
|
|
376
|
+
* with sensitive credential fields that should never be exposed to consumers.
|
|
377
|
+
*/
|
|
378
|
+
export interface StorageConfig extends PublicStorageConfig {
|
|
379
|
+
awsAccessKey?: string | undefined;
|
|
380
|
+
awsSecretKey?: string | undefined;
|
|
381
|
+
gcsCredentials?: string | undefined;
|
|
382
|
+
azureConnectionString?: string | undefined;
|
|
383
|
+
azureAccountKey?: string | undefined;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Information about a single file.
|
|
387
|
+
*/
|
|
388
|
+
export interface FileInfo {
|
|
389
|
+
/** File path/name */
|
|
390
|
+
name: string;
|
|
391
|
+
/** File size in bytes */
|
|
392
|
+
size?: number;
|
|
393
|
+
/** MIME type */
|
|
394
|
+
contentType?: string;
|
|
395
|
+
/** When the file was last modified */
|
|
396
|
+
lastModified?: Date;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* The interface all storage drivers implement.
|
|
400
|
+
*/
|
|
401
|
+
export interface IStorageDriver {
|
|
402
|
+
upload(file: Express.Multer.File, options?: UploadOptions): Promise<FileUploadResult>;
|
|
403
|
+
generateUploadUrl(fileName: string, contentType?: string, fileSize?: number): Promise<PresignedUrlResult>;
|
|
404
|
+
generateViewUrl(fileName: string): Promise<PresignedUrlResult>;
|
|
405
|
+
delete(fileName: string): Promise<DeleteResult>;
|
|
406
|
+
validateAndConfirmUpload(reference: string, options?: BlobValidationOptions): Promise<BlobValidationResult>;
|
|
407
|
+
listFiles(prefix?: string, maxResults?: number, continuationToken?: string): Promise<ListFilesResult>;
|
|
408
|
+
getMetadata(reference: string): Promise<FileInfo | null>;
|
|
409
|
+
/** Releases SDK client connections and internal resources. */
|
|
410
|
+
destroy(): void;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Result of configuration validation.
|
|
414
|
+
*/
|
|
415
|
+
export interface ValidationResult {
|
|
416
|
+
isValid: boolean;
|
|
417
|
+
errors: string[];
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Environment variables we look for.
|
|
421
|
+
*/
|
|
422
|
+
export interface EnvironmentConfig {
|
|
423
|
+
FILE_DRIVER: string;
|
|
424
|
+
BUCKET_NAME?: string | undefined;
|
|
425
|
+
BUCKET_PATH?: string | undefined;
|
|
426
|
+
LOCAL_PATH?: string | undefined;
|
|
427
|
+
PRESIGNED_URL_EXPIRY?: string | undefined;
|
|
428
|
+
MAX_FILE_SIZE?: string | undefined;
|
|
429
|
+
AWS_REGION?: string | undefined;
|
|
430
|
+
AWS_ACCESS_KEY?: string | undefined;
|
|
431
|
+
AWS_SECRET_KEY?: string | undefined;
|
|
432
|
+
GCS_PROJECT_ID?: string | undefined;
|
|
433
|
+
GCS_CREDENTIALS?: string | undefined;
|
|
434
|
+
AZURE_CONNECTION_STRING?: string | undefined;
|
|
435
|
+
AZURE_ACCOUNT_NAME?: string | undefined;
|
|
436
|
+
AZURE_ACCOUNT_KEY?: string | undefined;
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=storage.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.types.d.ts","sourceRoot":"","sources":["../../../src/types/storage.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.types.js","sourceRoot":"","sources":["../../../src/types/storage.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/config.utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAI/F;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AA2BD;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,CAsBzD;AAuBD;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,iBAAiB,GAAG,aAAa,CAuBtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,CA2E7E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAM/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initializeDotenv = initializeDotenv;
|
|
7
|
+
exports.loadEnvironmentConfig = loadEnvironmentConfig;
|
|
8
|
+
exports.environmentToStorageConfig = environmentToStorageConfig;
|
|
9
|
+
exports.validateStorageConfig = validateStorageConfig;
|
|
10
|
+
exports.loadAndValidateConfig = loadAndValidateConfig;
|
|
11
|
+
exports.resetDotenvInitialization = resetDotenvInitialization;
|
|
12
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
13
|
+
let dotenvInitialized = false;
|
|
14
|
+
/**
|
|
15
|
+
* Loads your .env file if it hasn't been loaded already.
|
|
16
|
+
* Safe to call multiple times — it only runs once.
|
|
17
|
+
*/
|
|
18
|
+
function initializeDotenv() {
|
|
19
|
+
if (!dotenvInitialized) {
|
|
20
|
+
dotenv_1.default.config();
|
|
21
|
+
dotenvInitialized = true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const ENV_KEYS = {
|
|
25
|
+
FILE_DRIVER: 'FILE_DRIVER',
|
|
26
|
+
BUCKET_NAME: 'BUCKET_NAME',
|
|
27
|
+
BUCKET_PATH: 'BUCKET_PATH',
|
|
28
|
+
LOCAL_PATH: 'LOCAL_PATH',
|
|
29
|
+
PRESIGNED_URL_EXPIRY: 'PRESIGNED_URL_EXPIRY',
|
|
30
|
+
MAX_FILE_SIZE: 'MAX_FILE_SIZE',
|
|
31
|
+
AWS_REGION: 'AWS_REGION',
|
|
32
|
+
AWS_ACCESS_KEY: 'AWS_ACCESS_KEY',
|
|
33
|
+
AWS_SECRET_KEY: 'AWS_SECRET_KEY',
|
|
34
|
+
GCS_PROJECT_ID: 'GCS_PROJECT_ID',
|
|
35
|
+
GCS_CREDENTIALS: 'GCS_CREDENTIALS',
|
|
36
|
+
AZURE_CONNECTION_STRING: 'AZURE_CONNECTION_STRING',
|
|
37
|
+
AZURE_ACCOUNT_NAME: 'AZURE_ACCOUNT_NAME',
|
|
38
|
+
AZURE_ACCOUNT_KEY: 'AZURE_ACCOUNT_KEY',
|
|
39
|
+
};
|
|
40
|
+
const DEFAULT_CONFIG = {
|
|
41
|
+
presignedUrlExpiry: 600,
|
|
42
|
+
localPath: 'public/express-storage',
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Reads storage configuration from environment variables.
|
|
46
|
+
* Automatically loads .env on first call.
|
|
47
|
+
*/
|
|
48
|
+
function loadEnvironmentConfig() {
|
|
49
|
+
initializeDotenv();
|
|
50
|
+
return {
|
|
51
|
+
FILE_DRIVER: process.env[ENV_KEYS.FILE_DRIVER] || '',
|
|
52
|
+
BUCKET_NAME: process.env[ENV_KEYS.BUCKET_NAME] || undefined,
|
|
53
|
+
BUCKET_PATH: process.env[ENV_KEYS.BUCKET_PATH] || undefined,
|
|
54
|
+
LOCAL_PATH: process.env[ENV_KEYS.LOCAL_PATH] || undefined,
|
|
55
|
+
PRESIGNED_URL_EXPIRY: process.env[ENV_KEYS.PRESIGNED_URL_EXPIRY] || undefined,
|
|
56
|
+
MAX_FILE_SIZE: process.env[ENV_KEYS.MAX_FILE_SIZE] || undefined,
|
|
57
|
+
AWS_REGION: process.env[ENV_KEYS.AWS_REGION] || undefined,
|
|
58
|
+
AWS_ACCESS_KEY: process.env[ENV_KEYS.AWS_ACCESS_KEY] || undefined,
|
|
59
|
+
AWS_SECRET_KEY: process.env[ENV_KEYS.AWS_SECRET_KEY] || undefined,
|
|
60
|
+
GCS_PROJECT_ID: process.env[ENV_KEYS.GCS_PROJECT_ID] || undefined,
|
|
61
|
+
GCS_CREDENTIALS: process.env[ENV_KEYS.GCS_CREDENTIALS] || undefined,
|
|
62
|
+
AZURE_CONNECTION_STRING: process.env[ENV_KEYS.AZURE_CONNECTION_STRING] || undefined,
|
|
63
|
+
AZURE_ACCOUNT_NAME: process.env[ENV_KEYS.AZURE_ACCOUNT_NAME] || undefined,
|
|
64
|
+
AZURE_ACCOUNT_KEY: process.env[ENV_KEYS.AZURE_ACCOUNT_KEY] || undefined,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Safely parses a string to an integer, returning a default for invalid values.
|
|
69
|
+
*
|
|
70
|
+
* Unlike parseInt(), this function rejects strings with trailing non-numeric characters.
|
|
71
|
+
* For example, "100abc" returns the default value, not 100.
|
|
72
|
+
*/
|
|
73
|
+
function parseIntSafe(value, defaultValue) {
|
|
74
|
+
if (!value)
|
|
75
|
+
return defaultValue;
|
|
76
|
+
// Trim whitespace and check if the entire string is a valid integer
|
|
77
|
+
const trimmed = value.trim();
|
|
78
|
+
// Check if the string matches a valid integer pattern (optional sign followed by digits)
|
|
79
|
+
if (!/^-?\d+$/.test(trimmed)) {
|
|
80
|
+
return defaultValue;
|
|
81
|
+
}
|
|
82
|
+
const parsed = parseInt(trimmed, 10);
|
|
83
|
+
return Number.isNaN(parsed) ? defaultValue : parsed;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Converts environment variables into a StorageConfig object.
|
|
87
|
+
*/
|
|
88
|
+
function environmentToStorageConfig(envConfig) {
|
|
89
|
+
const config = {
|
|
90
|
+
driver: envConfig.FILE_DRIVER,
|
|
91
|
+
bucketName: envConfig.BUCKET_NAME,
|
|
92
|
+
bucketPath: envConfig.BUCKET_PATH || '',
|
|
93
|
+
localPath: envConfig.LOCAL_PATH || DEFAULT_CONFIG.localPath,
|
|
94
|
+
presignedUrlExpiry: parseIntSafe(envConfig.PRESIGNED_URL_EXPIRY, DEFAULT_CONFIG.presignedUrlExpiry),
|
|
95
|
+
maxFileSize: parseIntSafe(envConfig.MAX_FILE_SIZE, undefined),
|
|
96
|
+
awsRegion: envConfig.AWS_REGION,
|
|
97
|
+
awsAccessKey: envConfig.AWS_ACCESS_KEY,
|
|
98
|
+
awsSecretKey: envConfig.AWS_SECRET_KEY,
|
|
99
|
+
gcsProjectId: envConfig.GCS_PROJECT_ID,
|
|
100
|
+
gcsCredentials: envConfig.GCS_CREDENTIALS,
|
|
101
|
+
azureConnectionString: envConfig.AZURE_CONNECTION_STRING,
|
|
102
|
+
azureAccountName: envConfig.AZURE_ACCOUNT_NAME,
|
|
103
|
+
azureAccountKey: envConfig.AZURE_ACCOUNT_KEY,
|
|
104
|
+
azureContainerName: envConfig.BUCKET_NAME, // Use BUCKET_NAME for Azure container
|
|
105
|
+
};
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validates a storage configuration.
|
|
110
|
+
*
|
|
111
|
+
* Checks that:
|
|
112
|
+
* - A valid driver is specified
|
|
113
|
+
* - Required credentials are present for the chosen driver
|
|
114
|
+
* - Numeric values are within acceptable ranges
|
|
115
|
+
*
|
|
116
|
+
* Returns an object with isValid and an array of error messages.
|
|
117
|
+
*/
|
|
118
|
+
function validateStorageConfig(config) {
|
|
119
|
+
const errors = [];
|
|
120
|
+
// Check driver
|
|
121
|
+
if (!config.driver) {
|
|
122
|
+
errors.push('FILE_DRIVER is required');
|
|
123
|
+
}
|
|
124
|
+
else if (!['s3', 's3-presigned', 'gcs', 'gcs-presigned', 'azure', 'azure-presigned', 'local'].includes(config.driver)) {
|
|
125
|
+
errors.push(`Invalid FILE_DRIVER: ${config.driver}. Must be one of: s3, s3-presigned, gcs, gcs-presigned, azure, azure-presigned, local`);
|
|
126
|
+
}
|
|
127
|
+
// S3 requirements
|
|
128
|
+
if (config.driver?.includes('s3')) {
|
|
129
|
+
if (!config.bucketName)
|
|
130
|
+
errors.push('BUCKET_NAME is required for S3');
|
|
131
|
+
if (!config.awsRegion)
|
|
132
|
+
errors.push('AWS_REGION is required for S3');
|
|
133
|
+
// Access keys are optional — IAM roles work when running on AWS
|
|
134
|
+
}
|
|
135
|
+
// GCS requirements
|
|
136
|
+
if (config.driver?.includes('gcs')) {
|
|
137
|
+
if (!config.bucketName)
|
|
138
|
+
errors.push('BUCKET_NAME is required for GCS');
|
|
139
|
+
if (!config.gcsProjectId)
|
|
140
|
+
errors.push('GCS_PROJECT_ID is required for GCS');
|
|
141
|
+
// Credentials are optional — ADC works when running on GCP
|
|
142
|
+
}
|
|
143
|
+
// Azure requirements
|
|
144
|
+
if (config.driver?.includes('azure')) {
|
|
145
|
+
const hasConnectionString = !!config.azureConnectionString;
|
|
146
|
+
const hasAccountKey = config.azureAccountName && config.azureAccountKey;
|
|
147
|
+
const hasManagedIdentity = config.azureAccountName && !config.azureAccountKey;
|
|
148
|
+
if (config.driver === 'azure-presigned') {
|
|
149
|
+
// Presigned mode needs account key for SAS URL generation
|
|
150
|
+
if (!hasConnectionString && !hasAccountKey) {
|
|
151
|
+
errors.push('Azure presigned driver requires either AZURE_CONNECTION_STRING or both AZURE_ACCOUNT_NAME and AZURE_ACCOUNT_KEY (Managed Identity cannot generate SAS URLs)');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Direct mode supports any authentication method
|
|
156
|
+
if (!hasConnectionString && !hasAccountKey && !hasManagedIdentity) {
|
|
157
|
+
errors.push('Azure requires AZURE_CONNECTION_STRING, AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY, or AZURE_ACCOUNT_NAME only (for Managed Identity)');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!config.azureContainerName) {
|
|
161
|
+
errors.push('BUCKET_NAME is required for Azure');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Validate URL expiry time
|
|
165
|
+
if (config.presignedUrlExpiry !== undefined) {
|
|
166
|
+
if (Number.isNaN(config.presignedUrlExpiry) || config.presignedUrlExpiry <= 0) {
|
|
167
|
+
errors.push('PRESIGNED_URL_EXPIRY must be a positive number greater than 0');
|
|
168
|
+
}
|
|
169
|
+
// Max 7 days — that's the cloud provider limit
|
|
170
|
+
const MAX_EXPIRY = 604800;
|
|
171
|
+
if (!Number.isNaN(config.presignedUrlExpiry) && config.presignedUrlExpiry > MAX_EXPIRY) {
|
|
172
|
+
errors.push(`PRESIGNED_URL_EXPIRY cannot exceed ${MAX_EXPIRY} seconds (7 days). Cloud providers enforce this limit.`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Validate max file size
|
|
176
|
+
if (config.maxFileSize !== undefined) {
|
|
177
|
+
if (Number.isNaN(config.maxFileSize) || config.maxFileSize <= 0) {
|
|
178
|
+
errors.push('MAX_FILE_SIZE must be a positive number greater than 0');
|
|
179
|
+
}
|
|
180
|
+
// Max 5TB — reasonable limit for single uploads
|
|
181
|
+
const MAX_FILE_SIZE_LIMIT = 5 * 1024 * 1024 * 1024 * 1024;
|
|
182
|
+
if (!Number.isNaN(config.maxFileSize) && config.maxFileSize > MAX_FILE_SIZE_LIMIT) {
|
|
183
|
+
errors.push(`MAX_FILE_SIZE cannot exceed ${MAX_FILE_SIZE_LIMIT} bytes (5TB). Consider using multipart uploads for larger files.`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
isValid: errors.length === 0,
|
|
188
|
+
errors,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Convenience function that loads and validates config in one call.
|
|
193
|
+
* Returns both the config and validation result.
|
|
194
|
+
*/
|
|
195
|
+
function loadAndValidateConfig() {
|
|
196
|
+
const envConfig = loadEnvironmentConfig();
|
|
197
|
+
const config = environmentToStorageConfig(envConfig);
|
|
198
|
+
const validation = validateStorageConfig(config);
|
|
199
|
+
return { config, validation };
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Resets the dotenv initialization flag.
|
|
203
|
+
*
|
|
204
|
+
* This is primarily useful for testing scenarios where you need to
|
|
205
|
+
* reinitialize dotenv with different environment variables.
|
|
206
|
+
*
|
|
207
|
+
* WARNING: This does not clear previously loaded environment variables.
|
|
208
|
+
* It only allows initializeDotenv() to run again.
|
|
209
|
+
*/
|
|
210
|
+
function resetDotenvInitialization() {
|
|
211
|
+
dotenvInitialized = false;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=config.utils.js.map
|