@visulima/storage 1.0.0-alpha.1 → 1.0.0-alpha.11

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 (225) hide show
  1. package/CHANGELOG.md +170 -0
  2. package/LICENSE.md +6 -6
  3. package/README.md +33 -14
  4. package/dist/adapter/nuxt/module.d.ts +39 -0
  5. package/dist/adapter/nuxt/module.js +93 -0
  6. package/dist/adapter/nuxt/package.json +20 -0
  7. package/dist/handler/base/base-handler-core.d.ts +91 -0
  8. package/dist/handler/base/base-handler-fetch.d.ts +76 -0
  9. package/dist/handler/base/base-handler-node.d.ts +137 -0
  10. package/dist/handler/http/fetch/index.d.ts +4 -0
  11. package/dist/handler/http/fetch/index.js +4 -0
  12. package/dist/handler/http/hono/index.d.ts +67 -0
  13. package/dist/handler/http/hono/index.js +65 -0
  14. package/dist/handler/http/nextjs/index.d.ts +61 -0
  15. package/dist/handler/http/nextjs/index.js +37 -0
  16. package/dist/handler/http/node/index.d.ts +4 -0
  17. package/dist/handler/http/node/index.js +8 -0
  18. package/dist/handler/http/solid-start/index.d.ts +60 -0
  19. package/dist/handler/http/solid-start/index.js +44 -0
  20. package/dist/handler/multipart/multipart-base.d.ts +84 -0
  21. package/dist/handler/multipart/multipart-fetch.d.ts +64 -0
  22. package/dist/handler/multipart/multipart.d.ts +49 -0
  23. package/dist/handler/rest/rest-base.d.ts +106 -0
  24. package/dist/handler/rest/rest-fetch.d.ts +88 -0
  25. package/dist/handler/rest/rest.d.ts +93 -0
  26. package/dist/handler/tus/tus-base.d.ts +152 -0
  27. package/dist/handler/tus/tus-fetch.d.ts +72 -0
  28. package/dist/handler/tus/tus.d.ts +78 -0
  29. package/dist/handler/types.d.ts +53 -0
  30. package/dist/handler/utils/request-parser.d.ts +72 -0
  31. package/dist/handler/utils/response-builder.d.ts +83 -0
  32. package/dist/handler/utils/storage-utils.d.ts +10 -0
  33. package/dist/handler/utils/stream-utils.d.ts +29 -0
  34. package/dist/handler/utils/upload-handlers.d.ts +76 -0
  35. package/dist/index.d.ts +17 -0
  36. package/dist/index.js +13 -0
  37. package/dist/metrics/index.d.ts +2 -0
  38. package/dist/metrics/no-op-metrics.d.ts +15 -0
  39. package/dist/metrics/opentelemetry-metrics.d.ts +55 -0
  40. package/dist/openapi/index.d.ts +5 -0
  41. package/dist/openapi/index.js +5 -0
  42. package/dist/openapi/rest.d.ts +7 -0
  43. package/dist/openapi/shared.d.ts +13 -0
  44. package/dist/openapi/transform.d.ts +3 -0
  45. package/dist/openapi/tus.d.ts +7 -0
  46. package/dist/openapi/xhr.d.ts +7 -0
  47. package/dist/packem_shared/AwsLightFile-tTneXZgG.js +11 -0
  48. package/dist/packem_shared/AwsLightMetaStorage-D9qWQt6q.js +4 -0
  49. package/dist/packem_shared/AwsLightStorage-CEJTYBVv.js +133 -0
  50. package/dist/packem_shared/AzureFile-CesgFzps.js +8 -0
  51. package/dist/packem_shared/AzureSMetaStorage-BEbXX9Uk.js +89 -0
  52. package/dist/packem_shared/AzureStorage-CH6nvQx8.js +357 -0
  53. package/dist/packem_shared/BaseTransformer-9965D4pb.js +83 -0
  54. package/dist/packem_shared/DiskStorage-DziI2mwX.js +12 -0
  55. package/dist/packem_shared/DiskStorageWithChecksum-B_XY8_cO.js +240 -0
  56. package/dist/packem_shared/ERRORS-D0apMqnc.js +97 -0
  57. package/dist/packem_shared/File-Bb3P23dr.js +69 -0
  58. package/dist/packem_shared/GCSConfig-vPP22kN6.js +11 -0
  59. package/dist/packem_shared/GCSFile-BIEunhAN.js +8 -0
  60. package/dist/packem_shared/GCSMetaStorage-FypK8Tn1.js +7 -0
  61. package/dist/packem_shared/GCStorage-CasTo9rF.js +408 -0
  62. package/dist/packem_shared/LocalMetaStorage-BnllcjV9.js +7 -0
  63. package/dist/packem_shared/MediaTransformer-BErvw2vE.js +1196 -0
  64. package/dist/packem_shared/MetaStorage-pECeFOad.js +46 -0
  65. package/dist/packem_shared/Metadata-DRLXeJ0F.js +89 -0
  66. package/dist/packem_shared/Multipart-CDDlDOs7.js +163 -0
  67. package/dist/packem_shared/Multipart-vxBL2VXm.js +128 -0
  68. package/dist/packem_shared/NetlifyBlobFile-CXzyjqrD.js +14 -0
  69. package/dist/packem_shared/NetlifyBlobMetaStorage-DIkZ2umW.js +9 -0
  70. package/dist/packem_shared/NetlifyBlobStorage-DEpx_4q-.js +376 -0
  71. package/dist/packem_shared/NoOpMetrics-DhAk5rXc.js +10 -0
  72. package/dist/packem_shared/OpenTelemetryMetrics-BnxhqIaH.js +67 -0
  73. package/dist/packem_shared/Rest-CEj3EhMj.js +228 -0
  74. package/dist/packem_shared/Rest-D14vM7aJ.js +267 -0
  75. package/dist/packem_shared/S3File-DZiyk9Qt.js +11 -0
  76. package/dist/packem_shared/S3MetaStorage-yT4CznlV.js +77 -0
  77. package/dist/packem_shared/S3Storage-B0scgwPa.js +317 -0
  78. package/dist/packem_shared/TUS_RESUMABLE-Dtfsffnj.js +434 -0
  79. package/dist/packem_shared/Tus-Cjz87bpz.js +200 -0
  80. package/dist/packem_shared/Tus-WOVg-YnB.js +195 -0
  81. package/dist/packem_shared/ValidationError-BfF1aE4h.js +26 -0
  82. package/dist/packem_shared/VercelBlobFile-BCg4aTEq.js +18 -0
  83. package/dist/packem_shared/VercelBlobMetaStorage-c0M-TvAR.js +9 -0
  84. package/dist/packem_shared/VercelBlobStorage-wOYxv8F7.js +261 -0
  85. package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +5 -0
  86. package/dist/packem_shared/aws-light-meta-storage-Ba2b_h-o.js +447 -0
  87. package/dist/packem_shared/backblaze-BlMnIcBC.js +20 -0
  88. package/dist/packem_shared/base-handler-core-BoAqTyz7.js +303 -0
  89. package/dist/packem_shared/base-handler-fetch-CinvR65S.js +291 -0
  90. package/dist/packem_shared/base-handler-node-c02H0AxN.js +731 -0
  91. package/dist/packem_shared/cache-B88MXQ_2.js +18 -0
  92. package/dist/packem_shared/cloudflare-Bi1q8wXE.js +21 -0
  93. package/dist/packem_shared/defaultCloudStorageFileNameValidation-CGoYrGB2.js +11 -0
  94. package/dist/packem_shared/digitalOcean-CWQRJM3L.js +21 -0
  95. package/dist/packem_shared/disk-storage-DeivH-J5.js +816 -0
  96. package/dist/packem_shared/gcs-meta-storage-B0Baj0Xr.js +159 -0
  97. package/dist/packem_shared/has-content-CY66ehMK.js +3 -0
  98. package/dist/packem_shared/headers-YLRp1dLo.js +1318 -0
  99. package/dist/packem_shared/is-expired-CTThU1q5.js +8 -0
  100. package/dist/packem_shared/isRetryableError-Dycp7127.js +82 -0
  101. package/dist/packem_shared/isValidMediaType-BeDgiObq.js +35 -0
  102. package/dist/packem_shared/local-meta-storage-BlOk6m7F.js +647 -0
  103. package/dist/packem_shared/minio-C2YBZQOw.js +22 -0
  104. package/dist/packem_shared/multipart-base-C994naBi.js +102 -0
  105. package/dist/packem_shared/part-match-BMNqHDYD.js +96 -0
  106. package/dist/packem_shared/path-aV9lMdcn-DMU5H1-h.js +162 -0
  107. package/dist/packem_shared/response-builder-BtnRiBUI.js +45 -0
  108. package/dist/packem_shared/rest-base-D9URIFkc.js +457 -0
  109. package/dist/packem_shared/restOpenApiSpec-D1zbmid7.js +800 -0
  110. package/dist/packem_shared/s3-base-storage-CG21uusd.js +513 -0
  111. package/dist/packem_shared/sharedGet-DAyJfjhl.js +1018 -0
  112. package/dist/packem_shared/storage-CpJpqLdn.js +1184 -0
  113. package/dist/packem_shared/tigris-Hac8TKnX.js +21 -0
  114. package/dist/packem_shared/transformOpenApiSpec-BC0r6PzI.js +975 -0
  115. package/dist/packem_shared/tusOpenApiSpec-BLIjKf0s.js +740 -0
  116. package/dist/packem_shared/update-size-CCGm6i1J.js +8 -0
  117. package/dist/packem_shared/validator-DuO17wFF.js +79 -0
  118. package/dist/packem_shared/waitForStorage-Cscw85sx.js +18 -0
  119. package/dist/packem_shared/wasabi-DIyflHSd.js +21 -0
  120. package/dist/packem_shared/xhrOpenApiSpec-kItrSAsc.js +264 -0
  121. package/dist/storage/aws/clients/backblaze.d.ts +12 -0
  122. package/dist/storage/aws/clients/cloudflare.d.ts +13 -0
  123. package/dist/storage/aws/clients/digital-ocean.d.ts +12 -0
  124. package/dist/storage/aws/clients/index.d.ts +6 -0
  125. package/dist/storage/aws/clients/index.js +6 -0
  126. package/dist/storage/aws/clients/minio.d.ts +13 -0
  127. package/dist/storage/aws/clients/tigris.d.ts +12 -0
  128. package/dist/storage/aws/clients/types.d.ts +95 -0
  129. package/dist/storage/aws/clients/wasabi.d.ts +12 -0
  130. package/dist/storage/aws/index.d.ts +4 -0
  131. package/dist/storage/aws/index.js +3 -0
  132. package/dist/storage/aws/s3-base-storage.d.ts +248 -0
  133. package/dist/storage/aws/s3-client-adapter.d.ts +110 -0
  134. package/dist/storage/aws/s3-file.d.ts +10 -0
  135. package/dist/storage/aws/s3-meta-storage.d.ts +15 -0
  136. package/dist/storage/aws/s3-storage.d.ts +70 -0
  137. package/dist/storage/aws/types.d.ts +119 -0
  138. package/dist/storage/aws-light/aws-light-api-adapter.d.ts +130 -0
  139. package/dist/storage/aws-light/aws-light-file.d.ts +10 -0
  140. package/dist/storage/aws-light/aws-light-meta-storage.d.ts +19 -0
  141. package/dist/storage/aws-light/aws-light-storage.d.ts +65 -0
  142. package/dist/storage/aws-light/index.d.ts +4 -0
  143. package/dist/storage/aws-light/index.js +3 -0
  144. package/dist/storage/aws-light/types.d.ts +37 -0
  145. package/dist/storage/azure/azure-file.d.ts +6 -0
  146. package/dist/storage/azure/azure-meta-storage.d.ts +15 -0
  147. package/dist/storage/azure/azure-storage.d.ts +69 -0
  148. package/dist/storage/azure/index.d.ts +4 -0
  149. package/dist/storage/azure/index.js +3 -0
  150. package/dist/storage/azure/types.d.ts +62 -0
  151. package/dist/storage/gcs/fetch-error.d.ts +11 -0
  152. package/dist/storage/gcs/gcs-config.d.ts +2 -0
  153. package/dist/storage/gcs/gcs-file.d.ts +6 -0
  154. package/dist/storage/gcs/gcs-meta-storage.d.ts +27 -0
  155. package/dist/storage/gcs/gcs-storage.d.ts +91 -0
  156. package/dist/storage/gcs/index.d.ts +5 -0
  157. package/dist/storage/gcs/index.js +4 -0
  158. package/dist/storage/gcs/types.d.ts +55 -0
  159. package/dist/storage/gcs/utils.d.ts +7 -0
  160. package/dist/storage/local/disk-storage-with-checksum.d.ts +15 -0
  161. package/dist/storage/local/disk-storage.d.ts +135 -0
  162. package/dist/storage/local/index.d.ts +4 -0
  163. package/dist/storage/local/index.js +3 -0
  164. package/dist/storage/local/local-meta-storage.d.ts +32 -0
  165. package/dist/storage/meta-storage.d.ts +30 -0
  166. package/dist/storage/netlify-blob/index.d.ts +4 -0
  167. package/dist/storage/netlify-blob/index.js +3 -0
  168. package/dist/storage/netlify-blob/netlify-blob-file.d.ts +12 -0
  169. package/dist/storage/netlify-blob/netlify-blob-meta-storage.d.ts +7 -0
  170. package/dist/storage/netlify-blob/netlify-blob-storage.d.ts +93 -0
  171. package/dist/storage/netlify-blob/types.d.ts +30 -0
  172. package/dist/storage/storage.d.ts +353 -0
  173. package/dist/storage/types.d.ts +221 -0
  174. package/dist/storage/utils/file/file.d.ts +25 -0
  175. package/dist/storage/utils/file/get-file-status.d.ts +9 -0
  176. package/dist/storage/utils/file/has-content.d.ts +9 -0
  177. package/dist/storage/utils/file/index.d.ts +10 -0
  178. package/dist/storage/utils/file/is-expired.d.ts +8 -0
  179. package/dist/storage/utils/file/metadata.d.ts +18 -0
  180. package/dist/storage/utils/file/part-match.d.ts +11 -0
  181. package/dist/storage/utils/file/types.d.ts +37 -0
  182. package/dist/storage/utils/file/update-metadata.d.ts +10 -0
  183. package/dist/storage/utils/file/update-size.d.ts +10 -0
  184. package/dist/storage/vercel-blob/index.d.ts +4 -0
  185. package/dist/storage/vercel-blob/index.js +3 -0
  186. package/dist/storage/vercel-blob/types.d.ts +32 -0
  187. package/dist/storage/vercel-blob/vercel-blob-file.d.ts +16 -0
  188. package/dist/storage/vercel-blob/vercel-blob-meta-storage.d.ts +7 -0
  189. package/dist/storage/vercel-blob/vercel-blob-storage.d.ts +76 -0
  190. package/dist/transformer/audio-transformer.d.ts +128 -0
  191. package/dist/transformer/audio-transformer.js +278 -0
  192. package/dist/transformer/base-transformer.d.ts +63 -0
  193. package/dist/transformer/image-transformer.d.ts +571 -0
  194. package/dist/transformer/image-transformer.js +1100 -0
  195. package/dist/transformer/index.d.ts +5 -0
  196. package/dist/transformer/index.js +4 -0
  197. package/dist/transformer/media-transformer.d.ts +332 -0
  198. package/dist/transformer/types.d.ts +652 -0
  199. package/dist/transformer/utils.d.ts +33 -0
  200. package/dist/transformer/validation-error.d.ts +23 -0
  201. package/dist/transformer/video-transformer.d.ts +145 -0
  202. package/dist/transformer/video-transformer.js +310 -0
  203. package/dist/utils/cache.d.ts +32 -0
  204. package/dist/utils/chunked-upload.d.ts +65 -0
  205. package/dist/utils/detect-file-type.d.ts +28 -0
  206. package/dist/utils/errors.d.ts +74 -0
  207. package/dist/utils/file-path-url-matcher.d.ts +18 -0
  208. package/dist/utils/headers.d.ts +111 -0
  209. package/dist/utils/http.d.ts +92 -0
  210. package/dist/utils/locker.d.ts +26 -0
  211. package/dist/utils/pipes/stream-checksum.d.ts +47 -0
  212. package/dist/utils/pipes/stream-length.d.ts +22 -0
  213. package/dist/utils/primitives/get-last-one.d.ts +3 -0
  214. package/dist/utils/primitives/is-record.d.ts +2 -0
  215. package/dist/utils/primitives/map-values.d.ts +9 -0
  216. package/dist/utils/primitives/pick.d.ts +2 -0
  217. package/dist/utils/primitives/to-milliseconds.d.ts +12 -0
  218. package/dist/utils/primitives/to-seconds.d.ts +12 -0
  219. package/dist/utils/range-checksum.d.ts +33 -0
  220. package/dist/utils/range-hasher.d.ts +46 -0
  221. package/dist/utils/retry.d.ts +64 -0
  222. package/dist/utils/types.d.ts +108 -0
  223. package/dist/utils/validation-error.d.ts +22 -0
  224. package/dist/utils/validator.d.ts +36 -0
  225. package/package.json +9 -9
@@ -0,0 +1,240 @@
1
+ import { createReadStream, createWriteStream } from 'node:fs';
2
+ import { truncate } from 'node:fs/promises';
3
+ import { Transform, pipeline } from 'node:stream';
4
+ import { p as partMatch, d as detectFileTypeFromStream, g as getFileStatus } from './part-match-BMNqHDYD.js';
5
+ import { throwErrorCode, ERRORS } from './ERRORS-D0apMqnc.js';
6
+ import { D as DiskStorage, e as ensureFile, S as StreamLength, s as streamChecksum } from './disk-storage-DeivH-J5.js';
7
+ import { LRUCache } from 'lru-cache';
8
+ import { createHash } from 'node:crypto';
9
+ import { r as remove } from './local-meta-storage-BlOk6m7F.js';
10
+ import { u as updateSize } from './update-size-CCGm6i1J.js';
11
+ import { h as hasContent } from './has-content-CY66ehMK.js';
12
+
13
+ class RangeChecksum extends Transform {
14
+ /**
15
+ * Creates a new RangeChecksum transform stream.
16
+ * @param hashes Range hasher instance managing multiple file hashes
17
+ * @param path File path identifier for this checksum operation
18
+ */
19
+ constructor(hashes, path) {
20
+ super();
21
+ this.path = path;
22
+ this.hashes = hashes;
23
+ this.hash = this.hashes.get(path) || createHash(this.hashes.algorithm);
24
+ this.hashCopy = this.hash.copy();
25
+ }
26
+ path;
27
+ hash;
28
+ hashCopy;
29
+ hashes;
30
+ /**
31
+ * Resets the hash state to its initial value.
32
+ * Useful for reusing the checksum calculator for multiple operations.
33
+ */
34
+ reset() {
35
+ this.hashes.set(this.path, this.hashCopy);
36
+ }
37
+ /**
38
+ * Returns the current hash digest in the specified encoding.
39
+ * @param encoding Output encoding format (default: 'hex')
40
+ * @returns Hash digest as a string
41
+ */
42
+ digest(encoding = "hex") {
43
+ return this.hash.copy().digest(encoding);
44
+ }
45
+ // eslint-disable-next-line no-underscore-dangle
46
+ _transform(chunk, _encoding, done) {
47
+ this.push(chunk);
48
+ this.hash.update(chunk);
49
+ done();
50
+ }
51
+ // eslint-disable-next-line class-methods-use-this,no-underscore-dangle
52
+ _flush(callback) {
53
+ callback();
54
+ }
55
+ }
56
+
57
+ class RangeHasher extends LRUCache {
58
+ /**
59
+ * Creates a new RangeHasher instance.
60
+ * @param algorithm Hash algorithm to use (default: 'sha1')
61
+ * @param options LRU cache configuration options
62
+ */
63
+ constructor(algorithm = "sha1", options) {
64
+ super({
65
+ ttl: 1e3,
66
+ ttlAutopurge: true,
67
+ ...options
68
+ });
69
+ this.algorithm = algorithm;
70
+ }
71
+ algorithm;
72
+ /**
73
+ * Returns the hex-encoded digest for a previously initialized path.
74
+ * @param path File path identifier
75
+ * @returns Hex-encoded hash digest, or empty string if not found
76
+ */
77
+ hex(path) {
78
+ return this.get(path)?.copy().digest("hex") || "";
79
+ }
80
+ /**
81
+ * Returns the base64-encoded digest for a previously initialized path.
82
+ * @param path File path identifier
83
+ * @returns Base64-encoded hash digest, or empty string if not found
84
+ */
85
+ base64(path) {
86
+ return this.get(path)?.copy().digest("base64") || "";
87
+ }
88
+ /**
89
+ * Initializes or continues a hasher for a file from the specified offset.
90
+ * Returns cached hash if available, otherwise calculates from filesystem.
91
+ * @param path File path to hash
92
+ * @param start Starting offset in bytes (default: 0)
93
+ * @returns Promise resolving to the hash instance
94
+ */
95
+ async init(path, start = 0) {
96
+ return this.get(path)?.copy() || this.updateFromFs(path, start);
97
+ }
98
+ /**
99
+ * Creates a transform stream that updates the rolling hash for a file path.
100
+ * Useful for incremental hashing during streaming operations.
101
+ * @param path File path identifier for hash tracking
102
+ * @returns RangeChecksum transform stream instance
103
+ */
104
+ digester(path) {
105
+ return new RangeChecksum(this, path);
106
+ }
107
+ async updateFromFs(path, start = 0, initial) {
108
+ const hash = await this.fromFs(path, start, initial);
109
+ this.set(path, hash);
110
+ return hash;
111
+ }
112
+ fromFs(path, start = 0, initial) {
113
+ return new Promise((resolve, reject) => {
114
+ const digester = this.digester(path);
115
+ if (initial !== void 0) {
116
+ digester.hash = initial;
117
+ }
118
+ createReadStream(path, { start }).on("error", reject).on("end", () => resolve(digester.hash)).pipe(digester).resume();
119
+ });
120
+ }
121
+ }
122
+
123
+ class DiskStorageWithChecksum extends DiskStorage {
124
+ hashes;
125
+ constructor(config) {
126
+ super(config);
127
+ this.hashes = new RangeHasher(config?.checksum === "sha1" ? "sha1" : "md5");
128
+ }
129
+ async delete({ id }) {
130
+ try {
131
+ const file = await this.getMeta(id);
132
+ const path = this.getFilePath(file.name);
133
+ this.hashes.delete(path);
134
+ await remove(path);
135
+ await this.deleteMeta(id);
136
+ const deletedFile = { ...file, status: "deleted" };
137
+ await this.onDelete(deletedFile);
138
+ return deletedFile;
139
+ } catch (error) {
140
+ this.logger?.error("[error]: Could not delete file: %O", error);
141
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
142
+ await this.onError(httpError);
143
+ }
144
+ return { id };
145
+ }
146
+ async write(part) {
147
+ let file;
148
+ if ("contentType" in part && "metadata" in part && !("body" in part) && !("start" in part)) {
149
+ file = part;
150
+ } else {
151
+ file = await this.getMeta(part.id);
152
+ await this.checkIfExpired(file);
153
+ }
154
+ if (file.status === "completed") {
155
+ return file;
156
+ }
157
+ if (part.size !== void 0) {
158
+ updateSize(file, part.size);
159
+ }
160
+ if (!partMatch(part, file)) {
161
+ return throwErrorCode(ERRORS.FILE_CONFLICT);
162
+ }
163
+ const path = this.getFilePath(file.name);
164
+ try {
165
+ const startPosition = part.start || 0;
166
+ await ensureFile(path);
167
+ if (file.bytesWritten === 0 || Number.isNaN(file.bytesWritten)) {
168
+ file.bytesWritten = startPosition;
169
+ }
170
+ await this.hashes.init(path);
171
+ if (hasContent(part)) {
172
+ if (this.isUnsupportedChecksum(part.checksumAlgorithm)) {
173
+ return throwErrorCode(ERRORS.UNSUPPORTED_CHECKSUM_ALGORITHM);
174
+ }
175
+ const isFirstChunk = part.start === 0 || part.start === void 0;
176
+ if (isFirstChunk && (file.bytesWritten === 0 || Number.isNaN(file.bytesWritten)) && (!file.contentType || file.contentType === "application/octet-stream")) {
177
+ try {
178
+ const { fileType, stream: detectedStream } = await detectFileTypeFromStream(part.body);
179
+ if (fileType?.mime) {
180
+ file.contentType = fileType.mime;
181
+ }
182
+ part.body = detectedStream;
183
+ } catch {
184
+ }
185
+ }
186
+ const [bytesWritten, errorCode] = await this.lazyWrite({ ...part, ...file });
187
+ if (errorCode) {
188
+ await truncate(path, file.bytesWritten);
189
+ return throwErrorCode(errorCode);
190
+ }
191
+ if (typeof bytesWritten !== "number") {
192
+ await this.hashes.updateFromFs(path, file.bytesWritten);
193
+ }
194
+ file.bytesWritten = bytesWritten;
195
+ }
196
+ file.status = getFileStatus(file);
197
+ file.hash = {
198
+ algorithm: this.hashes.algorithm,
199
+ value: this.hashes.hex(path)
200
+ };
201
+ if (file.status === "completed") {
202
+ this.hashes.delete(path);
203
+ }
204
+ await this.saveMeta(file);
205
+ return file;
206
+ } catch (error) {
207
+ await this.hashes.updateFromFs(path, file.bytesWritten);
208
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
209
+ await this.onError(httpError);
210
+ return throwErrorCode(ERRORS.FILE_ERROR, (typeof httpError.message === "string" ? httpError.message : String(error)) || String(error));
211
+ }
212
+ }
213
+ lazyWrite(part) {
214
+ return new Promise((resolve, reject) => {
215
+ const path = this.getFilePath(part.name);
216
+ const destination = createWriteStream(path, { flags: "r+", start: part.start });
217
+ const lengthChecker = new StreamLength(part.contentLength || Number(part.size) - part.start);
218
+ const checksumChecker = streamChecksum(part.checksum, part.checksumAlgorithm);
219
+ const digester = this.hashes.digester(path);
220
+ const keepPartial = !part.checksum;
221
+ const failWithCode = (code) => {
222
+ digester.reset();
223
+ destination.close();
224
+ resolve([Number.NaN, code]);
225
+ };
226
+ lengthChecker.on("error", () => failWithCode(ERRORS.FILE_CONFLICT));
227
+ checksumChecker.on("error", () => failWithCode(ERRORS.CHECKSUM_MISMATCH));
228
+ part.body.on("aborted", () => failWithCode(keepPartial ? void 0 : ERRORS.REQUEST_ABORTED));
229
+ pipeline(part.body, lengthChecker, checksumChecker, digester, destination, (error) => {
230
+ if (error) {
231
+ digester.reset();
232
+ return reject(error);
233
+ }
234
+ return resolve([part.start + destination.bytesWritten]);
235
+ });
236
+ });
237
+ }
238
+ }
239
+
240
+ export { DiskStorageWithChecksum as default };
@@ -0,0 +1,97 @@
1
+ var ERRORS = /* @__PURE__ */ ((ERRORS2) => {
2
+ ERRORS2["BAD_REQUEST"] = "BadRequest";
3
+ ERRORS2["CHECKSUM_MISMATCH"] = "ChecksumMismatch";
4
+ ERRORS2["FILE_CONFLICT"] = "FileConflict";
5
+ ERRORS2["FILE_ERROR"] = "FileError";
6
+ ERRORS2["FILE_LOCKED"] = "FileLocked";
7
+ ERRORS2["FILE_NOT_ALLOWED"] = "FileNotAllowed";
8
+ ERRORS2["FILE_NOT_FOUND"] = "FileNotFound";
9
+ ERRORS2["FORBIDDEN"] = "Forbidden";
10
+ ERRORS2["GONE"] = "Gone";
11
+ ERRORS2["INVALID_FILE_NAME"] = "InvalidFileName";
12
+ ERRORS2["INVALID_FILE_SIZE"] = "InvalidFileSize";
13
+ ERRORS2["INVALID_RANGE"] = "InvalidRange";
14
+ ERRORS2["INVALID_TYPE"] = "Invalidtype";
15
+ ERRORS2["METHOD_NOT_ALLOWED"] = "MethodNotAllowed";
16
+ ERRORS2["REQUEST_ABORTED"] = "RequestAborted";
17
+ ERRORS2["REQUEST_ENTITY_TOO_LARGE"] = "RequestEntityTooLarge";
18
+ ERRORS2["STORAGE_BUSY"] = "StorageBusy";
19
+ ERRORS2["STORAGE_ERROR"] = "StorageError";
20
+ ERRORS2["TOO_MANY_REQUESTS"] = "TooManyRequests";
21
+ ERRORS2["UNKNOWN_ERROR"] = "UnknownError";
22
+ ERRORS2["UNPROCESSABLE_ENTITY"] = "UnprocessableEntity";
23
+ ERRORS2["UNSUPPORTED_CHECKSUM_ALGORITHM"] = "UnsupportedChecksumAlgorithm";
24
+ ERRORS2["UNSUPPORTED_MEDIA_TYPE"] = "UnsupportedMediaType";
25
+ return ERRORS2;
26
+ })(ERRORS || {});
27
+ const ErrorMap = (() => {
28
+ const errors = {
29
+ BadRequest: [400, "Bad request"],
30
+ ChecksumMismatch: [460, "Checksum mismatch"],
31
+ FileConflict: [409, "File conflict"],
32
+ FileError: [500, "Something went wrong writing the file"],
33
+ FileLocked: [423, "File locked"],
34
+ FileNotAllowed: [403, "File not allowed"],
35
+ FileNotFound: [404, "Not found"],
36
+ Forbidden: [403, "Authenticated user is not allowed access"],
37
+ Gone: [410, "The file for this url no longer exists"],
38
+ InvalidFileName: [400, "Invalid file name or it cannot be retrieved"],
39
+ InvalidFileSize: [400, "File size cannot be retrieved"],
40
+ InvalidRange: [400, "Invalid or missing content-range header"],
41
+ Invalidtype: [400, 'Invalid or missing "content-type" header'],
42
+ MethodNotAllowed: [405, "Method not allowed"],
43
+ RequestAborted: [499, "Request aborted"],
44
+ RequestEntityTooLarge: [413, "Request entity too large"],
45
+ StorageBusy: [503, "Storage is busy"],
46
+ StorageError: [503, "Storage error"],
47
+ TooManyRequests: [429, "Too many requests"],
48
+ UnknownError: [500, "Something went wrong"],
49
+ UnprocessableEntity: [422, "Validation failed"],
50
+ UnsupportedChecksumAlgorithm: [400, "Unsupported checksum algorithm"],
51
+ UnsupportedMediaType: [415, "Unsupported media type"]
52
+ };
53
+ const errorMap = {};
54
+ Object.keys(errors).forEach((code) => {
55
+ const [statusCode, message] = errors[code];
56
+ errorMap[code] = { code, message, statusCode };
57
+ });
58
+ return errorMap;
59
+ })();
60
+ class UploadError extends Error {
61
+ name = "UploadError";
62
+ /** The standardized error code from the ERRORS enum */
63
+ UploadErrorCode = "UnknownError" /* UNKNOWN_ERROR */;
64
+ /** Optional additional error details */
65
+ detail;
66
+ /**
67
+ * Creates a new UploadError instance.
68
+ * @param code Standardized error code (defaults to UNKNOWN_ERROR)
69
+ * @param message Human-readable error message (defaults to the code)
70
+ * @param detail Optional additional error details
71
+ */
72
+ constructor(code = "UnknownError" /* UNKNOWN_ERROR */, message, detail) {
73
+ super(message || code);
74
+ this.name = "UploadError";
75
+ this.detail = detail;
76
+ if (Object.values(ERRORS).includes(code)) {
77
+ this.UploadErrorCode = code;
78
+ }
79
+ }
80
+ }
81
+ const isUploadError = (error) => !!error.UploadErrorCode;
82
+ const throwErrorCode = (UploadErrorCode, detail) => {
83
+ const errorCode = UploadErrorCode;
84
+ let errorResponse;
85
+ if (errorCode && typeof errorCode === "string" && errorCode in ErrorMap) {
86
+ errorResponse = ErrorMap[errorCode];
87
+ }
88
+ const message = detail || (errorResponse?.body && typeof errorResponse.body === "object" && "message" in errorResponse.body ? errorResponse.body.message : void 0) || errorResponse?.message || "UnknownError" /* UNKNOWN_ERROR */;
89
+ const error = new UploadError(errorCode, message);
90
+ error.UploadErrorCode = errorCode;
91
+ if (typeof detail === "string") {
92
+ error.detail = detail;
93
+ }
94
+ throw error;
95
+ };
96
+
97
+ export { ERRORS, ErrorMap, UploadError, isUploadError, throwErrorCode };
@@ -0,0 +1,69 @@
1
+ import fnv1a from '@sindresorhus/fnv1a';
2
+ import { nanoid } from 'nanoid';
3
+
4
+ const hash = (value) => fnv1a(value, { size: 64 }).toString(16);
5
+ const extractMimeType = (meta) => {
6
+ if (typeof meta.mimeType === "string") {
7
+ return meta.mimeType;
8
+ }
9
+ if (typeof meta.type === "string") {
10
+ return meta.type;
11
+ }
12
+ if (typeof meta.filetype === "string") {
13
+ return meta.filetype;
14
+ }
15
+ return void 0;
16
+ };
17
+ const extractOriginalName = (meta) => {
18
+ if (typeof meta.name === "string") {
19
+ return meta.name;
20
+ }
21
+ if (typeof meta.title === "string") {
22
+ return meta.title;
23
+ }
24
+ if (typeof meta.originalName === "string") {
25
+ return meta.originalName;
26
+ }
27
+ if (typeof meta.filename === "string") {
28
+ return meta.filename;
29
+ }
30
+ return void 0;
31
+ };
32
+ const generateFileId = (file) => {
33
+ const { metadata, originalName, size } = file;
34
+ const mtime = String(metadata.lastModified ?? Date.now());
35
+ return [originalName, size, mtime].filter(Boolean).map(String).map((value) => hash(value)).join("-");
36
+ };
37
+ class File {
38
+ bytesWritten = Number.NaN;
39
+ contentType;
40
+ originalName;
41
+ id;
42
+ metadata;
43
+ name = "";
44
+ size;
45
+ status;
46
+ expiredAt;
47
+ createdAt;
48
+ modifiedAt;
49
+ hash;
50
+ content;
51
+ ETag;
52
+ constructor({ contentType, expiredAt, metadata = {}, originalName, size }) {
53
+ this.metadata = metadata;
54
+ this.originalName = originalName || extractOriginalName(metadata) || (this.id = nanoid());
55
+ this.contentType = contentType || extractMimeType(metadata) || "application/octet-stream";
56
+ this.expiredAt = expiredAt;
57
+ if (typeof size === "string" || typeof size === "number") {
58
+ this.size = Number(size);
59
+ } else if (typeof metadata.size === "string" || typeof metadata.size === "number") {
60
+ this.size = Number(metadata.size);
61
+ }
62
+ if (typeof this.size === "number" && this.size <= 0) {
63
+ this.size = void 0;
64
+ }
65
+ this.id ||= generateFileId(this);
66
+ }
67
+ }
68
+
69
+ export { File as default };
@@ -0,0 +1,11 @@
1
+ const GCSConfig = {
2
+ authScopes: [
3
+ "https://www.googleapis.com/auth/iam",
4
+ "https://www.googleapis.com/auth/cloud-platform",
5
+ "https://www.googleapis.com/auth/devstorage.full_control"
6
+ ],
7
+ storageAPI: "https://storage.googleapis.com/storage/v1/b",
8
+ uploadAPI: "https://storage.googleapis.com/upload/storage/v1/b"
9
+ };
10
+
11
+ export { GCSConfig as default };
@@ -0,0 +1,8 @@
1
+ import File from './File-Bb3P23dr.js';
2
+
3
+ class GCSFile extends File {
4
+ GCSUploadURI;
5
+ uri;
6
+ }
7
+
8
+ export { GCSFile as default };
@@ -0,0 +1,7 @@
1
+ import 'node:crypto';
2
+ import 'gaxios';
3
+ import 'google-auth-library';
4
+ export { G as default } from './gcs-meta-storage-B0Baj0Xr.js';
5
+ import './MetaStorage-pECeFOad.js';
6
+ import './Metadata-DRLXeJ0F.js';
7
+ import './GCSConfig-vPP22kN6.js';