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.
Files changed (177) hide show
  1. package/README.md +366 -34
  2. package/dist/cjs/config/index.d.ts +10 -0
  3. package/dist/cjs/config/index.d.ts.map +1 -0
  4. package/dist/cjs/config/index.js +19 -0
  5. package/dist/cjs/config/index.js.map +1 -0
  6. package/dist/cjs/drivers/azure.driver.d.ts +73 -0
  7. package/dist/cjs/drivers/azure.driver.d.ts.map +1 -0
  8. package/dist/cjs/drivers/azure.driver.js +390 -0
  9. package/dist/cjs/drivers/azure.driver.js.map +1 -0
  10. package/dist/cjs/drivers/base.driver.d.ts +136 -0
  11. package/dist/cjs/drivers/base.driver.d.ts.map +1 -0
  12. package/dist/cjs/drivers/base.driver.js +357 -0
  13. package/dist/cjs/drivers/base.driver.js.map +1 -0
  14. package/dist/{drivers → cjs/drivers}/gcs.driver.d.ts +20 -38
  15. package/dist/cjs/drivers/gcs.driver.d.ts.map +1 -0
  16. package/dist/cjs/drivers/gcs.driver.js +343 -0
  17. package/dist/cjs/drivers/gcs.driver.js.map +1 -0
  18. package/dist/cjs/drivers/index.d.ts +15 -0
  19. package/dist/cjs/drivers/index.d.ts.map +1 -0
  20. package/dist/cjs/drivers/index.js +26 -0
  21. package/dist/cjs/drivers/index.js.map +1 -0
  22. package/dist/cjs/drivers/local.driver.d.ts +86 -0
  23. package/dist/cjs/drivers/local.driver.d.ts.map +1 -0
  24. package/dist/cjs/drivers/local.driver.js +556 -0
  25. package/dist/cjs/drivers/local.driver.js.map +1 -0
  26. package/dist/{drivers → cjs/drivers}/s3.driver.d.ts +19 -39
  27. package/dist/cjs/drivers/s3.driver.d.ts.map +1 -0
  28. package/dist/cjs/drivers/s3.driver.js +400 -0
  29. package/dist/cjs/drivers/s3.driver.js.map +1 -0
  30. package/dist/cjs/factory/driver.factory.d.ts +43 -0
  31. package/dist/cjs/factory/driver.factory.d.ts.map +1 -0
  32. package/dist/cjs/factory/driver.factory.js +101 -0
  33. package/dist/cjs/factory/driver.factory.js.map +1 -0
  34. package/dist/cjs/index.d.ts +26 -0
  35. package/dist/cjs/index.d.ts.map +1 -0
  36. package/dist/cjs/index.js +31 -0
  37. package/dist/cjs/index.js.map +1 -0
  38. package/dist/cjs/package.json +1 -0
  39. package/dist/cjs/storage-manager.d.ts +210 -0
  40. package/dist/cjs/storage-manager.d.ts.map +1 -0
  41. package/dist/cjs/storage-manager.js +649 -0
  42. package/dist/cjs/storage-manager.js.map +1 -0
  43. package/dist/cjs/types/storage.types.d.ts +438 -0
  44. package/dist/cjs/types/storage.types.d.ts.map +1 -0
  45. package/dist/cjs/types/storage.types.js +3 -0
  46. package/dist/cjs/types/storage.types.js.map +1 -0
  47. package/dist/cjs/utils/config.utils.d.ts.map +1 -0
  48. package/dist/cjs/utils/config.utils.js +213 -0
  49. package/dist/cjs/utils/config.utils.js.map +1 -0
  50. package/dist/{utils → cjs/utils}/file.utils.d.ts +62 -8
  51. package/dist/cjs/utils/file.utils.d.ts.map +1 -0
  52. package/dist/cjs/utils/file.utils.js +464 -0
  53. package/dist/cjs/utils/file.utils.js.map +1 -0
  54. package/dist/cjs/utils/index.d.ts +12 -0
  55. package/dist/cjs/utils/index.d.ts.map +1 -0
  56. package/dist/cjs/utils/index.js +36 -0
  57. package/dist/cjs/utils/index.js.map +1 -0
  58. package/dist/cjs/utils/rate-limiter.d.ts +40 -0
  59. package/dist/cjs/utils/rate-limiter.d.ts.map +1 -0
  60. package/dist/cjs/utils/rate-limiter.js +87 -0
  61. package/dist/cjs/utils/rate-limiter.js.map +1 -0
  62. package/dist/esm/config/index.d.ts +10 -0
  63. package/dist/esm/config/index.d.ts.map +1 -0
  64. package/dist/esm/config/index.js +10 -0
  65. package/dist/esm/config/index.js.map +1 -0
  66. package/dist/esm/drivers/azure.driver.d.ts +73 -0
  67. package/dist/esm/drivers/azure.driver.d.ts.map +1 -0
  68. package/dist/esm/drivers/azure.driver.js +353 -0
  69. package/dist/esm/drivers/azure.driver.js.map +1 -0
  70. package/dist/esm/drivers/base.driver.d.ts +136 -0
  71. package/dist/esm/drivers/base.driver.d.ts.map +1 -0
  72. package/dist/esm/drivers/base.driver.js +350 -0
  73. package/dist/esm/drivers/base.driver.js.map +1 -0
  74. package/dist/esm/drivers/gcs.driver.d.ts +68 -0
  75. package/dist/esm/drivers/gcs.driver.d.ts.map +1 -0
  76. package/dist/esm/drivers/gcs.driver.js +306 -0
  77. package/dist/esm/drivers/gcs.driver.js.map +1 -0
  78. package/dist/esm/drivers/index.d.ts +15 -0
  79. package/dist/esm/drivers/index.d.ts.map +1 -0
  80. package/dist/esm/drivers/index.js +15 -0
  81. package/dist/esm/drivers/index.js.map +1 -0
  82. package/dist/esm/drivers/local.driver.d.ts +86 -0
  83. package/dist/esm/drivers/local.driver.d.ts.map +1 -0
  84. package/dist/esm/drivers/local.driver.js +549 -0
  85. package/dist/esm/drivers/local.driver.js.map +1 -0
  86. package/dist/esm/drivers/s3.driver.d.ts +69 -0
  87. package/dist/esm/drivers/s3.driver.d.ts.map +1 -0
  88. package/dist/esm/drivers/s3.driver.js +363 -0
  89. package/dist/esm/drivers/s3.driver.js.map +1 -0
  90. package/dist/esm/factory/driver.factory.d.ts +43 -0
  91. package/dist/esm/factory/driver.factory.d.ts.map +1 -0
  92. package/dist/esm/factory/driver.factory.js +92 -0
  93. package/dist/esm/factory/driver.factory.js.map +1 -0
  94. package/dist/esm/index.d.ts +26 -0
  95. package/dist/esm/index.d.ts.map +1 -0
  96. package/dist/esm/index.js +26 -0
  97. package/dist/esm/index.js.map +1 -0
  98. package/dist/esm/package.json +1 -0
  99. package/dist/esm/storage-manager.d.ts +210 -0
  100. package/dist/esm/storage-manager.d.ts.map +1 -0
  101. package/dist/esm/storage-manager.js +645 -0
  102. package/dist/esm/storage-manager.js.map +1 -0
  103. package/dist/esm/types/storage.types.d.ts +438 -0
  104. package/dist/esm/types/storage.types.d.ts.map +1 -0
  105. package/dist/esm/types/storage.types.js.map +1 -0
  106. package/dist/esm/utils/config.utils.d.ts +45 -0
  107. package/dist/esm/utils/config.utils.d.ts.map +1 -0
  108. package/dist/esm/utils/config.utils.js.map +1 -0
  109. package/dist/esm/utils/file.utils.d.ts +196 -0
  110. package/dist/esm/utils/file.utils.d.ts.map +1 -0
  111. package/dist/esm/utils/file.utils.js +439 -0
  112. package/dist/esm/utils/file.utils.js.map +1 -0
  113. package/dist/esm/utils/index.d.ts +12 -0
  114. package/dist/esm/utils/index.d.ts.map +1 -0
  115. package/dist/esm/utils/index.js +11 -0
  116. package/dist/esm/utils/index.js.map +1 -0
  117. package/dist/esm/utils/rate-limiter.d.ts +40 -0
  118. package/dist/esm/utils/rate-limiter.d.ts.map +1 -0
  119. package/dist/esm/utils/rate-limiter.js +82 -0
  120. package/dist/esm/utils/rate-limiter.js.map +1 -0
  121. package/package.json +90 -52
  122. package/src/config/index.ts +17 -0
  123. package/src/drivers/azure.driver.ts +434 -0
  124. package/src/drivers/base.driver.ts +436 -0
  125. package/src/drivers/gcs.driver.ts +366 -0
  126. package/src/drivers/index.ts +15 -0
  127. package/src/drivers/local.driver.ts +626 -0
  128. package/src/drivers/s3.driver.ts +459 -0
  129. package/src/factory/driver.factory.ts +101 -0
  130. package/src/index.ts +72 -0
  131. package/src/storage-manager.ts +801 -0
  132. package/src/types/storage.types.ts +561 -0
  133. package/src/utils/config.utils.ts +229 -0
  134. package/src/utils/file.utils.ts +536 -0
  135. package/src/utils/index.ts +35 -0
  136. package/src/utils/rate-limiter.ts +94 -0
  137. package/dist/drivers/azure.driver.d.ts +0 -88
  138. package/dist/drivers/azure.driver.d.ts.map +0 -1
  139. package/dist/drivers/azure.driver.js +0 -391
  140. package/dist/drivers/azure.driver.js.map +0 -1
  141. package/dist/drivers/base.driver.d.ts +0 -170
  142. package/dist/drivers/base.driver.d.ts.map +0 -1
  143. package/dist/drivers/base.driver.js +0 -347
  144. package/dist/drivers/base.driver.js.map +0 -1
  145. package/dist/drivers/gcs.driver.d.ts.map +0 -1
  146. package/dist/drivers/gcs.driver.js +0 -354
  147. package/dist/drivers/gcs.driver.js.map +0 -1
  148. package/dist/drivers/local.driver.d.ts +0 -107
  149. package/dist/drivers/local.driver.d.ts.map +0 -1
  150. package/dist/drivers/local.driver.js +0 -621
  151. package/dist/drivers/local.driver.js.map +0 -1
  152. package/dist/drivers/s3.driver.d.ts.map +0 -1
  153. package/dist/drivers/s3.driver.js +0 -387
  154. package/dist/drivers/s3.driver.js.map +0 -1
  155. package/dist/factory/driver.factory.d.ts +0 -62
  156. package/dist/factory/driver.factory.d.ts.map +0 -1
  157. package/dist/factory/driver.factory.js +0 -177
  158. package/dist/factory/driver.factory.js.map +0 -1
  159. package/dist/index.d.ts +0 -30
  160. package/dist/index.d.ts.map +0 -1
  161. package/dist/index.js +0 -33
  162. package/dist/index.js.map +0 -1
  163. package/dist/storage-manager.d.ts +0 -228
  164. package/dist/storage-manager.d.ts.map +0 -1
  165. package/dist/storage-manager.js +0 -715
  166. package/dist/storage-manager.js.map +0 -1
  167. package/dist/types/storage.types.d.ts +0 -295
  168. package/dist/types/storage.types.d.ts.map +0 -1
  169. package/dist/types/storage.types.js.map +0 -1
  170. package/dist/utils/config.utils.d.ts.map +0 -1
  171. package/dist/utils/config.utils.js.map +0 -1
  172. package/dist/utils/file.utils.d.ts.map +0 -1
  173. package/dist/utils/file.utils.js +0 -278
  174. package/dist/utils/file.utils.js.map +0 -1
  175. /package/dist/{utils → cjs/utils}/config.utils.d.ts +0 -0
  176. /package/dist/{types → esm/types}/storage.types.js +0 -0
  177. /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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=storage.types.js.map
@@ -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