@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,810 @@
1
+ import { createReadStream, createWriteStream } from 'node:fs';
2
+ import { truncate, stat as stat$1, copyFile as copyFile$1 } from 'node:fs/promises';
3
+ import { PassThrough, Transform, pipeline } from 'node:stream';
4
+ import { g as getDefaultExportFromCjs } from './_commonjsHelpers-B85MJLTf.js';
5
+ import require$$0 from 'crypto';
6
+ import require$$1 from 'fs';
7
+ import { g as getFileStatus, p as partMatch, d as detectFileTypeFromStream } from './part-match-BMNqHDYD.js';
8
+ import { throwErrorCode, isUploadError, ERRORS } from './ERRORS-D0apMqnc.js';
9
+ import { createHash } from 'node:crypto';
10
+ import { B as BaseStorage, a as defaultFilesystemFileNameValidation, t as toMilliseconds } from './storage-C6NSXb8h.js';
11
+ import { a as assertValidFileOrDirectoryPath, g as getFileInfoType, e as ensureDir, t as toPath, i as isAccessible, L as LocalMetaStorage, b as readFile, r as remove } from './local-meta-storage-By-3SNBI.js';
12
+ import File from './File-Bb3P23dr.js';
13
+ import { createRequire } from 'node:module';
14
+ import { d as dirname, r as resolve, j as join, n as normalize, b as basename, i as isAbsolute } from './path-CR6YkPXX-7R1-9CMk.js';
15
+ import { u as updateSize } from './update-size-CCGm6i1J.js';
16
+ import { h as hasContent } from './has-content-CY66ehMK.js';
17
+
18
+ const __cjs_require$2 = createRequire(import.meta.url);
19
+ const __cjs_getProcess$2 = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
20
+ const __cjs_getBuiltinModule$2 = (module) => {
21
+ if (typeof __cjs_getProcess$2 !== "undefined" && __cjs_getProcess$2.versions && __cjs_getProcess$2.versions.node) {
22
+ const [major, minor] = __cjs_getProcess$2.versions.node.split(".").map(Number);
23
+ if (major > 22 || major === 22 && minor >= 3 || major === 20 && minor >= 16) {
24
+ return __cjs_getProcess$2.getBuiltinModule(module);
25
+ }
26
+ }
27
+ return __cjs_require$2(module);
28
+ };
29
+ const {
30
+ lstat,
31
+ writeFile
32
+ } = __cjs_getBuiltinModule$2("node:fs/promises");
33
+ const ensureFile = async (filePath) => {
34
+ assertValidFileOrDirectoryPath(filePath);
35
+ try {
36
+ const stat = await lstat(filePath);
37
+ if (!stat.isFile()) {
38
+ throw new Error(`Ensure path exists, expected 'file', got '${getFileInfoType(stat)}'`);
39
+ }
40
+ } catch (error) {
41
+ if (error.code === "ENOENT") {
42
+ await ensureDir(dirname(toPath(filePath)));
43
+ await writeFile(filePath, new Uint8Array());
44
+ return;
45
+ }
46
+ throw error;
47
+ }
48
+ };
49
+
50
+ class WalkError extends Error {
51
+ /** File path of the root that's being walked. */
52
+ root;
53
+ /**
54
+ * Constructs a new instance.
55
+ * @param cause The underlying error or reason for the walk failure.
56
+ * @param root The root directory path where the walk operation started or encountered the error.
57
+ */
58
+ constructor(cause, root) {
59
+ super(`${cause instanceof Error ? cause.message : cause} for path "${root}"`);
60
+ this.cause = cause;
61
+ this.root = root;
62
+ }
63
+ // eslint-disable-next-line class-methods-use-this
64
+ get name() {
65
+ return "WalkError";
66
+ }
67
+ // eslint-disable-next-line class-methods-use-this,@typescript-eslint/explicit-module-boundary-types
68
+ set name(_name) {
69
+ throw new Error("Cannot overwrite name of WalkError");
70
+ }
71
+ }
72
+
73
+ const globToRegExp = (glob) => {
74
+ const reString = glob.replace(/\.\*/g, ".([^/]*)").replace(/\*\*/g, "(.*)").replace(/(?<!\.)\*(?!\*)/g, "([^/]*)").replace(/\?/g, "[^/]").replace(/\.(?!\*)/g, String.raw`\.`).replace(/\{/g, "(").replace(/\}/g, ")").replace(/,/g, "|").replace(/\[!(.*?)\]/g, "[^$1]");
75
+ return new RegExp(`^${reString}$`);
76
+ };
77
+ const walkInclude = (path, extensions, match, skip) => {
78
+ if (Array.isArray(extensions) && extensions.length > 0 && !extensions.some((extension) => path.endsWith(extension))) {
79
+ return false;
80
+ }
81
+ if (match && !match.some((pattern) => pattern.test(path))) {
82
+ return false;
83
+ }
84
+ return !skip?.some((pattern) => pattern.test(path));
85
+ };
86
+
87
+ const __cjs_require$1 = createRequire(import.meta.url);
88
+ const __cjs_getProcess$1 = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
89
+ const __cjs_getBuiltinModule$1 = (module) => {
90
+ if (typeof __cjs_getProcess$1 !== "undefined" && __cjs_getProcess$1.versions && __cjs_getProcess$1.versions.node) {
91
+ const [major, minor] = __cjs_getProcess$1.versions.node.split(".").map(Number);
92
+ if (major > 22 || major === 22 && minor >= 3 || major === 20 && minor >= 16) {
93
+ return __cjs_getProcess$1.getBuiltinModule(module);
94
+ }
95
+ }
96
+ return __cjs_require$1(module);
97
+ };
98
+ const {
99
+ readdir,
100
+ realpath,
101
+ stat
102
+ } = __cjs_getBuiltinModule$1("node:fs/promises");
103
+ const _createWalkEntry = async (path) => {
104
+ const normalizePath = normalize(path);
105
+ const name = basename(normalizePath);
106
+ const info = await stat(normalizePath);
107
+ return {
108
+ isDirectory: () => info.isDirectory(),
109
+ isFile: () => info.isFile(),
110
+ isSymbolicLink: () => info.isSymbolicLink(),
111
+ name,
112
+ path: normalizePath
113
+ };
114
+ };
115
+ async function* walk(directory, {
116
+ extensions,
117
+ followSymlinks = false,
118
+ includeDirs: includeDirectories = true,
119
+ includeFiles = true,
120
+ includeSymlinks = true,
121
+ match,
122
+ maxDepth = Number.POSITIVE_INFINITY,
123
+ skip
124
+ } = {}) {
125
+ assertValidFileOrDirectoryPath(directory);
126
+ if (maxDepth < 0) {
127
+ return;
128
+ }
129
+ const mappedMatch = match ? match.map((pattern) => typeof pattern === "string" ? globToRegExp(pattern) : pattern) : void 0;
130
+ const mappedSkip = skip ? skip.map((pattern) => typeof pattern === "string" ? globToRegExp(pattern) : pattern) : void 0;
131
+ directory = resolve(toPath(directory));
132
+ if (includeDirectories && walkInclude(directory, extensions, mappedMatch, mappedSkip)) {
133
+ yield await _createWalkEntry(directory);
134
+ }
135
+ if (maxDepth < 1 || !walkInclude(directory, void 0, void 0, mappedSkip)) {
136
+ return;
137
+ }
138
+ try {
139
+ for await (const entry of await readdir(directory, {
140
+ withFileTypes: true
141
+ })) {
142
+ let path = join(directory, entry.name);
143
+ if (entry.isSymbolicLink()) {
144
+ if (followSymlinks) {
145
+ path = await realpath(path);
146
+ } else if (includeSymlinks && walkInclude(path, extensions, mappedMatch, mappedSkip)) {
147
+ yield {
148
+ isDirectory: entry.isDirectory,
149
+ isFile: entry.isFile,
150
+ isSymbolicLink: entry.isSymbolicLink,
151
+ name: entry.name,
152
+ path
153
+ };
154
+ } else {
155
+ continue;
156
+ }
157
+ }
158
+ if (entry.isSymbolicLink() || entry.isDirectory()) {
159
+ yield* walk(path, {
160
+ extensions,
161
+ followSymlinks,
162
+ includeDirs: includeDirectories,
163
+ includeFiles,
164
+ includeSymlinks,
165
+ match: mappedMatch,
166
+ maxDepth: maxDepth - 1,
167
+ skip: mappedSkip
168
+ });
169
+ } else if (entry.isFile() && includeFiles && walkInclude(path, extensions, mappedMatch, mappedSkip)) {
170
+ yield {
171
+ isDirectory: () => entry.isDirectory(),
172
+ isFile: () => entry.isFile(),
173
+ isSymbolicLink: () => entry.isSymbolicLink(),
174
+ name: entry.name,
175
+ path
176
+ };
177
+ }
178
+ }
179
+ } catch (error) {
180
+ if (error instanceof WalkError) {
181
+ throw error;
182
+ }
183
+ throw new WalkError(error, directory);
184
+ }
185
+ }
186
+
187
+ const __cjs_require = createRequire(import.meta.url);
188
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
189
+ const __cjs_getBuiltinModule = (module) => {
190
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
191
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
192
+ if (major > 22 || major === 22 && minor >= 3 || major === 20 && minor >= 16) {
193
+ return __cjs_getProcess.getBuiltinModule(module);
194
+ }
195
+ }
196
+ return __cjs_require(module);
197
+ };
198
+ const {
199
+ cwd
200
+ } = __cjs_getProcess;
201
+ const {
202
+ mkdir,
203
+ rename: rename$1,
204
+ copyFile,
205
+ unlink
206
+ } = __cjs_getBuiltinModule("node:fs/promises");
207
+ __cjs_getBuiltinModule("node:fs");
208
+ class SameDirectoryError extends Error {
209
+ constructor(source, destination) {
210
+ super(`Source directory "${dirname(source)}" does not match destination directory "${dirname(destination)}"`);
211
+ this.name = "SameDirectoryError";
212
+ }
213
+ }
214
+ const validateSameDirectory = (source, destination) => {
215
+ if (!source || !destination) {
216
+ throw new Error("Source and destination paths must not be empty");
217
+ }
218
+ if (dirname(source) !== dirname(destination)) {
219
+ throw new SameDirectoryError(source, destination);
220
+ }
221
+ };
222
+ const internalMoveFile = async (sourcePath, destinationPath, { cwd: cwd2, directoryMode, overwrite, validateDirectory }) => {
223
+ if (cwd2) {
224
+ sourcePath = resolve(cwd2, sourcePath);
225
+ destinationPath = resolve(cwd2, destinationPath);
226
+ }
227
+ if (validateDirectory) {
228
+ validateSameDirectory(sourcePath, destinationPath);
229
+ }
230
+ if (!overwrite && await isAccessible(destinationPath)) {
231
+ throw new Error(`The destination file exists: ${destinationPath}`);
232
+ }
233
+ await mkdir(dirname(destinationPath), {
234
+ mode: directoryMode,
235
+ recursive: true
236
+ });
237
+ try {
238
+ await rename$1(sourcePath, destinationPath);
239
+ } catch (error) {
240
+ if (error.code === "EXDEV") {
241
+ await copyFile(sourcePath, destinationPath);
242
+ await unlink(sourcePath);
243
+ } else {
244
+ throw error;
245
+ }
246
+ }
247
+ };
248
+ const move = async (sourcePath, destinationPath, options = {}) => {
249
+ const internalOptions = {
250
+ overwrite: true,
251
+ validateDirectory: false,
252
+ ...options,
253
+ cwd: options.cwd ? toPath(options.cwd) : cwd()
254
+ };
255
+ await internalMoveFile(sourcePath, destinationPath, internalOptions);
256
+ };
257
+
258
+ var etag_1;
259
+ var hasRequiredEtag;
260
+
261
+ function requireEtag () {
262
+ if (hasRequiredEtag) return etag_1;
263
+ hasRequiredEtag = 1;
264
+ /*!
265
+ * etag
266
+ * Copyright(c) 2014-2016 Douglas Christopher Wilson
267
+ * MIT Licensed
268
+ */
269
+ etag_1 = etag;
270
+ var crypto = require$$0;
271
+ var Stats = require$$1.Stats;
272
+ var toString = Object.prototype.toString;
273
+ function entitytag(entity) {
274
+ if (entity.length === 0) {
275
+ return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
276
+ }
277
+ var hash = crypto.createHash("sha1").update(entity, "utf8").digest("base64").substring(0, 27);
278
+ var len = typeof entity === "string" ? Buffer.byteLength(entity, "utf8") : entity.length;
279
+ return '"' + len.toString(16) + "-" + hash + '"';
280
+ }
281
+ function etag(entity, options) {
282
+ if (entity == null) {
283
+ throw new TypeError("argument entity is required");
284
+ }
285
+ var isStats = isstats(entity);
286
+ var weak = options && typeof options.weak === "boolean" ? options.weak : isStats;
287
+ if (!isStats && typeof entity !== "string" && !Buffer.isBuffer(entity)) {
288
+ throw new TypeError("argument entity must be string, Buffer, or fs.Stats");
289
+ }
290
+ var tag = isStats ? stattag(entity) : entitytag(entity);
291
+ return weak ? "W/" + tag : tag;
292
+ }
293
+ function isstats(obj) {
294
+ if (typeof Stats === "function" && obj instanceof Stats) {
295
+ return true;
296
+ }
297
+ return obj && typeof obj === "object" && "ctime" in obj && toString.call(obj.ctime) === "[object Date]" && "mtime" in obj && toString.call(obj.mtime) === "[object Date]" && "ino" in obj && typeof obj.ino === "number" && "size" in obj && typeof obj.size === "number";
298
+ }
299
+ function stattag(stat) {
300
+ var mtime = stat.mtime.getTime().toString(16);
301
+ var size = stat.size.toString(16);
302
+ return '"' + size + "-" + mtime + '"';
303
+ }
304
+ return etag_1;
305
+ }
306
+
307
+ var etagExports = requireEtag();
308
+ const etag = /*@__PURE__*/getDefaultExportFromCjs(etagExports);
309
+
310
+ class StreamChecksum extends Transform {
311
+ /**
312
+ * Creates a new StreamChecksum transform stream.
313
+ * @param checksum Expected checksum value to validate against
314
+ * @param algorithm Hash algorithm to use (e.g., 'md5', 'sha256')
315
+ * @param encoding Encoding for the checksum comparison (defaults to 'base64')
316
+ */
317
+ constructor(checksum, algorithm, encoding = "base64") {
318
+ super();
319
+ this.checksum = checksum;
320
+ this.algorithm = algorithm;
321
+ this.encoding = encoding;
322
+ this.hash = createHash(algorithm);
323
+ }
324
+ length = 0;
325
+ digest = "";
326
+ hash;
327
+ /**
328
+ * Gets the calculated digest value after the stream has finished processing.
329
+ * @returns The digest value in the configured encoding, or empty string if not yet calculated
330
+ */
331
+ get calculatedDigest() {
332
+ return this.digest;
333
+ }
334
+ /**
335
+ * Transform method that updates the hash with incoming data.
336
+ * @param chunk Buffer chunk to process
337
+ * @param _encoding Unused encoding parameter
338
+ * @param done Callback to signal completion
339
+ */
340
+ // eslint-disable-next-line no-underscore-dangle
341
+ _transform(chunk, _encoding, done) {
342
+ this.push(chunk);
343
+ this.hash.update(chunk);
344
+ this.length += chunk.length;
345
+ done();
346
+ }
347
+ /**
348
+ * Finalization method that validates the checksum.
349
+ * @param callback Callback called with error if checksum validation fails
350
+ */
351
+ // eslint-disable-next-line no-underscore-dangle
352
+ _flush(callback) {
353
+ this.digest = this.hash.digest(this.encoding);
354
+ if (this.checksum && this.checksum !== this.digest) {
355
+ callback(new Error("Checksum mismatch"));
356
+ } else {
357
+ callback();
358
+ }
359
+ }
360
+ }
361
+ const streamChecksum = (checksum, algorithm, encoding = "base64") => algorithm ? new StreamChecksum(checksum, algorithm, encoding) : new PassThrough();
362
+
363
+ class StreamLength extends Transform {
364
+ /**
365
+ * Creates a new StreamLength transform stream.
366
+ * @param limit Maximum number of bytes allowed (defaults to infinity)
367
+ */
368
+ constructor(limit = Number.POSITIVE_INFINITY) {
369
+ super();
370
+ this.limit = limit;
371
+ }
372
+ length = 0;
373
+ /**
374
+ * Transform method that counts bytes and enforces size limits.
375
+ * @param chunk Buffer chunk to process
376
+ * @param _encoding Unused encoding parameter
377
+ * @param callback Callback called with error if limit exceeded
378
+ */
379
+ // eslint-disable-next-line no-underscore-dangle
380
+ _transform(chunk, _encoding, callback) {
381
+ const expected = this.length + chunk.length;
382
+ if (this.limit >= expected) {
383
+ this.push(chunk);
384
+ this.length = expected;
385
+ callback();
386
+ } else {
387
+ callback(new Error("Stream length limit exceeded"));
388
+ }
389
+ }
390
+ }
391
+
392
+ class DiskStorage extends BaseStorage {
393
+ static name = "disk";
394
+ checksumTypes = ["md5", "sha1"];
395
+ directory;
396
+ meta;
397
+ constructor(config) {
398
+ super(config);
399
+ this.directory = config.directory;
400
+ if (config.metaStorage) {
401
+ this.meta = config.metaStorage;
402
+ } else {
403
+ const metaConfig = { ...config, ...config.metaStorageConfig, logger: this.logger };
404
+ this.meta = new LocalMetaStorage(metaConfig);
405
+ }
406
+ if (!config.fileNameValidation) {
407
+ config.fileNameValidation = defaultFilesystemFileNameValidation;
408
+ }
409
+ this.isReady = false;
410
+ this.accessCheck().then(() => {
411
+ this.isReady = true;
412
+ return void 0;
413
+ }).catch((error) => {
414
+ this.logger?.error("Storage access check failed: %O", error);
415
+ });
416
+ }
417
+ /**
418
+ * Normalizes errors with disk storage context.
419
+ * @param error The error to normalize.
420
+ * @returns Normalized HTTP error.
421
+ */
422
+ normalizeError(error) {
423
+ return super.normalizeError(error);
424
+ }
425
+ /**
426
+ * Creates a new file upload and saves its metadata.
427
+ * @param fileInit File initialization configuration.
428
+ * @returns Promise resolving to the created file object.
429
+ * @throws {Error} If validation fails or file already exists and is completed.
430
+ * @remarks
431
+ * Supports TTL (time-to-live) option in fileInit.
432
+ * Creates the file on disk if it doesn't exist.
433
+ * Returns existing file if it's already completed.
434
+ */
435
+ async create(fileInit) {
436
+ return this.instrumentOperation("create", async () => {
437
+ const processedConfig = { ...fileInit };
438
+ if (fileInit.ttl) {
439
+ const ttlMs = typeof fileInit.ttl === "string" ? toMilliseconds(fileInit.ttl) : fileInit.ttl;
440
+ if (ttlMs !== void 0) {
441
+ processedConfig.expiredAt = Date.now() + ttlMs;
442
+ }
443
+ }
444
+ if (processedConfig.size !== void 0 && Number(processedConfig.size) < 0) {
445
+ throwErrorCode(ERRORS.REQUEST_ENTITY_TOO_LARGE, "Request entity too large");
446
+ }
447
+ const file = new File(processedConfig);
448
+ try {
449
+ const existing = await this.getMeta(file.id);
450
+ if (existing.status === "completed") {
451
+ return existing;
452
+ }
453
+ } catch {
454
+ }
455
+ file.name = this.namingFunction(file);
456
+ if (file.size === void 0 || Number.isNaN(file.size)) {
457
+ if (file.size === void 0) ; else {
458
+ file.size = this.maxUploadSize;
459
+ }
460
+ }
461
+ await this.validate(file);
462
+ const path = this.getFilePath(file.name);
463
+ try {
464
+ await ensureFile(path);
465
+ file.bytesWritten = 0;
466
+ } catch (error) {
467
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
468
+ await this.onError(httpError);
469
+ throwErrorCode(ERRORS.FILE_ERROR, httpError.message);
470
+ }
471
+ file.status = getFileStatus(file);
472
+ await this.saveMeta(file);
473
+ await this.onCreate(file);
474
+ return file;
475
+ });
476
+ }
477
+ /**
478
+ * Writes data to a file upload.
479
+ * @param part File part containing data to write, file query, or full file object.
480
+ * @returns Promise resolving to the updated file object.
481
+ * @throws {Error} If file is expired (ERRORS.GONE), locked (ERRORS.FILE_LOCKED), or conflicts occur (ERRORS.FILE_CONFLICT).
482
+ * @remarks
483
+ * Supports chunked uploads with start position.
484
+ * Automatically detects file type from stream on first chunk if contentType is not set.
485
+ * Validates checksum algorithms if provided.
486
+ * Uses file locking to prevent concurrent writes.
487
+ * Updates file status to "completed" when all bytes are written.
488
+ */
489
+ async write(part) {
490
+ return this.instrumentOperation("write", async () => {
491
+ let file;
492
+ const isFullFile = "contentType" in part && "metadata" in part && !("body" in part) && !("start" in part);
493
+ if (isFullFile) {
494
+ file = part;
495
+ } else {
496
+ file = await this.getMeta(part.id);
497
+ await this.checkIfExpired(file);
498
+ }
499
+ if (file.status === "completed") {
500
+ return file;
501
+ }
502
+ if (part.size !== void 0) {
503
+ updateSize(file, part.size);
504
+ }
505
+ if (!partMatch(part, file)) {
506
+ return throwErrorCode(ERRORS.FILE_CONFLICT);
507
+ }
508
+ const path = this.getFilePath(file.name);
509
+ await this.lock(path);
510
+ try {
511
+ const startPosition = part.start || 0;
512
+ await ensureFile(path);
513
+ if (file.bytesWritten === 0) {
514
+ file.bytesWritten = startPosition;
515
+ }
516
+ if (hasContent(part)) {
517
+ if (this.isUnsupportedChecksum(part.checksumAlgorithm)) {
518
+ return throwErrorCode(ERRORS.UNSUPPORTED_CHECKSUM_ALGORITHM);
519
+ }
520
+ const isFirstChunk = part.start === 0 || part.start === void 0;
521
+ if (isFirstChunk && (file.bytesWritten === 0 || Number.isNaN(file.bytesWritten)) && (!file.contentType || file.contentType === "application/octet-stream")) {
522
+ try {
523
+ const { fileType, stream: detectedStream } = await detectFileTypeFromStream(part.body);
524
+ if (fileType?.mime) {
525
+ file.contentType = fileType.mime;
526
+ }
527
+ part.body = detectedStream;
528
+ } catch {
529
+ }
530
+ }
531
+ const signalFromPart = part.signal;
532
+ const lazyWritePart = { ...file, ...part, body: part.body };
533
+ if (signalFromPart) {
534
+ lazyWritePart.signal = signalFromPart;
535
+ }
536
+ const [bytesWritten, errorCode] = await this.lazyWrite(lazyWritePart);
537
+ if (errorCode) {
538
+ await truncate(path, file.bytesWritten);
539
+ return throwErrorCode(errorCode);
540
+ }
541
+ const expectedBytesWritten = startPosition + (part.contentLength || 0);
542
+ file.bytesWritten = Math.max(file.bytesWritten || 0, expectedBytesWritten);
543
+ file.bytesWritten = Math.max(file.bytesWritten || 0, bytesWritten);
544
+ file.status = getFileStatus(file);
545
+ await this.saveMeta(file);
546
+ } else {
547
+ await ensureFile(path);
548
+ file.bytesWritten = 0;
549
+ }
550
+ return file;
551
+ } catch (error) {
552
+ if (isUploadError(error)) {
553
+ throw error;
554
+ }
555
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
556
+ await this.onError(httpError);
557
+ return throwErrorCode(ERRORS.FILE_ERROR, (typeof httpError.message === "string" ? httpError.message : String(error)) || String(error));
558
+ } finally {
559
+ await this.unlock(path);
560
+ }
561
+ });
562
+ }
563
+ /**
564
+ * Gets an uploaded file by ID.
565
+ * @param query File query containing the file ID to retrieve.
566
+ * @param query.id File ID to retrieve.
567
+ * @returns Promise resolving to the file data including content buffer.
568
+ * @throws {Error} If the file cannot be found (ERRORS.FILE_NOT_FOUND) or has expired (ERRORS.GONE).
569
+ * @remarks
570
+ * Loads the entire file content into memory as a Buffer.
571
+ * For large files, consider using getStream() instead.
572
+ * Includes ETag (MD5 hash) for content verification.
573
+ */
574
+ async get({ id }) {
575
+ return this.instrumentOperation("get", async () => {
576
+ const file = await this.checkIfExpired(await this.meta.get(id));
577
+ const { bytesWritten, contentType, expiredAt, metadata, modifiedAt, name, originalName, size } = file;
578
+ let content;
579
+ try {
580
+ content = await readFile(this.getFilePath(name), { buffer: true });
581
+ } catch (error) {
582
+ const errorWithCode = error;
583
+ if (errorWithCode.code === "ENOENT" || errorWithCode.code === "EPERM") {
584
+ const httpError2 = this.normalizeError(error instanceof Error ? error : new Error(errorWithCode.message || String(error)));
585
+ await this.onError(httpError2);
586
+ return throwErrorCode(ERRORS.FILE_NOT_FOUND, (typeof httpError2.message === "string" ? httpError2.message : String(error)) || String(error));
587
+ }
588
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
589
+ await this.onError(httpError);
590
+ throw error;
591
+ }
592
+ return {
593
+ content,
594
+ contentType,
595
+ ETag: etag(content),
596
+ expiredAt,
597
+ id,
598
+ metadata,
599
+ modifiedAt,
600
+ name,
601
+ originalName,
602
+ size: size || bytesWritten
603
+ };
604
+ });
605
+ }
606
+ /**
607
+ * Checks if a file exists by verifying both metadata and the actual filesystem file.
608
+ * Returns true only if both the metadata and the file exist.
609
+ * @param query File query containing the file ID to check.
610
+ * @returns Promise resolving to true if both metadata and file exist, false otherwise.
611
+ */
612
+ async exists({ id }) {
613
+ return this.instrumentOperation("exists", async () => {
614
+ try {
615
+ const file = await this.getMeta(id);
616
+ const filePath = this.getFilePath(file.name);
617
+ await stat$1(filePath);
618
+ return true;
619
+ } catch (error) {
620
+ const errorWithCode = error;
621
+ if (errorWithCode.code === "ENOENT") {
622
+ return false;
623
+ }
624
+ return false;
625
+ }
626
+ });
627
+ }
628
+ /**
629
+ * Gets an uploaded file as a readable stream for efficient large file handling.
630
+ * @param query File query containing the file ID to stream.
631
+ * @param query.id File ID to stream.
632
+ * @returns Promise resolving to an object containing the stream, headers, and size.
633
+ * @throws {UploadError} If the file cannot be found (ERRORS.FILE_NOT_FOUND) or has expired (ERRORS.GONE).
634
+ * @remarks Creates a readable stream directly from the file system for efficient memory usage.
635
+ */
636
+ async getStream({ id }) {
637
+ return this.instrumentOperation("getStream", async () => {
638
+ try {
639
+ const file = await this.checkIfExpired(await this.meta.get(id));
640
+ const { bytesWritten, contentType, expiredAt, modifiedAt, name, size } = file;
641
+ const stream = createReadStream(this.getFilePath(name));
642
+ return {
643
+ headers: {
644
+ "Content-Length": String(size || bytesWritten),
645
+ "Content-Type": contentType,
646
+ ...expiredAt && { "X-Upload-Expires": expiredAt.toString() },
647
+ ...modifiedAt && { "Last-Modified": modifiedAt.toString() }
648
+ // Note: ETag requires reading the file content, so we don't include it for streaming
649
+ // Clients can use HEAD requests to get ETag if needed
650
+ },
651
+ size: size || bytesWritten,
652
+ stream
653
+ };
654
+ } catch (error) {
655
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
656
+ await this.onError(httpError);
657
+ throw throwErrorCode(ERRORS.FILE_NOT_FOUND, (typeof httpError.message === "string" ? httpError.message : String(error)) || String(error));
658
+ }
659
+ });
660
+ }
661
+ /**
662
+ * Deletes an upload and its metadata.
663
+ * @param query File query containing the file ID to delete.
664
+ * @param query.id File ID to delete.
665
+ * @returns Promise resolving to the deleted file object with status: "deleted".
666
+ * @throws {UploadError} If the file metadata cannot be found.
667
+ */
668
+ async delete({ id }) {
669
+ return this.instrumentOperation("delete", async () => {
670
+ const file = await this.getMeta(id);
671
+ await remove(this.getFilePath(file.name));
672
+ await this.deleteMeta(id);
673
+ const deletedFile = { ...file, status: "deleted" };
674
+ await this.onDelete(deletedFile);
675
+ return deletedFile;
676
+ });
677
+ }
678
+ /**
679
+ * Copies an upload file to a new location.
680
+ * @param name Source file name/ID.
681
+ * @param destination Destination file name/ID.
682
+ * @returns Promise resolving to the copied file object.
683
+ * @throws {UploadError} If the source file cannot be found.
684
+ */
685
+ async copy(name, destination) {
686
+ return this.instrumentOperation("copy", async () => {
687
+ const sourceFile = await this.getMeta(name);
688
+ await copyFile$1(this.getFilePath(sourceFile.name), this.getFilePath(destination));
689
+ return { ...sourceFile, name: destination };
690
+ });
691
+ }
692
+ /**
693
+ * Moves an upload file to a new location.
694
+ * @param name Source file name/ID.
695
+ * @param destination Destination file name/ID.
696
+ * @returns Promise resolving to the moved file object.
697
+ * @throws {Error} If the source file cannot be found.
698
+ */
699
+ async move(name, destination) {
700
+ return this.instrumentOperation("move", async () => {
701
+ const sourceFile = await this.getMeta(name);
702
+ const source = this.getFilePath(sourceFile.name);
703
+ const destinationPath = this.getFilePath(destination);
704
+ try {
705
+ await move(source, destinationPath);
706
+ } catch (error) {
707
+ const errorWithCode = error;
708
+ if (errorWithCode?.code === "EXDEV") {
709
+ await copyFile$1(source, destinationPath);
710
+ await remove(source);
711
+ } else {
712
+ const httpError = this.normalizeError(error instanceof Error ? error : new Error(String(error)));
713
+ await this.onError(httpError);
714
+ throw error;
715
+ }
716
+ }
717
+ return { ...sourceFile, id: sourceFile.id, name: destination };
718
+ });
719
+ }
720
+ /**
721
+ * Retrieves a list of uploaded files.
722
+ * @returns Promise resolving to an array of file metadata objects.
723
+ * @remarks Walks the storage directory and returns all files, excluding metadata files.
724
+ */
725
+ async list() {
726
+ return this.instrumentOperation("list", async () => {
727
+ const config = {
728
+ followSymlinks: false,
729
+ includeDirs: false,
730
+ includeFiles: true,
731
+ skip: ["*.META$"]
732
+ };
733
+ const uploads = [];
734
+ const { directory } = this;
735
+ for await (const founding of walk(directory, config)) {
736
+ const { suffix } = this.meta;
737
+ const { path } = founding;
738
+ if (!path.includes(suffix)) {
739
+ const { birthtime, ctime, mtime } = await stat$1(path);
740
+ uploads.push({ createdAt: birthtime || ctime, id: path.replace(directory, ""), modifiedAt: mtime });
741
+ }
742
+ }
743
+ return uploads;
744
+ });
745
+ }
746
+ /**
747
+ * Returns path for the uploaded file
748
+ * If filename is already an absolute path, returns it as-is.
749
+ * Otherwise, joins it with the storage directory.
750
+ */
751
+ getFilePath(filename) {
752
+ if (isAbsolute(filename)) {
753
+ return filename;
754
+ }
755
+ return join(this.directory, filename);
756
+ }
757
+ lazyWrite(part) {
758
+ return new Promise((resolve, reject) => {
759
+ const destination = createWriteStream(this.getFilePath(part.name), { flags: "r+", start: part.start });
760
+ const lengthChecker = new StreamLength(part.contentLength || part.size - part.start);
761
+ const checksumChecker = streamChecksum(part.checksum, part.checksumAlgorithm);
762
+ const keepPartial = !part.checksum;
763
+ const { signal } = part;
764
+ const cleanupStreams = () => {
765
+ destination.close();
766
+ lengthChecker.destroy();
767
+ checksumChecker.destroy();
768
+ };
769
+ const failWithCode = (code) => {
770
+ cleanupStreams();
771
+ resolve([Number.NaN, code]);
772
+ };
773
+ lengthChecker.on("error", () => failWithCode(ERRORS.FILE_CONFLICT));
774
+ checksumChecker.on("error", () => failWithCode(ERRORS.CHECKSUM_MISMATCH));
775
+ part.body.on("aborted", () => failWithCode(keepPartial ? void 0 : ERRORS.REQUEST_ABORTED));
776
+ part.body.on("error", (error) => {
777
+ cleanupStreams();
778
+ reject(error);
779
+ });
780
+ if (signal?.aborted) {
781
+ return failWithCode(keepPartial ? void 0 : ERRORS.REQUEST_ABORTED);
782
+ }
783
+ if (signal) {
784
+ signal.addEventListener("abort", () => {
785
+ cleanupStreams();
786
+ destination.destroy();
787
+ lengthChecker.destroy();
788
+ checksumChecker.destroy();
789
+ part.body.destroy();
790
+ resolve([Number.NaN, keepPartial ? void 0 : ERRORS.REQUEST_ABORTED]);
791
+ });
792
+ }
793
+ pipeline(part.body, lengthChecker, checksumChecker, destination, (error) => {
794
+ if (error) {
795
+ cleanupStreams();
796
+ if (signal && signal.aborted) {
797
+ return resolve([Number.NaN, keepPartial ? void 0 : ERRORS.REQUEST_ABORTED]);
798
+ }
799
+ return resolve([Number.NaN, ERRORS.FILE_ERROR]);
800
+ }
801
+ return resolve([part.start + destination.bytesWritten]);
802
+ });
803
+ });
804
+ }
805
+ async accessCheck() {
806
+ await ensureDir(this.directory);
807
+ }
808
+ }
809
+
810
+ export { DiskStorage as D, StreamLength as S, ensureFile as e, streamChecksum as s };