@visulima/storage 1.0.0-alpha.1 → 1.0.0-alpha.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 (224) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +33 -14
  3. package/dist/adapter/nuxt/module.d.ts +39 -0
  4. package/dist/adapter/nuxt/module.js +93 -0
  5. package/dist/adapter/nuxt/package.json +20 -0
  6. package/dist/handler/base/base-handler-core.d.ts +91 -0
  7. package/dist/handler/base/base-handler-fetch.d.ts +76 -0
  8. package/dist/handler/base/base-handler-node.d.ts +137 -0
  9. package/dist/handler/http/fetch/index.d.ts +4 -0
  10. package/dist/handler/http/fetch/index.js +4 -0
  11. package/dist/handler/http/hono/index.d.ts +67 -0
  12. package/dist/handler/http/hono/index.js +65 -0
  13. package/dist/handler/http/nextjs/index.d.ts +61 -0
  14. package/dist/handler/http/nextjs/index.js +37 -0
  15. package/dist/handler/http/node/index.d.ts +4 -0
  16. package/dist/handler/http/node/index.js +4 -0
  17. package/dist/handler/http/solid-start/index.d.ts +60 -0
  18. package/dist/handler/http/solid-start/index.js +44 -0
  19. package/dist/handler/multipart/multipart-base.d.ts +84 -0
  20. package/dist/handler/multipart/multipart-fetch.d.ts +64 -0
  21. package/dist/handler/multipart/multipart.d.ts +49 -0
  22. package/dist/handler/rest/rest-base.d.ts +106 -0
  23. package/dist/handler/rest/rest-fetch.d.ts +88 -0
  24. package/dist/handler/rest/rest.d.ts +93 -0
  25. package/dist/handler/tus/tus-base.d.ts +152 -0
  26. package/dist/handler/tus/tus-fetch.d.ts +72 -0
  27. package/dist/handler/tus/tus.d.ts +78 -0
  28. package/dist/handler/types.d.ts +53 -0
  29. package/dist/handler/utils/request-parser.d.ts +72 -0
  30. package/dist/handler/utils/response-builder.d.ts +83 -0
  31. package/dist/handler/utils/storage-utils.d.ts +10 -0
  32. package/dist/handler/utils/stream-utils.d.ts +29 -0
  33. package/dist/handler/utils/upload-handlers.d.ts +76 -0
  34. package/dist/index.d.ts +17 -0
  35. package/dist/index.js +13 -0
  36. package/dist/metrics/index.d.ts +2 -0
  37. package/dist/metrics/no-op-metrics.d.ts +15 -0
  38. package/dist/metrics/opentelemetry-metrics.d.ts +55 -0
  39. package/dist/openapi/index.d.ts +5 -0
  40. package/dist/openapi/index.js +5 -0
  41. package/dist/openapi/rest.d.ts +7 -0
  42. package/dist/openapi/shared.d.ts +13 -0
  43. package/dist/openapi/transform.d.ts +3 -0
  44. package/dist/openapi/tus.d.ts +7 -0
  45. package/dist/openapi/xhr.d.ts +7 -0
  46. package/dist/packem_shared/AwsLightFile-tTneXZgG.js +11 -0
  47. package/dist/packem_shared/AwsLightMetaStorage-BWSOtVaN.js +4 -0
  48. package/dist/packem_shared/AwsLightStorage-Blv-GP4v.js +133 -0
  49. package/dist/packem_shared/AzureFile-CesgFzps.js +8 -0
  50. package/dist/packem_shared/AzureSMetaStorage-CFs-OYJT.js +88 -0
  51. package/dist/packem_shared/AzureStorage-B0v048hG.js +357 -0
  52. package/dist/packem_shared/BaseTransformer-C2gLib6v.js +82 -0
  53. package/dist/packem_shared/DiskStorage-BlltBst6.js +12 -0
  54. package/dist/packem_shared/DiskStorageWithChecksum-BJTmMklc.js +238 -0
  55. package/dist/packem_shared/ERRORS-D0apMqnc.js +97 -0
  56. package/dist/packem_shared/File-Bb3P23dr.js +69 -0
  57. package/dist/packem_shared/GCSConfig-vPP22kN6.js +11 -0
  58. package/dist/packem_shared/GCSFile-BIEunhAN.js +8 -0
  59. package/dist/packem_shared/GCSMetaStorage-BMFEdzJ7.js +7 -0
  60. package/dist/packem_shared/GCStorage-DnhiwaS9.js +406 -0
  61. package/dist/packem_shared/LocalMetaStorage-CZHhKkMd.js +7 -0
  62. package/dist/packem_shared/MediaTransformer-D6658DL1.js +1197 -0
  63. package/dist/packem_shared/MetaStorage-pECeFOad.js +46 -0
  64. package/dist/packem_shared/Metadata-DRLXeJ0F.js +89 -0
  65. package/dist/packem_shared/Multipart-CNFK_Okz.js +163 -0
  66. package/dist/packem_shared/Multipart-CtUL7BQw.js +128 -0
  67. package/dist/packem_shared/NetlifyBlobFile-CXzyjqrD.js +14 -0
  68. package/dist/packem_shared/NetlifyBlobMetaStorage-DxZ5aDvD.js +9 -0
  69. package/dist/packem_shared/NetlifyBlobStorage-CLPtjHqd.js +376 -0
  70. package/dist/packem_shared/NoOpMetrics-DhAk5rXc.js +10 -0
  71. package/dist/packem_shared/OpenTelemetryMetrics-BnxhqIaH.js +67 -0
  72. package/dist/packem_shared/Rest-CAOAEkOj.js +267 -0
  73. package/dist/packem_shared/Rest-DNuLwBrK.js +228 -0
  74. package/dist/packem_shared/S3File-DZiyk9Qt.js +11 -0
  75. package/dist/packem_shared/S3MetaStorage-Dz9aDabA.js +76 -0
  76. package/dist/packem_shared/S3Storage-DHmTk-hU.js +316 -0
  77. package/dist/packem_shared/TUS_RESUMABLE-GJzZ9R-f.js +434 -0
  78. package/dist/packem_shared/Tus-B8PmlMgR.js +200 -0
  79. package/dist/packem_shared/Tus-C4F1aYOl.js +195 -0
  80. package/dist/packem_shared/ValidationError-BfF1aE4h.js +26 -0
  81. package/dist/packem_shared/VercelBlobFile-BCg4aTEq.js +18 -0
  82. package/dist/packem_shared/VercelBlobMetaStorage-Bd9F-VFm.js +9 -0
  83. package/dist/packem_shared/VercelBlobStorage-DD9LMOS6.js +261 -0
  84. package/dist/packem_shared/_commonjsHelpers-B85MJLTf.js +5 -0
  85. package/dist/packem_shared/aws-light-meta-storage-DKJBgbR6.js +446 -0
  86. package/dist/packem_shared/backblaze-BlMnIcBC.js +20 -0
  87. package/dist/packem_shared/base-handler-core-BKuf4YLT.js +303 -0
  88. package/dist/packem_shared/base-handler-fetch-Cr0hLiqg.js +291 -0
  89. package/dist/packem_shared/base-handler-node-gk5aN9Cx.js +730 -0
  90. package/dist/packem_shared/cache-B88MXQ_2.js +18 -0
  91. package/dist/packem_shared/cloudflare-Bi1q8wXE.js +21 -0
  92. package/dist/packem_shared/defaultCloudStorageFileNameValidation-DUuacjWv.js +11 -0
  93. package/dist/packem_shared/digitalOcean-CWQRJM3L.js +21 -0
  94. package/dist/packem_shared/disk-storage-Bh2wy3YW.js +810 -0
  95. package/dist/packem_shared/gcs-meta-storage-0tgMNnPO.js +158 -0
  96. package/dist/packem_shared/has-content-CY66ehMK.js +3 -0
  97. package/dist/packem_shared/headers-DoS5nwM-.js +3220 -0
  98. package/dist/packem_shared/is-expired-CTThU1q5.js +8 -0
  99. package/dist/packem_shared/isRetryableError-Dycp7127.js +82 -0
  100. package/dist/packem_shared/isValidMediaType-BeDgiObq.js +35 -0
  101. package/dist/packem_shared/local-meta-storage-By-3SNBI.js +649 -0
  102. package/dist/packem_shared/minio-C2YBZQOw.js +22 -0
  103. package/dist/packem_shared/multipart-base-B3i67SSX.js +102 -0
  104. package/dist/packem_shared/part-match-BMNqHDYD.js +96 -0
  105. package/dist/packem_shared/path-CR6YkPXX-7R1-9CMk.js +161 -0
  106. package/dist/packem_shared/response-builder-BtnRiBUI.js +45 -0
  107. package/dist/packem_shared/rest-base-GRCcnan7.js +457 -0
  108. package/dist/packem_shared/restOpenApiSpec-CwcHHY2C.js +800 -0
  109. package/dist/packem_shared/s3-base-storage-C1DIHTYY.js +510 -0
  110. package/dist/packem_shared/sharedGet-Cpo7QUyu.js +1019 -0
  111. package/dist/packem_shared/storage-C6NSXb8h.js +1175 -0
  112. package/dist/packem_shared/tigris-Hac8TKnX.js +21 -0
  113. package/dist/packem_shared/transformOpenApiSpec-DWM5WtnN.js +975 -0
  114. package/dist/packem_shared/tusOpenApiSpec-6ohiToBy.js +740 -0
  115. package/dist/packem_shared/update-size-CCGm6i1J.js +8 -0
  116. package/dist/packem_shared/validator-BeX_lJet.js +78 -0
  117. package/dist/packem_shared/waitForStorage-Cscw85sx.js +18 -0
  118. package/dist/packem_shared/wasabi-DIyflHSd.js +21 -0
  119. package/dist/packem_shared/xhrOpenApiSpec-DS17brnx.js +264 -0
  120. package/dist/storage/aws/clients/backblaze.d.ts +12 -0
  121. package/dist/storage/aws/clients/cloudflare.d.ts +13 -0
  122. package/dist/storage/aws/clients/digital-ocean.d.ts +12 -0
  123. package/dist/storage/aws/clients/index.d.ts +6 -0
  124. package/dist/storage/aws/clients/index.js +6 -0
  125. package/dist/storage/aws/clients/minio.d.ts +13 -0
  126. package/dist/storage/aws/clients/tigris.d.ts +12 -0
  127. package/dist/storage/aws/clients/types.d.ts +95 -0
  128. package/dist/storage/aws/clients/wasabi.d.ts +12 -0
  129. package/dist/storage/aws/index.d.ts +4 -0
  130. package/dist/storage/aws/index.js +3 -0
  131. package/dist/storage/aws/s3-base-storage.d.ts +248 -0
  132. package/dist/storage/aws/s3-client-adapter.d.ts +110 -0
  133. package/dist/storage/aws/s3-file.d.ts +10 -0
  134. package/dist/storage/aws/s3-meta-storage.d.ts +15 -0
  135. package/dist/storage/aws/s3-storage.d.ts +70 -0
  136. package/dist/storage/aws/types.d.ts +119 -0
  137. package/dist/storage/aws-light/aws-light-api-adapter.d.ts +130 -0
  138. package/dist/storage/aws-light/aws-light-file.d.ts +10 -0
  139. package/dist/storage/aws-light/aws-light-meta-storage.d.ts +19 -0
  140. package/dist/storage/aws-light/aws-light-storage.d.ts +65 -0
  141. package/dist/storage/aws-light/index.d.ts +4 -0
  142. package/dist/storage/aws-light/index.js +3 -0
  143. package/dist/storage/aws-light/types.d.ts +37 -0
  144. package/dist/storage/azure/azure-file.d.ts +6 -0
  145. package/dist/storage/azure/azure-meta-storage.d.ts +15 -0
  146. package/dist/storage/azure/azure-storage.d.ts +69 -0
  147. package/dist/storage/azure/index.d.ts +4 -0
  148. package/dist/storage/azure/index.js +3 -0
  149. package/dist/storage/azure/types.d.ts +62 -0
  150. package/dist/storage/gcs/fetch-error.d.ts +11 -0
  151. package/dist/storage/gcs/gcs-config.d.ts +2 -0
  152. package/dist/storage/gcs/gcs-file.d.ts +6 -0
  153. package/dist/storage/gcs/gcs-meta-storage.d.ts +27 -0
  154. package/dist/storage/gcs/gcs-storage.d.ts +91 -0
  155. package/dist/storage/gcs/index.d.ts +5 -0
  156. package/dist/storage/gcs/index.js +4 -0
  157. package/dist/storage/gcs/types.d.ts +55 -0
  158. package/dist/storage/gcs/utils.d.ts +7 -0
  159. package/dist/storage/local/disk-storage-with-checksum.d.ts +15 -0
  160. package/dist/storage/local/disk-storage.d.ts +135 -0
  161. package/dist/storage/local/index.d.ts +4 -0
  162. package/dist/storage/local/index.js +3 -0
  163. package/dist/storage/local/local-meta-storage.d.ts +32 -0
  164. package/dist/storage/meta-storage.d.ts +30 -0
  165. package/dist/storage/netlify-blob/index.d.ts +4 -0
  166. package/dist/storage/netlify-blob/index.js +3 -0
  167. package/dist/storage/netlify-blob/netlify-blob-file.d.ts +12 -0
  168. package/dist/storage/netlify-blob/netlify-blob-meta-storage.d.ts +7 -0
  169. package/dist/storage/netlify-blob/netlify-blob-storage.d.ts +93 -0
  170. package/dist/storage/netlify-blob/types.d.ts +30 -0
  171. package/dist/storage/storage.d.ts +353 -0
  172. package/dist/storage/types.d.ts +221 -0
  173. package/dist/storage/utils/file/file.d.ts +25 -0
  174. package/dist/storage/utils/file/get-file-status.d.ts +9 -0
  175. package/dist/storage/utils/file/has-content.d.ts +9 -0
  176. package/dist/storage/utils/file/index.d.ts +10 -0
  177. package/dist/storage/utils/file/is-expired.d.ts +8 -0
  178. package/dist/storage/utils/file/metadata.d.ts +18 -0
  179. package/dist/storage/utils/file/part-match.d.ts +11 -0
  180. package/dist/storage/utils/file/types.d.ts +37 -0
  181. package/dist/storage/utils/file/update-metadata.d.ts +10 -0
  182. package/dist/storage/utils/file/update-size.d.ts +10 -0
  183. package/dist/storage/vercel-blob/index.d.ts +4 -0
  184. package/dist/storage/vercel-blob/index.js +3 -0
  185. package/dist/storage/vercel-blob/types.d.ts +32 -0
  186. package/dist/storage/vercel-blob/vercel-blob-file.d.ts +16 -0
  187. package/dist/storage/vercel-blob/vercel-blob-meta-storage.d.ts +7 -0
  188. package/dist/storage/vercel-blob/vercel-blob-storage.d.ts +76 -0
  189. package/dist/transformer/audio-transformer.d.ts +128 -0
  190. package/dist/transformer/audio-transformer.js +278 -0
  191. package/dist/transformer/base-transformer.d.ts +63 -0
  192. package/dist/transformer/image-transformer.d.ts +571 -0
  193. package/dist/transformer/image-transformer.js +1100 -0
  194. package/dist/transformer/index.d.ts +5 -0
  195. package/dist/transformer/index.js +4 -0
  196. package/dist/transformer/media-transformer.d.ts +332 -0
  197. package/dist/transformer/types.d.ts +652 -0
  198. package/dist/transformer/utils.d.ts +33 -0
  199. package/dist/transformer/validation-error.d.ts +23 -0
  200. package/dist/transformer/video-transformer.d.ts +145 -0
  201. package/dist/transformer/video-transformer.js +310 -0
  202. package/dist/utils/cache.d.ts +32 -0
  203. package/dist/utils/chunked-upload.d.ts +65 -0
  204. package/dist/utils/detect-file-type.d.ts +28 -0
  205. package/dist/utils/errors.d.ts +74 -0
  206. package/dist/utils/file-path-url-matcher.d.ts +18 -0
  207. package/dist/utils/headers.d.ts +111 -0
  208. package/dist/utils/http.d.ts +92 -0
  209. package/dist/utils/locker.d.ts +26 -0
  210. package/dist/utils/pipes/stream-checksum.d.ts +47 -0
  211. package/dist/utils/pipes/stream-length.d.ts +22 -0
  212. package/dist/utils/primitives/get-last-one.d.ts +3 -0
  213. package/dist/utils/primitives/is-record.d.ts +2 -0
  214. package/dist/utils/primitives/map-values.d.ts +9 -0
  215. package/dist/utils/primitives/pick.d.ts +2 -0
  216. package/dist/utils/primitives/to-milliseconds.d.ts +12 -0
  217. package/dist/utils/primitives/to-seconds.d.ts +12 -0
  218. package/dist/utils/range-checksum.d.ts +33 -0
  219. package/dist/utils/range-hasher.d.ts +46 -0
  220. package/dist/utils/retry.d.ts +64 -0
  221. package/dist/utils/types.d.ts +108 -0
  222. package/dist/utils/validation-error.d.ts +22 -0
  223. package/dist/utils/validator.d.ts +36 -0
  224. package/package.json +5 -5
@@ -0,0 +1,446 @@
1
+ import MetaStorage from './MetaStorage-pECeFOad.js';
2
+ import { parseMetadata, stringifyMetadata } from './Metadata-DRLXeJ0F.js';
3
+ import { Readable } from 'node:stream';
4
+ import { AwsClient } from 'aws4fetch';
5
+ import { i as isExpired } from './is-expired-CTThU1q5.js';
6
+
7
+ const parseXml = (text) => {
8
+ const result = {};
9
+ const cleanText = text.replaceAll(/<\?xml[^>]*\?>/g, "").replaceAll(/xmlns[^=]*="[^"]*"/g, "");
10
+ const tagRegex = /<([^>]+)>([^<]*)<\/\1>/g;
11
+ const matches = [...cleanText.matchAll(tagRegex)];
12
+ for (const match of matches) {
13
+ const [, tagName, content] = match;
14
+ if (tagName && content && content.trim()) {
15
+ if (result[tagName]) {
16
+ if (!Array.isArray(result[tagName])) {
17
+ result[tagName] = [result[tagName]];
18
+ }
19
+ result[tagName].push(content.trim());
20
+ } else {
21
+ result[tagName] = content.trim();
22
+ }
23
+ }
24
+ }
25
+ const nestedRegex = /<([^>]+)>([\s\S]*?)<\/\1>/g;
26
+ let nestedMatch;
27
+ while ((nestedMatch = nestedRegex.exec(cleanText)) !== null) {
28
+ const [, tagName, innerContent] = nestedMatch;
29
+ if (tagName && innerContent && innerContent.includes("<")) {
30
+ const nested = parseXml(innerContent);
31
+ if (Object.keys(nested).length > 0) {
32
+ result[tagName] = nested;
33
+ }
34
+ }
35
+ }
36
+ return result;
37
+ };
38
+ class AwsLightApiAdapter {
39
+ aws;
40
+ bucket;
41
+ endpoint;
42
+ constructor(config) {
43
+ this.bucket = config.bucket;
44
+ this.endpoint = config.endpoint || `https://${config.bucket}.s3.${config.region}.amazonaws.com`;
45
+ this.aws = new AwsClient({
46
+ accessKeyId: config.accessKeyId,
47
+ region: config.region,
48
+ secretAccessKey: config.secretAccessKey,
49
+ service: config.service || "s3",
50
+ sessionToken: config.sessionToken
51
+ });
52
+ }
53
+ async createMultipartUpload(params) {
54
+ const queryParams = { uploads: "" };
55
+ const headers = {};
56
+ if (params.ContentType) {
57
+ headers["Content-Type"] = params.ContentType;
58
+ }
59
+ if (params.ACL) {
60
+ headers["x-amz-acl"] = params.ACL;
61
+ }
62
+ if (params.Metadata) {
63
+ for (const [key, value] of Object.entries(params.Metadata)) {
64
+ headers[`x-amz-meta-${key}`] = value;
65
+ }
66
+ }
67
+ const url = this.buildUrl(params.Key, queryParams);
68
+ const response = await this.aws.fetch(url, {
69
+ headers,
70
+ method: "POST"
71
+ });
72
+ const xmlText = await response.text();
73
+ if (!response.ok) {
74
+ throw new Error(`Failed to create multipart upload: ${response.status} ${xmlText}`);
75
+ }
76
+ const xml = parseXml(xmlText);
77
+ const uploadId = xml.UploadId || xml.InitiateMultipartUploadResult?.UploadId;
78
+ if (!uploadId) {
79
+ const error = new Error("Failed to parse UploadId from response");
80
+ error.retryable = false;
81
+ throw error;
82
+ }
83
+ return { UploadId: uploadId };
84
+ }
85
+ async uploadPart(params) {
86
+ const queryParams = {
87
+ partNumber: String(params.PartNumber),
88
+ uploadId: params.UploadId
89
+ };
90
+ const headers = {};
91
+ if (params.ContentLength) {
92
+ headers["Content-Length"] = String(params.ContentLength);
93
+ }
94
+ if (params.ContentMD5) {
95
+ headers["Content-MD5"] = params.ContentMD5;
96
+ }
97
+ const body = params.Body instanceof Readable ? Readable.toWeb(params.Body) : params.Body;
98
+ const url = this.buildUrl(params.Key, queryParams);
99
+ const response = await this.aws.fetch(url, {
100
+ body,
101
+ headers,
102
+ method: "PUT"
103
+ });
104
+ if (!response.ok) {
105
+ const text = await response.text();
106
+ throw new Error(`Failed to upload part: ${response.status} ${text}`);
107
+ }
108
+ const etag = response.headers.get("ETag");
109
+ if (!etag) {
110
+ throw new Error("Failed to get ETag from response");
111
+ }
112
+ return { ETag: etag.replaceAll(/(^"|"$)/g, "") };
113
+ }
114
+ async completeMultipartUpload(params) {
115
+ const queryParams = { uploadId: params.UploadId };
116
+ const partsXml = params.Parts.map(({ ETag, PartNumber }) => `<Part><PartNumber>${PartNumber}</PartNumber><ETag>"${ETag}"</ETag></Part>`).join("");
117
+ const xmlBody = `<?xml version="1.0" encoding="UTF-8"?>
118
+ <CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
119
+ ${partsXml}
120
+ </CompleteMultipartUpload>`;
121
+ const url = this.buildUrl(params.Key, queryParams);
122
+ const response = await this.aws.fetch(url, {
123
+ body: xmlBody,
124
+ headers: {
125
+ "Content-Type": "application/xml"
126
+ },
127
+ method: "POST"
128
+ });
129
+ const xmlText = await response.text();
130
+ if (!response.ok) {
131
+ throw new Error(`Failed to complete multipart upload: ${response.status} ${xmlText}`);
132
+ }
133
+ const xml = parseXml(xmlText);
134
+ const result = xml.CompleteMultipartUploadResult || xml;
135
+ const location = result.Location || `${this.endpoint}/${params.Key}`;
136
+ const etag = result.ETag;
137
+ return {
138
+ ETag: etag?.replaceAll(/(^"|"$)/g, ""),
139
+ Location: location
140
+ };
141
+ }
142
+ async abortMultipartUpload(params) {
143
+ const queryParams = { uploadId: params.UploadId };
144
+ const url = this.buildUrl(params.Key, queryParams);
145
+ const response = await this.aws.fetch(url, {
146
+ method: "DELETE"
147
+ });
148
+ if (!response.ok) {
149
+ const text = await response.text();
150
+ throw new Error(`Failed to abort multipart upload: ${response.status} ${text}`);
151
+ }
152
+ }
153
+ async listParts(params) {
154
+ const queryParams = { uploadId: params.UploadId };
155
+ const url = this.buildUrl(params.Key, queryParams);
156
+ const response = await this.aws.fetch(url, {
157
+ method: "GET"
158
+ });
159
+ const xmlText = await response.text();
160
+ if (!response.ok) {
161
+ throw new Error(`Failed to list parts: ${response.status} ${xmlText}`);
162
+ }
163
+ const xml = parseXml(xmlText);
164
+ const listPartsResult = xml.ListPartsResult || xml;
165
+ let parts = [];
166
+ if (listPartsResult.Part) {
167
+ parts = Array.isArray(listPartsResult.Part) ? listPartsResult.Part : [listPartsResult.Part];
168
+ }
169
+ return {
170
+ Parts: parts.map((part) => {
171
+ return {
172
+ ETag: part.ETag?.replaceAll(/(^"|"$)/g, ""),
173
+ PartNumber: Number(part.PartNumber) || 0,
174
+ Size: part.Size ? Number(part.Size) : void 0
175
+ };
176
+ })
177
+ };
178
+ }
179
+ async getObject(params) {
180
+ const url = this.buildUrl(params.Key);
181
+ const response = await this.aws.fetch(url, {
182
+ method: "GET"
183
+ });
184
+ if (!response.ok) {
185
+ const text = await response.text();
186
+ throw new Error(`Failed to get object: ${response.status} ${text}`);
187
+ }
188
+ const contentLength = response.headers.get("Content-Length");
189
+ const contentType = response.headers.get("Content-Type");
190
+ const etag = response.headers.get("ETag");
191
+ const expires = response.headers.get("Expires");
192
+ const lastModified = response.headers.get("Last-Modified");
193
+ const metadata = {};
194
+ for (const [key, value] of response.headers.entries()) {
195
+ if (key.toLowerCase().startsWith("x-amz-meta-")) {
196
+ const metaKey = key.toLowerCase().replace("x-amz-meta-", "");
197
+ metadata[metaKey] = value;
198
+ }
199
+ }
200
+ const { body } = response;
201
+ return {
202
+ Body: body ? this.streamToReadable(body) : void 0,
203
+ ContentLength: contentLength ? Number(contentLength) : void 0,
204
+ ContentType: contentType || void 0,
205
+ ETag: etag?.replaceAll(/(^"|"$)/g, "") || void 0,
206
+ Expires: expires ? new Date(expires) : void 0,
207
+ LastModified: lastModified ? new Date(lastModified) : void 0,
208
+ Metadata: Object.keys(metadata).length > 0 ? metadata : void 0
209
+ };
210
+ }
211
+ async headObject(params) {
212
+ const url = this.buildUrl(params.Key);
213
+ const response = await this.aws.fetch(url, {
214
+ method: "HEAD"
215
+ });
216
+ if (!response.ok) {
217
+ const text = await response.text();
218
+ throw new Error(`Failed to head object: ${response.status} ${text}`);
219
+ }
220
+ const contentLength = response.headers.get("Content-Length");
221
+ const contentType = response.headers.get("Content-Type");
222
+ const etag = response.headers.get("ETag");
223
+ const expires = response.headers.get("Expires");
224
+ const lastModified = response.headers.get("Last-Modified");
225
+ const metadata = {};
226
+ for (const [key, value] of response.headers.entries()) {
227
+ if (key.toLowerCase().startsWith("x-amz-meta-")) {
228
+ const metaKey = key.toLowerCase().replace("x-amz-meta-", "");
229
+ metadata[metaKey] = value;
230
+ }
231
+ }
232
+ return {
233
+ ContentLength: contentLength ? Number(contentLength) : void 0,
234
+ ContentType: contentType || void 0,
235
+ ETag: etag?.replaceAll(/(^"|"$)/g, "") || void 0,
236
+ Expires: expires ? new Date(expires) : void 0,
237
+ LastModified: lastModified ? new Date(lastModified) : void 0,
238
+ Metadata: Object.keys(metadata).length > 0 ? metadata : void 0
239
+ };
240
+ }
241
+ async deleteObject(params) {
242
+ const url = this.buildUrl(params.Key);
243
+ const response = await this.aws.fetch(url, {
244
+ method: "DELETE"
245
+ });
246
+ if (!response.ok) {
247
+ const text = await response.text();
248
+ throw new Error(`Failed to delete object: ${response.status} ${text}`);
249
+ }
250
+ }
251
+ async copyObject(params) {
252
+ const headers = {
253
+ "x-amz-copy-source": params.CopySource
254
+ };
255
+ if (params.StorageClass) {
256
+ headers["x-amz-storage-class"] = params.StorageClass;
257
+ }
258
+ let url = this.buildUrl(params.Key);
259
+ if (params.Bucket !== this.bucket) {
260
+ url = url.replace(this.bucket, params.Bucket);
261
+ }
262
+ const response = await this.aws.fetch(url, {
263
+ headers,
264
+ method: "PUT"
265
+ });
266
+ if (!response.ok) {
267
+ const text = await response.text();
268
+ throw new Error(`Failed to copy object: ${response.status} ${text}`);
269
+ }
270
+ }
271
+ async listObjectsV2(params) {
272
+ const queryParams = {
273
+ "list-type": "2"
274
+ };
275
+ if (params.MaxKeys) {
276
+ queryParams["max-keys"] = String(params.MaxKeys);
277
+ }
278
+ if (params.ContinuationToken) {
279
+ queryParams["continuation-token"] = params.ContinuationToken;
280
+ }
281
+ const url = this.buildUrl("", queryParams);
282
+ const response = await this.aws.fetch(url, {
283
+ method: "GET"
284
+ });
285
+ const xmlText = await response.text();
286
+ if (!response.ok) {
287
+ throw new Error(`Failed to list objects: ${response.status} ${xmlText}`);
288
+ }
289
+ const xml = parseXml(xmlText);
290
+ const listResult = xml.ListBucketResult || xml;
291
+ const contents = listResult.Contents || (Array.isArray(listResult.Contents) ? listResult.Contents : []);
292
+ return {
293
+ Contents: Array.isArray(contents) ? contents.map((item) => {
294
+ return {
295
+ Key: item.Key,
296
+ LastModified: item.LastModified ? new Date(String(item.LastModified)) : void 0
297
+ };
298
+ }) : [],
299
+ IsTruncated: listResult.IsTruncated === "true" || listResult.IsTruncated === true,
300
+ NextContinuationToken: listResult.NextContinuationToken
301
+ };
302
+ }
303
+ async getPresignedUrl(params) {
304
+ const queryParams = {
305
+ partNumber: String(params.PartNumber),
306
+ uploadId: params.UploadId,
307
+ "X-Amz-Expires": String(params.expiresIn)
308
+ };
309
+ const url = this.buildUrl(params.Key, queryParams);
310
+ return url;
311
+ }
312
+ async putObject(params) {
313
+ const url = this.buildUrl(params.Key);
314
+ const headers = {};
315
+ if (params.ContentType) {
316
+ headers["Content-Type"] = params.ContentType;
317
+ }
318
+ if (params.ContentLength !== void 0) {
319
+ headers["Content-Length"] = String(params.ContentLength);
320
+ }
321
+ if (params.Metadata) {
322
+ for (const [key, value] of Object.entries(params.Metadata)) {
323
+ headers[`x-amz-meta-${key}`] = value;
324
+ }
325
+ }
326
+ let body;
327
+ if (params.Body === void 0) {
328
+ body = void 0;
329
+ } else if (params.Body instanceof Uint8Array) {
330
+ body = new Uint8Array(params.Body);
331
+ } else if (params.Body instanceof ReadableStream) {
332
+ body = params.Body;
333
+ } else {
334
+ body = void 0;
335
+ }
336
+ const response = await this.aws.fetch(url, {
337
+ body,
338
+ headers,
339
+ method: "PUT"
340
+ });
341
+ if (!response.ok) {
342
+ const text = await response.text();
343
+ throw new Error(`Failed to put object: ${response.status} ${text}`);
344
+ }
345
+ }
346
+ async checkBucketAccess(_params) {
347
+ const url = this.buildUrl("");
348
+ const response = await this.aws.fetch(url, {
349
+ method: "HEAD"
350
+ });
351
+ if (!response.ok && response.status !== 404) {
352
+ const text = await response.text();
353
+ throw new Error(`Failed to access bucket: ${response.status} ${text}`);
354
+ }
355
+ }
356
+ /**
357
+ * Builds S3 API URL.
358
+ */
359
+ buildUrl(key, queryParams) {
360
+ const url = new URL(key, this.endpoint);
361
+ if (queryParams) {
362
+ for (const [parameterKey, value] of Object.entries(queryParams)) {
363
+ url.searchParams.set(parameterKey, value);
364
+ }
365
+ }
366
+ return url.toString();
367
+ }
368
+ /**
369
+ * Converts ReadableStream to Readable for Node.js compatibility.
370
+ */
371
+ // eslint-disable-next-line class-methods-use-this
372
+ streamToReadable(stream) {
373
+ return Readable.fromWeb(stream);
374
+ }
375
+ }
376
+
377
+ class AwsLightMetaStorage extends MetaStorage {
378
+ constructor(config) {
379
+ super(config);
380
+ this.config = config;
381
+ const bucket = config.bucket || process.env.S3_BUCKET || process.env.AWS_S3_BUCKET;
382
+ if (!bucket) {
383
+ throw new Error("S3 bucket is not defined");
384
+ }
385
+ this.bucket = bucket;
386
+ this.adapter = new AwsLightApiAdapter({
387
+ accessKeyId: config.accessKeyId,
388
+ bucket,
389
+ endpoint: config.endpoint,
390
+ region: config.region,
391
+ secretAccessKey: config.secretAccessKey,
392
+ service: config.service,
393
+ sessionToken: config.sessionToken
394
+ });
395
+ this.adapter.checkBucketAccess({ Bucket: bucket }).catch((error) => {
396
+ throw error;
397
+ });
398
+ }
399
+ adapter;
400
+ bucket;
401
+ async get(id) {
402
+ const Key = this.getMetaName(id);
403
+ const { Expires, Metadata } = await this.adapter.headObject({
404
+ Bucket: this.bucket,
405
+ Key
406
+ });
407
+ if (Expires && isExpired({ expiredAt: Expires })) {
408
+ await this.delete(Key);
409
+ throw new Error(`Metafile ${id} not found`);
410
+ }
411
+ if (Metadata?.metadata !== void 0) {
412
+ const file = JSON.parse(decodeURIComponent(Metadata.metadata));
413
+ if (file.metadata && typeof file.metadata === "string") {
414
+ file.metadata = parseMetadata(file.metadata);
415
+ }
416
+ return file;
417
+ }
418
+ throw new Error(`Metafile ${id} not found`);
419
+ }
420
+ async touch(id, file) {
421
+ return this.save(id, file);
422
+ }
423
+ async delete(id) {
424
+ await this.adapter.deleteObject({
425
+ Bucket: this.bucket,
426
+ Key: this.getMetaName(id)
427
+ });
428
+ }
429
+ async save(id, file) {
430
+ const transformedMetadata = { ...file };
431
+ if (transformedMetadata.metadata) {
432
+ transformedMetadata.metadata = stringifyMetadata(file.metadata);
433
+ }
434
+ const metadata = encodeURIComponent(JSON.stringify(transformedMetadata));
435
+ await this.adapter.putObject({
436
+ Bucket: this.bucket,
437
+ ContentLength: 0,
438
+ ContentType: "application/json",
439
+ Key: this.getMetaName(id),
440
+ Metadata: { metadata }
441
+ });
442
+ return file;
443
+ }
444
+ }
445
+
446
+ export { AwsLightMetaStorage as A, AwsLightApiAdapter as a };
@@ -0,0 +1,20 @@
1
+ const backblaze = (parameters) => {
2
+ const { applicationKey, applicationKeyId, region } = parameters ?? {
3
+ applicationKey: process.env.AWS_SECRET_ACCESS_KEY || process.env.B2_APP_KEY || process.env.BACKBLAZE_APP_KEY,
4
+ applicationKeyId: process.env.AWS_ACCESS_KEY_ID || process.env.B2_APP_KEY_ID || process.env.BACKBLAZE_APP_KEY_ID,
5
+ region: process.env.AWS_REGION || process.env.B2_REGION || process.env.BACKBLAZE_REGION
6
+ };
7
+ if (!region || !applicationKeyId || !applicationKey) {
8
+ throw new Error("Missing required parameters for Backblaze B2 client.");
9
+ }
10
+ return {
11
+ credentials: {
12
+ accessKeyId: applicationKeyId,
13
+ secretAccessKey: applicationKey
14
+ },
15
+ endpoint: `https://s3.${region}.backblazeb2.com`,
16
+ region
17
+ };
18
+ };
19
+
20
+ export { backblaze, backblaze as default };