express-storage 1.0.0 → 1.1.3

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 (48) hide show
  1. package/README.md +519 -348
  2. package/dist/drivers/azure.driver.d.ts +88 -0
  3. package/dist/drivers/azure.driver.d.ts.map +1 -0
  4. package/dist/drivers/azure.driver.js +367 -0
  5. package/dist/drivers/azure.driver.js.map +1 -0
  6. package/dist/drivers/base.driver.d.ts +125 -24
  7. package/dist/drivers/base.driver.d.ts.map +1 -1
  8. package/dist/drivers/base.driver.js +248 -62
  9. package/dist/drivers/base.driver.js.map +1 -1
  10. package/dist/drivers/gcs.driver.d.ts +60 -13
  11. package/dist/drivers/gcs.driver.d.ts.map +1 -1
  12. package/dist/drivers/gcs.driver.js +242 -41
  13. package/dist/drivers/gcs.driver.js.map +1 -1
  14. package/dist/drivers/local.driver.d.ts +89 -12
  15. package/dist/drivers/local.driver.d.ts.map +1 -1
  16. package/dist/drivers/local.driver.js +533 -45
  17. package/dist/drivers/local.driver.js.map +1 -1
  18. package/dist/drivers/s3.driver.d.ts +64 -13
  19. package/dist/drivers/s3.driver.d.ts.map +1 -1
  20. package/dist/drivers/s3.driver.js +269 -41
  21. package/dist/drivers/s3.driver.js.map +1 -1
  22. package/dist/factory/driver.factory.d.ts +35 -29
  23. package/dist/factory/driver.factory.d.ts.map +1 -1
  24. package/dist/factory/driver.factory.js +119 -59
  25. package/dist/factory/driver.factory.js.map +1 -1
  26. package/dist/index.d.ts +23 -22
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +26 -46
  29. package/dist/index.js.map +1 -1
  30. package/dist/storage-manager.d.ts +205 -52
  31. package/dist/storage-manager.d.ts.map +1 -1
  32. package/dist/storage-manager.js +644 -73
  33. package/dist/storage-manager.js.map +1 -1
  34. package/dist/types/storage.types.d.ts +243 -18
  35. package/dist/types/storage.types.d.ts.map +1 -1
  36. package/dist/utils/config.utils.d.ts +28 -4
  37. package/dist/utils/config.utils.d.ts.map +1 -1
  38. package/dist/utils/config.utils.js +121 -47
  39. package/dist/utils/config.utils.js.map +1 -1
  40. package/dist/utils/file.utils.d.ts +111 -14
  41. package/dist/utils/file.utils.d.ts.map +1 -1
  42. package/dist/utils/file.utils.js +215 -32
  43. package/dist/utils/file.utils.js.map +1 -1
  44. package/package.json +51 -27
  45. package/dist/drivers/oci.driver.d.ts +0 -37
  46. package/dist/drivers/oci.driver.d.ts.map +0 -1
  47. package/dist/drivers/oci.driver.js +0 -84
  48. package/dist/drivers/oci.driver.js.map +0 -1
@@ -0,0 +1,88 @@
1
+ import { ContainerClient } from '@azure/storage-blob';
2
+ import { BaseStorageDriver } from './base.driver.js';
3
+ import { FileUploadResult, PresignedUrlResult, StorageConfig, BlobValidationOptions, BlobValidationResult, ListFilesResult, UploadOptions } from '../types/storage.types.js';
4
+ /**
5
+ * AzureStorageDriver - Handles file operations with Azure Blob Storage.
6
+ *
7
+ * Supports three authentication methods:
8
+ * 1. Connection string (simplest — recommended for getting started)
9
+ * 2. Account name + Account key (more control)
10
+ * 3. Managed Identity (when running on Azure — no secrets needed!)
11
+ *
12
+ * Important: SAS URL generation requires an account key.
13
+ * Managed Identity works great for direct uploads but can't create presigned URLs.
14
+ */
15
+ export declare class AzureStorageDriver extends BaseStorageDriver {
16
+ private blobServiceClient;
17
+ protected containerClient: ContainerClient;
18
+ private containerName;
19
+ protected accountName: string;
20
+ protected accountKey?: string;
21
+ constructor(config: StorageConfig);
22
+ /**
23
+ * Uploads a file directly to Azure Blob Storage.
24
+ * Handles both memory and disk storage from Multer.
25
+ *
26
+ * For large files (>100MB), uses streaming upload to reduce
27
+ * memory usage and improve reliability.
28
+ */
29
+ upload(file: Express.Multer.File, options?: UploadOptions): Promise<FileUploadResult>;
30
+ /**
31
+ * Creates a SAS URL for uploading directly to Azure.
32
+ *
33
+ * Important: Unlike S3 and GCS, Azure SAS URLs do NOT enforce file size
34
+ * or content type. Always call validateAndConfirmUpload() after the
35
+ * client uploads to verify the file is what you expected.
36
+ */
37
+ generateUploadUrl(fileName: string, contentType?: string, fileSize?: number): Promise<PresignedUrlResult>;
38
+ /**
39
+ * Creates a SAS URL for downloading/viewing a file.
40
+ */
41
+ generateViewUrl(fileName: string): Promise<PresignedUrlResult>;
42
+ /**
43
+ * Deletes a file from Azure Blob Storage.
44
+ * Returns false if the file doesn't exist, throws on real errors.
45
+ */
46
+ delete(fileName: string): Promise<boolean>;
47
+ /**
48
+ * Validates an upload against expected values and deletes invalid files.
49
+ *
50
+ * This is CRITICAL for Azure presigned uploads because Azure doesn't
51
+ * enforce constraints at the URL level. Someone could upload a 10GB
52
+ * executable when you expected a 1MB image.
53
+ *
54
+ * Always call this after presigned uploads with your expected values.
55
+ */
56
+ validateAndConfirmUpload(reference: string, options?: BlobValidationOptions): Promise<BlobValidationResult>;
57
+ /**
58
+ * Lists files in the container with optional prefix filtering and pagination.
59
+ */
60
+ listFiles(prefix?: string, maxResults?: number, continuationToken?: string): Promise<ListFilesResult>;
61
+ }
62
+ /**
63
+ * AzurePresignedStorageDriver - Azure driver that returns SAS URLs from upload().
64
+ *
65
+ * Use this when you want clients to upload directly to Azure without
66
+ * the file passing through your server.
67
+ *
68
+ * Critical: Always call validateAndConfirmUpload() after clients upload!
69
+ * Azure doesn't enforce any constraints on SAS URLs.
70
+ */
71
+ export declare class AzurePresignedStorageDriver extends AzureStorageDriver {
72
+ constructor(config: StorageConfig);
73
+ private hasAccountKey;
74
+ /**
75
+ * Instead of uploading the file, returns a SAS URL for the client to use.
76
+ *
77
+ * The returned fileUrl is the SAS upload URL.
78
+ * After the client uploads, use validateAndConfirmUpload() to verify
79
+ * the file and get a view URL.
80
+ *
81
+ * Note: The `options` parameter (metadata, cacheControl, etc.) is NOT applied
82
+ * when using presigned uploads. These options must be set by the client when
83
+ * making the actual upload request to Azure, or configured via container settings.
84
+ * For server-side uploads with full options support, use the regular 'azure' driver.
85
+ */
86
+ upload(file: Express.Multer.File, _options?: UploadOptions): Promise<FileUploadResult>;
87
+ }
88
+ //# sourceMappingURL=azure.driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure.driver.d.ts","sourceRoot":"","sources":["../../src/drivers/azure.driver.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAIhB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,eAAe,EAAE,aAAa,EAAY,MAAM,2BAA2B,CAAC;AAEvL;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAC3C,OAAO,CAAC,aAAa,CAAS;IAC9B,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAElB,MAAM,EAAE,aAAa;IAqDjC;;;;;;OAMG;IACG,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqE3F;;;;;;OAMG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAwD/G;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoCpE;;;OAGG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBhD;;;;;;;;OAQG;IACY,wBAAwB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC;IA0DhC;;OAEG;IACG,SAAS,CACb,MAAM,CAAC,EAAE,MAAM,EACf,UAAU,GAAE,MAAa,EACzB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,eAAe,CAAC;CAyD5B;AAED;;;;;;;;GAQG;AACH,qBAAa,2BAA4B,SAAQ,kBAAkB;gBACrD,MAAM,EAAE,aAAa;IAYjC,OAAO,CAAC,aAAa;IAIrB;;;;;;;;;;;OAWG;IACY,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA2BtG"}
@@ -0,0 +1,367 @@
1
+ import { BlobServiceClient, StorageSharedKeyCredential, BlobSASPermissions, generateBlobSASQueryParameters, } from '@azure/storage-blob';
2
+ import { DefaultAzureCredential } from '@azure/identity';
3
+ import { BaseStorageDriver } from './base.driver.js';
4
+ /**
5
+ * AzureStorageDriver - Handles file operations with Azure Blob Storage.
6
+ *
7
+ * Supports three authentication methods:
8
+ * 1. Connection string (simplest — recommended for getting started)
9
+ * 2. Account name + Account key (more control)
10
+ * 3. Managed Identity (when running on Azure — no secrets needed!)
11
+ *
12
+ * Important: SAS URL generation requires an account key.
13
+ * Managed Identity works great for direct uploads but can't create presigned URLs.
14
+ */
15
+ export class AzureStorageDriver extends BaseStorageDriver {
16
+ constructor(config) {
17
+ super(config);
18
+ this.containerName = config.azureContainerName || config.bucketName || '';
19
+ if (!this.containerName) {
20
+ throw new Error('Azure container name is required. Set BUCKET_NAME environment variable or pass azureContainerName in credentials.');
21
+ }
22
+ this.accountName = '';
23
+ if (config.azureConnectionString) {
24
+ // Method 1: Connection string
25
+ this.blobServiceClient = BlobServiceClient.fromConnectionString(config.azureConnectionString);
26
+ const accountNameMatch = config.azureConnectionString.match(/AccountName=([a-z0-9]{3,24})(?:;|$)/i);
27
+ if (accountNameMatch && accountNameMatch[1]) {
28
+ this.accountName = accountNameMatch[1].toLowerCase();
29
+ }
30
+ else {
31
+ throw new Error('Could not extract AccountName from Azure connection string. ' +
32
+ 'Ensure the connection string contains "AccountName=<name>" where name is 3-24 lowercase letters/numbers.');
33
+ }
34
+ const keyMatch = config.azureConnectionString.match(/AccountKey=([A-Za-z0-9+/=]{20,})(?:;|$)/);
35
+ if (keyMatch && keyMatch[1]) {
36
+ this.accountKey = keyMatch[1];
37
+ }
38
+ }
39
+ else if (config.azureAccountName && config.azureAccountKey) {
40
+ // Method 2: Account name + key
41
+ this.accountName = config.azureAccountName;
42
+ this.accountKey = config.azureAccountKey;
43
+ const sharedKeyCredential = new StorageSharedKeyCredential(config.azureAccountName, config.azureAccountKey);
44
+ this.blobServiceClient = new BlobServiceClient(`https://${config.azureAccountName}.blob.core.windows.net`, sharedKeyCredential);
45
+ }
46
+ else if (config.azureAccountName) {
47
+ // Method 3: Managed Identity
48
+ this.accountName = config.azureAccountName;
49
+ this.blobServiceClient = new BlobServiceClient(`https://${config.azureAccountName}.blob.core.windows.net`, new DefaultAzureCredential());
50
+ }
51
+ else {
52
+ throw new Error('Azure configuration requires either AZURE_CONNECTION_STRING, AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY, or AZURE_ACCOUNT_NAME (for Managed Identity)');
53
+ }
54
+ this.containerClient = this.blobServiceClient.getContainerClient(this.containerName);
55
+ }
56
+ /**
57
+ * Uploads a file directly to Azure Blob Storage.
58
+ * Handles both memory and disk storage from Multer.
59
+ *
60
+ * For large files (>100MB), uses streaming upload to reduce
61
+ * memory usage and improve reliability.
62
+ */
63
+ async upload(file, options) {
64
+ try {
65
+ const validationErrors = this.validateFile(file);
66
+ if (validationErrors.length > 0) {
67
+ return this.createErrorResult(validationErrors.join(', '));
68
+ }
69
+ const fileName = this.generateFileName(file.originalname);
70
+ const blobPath = this.buildFilePath(fileName);
71
+ const blockBlobClient = this.containerClient.getBlockBlobClient(blobPath);
72
+ const uploadOptions = {
73
+ blobHTTPHeaders: {
74
+ blobContentType: options?.contentType || file.mimetype,
75
+ },
76
+ };
77
+ if (options?.cacheControl) {
78
+ uploadOptions.blobHTTPHeaders.blobCacheControl = options.cacheControl;
79
+ }
80
+ if (options?.contentDisposition) {
81
+ uploadOptions.blobHTTPHeaders.blobContentDisposition = options.contentDisposition;
82
+ }
83
+ if (options?.metadata) {
84
+ uploadOptions.metadata = options.metadata;
85
+ }
86
+ // Use streaming upload for large files to reduce memory usage
87
+ if (this.shouldUseStreaming(file)) {
88
+ const fileStream = this.getFileStream(file);
89
+ const streamOptions = {
90
+ blobHTTPHeaders: uploadOptions.blobHTTPHeaders,
91
+ };
92
+ if (uploadOptions.metadata) {
93
+ streamOptions.metadata = uploadOptions.metadata;
94
+ }
95
+ await blockBlobClient.uploadStream(fileStream, 4 * 1024 * 1024, // 4MB buffer size
96
+ 4, // 4 concurrent uploads
97
+ streamOptions);
98
+ }
99
+ else {
100
+ const fileContent = this.getFileContent(file);
101
+ await blockBlobClient.uploadData(fileContent, uploadOptions);
102
+ }
103
+ // Build the public URL with proper encoding
104
+ const encodedPath = blobPath.split('/').map(segment => encodeURIComponent(segment)).join('/');
105
+ const fileUrl = `https://${this.accountName}.blob.core.windows.net/${this.containerName}/${encodedPath}`;
106
+ return this.createSuccessResult(blobPath, fileUrl);
107
+ }
108
+ catch (error) {
109
+ return this.createErrorResult(error instanceof Error ? error.message : 'Failed to upload file to Azure');
110
+ }
111
+ }
112
+ /**
113
+ * Creates a SAS URL for uploading directly to Azure.
114
+ *
115
+ * Important: Unlike S3 and GCS, Azure SAS URLs do NOT enforce file size
116
+ * or content type. Always call validateAndConfirmUpload() after the
117
+ * client uploads to verify the file is what you expected.
118
+ */
119
+ async generateUploadUrl(fileName, contentType, fileSize) {
120
+ // Security: Defense-in-depth validation (StorageManager also validates)
121
+ if (fileName.includes('..') || fileName.includes('\0')) {
122
+ return this.createPresignedErrorResult('Invalid fileName: path traversal sequences are not allowed');
123
+ }
124
+ // Warn developers that fileSize is not enforced by Azure (unlike S3/GCS)
125
+ if (fileSize !== undefined && process.env['NODE_ENV'] !== 'production') {
126
+ console.warn('[express-storage] Azure SAS URLs do not enforce fileSize constraints. ' +
127
+ 'The provided fileSize (%d bytes) is recorded but not enforced at upload time. ' +
128
+ 'Always call validateAndConfirmUpload() with expectedFileSize to verify the uploaded file.', fileSize);
129
+ }
130
+ try {
131
+ if (!this.accountKey) {
132
+ return this.createPresignedErrorResult('Account key is required for generating SAS URLs. Use connection string or provide AZURE_ACCOUNT_KEY.');
133
+ }
134
+ const blockBlobClient = this.containerClient.getBlockBlobClient(fileName);
135
+ const expiresOn = new Date(Date.now() + (this.getPresignedUrlExpiry() * 1000));
136
+ const resolvedContentType = contentType || 'application/octet-stream';
137
+ const sasOptions = {
138
+ containerName: this.containerName,
139
+ blobName: fileName,
140
+ permissions: BlobSASPermissions.parse('cw'),
141
+ expiresOn,
142
+ contentType: resolvedContentType,
143
+ };
144
+ const sasToken = generateBlobSASQueryParameters(sasOptions, new StorageSharedKeyCredential(this.accountName, this.accountKey)).toString();
145
+ const uploadUrl = `${blockBlobClient.url}?${sasToken}`;
146
+ return this.createPresignedSuccessResult(uploadUrl);
147
+ }
148
+ catch (error) {
149
+ return this.createPresignedErrorResult(error instanceof Error ? error.message : 'Failed to generate upload URL');
150
+ }
151
+ }
152
+ /**
153
+ * Creates a SAS URL for downloading/viewing a file.
154
+ */
155
+ async generateViewUrl(fileName) {
156
+ // Security: Defense-in-depth validation
157
+ if (fileName.includes('..') || fileName.includes('\0')) {
158
+ return this.createPresignedErrorResult('Invalid fileName: path traversal sequences are not allowed');
159
+ }
160
+ try {
161
+ if (!this.accountKey) {
162
+ return this.createPresignedErrorResult('Account key is required for generating SAS URLs. Use connection string or provide AZURE_ACCOUNT_KEY.');
163
+ }
164
+ const blockBlobClient = this.containerClient.getBlockBlobClient(fileName);
165
+ const expiresOn = new Date(Date.now() + (this.getPresignedUrlExpiry() * 1000));
166
+ const sasToken = generateBlobSASQueryParameters({
167
+ containerName: this.containerName,
168
+ blobName: fileName,
169
+ permissions: BlobSASPermissions.parse('r'),
170
+ expiresOn,
171
+ }, new StorageSharedKeyCredential(this.accountName, this.accountKey)).toString();
172
+ const viewUrl = `${blockBlobClient.url}?${sasToken}`;
173
+ return this.createPresignedSuccessResult(undefined, viewUrl);
174
+ }
175
+ catch (error) {
176
+ return this.createPresignedErrorResult(error instanceof Error ? error.message : 'Failed to generate view URL');
177
+ }
178
+ }
179
+ /**
180
+ * Deletes a file from Azure Blob Storage.
181
+ * Returns false if the file doesn't exist, throws on real errors.
182
+ */
183
+ async delete(fileName) {
184
+ // Security: Defense-in-depth validation
185
+ if (fileName.includes('..') || fileName.includes('\0')) {
186
+ return false;
187
+ }
188
+ const blockBlobClient = this.containerClient.getBlockBlobClient(fileName);
189
+ const exists = await blockBlobClient.exists();
190
+ if (!exists) {
191
+ return false;
192
+ }
193
+ await blockBlobClient.delete();
194
+ return true;
195
+ }
196
+ /**
197
+ * Validates an upload against expected values and deletes invalid files.
198
+ *
199
+ * This is CRITICAL for Azure presigned uploads because Azure doesn't
200
+ * enforce constraints at the URL level. Someone could upload a 10GB
201
+ * executable when you expected a 1MB image.
202
+ *
203
+ * Always call this after presigned uploads with your expected values.
204
+ */
205
+ async validateAndConfirmUpload(reference, options) {
206
+ const deleteOnFailure = options?.deleteOnFailure !== false;
207
+ try {
208
+ const blockBlobClient = this.containerClient.getBlockBlobClient(reference);
209
+ const properties = await blockBlobClient.getProperties();
210
+ const actualContentType = properties.contentType;
211
+ const actualFileSize = properties.contentLength;
212
+ // Validate content type if expected
213
+ if (options?.expectedContentType && actualContentType !== options.expectedContentType) {
214
+ if (deleteOnFailure) {
215
+ await this.delete(reference);
216
+ }
217
+ const errorResult = {
218
+ success: false,
219
+ error: `Content type mismatch: expected '${options.expectedContentType}', got '${actualContentType}'${deleteOnFailure ? ' (file deleted)' : ' (file kept for inspection)'}`,
220
+ };
221
+ if (actualContentType)
222
+ errorResult.actualContentType = actualContentType;
223
+ if (actualFileSize !== undefined)
224
+ errorResult.actualFileSize = actualFileSize;
225
+ return errorResult;
226
+ }
227
+ // Validate file size if expected
228
+ if (options?.expectedFileSize !== undefined && actualFileSize !== options.expectedFileSize) {
229
+ if (deleteOnFailure) {
230
+ await this.delete(reference);
231
+ }
232
+ const errorResult = {
233
+ success: false,
234
+ error: `File size mismatch: expected ${options.expectedFileSize} bytes, got ${actualFileSize} bytes${deleteOnFailure ? ' (file deleted)' : ' (file kept for inspection)'}`,
235
+ };
236
+ if (actualContentType)
237
+ errorResult.actualContentType = actualContentType;
238
+ if (actualFileSize !== undefined)
239
+ errorResult.actualFileSize = actualFileSize;
240
+ return errorResult;
241
+ }
242
+ const viewResult = await this.generateViewUrl(reference);
243
+ const successResult = {
244
+ success: true,
245
+ reference,
246
+ expiresIn: this.getPresignedUrlExpiry(),
247
+ };
248
+ if (viewResult.viewUrl)
249
+ successResult.viewUrl = viewResult.viewUrl;
250
+ if (actualContentType)
251
+ successResult.actualContentType = actualContentType;
252
+ if (actualFileSize !== undefined)
253
+ successResult.actualFileSize = actualFileSize;
254
+ return successResult;
255
+ }
256
+ catch (error) {
257
+ return {
258
+ success: false,
259
+ error: error instanceof Error ? error.message : 'Failed to validate upload',
260
+ };
261
+ }
262
+ }
263
+ /**
264
+ * Lists files in the container with optional prefix filtering and pagination.
265
+ */
266
+ async listFiles(prefix, maxResults = 1000, continuationToken) {
267
+ try {
268
+ const validatedMaxResults = Math.floor(Math.max(1, Math.min(Number.isNaN(maxResults) ? 1000 : maxResults, 1000)));
269
+ const files = [];
270
+ let nextToken;
271
+ const listOptions = {};
272
+ if (prefix)
273
+ listOptions.prefix = prefix;
274
+ const pageOptions = {
275
+ maxPageSize: validatedMaxResults,
276
+ };
277
+ if (continuationToken)
278
+ pageOptions.continuationToken = continuationToken;
279
+ const iterator = this.containerClient.listBlobsFlat(listOptions)
280
+ .byPage(pageOptions);
281
+ const page = await iterator.next();
282
+ if (!page.done && page.value) {
283
+ for (const blob of page.value.segment.blobItems) {
284
+ const fileInfo = { name: blob.name };
285
+ if (blob.properties.contentLength !== undefined) {
286
+ fileInfo.size = blob.properties.contentLength;
287
+ }
288
+ if (blob.properties.contentType) {
289
+ fileInfo.contentType = blob.properties.contentType;
290
+ }
291
+ if (blob.properties.lastModified) {
292
+ fileInfo.lastModified = blob.properties.lastModified;
293
+ }
294
+ files.push(fileInfo);
295
+ }
296
+ nextToken = page.value.continuationToken;
297
+ }
298
+ const result = {
299
+ success: true,
300
+ files,
301
+ };
302
+ if (nextToken) {
303
+ result.nextToken = nextToken;
304
+ }
305
+ return result;
306
+ }
307
+ catch (error) {
308
+ return {
309
+ success: false,
310
+ error: error instanceof Error ? error.message : 'Failed to list files',
311
+ };
312
+ }
313
+ }
314
+ }
315
+ /**
316
+ * AzurePresignedStorageDriver - Azure driver that returns SAS URLs from upload().
317
+ *
318
+ * Use this when you want clients to upload directly to Azure without
319
+ * the file passing through your server.
320
+ *
321
+ * Critical: Always call validateAndConfirmUpload() after clients upload!
322
+ * Azure doesn't enforce any constraints on SAS URLs.
323
+ */
324
+ export class AzurePresignedStorageDriver extends AzureStorageDriver {
325
+ constructor(config) {
326
+ super(config);
327
+ if (!this.hasAccountKey()) {
328
+ throw new Error('AzurePresignedStorageDriver requires an account key for SAS URL generation. ' +
329
+ 'Use AZURE_CONNECTION_STRING or provide both AZURE_ACCOUNT_NAME and AZURE_ACCOUNT_KEY. ' +
330
+ 'Managed Identity cannot be used with presigned URLs - use the regular "azure" driver instead.');
331
+ }
332
+ }
333
+ hasAccountKey() {
334
+ return this.accountKey !== undefined;
335
+ }
336
+ /**
337
+ * Instead of uploading the file, returns a SAS URL for the client to use.
338
+ *
339
+ * The returned fileUrl is the SAS upload URL.
340
+ * After the client uploads, use validateAndConfirmUpload() to verify
341
+ * the file and get a view URL.
342
+ *
343
+ * Note: The `options` parameter (metadata, cacheControl, etc.) is NOT applied
344
+ * when using presigned uploads. These options must be set by the client when
345
+ * making the actual upload request to Azure, or configured via container settings.
346
+ * For server-side uploads with full options support, use the regular 'azure' driver.
347
+ */
348
+ async upload(file, _options) {
349
+ try {
350
+ const validationErrors = this.validateFile(file);
351
+ if (validationErrors.length > 0) {
352
+ return this.createErrorResult(validationErrors.join(', '));
353
+ }
354
+ const fileName = this.generateFileName(file.originalname);
355
+ const filePath = this.buildFilePath(fileName);
356
+ const presignedResult = await this.generateUploadUrl(filePath, file.mimetype, file.size);
357
+ if (!presignedResult.success) {
358
+ return this.createErrorResult(presignedResult.error || 'Failed to generate presigned URL');
359
+ }
360
+ return this.createSuccessResult(filePath, presignedResult.uploadUrl);
361
+ }
362
+ catch (error) {
363
+ return this.createErrorResult(error instanceof Error ? error.message : 'Failed to generate presigned URL');
364
+ }
365
+ }
366
+ }
367
+ //# 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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"}