@visulima/storage 1.0.0-alpha.17 → 1.0.0-alpha.19

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 (185) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE.md +3 -0
  3. package/dist/adapter/nuxt/module.d.ts +3 -3
  4. package/dist/adapter/nuxt/module.js +1 -93
  5. package/dist/handler/http/fetch/index.d.ts +6 -6
  6. package/dist/handler/http/fetch/index.js +1 -4
  7. package/dist/handler/http/hono/index.d.ts +3 -3
  8. package/dist/handler/http/hono/index.js +1 -65
  9. package/dist/handler/http/nextjs/index.d.ts +4 -4
  10. package/dist/handler/http/nextjs/index.js +1 -37
  11. package/dist/handler/http/node/index.d.ts +6 -6
  12. package/dist/handler/http/node/index.js +1 -8
  13. package/dist/handler/http/solid-start/index.d.ts +4 -4
  14. package/dist/handler/http/solid-start/index.js +1 -44
  15. package/dist/index.js +1 -13
  16. package/dist/openapi/index.js +1 -5
  17. package/dist/packem_shared/AwsLightFile-BTLiRxXj.js +1 -0
  18. package/dist/packem_shared/AwsLightMetaStorage-DHz1nf_H.js +1 -0
  19. package/dist/packem_shared/AwsLightStorage-CA9cdfJ6.js +1 -0
  20. package/dist/packem_shared/AzureFile-BKHru1zB.js +1 -0
  21. package/dist/packem_shared/AzureSMetaStorage-BqA4jUDJ.js +1 -0
  22. package/dist/packem_shared/AzureStorage-BKUjCymW.js +1 -0
  23. package/dist/packem_shared/BaseTransformer-D68eLyz1.js +1 -0
  24. package/dist/packem_shared/DiskStorage-DNjpDMX9.js +1 -0
  25. package/dist/packem_shared/DiskStorageWithChecksum-Bb6JX_tC.js +1 -0
  26. package/dist/packem_shared/ERRORS-B9jkvKwx.js +1 -0
  27. package/dist/packem_shared/File-alcSNpLq.js +1 -0
  28. package/dist/packem_shared/GCSConfig-BQ0OpVhe.js +1 -0
  29. package/dist/packem_shared/GCSFile-CHjX_fJk.js +1 -0
  30. package/dist/packem_shared/GCSMetaStorage-CpxQ8wM9.js +1 -0
  31. package/dist/packem_shared/GCStorage-DAg1V55T.js +1 -0
  32. package/dist/packem_shared/LocalMetaStorage-BWuFvWn4.js +1 -0
  33. package/dist/packem_shared/MediaTransformer-2C8MJeAg.js +1 -0
  34. package/dist/packem_shared/MetaStorage-Y4m1dWgd.js +1 -0
  35. package/dist/packem_shared/Metadata-B6Ir0KO7.js +1 -0
  36. package/dist/packem_shared/Multipart-Bd9YFFn0.js +1 -0
  37. package/dist/packem_shared/Multipart-D5bcEvga.js +1 -0
  38. package/dist/packem_shared/NetlifyBlobFile-CpzkMKng.js +1 -0
  39. package/dist/packem_shared/NetlifyBlobMetaStorage-dD0oBLom.js +1 -0
  40. package/dist/packem_shared/NetlifyBlobStorage-ByTwCN-h.js +1 -0
  41. package/dist/packem_shared/NoOpMetrics-Dky06sf1.js +1 -0
  42. package/dist/packem_shared/OpenTelemetryMetrics-9uxQMSlg.js +1 -0
  43. package/dist/packem_shared/Rest-CYEBbtCD.js +1 -0
  44. package/dist/packem_shared/Rest-DoonVU7B.js +1 -0
  45. package/dist/packem_shared/S3File-Du6wP0Sz.js +1 -0
  46. package/dist/packem_shared/S3MetaStorage-vcriiosn.js +1 -0
  47. package/dist/packem_shared/S3Storage-Fx6-OSc-.js +1 -0
  48. package/dist/packem_shared/TUS_RESUMABLE-B7KtPVeC.js +1 -0
  49. package/dist/packem_shared/Tus-Bd_2Ki2G.js +1 -0
  50. package/dist/packem_shared/Tus-CUBCkuPE.js +1 -0
  51. package/dist/packem_shared/ValidationError-D8KKJiKA.js +1 -0
  52. package/dist/packem_shared/VercelBlobFile-CL9MjKcY.js +1 -0
  53. package/dist/packem_shared/VercelBlobMetaStorage-BsOTx-Su.js +1 -0
  54. package/dist/packem_shared/VercelBlobStorage-kNkk5Cn4.js +1 -0
  55. package/dist/packem_shared/_commonjsHelpers-D6W6KoPK.js +1 -0
  56. package/dist/packem_shared/aws-light-meta-storage-TPyQwLvk.js +4 -0
  57. package/dist/packem_shared/backblaze-DEflv87m.js +1 -0
  58. package/dist/packem_shared/base-handler-core-DaggCVsq.js +1 -0
  59. package/dist/packem_shared/base-handler-fetch-DnarP64X.js +1 -0
  60. package/dist/packem_shared/base-handler-node-BTes6sql.js +1 -0
  61. package/dist/packem_shared/cache-qV_5Umeq.js +1 -0
  62. package/dist/packem_shared/cloudflare-DLAeQvgD.js +1 -0
  63. package/dist/packem_shared/defaultCloudStorageFileNameValidation-yiM9GxHr.js +1 -0
  64. package/dist/packem_shared/digitalOcean-nhZUds87.js +1 -0
  65. package/dist/packem_shared/disk-storage-BvdK4bqF.js +5 -0
  66. package/dist/packem_shared/gcs-meta-storage-CvGkpzVE.js +1 -0
  67. package/dist/packem_shared/has-content-Bx2p8Okx.js +1 -0
  68. package/dist/packem_shared/headers-DC2MEOrK.js +27 -0
  69. package/dist/packem_shared/is-expired-1JuZjDtb.js +1 -0
  70. package/dist/packem_shared/isRetryableError-DQNSZiBc.js +1 -0
  71. package/dist/packem_shared/isValidMediaType-B-2UKjZx.js +1 -0
  72. package/dist/packem_shared/local-meta-storage-Bkwqi_gi.js +1 -0
  73. package/dist/packem_shared/{media-transformer.d-ChmjTvjc.d.ts → media-transformer.d-CY9CsEOe.d.ts} +1 -1
  74. package/dist/packem_shared/minio-BWwgGXeE.js +1 -0
  75. package/dist/packem_shared/multipart-base-C6OjBwMS.js +1 -0
  76. package/dist/packem_shared/part-match-DqD5U7An.js +1 -0
  77. package/dist/packem_shared/path-D7rMc9nq-B718mbm6.js +1 -0
  78. package/dist/packem_shared/response-builder-Wdo_fvcF.js +1 -0
  79. package/dist/packem_shared/rest-base-B2Dv7esY.js +1 -0
  80. package/dist/packem_shared/restOpenApiSpec-PaIVbESh.js +1 -0
  81. package/dist/packem_shared/s3-base-storage-xHZNtsGe.js +1 -0
  82. package/dist/packem_shared/sharedGet-Ce7WGAsc.js +1 -0
  83. package/dist/packem_shared/storage-m_Cxgiih.js +1 -0
  84. package/dist/packem_shared/tigris-DZoyrMNd.js +1 -0
  85. package/dist/packem_shared/transformOpenApiSpec-C0vEbDTO.js +1 -0
  86. package/dist/packem_shared/{tus-base.d-CpLzyd-S.d.ts → tus-base.d-DNZRXR9X.d.ts} +2 -2
  87. package/dist/packem_shared/tusOpenApiSpec-DF0-hlWV.js +1 -0
  88. package/dist/packem_shared/{types.d-DBjmJvIT.d.ts → types.d-BCN94sB_.d.ts} +1 -1
  89. package/dist/packem_shared/{types.d-DviSTLOg.d.ts → types.d-D4caL2Fp.d.ts} +1 -1
  90. package/dist/packem_shared/update-size-DANV7aa2.js +1 -0
  91. package/dist/packem_shared/validator-DK41xp8N.js +1 -0
  92. package/dist/packem_shared/waitForStorage-ChSBLhLc.js +1 -0
  93. package/dist/packem_shared/wasabi-Dmce4x9s.js +1 -0
  94. package/dist/packem_shared/xhrOpenApiSpec-nyoboz83.js +1 -0
  95. package/dist/storage/aws/clients/index.js +1 -6
  96. package/dist/storage/aws/index.js +1 -3
  97. package/dist/storage/aws-light/index.js +1 -3
  98. package/dist/storage/azure/index.js +1 -3
  99. package/dist/storage/gcs/index.js +1 -4
  100. package/dist/storage/local/index.js +1 -3
  101. package/dist/storage/netlify-blob/index.js +1 -3
  102. package/dist/storage/vercel-blob/index.js +1 -3
  103. package/dist/transformer/audio-transformer.d.ts +1 -1
  104. package/dist/transformer/audio-transformer.js +1 -278
  105. package/dist/transformer/image-transformer.d.ts +1 -1
  106. package/dist/transformer/image-transformer.js +1 -1100
  107. package/dist/transformer/index.d.ts +2 -2
  108. package/dist/transformer/index.js +1 -4
  109. package/dist/transformer/video-transformer.d.ts +1 -1
  110. package/dist/transformer/video-transformer.js +1 -310
  111. package/package.json +18 -18
  112. package/dist/packem_shared/AwsLightFile-C-Nd5rtl.js +0 -11
  113. package/dist/packem_shared/AwsLightMetaStorage-BIDb5EPg.js +0 -4
  114. package/dist/packem_shared/AwsLightStorage-CMuKw4bI.js +0 -133
  115. package/dist/packem_shared/AzureFile-C0kug4w4.js +0 -8
  116. package/dist/packem_shared/AzureSMetaStorage-BEbXX9Uk.js +0 -89
  117. package/dist/packem_shared/AzureStorage-98-LRZ1e.js +0 -359
  118. package/dist/packem_shared/BaseTransformer-9965D4pb.js +0 -83
  119. package/dist/packem_shared/DiskStorage-COMe_G42.js +0 -12
  120. package/dist/packem_shared/DiskStorageWithChecksum-BVaaZiyS.js +0 -249
  121. package/dist/packem_shared/ERRORS-D0apMqnc.js +0 -97
  122. package/dist/packem_shared/File-CPUhj3DI.js +0 -69
  123. package/dist/packem_shared/GCSConfig-vPP22kN6.js +0 -11
  124. package/dist/packem_shared/GCSFile-DaDiCKE2.js +0 -8
  125. package/dist/packem_shared/GCSMetaStorage-BygVH0Ee.js +0 -7
  126. package/dist/packem_shared/GCStorage-4hSx_bN1.js +0 -410
  127. package/dist/packem_shared/LocalMetaStorage-DvnZqf61.js +0 -7
  128. package/dist/packem_shared/MediaTransformer-BRRqYA0E.js +0 -1202
  129. package/dist/packem_shared/MetaStorage-pECeFOad.js +0 -46
  130. package/dist/packem_shared/Metadata-DRLXeJ0F.js +0 -89
  131. package/dist/packem_shared/Multipart-BzzvNxt4.js +0 -128
  132. package/dist/packem_shared/Multipart-DLtFLQ8s.js +0 -163
  133. package/dist/packem_shared/NetlifyBlobFile-CfyJtGWN.js +0 -14
  134. package/dist/packem_shared/NetlifyBlobMetaStorage-eJT6RFy9.js +0 -9
  135. package/dist/packem_shared/NetlifyBlobStorage-nPv7iIAG.js +0 -376
  136. package/dist/packem_shared/NoOpMetrics-DhAk5rXc.js +0 -10
  137. package/dist/packem_shared/OpenTelemetryMetrics-BnxhqIaH.js +0 -67
  138. package/dist/packem_shared/Rest-DEa7IA9R.js +0 -267
  139. package/dist/packem_shared/Rest-qhMbCn5a.js +0 -228
  140. package/dist/packem_shared/S3File-BXCuJaQZ.js +0 -11
  141. package/dist/packem_shared/S3MetaStorage-yT4CznlV.js +0 -77
  142. package/dist/packem_shared/S3Storage-wi5XT-yu.js +0 -317
  143. package/dist/packem_shared/TUS_RESUMABLE-Dtfsffnj.js +0 -434
  144. package/dist/packem_shared/Tus-Ck0Hdle5.js +0 -195
  145. package/dist/packem_shared/Tus-_0vCdHyB.js +0 -200
  146. package/dist/packem_shared/ValidationError-BfF1aE4h.js +0 -26
  147. package/dist/packem_shared/VercelBlobFile-DkFIIb9Q.js +0 -18
  148. package/dist/packem_shared/VercelBlobMetaStorage-DjFmi4vp.js +0 -9
  149. package/dist/packem_shared/VercelBlobStorage-CmMgiDgr.js +0 -261
  150. package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +0 -5
  151. package/dist/packem_shared/aws-light-meta-storage-BGZEiY3y.js +0 -447
  152. package/dist/packem_shared/backblaze-BlMnIcBC.js +0 -20
  153. package/dist/packem_shared/base-handler-core-lVB-D59L.js +0 -306
  154. package/dist/packem_shared/base-handler-fetch-CitgN-Aw.js +0 -291
  155. package/dist/packem_shared/base-handler-node-BiO2DF87.js +0 -731
  156. package/dist/packem_shared/cache-B88MXQ_2.js +0 -18
  157. package/dist/packem_shared/cloudflare-Bi1q8wXE.js +0 -21
  158. package/dist/packem_shared/defaultCloudStorageFileNameValidation-Brw40ZEP.js +0 -11
  159. package/dist/packem_shared/digitalOcean-CWQRJM3L.js +0 -21
  160. package/dist/packem_shared/disk-storage-D9RfoKjW.js +0 -832
  161. package/dist/packem_shared/gcs-meta-storage-8FovEDbW.js +0 -159
  162. package/dist/packem_shared/has-content-CY66ehMK.js +0 -3
  163. package/dist/packem_shared/headers-YLRp1dLo.js +0 -1318
  164. package/dist/packem_shared/is-expired-CTThU1q5.js +0 -8
  165. package/dist/packem_shared/isRetryableError-Dycp7127.js +0 -82
  166. package/dist/packem_shared/isValidMediaType-BeDgiObq.js +0 -35
  167. package/dist/packem_shared/local-meta-storage-D-pPc3FI.js +0 -658
  168. package/dist/packem_shared/minio-C2YBZQOw.js +0 -22
  169. package/dist/packem_shared/multipart-base-C994naBi.js +0 -102
  170. package/dist/packem_shared/part-match-Dt738Ddb.js +0 -96
  171. package/dist/packem_shared/path-aV9lMdcn-DMU5H1-h.js +0 -162
  172. package/dist/packem_shared/response-builder-BtnRiBUI.js +0 -45
  173. package/dist/packem_shared/rest-base-k1ory8uB.js +0 -457
  174. package/dist/packem_shared/restOpenApiSpec-BBJ_SiPE.js +0 -800
  175. package/dist/packem_shared/s3-base-storage-zUO8u8Cp.js +0 -510
  176. package/dist/packem_shared/sharedGet-CkSLSnMd.js +0 -1022
  177. package/dist/packem_shared/storage-5XW1E7XU.js +0 -1188
  178. package/dist/packem_shared/tigris-Hac8TKnX.js +0 -21
  179. package/dist/packem_shared/transformOpenApiSpec-BodFhFls.js +0 -975
  180. package/dist/packem_shared/tusOpenApiSpec-DzppyJTW.js +0 -740
  181. package/dist/packem_shared/update-size-CCGm6i1J.js +0 -8
  182. package/dist/packem_shared/validator-DuO17wFF.js +0 -79
  183. package/dist/packem_shared/waitForStorage-Cscw85sx.js +0 -18
  184. package/dist/packem_shared/wasabi-DIyflHSd.js +0 -21
  185. package/dist/packem_shared/xhrOpenApiSpec-CXz7BC5J.js +0 -264
@@ -1,434 +0,0 @@
1
- import { c as createHttpError, H as HeaderUtilities } from './headers-YLRp1dLo.js';
2
- import { Metadata } from './Metadata-DRLXeJ0F.js';
3
-
4
- const TUS_RESUMABLE_VERSION = "1.0.0";
5
- const TUS_VERSION_VERSION = "1.0.0";
6
- const parseMetadata = (encoded = "") => {
7
- const kvPairs = encoded.split(",").map((kv) => kv.split(" "));
8
- const metadata = Object.create(Metadata.prototype);
9
- Object.values(kvPairs).forEach(([key, value]) => {
10
- if (key) {
11
- metadata[key] = value ? Buffer.from(value, "base64").toString() : "";
12
- }
13
- });
14
- return metadata;
15
- };
16
- const serializeMetadata = (object) => {
17
- if (!object || Object.keys(object).length === 0) {
18
- return "";
19
- }
20
- return Object.entries(object).map(([key, value]) => {
21
- if (value === void 0) {
22
- return key;
23
- }
24
- return `${key} ${Buffer.from(String(value)).toString("base64")}`;
25
- }).toString();
26
- };
27
- class TusBase {
28
- /**
29
- * Storage instance for file operations.
30
- */
31
- // eslint-disable-next-line class-methods-use-this
32
- get storage() {
33
- throw new Error("storage must be implemented");
34
- }
35
- /**
36
- * Build file URL from request URL and file data.
37
- * @param _requestUrl Request URL string
38
- * @param _file File object containing ID
39
- * @returns Constructed file URL for TUS protocol
40
- */
41
- // eslint-disable-next-line class-methods-use-this
42
- buildFileUrl(_requestUrl, _file) {
43
- throw new Error("buildFileUrl must be implemented");
44
- }
45
- /**
46
- * Handle OPTIONS request with TUS protocol capabilities.
47
- * @param methods Array of supported HTTP methods
48
- * @returns ResponseFile with TUS headers
49
- */
50
- handleOptions(methods) {
51
- const headers = {
52
- "Access-Control-Allow-Headers": "Authorization, Content-Type, Location, Tus-Extension, Tus-Max-Size, Tus-Resumable, Tus-Version, Upload-Concat, Upload-Defer-Length, Upload-Length, Upload-Metadata, Upload-Offset, X-HTTP-Method-Override, X-Requested-With",
53
- "Access-Control-Allow-Methods": methods.map((method) => method.toUpperCase()).join(", "),
54
- "Access-Control-Max-Age": 86400,
55
- "Tus-Checksum-Algorithm": this.storage.checksumTypes.join(","),
56
- "Tus-Extension": this.storage.tusExtension.toString(),
57
- "Tus-Max-Size": this.storage.maxUploadSize,
58
- "Tus-Version": TUS_VERSION_VERSION
59
- };
60
- return { headers, statusCode: 204 };
61
- }
62
- /**
63
- * Handle TUS POST (create upload).
64
- * @param uploadLength Upload length header value
65
- * @param uploadDeferLength Upload defer length header value
66
- * @param uploadConcat Upload concat header value
67
- * @param metadataHeader Upload metadata header value
68
- * @param requestUrl Request URL for Location header
69
- * @param bodyStream Request body stream (for creation-with-upload)
70
- * @param contentLength Content length (for creation-with-upload)
71
- * @param contentType Content type (for creation-with-upload)
72
- * @returns Promise resolving to ResponseFile with upload result
73
- */
74
- async handlePost(uploadLength, uploadDeferLength, uploadConcat, metadataHeader, requestUrl, bodyStream, contentLength, contentType) {
75
- if (uploadDeferLength !== void 0) {
76
- if (!this.storage.tusExtension.includes("creation-defer-length")) {
77
- throw createHttpError(501, "creation-defer-length extension is not (yet) supported.");
78
- }
79
- if (uploadLength === void 0) {
80
- const metadata2 = metadataHeader ? parseMetadata(metadataHeader) : {};
81
- const config2 = { metadata: metadata2 };
82
- let file2 = await this.storage.create(config2);
83
- if (contentType === "application/offset+octet-stream" && contentLength > 0) {
84
- file2 = await this.storage.write({
85
- ...file2,
86
- body: bodyStream,
87
- contentLength,
88
- start: 0
89
- });
90
- }
91
- let headers2 = {};
92
- if (this.storage.tusExtension.includes("expiration") && typeof file2.expiredAt === "number" && file2.size === void 0) {
93
- headers2 = { "Upload-Expires": new Date(file2.expiredAt).toUTCString() };
94
- }
95
- const locationUrl2 = this.buildFileUrl(requestUrl, file2);
96
- headers2 = { ...headers2, ...this.buildHeaders(file2, { Location: locationUrl2 }) };
97
- if (!headers2.Location) {
98
- headers2.Location = locationUrl2;
99
- }
100
- if (file2.bytesWritten > 0) {
101
- headers2["Upload-Offset"] = file2.bytesWritten.toString();
102
- }
103
- headers2["Upload-Defer-Length"] = "1";
104
- const statusCode2 = file2.bytesWritten > 0 ? 200 : 201;
105
- return { ...file2, headers: headers2, statusCode: statusCode2 };
106
- }
107
- }
108
- if (uploadConcat) {
109
- if (!this.storage.tusExtension.includes("concatenation")) {
110
- throw createHttpError(501, "Concatenation extension is not (yet) supported. Disable parallel upload in the tus client.");
111
- }
112
- const parsedMetadata = metadataHeader ? parseMetadata(metadataHeader) : {};
113
- if (uploadConcat === "partial") {
114
- const config2 = {
115
- metadata: { ...parsedMetadata, uploadConcat: "partial" },
116
- size: uploadLength
117
- };
118
- let file2 = await this.storage.create(config2);
119
- if (contentType === "application/offset+octet-stream" && contentLength > 0) {
120
- file2 = await this.storage.write({
121
- ...file2,
122
- body: bodyStream,
123
- contentLength,
124
- start: 0
125
- });
126
- }
127
- let headers2 = {};
128
- if (this.storage.tusExtension.includes("expiration") && typeof file2.expiredAt === "number" && file2.bytesWritten !== (file2.size ?? 0)) {
129
- headers2 = { "Upload-Expires": new Date(file2.expiredAt).toUTCString() };
130
- }
131
- const locationUrl2 = this.buildFileUrl(requestUrl, file2);
132
- headers2 = { ...headers2, ...this.buildHeaders(file2, { Location: locationUrl2 }) };
133
- if (!headers2.Location) {
134
- headers2.Location = locationUrl2;
135
- }
136
- if (file2.bytesWritten > 0) {
137
- headers2["Upload-Offset"] = file2.bytesWritten.toString();
138
- }
139
- headers2["Upload-Concat"] = "partial";
140
- const statusCode2 = file2.bytesWritten > 0 ? 200 : 201;
141
- return { ...file2, headers: headers2, statusCode: statusCode2 };
142
- }
143
- if (uploadConcat.startsWith("final;")) {
144
- const partialIds = uploadConcat.slice(6).trim().split(/\s+/).filter(Boolean);
145
- if (partialIds.length === 0) {
146
- throw createHttpError(400, "Upload-Concat final must include at least one partial upload ID");
147
- }
148
- let totalSize = 0;
149
- const partialFiles = [];
150
- for (const partialId of partialIds) {
151
- try {
152
- const partialFile = await this.storage.getMeta(partialId);
153
- await this.storage.checkIfExpired(partialFile);
154
- if (partialFile.metadata?.uploadConcat !== "partial") {
155
- throw createHttpError(400, `Upload ${partialId} is not a partial upload`);
156
- }
157
- if (partialFile.status !== "completed" || partialFile.size === void 0) {
158
- throw createHttpError(409, `Partial upload ${partialId} is not completed`);
159
- }
160
- partialFiles.push(partialFile);
161
- totalSize += partialFile.size;
162
- } catch (error) {
163
- const errorWithCode = error;
164
- if (errorWithCode.statusCode === 404 || errorWithCode.statusCode === 410) {
165
- throw createHttpError(409, `Partial upload ${partialId} not found or expired`);
166
- }
167
- throw error;
168
- }
169
- }
170
- const config2 = {
171
- metadata: {
172
- ...parsedMetadata,
173
- partialIds,
174
- uploadConcat: `final;${partialIds.join(" ")}`
175
- },
176
- size: totalSize
177
- };
178
- const file2 = await this.storage.create(config2);
179
- await this.concatenateFiles(file2, partialFiles);
180
- const locationUrl2 = this.buildFileUrl(requestUrl, file2);
181
- const headers2 = {
182
- ...this.buildHeaders(file2, { Location: locationUrl2 }),
183
- "Upload-Concat": uploadConcat
184
- };
185
- return { ...file2, headers: headers2, statusCode: 201 };
186
- }
187
- throw createHttpError(400, "Invalid Upload-Concat header format");
188
- }
189
- if (uploadLength === void 0 && uploadDeferLength === void 0) {
190
- throw createHttpError(400, "Either upload-length or upload-defer-length must be specified.");
191
- }
192
- if (uploadLength !== void 0 && Number.isNaN(Number(uploadLength))) {
193
- throw createHttpError(400, "Invalid upload-length");
194
- }
195
- const metadata = metadataHeader ? parseMetadata(metadataHeader) : {};
196
- const config = { metadata, size: uploadLength };
197
- let file = await this.storage.create(config);
198
- if (contentType === "application/offset+octet-stream" && contentLength > 0) {
199
- file = await this.storage.write({
200
- ...file,
201
- body: bodyStream,
202
- contentLength,
203
- start: 0
204
- });
205
- }
206
- let headers = {};
207
- if (this.storage.tusExtension.includes("expiration") && typeof file.expiredAt === "number" && file.bytesWritten !== Number.parseInt(uploadLength, 10)) {
208
- headers = { "Upload-Expires": new Date(file.expiredAt).toUTCString() };
209
- }
210
- const locationUrl = this.buildFileUrl(requestUrl, file);
211
- headers = { ...headers, ...this.buildHeaders(file, { Location: locationUrl }) };
212
- if (!headers.Location) {
213
- headers.Location = locationUrl;
214
- }
215
- if (file.bytesWritten > 0) {
216
- headers["Upload-Offset"] = file.bytesWritten.toString();
217
- }
218
- const statusCode = file.bytesWritten > 0 ? 200 : 201;
219
- return { ...file, headers, statusCode };
220
- }
221
- /**
222
- * Handle TUS PATCH (write chunk).
223
- * @param id File ID from URL
224
- * @param uploadOffset Upload offset header value
225
- * @param uploadLength Optional upload length header value (for defer-length)
226
- * @param metadataHeader Optional upload metadata header value
227
- * @param checksum Optional checksum
228
- * @param checksumAlgorithm Optional checksum algorithm
229
- * @param requestUrl Request URL for Location header
230
- * @param bodyStream Request body stream
231
- * @param contentLength Content length
232
- * @returns Promise resolving to ResponseFile with upload progress
233
- */
234
- async handlePatch(id, uploadOffset, uploadLength, metadataHeader, checksum, checksumAlgorithm, _requestUrl, bodyStream, contentLength) {
235
- const metadata = metadataHeader ? parseMetadata(metadataHeader) : void 0;
236
- if (metadata) {
237
- try {
238
- await this.storage.update({ id }, { id, metadata });
239
- } catch (error) {
240
- const errorWithCode = error;
241
- if (errorWithCode.UploadErrorCode === "FILE_NOT_FOUND") {
242
- throw createHttpError(410, "Upload expired");
243
- }
244
- throw error;
245
- }
246
- }
247
- let currentFile;
248
- try {
249
- currentFile = await this.storage.getMeta(id);
250
- await this.storage.checkIfExpired(currentFile);
251
- } catch (error) {
252
- const errorWithCode = error;
253
- if (errorWithCode.UploadErrorCode === "GONE" || errorWithCode.UploadErrorCode === "FILE_NOT_FOUND") {
254
- throw createHttpError(410, "Upload expired");
255
- }
256
- throw error;
257
- }
258
- const uploadConcatValue = currentFile.metadata?.uploadConcat;
259
- if (typeof uploadConcatValue === "string" && uploadConcatValue.startsWith("final;")) {
260
- throw createHttpError(403, "Cannot PATCH a final concatenation upload");
261
- }
262
- let file = await this.storage.write({
263
- body: bodyStream,
264
- checksum,
265
- checksumAlgorithm,
266
- contentLength,
267
- id,
268
- start: uploadOffset
269
- });
270
- if (uploadLength !== void 0) {
271
- if (!this.storage.tusExtension.includes("creation-defer-length")) {
272
- throw createHttpError(501, "creation-defer-length extension is not (yet) supported.");
273
- }
274
- if (file.size !== void 0 && !Number.isNaN(file.size)) {
275
- throw createHttpError(412, "Upload-Length has already been set for this upload");
276
- }
277
- const size = Number.parseInt(uploadLength, 10);
278
- if (Number.isNaN(size)) {
279
- throw createHttpError(400, "Invalid Upload-Length value");
280
- }
281
- if (size < file.bytesWritten) {
282
- throw createHttpError(400, "Upload-Length is smaller than the current offset");
283
- }
284
- file = await this.storage.update({ id }, { size });
285
- if (file.bytesWritten === file.size) {
286
- file = { ...file, status: "completed" };
287
- }
288
- }
289
- return {
290
- ...file,
291
- headers: this.buildHeaders(file, {
292
- "Upload-Offset": file.bytesWritten
293
- }),
294
- statusCode: file.status === "completed" ? 200 : 204
295
- };
296
- }
297
- /**
298
- * Handle TUS HEAD (get upload status).
299
- * @param id File ID from URL
300
- * @returns Promise resolving to ResponseFile with upload status headers
301
- */
302
- async handleHead(id) {
303
- const file = await this.storage.getMeta(id);
304
- await this.storage.checkIfExpired(file);
305
- const headers = {
306
- ...typeof file.size === "number" && !Number.isNaN(file.size) ? {
307
- "Upload-Length": file.size
308
- } : {
309
- "Upload-Defer-Length": "1"
310
- },
311
- ...this.buildHeaders(file, {
312
- "Cache-Control": HeaderUtilities.createCacheControlPreset("no-store"),
313
- "Upload-Metadata": serializeMetadata(file.metadata),
314
- "Upload-Offset": file.bytesWritten
315
- })
316
- };
317
- const uploadConcatValue = file.metadata?.uploadConcat;
318
- if (typeof uploadConcatValue === "string") {
319
- headers["Upload-Concat"] = uploadConcatValue;
320
- }
321
- return { headers, statusCode: 200 };
322
- }
323
- /**
324
- * Handle TUS GET (get upload metadata).
325
- * @param id File ID from URL
326
- * @returns Promise resolving to ResponseFile with file metadata as JSON
327
- */
328
- async handleGet(id) {
329
- const file = await this.storage.getMeta(id);
330
- return {
331
- ...file,
332
- body: file,
333
- // Return file metadata as JSON
334
- headers: this.buildHeaders(file, {
335
- "Content-Type": HeaderUtilities.createContentType({
336
- mediaType: "application/json"
337
- })
338
- }),
339
- statusCode: 200
340
- };
341
- }
342
- /**
343
- * Handle TUS DELETE (terminate upload).
344
- * @param id File ID from URL
345
- * @returns Promise resolving to ResponseFile with deletion confirmation
346
- */
347
- async handleDelete(id) {
348
- if (this.disableTerminationForFinishedUploads) {
349
- const file2 = await this.storage.getMeta(id);
350
- if (file2.status === "completed") {
351
- throw createHttpError(400, "Termination of finished uploads is disabled");
352
- }
353
- }
354
- const file = await this.storage.delete({ id });
355
- if (file.status === void 0) {
356
- throw createHttpError(404, "File not found");
357
- }
358
- return {
359
- ...file,
360
- headers: this.buildHeaders(file),
361
- statusCode: 204
362
- };
363
- }
364
- /**
365
- * Build TUS protocol headers including required Tus-Resumable and optional Upload-Expires.
366
- * @param file Upload file object with metadata
367
- * @param headers Additional headers to include
368
- * @returns Headers object with TUS protocol headers
369
- */
370
- buildHeaders(file, headers = {}) {
371
- headers["Tus-Resumable"] = TUS_RESUMABLE_VERSION;
372
- if (this.storage.tusExtension.includes("expiration") && file.expiredAt !== void 0) {
373
- headers["Upload-Expires"] = new Date(file.expiredAt).toUTCString();
374
- }
375
- return headers;
376
- }
377
- /**
378
- * Extract checksum algorithm and value from Upload-Checksum header.
379
- * @param checksumHeader Upload-Checksum header value
380
- * @returns Object containing checksum algorithm and value
381
- */
382
- // eslint-disable-next-line class-methods-use-this
383
- extractChecksum(checksumHeader) {
384
- if (!checksumHeader) {
385
- return { checksum: void 0, checksumAlgorithm: void 0 };
386
- }
387
- const [checksumAlgorithm, checksum] = checksumHeader.split(/\s+/).filter(Boolean);
388
- return { checksum, checksumAlgorithm };
389
- }
390
- /**
391
- * Validate Tus-Resumable header value.
392
- * @param tusResumable Tus-Resumable header value
393
- * @throws {Error} 412 if version doesn't match or header is missing
394
- */
395
- // eslint-disable-next-line class-methods-use-this
396
- validateTusResumableHeader(tusResumable) {
397
- if (!tusResumable) {
398
- throw createHttpError(412, "Missing Tus-Resumable header");
399
- }
400
- if (tusResumable !== TUS_RESUMABLE_VERSION) {
401
- throw createHttpError(412, `Unsupported TUS version: ${tusResumable}. Server supports: ${TUS_RESUMABLE_VERSION}`);
402
- }
403
- }
404
- /**
405
- * Concatenate partial uploads into a final upload.
406
- * @param finalFile Final file that will contain concatenated content
407
- * @param partialFiles Array of partial upload files to concatenate
408
- * @returns Promise resolving when concatenation is complete
409
- */
410
- async concatenateFiles(finalFile, partialFiles) {
411
- let offset = 0;
412
- for (const partialFile of partialFiles) {
413
- if (!this.storage.getStream) {
414
- throw createHttpError(501, "getStream is not supported by this storage backend");
415
- }
416
- const { size, stream } = await this.storage.getStream({ id: partialFile.id });
417
- if (size === void 0) {
418
- throw createHttpError(500, "Partial upload size is undefined");
419
- }
420
- const updatedFile = await this.storage.write({
421
- ...finalFile,
422
- body: stream,
423
- contentLength: size,
424
- start: offset
425
- });
426
- Object.assign(finalFile, updatedFile);
427
- offset += size;
428
- }
429
- }
430
- }
431
- const TUS_RESUMABLE = TUS_RESUMABLE_VERSION;
432
- const TUS_VERSION = TUS_VERSION_VERSION;
433
-
434
- export { TUS_RESUMABLE, TUS_VERSION, TusBase, parseMetadata, serializeMetadata };
@@ -1,195 +0,0 @@
1
- import { format } from 'node:url';
2
- import { c as createHttpError } from './headers-YLRp1dLo.js';
3
- import { a as getHeader, b as getRequestStream, g as getIdFromRequest, c as getBaseUrl } from './base-handler-core-lVB-D59L.js';
4
- import { B as BaseHandlerNode } from './base-handler-node-BiO2DF87.js';
5
- import { TusBase } from './TUS_RESUMABLE-Dtfsffnj.js';
6
- export { TUS_RESUMABLE, TUS_VERSION } from './TUS_RESUMABLE-Dtfsffnj.js';
7
-
8
- class Tus extends BaseHandlerNode {
9
- /**
10
- * Limiting enabled http method handler
11
- */
12
- static methods = ["delete", "download", "get", "head", "options", "patch", "post"];
13
- disableTerminationForFinishedUploads = false;
14
- tusBase;
15
- constructor(options) {
16
- super(options);
17
- this.disableTerminationForFinishedUploads = options.disableTerminationForFinishedUploads ?? false;
18
- const tusInstance = this;
19
- this.tusBase = new class extends TusBase {
20
- // eslint-disable-next-line class-methods-use-this
21
- get storage() {
22
- return tusInstance.storage;
23
- }
24
- // eslint-disable-next-line class-methods-use-this
25
- get disableTerminationForFinishedUploads() {
26
- return tusInstance.disableTerminationForFinishedUploads;
27
- }
28
- // eslint-disable-next-line class-methods-use-this
29
- buildFileUrl(requestUrl, file) {
30
- return tusInstance.buildFileUrlForTus(requestUrl, file);
31
- }
32
- }();
33
- }
34
- /**
35
- * Handle OPTIONS requests with TUS protocol capabilities.
36
- * @returns Promise resolving to ResponseFile with TUS headers
37
- */
38
- async options() {
39
- return this.tusBase.handleOptions(Tus.methods);
40
- }
41
- /**
42
- * Creates a new TUS upload and optionally starts uploading data.
43
- * @param request Node.js IncomingMessage with TUS headers.
44
- * @returns Promise resolving to ResponseFile with upload location and offset.
45
- */
46
- async post(request) {
47
- this.tusBase.validateTusResumableHeader(getHeader(request, "tus-resumable"));
48
- const uploadLength = request.headers["upload-length"];
49
- const uploadDeferLength = request.headers["upload-defer-length"];
50
- const uploadConcat = request.headers["upload-concat"];
51
- const metadataHeader = getHeader(request, "upload-metadata", true);
52
- const contentType = getHeader(request, "content-type") || "";
53
- const contentLength = Number.parseInt(getHeader(request, "content-length") || "0", 10);
54
- const requestUrl = request.originalUrl || request.url;
55
- const bodyStream = getRequestStream(request);
56
- return this.tusBase.handlePost(uploadLength, uploadDeferLength, uploadConcat, metadataHeader, requestUrl, bodyStream, contentLength, contentType);
57
- }
58
- /**
59
- * Write a chunk of data to an existing TUS upload.
60
- * @param request Node.js IncomingMessage with chunk data and TUS headers
61
- * @returns Promise resolving to ResponseFile with updated offset
62
- */
63
- async patch(request) {
64
- this.tusBase.validateTusResumableHeader(getHeader(request, "tus-resumable"));
65
- try {
66
- const id = getIdFromRequest(request);
67
- if (request.headers["upload-offset"] === void 0) {
68
- throw createHttpError(412, "Missing Upload-Offset header");
69
- }
70
- if (request.headers["content-type"] === void 0) {
71
- throw createHttpError(412, "Content-Type header required");
72
- }
73
- if (request.headers["content-type"] !== "application/offset+octet-stream") {
74
- throw createHttpError(415, "Unsupported Media Type");
75
- }
76
- const uploadOffset = Number.parseInt(getHeader(request, "upload-offset"), 10);
77
- const uploadLength = request.headers["upload-length"];
78
- const metadataHeader = getHeader(request, "upload-metadata", true);
79
- const contentLength = Number(getHeader(request, "content-length"));
80
- const checksumHeader = getHeader(request, "upload-checksum");
81
- const { checksum, checksumAlgorithm } = this.tusBase.extractChecksum(checksumHeader);
82
- const requestUrl = request.originalUrl || request.url;
83
- const bodyStream = getRequestStream(request);
84
- return this.tusBase.handlePatch(id, uploadOffset, uploadLength, metadataHeader, checksum, checksumAlgorithm, requestUrl, bodyStream, contentLength);
85
- } catch (error) {
86
- this.checkForUndefinedIdOrPath(error);
87
- const errorWithCode = error;
88
- if (errorWithCode.UploadErrorCode === "GONE" || errorWithCode.UploadErrorCode === "FILE_NOT_FOUND") {
89
- throw createHttpError(410, "Upload expired");
90
- }
91
- throw error;
92
- }
93
- }
94
- /**
95
- * Get current upload offset and metadata for TUS resumable uploads.
96
- * @param request Node.js IncomingMessage with upload ID
97
- * @returns Promise resolving to ResponseFile with upload-offset and metadata headers
98
- */
99
- async head(request) {
100
- this.tusBase.validateTusResumableHeader(getHeader(request, "tus-resumable"));
101
- try {
102
- const id = getIdFromRequest(request);
103
- return this.tusBase.handleHead(id);
104
- } catch (error) {
105
- this.checkForUndefinedIdOrPath(error);
106
- const errorWithCode = error;
107
- if (errorWithCode.UploadErrorCode === "GONE" || errorWithCode.UploadErrorCode === "FILE_NOT_FOUND") {
108
- throw createHttpError(410, "Upload expired");
109
- }
110
- throw error;
111
- }
112
- }
113
- /**
114
- * Get TUS upload metadata and current status.
115
- * @param request Node.js IncomingMessage with upload ID
116
- * @returns Promise resolving to ResponseFile with file metadata as JSON
117
- */
118
- async get(request) {
119
- this.tusBase.validateTusResumableHeader(getHeader(request, "tus-resumable"));
120
- try {
121
- const id = getIdFromRequest(request);
122
- return this.tusBase.handleGet(id);
123
- } catch (error) {
124
- this.checkForUndefinedIdOrPath(error);
125
- const errorWithCode = error;
126
- if (errorWithCode.UploadErrorCode === "GONE") {
127
- throw createHttpError(410, "Upload expired");
128
- }
129
- throw error;
130
- }
131
- }
132
- /**
133
- * Delete a TUS upload and its associated data.
134
- * @param request Node.js IncomingMessage with upload ID
135
- * @returns Promise resolving to ResponseFile with deletion confirmation
136
- */
137
- async delete(request) {
138
- this.tusBase.validateTusResumableHeader(getHeader(request, "tus-resumable"));
139
- try {
140
- const id = getIdFromRequest(request);
141
- return this.tusBase.handleDelete(id);
142
- } catch (error) {
143
- this.checkForUndefinedIdOrPath(error);
144
- const errorWithCode = error;
145
- if (errorWithCode.code === "ENOENT") {
146
- throw createHttpError(404, "File not found");
147
- }
148
- throw error;
149
- }
150
- }
151
- /**
152
- * Send TUS protocol response with required headers.
153
- * @param response Node.js ServerResponse to send response to
154
- * @param uploadResponse Response data with body, headers, and status code
155
- */
156
- send(response, { body = "", headers = {}, statusCode = 200 }) {
157
- const uploadResponse = {
158
- body,
159
- headers: {
160
- ...headers,
161
- "Access-Control-Expose-Headers": "location,upload-expires,upload-offset,upload-length,upload-metadata,upload-defer-length,tus-resumable,tus-extension,tus-max-size,tus-version,tus-checksum-algorithm,cache-control",
162
- "Tus-Resumable": "1.0.0"
163
- },
164
- statusCode: statusCode || 200
165
- };
166
- super.send(response, uploadResponse);
167
- }
168
- /**
169
- * Compose and register HTTP method handlers.
170
- */
171
- compose() {
172
- this.registeredHandlers.set("POST", this.post.bind(this));
173
- this.registeredHandlers.set("PATCH", this.patch.bind(this));
174
- this.registeredHandlers.set("HEAD", this.head.bind(this));
175
- this.registeredHandlers.set("GET", this.get.bind(this));
176
- this.registeredHandlers.set("DELETE", this.delete.bind(this));
177
- this.registeredHandlers.set("OPTIONS", this.options.bind(this));
178
- this.logger?.debug("Registered handler: %s", [...this.registeredHandlers.keys()].join(", "));
179
- }
180
- /**
181
- * Build file URL for TUS uploads (without file extension).
182
- * @param requestUrl Request URL string
183
- * @param file File object containing ID
184
- * @returns Constructed file URL for TUS protocol
185
- */
186
- buildFileUrlForTus(requestUrl, file) {
187
- const url = new URL(requestUrl, "http://localhost");
188
- const { pathname } = url;
189
- const query = Object.fromEntries(url.searchParams.entries());
190
- const relative = format({ pathname: `${pathname}/${file.id}`, query });
191
- return this.storage.config.useRelativeLocation ? relative : getBaseUrl({ }) + relative;
192
- }
193
- }
194
-
195
- export { Tus };