@scality/data-browser-library 1.0.0-preview.2

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 (176) hide show
  1. package/dist/components/Editor.d.ts +12 -0
  2. package/dist/components/Editor.js +28 -0
  3. package/dist/components/__tests__/BucketList.test.d.ts +1 -0
  4. package/dist/components/__tests__/BucketList.test.js +225 -0
  5. package/dist/components/__tests__/BucketOverview.test.d.ts +1 -0
  6. package/dist/components/__tests__/BucketOverview.test.js +479 -0
  7. package/dist/components/__tests__/BucketPolicyPage.test.d.ts +1 -0
  8. package/dist/components/__tests__/BucketPolicyPage.test.js +213 -0
  9. package/dist/components/__tests__/CreateFolderButton.test.d.ts +1 -0
  10. package/dist/components/__tests__/CreateFolderButton.test.js +147 -0
  11. package/dist/components/__tests__/DeleteBucketButton.test.d.ts +1 -0
  12. package/dist/components/__tests__/DeleteBucketButton.test.js +272 -0
  13. package/dist/components/__tests__/DeleteObjectButton.test.d.ts +1 -0
  14. package/dist/components/__tests__/DeleteObjectButton.test.js +302 -0
  15. package/dist/components/__tests__/MetadataSearch.test.d.ts +1 -0
  16. package/dist/components/__tests__/MetadataSearch.test.js +201 -0
  17. package/dist/components/__tests__/ObjectList.test.d.ts +1 -0
  18. package/dist/components/__tests__/ObjectList.test.js +283 -0
  19. package/dist/components/__tests__/UploadButton.test.d.ts +1 -0
  20. package/dist/components/__tests__/UploadButton.test.js +144 -0
  21. package/dist/components/buckets/BucketDetails.d.ts +1 -0
  22. package/dist/components/buckets/BucketDetails.js +51 -0
  23. package/dist/components/buckets/BucketList.d.ts +12 -0
  24. package/dist/components/buckets/BucketList.js +136 -0
  25. package/dist/components/buckets/BucketLocation.d.ts +3 -0
  26. package/dist/components/buckets/BucketLocation.js +16 -0
  27. package/dist/components/buckets/BucketOverview.d.ts +14 -0
  28. package/dist/components/buckets/BucketOverview.js +209 -0
  29. package/dist/components/buckets/BucketPage.d.ts +2 -0
  30. package/dist/components/buckets/BucketPage.js +47 -0
  31. package/dist/components/buckets/BucketPolicyButton.d.ts +7 -0
  32. package/dist/components/buckets/BucketPolicyButton.js +18 -0
  33. package/dist/components/buckets/BucketPolicyPage.d.ts +1 -0
  34. package/dist/components/buckets/BucketPolicyPage.js +205 -0
  35. package/dist/components/buckets/DeleteBucketButton.d.ts +8 -0
  36. package/dist/components/buckets/DeleteBucketButton.js +78 -0
  37. package/dist/components/index.d.ts +12 -0
  38. package/dist/components/index.js +13 -0
  39. package/dist/components/layouts/BrowserPageLayout.d.ts +9 -0
  40. package/dist/components/layouts/BrowserPageLayout.js +46 -0
  41. package/dist/components/objects/CreateFolderButton.d.ts +29 -0
  42. package/dist/components/objects/CreateFolderButton.js +118 -0
  43. package/dist/components/objects/DeleteObjectButton.d.ts +8 -0
  44. package/dist/components/objects/DeleteObjectButton.js +191 -0
  45. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +2 -0
  46. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +323 -0
  47. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +3 -0
  48. package/dist/components/objects/ObjectDetails/ObjectSummary.js +193 -0
  49. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +3 -0
  50. package/dist/components/objects/ObjectDetails/ObjectTags.js +300 -0
  51. package/dist/components/objects/ObjectDetails/index.d.ts +9 -0
  52. package/dist/components/objects/ObjectDetails/index.js +49 -0
  53. package/dist/components/objects/ObjectList.d.ts +40 -0
  54. package/dist/components/objects/ObjectList.js +407 -0
  55. package/dist/components/objects/ObjectPage.d.ts +1 -0
  56. package/dist/components/objects/ObjectPage.js +43 -0
  57. package/dist/components/objects/UploadButton.d.ts +34 -0
  58. package/dist/components/objects/UploadButton.js +229 -0
  59. package/dist/components/providers/DataBrowserProvider.d.ts +20 -0
  60. package/dist/components/providers/DataBrowserProvider.js +42 -0
  61. package/dist/components/search/MetadataSearch.d.ts +5 -0
  62. package/dist/components/search/MetadataSearch.js +162 -0
  63. package/dist/components/search/SearchHints.d.ts +8 -0
  64. package/dist/components/search/SearchHints.js +21 -0
  65. package/dist/components/ui/DeleteObjectModalContent.d.ts +5 -0
  66. package/dist/components/ui/DeleteObjectModalContent.js +71 -0
  67. package/dist/components/ui/Search.elements.d.ts +17 -0
  68. package/dist/components/ui/Search.elements.js +59 -0
  69. package/dist/components/ui/Table.elements.d.ts +36 -0
  70. package/dist/components/ui/Table.elements.js +87 -0
  71. package/dist/config/factory.d.ts +52 -0
  72. package/dist/config/factory.js +70 -0
  73. package/dist/config/types.d.ts +46 -0
  74. package/dist/config/types.js +0 -0
  75. package/dist/hooks/__tests__/useIsBucketEmpty.test.d.ts +1 -0
  76. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +122 -0
  77. package/dist/hooks/bucketConfiguration.d.ts +147 -0
  78. package/dist/hooks/bucketConfiguration.js +59 -0
  79. package/dist/hooks/bucketOperations.d.ts +36 -0
  80. package/dist/hooks/bucketOperations.js +12 -0
  81. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.d.ts +1 -0
  82. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +276 -0
  83. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.d.ts +1 -0
  84. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +259 -0
  85. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.d.ts +1 -0
  86. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +166 -0
  87. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.d.ts +1 -0
  88. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +200 -0
  89. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.d.ts +1 -0
  90. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +136 -0
  91. package/dist/hooks/factories/index.d.ts +18 -0
  92. package/dist/hooks/factories/index.js +5 -0
  93. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +13 -0
  94. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +76 -0
  95. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +8 -0
  96. package/dist/hooks/factories/useCreateS3LoginHook.js +22 -0
  97. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +5 -0
  98. package/dist/hooks/factories/useCreateS3MutationHook.js +50 -0
  99. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +3 -0
  100. package/dist/hooks/factories/useCreateS3QueryHook.js +30 -0
  101. package/dist/hooks/index.d.ts +8 -0
  102. package/dist/hooks/index.js +8 -0
  103. package/dist/hooks/loginOperations.d.ts +21 -0
  104. package/dist/hooks/loginOperations.js +9 -0
  105. package/dist/hooks/objectOperations.d.ts +190 -0
  106. package/dist/hooks/objectOperations.js +66 -0
  107. package/dist/hooks/presignedOperations.d.ts +73 -0
  108. package/dist/hooks/presignedOperations.js +72 -0
  109. package/dist/hooks/useIsBucketEmpty.d.ts +7 -0
  110. package/dist/hooks/useIsBucketEmpty.js +36 -0
  111. package/dist/hooks/useLoginMutation.d.ts +21 -0
  112. package/dist/hooks/useLoginMutation.js +9 -0
  113. package/dist/hooks/useS3Client.d.ts +1 -0
  114. package/dist/hooks/useS3Client.js +13 -0
  115. package/dist/index.d.ts +6 -0
  116. package/dist/index.js +6 -0
  117. package/dist/schemas/bucketPolicySchema.json +321 -0
  118. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -0
  119. package/dist/test/msw/handlers/deleteBucket.js +14 -0
  120. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -0
  121. package/dist/test/msw/handlers/getBucketAcl.js +96 -0
  122. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -0
  123. package/dist/test/msw/handlers/getBucketLocation.js +23 -0
  124. package/dist/test/msw/handlers/getBucketPolicy.d.ts +11 -0
  125. package/dist/test/msw/handlers/getBucketPolicy.js +72 -0
  126. package/dist/test/msw/handlers/headObject.d.ts +1 -0
  127. package/dist/test/msw/handlers/headObject.js +17 -0
  128. package/dist/test/msw/handlers/listBuckets.d.ts +1 -0
  129. package/dist/test/msw/handlers/listBuckets.js +24 -0
  130. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -0
  131. package/dist/test/msw/handlers/listObjectVersions.js +83 -0
  132. package/dist/test/msw/handlers/listObjects.d.ts +1 -0
  133. package/dist/test/msw/handlers/listObjects.js +66 -0
  134. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -0
  135. package/dist/test/msw/handlers/objectLegalHold.js +24 -0
  136. package/dist/test/msw/handlers/objectRetention.d.ts +1 -0
  137. package/dist/test/msw/handlers/objectRetention.js +27 -0
  138. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -0
  139. package/dist/test/msw/handlers/putBucketAcl.js +18 -0
  140. package/dist/test/msw/handlers/putObject.d.ts +1 -0
  141. package/dist/test/msw/handlers/putObject.js +16 -0
  142. package/dist/test/msw/handlers.d.ts +4 -0
  143. package/dist/test/msw/handlers.js +109 -0
  144. package/dist/test/msw/index.d.ts +2 -0
  145. package/dist/test/msw/index.js +3 -0
  146. package/dist/test/msw/server.d.ts +4 -0
  147. package/dist/test/msw/server.js +20 -0
  148. package/dist/test/msw/utils.d.ts +2 -0
  149. package/dist/test/msw/utils.js +13 -0
  150. package/dist/test/setup.d.ts +1 -0
  151. package/dist/test/setup.js +82 -0
  152. package/dist/test/testUtils.d.ts +82 -0
  153. package/dist/test/testUtils.js +236 -0
  154. package/dist/test/utils/errorHandling.test.d.ts +1 -0
  155. package/dist/test/utils/errorHandling.test.js +385 -0
  156. package/dist/types/index.d.ts +48 -0
  157. package/dist/types/index.js +0 -0
  158. package/dist/utils/deletion/index.d.ts +2 -0
  159. package/dist/utils/deletion/index.js +2 -0
  160. package/dist/utils/deletion/messages.d.ts +5 -0
  161. package/dist/utils/deletion/messages.js +29 -0
  162. package/dist/utils/deletion/types.d.ts +11 -0
  163. package/dist/utils/deletion/types.js +0 -0
  164. package/dist/utils/errorHandling.d.ts +54 -0
  165. package/dist/utils/errorHandling.js +79 -0
  166. package/dist/utils/hooks.d.ts +2 -0
  167. package/dist/utils/hooks.js +26 -0
  168. package/dist/utils/index.d.ts +2 -0
  169. package/dist/utils/index.js +2 -0
  170. package/dist/utils/proxyMiddleware.d.ts +18 -0
  171. package/dist/utils/proxyMiddleware.js +56 -0
  172. package/dist/utils/s3Client.d.ts +5 -0
  173. package/dist/utils/s3Client.js +35 -0
  174. package/dist/utils/useFeatures.d.ts +1 -0
  175. package/dist/utils/useFeatures.js +7 -0
  176. package/package.json +79 -0
@@ -0,0 +1,83 @@
1
+ import { rest } from "msw";
2
+ import { createS3ErrorXml, getS3BaseUrl } from "../utils.js";
3
+ const listObjectVersionsHandler = rest.get(`${getS3BaseUrl()}/:bucketName`, (req, res, ctx)=>{
4
+ const { bucketName } = req.params;
5
+ const url = new URL(req.url);
6
+ if (!url.searchParams.has("versions")) return;
7
+ const prefix = url.searchParams.get("prefix") || "";
8
+ const delimiter = url.searchParams.get("delimiter") || "";
9
+ const maxKeys = parseInt(url.searchParams.get("max-keys") || "1000", 10);
10
+ const keyMarker = url.searchParams.get("key-marker");
11
+ if ("string" == typeof bucketName) {
12
+ if (bucketName.includes("non-existent-bucket")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchBucket", "The specified bucket does not exist", bucketName)));
13
+ if (bucketName.includes("access-denied-bucket")) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied")));
14
+ if (bucketName.includes("network-error-bucket")) return res.networkError("Failed to connect");
15
+ if (bucketName.includes("empty-bucket")) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
16
+ <ListVersionsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
17
+ <Name>${bucketName}</Name>
18
+ <Prefix>${prefix}</Prefix>
19
+ <Delimiter>${delimiter}</Delimiter>
20
+ <MaxKeys>${maxKeys}</MaxKeys>
21
+ <IsTruncated>false</IsTruncated>
22
+ </ListVersionsResult>`));
23
+ if (keyMarker) {
24
+ const pageKey = prefix && "file.txt" !== prefix ? `${prefix.replace(/\/$/, "")}-v3.txt` : "file-v3.txt";
25
+ return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
26
+ <ListVersionsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
27
+ <Name>${bucketName}</Name>
28
+ <Prefix>${prefix}</Prefix>
29
+ <Delimiter>${delimiter}</Delimiter>
30
+ <MaxKeys>${maxKeys}</MaxKeys>
31
+ <IsTruncated>false</IsTruncated>
32
+ <Version>
33
+ <Key>${pageKey}</Key>
34
+ <VersionId>version-id-3</VersionId>
35
+ <IsLatest>true</IsLatest>
36
+ <LastModified>2023-10-12T17:50:00.000Z</LastModified>
37
+ <ETag>&quot;version-etag-3&quot;</ETag>
38
+ <Size>1024</Size>
39
+ <StorageClass>STANDARD</StorageClass>
40
+ </Version>
41
+ </ListVersionsResult>`));
42
+ }
43
+ const hasMorePages = bucketName.includes("paginated-bucket");
44
+ const baseKey = prefix && "file.txt" !== prefix ? prefix : "file.txt";
45
+ const deletedKey = prefix && "file.txt" !== prefix ? `${prefix.replace(/\/$/, "")}-deleted.txt` : "deleted-file.txt";
46
+ const nextKey = prefix && "file.txt" !== prefix ? `${prefix.replace(/\/$/, "")}-v2.txt` : "file-v2.txt";
47
+ return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
48
+ <ListVersionsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
49
+ <Name>${bucketName}</Name>
50
+ <Prefix>${prefix}</Prefix>
51
+ <Delimiter>${delimiter}</Delimiter>
52
+ <MaxKeys>${maxKeys}</MaxKeys>
53
+ <IsTruncated>${hasMorePages}</IsTruncated>
54
+ ${hasMorePages ? `<NextKeyMarker>${nextKey}</NextKeyMarker><NextVersionIdMarker>version-id-2</NextVersionIdMarker>` : ""}
55
+ <Version>
56
+ <Key>${baseKey}</Key>
57
+ <VersionId>version-id-1</VersionId>
58
+ <IsLatest>true</IsLatest>
59
+ <LastModified>2023-10-12T17:50:00.000Z</LastModified>
60
+ <ETag>&quot;version-etag-1&quot;</ETag>
61
+ <Size>1024</Size>
62
+ <StorageClass>STANDARD</StorageClass>
63
+ </Version>
64
+ <Version>
65
+ <Key>${baseKey}</Key>
66
+ <VersionId>version-id-2</VersionId>
67
+ <IsLatest>false</IsLatest>
68
+ <LastModified>2023-10-11T17:50:00.000Z</LastModified>
69
+ <ETag>&quot;version-etag-2&quot;</ETag>
70
+ <Size>512</Size>
71
+ <StorageClass>STANDARD</StorageClass>
72
+ </Version>
73
+ <DeleteMarker>
74
+ <Key>${deletedKey}</Key>
75
+ <VersionId>delete-marker-1</VersionId>
76
+ <IsLatest>true</IsLatest>
77
+ <LastModified>2023-10-10T17:50:00.000Z</LastModified>
78
+ </DeleteMarker>
79
+ </ListVersionsResult>`));
80
+ }
81
+ return res(ctx.status(200));
82
+ });
83
+ export { listObjectVersionsHandler };
@@ -0,0 +1 @@
1
+ export declare const listObjectsHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
@@ -0,0 +1,66 @@
1
+ import { rest } from "msw";
2
+ import { createS3ErrorXml, getS3BaseUrl } from "../utils.js";
3
+ const listObjectsHandler = rest.get(`${getS3BaseUrl()}/:bucketName`, (req, res, ctx)=>{
4
+ const { bucketName } = req.params;
5
+ const url = new URL(req.url);
6
+ if ("2" !== url.searchParams.get("list-type")) return;
7
+ const prefix = url.searchParams.get("prefix") || "";
8
+ const delimiter = url.searchParams.get("delimiter") || "";
9
+ const maxKeys = parseInt(url.searchParams.get("max-keys") || "1000", 10);
10
+ const continuationToken = url.searchParams.get("continuation-token");
11
+ if ("string" == typeof bucketName) {
12
+ if (bucketName.includes("non-existent-bucket")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchBucket", "The specified bucket does not exist", bucketName)));
13
+ if (bucketName.includes("access-denied-bucket")) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied")));
14
+ if (bucketName.includes("network-error-bucket")) return res.networkError("Failed to connect");
15
+ if (bucketName.includes("empty-bucket")) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
16
+ <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
17
+ <Name>${bucketName}</Name>
18
+ <Prefix>${prefix}</Prefix>
19
+ <Delimiter>${delimiter}</Delimiter>
20
+ <MaxKeys>${maxKeys}</MaxKeys>
21
+ <IsTruncated>false</IsTruncated>
22
+ </ListBucketResult>`));
23
+ if (continuationToken) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
24
+ <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
25
+ <Name>${bucketName}</Name>
26
+ <Prefix>${prefix}</Prefix>
27
+ <Delimiter>${delimiter}</Delimiter>
28
+ <MaxKeys>${maxKeys}</MaxKeys>
29
+ <IsTruncated>false</IsTruncated>
30
+ <Contents>
31
+ <Key>${prefix}file3.txt</Key>
32
+ <LastModified>2023-10-12T17:50:00.000Z</LastModified>
33
+ <ETag>&quot;d41d8cd98f00b204e9800998ecf8427e&quot;</ETag>
34
+ <Size>2048</Size>
35
+ <StorageClass>STANDARD</StorageClass>
36
+ </Contents>
37
+ </ListBucketResult>`));
38
+ const hasMorePages = bucketName.includes("paginated-bucket");
39
+ return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
40
+ <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
41
+ <Name>${bucketName}</Name>
42
+ <Prefix>${prefix}</Prefix>
43
+ <Delimiter>${delimiter}</Delimiter>
44
+ <MaxKeys>${maxKeys}</MaxKeys>
45
+ <IsTruncated>${hasMorePages}</IsTruncated>
46
+ ${hasMorePages ? "<NextContinuationToken>token-123</NextContinuationToken>" : ""}
47
+ <Contents>
48
+ <Key>${prefix}file1.txt</Key>
49
+ <LastModified>2023-10-12T17:50:00.000Z</LastModified>
50
+ <ETag>&quot;d41d8cd98f00b204e9800998ecf8427e&quot;</ETag>
51
+ <Size>1024</Size>
52
+ <StorageClass>STANDARD</StorageClass>
53
+ </Contents>
54
+ <Contents>
55
+ <Key>${prefix}file2.txt</Key>
56
+ <LastModified>2023-10-12T17:50:00.000Z</LastModified>
57
+ <ETag>&quot;e58ed763928cf52221fa5c4e2d6422a&quot;</ETag>
58
+ <Size>512</Size>
59
+ <StorageClass>STANDARD</StorageClass>
60
+ </Contents>
61
+ ${delimiter ? `<CommonPrefixes><Prefix>${prefix}folder1/</Prefix></CommonPrefixes>` : ""}
62
+ </ListBucketResult>`));
63
+ }
64
+ return res(ctx.status(200));
65
+ });
66
+ export { listObjectsHandler };
@@ -0,0 +1 @@
1
+ export declare const getObjectLegalHoldHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
@@ -0,0 +1,24 @@
1
+ import { rest } from "msw";
2
+ import { createS3ErrorXml, getS3BaseUrl } from "../utils.js";
3
+ import { ObjectLockLegalHoldStatus } from "@aws-sdk/client-s3";
4
+ const getObjectLegalHoldHandler = rest.get(`${getS3BaseUrl()}/:bucketName/*`, (req, res, ctx)=>{
5
+ const { bucketName } = req.params;
6
+ const url = new URL(req.url);
7
+ const objectKey = url.pathname.substring(url.pathname.indexOf("/", 1) + 1);
8
+ if (!url.searchParams.has("legal-hold")) return;
9
+ if ("string" == typeof bucketName) {
10
+ if ("no-such-bucket" === bucketName || "non-existent-bucket" === bucketName) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchBucket", "The specified bucket does not exist", bucketName)));
11
+ if ("access-denied-bucket" === bucketName || "restricted-bucket" === bucketName) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied", bucketName, objectKey)));
12
+ if ("network-error-bucket" === bucketName) return res.networkError("Failed to connect");
13
+ if ("non-existent-object.txt" === objectKey) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchKey", "The specified key does not exist.", bucketName, objectKey)));
14
+ if ("no-legal-hold-object.txt" === objectKey) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchObjectLockConfiguration", "The specified object does not have a ObjectLock configuration", bucketName, objectKey)));
15
+ let status = ObjectLockLegalHoldStatus.ON;
16
+ if ("legal-hold-off-object.txt" === objectKey) status = ObjectLockLegalHoldStatus.OFF;
17
+ return res(ctx.status(200), ctx.set("Content-Type", "application/xml"), ctx.body(`<?xml version="1.0" encoding="UTF-8"?>
18
+ <LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
19
+ <Status>${status}</Status>
20
+ </LegalHold>`));
21
+ }
22
+ return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidArgument", "Invalid request parameters")));
23
+ });
24
+ export { getObjectLegalHoldHandler };
@@ -0,0 +1 @@
1
+ export declare const getObjectRetentionHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
@@ -0,0 +1,27 @@
1
+ import { rest } from "msw";
2
+ import { createS3ErrorXml, getS3BaseUrl } from "../utils.js";
3
+ const getObjectRetentionHandler = rest.get(`${getS3BaseUrl()}/:bucketName/*`, (req, res, ctx)=>{
4
+ const { bucketName } = req.params;
5
+ const url = new URL(req.url);
6
+ const objectKey = url.pathname.substring(url.pathname.indexOf("/", 1) + 1);
7
+ if (!url.searchParams.has("retention")) return;
8
+ if ("string" == typeof bucketName) {
9
+ if (bucketName.includes("non-existent-bucket")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchBucket", "The specified bucket does not exist", bucketName)));
10
+ if (objectKey.includes("non-existent-object")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchKey", "The specified key does not exist.", bucketName, objectKey)));
11
+ if (bucketName.includes("restricted-bucket")) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied")));
12
+ if (objectKey.includes("no-retention-object")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchObjectLockConfiguration", "The specified object does not have a ObjectLock configuration", bucketName, objectKey)));
13
+ if (bucketName.includes("network-error-bucket")) return res.networkError("Failed to connect");
14
+ if (objectKey.includes("compliance-retention")) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
15
+ <Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
16
+ <Mode>COMPLIANCE</Mode>
17
+ <RetainUntilDate>2024-12-31T23:59:59.000Z</RetainUntilDate>
18
+ </Retention>`));
19
+ return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
20
+ <Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
21
+ <Mode>GOVERNANCE</Mode>
22
+ <RetainUntilDate>2024-06-30T23:59:59.000Z</RetainUntilDate>
23
+ </Retention>`));
24
+ }
25
+ return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidArgument", "Invalid request parameters")));
26
+ });
27
+ export { getObjectRetentionHandler };
@@ -0,0 +1 @@
1
+ export declare const putBucketAclHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
@@ -0,0 +1,18 @@
1
+ import { rest } from "msw";
2
+ import { createS3ErrorXml, getS3BaseUrl } from "../utils.js";
3
+ const putBucketAclHandler = rest.put(`${getS3BaseUrl()}/:bucketName`, (req, res, ctx)=>{
4
+ const { bucketName } = req.params;
5
+ const url = new URL(req.url);
6
+ if (!url.searchParams.has("acl")) return;
7
+ if ("string" == typeof bucketName) {
8
+ if (bucketName.includes("non-existent-bucket")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchBucket", "The specified bucket does not exist", bucketName)));
9
+ if (bucketName.includes("access-denied-bucket")) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied")));
10
+ if (bucketName.includes("invalid-acl-bucket")) return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidRequest", "The ACL configuration is invalid")));
11
+ if (bucketName.includes("malformed-acl-bucket")) return res(ctx.status(400), ctx.xml(createS3ErrorXml("MalformedACLError", "The XML provided does not match the expected format")));
12
+ if (bucketName.includes("network-error-bucket")) return res.networkError("Failed to connect");
13
+ const aclParam = url.searchParams.get("acl");
14
+ if ("invalid-acl-type" === aclParam) return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidArgument", "Invalid canned ACL value")));
15
+ }
16
+ return res(ctx.status(200), ctx.set("Content-Type", "application/xml"), ctx.body(""));
17
+ });
18
+ export { putBucketAclHandler };
@@ -0,0 +1 @@
1
+ export declare const putObjectHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
@@ -0,0 +1,16 @@
1
+ import { rest } from "msw";
2
+ import { createS3ErrorXml, getS3BaseUrl } from "../utils.js";
3
+ const putObjectHandler = rest.put(`${getS3BaseUrl()}/:bucketName/*`, (req, res, ctx)=>{
4
+ const { bucketName } = req.params;
5
+ const url = new URL(req.url);
6
+ const objectKey = url.pathname.substring(url.pathname.indexOf("/", 1) + 1);
7
+ if ("string" == typeof bucketName) {
8
+ if (bucketName.includes("non-existent-bucket")) return res(ctx.status(404), ctx.xml(createS3ErrorXml("NoSuchBucket", "The specified bucket does not exist", bucketName)));
9
+ if (bucketName.includes("access-denied-bucket")) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied")));
10
+ if (bucketName.includes("network-error-bucket")) return res.networkError("Failed to connect");
11
+ if (objectKey.includes("invalid-key")) return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidRequest", "The specified key is not valid")));
12
+ return res(ctx.status(200), ctx.set("ETag", '"mock-etag-123"'), ctx.set("x-amz-version-id", "mock-version-id"), ctx.set("x-amz-server-side-encryption", "AES256"), ctx.body(""));
13
+ }
14
+ return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidArgument", "Invalid request parameters")));
15
+ });
16
+ export { putObjectHandler };
@@ -0,0 +1,4 @@
1
+ export declare const createBucketHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
2
+ export declare const getBucketVersioningHandler: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>;
3
+ export declare const s3Handlers: import("msw").RestHandler<import("msw").MockedRequest<import("msw").DefaultRequestBody>>[];
4
+ export default s3Handlers;
@@ -0,0 +1,109 @@
1
+ import { rest } from "msw";
2
+ import { listBucketsHandler } from "./handlers/listBuckets.js";
3
+ import { deleteBucketHandler } from "./handlers/deleteBucket.js";
4
+ import { getBucketLocationHandler } from "./handlers/getBucketLocation.js";
5
+ import { getBucketAclHandler } from "./handlers/getBucketAcl.js";
6
+ import { getBucketPolicyHandler } from "./handlers/getBucketPolicy.js";
7
+ import { listObjectsHandler } from "./handlers/listObjects.js";
8
+ import { listObjectVersionsHandler } from "./handlers/listObjectVersions.js";
9
+ import { headObjectHandler } from "./handlers/headObject.js";
10
+ import { getObjectRetentionHandler } from "./handlers/objectRetention.js";
11
+ import { getObjectLegalHoldHandler } from "./handlers/objectLegalHold.js";
12
+ import { putObjectHandler } from "./handlers/putObject.js";
13
+ import { putBucketAclHandler } from "./handlers/putBucketAcl.js";
14
+ import { createS3ErrorXml, getS3BaseUrl } from "./utils.js";
15
+ const isBucketConfigurationRequest = (url)=>{
16
+ const configParams = [
17
+ "acl",
18
+ "policy",
19
+ "versioning",
20
+ "lifecycle",
21
+ "cors",
22
+ "website",
23
+ "tagging",
24
+ "encryption",
25
+ "notification",
26
+ "replication",
27
+ "requestPayment",
28
+ "accelerate",
29
+ "metrics",
30
+ "inventory",
31
+ "analytics",
32
+ "intelligentTiering",
33
+ "ownershipControls",
34
+ "publicAccessBlock",
35
+ "logging",
36
+ "location"
37
+ ];
38
+ return configParams.some((param)=>url.searchParams.has(param));
39
+ };
40
+ const createBucketHandler = rest.put(`${getS3BaseUrl()}/:bucketName`, (req, res, ctx)=>{
41
+ const { bucketName } = req.params;
42
+ const url = new URL(req.url);
43
+ if (isBucketConfigurationRequest(url)) return;
44
+ if ("string" == typeof bucketName) {
45
+ if (bucketName.includes("existing-bucket")) return res(ctx.status(409), ctx.xml(createS3ErrorXml("BucketAlreadyExists", "The requested bucket name is not available", bucketName)));
46
+ if (bucketName.includes("restricted-bucket")) return res(ctx.status(403), ctx.xml(createS3ErrorXml("AccessDenied", "Access Denied")));
47
+ if (bucketName.includes("invalid-bucket-name")) return res(ctx.status(400), ctx.xml(createS3ErrorXml("InvalidBucketName", "Invalid bucket name")));
48
+ if (bucketName.includes("network-test-bucket")) return res.networkError("Network connection failed");
49
+ }
50
+ return res(ctx.status(200), ctx.set("Location", `/${bucketName}`), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
51
+ <CreateBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
52
+ <Location>/${bucketName}</Location>
53
+ </CreateBucketResult>`));
54
+ });
55
+ const getBucketVersioningHandler = rest.get(`${getS3BaseUrl()}/:bucketName`, (req, res, ctx)=>{
56
+ const { bucketName } = req.params;
57
+ const url = new URL(req.url);
58
+ if (!url.searchParams.has("versioning")) return;
59
+ if ("string" == typeof bucketName) {
60
+ if (bucketName.includes("nonexistent-bucket")) return res(ctx.status(404), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
61
+ <Error>
62
+ <Code>NoSuchBucket</Code>
63
+ <Message>The specified bucket does not exist</Message>
64
+ <BucketName>${bucketName}</BucketName>
65
+ </Error>`));
66
+ if (bucketName.includes("access-denied-bucket")) return res(ctx.status(403), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
67
+ <Error>
68
+ <Code>AccessDenied</Code>
69
+ <Message>Access Denied</Message>
70
+ </Error>`));
71
+ if (bucketName.includes("network-error-bucket")) return res.networkError("Network connection failed");
72
+ if (bucketName.includes("enabled-versioning-bucket")) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
73
+ <VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
74
+ <Status>Enabled</Status>
75
+ <MfaDelete>Disabled</MfaDelete>
76
+ </VersioningConfiguration>`));
77
+ if (bucketName.includes("suspended-versioning-bucket")) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
78
+ <VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
79
+ <Status>Suspended</Status>
80
+ <MfaDelete>Disabled</MfaDelete>
81
+ </VersioningConfiguration>`));
82
+ if (bucketName.includes("mfa-enabled-bucket")) return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
83
+ <VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
84
+ <Status>Enabled</Status>
85
+ <MfaDelete>Enabled</MfaDelete>
86
+ </VersioningConfiguration>`));
87
+ }
88
+ return res(ctx.status(200), ctx.xml(`<?xml version="1.0" encoding="UTF-8"?>
89
+ <VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
90
+ </VersioningConfiguration>`));
91
+ });
92
+ const s3Handlers = [
93
+ listBucketsHandler,
94
+ createBucketHandler,
95
+ deleteBucketHandler,
96
+ getBucketVersioningHandler,
97
+ getBucketLocationHandler,
98
+ getBucketAclHandler,
99
+ getBucketPolicyHandler,
100
+ listObjectsHandler,
101
+ listObjectVersionsHandler,
102
+ getObjectRetentionHandler,
103
+ getObjectLegalHoldHandler,
104
+ putObjectHandler,
105
+ headObjectHandler,
106
+ putBucketAclHandler
107
+ ];
108
+ const handlers = s3Handlers;
109
+ export { createBucketHandler, handlers as default, getBucketVersioningHandler, s3Handlers };
@@ -0,0 +1,2 @@
1
+ export { server, setupMswServer, overrideHandlers } from "./server";
2
+ export { s3Handlers, createBucketHandler, getBucketVersioningHandler, } from "./handlers";
@@ -0,0 +1,3 @@
1
+ import { overrideHandlers, server, setupMswServer } from "./server.js";
2
+ import { createBucketHandler, getBucketVersioningHandler, s3Handlers } from "./handlers.js";
3
+ export { createBucketHandler, getBucketVersioningHandler, overrideHandlers, s3Handlers, server, setupMswServer };
@@ -0,0 +1,4 @@
1
+ export declare const server: import("msw/node").SetupServerApi;
2
+ export declare const setupMswServer: () => void;
3
+ export declare const overrideHandlers: (...handlers: Parameters<typeof server.use>) => void;
4
+ export { s3Handlers } from "./handlers";
@@ -0,0 +1,20 @@
1
+ import { setupServer } from "msw/node";
2
+ import { s3Handlers } from "./handlers.js";
3
+ const server = setupServer(...s3Handlers);
4
+ const setupMswServer = ()=>{
5
+ beforeAll(()=>{
6
+ server.listen({
7
+ onUnhandledRequest: "warn"
8
+ });
9
+ });
10
+ afterEach(()=>{
11
+ server.resetHandlers();
12
+ });
13
+ afterAll(()=>{
14
+ server.close();
15
+ });
16
+ };
17
+ const overrideHandlers = (...handlers)=>{
18
+ server.use(...handlers);
19
+ };
20
+ export { overrideHandlers, s3Handlers, server, setupMswServer };
@@ -0,0 +1,2 @@
1
+ export declare const getS3BaseUrl: () => string;
2
+ export declare const createS3ErrorXml: (code: string, message: string, bucketName?: string, key?: string) => string;
@@ -0,0 +1,13 @@
1
+ const getS3BaseUrl = ()=>"https://s3.amazonaws.com";
2
+ const createS3ErrorXml = (code, message, bucketName, key)=>{
3
+ let resourceDetails = "";
4
+ if (bucketName) resourceDetails += `<BucketName>${bucketName}</BucketName>`;
5
+ if (key) resourceDetails += `<Key>${key}</Key>`;
6
+ return `<?xml version="1.0" encoding="UTF-8"?>
7
+ <Error>
8
+ <Code>${code}</Code>
9
+ <Message>${message}</Message>
10
+ ${resourceDetails}
11
+ </Error>`;
12
+ };
13
+ export { createS3ErrorXml, getS3BaseUrl };
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
@@ -0,0 +1,82 @@
1
+ import "@testing-library/jest-dom";
2
+ import { TextDecoder, TextEncoder } from "util";
3
+ var __webpack_require__ = {};
4
+ (()=>{
5
+ __webpack_require__.g = (()=>{
6
+ if ('object' == typeof globalThis) return globalThis;
7
+ try {
8
+ return this || new Function('return this')();
9
+ } catch (e) {
10
+ if ('object' == typeof window) return window;
11
+ }
12
+ })();
13
+ })();
14
+ process.env.AWS_ACCESS_KEY_ID = "test-access-key";
15
+ process.env.AWS_SECRET_ACCESS_KEY = "test-secret-key";
16
+ process.env.AWS_DEFAULT_REGION = "us-east-1";
17
+ const testS3Config = {
18
+ endpoint: "http://localhost:8000",
19
+ region: "us-east-1",
20
+ realHost: "s3.amazonaws.com",
21
+ forcePathStyle: true
22
+ };
23
+ const testDevConfig = {
24
+ useProxy: false,
25
+ proxyEndpoint: "http://localhost:3000/api/s3",
26
+ proxyBasePath: "/api/s3",
27
+ proxyHost: "localhost",
28
+ proxyPort: 3000
29
+ };
30
+ globalThis.__S3_CONFIG__ = testS3Config;
31
+ globalThis.__DEV_CONFIG__ = testDevConfig;
32
+ globalThis.__IS_DEVELOPMENT__ = true;
33
+ globalThis.__IS_PRODUCTION__ = false;
34
+ jest.setTimeout(10000);
35
+ Object.assign(__webpack_require__.g, {
36
+ TextDecoder: TextDecoder,
37
+ TextEncoder: TextEncoder
38
+ });
39
+ Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
40
+ value: ()=>null
41
+ });
42
+ jest.mock("pretty-bytes", ()=>({
43
+ __esModule: true,
44
+ default: (bytes)=>{
45
+ const sizes = [
46
+ "B",
47
+ "KB",
48
+ "MB",
49
+ "GB"
50
+ ];
51
+ let i = 0;
52
+ let num = bytes;
53
+ while(num >= 1024 && i < sizes.length - 1){
54
+ num /= 1024;
55
+ i++;
56
+ }
57
+ return `${Math.round(num)} ${sizes[i]}`;
58
+ }
59
+ }));
60
+ if (!File.prototype.arrayBuffer) File.prototype.arrayBuffer = function() {
61
+ return new Promise((resolve)=>{
62
+ const reader = new FileReader();
63
+ reader.onload = ()=>resolve(reader.result);
64
+ reader.readAsArrayBuffer(this);
65
+ });
66
+ };
67
+ const originalError = console.error;
68
+ const originalWarn = console.warn;
69
+ beforeAll(()=>{
70
+ console.error = (...args)=>{
71
+ if ("string" == typeof args[0] && (args[0].includes("AWS") || args[0].includes("S3") || args[0].includes("Warning: An update to") || args[0].includes('Warning: A props object containing a "key" prop'))) return;
72
+ originalError(...args);
73
+ };
74
+ console.warn = (...args)=>{
75
+ if ("string" == typeof args[0] && (args[0].includes("AWS") || args[0].includes("S3") || args[0].includes("Warning: An update to") || args[0].includes('Warning: A props object containing a "key" prop'))) return;
76
+ originalWarn(...args);
77
+ };
78
+ });
79
+ afterAll(()=>{
80
+ console.error = originalError;
81
+ console.warn = originalWarn;
82
+ });
@@ -0,0 +1,82 @@
1
+ import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
2
+ import React from "react";
3
+ import { S3BrowserConfig, S3Credentials } from "../types";
4
+ export declare const testConfig: S3BrowserConfig;
5
+ export declare const testCredentials: S3Credentials;
6
+ export declare const mockS3Client: {
7
+ send: jest.Mock<any, any, any>;
8
+ };
9
+ export declare const MockedS3Client: jest.MockedClass<typeof S3Client>;
10
+ export declare const MockedPutObjectCommand: jest.MockedClass<typeof PutObjectCommand>;
11
+ export declare function mockOffsetSize(width: number, height: number): void;
12
+ /**
13
+ * Creates a simple QueryClient wrapper for tests that don't need DataBrowser context
14
+ */
15
+ export declare const createQueryWrapper: () => ({ children }: {
16
+ children: React.ReactNode;
17
+ }) => import("react/jsx-runtime").JSX.Element;
18
+ /**
19
+ * Creates a test wrapper with DataBrowser context and QueryClient
20
+ */
21
+ export declare const createTestWrapper: (config?: S3BrowserConfig, credentials?: S3Credentials) => ({ children }: {
22
+ children: React.ReactNode;
23
+ }) => import("react/jsx-runtime").JSX.Element;
24
+ /**
25
+ * Renders a hook with the standard test wrapper
26
+ */
27
+ export declare const renderHookWithWrapper: <TProps, TResult>(hook: (props: TProps) => TResult, options?: {
28
+ initialProps?: TProps;
29
+ config?: S3BrowserConfig;
30
+ credentials?: S3Credentials;
31
+ }) => import("@testing-library/react").RenderHookResult<TResult, TProps>;
32
+ /**
33
+ * Creates a test File object
34
+ */
35
+ export declare const createTestFile: (name: string, content: string, type?: string) => File;
36
+ /**
37
+ * Sets up S3 mocks for testing
38
+ */
39
+ export declare const setupS3Mocks: () => void;
40
+ /**
41
+ * Common mock setup that should be run before each test
42
+ */
43
+ export declare const setupCommonMocks: () => void;
44
+ /**
45
+ * Configuration test utilities for overriding build-time globals
46
+ */
47
+ import type { S3Configuration, DevelopmentConfiguration } from "../config/types";
48
+ type GlobalConfigOverrides = {
49
+ s3?: Partial<S3Configuration>;
50
+ dev?: Partial<DevelopmentConfiguration>;
51
+ environment?: {
52
+ isDevelopment?: boolean;
53
+ isProduction?: boolean;
54
+ };
55
+ };
56
+ /**
57
+ * Override global configuration for testing specific scenarios
58
+ * Useful for testing different deployment environments or proxy configurations
59
+ */
60
+ export declare const overrideGlobalConfig: (overrides: GlobalConfigOverrides) => void;
61
+ /**
62
+ * Reset global configuration to test defaults
63
+ * Should be called in afterEach or afterAll to ensure test isolation
64
+ */
65
+ export declare const resetGlobalConfig: () => void;
66
+ /**
67
+ * Test helper for running tests with specific global configuration
68
+ */
69
+ export declare const withGlobalConfig: (overrides: GlobalConfigOverrides, testFn: () => void | Promise<void>) => () => Promise<void>;
70
+ /**
71
+ * Validates that a hook follows the expected factory pattern
72
+ */
73
+ export declare const validateFactoryHook: (hook: any, operationName: string) => void;
74
+ /**
75
+ * Creates a factory test error
76
+ */
77
+ export declare const createFactoryTestError: (testContext: string, operationName: string, details?: string) => Error;
78
+ /**
79
+ * Validates that a hook result has expected React Query properties
80
+ */
81
+ export declare const validateHookResult: (result: any, hookType: "query" | "mutation" | "infiniteQuery") => void;
82
+ export { setupMswServer, overrideHandlers } from "./msw";