@geekmidas/storage 2.0.4 → 10.0.0-alpha.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 (69) hide show
  1. package/dist/aws.cjs +159 -4
  2. package/dist/aws.cjs.map +1 -0
  3. package/dist/aws.d.cts +51 -3
  4. package/dist/aws.d.cts.map +1 -0
  5. package/dist/aws.d.mts +51 -3
  6. package/dist/aws.d.mts.map +1 -0
  7. package/dist/aws.mjs +151 -3
  8. package/dist/aws.mjs.map +1 -0
  9. package/dist/chunk-B9dir_RE.mjs +11 -0
  10. package/dist/errors-Bce0CJ11.cjs +109 -0
  11. package/dist/errors-Bce0CJ11.cjs.map +1 -0
  12. package/dist/errors-D5UnAd-X.mjs +79 -0
  13. package/dist/errors-D5UnAd-X.mjs.map +1 -0
  14. package/dist/index.cjs +39 -0
  15. package/dist/index.cjs.map +1 -0
  16. package/dist/index.d.cts +66 -2
  17. package/dist/index.d.cts.map +1 -0
  18. package/dist/index.d.mts +66 -2
  19. package/dist/index.d.mts.map +1 -0
  20. package/dist/index.mjs +32 -0
  21. package/dist/index.mjs.map +1 -0
  22. package/dist/{StorageClient-COs9SOsU.d.cts → registry-DBsAUTT3.d.cts} +27 -2
  23. package/dist/registry-DBsAUTT3.d.cts.map +1 -0
  24. package/dist/{StorageClient-DH4tP-Mf.d.mts → registry-DEqSHjx-.d.mts} +27 -2
  25. package/dist/registry-DEqSHjx-.d.mts.map +1 -0
  26. package/dist/s3Url-BfztIltX.d.cts +39 -0
  27. package/dist/s3Url-BfztIltX.d.cts.map +1 -0
  28. package/dist/s3Url-Bo32UTTA.cjs +103 -0
  29. package/dist/s3Url-Bo32UTTA.cjs.map +1 -0
  30. package/dist/s3Url-C8FGPNrG.mjs +52 -0
  31. package/dist/s3Url-C8FGPNrG.mjs.map +1 -0
  32. package/dist/s3Url-COpMIgF9.d.mts +42 -0
  33. package/dist/s3Url-COpMIgF9.d.mts.map +1 -0
  34. package/dist/s3Url.cjs +5 -0
  35. package/dist/s3Url.d.cts +2 -0
  36. package/dist/s3Url.d.mts +2 -0
  37. package/dist/s3Url.mjs +4 -0
  38. package/package.json +16 -3
  39. package/CHANGELOG.md +0 -51
  40. package/dist/AmazonStorageClient-BHpWawGD.d.mts +0 -45
  41. package/dist/AmazonStorageClient-BHpWawGD.d.mts.map +0 -1
  42. package/dist/AmazonStorageClient-BNoY2PL6.d.cts +0 -45
  43. package/dist/AmazonStorageClient-BNoY2PL6.d.cts.map +0 -1
  44. package/dist/AmazonStorageClient-BvoZepKJ.cjs +0 -161
  45. package/dist/AmazonStorageClient-BvoZepKJ.cjs.map +0 -1
  46. package/dist/AmazonStorageClient-Dz-KCJ_4.mjs +0 -127
  47. package/dist/AmazonStorageClient-Dz-KCJ_4.mjs.map +0 -1
  48. package/dist/AmazonStorageClient.cjs +0 -5
  49. package/dist/AmazonStorageClient.d.cts +0 -3
  50. package/dist/AmazonStorageClient.d.mts +0 -3
  51. package/dist/AmazonStorageClient.mjs +0 -4
  52. package/dist/StorageClient-4ADnTPnJ.mjs +0 -11
  53. package/dist/StorageClient-4ADnTPnJ.mjs.map +0 -1
  54. package/dist/StorageClient-BDRVrMJj.cjs +0 -17
  55. package/dist/StorageClient-BDRVrMJj.cjs.map +0 -1
  56. package/dist/StorageClient-COs9SOsU.d.cts.map +0 -1
  57. package/dist/StorageClient-DH4tP-Mf.d.mts.map +0 -1
  58. package/dist/StorageClient.cjs +0 -3
  59. package/dist/StorageClient.d.cts +0 -2
  60. package/dist/StorageClient.d.mts +0 -2
  61. package/dist/StorageClient.mjs +0 -3
  62. package/src/AmazonStorageClient.ts +0 -207
  63. package/src/StorageClient.ts +0 -108
  64. package/src/__tests__/AmazonStorageClient.spec.ts +0 -606
  65. package/src/__tests__/StorageClient.spec.ts +0 -98
  66. package/src/aws.ts +0 -11
  67. package/src/index.ts +0 -1
  68. package/tsconfig.json +0 -9
  69. package/tsdown.config.ts +0 -9
@@ -1,606 +0,0 @@
1
- import { S3Client } from '@aws-sdk/client-s3';
2
- import { InMemoryCache } from '@geekmidas/cache/memory';
3
- import { beforeAll, describe, expect, it } from 'vitest';
4
- import {
5
- AmazonCannedAccessControlList,
6
- AmazonStorageClient,
7
- } from '../AmazonStorageClient';
8
- import { StorageProvider } from '../StorageClient';
9
-
10
- describe('AmazonStorageClient Integration Tests', () => {
11
- let client: AmazonStorageClient;
12
- const testBucket = 'geekmidas';
13
- const testKey = 'test-files/test.txt';
14
- const testContent = 'Hello, World!';
15
- const testContentType = 'text/plain';
16
-
17
- beforeAll(async () => {
18
- // Create storage client pointing to MinIO
19
- client = AmazonStorageClient.create({
20
- bucket: testBucket,
21
- region: 'us-east-1',
22
- accessKeyId: 'geekmidas',
23
- secretAccessKey: 'geekmidas',
24
- endpoint: 'http://localhost:9000',
25
- acl: AmazonCannedAccessControlList.PublicRead,
26
- forcePathStyle: true,
27
- });
28
-
29
- // Wait for MinIO to be ready
30
- await new Promise((resolve) => setTimeout(resolve, 2000));
31
- });
32
-
33
- describe('provider property', () => {
34
- it('should return AWS S3 provider', () => {
35
- expect(client.provider).toBe(StorageProvider.AWSS3);
36
- });
37
- });
38
-
39
- describe('upload and download workflow', () => {
40
- it.skip('should upload a file directly and generate download URL', async () => {
41
- // Upload file directly
42
- await client.upload(testKey, testContent, testContentType);
43
-
44
- // Generate download URL
45
- const downloadUrl = await client.getDownloadURL({ path: testKey });
46
-
47
- expect(downloadUrl).toMatch(
48
- /^http:\/\/localhost:9000\/geekmidas\/test-files\/test\.txt/,
49
- );
50
- expect(downloadUrl).toContain('X-Amz-Algorithm=AWS4-HMAC-SHA256');
51
- expect(downloadUrl).toContain('X-Amz-Credential=');
52
- expect(downloadUrl).toContain('X-Amz-Date=');
53
- expect(downloadUrl).toContain('X-Amz-SignedHeaders=');
54
- expect(downloadUrl).toContain('X-Amz-Signature=');
55
-
56
- // Verify file can be downloaded
57
- const response = await fetch(downloadUrl);
58
- expect(response.ok).toBe(true);
59
-
60
- const downloadedContent = await response.text();
61
- expect(downloadedContent).toBe(testContent);
62
- });
63
-
64
- it('should upload a file with filename and generate download URL with content disposition', async () => {
65
- const keyWithName = 'test-files/named-file.txt';
66
- const fileName = 'my-document.txt';
67
-
68
- await client.upload(keyWithName, testContent, testContentType);
69
-
70
- const downloadUrl = await client.getDownloadURL({
71
- path: keyWithName,
72
- name: fileName,
73
- });
74
-
75
- expect(downloadUrl).toContain(
76
- 'response-content-disposition=attachment%3B%20filename%3Dmy-document.txt',
77
- );
78
- });
79
-
80
- it('should generate download URL with inline disposition', async () => {
81
- const key = 'test-files/inline-file.txt';
82
- await client.upload(key, testContent, testContentType);
83
-
84
- const downloadUrl = await client.getDownloadURL({
85
- path: key,
86
- disposition: 'inline',
87
- });
88
-
89
- expect(downloadUrl).toContain('response-content-disposition=inline');
90
- });
91
-
92
- it('should generate download URL with inline disposition and filename', async () => {
93
- const key = 'test-files/inline-named.txt';
94
- await client.upload(key, testContent, testContentType);
95
-
96
- const downloadUrl = await client.getDownloadURL({
97
- path: key,
98
- name: 'preview.txt',
99
- disposition: 'inline',
100
- });
101
-
102
- expect(downloadUrl).toContain(
103
- 'response-content-disposition=inline%3B%20filename%3Dpreview.txt',
104
- );
105
- });
106
-
107
- it('should generate download URL with response content type override', async () => {
108
- const key = 'test-files/content-type-override.bin';
109
- await client.upload(key, testContent, 'application/octet-stream');
110
-
111
- const downloadUrl = await client.getDownloadURL({
112
- path: key,
113
- responseContentType: 'application/pdf',
114
- disposition: 'inline',
115
- });
116
-
117
- expect(downloadUrl).toContain('response-content-type=application%2Fpdf');
118
- });
119
-
120
- it('should default to attachment disposition when name is set', async () => {
121
- const key = 'test-files/default-disposition.txt';
122
- await client.upload(key, testContent, testContentType);
123
-
124
- const downloadUrl = await client.getDownloadURL({
125
- path: key,
126
- name: 'download.txt',
127
- });
128
-
129
- expect(downloadUrl).toContain(
130
- 'response-content-disposition=attachment%3B%20filename%3Ddownload.txt',
131
- );
132
- });
133
-
134
- it('should handle binary data upload', async () => {
135
- const binaryKey = 'test-files/binary.bin';
136
- const binaryData = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]); // "Hello" in bytes
137
-
138
- await client.upload(binaryKey, binaryData, 'application/octet-stream');
139
-
140
- const downloadUrl = await client.getDownloadURL({ path: binaryKey });
141
- const response = await fetch(downloadUrl);
142
- const downloadedBuffer = await response.arrayBuffer();
143
-
144
- expect(new Uint8Array(downloadedBuffer)).toEqual(
145
- new Uint8Array(binaryData),
146
- );
147
- });
148
- });
149
-
150
- describe('presigned upload URLs', () => {
151
- it('should generate presigned PUT upload URL', async () => {
152
- const uploadKey = 'test-files/presigned-upload.txt';
153
- const uploadUrl = await client.getUploadURL({
154
- path: uploadKey,
155
- contentType: testContentType,
156
- contentLength: testContent.length,
157
- });
158
-
159
- expect(uploadUrl).toMatch(
160
- /^http:\/\/localhost:9000\/geekmidas\/test-files\/presigned-upload\.txt/,
161
- );
162
- expect(uploadUrl).toContain('X-Amz-Algorithm=AWS4-HMAC-SHA256');
163
-
164
- // Test actual upload using the presigned URL
165
- const uploadResponse = await fetch(uploadUrl, {
166
- method: 'PUT',
167
- headers: {
168
- 'Content-Type': testContentType,
169
- 'Content-Length': testContent.length.toString(),
170
- },
171
- body: testContent,
172
- });
173
-
174
- expect(uploadResponse.ok).toBe(true);
175
-
176
- // Verify file was uploaded
177
- const downloadUrl = await client.getDownloadURL({ path: uploadKey });
178
- const downloadResponse = await fetch(downloadUrl);
179
- const downloadedContent = await downloadResponse.text();
180
- expect(downloadedContent).toBe(testContent);
181
- });
182
-
183
- it('should generate presigned POST upload with form fields', async () => {
184
- const uploadKey = 'test-files/presigned-post.txt';
185
- const uploadData = await client.getUpload({
186
- path: uploadKey,
187
- contentType: testContentType,
188
- contentLength: testContent.length,
189
- });
190
-
191
- expect(uploadData.url).toBe('http://localhost:9000/geekmidas');
192
- expect(uploadData.fields).toContainEqual({
193
- key: 'key',
194
- value: uploadKey,
195
- });
196
- expect(uploadData.fields).toContainEqual({
197
- key: 'acl',
198
- value: 'public-read',
199
- });
200
-
201
- // Test actual upload using the presigned POST
202
- const formData = new FormData();
203
- uploadData.fields.forEach(({ key, value }) => {
204
- formData.append(key, value);
205
- });
206
- formData.append(
207
- 'file',
208
- new Blob([testContent], { type: testContentType }),
209
- );
210
-
211
- const uploadResponse = await fetch(uploadData.url, {
212
- method: 'POST',
213
- body: formData,
214
- });
215
-
216
- expect(uploadResponse.ok).toBe(true);
217
-
218
- // Verify file was uploaded
219
- const downloadUrl = await client.getDownloadURL({ path: uploadKey });
220
- const downloadResponse = await fetch(downloadUrl);
221
- const downloadedContent = await downloadResponse.blob();
222
- expect(downloadedContent).toEqual(
223
- new Blob([testContent], { type: testContentType }),
224
- );
225
- });
226
- });
227
-
228
- describe('versioning', () => {
229
- it('should handle file versions', async () => {
230
- const versionKey = 'test-files/versioned.txt';
231
- const content1 = 'Version 1';
232
- const content2 = 'Version 2';
233
-
234
- // Upload first version
235
- await client.upload(versionKey, content1, testContentType);
236
-
237
- // Upload second version
238
- await client.upload(versionKey, content2, testContentType);
239
-
240
- // Get versions - MinIO might not enable versioning by default
241
- // This test verifies the method works even if versioning is not enabled
242
- const versions = await client.getVersions(versionKey);
243
- expect(Array.isArray(versions)).toBe(true);
244
-
245
- // If versioning is enabled, we should have multiple versions
246
- // If not, we should have at least the current version
247
- if (versions.length > 0) {
248
- expect(versions[0]).toHaveProperty('id');
249
- expect(versions[0]).toHaveProperty('createdAt');
250
- expect(versions[0].createdAt).toBeInstanceOf(Date);
251
- }
252
- });
253
- });
254
-
255
- describe('error handling', () => {
256
- it('should handle download URL generation for non-existent files', async () => {
257
- // This should not throw - presigned URLs can be generated for non-existent files
258
- const downloadUrl = await client.getDownloadURL({
259
- path: 'non-existent/file.txt',
260
- });
261
- expect(downloadUrl).toMatch(
262
- /^http:\/\/localhost:9000\/geekmidas\/non-existent\/file\.txt/,
263
- );
264
-
265
- // But accessing the URL should return 404
266
- const response = await fetch(downloadUrl);
267
- expect(response.status).toBe(404);
268
- });
269
- });
270
-
271
- describe('custom expiration times', () => {
272
- it('should respect custom expiration for download URLs', async () => {
273
- const key = 'test-files/expiration-test.txt';
274
- await client.upload(key, testContent, testContentType);
275
-
276
- const shortExpirationUrl = await client.getDownloadURL({ path: key }, 1); // 1 second
277
- const longExpirationUrl = await client.getDownloadURL(
278
- { path: key },
279
- 3600,
280
- ); // 1 hour
281
-
282
- expect(shortExpirationUrl).toContain('X-Amz-Expires=1');
283
- expect(longExpirationUrl).toContain('X-Amz-Expires=3600');
284
- });
285
-
286
- it('should respect custom expiration for upload URLs', async () => {
287
- const key = 'test-files/upload-expiration-test.txt';
288
-
289
- const shortExpirationUrl = await client.getUploadURL(
290
- {
291
- path: key,
292
- contentType: testContentType,
293
- contentLength: testContent.length,
294
- },
295
- 1,
296
- ); // 1 second
297
-
298
- const longExpirationUrl = await client.getUploadURL(
299
- {
300
- path: key,
301
- contentType: testContentType,
302
- contentLength: testContent.length,
303
- },
304
- 3600,
305
- ); // 1 hour
306
-
307
- expect(shortExpirationUrl).toContain('X-Amz-Expires=1');
308
- expect(longExpirationUrl).toContain('X-Amz-Expires=3600');
309
- });
310
- });
311
-
312
- describe('factory method', () => {
313
- it('should create client with minimal configuration', () => {
314
- const minimalClient = AmazonStorageClient.create({
315
- bucket: 'geekmidas',
316
- });
317
-
318
- expect(minimalClient).toBeInstanceOf(AmazonStorageClient);
319
- expect(minimalClient.provider).toBe(StorageProvider.AWSS3);
320
- });
321
-
322
- it('should create client with full configuration', () => {
323
- const fullClient = AmazonStorageClient.create({
324
- bucket: 'geekmidas',
325
- region: 'us-west-2',
326
- accessKeyId: 'test-key',
327
- secretAccessKey: 'test-secret',
328
- endpoint: 'https://custom-s3.example.com',
329
- acl: AmazonCannedAccessControlList.Private,
330
- });
331
-
332
- expect(fullClient).toBeInstanceOf(AmazonStorageClient);
333
- expect(fullClient.provider).toBe(StorageProvider.AWSS3);
334
- });
335
- });
336
-
337
- describe('different ACL configurations', () => {
338
- it('should work with different ACL settings', async () => {
339
- const privateClient = AmazonStorageClient.create({
340
- bucket: testBucket,
341
- region: 'us-east-1',
342
- accessKeyId: 'minioadmin',
343
- secretAccessKey: 'minioadmin',
344
- endpoint: 'http://localhost:9000',
345
- acl: AmazonCannedAccessControlList.Private,
346
- });
347
-
348
- const uploadData = await privateClient.getUpload({
349
- path: 'test-files/private.txt',
350
- contentType: testContentType,
351
- contentLength: testContent.length,
352
- });
353
-
354
- expect(uploadData.fields).toContainEqual({
355
- key: 'acl',
356
- value: 'private',
357
- });
358
- });
359
- });
360
-
361
- describe('S3Client integration', () => {
362
- it('should work with externally created S3Client', () => {
363
- const s3Client = new S3Client({
364
- region: 'us-east-1',
365
- credentials: {
366
- accessKeyId: 'minioadmin',
367
- secretAccessKey: 'minioadmin',
368
- },
369
- endpoint: 'http://localhost:9000',
370
- });
371
-
372
- const storageClient = new AmazonStorageClient(
373
- s3Client,
374
- testBucket,
375
- AmazonCannedAccessControlList.PublicRead,
376
- );
377
-
378
- expect(storageClient).toBeInstanceOf(AmazonStorageClient);
379
- expect(storageClient.provider).toBe(StorageProvider.AWSS3);
380
- });
381
- });
382
-
383
- describe('cache functionality', () => {
384
- it('should cache download URLs', async () => {
385
- const cache = new InMemoryCache();
386
- const clientWithCache = AmazonStorageClient.create({
387
- bucket: testBucket,
388
- region: 'us-east-1',
389
- accessKeyId: 'geekmidas',
390
- secretAccessKey: 'geekmidas',
391
- endpoint: 'http://localhost:9000',
392
- forcePathStyle: true,
393
- cache,
394
- });
395
-
396
- const key = 'test-files/cache-test.txt';
397
- await clientWithCache.upload(key, testContent, testContentType);
398
-
399
- // First call should generate and cache the URL
400
- const url1 = await clientWithCache.getDownloadURL({ path: key });
401
-
402
- // Second call should return the cached URL
403
- const url2 = await clientWithCache.getDownloadURL({ path: key });
404
-
405
- // URLs should be identical (same cached value)
406
- expect(url1).toBe(url2);
407
-
408
- // Verify the URL was cached
409
- const cacheKey = `download-url:${key}`;
410
- const cachedUrl = await cache.get(cacheKey);
411
- expect(cachedUrl).toBe(url1);
412
- });
413
-
414
- it('should respect cache expiration based on URL expiry', async () => {
415
- const cache = new InMemoryCache();
416
- const clientWithCache = AmazonStorageClient.create({
417
- bucket: testBucket,
418
- region: 'us-east-1',
419
- accessKeyId: 'geekmidas',
420
- secretAccessKey: 'geekmidas',
421
- endpoint: 'http://localhost:9000',
422
- forcePathStyle: true,
423
- cache,
424
- });
425
-
426
- const key = 'test-files/cache-expiry.txt';
427
- await clientWithCache.upload(key, testContent, testContentType);
428
-
429
- // Generate URL with short expiry that won't be cached
430
- await clientWithCache.getDownloadURL({ path: key }, 30); // 30 seconds
431
-
432
- // Check cache doesn't contain the URL (too short to cache)
433
- const cacheKey = `download-url:${key}`;
434
- const cachedShortUrl = await cache.get(cacheKey);
435
- expect(cachedShortUrl).toBeUndefined();
436
-
437
- // Generate URL with longer expiry that will be cached
438
- const longExpiryUrl = await clientWithCache.getDownloadURL(
439
- { path: key },
440
- 3600,
441
- ); // 1 hour
442
-
443
- // Check cache contains the URL
444
- const cachedLongUrl = await cache.get(cacheKey);
445
- expect(cachedLongUrl).toBe(longExpiryUrl);
446
- });
447
-
448
- it('should use cached URL when available', async () => {
449
- const cache = new InMemoryCache();
450
- const clientWithCache = AmazonStorageClient.create({
451
- bucket: testBucket,
452
- region: 'us-east-1',
453
- accessKeyId: 'geekmidas',
454
- secretAccessKey: 'geekmidas',
455
- endpoint: 'http://localhost:9000',
456
- forcePathStyle: true,
457
- cache,
458
- });
459
-
460
- const key = 'test-files/pre-cached.txt';
461
- const cachedUrl = 'https://pre-cached-url.example.com';
462
- const cacheKey = `download-url:${key}`;
463
-
464
- // Pre-populate cache
465
- await cache.set(cacheKey, cachedUrl);
466
-
467
- // Get download URL should return cached value
468
- const url = await clientWithCache.getDownloadURL({ path: key });
469
- expect(url).toBe(cachedUrl);
470
- });
471
-
472
- it('should work without cache', async () => {
473
- // Client without cache should work normally
474
- const clientNoCache = AmazonStorageClient.create({
475
- bucket: testBucket,
476
- region: 'us-east-1',
477
- accessKeyId: 'geekmidas',
478
- secretAccessKey: 'geekmidas',
479
- endpoint: 'http://localhost:9000',
480
- forcePathStyle: true,
481
- });
482
-
483
- const key = 'test-files/no-cache.txt';
484
- await clientNoCache.upload(key, testContent, testContentType);
485
-
486
- const url1 = await clientNoCache.getDownloadURL({ path: key });
487
- const url2 = await clientNoCache.getDownloadURL({ path: key });
488
-
489
- // Without cache, new URLs might be generated each time
490
- // Both should be valid URLs
491
- expect(url1).toMatch(
492
- /^http:\/\/localhost:9000\/geekmidas\/test-files\/no-cache\.txt/,
493
- );
494
- expect(url2).toMatch(
495
- /^http:\/\/localhost:9000\/geekmidas\/test-files\/no-cache\.txt/,
496
- );
497
- });
498
-
499
- it('should pass cache to constructor', () => {
500
- const cache = new InMemoryCache();
501
- const s3Client = new S3Client({
502
- region: 'us-east-1',
503
- credentials: {
504
- accessKeyId: 'geekmidas',
505
- secretAccessKey: 'geekmidas',
506
- },
507
- endpoint: 'http://localhost:9000',
508
- forcePathStyle: true,
509
- });
510
-
511
- const clientWithCache = new AmazonStorageClient(
512
- s3Client,
513
- testBucket,
514
- AmazonCannedAccessControlList.PublicRead,
515
- cache,
516
- );
517
-
518
- expect(clientWithCache.cache).toBe(cache);
519
- });
520
- });
521
-
522
- describe('delete', () => {
523
- it('should delete an uploaded file', async () => {
524
- const key = 'test-files/delete-test.txt';
525
- await client.upload(key, testContent, testContentType);
526
-
527
- // Verify file exists
528
- const downloadUrl = await client.getDownloadURL({ path: key });
529
- const before = await fetch(downloadUrl);
530
- expect(before.ok).toBe(true);
531
-
532
- // Delete file
533
- await client.delete(key);
534
-
535
- // Verify file is gone
536
- const afterUrl = await client.getDownloadURL({ path: key });
537
- const after = await fetch(afterUrl);
538
- expect(after.status).toBe(404);
539
- });
540
-
541
- it('should not throw when deleting a non-existent file', async () => {
542
- await expect(
543
- client.delete('non-existent/file.txt'),
544
- ).resolves.not.toThrow();
545
- });
546
- });
547
-
548
- describe('getVersionDownloadURL', () => {
549
- it('should generate version-specific download URL', async () => {
550
- const versionKey = 'test-files/version-download.txt';
551
- const versionId = 'test-version-id';
552
-
553
- // Upload a file first
554
- await client.upload(versionKey, testContent, testContentType);
555
-
556
- // Generate version-specific download URL
557
- const downloadUrl = await client.getVersionDownloadURL(
558
- { path: versionKey, name: 'versioned-file.txt' },
559
- versionId,
560
- );
561
-
562
- expect(downloadUrl).toMatch(
563
- /^http:\/\/localhost:9000\/geekmidas\/test-files\/version-download\.txt/,
564
- );
565
- expect(downloadUrl).toContain('X-Amz-Algorithm=AWS4-HMAC-SHA256');
566
- expect(downloadUrl).toContain(
567
- 'response-content-disposition=attachment%3B%20filename%3Dversioned-file.txt',
568
- );
569
- });
570
-
571
- it('should generate version URL with inline disposition', async () => {
572
- const versionKey = 'test-files/version-inline.txt';
573
- const versionId = 'test-version-id';
574
-
575
- await client.upload(versionKey, testContent, testContentType);
576
-
577
- const downloadUrl = await client.getVersionDownloadURL(
578
- { path: versionKey, name: 'inline-file.txt', disposition: 'inline' },
579
- versionId,
580
- );
581
-
582
- expect(downloadUrl).toContain(
583
- 'response-content-disposition=inline%3B%20filename%3Dinline-file.txt',
584
- );
585
- });
586
-
587
- it('should generate version URL without filename', async () => {
588
- const versionKey = 'test-files/version-no-name.txt';
589
- const versionId = 'test-version-id';
590
-
591
- // Upload a file first
592
- await client.upload(versionKey, testContent, testContentType);
593
-
594
- // Generate version-specific download URL without filename
595
- const downloadUrl = await client.getVersionDownloadURL(
596
- { path: versionKey },
597
- versionId,
598
- );
599
-
600
- expect(downloadUrl).toMatch(
601
- /^http:\/\/localhost:9000\/geekmidas\/test-files\/version-no-name\.txt/,
602
- );
603
- expect(downloadUrl).not.toContain('response-content-disposition');
604
- });
605
- });
606
- });
@@ -1,98 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { StorageProvider } from '../StorageClient';
3
-
4
- describe('StorageClient', () => {
5
- describe('StorageProvider enum', () => {
6
- it('should have correct provider values', () => {
7
- expect(StorageProvider.AWSS3).toBe('geekimdas.toolbox.storage.aws.s3');
8
- expect(StorageProvider.GCP).toBe('geekimdas.toolbox.storage.gcp');
9
- expect(StorageProvider.AZURE).toBe('geekimdas.toolbox.storage.azure');
10
- });
11
-
12
- it('should have unique provider values', () => {
13
- const values = Object.values(StorageProvider);
14
- const uniqueValues = new Set(values);
15
- expect(uniqueValues.size).toBe(values.length);
16
- });
17
- });
18
-
19
- describe('interfaces', () => {
20
- it('should define DocumentVersion interface correctly', () => {
21
- // This is a compile-time test to ensure the interface exists
22
- // and has the correct shape
23
- const version: import('../StorageClient').DocumentVersion = {
24
- id: 'test-id',
25
- createdAt: new Date(),
26
- };
27
-
28
- expect(version.id).toBe('test-id');
29
- expect(version.createdAt).toBeInstanceOf(Date);
30
- });
31
-
32
- it('should define File interface correctly', () => {
33
- const file: import('../StorageClient').File = {
34
- path: 'test/path.txt',
35
- };
36
-
37
- expect(file.path).toBe('test/path.txt');
38
- expect(file.name).toBeUndefined();
39
-
40
- const fileWithName: import('../StorageClient').File = {
41
- path: 'test/path.txt',
42
- name: 'display-name.txt',
43
- };
44
-
45
- expect(fileWithName.path).toBe('test/path.txt');
46
- expect(fileWithName.name).toBe('display-name.txt');
47
-
48
- const fileWithDisposition: import('../StorageClient').File = {
49
- path: 'test/path.txt',
50
- disposition: 'inline',
51
- responseContentType: 'application/pdf',
52
- };
53
-
54
- expect(fileWithDisposition.disposition).toBe('inline');
55
- expect(fileWithDisposition.responseContentType).toBe('application/pdf');
56
- });
57
-
58
- it('should define GetUploadParams interface correctly', () => {
59
- const params: import('../StorageClient').GetUploadParams = {
60
- path: 'test/upload.txt',
61
- contentType: 'text/plain',
62
- contentLength: 100,
63
- };
64
-
65
- expect(params.path).toBe('test/upload.txt');
66
- expect(params.contentType).toBe('text/plain');
67
- expect(params.contentLength).toBe(100);
68
- });
69
-
70
- it('should define GetUploadResponse interface correctly', () => {
71
- const response: import('../StorageClient').GetUploadResponse = {
72
- url: 'https://example.com/upload',
73
- fields: [
74
- { key: 'key', value: 'test/path.txt' },
75
- { key: 'acl', value: 'public-read' },
76
- ],
77
- };
78
-
79
- expect(response.url).toBe('https://example.com/upload');
80
- expect(response.fields).toHaveLength(2);
81
- expect(response.fields[0]).toEqual({
82
- key: 'key',
83
- value: 'test/path.txt',
84
- });
85
- expect(response.fields[1]).toEqual({ key: 'acl', value: 'public-read' });
86
- });
87
-
88
- it('should define UploadField type correctly', () => {
89
- const field: import('../StorageClient').UploadField = {
90
- key: 'test-key',
91
- value: 'test-value',
92
- };
93
-
94
- expect(field.key).toBe('test-key');
95
- expect(field.value).toBe('test-value');
96
- });
97
- });
98
- });