@fragno-dev/upload 0.1.1 → 0.1.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 (301) hide show
  1. package/README.md +148 -12
  2. package/dist/browser/client/clients.js +17 -9
  3. package/dist/browser/client/clients.js.map +1 -1
  4. package/dist/browser/client/helpers.d.ts +15 -6
  5. package/dist/browser/client/helpers.d.ts.map +1 -1
  6. package/dist/browser/client/helpers.js +176 -30
  7. package/dist/browser/client/helpers.js.map +1 -1
  8. package/dist/browser/client/node_modules/.pnpm/{@nanostores_query@0.3.4_nanostores@1.1.0 → @nanostores_query@0.3.4_nanostores@1.2.0}/node_modules/@nanostores/query/dist/nanoquery.js +6 -6
  9. package/dist/browser/client/node_modules/.pnpm/{@nanostores_query@0.3.4_nanostores@1.1.0 → @nanostores_query@0.3.4_nanostores@1.2.0}/node_modules/@nanostores/query/dist/nanoquery.js.map +1 -1
  10. package/dist/browser/client/node_modules/.pnpm/{@nanostores_solid@1.1.1_nanostores@1.1.0_solid-js@1.9.10 → @nanostores_solid@1.1.1_nanostores@1.2.0_solid-js@1.9.10}/node_modules/@nanostores/solid/dist/index.js +2 -2
  11. package/dist/browser/client/node_modules/.pnpm/{@nanostores_solid@1.1.1_nanostores@1.1.0_solid-js@1.9.10 → @nanostores_solid@1.1.1_nanostores@1.2.0_solid-js@1.9.10}/node_modules/@nanostores/solid/dist/index.js.map +1 -1
  12. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/atom/index.js +2 -1
  13. package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/atom/index.js.map +1 -0
  14. package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/clean-stores/index.js +6 -0
  15. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/clean-stores/index.js.map +1 -1
  16. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/computed/index.js +8 -5
  17. package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/computed/index.js.map +1 -0
  18. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/lifecycle/index.js +1 -1
  19. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/lifecycle/index.js.map +1 -1
  20. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/listen-keys/index.js +1 -1
  21. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/listen-keys/index.js.map +1 -1
  22. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/map/index.js +1 -1
  23. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/map/index.js.map +1 -1
  24. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/task/index.js +1 -1
  25. package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/task/index.js.map +1 -1
  26. package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/warn/index.js +16 -0
  27. package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/warn/index.js.map +1 -0
  28. package/dist/browser/client/packages/fragment-upload/src/definition.js +1 -42
  29. package/dist/browser/client/packages/fragment-upload/src/definition.js.map +1 -1
  30. package/dist/browser/client/packages/fragment-upload/src/routes/files.js +12 -5
  31. package/dist/browser/client/packages/fragment-upload/src/routes/files.js.map +1 -1
  32. package/dist/browser/client/packages/fragment-upload/src/routes/shared.js +3 -4
  33. package/dist/browser/client/packages/fragment-upload/src/routes/shared.js.map +1 -1
  34. package/dist/browser/client/packages/fragment-upload/src/routes/uploads.js +32 -21
  35. package/dist/browser/client/packages/fragment-upload/src/routes/uploads.js.map +1 -1
  36. package/dist/browser/client/packages/fragment-upload/src/schema.js +33 -3
  37. package/dist/browser/client/packages/fragment-upload/src/schema.js.map +1 -1
  38. package/dist/browser/client/packages/fragment-upload/src/types.d.ts +1 -2
  39. package/dist/browser/client/packages/fragment-upload/src/types.d.ts.map +1 -1
  40. package/dist/browser/client/packages/fragno/dist/client/client.js +28 -12
  41. package/dist/browser/client/packages/fragno/dist/client/client.js.map +1 -1
  42. package/dist/browser/client/packages/fragno/dist/client/client.svelte.js +11 -3
  43. package/dist/browser/client/packages/fragno/dist/client/client.svelte.js.map +1 -1
  44. package/dist/browser/client/packages/fragno/dist/client/react.js +104 -12
  45. package/dist/browser/client/packages/fragno/dist/client/react.js.map +1 -1
  46. package/dist/browser/client/packages/fragno/dist/client/solid.js +25 -11
  47. package/dist/browser/client/packages/fragno/dist/client/solid.js.map +1 -1
  48. package/dist/browser/client/packages/fragno/dist/client/vanilla.js +21 -1
  49. package/dist/browser/client/packages/fragno/dist/client/vanilla.js.map +1 -1
  50. package/dist/browser/client/packages/fragno/dist/client/vue.js +19 -11
  51. package/dist/browser/client/packages/fragno/dist/client/vue.js.map +1 -1
  52. package/dist/browser/client/react.d.ts +215 -192
  53. package/dist/browser/client/react.d.ts.map +1 -1
  54. package/dist/browser/client/react.js.map +1 -1
  55. package/dist/browser/client/solid.d.ts +218 -196
  56. package/dist/browser/client/solid.d.ts.map +1 -1
  57. package/dist/browser/client/solid.js.map +1 -1
  58. package/dist/browser/client/svelte.d.ts +216 -193
  59. package/dist/browser/client/svelte.d.ts.map +1 -1
  60. package/dist/browser/client/svelte.js.map +1 -1
  61. package/dist/browser/client/vanilla.d.ts +217 -195
  62. package/dist/browser/client/vanilla.d.ts.map +1 -1
  63. package/dist/browser/client/vanilla.js.map +1 -1
  64. package/dist/browser/client/vue.d.ts +217 -194
  65. package/dist/browser/client/vue.d.ts.map +1 -1
  66. package/dist/browser/client/vue.js.map +1 -1
  67. package/dist/cli/commands/files/delete.d.ts +4 -4
  68. package/dist/cli/commands/files/delete.d.ts.map +1 -1
  69. package/dist/cli/commands/files/delete.js +8 -10
  70. package/dist/cli/commands/files/delete.js.map +1 -1
  71. package/dist/cli/commands/files/download-url.d.ts +4 -4
  72. package/dist/cli/commands/files/download-url.d.ts.map +1 -1
  73. package/dist/cli/commands/files/download-url.js +8 -10
  74. package/dist/cli/commands/files/download-url.js.map +1 -1
  75. package/dist/cli/commands/files/download.d.ts +4 -4
  76. package/dist/cli/commands/files/download.d.ts.map +1 -1
  77. package/dist/cli/commands/files/download.js +10 -12
  78. package/dist/cli/commands/files/download.js.map +1 -1
  79. package/dist/cli/commands/files/get.d.ts +4 -4
  80. package/dist/cli/commands/files/get.d.ts.map +1 -1
  81. package/dist/cli/commands/files/get.js +8 -10
  82. package/dist/cli/commands/files/get.js.map +1 -1
  83. package/dist/cli/commands/files/list.d.ts +4 -4
  84. package/dist/cli/commands/files/list.d.ts.map +1 -1
  85. package/dist/cli/commands/files/list.js +6 -8
  86. package/dist/cli/commands/files/list.js.map +1 -1
  87. package/dist/cli/commands/files/update.d.ts +4 -4
  88. package/dist/cli/commands/files/update.d.ts.map +1 -1
  89. package/dist/cli/commands/files/update.js +8 -10
  90. package/dist/cli/commands/files/update.js.map +1 -1
  91. package/dist/cli/commands/files/upload.d.ts +4 -4
  92. package/dist/cli/commands/files/upload.d.ts.map +1 -1
  93. package/dist/cli/commands/files/upload.js +10 -12
  94. package/dist/cli/commands/files/upload.js.map +1 -1
  95. package/dist/cli/commands/uploads/abort.d.ts +2 -2
  96. package/dist/cli/commands/uploads/abort.d.ts.map +1 -1
  97. package/dist/cli/commands/uploads/abort.js.map +1 -1
  98. package/dist/cli/commands/uploads/complete.d.ts +2 -2
  99. package/dist/cli/commands/uploads/complete.d.ts.map +1 -1
  100. package/dist/cli/commands/uploads/complete.js.map +1 -1
  101. package/dist/cli/commands/uploads/content.d.ts +2 -2
  102. package/dist/cli/commands/uploads/content.d.ts.map +1 -1
  103. package/dist/cli/commands/uploads/content.js +1 -1
  104. package/dist/cli/commands/uploads/content.js.map +1 -1
  105. package/dist/cli/commands/uploads/create.d.ts +4 -4
  106. package/dist/cli/commands/uploads/create.d.ts.map +1 -1
  107. package/dist/cli/commands/uploads/create.js +8 -11
  108. package/dist/cli/commands/uploads/create.js.map +1 -1
  109. package/dist/cli/commands/uploads/get.d.ts +2 -2
  110. package/dist/cli/commands/uploads/get.d.ts.map +1 -1
  111. package/dist/cli/commands/uploads/get.js.map +1 -1
  112. package/dist/cli/commands/uploads/parts-complete.d.ts +2 -2
  113. package/dist/cli/commands/uploads/parts-complete.d.ts.map +1 -1
  114. package/dist/cli/commands/uploads/parts-complete.js.map +1 -1
  115. package/dist/cli/commands/uploads/parts-list.d.ts +2 -2
  116. package/dist/cli/commands/uploads/parts-list.d.ts.map +1 -1
  117. package/dist/cli/commands/uploads/parts-list.js.map +1 -1
  118. package/dist/cli/commands/uploads/parts-urls.d.ts +2 -2
  119. package/dist/cli/commands/uploads/parts-urls.d.ts.map +1 -1
  120. package/dist/cli/commands/uploads/parts-urls.js.map +1 -1
  121. package/dist/cli/commands/uploads/progress.d.ts +2 -2
  122. package/dist/cli/commands/uploads/progress.d.ts.map +1 -1
  123. package/dist/cli/commands/uploads/progress.js.map +1 -1
  124. package/dist/cli/commands/uploads/transfer.d.ts +4 -4
  125. package/dist/cli/commands/uploads/transfer.d.ts.map +1 -1
  126. package/dist/cli/commands/uploads/transfer.js +9 -12
  127. package/dist/cli/commands/uploads/transfer.js.map +1 -1
  128. package/dist/cli/index.d.ts +13 -13
  129. package/dist/cli/index.d.ts.map +1 -1
  130. package/dist/cli/index.js +14 -14
  131. package/dist/cli/index.js.map +1 -1
  132. package/dist/cli/utils/client.js +22 -5
  133. package/dist/cli/utils/client.js.map +1 -1
  134. package/dist/cli/utils/options.js +7 -43
  135. package/dist/cli/utils/options.js.map +1 -1
  136. package/dist/node/cli/commands/files/delete.d.ts +4 -4
  137. package/dist/node/cli/commands/files/delete.d.ts.map +1 -1
  138. package/dist/node/cli/commands/files/delete.js +8 -10
  139. package/dist/node/cli/commands/files/delete.js.map +1 -1
  140. package/dist/node/cli/commands/files/download-url.d.ts +4 -4
  141. package/dist/node/cli/commands/files/download-url.d.ts.map +1 -1
  142. package/dist/node/cli/commands/files/download-url.js +8 -10
  143. package/dist/node/cli/commands/files/download-url.js.map +1 -1
  144. package/dist/node/cli/commands/files/download.d.ts +4 -4
  145. package/dist/node/cli/commands/files/download.d.ts.map +1 -1
  146. package/dist/node/cli/commands/files/download.js +9 -11
  147. package/dist/node/cli/commands/files/download.js.map +1 -1
  148. package/dist/node/cli/commands/files/get.d.ts +4 -4
  149. package/dist/node/cli/commands/files/get.d.ts.map +1 -1
  150. package/dist/node/cli/commands/files/get.js +8 -10
  151. package/dist/node/cli/commands/files/get.js.map +1 -1
  152. package/dist/node/cli/commands/files/list.d.ts +4 -4
  153. package/dist/node/cli/commands/files/list.d.ts.map +1 -1
  154. package/dist/node/cli/commands/files/list.js +6 -8
  155. package/dist/node/cli/commands/files/list.js.map +1 -1
  156. package/dist/node/cli/commands/files/update.d.ts +4 -4
  157. package/dist/node/cli/commands/files/update.d.ts.map +1 -1
  158. package/dist/node/cli/commands/files/update.js +8 -10
  159. package/dist/node/cli/commands/files/update.js.map +1 -1
  160. package/dist/node/cli/commands/files/upload.d.ts +4 -4
  161. package/dist/node/cli/commands/files/upload.d.ts.map +1 -1
  162. package/dist/node/cli/commands/files/upload.js +9 -11
  163. package/dist/node/cli/commands/files/upload.js.map +1 -1
  164. package/dist/node/cli/commands/uploads/abort.d.ts +2 -2
  165. package/dist/node/cli/commands/uploads/abort.d.ts.map +1 -1
  166. package/dist/node/cli/commands/uploads/abort.js.map +1 -1
  167. package/dist/node/cli/commands/uploads/complete.d.ts +2 -2
  168. package/dist/node/cli/commands/uploads/complete.d.ts.map +1 -1
  169. package/dist/node/cli/commands/uploads/complete.js.map +1 -1
  170. package/dist/node/cli/commands/uploads/content.d.ts +2 -2
  171. package/dist/node/cli/commands/uploads/content.d.ts.map +1 -1
  172. package/dist/node/cli/commands/uploads/content.js.map +1 -1
  173. package/dist/node/cli/commands/uploads/create.d.ts +4 -4
  174. package/dist/node/cli/commands/uploads/create.d.ts.map +1 -1
  175. package/dist/node/cli/commands/uploads/create.js +8 -11
  176. package/dist/node/cli/commands/uploads/create.js.map +1 -1
  177. package/dist/node/cli/commands/uploads/get.d.ts +2 -2
  178. package/dist/node/cli/commands/uploads/get.d.ts.map +1 -1
  179. package/dist/node/cli/commands/uploads/get.js.map +1 -1
  180. package/dist/node/cli/commands/uploads/parts-complete.d.ts +2 -2
  181. package/dist/node/cli/commands/uploads/parts-complete.d.ts.map +1 -1
  182. package/dist/node/cli/commands/uploads/parts-complete.js.map +1 -1
  183. package/dist/node/cli/commands/uploads/parts-list.d.ts +2 -2
  184. package/dist/node/cli/commands/uploads/parts-list.d.ts.map +1 -1
  185. package/dist/node/cli/commands/uploads/parts-list.js.map +1 -1
  186. package/dist/node/cli/commands/uploads/parts-urls.d.ts +2 -2
  187. package/dist/node/cli/commands/uploads/parts-urls.d.ts.map +1 -1
  188. package/dist/node/cli/commands/uploads/parts-urls.js.map +1 -1
  189. package/dist/node/cli/commands/uploads/progress.d.ts +2 -2
  190. package/dist/node/cli/commands/uploads/progress.d.ts.map +1 -1
  191. package/dist/node/cli/commands/uploads/progress.js.map +1 -1
  192. package/dist/node/cli/commands/uploads/transfer.d.ts +4 -4
  193. package/dist/node/cli/commands/uploads/transfer.d.ts.map +1 -1
  194. package/dist/node/cli/commands/uploads/transfer.js +8 -11
  195. package/dist/node/cli/commands/uploads/transfer.js.map +1 -1
  196. package/dist/node/cli/index.d.ts +13 -13
  197. package/dist/node/cli/index.d.ts.map +1 -1
  198. package/dist/node/cli/index.js +14 -14
  199. package/dist/node/cli/index.js.map +1 -1
  200. package/dist/node/cli/utils/client.js +22 -5
  201. package/dist/node/cli/utils/client.js.map +1 -1
  202. package/dist/node/cli/utils/options.js +7 -43
  203. package/dist/node/cli/utils/options.js.map +1 -1
  204. package/dist/node/client/clients.d.ts +217 -194
  205. package/dist/node/client/clients.d.ts.map +1 -1
  206. package/dist/node/client/clients.js +17 -9
  207. package/dist/node/client/clients.js.map +1 -1
  208. package/dist/node/client/helpers.d.ts +15 -6
  209. package/dist/node/client/helpers.d.ts.map +1 -1
  210. package/dist/node/client/helpers.js +176 -30
  211. package/dist/node/client/helpers.js.map +1 -1
  212. package/dist/node/client/react.d.ts +217 -194
  213. package/dist/node/client/react.d.ts.map +1 -1
  214. package/dist/node/client/react.js.map +1 -1
  215. package/dist/node/client/solid.d.ts +218 -196
  216. package/dist/node/client/solid.d.ts.map +1 -1
  217. package/dist/node/client/solid.js.map +1 -1
  218. package/dist/node/client/svelte.d.ts +216 -193
  219. package/dist/node/client/svelte.d.ts.map +1 -1
  220. package/dist/node/client/svelte.js.map +1 -1
  221. package/dist/node/client/vanilla.d.ts +217 -195
  222. package/dist/node/client/vanilla.d.ts.map +1 -1
  223. package/dist/node/client/vanilla.js.map +1 -1
  224. package/dist/node/client/vue.d.ts +217 -194
  225. package/dist/node/client/vue.d.ts.map +1 -1
  226. package/dist/node/client/vue.js.map +1 -1
  227. package/dist/node/config.d.ts +6 -6
  228. package/dist/node/config.d.ts.map +1 -1
  229. package/dist/node/config.js.map +1 -1
  230. package/dist/node/definition.d.ts +588 -219
  231. package/dist/node/definition.d.ts.map +1 -1
  232. package/dist/node/definition.js +27 -3
  233. package/dist/node/definition.js.map +1 -1
  234. package/dist/node/file-key.d.ts +19 -0
  235. package/dist/node/file-key.d.ts.map +1 -0
  236. package/dist/node/file-key.js +47 -0
  237. package/dist/node/file-key.js.map +1 -0
  238. package/dist/node/index.d.ts +582 -175
  239. package/dist/node/index.d.ts.map +1 -1
  240. package/dist/node/index.js +3 -2
  241. package/dist/node/index.js.map +1 -1
  242. package/dist/node/routes/files.js +99 -64
  243. package/dist/node/routes/files.js.map +1 -1
  244. package/dist/node/routes/index.d.ts +1497 -721
  245. package/dist/node/routes/index.d.ts.map +1 -1
  246. package/dist/node/routes/shared.js +5 -9
  247. package/dist/node/routes/shared.js.map +1 -1
  248. package/dist/node/routes/uploads.js +105 -47
  249. package/dist/node/routes/uploads.js.map +1 -1
  250. package/dist/node/schema.d.ts +6 -6
  251. package/dist/node/schema.d.ts.map +1 -1
  252. package/dist/node/schema.js +12 -3
  253. package/dist/node/schema.js.map +1 -1
  254. package/dist/node/services/files.d.ts +6 -2
  255. package/dist/node/services/files.d.ts.map +1 -1
  256. package/dist/node/services/files.js +22 -20
  257. package/dist/node/services/files.js.map +1 -1
  258. package/dist/node/services/helpers.js +37 -15
  259. package/dist/node/services/helpers.js.map +1 -1
  260. package/dist/node/services/uploads.d.ts +10 -5
  261. package/dist/node/services/uploads.d.ts.map +1 -1
  262. package/dist/node/services/uploads.js +340 -63
  263. package/dist/node/services/uploads.js.map +1 -1
  264. package/dist/node/storage/fs.d.ts.map +1 -1
  265. package/dist/node/storage/fs.js +16 -10
  266. package/dist/node/storage/fs.js.map +1 -1
  267. package/dist/node/storage/object-key.js +36 -0
  268. package/dist/node/storage/object-key.js.map +1 -0
  269. package/dist/node/storage/r2-binding.d.ts +59 -0
  270. package/dist/node/storage/r2-binding.d.ts.map +1 -0
  271. package/dist/node/storage/r2-binding.js +245 -0
  272. package/dist/node/storage/r2-binding.js.map +1 -0
  273. package/dist/node/storage/r2.d.ts +6 -5
  274. package/dist/node/storage/r2.d.ts.map +1 -1
  275. package/dist/node/storage/s3.d.ts.map +1 -1
  276. package/dist/node/storage/s3.js +16 -10
  277. package/dist/node/storage/s3.js.map +1 -1
  278. package/dist/node/storage/types.d.ts +6 -5
  279. package/dist/node/storage/types.d.ts.map +1 -1
  280. package/dist/node/types.d.ts +1 -2
  281. package/dist/node/types.d.ts.map +1 -1
  282. package/package.json +26 -46
  283. package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/atom/index.js.map +0 -1
  284. package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/clean-stores/index.js +0 -6
  285. package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/computed/index.js.map +0 -1
  286. package/dist/browser/client/packages/fragment-upload/src/keys.d.ts +0 -7
  287. package/dist/browser/client/packages/fragment-upload/src/keys.d.ts.map +0 -1
  288. package/dist/browser/client/packages/fragment-upload/src/keys.js +0 -28
  289. package/dist/browser/client/packages/fragment-upload/src/keys.js.map +0 -1
  290. package/dist/browser/index-BdjKPO4J.d.ts +0 -177
  291. package/dist/browser/index-BdjKPO4J.d.ts.map +0 -1
  292. package/dist/browser/index.js +0 -3
  293. package/dist/browser/src-vdNJUbjT.js +0 -1982
  294. package/dist/browser/src-vdNJUbjT.js.map +0 -1
  295. package/dist/cli/keys.js +0 -32
  296. package/dist/cli/keys.js.map +0 -1
  297. package/dist/node/keys.d.ts +0 -12
  298. package/dist/node/keys.d.ts.map +0 -1
  299. package/dist/node/keys.js +0 -63
  300. package/dist/node/keys.js.map +0 -1
  301. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,4 +1,3 @@
1
- import { FileKeyEncoded, FileKeyParts } from "../keys.js";
2
1
  import { UploadChecksum } from "../storage/types.js";
3
2
  import { FileMetadata, FileVisibility, UploadStrategy } from "../types.js";
4
3
 
@@ -10,8 +9,8 @@ type UploadProgress = {
10
9
  totalParts?: number;
11
10
  };
12
11
  type CreateUploadAndTransferOptions = {
13
- keyParts?: FileKeyParts;
14
- fileKey?: FileKeyEncoded;
12
+ provider: string;
13
+ fileKey: string;
15
14
  filename?: string;
16
15
  contentType?: string;
17
16
  checksum?: UploadChecksum | null;
@@ -21,10 +20,16 @@ type CreateUploadAndTransferOptions = {
21
20
  metadata?: Record<string, unknown>;
22
21
  onProgress?: (progress: UploadProgress) => void;
23
22
  };
23
+ type DownloadMethod = "signed-url" | "content";
24
+ type DownloadFileOptions = {
25
+ provider: string;
26
+ method: DownloadMethod;
27
+ };
24
28
  type UploadCreateResponse = {
25
29
  uploadId: string;
26
30
  fileKey: string;
27
- status: "created";
31
+ provider: string;
32
+ status: "created" | "in_progress";
28
33
  strategy: UploadStrategy;
29
34
  expiresAt: string;
30
35
  upload: {
@@ -34,8 +39,12 @@ type UploadCreateResponse = {
34
39
  uploadHeaders?: Record<string, string>;
35
40
  partSizeBytes?: number;
36
41
  maxParts?: number;
42
+ statusEndpoint: string;
43
+ progressEndpoint: string;
37
44
  partsEndpoint?: string;
45
+ partsCompleteEndpoint?: string;
38
46
  completeEndpoint: string;
47
+ abortEndpoint: string;
39
48
  contentEndpoint?: string;
40
49
  };
41
50
  };
@@ -44,8 +53,8 @@ type UploadHelpers = {
44
53
  upload: UploadCreateResponse;
45
54
  file: FileMetadata;
46
55
  }>;
47
- downloadFile: (fileKeyOrParts: FileKeyEncoded | FileKeyParts) => Promise<Response>;
56
+ downloadFile: (fileKey: string, options: DownloadFileOptions) => Promise<Response>;
48
57
  };
49
58
  //#endregion
50
- export { CreateUploadAndTransferOptions, UploadCreateResponse, UploadHelpers, UploadProgress };
59
+ export { CreateUploadAndTransferOptions, DownloadFileOptions, DownloadMethod, UploadCreateResponse, UploadHelpers, UploadProgress };
51
60
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","names":[],"sources":["../../../src/client/helpers.ts"],"sourcesContent":[],"mappings":";;;;;KAIY,cAAA;;EAAA,UAAA,EAAA,MAAc;EAOd,aAAA,EAAA,MAAA;EAA8B,UAAA,CAAA,EAAA,MAAA;;AAE9B,KAFA,8BAAA,GAEA;UAGC,CAAA,EAJA,YAIA;SAEE,CAAA,EALH,cAKG;UAEF,CAAA,EAAA,MAAA;aACa,CAAA,EAAA,MAAA;EAAc,QAAA,CAAA,EAL3B,cAK2B,GAAA,IAAA;EAG5B,IAAA,CAAA,EAAA,MAAA,EAAA;EAAoB,UAAA,CAAA,EANjB,cAMiB;YAIpB,CAAA,EAAA,MAAA;UAMQ,CAAA,EAdP,MAcO,CAAA,MAAA,EAAA,OAAA,CAAA;EAAM,UAAA,CAAA,EAAA,CAAA,QAAA,EAbA,cAaA,EAAA,GAAA,IAAA;AAS1B,CAAA;AAAyB,KAnBb,oBAAA,GAmBa;UAEf,EAAA,MAAA;SACG,EAAA,MAAA;QACY,EAAA,SAAA;UAA4B,EAnBzC,cAmByC;WAA9C,EAAA,MAAA;QAC0B,EAAA;IAAiB,IAAA,EAAA,QAAA,GAAA,WAAA;IAAyB,SAAA,EAAA,QAAA,GAAA,OAAA;IAAR,SAAA,CAAA,EAAA,MAAA;IAAO,aAAA,CAAA,EAdtD,MAcsD,CAAA,MAAA,EAAA,MAAA,CAAA;;;;;;;;KAL9D,aAAA;kCAEF,eACG,mCACN;YAAkB;UAA4B;;iCACpB,iBAAiB,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"helpers.d.ts","names":[],"sources":["../../../src/client/helpers.ts"],"sourcesContent":[],"mappings":";;;;KAGY,cAAA;;EAAA,UAAA,EAAA,MAAc;EAOd,aAAA,EAAA,MAAA;EAA8B,UAAA,CAAA,EAAA,MAAA;;AAO3B,KAPH,8BAAA,GAOG;UAEF,EAAA,MAAA;SACa,EAAA,MAAA;EAAc,QAAA,CAAA,EAAA,MAAA;EAG5B,WAAA,CAAA,EAAA,MAAc;EAEd,QAAA,CAAA,EAVC,cAUkB,GAAA,IAAA;EAKnB,IAAA,CAAA,EAAA,MAAA,EAAA;EAAoB,UAAA,CAAA,EAbjB,cAaiB;YAKpB,CAAA,EAAA,MAAA;UAMQ,CAAA,EAtBP,MAsBO,CAAA,MAAA,EAAA,OAAA,CAAA;EAAM,UAAA,CAAA,EAAA,CAAA,QAAA,EArBA,cAqBA,EAAA,GAAA,IAAA;AAa1B,CAAA;AAAyB,KA/Bb,cAAA,GA+Ba,YAAA,GAAA,SAAA;AAEf,KA/BE,mBAAA,GA+BF;UACG,EAAA,MAAA;QACY,EA/Bf,cA+Be;;AAAlB,KA5BK,oBAAA,GA4BL;UACoC,EAAA,MAAA;SAAgC,EAAA,MAAA;UAAR,EAAA,MAAA;EAAO,MAAA,EAAA,SAAA,GAAA,aAAA;YAxB9D;;;;;;oBAMQ;;;;;;;;;;;;KAaR,aAAA;kCAEF,eACG,mCACN;YAAkB;UAA4B;;2CACV,wBAAwB,QAAQ"}
@@ -1,7 +1,8 @@
1
- import { encodeFileKey } from "../keys.js";
2
-
3
1
  //#region src/client/helpers.ts
4
2
  const DEFAULT_CONTENT_TYPE = "application/octet-stream";
3
+ const PROXY_UPLOAD_STRATEGY_HINT = "Server selected proxy upload strategy for this file (no direct upload URL was returned). If you expected direct-to-storage upload, your active provider/config does not support direct upload for this request.";
4
+ const PROXY_UPLOAD_RECOVERY_HINT = "Verify the /uploads/:uploadId/content endpoint is reachable from the client, or switch provider/config so /uploads returns a direct strategy.";
5
+ const DOWNLOAD_METHOD_HINT = "Pick the download method explicitly: use 'signed-url' for GET /files/by-key/download-url, otherwise use 'content' for GET /files/by-key/content.";
5
6
  const mergeHeaders = (base, next) => {
6
7
  const merged = new Headers(base ?? void 0);
7
8
  if (!next) return merged;
@@ -25,6 +26,74 @@ const readJsonSafely = async (response) => {
25
26
  return null;
26
27
  }
27
28
  };
29
+ const toErrorMessage = (error) => {
30
+ if (error instanceof Error && error.message) return error.message;
31
+ if (typeof error === "string" && error.length > 0) return error;
32
+ return "Unknown network error";
33
+ };
34
+ const readMessageFromPayload = (payload) => {
35
+ if (payload && typeof payload === "object" && "message" in payload && typeof payload.message === "string" && payload.message.length > 0) return payload.message;
36
+ return null;
37
+ };
38
+ const toAbsoluteUrl = (url) => {
39
+ try {
40
+ if (typeof window !== "undefined" && window.location?.origin) return new URL(url, window.location.origin);
41
+ return new URL(url, "http://fragno.local");
42
+ } catch {
43
+ return null;
44
+ }
45
+ };
46
+ const validateProxyContentUrl = (url) => {
47
+ const parsed = toAbsoluteUrl(url);
48
+ if (!parsed) return `Proxy upload endpoint '${url}' is not a valid URL.`;
49
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return `Proxy upload endpoint '${url}' must use http:// or https://.`;
50
+ if (typeof window !== "undefined" && window.location?.protocol === "https:" && parsed.protocol === "http:") return `Proxy upload endpoint '${url}' uses http:// on a https:// page.`;
51
+ return null;
52
+ };
53
+ const buildProxyUploadErrorMessage = (input) => {
54
+ const detailLines = [];
55
+ if (typeof input.status === "number") detailLines.push(`response status ${input.status}`);
56
+ if (input.streamError !== void 0) detailLines.push(`streamed upload error: ${toErrorMessage(input.streamError)}`);
57
+ if (input.fallbackError !== void 0) detailLines.push(`buffered upload error: ${toErrorMessage(input.fallbackError)}`);
58
+ const details = detailLines.length > 0 ? ` Details: ${detailLines.join(" | ")}.` : "";
59
+ return `${PROXY_UPLOAD_STRATEGY_HINT} Proxy upload to '${input.endpointUrl}' failed.${details} ${PROXY_UPLOAD_RECOVERY_HINT}`;
60
+ };
61
+ const buildDownloadRequestErrorMessage = (input) => {
62
+ const detailLines = [];
63
+ if (typeof input.status === "number") detailLines.push(`response status ${input.status}`);
64
+ const payloadMessage = readMessageFromPayload(input.payload);
65
+ if (payloadMessage) detailLines.push(`message: ${payloadMessage}`);
66
+ if (input.requestError !== void 0) detailLines.push(`request error: ${toErrorMessage(input.requestError)}`);
67
+ const details = detailLines.length > 0 ? ` Details: ${detailLines.join(" | ")}.` : "";
68
+ const hint = input.hint ? ` ${input.hint}` : "";
69
+ return `Download request to '${input.endpointUrl}' failed.${details}${hint}`;
70
+ };
71
+ const sanitizeSignedDownloadUrl = (url) => {
72
+ try {
73
+ const parsed = new URL(url);
74
+ parsed.search = "";
75
+ parsed.hash = "";
76
+ return parsed.toString();
77
+ } catch {
78
+ return "<redacted-signed-url>";
79
+ }
80
+ };
81
+ const readErrorCodeFromPayload = (payload) => {
82
+ if (payload && typeof payload === "object" && "code" in payload) {
83
+ const code = payload.code;
84
+ if (typeof code === "string" && code.length > 0) return code;
85
+ }
86
+ return null;
87
+ };
88
+ const hasText = (value) => typeof value === "string" && value.trim().length > 0;
89
+ const requireUploadEndpoint = (endpoint, label) => {
90
+ if (!hasText(endpoint)) throw new Error(`Missing ${label} endpoint for upload`);
91
+ return endpoint;
92
+ };
93
+ const buildByKeyQuery = (provider, fileKey) => new URLSearchParams({
94
+ provider,
95
+ key: fileKey
96
+ }).toString();
28
97
  const createUploadHelpers = (input) => {
29
98
  const { buildUrl, fetcher, defaultOptions } = input;
30
99
  const fetchJson = async (path, init, expectedErrorCode) => {
@@ -38,9 +107,9 @@ const createUploadHelpers = (input) => {
38
107
  }
39
108
  return await response.json();
40
109
  };
41
- const reportProgress = async (uploadId, progress, onProgress) => {
110
+ const reportProgress = async (progressEndpoint, progress, onProgress) => {
42
111
  onProgress?.(progress);
43
- await fetchJson(`/uploads/${uploadId}/progress`, {
112
+ await fetchJson(progressEndpoint, {
44
113
  method: "POST",
45
114
  headers: { "Content-Type": "application/json" },
46
115
  body: JSON.stringify({
@@ -53,12 +122,13 @@ const createUploadHelpers = (input) => {
53
122
  const filename = options.filename ?? (typeof File !== "undefined" && file instanceof File && file.name ? file.name : "upload");
54
123
  const contentType = options.contentType ?? (file.type && file.type.length > 0 ? file.type : void 0) ?? DEFAULT_CONTENT_TYPE;
55
124
  const sizeBytes = file.size;
56
- if (!options.keyParts && !options.fileKey) throw new Error("File key parts or file key is required");
125
+ if (!hasText(options.provider)) throw new Error("Provider is required");
126
+ if (!hasText(options.fileKey)) throw new Error("File key is required");
57
127
  const upload = await fetchJson("/uploads", {
58
128
  method: "POST",
59
129
  headers: { "Content-Type": "application/json" },
60
130
  body: JSON.stringify({
61
- keyParts: options.keyParts,
131
+ provider: options.provider,
62
132
  fileKey: options.fileKey,
63
133
  filename,
64
134
  sizeBytes,
@@ -73,6 +143,7 @@ const createUploadHelpers = (input) => {
73
143
  const totalBytes = sizeBytes;
74
144
  let bytesUploaded = 0;
75
145
  let partsUploaded = 0;
146
+ const progressEndpoint = requireUploadEndpoint(upload.upload.progressEndpoint, "progress");
76
147
  if (upload.strategy === "direct-single") {
77
148
  if (!upload.upload.uploadUrl) throw new Error("Missing upload URL for direct upload");
78
149
  const uploadResponse = await fetcher(upload.upload.uploadUrl, {
@@ -83,7 +154,7 @@ const createUploadHelpers = (input) => {
83
154
  if (!uploadResponse.ok) throw new Error(`Direct upload failed (${uploadResponse.status})`);
84
155
  bytesUploaded = totalBytes;
85
156
  partsUploaded = 1;
86
- await reportProgress(upload.uploadId, {
157
+ await reportProgress(progressEndpoint, {
87
158
  bytesUploaded,
88
159
  totalBytes,
89
160
  partsUploaded,
@@ -101,6 +172,7 @@ const createUploadHelpers = (input) => {
101
172
  if (upload.strategy === "direct-multipart") {
102
173
  const partSizeBytes = upload.upload.partSizeBytes;
103
174
  if (!partSizeBytes || !upload.upload.partsEndpoint) throw new Error("Missing multipart configuration for upload");
175
+ const partsCompleteEndpoint = requireUploadEndpoint(upload.upload.partsCompleteEndpoint, "multipart completion");
104
176
  const totalParts = Math.ceil(totalBytes / partSizeBytes);
105
177
  if (upload.upload.maxParts && totalParts > upload.upload.maxParts) throw new Error("Multipart upload exceeds maximum parts");
106
178
  const partNumbers = Array.from({ length: totalParts }, (_, i) => i + 1);
@@ -135,14 +207,14 @@ const createUploadHelpers = (input) => {
135
207
  });
136
208
  bytesUploaded += partSize;
137
209
  partsUploaded += 1;
138
- await reportProgress(upload.uploadId, {
210
+ await reportProgress(progressEndpoint, {
139
211
  bytesUploaded,
140
212
  totalBytes,
141
213
  partsUploaded,
142
214
  totalParts
143
215
  }, options.onProgress);
144
216
  }
145
- await fetchJson(`/uploads/${upload.uploadId}/parts/complete`, {
217
+ await fetchJson(partsCompleteEndpoint, {
146
218
  method: "POST",
147
219
  headers: { "Content-Type": "application/json" },
148
220
  body: JSON.stringify({ parts: completedParts })
@@ -157,6 +229,9 @@ const createUploadHelpers = (input) => {
157
229
  };
158
230
  }
159
231
  if (!upload.upload.contentEndpoint) throw new Error("Missing proxy content endpoint for upload");
232
+ const proxyContentUrl = buildUrl(upload.upload.contentEndpoint);
233
+ const proxyUrlValidationError = validateProxyContentUrl(proxyContentUrl);
234
+ if (proxyUrlValidationError) throw new Error(`${proxyUrlValidationError} ${PROXY_UPLOAD_RECOVERY_HINT}`);
160
235
  const source = file.stream();
161
236
  const stream = new ReadableStream({ start(controller) {
162
237
  const reader = source.getReader();
@@ -190,14 +265,27 @@ const createUploadHelpers = (input) => {
190
265
  requestInit.duplex = "half";
191
266
  let proxyResponse;
192
267
  try {
193
- proxyResponse = await fetcher(buildUrl(upload.upload.contentEndpoint), requestInit);
194
- } catch (_error) {
195
- const fallbackResponse = await fetcher(buildUrl(upload.upload.contentEndpoint), buildRequestInit(defaultOptions, {
196
- method: "PUT",
197
- headers: { "Content-Type": DEFAULT_CONTENT_TYPE },
198
- body: file
268
+ proxyResponse = await fetcher(proxyContentUrl, requestInit);
269
+ } catch (streamError) {
270
+ let fallbackResponse;
271
+ try {
272
+ fallbackResponse = await fetcher(proxyContentUrl, buildRequestInit(defaultOptions, {
273
+ method: "PUT",
274
+ headers: { "Content-Type": DEFAULT_CONTENT_TYPE },
275
+ body: file
276
+ }));
277
+ } catch (fallbackError) {
278
+ throw new Error(buildProxyUploadErrorMessage({
279
+ endpointUrl: proxyContentUrl,
280
+ streamError,
281
+ fallbackError
282
+ }));
283
+ }
284
+ if (!fallbackResponse.ok) throw new Error(buildProxyUploadErrorMessage({
285
+ endpointUrl: proxyContentUrl,
286
+ status: fallbackResponse.status,
287
+ streamError
199
288
  }));
200
- if (!fallbackResponse.ok) throw new Error(`Proxy upload failed (${fallbackResponse.status})`);
201
289
  options.onProgress?.({
202
290
  bytesUploaded: totalBytes,
203
291
  totalBytes,
@@ -208,28 +296,86 @@ const createUploadHelpers = (input) => {
208
296
  file: await fallbackResponse.json()
209
297
  };
210
298
  }
211
- if (!proxyResponse.ok) throw new Error(`Proxy upload failed (${proxyResponse.status})`);
299
+ if (!proxyResponse.ok) throw new Error(buildProxyUploadErrorMessage({
300
+ endpointUrl: proxyContentUrl,
301
+ status: proxyResponse.status
302
+ }));
212
303
  return {
213
304
  upload,
214
305
  file: await proxyResponse.json()
215
306
  };
216
307
  };
217
- const downloadFile = async (fileKeyOrParts) => {
218
- const fileKey = Array.isArray(fileKeyOrParts) ? encodeFileKey(fileKeyOrParts) : fileKeyOrParts;
219
- const downloadUrlResponse = await fetcher(buildUrl(`/files/${fileKey}/download-url`), buildRequestInit(defaultOptions, { method: "GET" }));
220
- if (downloadUrlResponse.ok) {
308
+ const downloadFile = async (fileKey, options) => {
309
+ if (!hasText(fileKey)) throw new Error("File key is required");
310
+ if (!options || !hasText(options.provider)) throw new Error("Download provider is required");
311
+ if (!options || options.method !== "signed-url" && options.method !== "content") throw new Error(`Download method is required. ${DOWNLOAD_METHOD_HINT}`);
312
+ const byKeyQuery = buildByKeyQuery(options.provider, fileKey);
313
+ if (options.method === "signed-url") {
314
+ const downloadUrlEndpoint = buildUrl(`/files/by-key/download-url?${byKeyQuery}`);
315
+ let downloadUrlResponse;
316
+ try {
317
+ downloadUrlResponse = await fetcher(downloadUrlEndpoint, buildRequestInit(defaultOptions, { method: "GET" }));
318
+ } catch (error) {
319
+ throw new Error(buildDownloadRequestErrorMessage({
320
+ endpointUrl: downloadUrlEndpoint,
321
+ requestError: error
322
+ }));
323
+ }
324
+ if (!downloadUrlResponse.ok) {
325
+ const errorPayload = await readJsonSafely(downloadUrlResponse);
326
+ const hint = readErrorCodeFromPayload(errorPayload) === "SIGNED_URL_UNSUPPORTED" ? "Requested method 'signed-url' is unsupported by this storage adapter. This is a programming error. Use method 'content' when streaming downloads are available." : void 0;
327
+ throw new Error(buildDownloadRequestErrorMessage({
328
+ endpointUrl: downloadUrlEndpoint,
329
+ status: downloadUrlResponse.status,
330
+ payload: errorPayload,
331
+ hint
332
+ }));
333
+ }
221
334
  const payload = await downloadUrlResponse.json();
222
- return fetcher(payload.url, {
223
- method: "GET",
224
- headers: payload.headers
225
- });
335
+ const sanitizedUrl = sanitizeSignedDownloadUrl(payload.url);
336
+ let response;
337
+ try {
338
+ response = await fetcher(payload.url, {
339
+ method: "GET",
340
+ headers: payload.headers
341
+ });
342
+ } catch (error) {
343
+ throw new Error(buildDownloadRequestErrorMessage({
344
+ endpointUrl: sanitizedUrl,
345
+ requestError: error
346
+ }));
347
+ }
348
+ if (!response.ok) {
349
+ const payloadError = await readJsonSafely(response);
350
+ throw new Error(buildDownloadRequestErrorMessage({
351
+ endpointUrl: sanitizedUrl,
352
+ status: response.status,
353
+ payload: payloadError
354
+ }));
355
+ }
356
+ return response;
226
357
  }
227
- const errorPayload = await readJsonSafely(downloadUrlResponse);
228
- if ((typeof errorPayload === "object" && errorPayload ? errorPayload.code : void 0) !== "SIGNED_URL_UNSUPPORTED") {
229
- const message = typeof errorPayload === "object" && errorPayload && "message" in errorPayload ? String(errorPayload.message) : `Download failed (${downloadUrlResponse.status})`;
230
- throw new Error(message);
358
+ const contentEndpoint = buildUrl(`/files/by-key/content?${byKeyQuery}`);
359
+ let contentResponse;
360
+ try {
361
+ contentResponse = await fetcher(contentEndpoint, buildRequestInit(defaultOptions, { method: "GET" }));
362
+ } catch (error) {
363
+ throw new Error(buildDownloadRequestErrorMessage({
364
+ endpointUrl: contentEndpoint,
365
+ requestError: error
366
+ }));
367
+ }
368
+ if (!contentResponse.ok) {
369
+ const contentError = await readJsonSafely(contentResponse);
370
+ const hint = readErrorCodeFromPayload(contentError) === "SIGNED_URL_UNSUPPORTED" ? "The 'content' download endpoint is unsupported by this storage adapter. This request used method 'content'. Use method 'signed-url' when signed downloads are available." : void 0;
371
+ throw new Error(buildDownloadRequestErrorMessage({
372
+ endpointUrl: contentEndpoint,
373
+ status: contentResponse.status,
374
+ payload: contentError,
375
+ hint
376
+ }));
231
377
  }
232
- return fetcher(buildUrl(`/files/${fileKey}/content`), buildRequestInit(defaultOptions, { method: "GET" }));
378
+ return contentResponse;
233
379
  };
234
380
  return {
235
381
  createUploadAndTransfer,
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","names":["createUploadAndTransfer: UploadHelpers[\"createUploadAndTransfer\"]","completedParts: { partNumber: number; etag: string; sizeBytes: number }[]","completionParts: { partNumber: number; etag: string }[]","proxyResponse: Response","downloadFile: UploadHelpers[\"downloadFile\"]"],"sources":["../../../src/client/helpers.ts"],"sourcesContent":["import { encodeFileKey, type FileKeyEncoded, type FileKeyParts } from \"../keys\";\nimport type { UploadChecksum } from \"../storage/types\";\nimport type { FileMetadata, FileVisibility, UploadStrategy } from \"../types\";\n\nexport type UploadProgress = {\n bytesUploaded: number;\n totalBytes: number;\n partsUploaded: number;\n totalParts?: number;\n};\n\nexport type CreateUploadAndTransferOptions = {\n keyParts?: FileKeyParts;\n fileKey?: FileKeyEncoded;\n filename?: string;\n contentType?: string;\n checksum?: UploadChecksum | null;\n tags?: string[];\n visibility?: FileVisibility;\n uploaderId?: string;\n metadata?: Record<string, unknown>;\n onProgress?: (progress: UploadProgress) => void;\n};\n\nexport type UploadCreateResponse = {\n uploadId: string;\n fileKey: string;\n status: \"created\";\n strategy: UploadStrategy;\n expiresAt: string;\n upload: {\n mode: \"single\" | \"multipart\";\n transport: \"direct\" | \"proxy\";\n uploadUrl?: string;\n uploadHeaders?: Record<string, string>;\n partSizeBytes?: number;\n maxParts?: number;\n partsEndpoint?: string;\n completeEndpoint: string;\n contentEndpoint?: string;\n };\n};\n\nexport type UploadHelpers = {\n createUploadAndTransfer: (\n file: Blob,\n options: CreateUploadAndTransferOptions,\n ) => Promise<{ upload: UploadCreateResponse; file: FileMetadata }>;\n downloadFile: (fileKeyOrParts: FileKeyEncoded | FileKeyParts) => Promise<Response>;\n};\n\nconst DEFAULT_CONTENT_TYPE = \"application/octet-stream\";\n\nconst mergeHeaders = (base?: HeadersInit, next?: HeadersInit) => {\n const merged = new Headers(base ?? undefined);\n\n if (!next) {\n return merged;\n }\n\n if (next instanceof Headers) {\n for (const [key, value] of next.entries()) {\n merged.set(key, value);\n }\n } else if (Array.isArray(next)) {\n for (const [key, value] of next) {\n merged.set(key, value);\n }\n } else {\n for (const [key, value] of Object.entries(next)) {\n merged.set(key, value);\n }\n }\n\n return merged;\n};\n\nconst buildRequestInit = (defaults: RequestInit | undefined, init: RequestInit): RequestInit => {\n if (!defaults) {\n return init;\n }\n\n return {\n ...defaults,\n ...init,\n headers: mergeHeaders(defaults.headers, init.headers),\n };\n};\n\nconst readJsonSafely = async (response: Response) => {\n try {\n return (await response.json()) as unknown;\n } catch {\n return null;\n }\n};\n\nexport const createUploadHelpers = (input: {\n buildUrl: (path: string) => string;\n fetcher: typeof fetch;\n defaultOptions?: RequestInit;\n}): UploadHelpers => {\n const { buildUrl, fetcher, defaultOptions } = input;\n\n const fetchJson = async <T>(\n path: string,\n init: RequestInit,\n expectedErrorCode?: string,\n ): Promise<T> => {\n const response = await fetcher(buildUrl(path), buildRequestInit(defaultOptions, init));\n\n if (!response.ok) {\n const payload = await readJsonSafely(response);\n const code =\n typeof payload === \"object\" && payload ? (payload as { code?: string }).code : undefined;\n if (expectedErrorCode && code === expectedErrorCode) {\n throw new Error(expectedErrorCode);\n }\n const message =\n typeof payload === \"object\" && payload && \"message\" in payload\n ? String((payload as { message?: string }).message)\n : `Request failed (${response.status})`;\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n };\n\n const reportProgress = async (\n uploadId: string,\n progress: UploadProgress,\n onProgress?: (progress: UploadProgress) => void,\n ) => {\n onProgress?.(progress);\n await fetchJson<{ bytesUploaded: number; partsUploaded: number }>(\n `/uploads/${uploadId}/progress`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n bytesUploaded: progress.bytesUploaded,\n partsUploaded: progress.partsUploaded,\n }),\n },\n );\n };\n\n const createUploadAndTransfer: UploadHelpers[\"createUploadAndTransfer\"] = async (\n file,\n options,\n ) => {\n const filename =\n options.filename ??\n (typeof File !== \"undefined\" && file instanceof File && file.name ? file.name : \"upload\");\n const contentType =\n options.contentType ??\n (file.type && file.type.length > 0 ? file.type : undefined) ??\n DEFAULT_CONTENT_TYPE;\n const sizeBytes = file.size;\n\n if (!options.keyParts && !options.fileKey) {\n throw new Error(\"File key parts or file key is required\");\n }\n\n const upload = await fetchJson<UploadCreateResponse>(\"/uploads\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n keyParts: options.keyParts,\n fileKey: options.fileKey,\n filename,\n sizeBytes,\n contentType,\n checksum: options.checksum ?? null,\n tags: options.tags,\n visibility: options.visibility,\n uploaderId: options.uploaderId,\n metadata: options.metadata,\n }),\n });\n\n const totalBytes = sizeBytes;\n let bytesUploaded = 0;\n let partsUploaded = 0;\n\n if (upload.strategy === \"direct-single\") {\n if (!upload.upload.uploadUrl) {\n throw new Error(\"Missing upload URL for direct upload\");\n }\n\n const uploadResponse = await fetcher(upload.upload.uploadUrl, {\n method: \"PUT\",\n headers: upload.upload.uploadHeaders,\n body: file,\n });\n\n if (!uploadResponse.ok) {\n throw new Error(`Direct upload failed (${uploadResponse.status})`);\n }\n\n bytesUploaded = totalBytes;\n partsUploaded = 1;\n await reportProgress(\n upload.uploadId,\n {\n bytesUploaded,\n totalBytes,\n partsUploaded,\n totalParts: 1,\n },\n options.onProgress,\n );\n\n const fileMetadata = await fetchJson<FileMetadata>(upload.upload.completeEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({}),\n });\n\n return { upload, file: fileMetadata };\n }\n\n if (upload.strategy === \"direct-multipart\") {\n const partSizeBytes = upload.upload.partSizeBytes;\n if (!partSizeBytes || !upload.upload.partsEndpoint) {\n throw new Error(\"Missing multipart configuration for upload\");\n }\n\n const totalParts = Math.ceil(totalBytes / partSizeBytes);\n if (upload.upload.maxParts && totalParts > upload.upload.maxParts) {\n throw new Error(\"Multipart upload exceeds maximum parts\");\n }\n\n const partNumbers = Array.from({ length: totalParts }, (_, i) => i + 1);\n const partUrls = await fetchJson<{\n parts: { partNumber: number; url: string; headers?: Record<string, string> }[];\n }>(upload.upload.partsEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ partNumbers }),\n });\n\n const parts = partUrls.parts.sort((a, b) => a.partNumber - b.partNumber);\n const completedParts: { partNumber: number; etag: string; sizeBytes: number }[] = [];\n const completionParts: { partNumber: number; etag: string }[] = [];\n\n for (const part of parts) {\n const start = (part.partNumber - 1) * partSizeBytes;\n const end = Math.min(start + partSizeBytes, totalBytes);\n const partBlob = file.slice(start, end);\n\n const response = await fetcher(part.url, {\n method: \"PUT\",\n headers: part.headers,\n body: partBlob,\n });\n\n if (!response.ok) {\n throw new Error(`Multipart upload failed (${response.status})`);\n }\n\n const etag = response.headers.get(\"ETag\") ?? response.headers.get(\"etag\");\n if (!etag) {\n throw new Error(\"Missing ETag for uploaded part\");\n }\n\n const partSize = partBlob.size;\n completedParts.push({ partNumber: part.partNumber, etag, sizeBytes: partSize });\n completionParts.push({ partNumber: part.partNumber, etag });\n\n bytesUploaded += partSize;\n partsUploaded += 1;\n await reportProgress(\n upload.uploadId,\n {\n bytesUploaded,\n totalBytes,\n partsUploaded,\n totalParts,\n },\n options.onProgress,\n );\n }\n\n await fetchJson<{ bytesUploaded: number; partsUploaded: number }>(\n `/uploads/${upload.uploadId}/parts/complete`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ parts: completedParts }),\n },\n );\n\n const fileMetadata = await fetchJson<FileMetadata>(upload.upload.completeEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ parts: completionParts }),\n });\n\n return { upload, file: fileMetadata };\n }\n\n if (!upload.upload.contentEndpoint) {\n throw new Error(\"Missing proxy content endpoint for upload\");\n }\n\n const source = file.stream();\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const reader = source.getReader();\n\n const pump = (): void => {\n reader.read().then(\n ({ done, value }) => {\n if (done) {\n controller.close();\n return;\n }\n\n if (value) {\n bytesUploaded += value.byteLength;\n options.onProgress?.({\n bytesUploaded,\n totalBytes,\n partsUploaded: 0,\n });\n controller.enqueue(value);\n }\n\n pump();\n },\n (error) => {\n controller.error(error);\n },\n );\n };\n\n pump();\n },\n });\n\n const requestInit = buildRequestInit(defaultOptions, {\n method: \"PUT\",\n headers: { \"Content-Type\": DEFAULT_CONTENT_TYPE },\n body: stream,\n }) as RequestInit & { duplex?: \"half\" };\n requestInit.duplex = \"half\";\n\n let proxyResponse: Response;\n try {\n proxyResponse = await fetcher(buildUrl(upload.upload.contentEndpoint), requestInit);\n } catch (_error) {\n const fallbackResponse = await fetcher(\n buildUrl(upload.upload.contentEndpoint),\n buildRequestInit(defaultOptions, {\n method: \"PUT\",\n headers: { \"Content-Type\": DEFAULT_CONTENT_TYPE },\n body: file,\n }),\n );\n\n if (!fallbackResponse.ok) {\n throw new Error(`Proxy upload failed (${fallbackResponse.status})`);\n }\n\n options.onProgress?.({\n bytesUploaded: totalBytes,\n totalBytes,\n partsUploaded: 0,\n });\n\n const fallbackMetadata = (await fallbackResponse.json()) as FileMetadata;\n return { upload, file: fallbackMetadata };\n }\n\n if (!proxyResponse.ok) {\n throw new Error(`Proxy upload failed (${proxyResponse.status})`);\n }\n\n const proxyMetadata = (await proxyResponse.json()) as FileMetadata;\n\n return { upload, file: proxyMetadata };\n };\n\n const downloadFile: UploadHelpers[\"downloadFile\"] = async (fileKeyOrParts) => {\n const fileKey = Array.isArray(fileKeyOrParts) ? encodeFileKey(fileKeyOrParts) : fileKeyOrParts;\n\n const downloadUrlResponse = await fetcher(\n buildUrl(`/files/${fileKey}/download-url`),\n buildRequestInit(defaultOptions, { method: \"GET\" }),\n );\n\n if (downloadUrlResponse.ok) {\n const payload = (await downloadUrlResponse.json()) as {\n url: string;\n headers?: Record<string, string>;\n };\n\n return fetcher(payload.url, {\n method: \"GET\",\n headers: payload.headers,\n });\n }\n\n const errorPayload = await readJsonSafely(downloadUrlResponse);\n const errorCode =\n typeof errorPayload === \"object\" && errorPayload\n ? (errorPayload as { code?: string }).code\n : undefined;\n\n if (errorCode !== \"SIGNED_URL_UNSUPPORTED\") {\n const message =\n typeof errorPayload === \"object\" && errorPayload && \"message\" in errorPayload\n ? String((errorPayload as { message?: string }).message)\n : `Download failed (${downloadUrlResponse.status})`;\n throw new Error(message);\n }\n\n return fetcher(\n buildUrl(`/files/${fileKey}/content`),\n buildRequestInit(defaultOptions, { method: \"GET\" }),\n );\n };\n\n return {\n createUploadAndTransfer,\n downloadFile,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"helpers.js","names":["detailLines: string[]","createUploadAndTransfer: UploadHelpers[\"createUploadAndTransfer\"]","completedParts: {\n partNumber: number;\n etag: string;\n sizeBytes: number;\n }[]","completionParts: { partNumber: number; etag: string }[]","proxyResponse: Response","fallbackResponse: Response","downloadFile: UploadHelpers[\"downloadFile\"]","downloadUrlResponse: Response","response: Response","contentResponse: Response"],"sources":["../../../src/client/helpers.ts"],"sourcesContent":["import type { UploadChecksum } from \"../storage/types\";\nimport type { FileMetadata, FileVisibility, UploadStrategy } from \"../types\";\n\nexport type UploadProgress = {\n bytesUploaded: number;\n totalBytes: number;\n partsUploaded: number;\n totalParts?: number;\n};\n\nexport type CreateUploadAndTransferOptions = {\n provider: string;\n fileKey: string;\n filename?: string;\n contentType?: string;\n checksum?: UploadChecksum | null;\n tags?: string[];\n visibility?: FileVisibility;\n uploaderId?: string;\n metadata?: Record<string, unknown>;\n onProgress?: (progress: UploadProgress) => void;\n};\n\nexport type DownloadMethod = \"signed-url\" | \"content\";\n\nexport type DownloadFileOptions = {\n provider: string;\n method: DownloadMethod;\n};\n\nexport type UploadCreateResponse = {\n uploadId: string;\n fileKey: string;\n provider: string;\n status: \"created\" | \"in_progress\";\n strategy: UploadStrategy;\n expiresAt: string;\n upload: {\n mode: \"single\" | \"multipart\";\n transport: \"direct\" | \"proxy\";\n uploadUrl?: string;\n uploadHeaders?: Record<string, string>;\n partSizeBytes?: number;\n maxParts?: number;\n statusEndpoint: string;\n progressEndpoint: string;\n partsEndpoint?: string;\n partsCompleteEndpoint?: string;\n completeEndpoint: string;\n abortEndpoint: string;\n contentEndpoint?: string;\n };\n};\n\nexport type UploadHelpers = {\n createUploadAndTransfer: (\n file: Blob,\n options: CreateUploadAndTransferOptions,\n ) => Promise<{ upload: UploadCreateResponse; file: FileMetadata }>;\n downloadFile: (fileKey: string, options: DownloadFileOptions) => Promise<Response>;\n};\n\nconst DEFAULT_CONTENT_TYPE = \"application/octet-stream\";\nconst PROXY_UPLOAD_STRATEGY_HINT =\n \"Server selected proxy upload strategy for this file (no direct upload URL was returned). If you expected direct-to-storage upload, your active provider/config does not support direct upload for this request.\";\nconst PROXY_UPLOAD_RECOVERY_HINT =\n \"Verify the /uploads/:uploadId/content endpoint is reachable from the client, or switch provider/config so /uploads returns a direct strategy.\";\nconst DOWNLOAD_METHOD_HINT =\n \"Pick the download method explicitly: use 'signed-url' for GET /files/by-key/download-url, otherwise use 'content' for GET /files/by-key/content.\";\n\nconst mergeHeaders = (base?: HeadersInit, next?: HeadersInit) => {\n const merged = new Headers(base ?? undefined);\n\n if (!next) {\n return merged;\n }\n\n if (next instanceof Headers) {\n for (const [key, value] of next.entries()) {\n merged.set(key, value);\n }\n } else if (Array.isArray(next)) {\n for (const [key, value] of next) {\n merged.set(key, value);\n }\n } else {\n for (const [key, value] of Object.entries(next)) {\n merged.set(key, value);\n }\n }\n\n return merged;\n};\n\nconst buildRequestInit = (defaults: RequestInit | undefined, init: RequestInit): RequestInit => {\n if (!defaults) {\n return init;\n }\n\n return {\n ...defaults,\n ...init,\n headers: mergeHeaders(defaults.headers, init.headers),\n };\n};\n\nconst readJsonSafely = async (response: Response) => {\n try {\n return (await response.json()) as unknown;\n } catch {\n return null;\n }\n};\n\nconst toErrorMessage = (error: unknown) => {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n\n if (typeof error === \"string\" && error.length > 0) {\n return error;\n }\n\n return \"Unknown network error\";\n};\n\nconst readMessageFromPayload = (payload: unknown): string | null => {\n if (\n payload &&\n typeof payload === \"object\" &&\n \"message\" in payload &&\n typeof payload.message === \"string\" &&\n payload.message.length > 0\n ) {\n return payload.message;\n }\n\n return null;\n};\n\nconst toAbsoluteUrl = (url: string): URL | null => {\n try {\n if (typeof window !== \"undefined\" && window.location?.origin) {\n return new URL(url, window.location.origin);\n }\n\n return new URL(url, \"http://fragno.local\");\n } catch {\n return null;\n }\n};\n\nconst validateProxyContentUrl = (url: string): string | null => {\n const parsed = toAbsoluteUrl(url);\n if (!parsed) {\n return `Proxy upload endpoint '${url}' is not a valid URL.`;\n }\n\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return `Proxy upload endpoint '${url}' must use http:// or https://.`;\n }\n\n if (\n typeof window !== \"undefined\" &&\n window.location?.protocol === \"https:\" &&\n parsed.protocol === \"http:\"\n ) {\n return `Proxy upload endpoint '${url}' uses http:// on a https:// page.`;\n }\n\n return null;\n};\n\nconst buildProxyUploadErrorMessage = (input: {\n endpointUrl: string;\n status?: number;\n streamError?: unknown;\n fallbackError?: unknown;\n}) => {\n const detailLines: string[] = [];\n if (typeof input.status === \"number\") {\n detailLines.push(`response status ${input.status}`);\n }\n if (input.streamError !== undefined) {\n detailLines.push(`streamed upload error: ${toErrorMessage(input.streamError)}`);\n }\n if (input.fallbackError !== undefined) {\n detailLines.push(`buffered upload error: ${toErrorMessage(input.fallbackError)}`);\n }\n\n const details = detailLines.length > 0 ? ` Details: ${detailLines.join(\" | \")}.` : \"\";\n return `${PROXY_UPLOAD_STRATEGY_HINT} Proxy upload to '${input.endpointUrl}' failed.${details} ${PROXY_UPLOAD_RECOVERY_HINT}`;\n};\n\nconst buildDownloadRequestErrorMessage = (input: {\n endpointUrl: string;\n status?: number;\n payload?: unknown;\n requestError?: unknown;\n hint?: string;\n}) => {\n const detailLines: string[] = [];\n if (typeof input.status === \"number\") {\n detailLines.push(`response status ${input.status}`);\n }\n\n const payloadMessage = readMessageFromPayload(input.payload);\n if (payloadMessage) {\n detailLines.push(`message: ${payloadMessage}`);\n }\n\n if (input.requestError !== undefined) {\n detailLines.push(`request error: ${toErrorMessage(input.requestError)}`);\n }\n\n const details = detailLines.length > 0 ? ` Details: ${detailLines.join(\" | \")}.` : \"\";\n const hint = input.hint ? ` ${input.hint}` : \"\";\n return `Download request to '${input.endpointUrl}' failed.${details}${hint}`;\n};\n\nconst sanitizeSignedDownloadUrl = (url: string) => {\n try {\n const parsed = new URL(url);\n parsed.search = \"\";\n parsed.hash = \"\";\n return parsed.toString();\n } catch {\n return \"<redacted-signed-url>\";\n }\n};\n\nconst readErrorCodeFromPayload = (payload: unknown): string | null => {\n if (payload && typeof payload === \"object\" && \"code\" in payload) {\n const code = (payload as { code?: unknown }).code;\n if (typeof code === \"string\" && code.length > 0) {\n return code;\n }\n }\n\n return null;\n};\n\nconst hasText = (value: string | undefined | null): value is string =>\n typeof value === \"string\" && value.trim().length > 0;\n\nconst requireUploadEndpoint = (endpoint: string | undefined, label: string) => {\n if (!hasText(endpoint)) {\n throw new Error(`Missing ${label} endpoint for upload`);\n }\n\n return endpoint;\n};\n\nconst buildByKeyQuery = (provider: string, fileKey: string) =>\n new URLSearchParams({ provider, key: fileKey }).toString();\n\nexport const createUploadHelpers = (input: {\n buildUrl: (path: string) => string;\n fetcher: typeof fetch;\n defaultOptions?: RequestInit;\n}): UploadHelpers => {\n const { buildUrl, fetcher, defaultOptions } = input;\n\n const fetchJson = async <T>(\n path: string,\n init: RequestInit,\n expectedErrorCode?: string,\n ): Promise<T> => {\n const response = await fetcher(buildUrl(path), buildRequestInit(defaultOptions, init));\n\n if (!response.ok) {\n const payload = await readJsonSafely(response);\n const code =\n typeof payload === \"object\" && payload ? (payload as { code?: string }).code : undefined;\n if (expectedErrorCode && code === expectedErrorCode) {\n throw new Error(expectedErrorCode);\n }\n const message =\n typeof payload === \"object\" && payload && \"message\" in payload\n ? String((payload as { message?: string }).message)\n : `Request failed (${response.status})`;\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n };\n\n const reportProgress = async (\n progressEndpoint: string,\n progress: UploadProgress,\n onProgress?: (progress: UploadProgress) => void,\n ) => {\n onProgress?.(progress);\n await fetchJson<{ bytesUploaded: number; partsUploaded: number }>(progressEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n bytesUploaded: progress.bytesUploaded,\n partsUploaded: progress.partsUploaded,\n }),\n });\n };\n\n const createUploadAndTransfer: UploadHelpers[\"createUploadAndTransfer\"] = async (\n file,\n options,\n ) => {\n const filename =\n options.filename ??\n (typeof File !== \"undefined\" && file instanceof File && file.name ? file.name : \"upload\");\n const contentType =\n options.contentType ??\n (file.type && file.type.length > 0 ? file.type : undefined) ??\n DEFAULT_CONTENT_TYPE;\n const sizeBytes = file.size;\n\n if (!hasText(options.provider)) {\n throw new Error(\"Provider is required\");\n }\n\n if (!hasText(options.fileKey)) {\n throw new Error(\"File key is required\");\n }\n\n const upload = await fetchJson<UploadCreateResponse>(\"/uploads\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n provider: options.provider,\n fileKey: options.fileKey,\n filename,\n sizeBytes,\n contentType,\n checksum: options.checksum ?? null,\n tags: options.tags,\n visibility: options.visibility,\n uploaderId: options.uploaderId,\n metadata: options.metadata,\n }),\n });\n\n const totalBytes = sizeBytes;\n let bytesUploaded = 0;\n let partsUploaded = 0;\n const progressEndpoint = requireUploadEndpoint(upload.upload.progressEndpoint, \"progress\");\n\n if (upload.strategy === \"direct-single\") {\n if (!upload.upload.uploadUrl) {\n throw new Error(\"Missing upload URL for direct upload\");\n }\n\n const uploadResponse = await fetcher(upload.upload.uploadUrl, {\n method: \"PUT\",\n headers: upload.upload.uploadHeaders,\n body: file,\n });\n\n if (!uploadResponse.ok) {\n throw new Error(`Direct upload failed (${uploadResponse.status})`);\n }\n\n bytesUploaded = totalBytes;\n partsUploaded = 1;\n await reportProgress(\n progressEndpoint,\n {\n bytesUploaded,\n totalBytes,\n partsUploaded,\n totalParts: 1,\n },\n options.onProgress,\n );\n\n const fileMetadata = await fetchJson<FileMetadata>(upload.upload.completeEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({}),\n });\n\n return { upload, file: fileMetadata };\n }\n\n if (upload.strategy === \"direct-multipart\") {\n const partSizeBytes = upload.upload.partSizeBytes;\n if (!partSizeBytes || !upload.upload.partsEndpoint) {\n throw new Error(\"Missing multipart configuration for upload\");\n }\n const partsCompleteEndpoint = requireUploadEndpoint(\n upload.upload.partsCompleteEndpoint,\n \"multipart completion\",\n );\n\n const totalParts = Math.ceil(totalBytes / partSizeBytes);\n if (upload.upload.maxParts && totalParts > upload.upload.maxParts) {\n throw new Error(\"Multipart upload exceeds maximum parts\");\n }\n\n const partNumbers = Array.from({ length: totalParts }, (_, i) => i + 1);\n const partUrls = await fetchJson<{\n parts: {\n partNumber: number;\n url: string;\n headers?: Record<string, string>;\n }[];\n }>(upload.upload.partsEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ partNumbers }),\n });\n\n const parts = partUrls.parts.sort((a, b) => a.partNumber - b.partNumber);\n const completedParts: {\n partNumber: number;\n etag: string;\n sizeBytes: number;\n }[] = [];\n const completionParts: { partNumber: number; etag: string }[] = [];\n\n for (const part of parts) {\n const start = (part.partNumber - 1) * partSizeBytes;\n const end = Math.min(start + partSizeBytes, totalBytes);\n const partBlob = file.slice(start, end);\n\n const response = await fetcher(part.url, {\n method: \"PUT\",\n headers: part.headers,\n body: partBlob,\n });\n\n if (!response.ok) {\n throw new Error(`Multipart upload failed (${response.status})`);\n }\n\n const etag = response.headers.get(\"ETag\") ?? response.headers.get(\"etag\");\n if (!etag) {\n throw new Error(\"Missing ETag for uploaded part\");\n }\n\n const partSize = partBlob.size;\n completedParts.push({\n partNumber: part.partNumber,\n etag,\n sizeBytes: partSize,\n });\n completionParts.push({ partNumber: part.partNumber, etag });\n\n bytesUploaded += partSize;\n partsUploaded += 1;\n await reportProgress(\n progressEndpoint,\n {\n bytesUploaded,\n totalBytes,\n partsUploaded,\n totalParts,\n },\n options.onProgress,\n );\n }\n\n await fetchJson<{ bytesUploaded: number; partsUploaded: number }>(partsCompleteEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ parts: completedParts }),\n });\n\n const fileMetadata = await fetchJson<FileMetadata>(upload.upload.completeEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ parts: completionParts }),\n });\n\n return { upload, file: fileMetadata };\n }\n\n if (!upload.upload.contentEndpoint) {\n throw new Error(\"Missing proxy content endpoint for upload\");\n }\n\n const proxyContentUrl = buildUrl(upload.upload.contentEndpoint);\n const proxyUrlValidationError = validateProxyContentUrl(proxyContentUrl);\n if (proxyUrlValidationError) {\n throw new Error(`${proxyUrlValidationError} ${PROXY_UPLOAD_RECOVERY_HINT}`);\n }\n\n const source = file.stream();\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const reader = source.getReader();\n\n const pump = (): void => {\n reader.read().then(\n ({ done, value }) => {\n if (done) {\n controller.close();\n return;\n }\n\n if (value) {\n bytesUploaded += value.byteLength;\n options.onProgress?.({\n bytesUploaded,\n totalBytes,\n partsUploaded: 0,\n });\n controller.enqueue(value);\n }\n\n pump();\n },\n (error) => {\n controller.error(error);\n },\n );\n };\n\n pump();\n },\n });\n\n const requestInit = buildRequestInit(defaultOptions, {\n method: \"PUT\",\n headers: { \"Content-Type\": DEFAULT_CONTENT_TYPE },\n body: stream,\n }) as RequestInit & { duplex?: \"half\" };\n requestInit.duplex = \"half\";\n\n let proxyResponse: Response;\n try {\n proxyResponse = await fetcher(proxyContentUrl, requestInit);\n } catch (streamError) {\n let fallbackResponse: Response;\n try {\n fallbackResponse = await fetcher(\n proxyContentUrl,\n buildRequestInit(defaultOptions, {\n method: \"PUT\",\n headers: { \"Content-Type\": DEFAULT_CONTENT_TYPE },\n body: file,\n }),\n );\n } catch (fallbackError) {\n throw new Error(\n buildProxyUploadErrorMessage({\n endpointUrl: proxyContentUrl,\n streamError,\n fallbackError,\n }),\n );\n }\n\n if (!fallbackResponse.ok) {\n throw new Error(\n buildProxyUploadErrorMessage({\n endpointUrl: proxyContentUrl,\n status: fallbackResponse.status,\n streamError,\n }),\n );\n }\n\n options.onProgress?.({\n bytesUploaded: totalBytes,\n totalBytes,\n partsUploaded: 0,\n });\n\n const fallbackMetadata = (await fallbackResponse.json()) as FileMetadata;\n return { upload, file: fallbackMetadata };\n }\n\n if (!proxyResponse.ok) {\n throw new Error(\n buildProxyUploadErrorMessage({\n endpointUrl: proxyContentUrl,\n status: proxyResponse.status,\n }),\n );\n }\n\n const proxyMetadata = (await proxyResponse.json()) as FileMetadata;\n\n return { upload, file: proxyMetadata };\n };\n\n const downloadFile: UploadHelpers[\"downloadFile\"] = async (fileKey, options) => {\n if (!hasText(fileKey)) {\n throw new Error(\"File key is required\");\n }\n\n if (!options || !hasText(options.provider)) {\n throw new Error(\"Download provider is required\");\n }\n\n if (!options || (options.method !== \"signed-url\" && options.method !== \"content\")) {\n throw new Error(`Download method is required. ${DOWNLOAD_METHOD_HINT}`);\n }\n\n const byKeyQuery = buildByKeyQuery(options.provider, fileKey);\n\n if (options.method === \"signed-url\") {\n const downloadUrlEndpoint = buildUrl(`/files/by-key/download-url?${byKeyQuery}`);\n\n let downloadUrlResponse: Response;\n try {\n downloadUrlResponse = await fetcher(\n downloadUrlEndpoint,\n buildRequestInit(defaultOptions, { method: \"GET\" }),\n );\n } catch (error) {\n throw new Error(\n buildDownloadRequestErrorMessage({\n endpointUrl: downloadUrlEndpoint,\n requestError: error,\n }),\n );\n }\n\n if (!downloadUrlResponse.ok) {\n const errorPayload = await readJsonSafely(downloadUrlResponse);\n const errorCode = readErrorCodeFromPayload(errorPayload);\n const hint =\n errorCode === \"SIGNED_URL_UNSUPPORTED\"\n ? \"Requested method 'signed-url' is unsupported by this storage adapter. This is a programming error. Use method 'content' when streaming downloads are available.\"\n : undefined;\n throw new Error(\n buildDownloadRequestErrorMessage({\n endpointUrl: downloadUrlEndpoint,\n status: downloadUrlResponse.status,\n payload: errorPayload,\n hint,\n }),\n );\n }\n\n const payload = (await downloadUrlResponse.json()) as {\n url: string;\n headers?: Record<string, string>;\n };\n const sanitizedUrl = sanitizeSignedDownloadUrl(payload.url);\n\n let response: Response;\n try {\n response = await fetcher(payload.url, {\n method: \"GET\",\n headers: payload.headers,\n });\n } catch (error) {\n throw new Error(\n buildDownloadRequestErrorMessage({\n endpointUrl: sanitizedUrl,\n requestError: error,\n }),\n );\n }\n\n if (!response.ok) {\n const payloadError = await readJsonSafely(response);\n throw new Error(\n buildDownloadRequestErrorMessage({\n endpointUrl: sanitizedUrl,\n status: response.status,\n payload: payloadError,\n }),\n );\n }\n\n return response;\n }\n\n const contentEndpoint = buildUrl(`/files/by-key/content?${byKeyQuery}`);\n let contentResponse: Response;\n try {\n contentResponse = await fetcher(\n contentEndpoint,\n buildRequestInit(defaultOptions, { method: \"GET\" }),\n );\n } catch (error) {\n throw new Error(\n buildDownloadRequestErrorMessage({\n endpointUrl: contentEndpoint,\n requestError: error,\n }),\n );\n }\n\n if (!contentResponse.ok) {\n const contentError = await readJsonSafely(contentResponse);\n const errorCode = readErrorCodeFromPayload(contentError);\n const hint =\n errorCode === \"SIGNED_URL_UNSUPPORTED\"\n ? \"The 'content' download endpoint is unsupported by this storage adapter. This request used method 'content'. Use method 'signed-url' when signed downloads are available.\"\n : undefined;\n throw new Error(\n buildDownloadRequestErrorMessage({\n endpointUrl: contentEndpoint,\n status: contentResponse.status,\n payload: contentError,\n hint,\n }),\n );\n }\n\n return contentResponse;\n };\n\n return {\n createUploadAndTransfer,\n downloadFile,\n };\n};\n"],"mappings":"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"}