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,390 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AzureStorageDriver = void 0;
37
+ const base_driver_js_1 = require("./base.driver.js");
38
+ const file_utils_js_1 = require("../utils/file.utils.js");
39
+ // Lazy SDK loaders — modules are imported on first use, not at import time.
40
+ let _azureBlobMod;
41
+ function loadAzureBlobSDK() {
42
+ if (!_azureBlobMod) {
43
+ _azureBlobMod = Promise.resolve().then(() => __importStar(require('@azure/storage-blob'))).catch(() => {
44
+ _azureBlobMod = undefined;
45
+ throw new Error('@azure/storage-blob is required for Azure storage.\n' +
46
+ 'Install: npm install @azure/storage-blob @azure/identity');
47
+ });
48
+ }
49
+ return _azureBlobMod;
50
+ }
51
+ let _azureIdentityMod;
52
+ function loadAzureIdentity() {
53
+ if (!_azureIdentityMod) {
54
+ _azureIdentityMod = Promise.resolve().then(() => __importStar(require('@azure/identity'))).catch(() => {
55
+ _azureIdentityMod = undefined;
56
+ throw new Error('@azure/identity is required for Azure Managed Identity authentication.\n' +
57
+ 'Install: npm install @azure/identity');
58
+ });
59
+ }
60
+ return _azureIdentityMod;
61
+ }
62
+ /**
63
+ * AzureStorageDriver - Handles file operations with Azure Blob Storage.
64
+ *
65
+ * Supports three authentication methods:
66
+ * 1. Connection string (simplest — recommended for getting started)
67
+ * 2. Account name + Account key (more control)
68
+ * 3. Managed Identity (when running on Azure — no secrets needed!)
69
+ *
70
+ * Important: SAS URL generation requires an account key.
71
+ * Managed Identity works great for direct uploads but can't create presigned URLs.
72
+ *
73
+ * When driver is 'azure-presigned', upload() returns SAS URLs instead of
74
+ * uploading directly. Always call validateAndConfirmUpload() after client
75
+ * uploads — Azure doesn't enforce constraints on SAS URLs.
76
+ *
77
+ * Required packages: @azure/storage-blob, @azure/identity
78
+ */
79
+ class AzureStorageDriver extends base_driver_js_1.BaseStorageDriver {
80
+ _blobServiceClient;
81
+ _containerClient;
82
+ containerName;
83
+ accountName;
84
+ accountKey;
85
+ constructor(config) {
86
+ super(config);
87
+ this.containerName = config.azureContainerName || config.bucketName || '';
88
+ if (!this.containerName) {
89
+ throw new Error('Azure container name is required. Set BUCKET_NAME environment variable or pass azureContainerName in credentials.');
90
+ }
91
+ this.accountName = '';
92
+ if (config.azureConnectionString) {
93
+ const accountNameMatch = config.azureConnectionString.match(/AccountName=([a-z0-9]{3,24})(?:;|$)/i);
94
+ if (accountNameMatch && accountNameMatch[1]) {
95
+ this.accountName = accountNameMatch[1].toLowerCase();
96
+ }
97
+ else {
98
+ throw new Error('Could not extract AccountName from Azure connection string. ' +
99
+ 'Ensure the connection string contains "AccountName=<name>" where name is 3-24 lowercase letters/numbers.');
100
+ }
101
+ const keyMatch = config.azureConnectionString.match(/AccountKey=([A-Za-z0-9+/=]{20,})(?:;|$)/);
102
+ if (keyMatch && keyMatch[1]) {
103
+ this.accountKey = keyMatch[1];
104
+ }
105
+ }
106
+ else if (config.azureAccountName) {
107
+ this.accountName = config.azureAccountName;
108
+ if (config.azureAccountKey) {
109
+ this.accountKey = config.azureAccountKey;
110
+ }
111
+ }
112
+ else {
113
+ throw new Error('Azure configuration requires either AZURE_CONNECTION_STRING, AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY, or AZURE_ACCOUNT_NAME (for Managed Identity)');
114
+ }
115
+ // Presigned mode requires an account key for SAS URL generation
116
+ if (this.presignedMode && this.accountKey === undefined) {
117
+ throw new Error('Azure presigned mode requires an account key for SAS URL generation. ' +
118
+ 'Use AZURE_CONNECTION_STRING or provide both AZURE_ACCOUNT_NAME and AZURE_ACCOUNT_KEY. ' +
119
+ 'Managed Identity cannot be used with presigned URLs - use the regular "azure" driver instead.');
120
+ }
121
+ }
122
+ async ensureContainerClient() {
123
+ if (this._containerClient)
124
+ return this._containerClient;
125
+ const azureBlob = await loadAzureBlobSDK();
126
+ if (this.config.azureConnectionString) {
127
+ this._blobServiceClient = azureBlob.BlobServiceClient.fromConnectionString(this.config.azureConnectionString);
128
+ }
129
+ else if (this.config.azureAccountName && this.config.azureAccountKey) {
130
+ const sharedKeyCredential = new azureBlob.StorageSharedKeyCredential(this.config.azureAccountName, this.config.azureAccountKey);
131
+ this._blobServiceClient = new azureBlob.BlobServiceClient(`https://${this.config.azureAccountName}.blob.core.windows.net`, sharedKeyCredential);
132
+ }
133
+ else if (this.config.azureAccountName) {
134
+ const azureIdentity = await loadAzureIdentity();
135
+ this._blobServiceClient = new azureBlob.BlobServiceClient(`https://${this.config.azureAccountName}.blob.core.windows.net`, new azureIdentity.DefaultAzureCredential());
136
+ }
137
+ else {
138
+ throw new Error('Azure configuration requires either AZURE_CONNECTION_STRING, AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY, or AZURE_ACCOUNT_NAME (for Managed Identity)');
139
+ }
140
+ this._containerClient = this._blobServiceClient.getContainerClient(this.containerName);
141
+ return this._containerClient;
142
+ }
143
+ destroy() {
144
+ this._blobServiceClient = undefined;
145
+ this._containerClient = undefined;
146
+ }
147
+ /**
148
+ * Uploads a file to Azure, or returns a SAS URL when in presigned mode.
149
+ *
150
+ * For large files (>100MB), uses streaming upload to reduce
151
+ * memory usage and improve reliability.
152
+ */
153
+ async upload(file, options) {
154
+ if (this.presignedMode) {
155
+ return this.presignedUpload(file);
156
+ }
157
+ try {
158
+ const { errors: validationErrors, resolvedSize } = await this.validateFile(file);
159
+ if (validationErrors.length > 0) {
160
+ return this.createErrorResult(validationErrors.join(', '), 'VALIDATION_FAILED');
161
+ }
162
+ const fileName = this.generateFileName(file.originalname);
163
+ const blobPath = this.buildFilePath(fileName);
164
+ const containerClient = await this.ensureContainerClient();
165
+ const blockBlobClient = containerClient.getBlockBlobClient(blobPath);
166
+ const uploadOptions = {
167
+ blobHTTPHeaders: {
168
+ blobContentType: options?.contentType || file.mimetype,
169
+ },
170
+ };
171
+ if (options?.cacheControl) {
172
+ uploadOptions.blobHTTPHeaders.blobCacheControl = options.cacheControl;
173
+ }
174
+ if (options?.contentDisposition) {
175
+ uploadOptions.blobHTTPHeaders.blobContentDisposition = options.contentDisposition;
176
+ }
177
+ if (options?.metadata) {
178
+ uploadOptions.metadata = options.metadata;
179
+ }
180
+ options?.signal?.throwIfAborted();
181
+ const abortSignal = options?.signal;
182
+ if (this.shouldUseStreaming(resolvedSize)) {
183
+ const fileStream = this.getFileStream(file);
184
+ const streamOptions = {
185
+ blobHTTPHeaders: uploadOptions.blobHTTPHeaders,
186
+ };
187
+ if (uploadOptions.metadata) {
188
+ streamOptions.metadata = uploadOptions.metadata;
189
+ }
190
+ if (abortSignal) {
191
+ streamOptions.abortSignal = abortSignal;
192
+ }
193
+ await blockBlobClient.uploadStream(fileStream, 4 * 1024 * 1024, 4, streamOptions);
194
+ }
195
+ else {
196
+ const fileContent = await this.getFileContent(file);
197
+ await blockBlobClient.uploadData(fileContent, {
198
+ ...uploadOptions,
199
+ ...(abortSignal ? { abortSignal } : {}),
200
+ });
201
+ }
202
+ const fileUrl = `https://${this.accountName}.blob.core.windows.net/${this.containerName}/${(0, file_utils_js_1.encodePathSegments)(blobPath)}`;
203
+ return this.createSuccessResult(blobPath, fileUrl);
204
+ }
205
+ catch (error) {
206
+ await this.cleanupTempFile(file);
207
+ return this.createErrorResult(error instanceof Error ? error.message : 'Failed to upload file to Azure');
208
+ }
209
+ }
210
+ /**
211
+ * Creates a SAS URL for uploading directly to Azure.
212
+ *
213
+ * Important: Unlike S3 and GCS, Azure SAS URLs do NOT enforce file size
214
+ * or content type. Always call validateAndConfirmUpload() after the
215
+ * client uploads to verify the file is what you expected.
216
+ */
217
+ async generateUploadUrl(fileName, contentType, _fileSize) {
218
+ try {
219
+ const decoded = this.decodeFileName(fileName);
220
+ const url = await this.generateSasUrl(decoded, 'cw', contentType || 'application/octet-stream');
221
+ return this.createPresignedSuccessResult(url);
222
+ }
223
+ catch (error) {
224
+ return this.createPresignedErrorResult(error instanceof Error ? error.message : 'Failed to generate upload URL');
225
+ }
226
+ }
227
+ /**
228
+ * Creates a SAS URL for downloading/viewing a file.
229
+ */
230
+ async generateViewUrl(fileName) {
231
+ try {
232
+ const decoded = this.decodeFileName(fileName);
233
+ const url = await this.generateSasUrl(decoded, 'r');
234
+ return this.createPresignedSuccessResult(undefined, url);
235
+ }
236
+ catch (error) {
237
+ return this.createPresignedErrorResult(error instanceof Error ? error.message : 'Failed to generate view URL');
238
+ }
239
+ }
240
+ /**
241
+ * Generates a SAS URL for a blob with the specified permissions.
242
+ */
243
+ async generateSasUrl(blobName, permissions, contentType) {
244
+ if (!this.accountKey) {
245
+ throw new Error('Account key is required for generating SAS URLs. Use connection string or provide AZURE_ACCOUNT_KEY.');
246
+ }
247
+ const azureBlob = await loadAzureBlobSDK();
248
+ const containerClient = await this.ensureContainerClient();
249
+ const blockBlobClient = containerClient.getBlockBlobClient(blobName);
250
+ const expiresOn = new Date(Date.now() + (this.getPresignedUrlExpiry() * 1000));
251
+ const sasOptions = {
252
+ containerName: this.containerName,
253
+ blobName,
254
+ permissions: azureBlob.BlobSASPermissions.parse(permissions),
255
+ expiresOn,
256
+ ...(contentType ? { contentType } : {}),
257
+ };
258
+ const sasToken = azureBlob.generateBlobSASQueryParameters(sasOptions, new azureBlob.StorageSharedKeyCredential(this.accountName, this.accountKey)).toString();
259
+ return `${blockBlobClient.url}?${sasToken}`;
260
+ }
261
+ /**
262
+ * Deletes a file from Azure Blob Storage.
263
+ */
264
+ async delete(fileName) {
265
+ try {
266
+ const decodedFileName = this.decodeFileName(fileName);
267
+ const containerClient = await this.ensureContainerClient();
268
+ const blockBlobClient = containerClient.getBlockBlobClient(decodedFileName);
269
+ const exists = await blockBlobClient.exists();
270
+ if (!exists) {
271
+ return { success: false, reference: fileName, error: 'File not found', code: 'FILE_NOT_FOUND' };
272
+ }
273
+ await blockBlobClient.delete();
274
+ return { success: true, reference: fileName };
275
+ }
276
+ catch (error) {
277
+ return { success: false, reference: fileName, error: error instanceof Error ? error.message : 'Failed to delete file', code: 'PROVIDER_ERROR' };
278
+ }
279
+ }
280
+ /**
281
+ * Validates an upload against expected values and deletes invalid files.
282
+ * Uses shared validation logic from BaseStorageDriver.
283
+ *
284
+ * This is CRITICAL for Azure presigned uploads because Azure doesn't
285
+ * enforce constraints at the URL level.
286
+ */
287
+ async validateAndConfirmUpload(reference, options) {
288
+ try {
289
+ const containerClient = await this.ensureContainerClient();
290
+ const blockBlobClient = containerClient.getBlockBlobClient(reference);
291
+ const properties = await blockBlobClient.getProperties();
292
+ const actual = {
293
+ contentType: properties.contentType,
294
+ fileSize: properties.contentLength,
295
+ };
296
+ const validationError = await this.checkUploadedFileMetadata(reference, actual, options);
297
+ if (validationError)
298
+ return validationError;
299
+ const viewResult = await this.generateViewUrl(reference);
300
+ return this.buildValidationSuccess(reference, viewResult.success ? viewResult.viewUrl : undefined, actual.contentType, actual.fileSize);
301
+ }
302
+ catch (error) {
303
+ return {
304
+ success: false,
305
+ error: error instanceof Error ? error.message : 'Failed to validate upload',
306
+ code: 'PROVIDER_ERROR',
307
+ };
308
+ }
309
+ }
310
+ /**
311
+ * Returns metadata about a file from Azure without downloading it.
312
+ */
313
+ async getMetadata(reference) {
314
+ try {
315
+ const decoded = this.decodeFileName(reference);
316
+ const containerClient = await this.ensureContainerClient();
317
+ const blockBlobClient = containerClient.getBlockBlobClient(decoded);
318
+ const exists = await blockBlobClient.exists();
319
+ if (!exists)
320
+ return null;
321
+ const properties = await blockBlobClient.getProperties();
322
+ const info = { name: reference };
323
+ if (properties.contentLength !== undefined)
324
+ info.size = properties.contentLength;
325
+ if (properties.contentType)
326
+ info.contentType = properties.contentType;
327
+ if (properties.lastModified)
328
+ info.lastModified = properties.lastModified;
329
+ return info;
330
+ }
331
+ catch {
332
+ return null;
333
+ }
334
+ }
335
+ /**
336
+ * Lists files in the container with optional prefix filtering and pagination.
337
+ */
338
+ async listFiles(prefix, maxResults = 1000, continuationToken) {
339
+ try {
340
+ const validatedMaxResults = this.validateMaxResults(maxResults);
341
+ const containerClient = await this.ensureContainerClient();
342
+ const files = [];
343
+ let nextToken;
344
+ const listOptions = {};
345
+ if (prefix)
346
+ listOptions.prefix = prefix;
347
+ const pageOptions = {
348
+ maxPageSize: validatedMaxResults,
349
+ };
350
+ if (continuationToken)
351
+ pageOptions.continuationToken = continuationToken;
352
+ const iterator = containerClient.listBlobsFlat(listOptions)
353
+ .byPage(pageOptions);
354
+ const page = await iterator.next();
355
+ if (!page.done && page.value) {
356
+ for (const blob of page.value.segment.blobItems) {
357
+ const fileInfo = { name: blob.name };
358
+ if (blob.properties.contentLength !== undefined) {
359
+ fileInfo.size = blob.properties.contentLength;
360
+ }
361
+ if (blob.properties.contentType) {
362
+ fileInfo.contentType = blob.properties.contentType;
363
+ }
364
+ if (blob.properties.lastModified) {
365
+ fileInfo.lastModified = blob.properties.lastModified;
366
+ }
367
+ files.push(fileInfo);
368
+ }
369
+ nextToken = page.value.continuationToken;
370
+ }
371
+ const result = {
372
+ success: true,
373
+ files,
374
+ };
375
+ if (nextToken) {
376
+ result.nextToken = nextToken;
377
+ }
378
+ return result;
379
+ }
380
+ catch (error) {
381
+ return {
382
+ success: false,
383
+ error: error instanceof Error ? error.message : 'Failed to list files',
384
+ code: 'PROVIDER_ERROR',
385
+ };
386
+ }
387
+ }
388
+ }
389
+ exports.AzureStorageDriver = AzureStorageDriver;
390
+ //# sourceMappingURL=azure.driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure.driver.js","sourceRoot":"","sources":["../../../src/drivers/azure.driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import { Readable } from 'stream';
2
+ import { IStorageDriver, FileUploadResult, PresignedUrlResult, PresignedUrlSuccess, StorageConfig, BlobValidationOptions, BlobValidationResult, BlobValidationSuccess, BlobValidationError, ListFilesResult, UploadOptions, DeleteResult, StorageErrorCode, FileInfo } from '../types/storage.types.js';
3
+ /**
4
+ * BaseStorageDriver - The foundation that all storage drivers build upon.
5
+ *
6
+ * This abstract class provides common functionality that every driver needs:
7
+ * filename generation, file validation, content reading, and result formatting.
8
+ *
9
+ * If you're building a custom driver, extend this class and implement the
10
+ * abstract methods. You'll get all the helper methods for free.
11
+ *
12
+ * **Security validation contract:**
13
+ * - **StorageManager** (layer 1): validates raw user input at the public API
14
+ * boundary — path traversal, MIME type format, file size limits.
15
+ * - **Driver** (layer 2): decodes URL-encoded filenames via `decodeFileName()`
16
+ * and rejects traversal/encoding attacks. This ensures safety when drivers
17
+ * are used directly without StorageManager.
18
+ * - **Local driver internals** (layer 3): containment checks (`path.resolve`
19
+ * stays within `basePath`), symlink rejection, file-type verification.
20
+ * These are filesystem-specific concerns, not input validation.
21
+ */
22
+ export declare abstract class BaseStorageDriver implements IStorageDriver {
23
+ protected readonly config: StorageConfig;
24
+ protected readonly presignedMode: boolean;
25
+ constructor(config: StorageConfig);
26
+ /**
27
+ * Builds the full storage path by combining the bucket path with the filename.
28
+ * For example: 'uploads' + 'photo.jpg' = 'uploads/photo.jpg'
29
+ */
30
+ protected buildFilePath(fileName: string): string;
31
+ /**
32
+ * Uploads a single file. Each driver implements this differently.
33
+ * When presignedMode is true, returns a presigned URL instead of uploading directly.
34
+ */
35
+ abstract upload(file: Express.Multer.File, options?: UploadOptions): Promise<FileUploadResult>;
36
+ abstract generateUploadUrl(fileName: string, contentType?: string, fileSize?: number): Promise<PresignedUrlResult>;
37
+ abstract generateViewUrl(fileName: string): Promise<PresignedUrlResult>;
38
+ abstract delete(fileName: string): Promise<DeleteResult>;
39
+ abstract listFiles(prefix?: string, maxResults?: number, continuationToken?: string): Promise<ListFilesResult>;
40
+ abstract getMetadata(reference: string): Promise<FileInfo | null>;
41
+ /**
42
+ * Releases SDK clients and internal resources. Override in drivers that
43
+ * hold connection pools (S3Client, GCS Storage, Azure BlobServiceClient).
44
+ * Default implementation is a no-op.
45
+ */
46
+ destroy(): void;
47
+ /**
48
+ * Creates a unique filename that won't collide with existing files.
49
+ */
50
+ protected generateFileName(originalName: string): string;
51
+ protected createSuccessResult(reference: string, fileUrl: string): FileUploadResult;
52
+ protected createErrorResult(error: string, code?: StorageErrorCode): FileUploadResult;
53
+ protected createPresignedSuccessResult(uploadUrl?: string, viewUrl?: string): PresignedUrlSuccess;
54
+ protected createPresignedErrorResult(error: string, code?: StorageErrorCode): PresignedUrlResult;
55
+ /**
56
+ * Validates a file before upload.
57
+ *
58
+ * Checks: missing file, no name, no MIME type, empty content, and
59
+ * maxFileSize from config (enforced here so direct driver usage is safe).
60
+ *
61
+ * Works with both Multer memory storage (file.buffer) and disk storage (file.path).
62
+ */
63
+ protected validateFile(file: Express.Multer.File): Promise<{
64
+ errors: string[];
65
+ resolvedSize: number;
66
+ }>;
67
+ /**
68
+ * Reads the file content, whether it's in memory or on disk.
69
+ *
70
+ * @warning **MEMORY IMPLICATIONS**: Loads the ENTIRE file into memory.
71
+ * ALWAYS call `shouldUseStreaming(file)` first and use `getFileStream()`
72
+ * for files larger than 100MB.
73
+ */
74
+ protected getFileContent(file: Express.Multer.File): Promise<Buffer>;
75
+ /**
76
+ * Returns a readable stream for the file content.
77
+ * Use this instead of getFileContent() for large files (>100MB).
78
+ */
79
+ protected getFileStream(file: Express.Multer.File): Readable;
80
+ /**
81
+ * Determines if a file should use streaming based on its size.
82
+ * Files larger than 100MB benefit from streaming to reduce memory usage.
83
+ */
84
+ protected shouldUseStreaming(fileSize: number): boolean;
85
+ /**
86
+ * Gets the file size, reading from disk if necessary.
87
+ */
88
+ protected getFileSize(file: Express.Multer.File): Promise<number>;
89
+ /**
90
+ * Cleans up a Multer disk storage temp file if it exists.
91
+ * Call this in upload error paths to prevent temp file leaks.
92
+ */
93
+ protected cleanupTempFile(file: Express.Multer.File): Promise<void>;
94
+ /**
95
+ * Returns how long presigned URLs should be valid (in seconds).
96
+ * Clamped to [1, 604800] (1 second to 7 days). Default: 600 (10 minutes).
97
+ */
98
+ protected getPresignedUrlExpiry(): number;
99
+ /**
100
+ * Decodes a URL-encoded filename and checks for path traversal attacks.
101
+ * Throws on malformed encoding or traversal sequences.
102
+ */
103
+ protected decodeFileName(fileName: string): string;
104
+ /**
105
+ * Validates and clamps maxResults for list operations.
106
+ */
107
+ protected validateMaxResults(maxResults: number): number;
108
+ /**
109
+ * Shared upload logic for presigned mode.
110
+ * Validates the file, generates a unique name, and returns a presigned upload URL.
111
+ */
112
+ protected presignedUpload(file: Express.Multer.File): Promise<FileUploadResult>;
113
+ /**
114
+ * Confirms that an upload completed successfully.
115
+ *
116
+ * The default implementation just checks if the file exists.
117
+ * Azure overrides this to validate file properties since Azure
118
+ * doesn't enforce constraints at the presigned URL level.
119
+ */
120
+ validateAndConfirmUpload(reference: string, _options?: BlobValidationOptions): Promise<BlobValidationResult>;
121
+ /**
122
+ * Validates uploaded file metadata against expected values.
123
+ * Shared by cloud drivers to avoid duplicating content-type and file-size checks.
124
+ * Returns a validation error result if checks fail, null if everything passes.
125
+ */
126
+ protected checkUploadedFileMetadata(reference: string, actual: {
127
+ contentType?: string | undefined;
128
+ fileSize?: number | undefined;
129
+ }, options?: BlobValidationOptions): Promise<BlobValidationError | null>;
130
+ /**
131
+ * Builds a successful validation result with optional view URL and metadata.
132
+ */
133
+ protected buildValidationSuccess(reference: string, viewUrl?: string, actualContentType?: string, actualFileSize?: number): BlobValidationSuccess;
134
+ private buildValidationError;
135
+ }
136
+ //# sourceMappingURL=base.driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.driver.d.ts","sourceRoot":"","sources":["../../../src/drivers/base.driver.ts"],"names":[],"mappings":"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"}