@backblaze-labs/b2-sdk 0.3.0 → 0.4.0

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 (393) hide show
  1. package/CHANGELOG.md +45 -1
  2. package/README.md +18 -5
  3. package/dist/_virtual/_b2-sdk-version-json.cjs +1 -1
  4. package/dist/_virtual/_b2-sdk-version-json.js +1 -1
  5. package/dist/auth/reauth-coalescer.cjs +65 -0
  6. package/dist/auth/reauth-coalescer.cjs.map +1 -0
  7. package/dist/auth/reauth-coalescer.d.cts +34 -0
  8. package/dist/auth/reauth-coalescer.d.cts.map +1 -0
  9. package/dist/auth/reauth-coalescer.d.ts +34 -0
  10. package/dist/auth/reauth-coalescer.d.ts.map +1 -0
  11. package/dist/auth/reauth-coalescer.js +65 -0
  12. package/dist/auth/reauth-coalescer.js.map +1 -0
  13. package/dist/backup/raw.cjs +37 -15
  14. package/dist/backup/raw.cjs.map +1 -1
  15. package/dist/backup/raw.d.cts +2 -2
  16. package/dist/backup/raw.d.cts.map +1 -1
  17. package/dist/backup/raw.d.ts +2 -2
  18. package/dist/backup/raw.d.ts.map +1 -1
  19. package/dist/backup/raw.js +37 -15
  20. package/dist/backup/raw.js.map +1 -1
  21. package/dist/bucket-validation.cjs +111 -0
  22. package/dist/bucket-validation.cjs.map +1 -0
  23. package/dist/bucket-validation.d.cts +27 -0
  24. package/dist/bucket-validation.d.cts.map +1 -0
  25. package/dist/bucket-validation.d.ts +27 -0
  26. package/dist/bucket-validation.d.ts.map +1 -0
  27. package/dist/bucket-validation.js +109 -0
  28. package/dist/bucket-validation.js.map +1 -0
  29. package/dist/bucket.cjs +123 -73
  30. package/dist/bucket.cjs.map +1 -1
  31. package/dist/bucket.d.cts +156 -61
  32. package/dist/bucket.d.cts.map +1 -1
  33. package/dist/bucket.d.ts +156 -61
  34. package/dist/bucket.d.ts.map +1 -1
  35. package/dist/bucket.js +123 -73
  36. package/dist/bucket.js.map +1 -1
  37. package/dist/client.cjs +29 -8
  38. package/dist/client.cjs.map +1 -1
  39. package/dist/client.d.cts +30 -9
  40. package/dist/client.d.cts.map +1 -1
  41. package/dist/client.d.ts +30 -9
  42. package/dist/client.d.ts.map +1 -1
  43. package/dist/client.js +29 -8
  44. package/dist/client.js.map +1 -1
  45. package/dist/download/single.cjs +38 -13
  46. package/dist/download/single.cjs.map +1 -1
  47. package/dist/download/single.d.cts +10 -4
  48. package/dist/download/single.d.cts.map +1 -1
  49. package/dist/download/single.d.ts +10 -4
  50. package/dist/download/single.d.ts.map +1 -1
  51. package/dist/download/single.js +38 -13
  52. package/dist/download/single.js.map +1 -1
  53. package/dist/errors/index.cjs +27 -4
  54. package/dist/errors/index.cjs.map +1 -1
  55. package/dist/errors/index.d.cts +15 -0
  56. package/dist/errors/index.d.cts.map +1 -1
  57. package/dist/errors/index.d.ts +15 -0
  58. package/dist/errors/index.d.ts.map +1 -1
  59. package/dist/errors/index.js +27 -5
  60. package/dist/errors/index.js.map +1 -1
  61. package/dist/http/non-idempotent-mutations.cjs +38 -0
  62. package/dist/http/non-idempotent-mutations.cjs.map +1 -0
  63. package/dist/http/non-idempotent-mutations.d.cts +25 -0
  64. package/dist/http/non-idempotent-mutations.d.cts.map +1 -0
  65. package/dist/http/non-idempotent-mutations.d.ts +25 -0
  66. package/dist/http/non-idempotent-mutations.d.ts.map +1 -0
  67. package/dist/http/non-idempotent-mutations.js +35 -0
  68. package/dist/http/non-idempotent-mutations.js.map +1 -0
  69. package/dist/http/transport.cjs +9 -8
  70. package/dist/http/transport.cjs.map +1 -1
  71. package/dist/http/transport.d.cts +5 -0
  72. package/dist/http/transport.d.cts.map +1 -1
  73. package/dist/http/transport.d.ts +5 -0
  74. package/dist/http/transport.d.ts.map +1 -1
  75. package/dist/http/transport.js +9 -8
  76. package/dist/http/transport.js.map +1 -1
  77. package/dist/http/user-agent.cjs +12 -1
  78. package/dist/http/user-agent.cjs.map +1 -1
  79. package/dist/http/user-agent.d.cts +8 -0
  80. package/dist/http/user-agent.d.cts.map +1 -1
  81. package/dist/http/user-agent.d.ts +8 -0
  82. package/dist/http/user-agent.d.ts.map +1 -1
  83. package/dist/http/user-agent.js +13 -3
  84. package/dist/http/user-agent.js.map +1 -1
  85. package/dist/index.cjs +25 -0
  86. package/dist/index.d.cts +10 -9
  87. package/dist/index.d.cts.map +1 -1
  88. package/dist/index.d.ts +10 -9
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +7 -6
  91. package/dist/notifications/index.cjs +3 -0
  92. package/dist/notifications/index.d.cts +2 -0
  93. package/dist/notifications/index.d.cts.map +1 -1
  94. package/dist/notifications/index.d.ts +2 -0
  95. package/dist/notifications/index.d.ts.map +1 -1
  96. package/dist/notifications/index.js +2 -1
  97. package/dist/object.cjs +12 -1
  98. package/dist/object.cjs.map +1 -1
  99. package/dist/object.d.cts +7 -1
  100. package/dist/object.d.cts.map +1 -1
  101. package/dist/object.d.ts +7 -1
  102. package/dist/object.d.ts.map +1 -1
  103. package/dist/object.js +12 -1
  104. package/dist/object.js.map +1 -1
  105. package/dist/partner/auth-core.cjs +4 -23
  106. package/dist/partner/auth-core.cjs.map +1 -1
  107. package/dist/partner/auth-core.d.cts +1 -1
  108. package/dist/partner/auth-core.d.cts.map +1 -1
  109. package/dist/partner/auth-core.d.ts +1 -1
  110. package/dist/partner/auth-core.d.ts.map +1 -1
  111. package/dist/partner/auth-core.js +5 -24
  112. package/dist/partner/auth-core.js.map +1 -1
  113. package/dist/partner/client.cjs +25 -10
  114. package/dist/partner/client.cjs.map +1 -1
  115. package/dist/partner/client.d.cts +32 -10
  116. package/dist/partner/client.d.cts.map +1 -1
  117. package/dist/partner/client.d.ts +32 -10
  118. package/dist/partner/client.d.ts.map +1 -1
  119. package/dist/partner/client.js +25 -10
  120. package/dist/partner/client.js.map +1 -1
  121. package/dist/partner/endpoint-url.cjs +1 -0
  122. package/dist/partner/endpoint-url.cjs.map +1 -1
  123. package/dist/partner/endpoint-url.d.cts +2 -0
  124. package/dist/partner/endpoint-url.d.cts.map +1 -1
  125. package/dist/partner/endpoint-url.d.ts +2 -0
  126. package/dist/partner/endpoint-url.d.ts.map +1 -1
  127. package/dist/partner/endpoint-url.js +1 -0
  128. package/dist/partner/endpoint-url.js.map +1 -1
  129. package/dist/partner/in-memory.cjs.map +1 -1
  130. package/dist/partner/in-memory.js.map +1 -1
  131. package/dist/partner/index.cjs +9 -0
  132. package/dist/partner/index.d.cts +11 -2
  133. package/dist/partner/index.d.cts.map +1 -1
  134. package/dist/partner/index.d.ts +11 -2
  135. package/dist/partner/index.d.ts.map +1 -1
  136. package/dist/partner/index.js +3 -1
  137. package/dist/partner/raw.cjs +52 -44
  138. package/dist/partner/raw.cjs.map +1 -1
  139. package/dist/partner/raw.d.cts +16 -19
  140. package/dist/partner/raw.d.cts.map +1 -1
  141. package/dist/partner/raw.d.ts +16 -19
  142. package/dist/partner/raw.d.ts.map +1 -1
  143. package/dist/partner/raw.js +52 -44
  144. package/dist/partner/raw.js.map +1 -1
  145. package/dist/partner/redaction.cjs +133 -108
  146. package/dist/partner/redaction.cjs.map +1 -1
  147. package/dist/partner/redaction.d.cts +47 -13
  148. package/dist/partner/redaction.d.cts.map +1 -1
  149. package/dist/partner/redaction.d.ts +47 -13
  150. package/dist/partner/redaction.d.ts.map +1 -1
  151. package/dist/partner/redaction.js +133 -109
  152. package/dist/partner/redaction.js.map +1 -1
  153. package/dist/raw/encoding.cjs +29 -10
  154. package/dist/raw/encoding.cjs.map +1 -1
  155. package/dist/raw/encoding.d.cts +3 -2
  156. package/dist/raw/encoding.d.cts.map +1 -1
  157. package/dist/raw/encoding.d.ts +3 -2
  158. package/dist/raw/encoding.d.ts.map +1 -1
  159. package/dist/raw/encoding.js +29 -10
  160. package/dist/raw/encoding.js.map +1 -1
  161. package/dist/raw/index.cjs +64 -39
  162. package/dist/raw/index.cjs.map +1 -1
  163. package/dist/raw/index.d.cts +21 -19
  164. package/dist/raw/index.d.cts.map +1 -1
  165. package/dist/raw/index.d.ts +21 -19
  166. package/dist/raw/index.d.ts.map +1 -1
  167. package/dist/raw/index.js +47 -40
  168. package/dist/raw/index.js.map +1 -1
  169. package/dist/raw/url.cjs.map +1 -1
  170. package/dist/raw/url.d.cts +3 -3
  171. package/dist/raw/url.d.ts +3 -3
  172. package/dist/raw/url.js.map +1 -1
  173. package/dist/simulator/index.cjs +456 -125
  174. package/dist/simulator/index.cjs.map +1 -1
  175. package/dist/simulator/index.d.cts +16 -1
  176. package/dist/simulator/index.d.cts.map +1 -1
  177. package/dist/simulator/index.d.ts +16 -1
  178. package/dist/simulator/index.d.ts.map +1 -1
  179. package/dist/simulator/index.js +449 -130
  180. package/dist/simulator/index.js.map +1 -1
  181. package/dist/simulator/partner-capabilities.cjs +77 -0
  182. package/dist/simulator/partner-capabilities.cjs.map +1 -0
  183. package/dist/simulator/partner-capabilities.d.cts +53 -0
  184. package/dist/simulator/partner-capabilities.d.cts.map +1 -0
  185. package/dist/simulator/partner-capabilities.d.ts +53 -0
  186. package/dist/simulator/partner-capabilities.d.ts.map +1 -0
  187. package/dist/simulator/partner-capabilities.js +73 -0
  188. package/dist/simulator/partner-capabilities.js.map +1 -0
  189. package/dist/simulator/partner.cjs +55 -61
  190. package/dist/simulator/partner.cjs.map +1 -1
  191. package/dist/simulator/partner.d.cts +5 -2
  192. package/dist/simulator/partner.d.cts.map +1 -1
  193. package/dist/simulator/partner.d.ts +5 -2
  194. package/dist/simulator/partner.d.ts.map +1 -1
  195. package/dist/simulator/partner.js +56 -61
  196. package/dist/simulator/partner.js.map +1 -1
  197. package/dist/simulator/validation.cjs +160 -30
  198. package/dist/simulator/validation.cjs.map +1 -1
  199. package/dist/simulator/validation.d.cts +28 -6
  200. package/dist/simulator/validation.d.cts.map +1 -1
  201. package/dist/simulator/validation.d.ts +28 -6
  202. package/dist/simulator/validation.d.ts.map +1 -1
  203. package/dist/simulator/validation.js +148 -31
  204. package/dist/simulator/validation.js.map +1 -1
  205. package/dist/streams/file-source.cjs +1 -1
  206. package/dist/streams/file-source.cjs.map +1 -1
  207. package/dist/streams/file-source.js +1 -1
  208. package/dist/streams/file-source.js.map +1 -1
  209. package/dist/streams/hash.cjs +246 -13
  210. package/dist/streams/hash.cjs.map +1 -1
  211. package/dist/streams/hash.d.cts +37 -12
  212. package/dist/streams/hash.d.cts.map +1 -1
  213. package/dist/streams/hash.d.ts +37 -12
  214. package/dist/streams/hash.d.ts.map +1 -1
  215. package/dist/streams/hash.js +246 -15
  216. package/dist/streams/hash.js.map +1 -1
  217. package/dist/streams/index.cjs +2 -0
  218. package/dist/streams/index.d.cts +1 -1
  219. package/dist/streams/index.d.cts.map +1 -1
  220. package/dist/streams/index.d.ts +1 -1
  221. package/dist/streams/index.d.ts.map +1 -1
  222. package/dist/streams/index.js +2 -2
  223. package/dist/streams/progress.cjs +63 -4
  224. package/dist/streams/progress.cjs.map +1 -1
  225. package/dist/streams/progress.d.cts +28 -2
  226. package/dist/streams/progress.d.cts.map +1 -1
  227. package/dist/streams/progress.d.ts +28 -2
  228. package/dist/streams/progress.d.ts.map +1 -1
  229. package/dist/streams/progress.js +63 -4
  230. package/dist/streams/progress.js.map +1 -1
  231. package/dist/sync/download-staging.cjs +147 -35
  232. package/dist/sync/download-staging.cjs.map +1 -1
  233. package/dist/sync/download-staging.d.cts +25 -2
  234. package/dist/sync/download-staging.d.cts.map +1 -1
  235. package/dist/sync/download-staging.d.ts +25 -2
  236. package/dist/sync/download-staging.d.ts.map +1 -1
  237. package/dist/sync/download-staging.js +146 -36
  238. package/dist/sync/download-staging.js.map +1 -1
  239. package/dist/sync/index.d.cts +1 -1
  240. package/dist/sync/index.d.cts.map +1 -1
  241. package/dist/sync/index.d.ts +1 -1
  242. package/dist/sync/index.d.ts.map +1 -1
  243. package/dist/sync/local-file-io.cjs +5 -1
  244. package/dist/sync/local-file-io.cjs.map +1 -1
  245. package/dist/sync/local-file-io.d.cts +2 -0
  246. package/dist/sync/local-file-io.d.cts.map +1 -1
  247. package/dist/sync/local-file-io.d.ts +2 -0
  248. package/dist/sync/local-file-io.d.ts.map +1 -1
  249. package/dist/sync/local-file-io.js +5 -1
  250. package/dist/sync/local-file-io.js.map +1 -1
  251. package/dist/sync/pairing.cjs +1 -0
  252. package/dist/sync/pairing.cjs.map +1 -1
  253. package/dist/sync/pairing.js +1 -0
  254. package/dist/sync/pairing.js.map +1 -1
  255. package/dist/sync/scanners/b2.cjs +2 -0
  256. package/dist/sync/scanners/b2.cjs.map +1 -1
  257. package/dist/sync/scanners/b2.d.cts.map +1 -1
  258. package/dist/sync/scanners/b2.d.ts.map +1 -1
  259. package/dist/sync/scanners/b2.js +2 -0
  260. package/dist/sync/scanners/b2.js.map +1 -1
  261. package/dist/sync/scanners/local.cjs +150 -33
  262. package/dist/sync/scanners/local.cjs.map +1 -1
  263. package/dist/sync/scanners/local.d.cts +6 -0
  264. package/dist/sync/scanners/local.d.cts.map +1 -1
  265. package/dist/sync/scanners/local.d.ts +6 -0
  266. package/dist/sync/scanners/local.d.ts.map +1 -1
  267. package/dist/sync/scanners/local.js +150 -33
  268. package/dist/sync/scanners/local.js.map +1 -1
  269. package/dist/sync/synchronizer.cjs +76 -29
  270. package/dist/sync/synchronizer.cjs.map +1 -1
  271. package/dist/sync/synchronizer.d.cts +1 -0
  272. package/dist/sync/synchronizer.d.cts.map +1 -1
  273. package/dist/sync/synchronizer.d.ts +1 -0
  274. package/dist/sync/synchronizer.d.ts.map +1 -1
  275. package/dist/sync/synchronizer.js +76 -29
  276. package/dist/sync/synchronizer.js.map +1 -1
  277. package/dist/sync/types.d.cts +19 -3
  278. package/dist/sync/types.d.cts.map +1 -1
  279. package/dist/sync/types.d.ts +19 -3
  280. package/dist/sync/types.d.ts.map +1 -1
  281. package/dist/types/backup.d.cts +6 -1
  282. package/dist/types/backup.d.cts.map +1 -1
  283. package/dist/types/backup.d.ts +6 -1
  284. package/dist/types/backup.d.ts.map +1 -1
  285. package/dist/types/bucket.cjs +81 -11
  286. package/dist/types/bucket.cjs.map +1 -1
  287. package/dist/types/bucket.d.cts +190 -39
  288. package/dist/types/bucket.d.cts.map +1 -1
  289. package/dist/types/bucket.d.ts +190 -39
  290. package/dist/types/bucket.d.ts.map +1 -1
  291. package/dist/types/bucket.js +67 -12
  292. package/dist/types/bucket.js.map +1 -1
  293. package/dist/types/download.cjs.map +1 -1
  294. package/dist/types/download.d.cts +3 -17
  295. package/dist/types/download.d.cts.map +1 -1
  296. package/dist/types/download.d.ts +3 -17
  297. package/dist/types/download.d.ts.map +1 -1
  298. package/dist/types/download.js.map +1 -1
  299. package/dist/types/encryption.cjs +18 -0
  300. package/dist/types/encryption.cjs.map +1 -1
  301. package/dist/types/encryption.d.cts +21 -11
  302. package/dist/types/encryption.d.cts.map +1 -1
  303. package/dist/types/encryption.d.ts +21 -11
  304. package/dist/types/encryption.d.ts.map +1 -1
  305. package/dist/types/encryption.js +18 -0
  306. package/dist/types/encryption.js.map +1 -1
  307. package/dist/types/file.cjs +3 -0
  308. package/dist/types/file.cjs.map +1 -1
  309. package/dist/types/file.d.cts +125 -16
  310. package/dist/types/file.d.cts.map +1 -1
  311. package/dist/types/file.d.ts +125 -16
  312. package/dist/types/file.d.ts.map +1 -1
  313. package/dist/types/file.js +3 -1
  314. package/dist/types/file.js.map +1 -1
  315. package/dist/types/index.d.cts +7 -7
  316. package/dist/types/index.d.cts.map +1 -1
  317. package/dist/types/index.d.ts +7 -7
  318. package/dist/types/index.d.ts.map +1 -1
  319. package/dist/types/key.d.cts +4 -3
  320. package/dist/types/key.d.cts.map +1 -1
  321. package/dist/types/key.d.ts +4 -3
  322. package/dist/types/key.d.ts.map +1 -1
  323. package/dist/types/notifications.cjs +30 -0
  324. package/dist/types/notifications.cjs.map +1 -1
  325. package/dist/types/notifications.d.cts +26 -1
  326. package/dist/types/notifications.d.cts.map +1 -1
  327. package/dist/types/notifications.d.ts +26 -1
  328. package/dist/types/notifications.d.ts.map +1 -1
  329. package/dist/types/notifications.js +29 -1
  330. package/dist/types/notifications.js.map +1 -1
  331. package/dist/types/partner.cjs.map +1 -1
  332. package/dist/types/partner.d.cts +28 -36
  333. package/dist/types/partner.d.cts.map +1 -1
  334. package/dist/types/partner.d.ts +28 -36
  335. package/dist/types/partner.d.ts.map +1 -1
  336. package/dist/types/partner.js.map +1 -1
  337. package/dist/types/upload.d.cts +4 -0
  338. package/dist/types/upload.d.cts.map +1 -1
  339. package/dist/types/upload.d.ts +4 -0
  340. package/dist/types/upload.d.ts.map +1 -1
  341. package/dist/upload/large.cjs +10 -7
  342. package/dist/upload/large.cjs.map +1 -1
  343. package/dist/upload/large.d.cts +15 -6
  344. package/dist/upload/large.d.cts.map +1 -1
  345. package/dist/upload/large.d.ts +15 -6
  346. package/dist/upload/large.d.ts.map +1 -1
  347. package/dist/upload/large.js +10 -7
  348. package/dist/upload/large.js.map +1 -1
  349. package/dist/upload/options.cjs.map +1 -1
  350. package/dist/upload/options.d.cts +12 -0
  351. package/dist/upload/options.d.cts.map +1 -1
  352. package/dist/upload/options.d.ts +12 -0
  353. package/dist/upload/options.d.ts.map +1 -1
  354. package/dist/upload/options.js.map +1 -1
  355. package/dist/upload/resume.cjs +4 -3
  356. package/dist/upload/resume.cjs.map +1 -1
  357. package/dist/upload/resume.d.cts +6 -4
  358. package/dist/upload/resume.d.cts.map +1 -1
  359. package/dist/upload/resume.d.ts +6 -4
  360. package/dist/upload/resume.d.ts.map +1 -1
  361. package/dist/upload/resume.js +4 -3
  362. package/dist/upload/resume.js.map +1 -1
  363. package/dist/upload/retry.cjs +17 -10
  364. package/dist/upload/retry.cjs.map +1 -1
  365. package/dist/upload/retry.d.cts.map +1 -1
  366. package/dist/upload/retry.d.ts.map +1 -1
  367. package/dist/upload/retry.js +17 -10
  368. package/dist/upload/retry.js.map +1 -1
  369. package/dist/upload/single.cjs +35 -31
  370. package/dist/upload/single.cjs.map +1 -1
  371. package/dist/upload/single.d.cts +6 -0
  372. package/dist/upload/single.d.cts.map +1 -1
  373. package/dist/upload/single.d.ts +6 -0
  374. package/dist/upload/single.d.ts.map +1 -1
  375. package/dist/upload/single.js +35 -31
  376. package/dist/upload/single.js.map +1 -1
  377. package/dist/upload/stream.cjs +12 -1
  378. package/dist/upload/stream.cjs.map +1 -1
  379. package/dist/upload/stream.d.cts +6 -0
  380. package/dist/upload/stream.d.cts.map +1 -1
  381. package/dist/upload/stream.d.ts +6 -0
  382. package/dist/upload/stream.d.ts.map +1 -1
  383. package/dist/upload/stream.js +12 -1
  384. package/dist/upload/stream.js.map +1 -1
  385. package/dist/version.cjs +56 -4
  386. package/dist/version.cjs.map +1 -1
  387. package/dist/version.d.cts +53 -4
  388. package/dist/version.d.cts.map +1 -1
  389. package/dist/version.d.ts +53 -4
  390. package/dist/version.d.ts.map +1 -1
  391. package/dist/version.js +52 -5
  392. package/dist/version.js.map +1 -1
  393. package/package.json +11 -4
@@ -1 +1 @@
1
- {"version":3,"file":"resume.js","names":[],"sources":["../../src/upload/resume.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport { ResumeFileIdMismatchError } from '../errors/index.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { BucketRetentionMode, type BucketRetentionPolicy } from '../types/bucket.ts'\nimport {\n EncryptionMode,\n type EncryptionSetting,\n type PublicEncryptionSetting,\n} from '../types/encryption.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport { largeFileId as largeFileIdOf } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport type {\n ReadableFileRetention,\n ReadableLegalHold,\n UnfinishedLargeFile,\n} from '../types/upload.ts'\n\nexport { ResumeFileIdMismatchError }\n\n/** Compatibility-only file-info key read from legacy unfinished uploads; new uploads do not write it. */\nexport const RESUME_SOURCE_SIZE_INFO_KEY = 'b2_sdk_resume_source_size'\n\n/** Compatibility-only file-info key read from legacy unfinished uploads; new uploads do not write it. */\nexport const RESUME_PART_SIZE_INFO_KEY = 'b2_sdk_resume_part_size'\n\nconst DEFAULT_MAX_RESUME_LIST_PAGES = 10\nconst DEFAULT_MAX_RESUME_PART_CANDIDATES = 25\nconst DEFAULT_MAX_RESUME_PART_PAGES = 10\n\n/** One planned part from the local upload source. */\nexport interface ResumePartPlan {\n /** 1-based B2 part number. */\n readonly partNumber: number\n /** Expected byte length for this part. */\n readonly length: number\n}\n\n/** Reason an unfinished same-name large file was not reused for resume. */\nexport type ResumeCandidateRejectedReason =\n | 'search-truncated'\n | 'candidate-limit'\n | 'file-name-mismatch'\n | 'content-type-mismatch'\n | 'file-info-mismatch'\n | 'source-size-mismatch'\n | 'part-size-mismatch'\n | 'upload-timestamp-mismatch'\n | 'encryption-mismatch'\n | 'sse-c-unsupported'\n | 'retention-mismatch'\n | 'legal-hold-mismatch'\n | 'part-length-mismatch'\n\n/** Diagnostic event emitted when resume discovery declines a candidate. */\nexport interface ResumeCandidateRejectedEvent {\n /** ID of the unfinished large file, when the event is candidate-specific. */\n readonly fileId?: LargeFileId\n /** Requested destination file name. */\n readonly requestedFileName: string\n /** Actual candidate file name, when the event is candidate-specific. */\n readonly candidateFileName?: string\n /** Machine-readable rejection reason. */\n readonly reason: ResumeCandidateRejectedReason\n}\n\n/** Diagnostic callback for declined resume candidates. */\nexport type ResumeCandidateRejectedListener = (event: ResumeCandidateRejectedEvent) => void\n\n/** Compatibility requirements an unfinished large file must satisfy before reuse. */\nexport interface ResumeCandidateCriteria {\n /** Effective MIME type for the upload, including SDK defaults. */\n readonly contentType: string\n /** Caller-owned file info. Legacy SDK resume keys on candidates are ignored separately. */\n readonly fileInfo: Record<string, string>\n /** Source size in bytes, checked against legacy SDK metadata when a candidate carries it. */\n readonly sourceSize: number\n /** Effective multipart part size, checked against legacy SDK metadata when present. */\n readonly partSize: number\n /** Planned local parts used to verify already-uploaded server part lengths. */\n readonly parts: readonly ResumePartPlan[]\n /** Requested B2 upload timestamp override, if configured by the caller. */\n readonly customUploadTimestamp?: number\n /** Explicit server-side encryption option, if configured by the caller. */\n readonly serverSideEncryption?: EncryptionSetting\n /** Explicit Object Lock retention option, if configured by the caller. */\n readonly fileRetention?: FileRetentionValue\n /** Effective readable bucket default retention when the caller omits fileRetention. */\n readonly defaultFileRetention?: BucketRetentionPolicy\n /** Whether bucket default retention exists but cannot be read by the caller. */\n readonly defaultFileRetentionUnreadable?: boolean\n /** Explicit legal hold option, if configured by the caller. */\n readonly legalHold?: LegalHoldValue\n /** Explicit unfinished large-file ID to verify before reuse. */\n readonly resumeFileId?: LargeFileId\n /** Abort signal used for B2 list requests and checked between pages. */\n readonly signal?: AbortSignal\n /** Optional diagnostic callback for candidates that are found but not reused. */\n readonly onCandidateRejected?: ResumeCandidateRejectedListener\n /** Maximum `b2_list_unfinished_large_files` pages to inspect. */\n readonly maxListPages?: number\n /** Maximum metadata-compatible candidates whose parts may be listed. */\n readonly maxPartCandidates?: number\n /** Maximum `b2_list_parts` pages to inspect for each metadata-compatible candidate. */\n readonly maxPartPages?: number\n /** Caller-supplied aggregate resume discovery timeout. */\n readonly discoveryTimeoutMs?: number\n}\n\n/** Uploaded part metadata used by the resume planner. */\nexport interface ResumePartInfo {\n /** SHA-1 stored by B2 for this uploaded part. */\n readonly contentSha1: string\n /** Byte length stored by B2 for this uploaded part. */\n readonly contentLength: number\n}\n\nconst LIST_PARTS_PAGE_SIZE = 100\n\n/** Information about an unfinished large file eligible for resume. */\nexport interface ResumeCandidate {\n /** ID of the unfinished large file. */\n readonly fileId: LargeFileId\n /** SHA-1 of each part already uploaded, indexed by 1-based part number. */\n readonly uploadedPartSha1s: ReadonlyMap<number, string>\n}\n\n/**\n * Finds an unfinished large file matching the given bucket and file name.\n * Returns `null` when no compatible candidate exists.\n *\n * With criteria, the newest compatible candidate is selected; incompatible\n * same-name uploads are ignored and optionally reported via\n * `onCandidateRejected`.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param bucketId - Target bucket of the upload.\n * @param fileName - Destination file name of the upload.\n * @param criteria - Upload identity and option checks.\n *\n * @returns A {@link ResumeCandidate} describing the candidate and its uploaded parts, or `null`.\n */\nexport async function findResumeCandidate(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n fileName: string,\n criteria: ResumeCandidateCriteria,\n): Promise<ResumeCandidate | null> {\n const discoverySignal = createResumeDiscoverySignal(criteria)\n try {\n return await findResumeCandidateWithSignal(\n raw,\n accountInfo,\n bucketId,\n fileName,\n criteria,\n discoverySignal.signal,\n )\n } finally {\n discoverySignal.dispose()\n }\n}\n\nasync function findResumeCandidateWithSignal(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n fileName: string,\n criteria: ResumeCandidateCriteria,\n signal: AbortSignal | undefined,\n): Promise<ResumeCandidate | null> {\n const matches: Array<{ file: UnfinishedLargeFile; sequence: number }> = []\n const maxListPages = criteria.maxListPages ?? DEFAULT_MAX_RESUME_LIST_PAGES\n const maxPartCandidates = criteria.maxPartCandidates ?? DEFAULT_MAX_RESUME_PART_CANDIDATES\n let sequence = 0\n let pageCount = 0\n const explicitResumeFileId = criteria.resumeFileId\n let startFileId: LargeFileId | undefined = explicitResumeFileId\n let truncated = false\n\n while (pageCount < maxListPages) {\n signal?.throwIfAborted()\n const unfinished = await abortableRequest(\n raw.listUnfinishedLargeFiles(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n bucketId,\n maxFileCount: explicitResumeFileId !== undefined ? 1 : 100,\n namePrefix: fileName,\n ...(startFileId !== undefined ? { startFileId } : {}),\n },\n signal !== undefined ? { signal } : undefined,\n ),\n signal,\n )\n pageCount++\n\n for (const file of unfinished.files) {\n const isMatch =\n explicitResumeFileId !== undefined\n ? file.fileId === explicitResumeFileId\n : file.fileName === fileName\n if (isMatch) {\n matches.push({ file, sequence })\n }\n sequence++\n }\n\n if (explicitResumeFileId !== undefined) break\n if (unfinished.nextFileId === null) break\n startFileId = unfinished.nextFileId\n truncated = pageCount >= maxListPages\n }\n\n if (truncated) {\n emitCandidateRejected(criteria, {\n requestedFileName: fileName,\n reason: 'search-truncated',\n })\n }\n\n matches.sort(compareNewestFirst)\n\n let partCandidatesInspected = 0\n for (const match of matches) {\n signal?.throwIfAborted()\n const rejection = candidateMetadataRejectReason(match.file, fileName, criteria)\n if (rejection !== null) {\n notifyCandidateRejected(criteria, match.file, fileName, rejection)\n continue\n }\n\n if (partCandidatesInspected >= maxPartCandidates) {\n notifyCandidateRejected(criteria, match.file, fileName, 'candidate-limit')\n break\n }\n\n partCandidatesInspected++\n const fileId = largeFileIdOf(match.file.fileId)\n const uploadedPartsResult = await collectResumePartInfo(raw, accountInfo, fileId, {\n maxPages: criteria.maxPartPages ?? DEFAULT_MAX_RESUME_PART_PAGES,\n maxParts: criteria.parts.length,\n ...(signal !== undefined ? { signal } : {}),\n })\n const uploadedParts = uploadedPartsResult.parts\n if (uploadedPartsResult.truncated || !uploadedPartsMatchPlan(uploadedParts, criteria.parts)) {\n notifyCandidateRejected(criteria, match.file, fileName, 'part-length-mismatch')\n continue\n }\n\n return { fileId, uploadedPartSha1s: partInfoToSha1s(uploadedParts) }\n }\n\n return null\n}\n\ninterface CollectResumePartInfoOptions {\n readonly signal?: AbortSignal\n readonly maxPages?: number\n readonly maxParts?: number\n}\n\nasync function collectResumePartInfo(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n options: CollectResumePartInfoOptions,\n): Promise<{ readonly parts: Map<number, ResumePartInfo>; readonly truncated: boolean }> {\n const parts = new Map<number, ResumePartInfo>()\n const maxPages = options.maxPages ?? Number.POSITIVE_INFINITY\n const maxParts = options.maxParts ?? Number.POSITIVE_INFINITY\n let startPartNumber: number | undefined\n let pageCount = 0\n\n while (pageCount < maxPages) {\n options.signal?.throwIfAborted()\n // Fetch one part beyond the local plan so a candidate with extra uploaded\n // parts is detected and rejected instead of silently reused.\n const remainingParts =\n maxParts === Number.POSITIVE_INFINITY\n ? undefined\n : Math.max(1, Math.min(LIST_PARTS_PAGE_SIZE, maxParts - parts.size + 1))\n const page = await abortableRequest(\n raw.listParts(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n fileId,\n ...(startPartNumber !== undefined ? { startPartNumber } : {}),\n ...(remainingParts !== undefined ? { maxPartCount: remainingParts } : {}),\n },\n options.signal !== undefined ? { signal: options.signal } : undefined,\n ),\n options.signal,\n )\n pageCount++\n for (const part of page.parts) {\n parts.set(part.partNumber, {\n contentSha1: part.contentSha1,\n contentLength: part.contentLength,\n })\n if (parts.size > maxParts) return { parts, truncated: true }\n }\n if (page.nextPartNumber === null) return { parts, truncated: false }\n assertAdvancingPartCursor(fileId, startPartNumber, page.nextPartNumber)\n startPartNumber = page.nextPartNumber\n }\n\n return { parts, truncated: true }\n}\n\nfunction compareNewestFirst(\n a: { file: UnfinishedLargeFile; sequence: number },\n b: { file: UnfinishedLargeFile; sequence: number },\n): number {\n const aTime = a.file.uploadTimestamp ?? Number.NEGATIVE_INFINITY\n const bTime = b.file.uploadTimestamp ?? Number.NEGATIVE_INFINITY\n if (aTime !== bTime) return bTime - aTime\n return b.sequence - a.sequence\n}\n\nfunction candidateMetadataRejectReason(\n candidate: UnfinishedLargeFile,\n fileName: string,\n criteria: ResumeCandidateCriteria,\n): ResumeCandidateRejectedReason | null {\n if (candidate.fileName !== fileName) return 'file-name-mismatch'\n if (\n criteria.contentType === 'b2/x-auto' &&\n criteria.resumeFileId === undefined &&\n candidate.contentType !== 'b2/x-auto'\n ) {\n return 'content-type-mismatch'\n }\n if (criteria.contentType !== 'b2/x-auto' && candidate.contentType !== criteria.contentType) {\n return 'content-type-mismatch'\n }\n\n const candidateInfo = splitResumeFileInfo(candidate.fileInfo ?? {})\n if (!recordEquals(candidateInfo.fileInfo, criteria.fileInfo)) return 'file-info-mismatch'\n if (\n candidateInfo.sourceSize !== undefined &&\n candidateInfo.sourceSize !== String(criteria.sourceSize)\n ) {\n return 'source-size-mismatch'\n }\n if (\n candidateInfo.partSize !== undefined &&\n candidateInfo.partSize !== String(criteria.partSize)\n ) {\n return 'part-size-mismatch'\n }\n if (\n criteria.customUploadTimestamp !== undefined &&\n candidate.uploadTimestamp !== criteria.customUploadTimestamp\n ) {\n return 'upload-timestamp-mismatch'\n }\n\n const encryptionRejectReason = serverSideEncryptionRejectReason(\n candidate.serverSideEncryption,\n criteria.serverSideEncryption,\n )\n if (encryptionRejectReason !== null) return encryptionRejectReason\n if (\n !fileRetentionMatches(\n candidate.fileRetention,\n criteria.fileRetention,\n criteria.defaultFileRetention,\n criteria.defaultFileRetentionUnreadable === true,\n candidate.uploadTimestamp,\n )\n ) {\n return 'retention-mismatch'\n }\n if (!legalHoldMatches(candidate.legalHold, criteria.legalHold)) {\n return 'legal-hold-mismatch'\n }\n\n return null\n}\n\nfunction notifyCandidateRejected(\n criteria: ResumeCandidateCriteria,\n candidate: UnfinishedLargeFile,\n requestedFileName: string,\n reason: ResumeCandidateRejectedReason,\n): void {\n emitCandidateRejected(criteria, {\n fileId: largeFileIdOf(candidate.fileId),\n requestedFileName,\n candidateFileName: candidate.fileName,\n reason,\n })\n}\n\nfunction emitCandidateRejected(\n criteria: ResumeCandidateCriteria,\n event: ResumeCandidateRejectedEvent,\n): void {\n try {\n criteria.onCandidateRejected?.(event)\n } catch {\n // Diagnostic listeners should not make an otherwise valid upload fail.\n }\n}\n\nfunction uploadedPartsMatchPlan(\n uploadedParts: ReadonlyMap<number, ResumePartInfo>,\n plans: readonly ResumePartPlan[],\n): boolean {\n for (const [partNumber, part] of uploadedParts) {\n const planned = plans[partNumber - 1]\n if (planned === undefined) return false\n if (planned.partNumber !== partNumber) return false\n if (planned.length !== part.contentLength) return false\n }\n return true\n}\n\nfunction partInfoToSha1s(parts: ReadonlyMap<number, ResumePartInfo>): Map<number, string> {\n const sha1s = new Map<number, string>()\n for (const [partNumber, part] of parts) {\n sha1s.set(partNumber, part.contentSha1)\n }\n return sha1s\n}\n\nfunction recordEquals(a: Record<string, string>, b: Record<string, string>): boolean {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) return false\n for (const key of aKeys) {\n if (a[key] !== b[key]) return false\n }\n return true\n}\n\ninterface SplitResumeFileInfo {\n readonly fileInfo: Record<string, string>\n readonly sourceSize?: string\n readonly partSize?: string\n}\n\nfunction splitResumeFileInfo(fileInfo: Record<string, string>): SplitResumeFileInfo {\n const userFileInfo: Record<string, string> = Object.create(null) as Record<string, string>\n let sourceSize: string | undefined\n let partSize: string | undefined\n for (const [key, value] of Object.entries(fileInfo)) {\n if (key === RESUME_SOURCE_SIZE_INFO_KEY) {\n sourceSize = value\n } else if (key === RESUME_PART_SIZE_INFO_KEY) {\n partSize = value\n } else {\n userFileInfo[key] = value\n }\n }\n return {\n fileInfo: userFileInfo,\n ...(sourceSize !== undefined ? { sourceSize } : {}),\n ...(partSize !== undefined ? { partSize } : {}),\n }\n}\n\nfunction fileRetentionMatches(\n candidate: ReadableFileRetention | undefined,\n expected: FileRetentionValue | undefined,\n defaultExpected: BucketRetentionPolicy | undefined,\n defaultUnreadable: boolean,\n uploadTimestamp: number | undefined,\n): boolean {\n if (expected === undefined && defaultUnreadable) return false\n if (expected === undefined && defaultExpected !== undefined) {\n if (defaultExpected.mode === BucketRetentionMode.None) {\n if (candidate === undefined) return true\n if (!candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueEquals(candidate.value, null)\n }\n if (candidate === undefined || !candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueMatchesBucketDefault(candidate.value, defaultExpected, uploadTimestamp)\n }\n if (expected === undefined) {\n if (candidate === undefined) return true\n if (!candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueEquals(candidate.value, null)\n }\n if (candidate === undefined || !candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueEquals(candidate.value, expected)\n}\n\nfunction fileRetentionValueMatchesBucketDefault(\n candidate: FileRetentionValue | null,\n expected: BucketRetentionPolicy,\n uploadTimestamp: number | undefined,\n): boolean {\n if (expected.period === null) return false\n if (candidate?.mode !== expected.mode || candidate.retainUntilTimestamp === null) return false\n if (uploadTimestamp === undefined) return false\n return candidate.retainUntilTimestamp === uploadTimestamp + retentionPeriodMillis(expected.period)\n}\n\nfunction retentionPeriodMillis(period: BucketRetentionPolicy['period']): number {\n if (period === null) return 0\n const days = period.unit === 'days' ? period.duration : period.duration * 365\n return days * 24 * 60 * 60 * 1000\n}\n\nfunction fileRetentionValueEquals(\n a: FileRetentionValue | null,\n b: FileRetentionValue | null,\n): boolean {\n return (\n (a?.mode ?? null) === (b?.mode ?? null) &&\n (a?.retainUntilTimestamp ?? null) === (b?.retainUntilTimestamp ?? null)\n )\n}\n\nfunction legalHoldMatches(\n candidate: ReadableLegalHold | undefined,\n expected: LegalHoldValue | undefined,\n): boolean {\n if (expected === undefined) {\n if (candidate === undefined) return true\n if (!candidate.isClientAuthorizedToRead) return false\n return candidate.value === null || candidate.value === 'off'\n }\n if (candidate === undefined || !candidate.isClientAuthorizedToRead) return false\n return candidate.value === expected\n}\n\ninterface ResumeDiscoverySignal {\n readonly signal?: AbortSignal\n dispose(): void\n}\n\nfunction createResumeDiscoverySignal(criteria: ResumeCandidateCriteria): ResumeDiscoverySignal {\n if (criteria.signal !== undefined) {\n return {\n signal: criteria.signal,\n dispose() {},\n }\n }\n\n if (criteria.discoveryTimeoutMs === undefined) {\n return {\n dispose() {},\n }\n }\n\n const timeoutMs = criteria.discoveryTimeoutMs\n if (timeoutMs === Number.POSITIVE_INFINITY) {\n return {\n dispose() {},\n }\n }\n\n const controller = new AbortController()\n const timeout = setTimeout(\n () => {\n controller.abort(resumeDiscoveryTimeoutReason(timeoutMs))\n },\n Math.max(0, timeoutMs),\n )\n\n return {\n signal: controller.signal,\n dispose() {\n clearTimeout(timeout)\n },\n }\n}\n\nasync function abortableRequest<T>(\n request: Promise<T>,\n signal: AbortSignal | undefined,\n): Promise<T> {\n if (signal === undefined) return request\n if (signal.aborted) throw resumeAbortReason(signal)\n\n let removeAbortListener: (() => void) | undefined\n const aborted = new Promise<never>((_resolve, reject) => {\n const onAbort = () => reject(resumeAbortReason(signal))\n signal.addEventListener('abort', onAbort, { once: true })\n removeAbortListener = () => signal.removeEventListener('abort', onAbort)\n })\n\n try {\n return await Promise.race([request, aborted])\n } finally {\n removeAbortListener?.()\n void request.catch(() => {})\n }\n}\n\nfunction resumeAbortReason(signal: AbortSignal): unknown {\n return signal.reason ?? resumeAbortFallbackReason()\n}\n\nfunction resumeAbortFallbackReason(): Error {\n if (typeof DOMException === 'function') {\n return new DOMException('Resume discovery aborted', 'AbortError')\n }\n const error = new Error('Resume discovery aborted')\n error.name = 'AbortError'\n return error\n}\n\nfunction resumeDiscoveryTimeoutReason(timeoutMs: number): Error {\n if (typeof DOMException === 'function') {\n return new DOMException(`Resume discovery timed out after ${timeoutMs} ms`, 'TimeoutError')\n }\n const error = new Error(`Resume discovery timed out after ${timeoutMs} ms`)\n error.name = 'TimeoutError'\n return error\n}\n\ntype ListedEncryption = PublicEncryptionSetting | undefined\n\nfunction serverSideEncryptionRejectReason(\n candidate: ListedEncryption,\n expected: EncryptionSetting | undefined,\n): 'encryption-mismatch' | 'sse-c-unsupported' | null {\n if (expected?.mode === EncryptionMode.SseC) return 'sse-c-unsupported'\n\n const actual = normalizeEncryption(candidate)\n if (expected === undefined) {\n if (candidate === undefined) return null\n if (actual === undefined) return 'encryption-mismatch'\n if (actual.mode === EncryptionMode.None) return null\n if (actual.mode === EncryptionMode.SseB2) return null\n return actual.mode === EncryptionMode.SseC ? 'sse-c-unsupported' : 'encryption-mismatch'\n }\n\n const normalizedExpected = normalizeEncryption(expected)\n if (normalizedExpected?.mode === EncryptionMode.None && candidate === undefined) return null\n if (actual === undefined || normalizedExpected === undefined) return 'encryption-mismatch'\n if (actual.mode !== normalizedExpected.mode) return 'encryption-mismatch'\n if (actual.mode === EncryptionMode.None) return null\n return actual.algorithm === normalizedExpected.algorithm ? null : 'encryption-mismatch'\n}\n\ninterface NormalizedEncryption {\n readonly mode: EncryptionMode\n readonly algorithm?: string\n}\n\nfunction normalizeEncryption(\n encryption: EncryptionSetting | ListedEncryption,\n): NormalizedEncryption | undefined {\n if (encryption === undefined) return undefined\n // Real B2 responses may spell no encryption as `{ mode: null, algorithm: null }`.\n if (encryption.mode === null || encryption.mode === EncryptionMode.None) {\n return { mode: EncryptionMode.None }\n }\n if (encryption.mode !== EncryptionMode.SseB2 && encryption.mode !== EncryptionMode.SseC) {\n return undefined\n }\n return {\n mode: encryption.mode,\n algorithm: encryption.algorithm,\n }\n}\n\nfunction assertAdvancingPartCursor(\n fileId: LargeFileId,\n previous: number | undefined,\n next: number,\n): void {\n if (!Number.isInteger(next) || next < 1 || (previous !== undefined && next <= previous)) {\n throw new Error(\n `uploadLargeFile: listParts returned a non-advancing nextPartNumber for ${fileId}; aborting resume.`,\n )\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"resume.js","names":[],"sources":["../../src/upload/resume.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport { ResumeFileIdMismatchError } from '../errors/index.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport {\n type BucketDefaultRetention,\n type BucketDefaultServerSideEncryption,\n BucketRetentionMode,\n type BucketRetentionPolicy,\n} from '../types/bucket.ts'\nimport {\n EncryptionMode,\n type EncryptionSetting,\n type PublicEncryptionSetting,\n} from '../types/encryption.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport { largeFileId as largeFileIdOf } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport type {\n ReadableFileRetention,\n ReadableLegalHold,\n UnfinishedLargeFile,\n} from '../types/upload.ts'\n\nexport { ResumeFileIdMismatchError }\n\n/** Compatibility-only file-info key read from legacy unfinished uploads; new uploads do not write it. */\nexport const RESUME_SOURCE_SIZE_INFO_KEY = 'b2_sdk_resume_source_size'\n\n/** Compatibility-only file-info key read from legacy unfinished uploads; new uploads do not write it. */\nexport const RESUME_PART_SIZE_INFO_KEY = 'b2_sdk_resume_part_size'\n\nconst DEFAULT_MAX_RESUME_LIST_PAGES = 10\nconst DEFAULT_MAX_RESUME_PART_CANDIDATES = 25\nconst DEFAULT_MAX_RESUME_PART_PAGES = 10\n\n/** One planned part from the local upload source. */\nexport interface ResumePartPlan {\n /** 1-based B2 part number. */\n readonly partNumber: number\n /** Expected byte length for this part. */\n readonly length: number\n}\n\n/** Reason an unfinished same-name large file was not reused for resume. */\nexport type ResumeCandidateRejectedReason =\n | 'search-truncated'\n | 'candidate-limit'\n | 'file-name-mismatch'\n | 'content-type-mismatch'\n | 'file-info-mismatch'\n | 'source-size-mismatch'\n | 'part-size-mismatch'\n | 'upload-timestamp-mismatch'\n | 'encryption-mismatch'\n | 'sse-c-unsupported'\n | 'retention-mismatch'\n | 'legal-hold-mismatch'\n | 'part-length-mismatch'\n\n/** Diagnostic event emitted when resume discovery declines a candidate. */\nexport interface ResumeCandidateRejectedEvent {\n /** ID of the unfinished large file, when the event is candidate-specific. */\n readonly fileId?: LargeFileId\n /** Requested destination file name. */\n readonly requestedFileName: string\n /** Actual candidate file name, when the event is candidate-specific. */\n readonly candidateFileName?: string\n /** Machine-readable rejection reason. */\n readonly reason: ResumeCandidateRejectedReason\n}\n\n/** Diagnostic callback for declined resume candidates. */\nexport type ResumeCandidateRejectedListener = (event: ResumeCandidateRejectedEvent) => void\n\n/** Compatibility requirements an unfinished large file must satisfy before reuse. */\nexport interface ResumeCandidateCriteria {\n /** Effective MIME type for the upload, including SDK defaults. */\n readonly contentType: string\n /** Caller-owned file info. Legacy SDK resume keys on candidates are ignored separately. */\n readonly fileInfo: Record<string, string>\n /** Source size in bytes, checked against legacy SDK metadata when a candidate carries it. */\n readonly sourceSize: number\n /** Effective multipart part size, checked against legacy SDK metadata when present. */\n readonly partSize: number\n /** Planned local parts used to verify already-uploaded server part lengths. */\n readonly parts: readonly ResumePartPlan[]\n /** Requested B2 upload timestamp override, if configured by the caller. */\n readonly customUploadTimestamp?: number\n /** Explicit or effective readable bucket default server-side encryption. */\n readonly serverSideEncryption?: EncryptionSetting | BucketDefaultServerSideEncryption\n /** Whether bucket default encryption exists but cannot be read by the caller. */\n readonly defaultServerSideEncryptionUnreadable?: boolean\n /** Explicit Object Lock retention option, if configured by the caller. */\n readonly fileRetention?: FileRetentionValue\n /** Effective readable bucket default retention when the caller omits fileRetention. */\n readonly defaultFileRetention?: BucketDefaultRetention\n /** Whether bucket default retention exists but cannot be read by the caller. */\n readonly defaultFileRetentionUnreadable?: boolean\n /** Explicit legal hold option, if configured by the caller. */\n readonly legalHold?: LegalHoldValue\n /** Explicit unfinished large-file ID to verify before reuse. */\n readonly resumeFileId?: LargeFileId\n /** Abort signal used for B2 list requests and checked between pages. */\n readonly signal?: AbortSignal\n /** Optional diagnostic callback for candidates that are found but not reused. */\n readonly onCandidateRejected?: ResumeCandidateRejectedListener\n /** Maximum `b2_list_unfinished_large_files` pages to inspect. */\n readonly maxListPages?: number\n /** Maximum metadata-compatible candidates whose parts may be listed. */\n readonly maxPartCandidates?: number\n /** Maximum `b2_list_parts` pages to inspect for each metadata-compatible candidate. */\n readonly maxPartPages?: number\n /** Caller-supplied aggregate resume discovery timeout. */\n readonly discoveryTimeoutMs?: number\n}\n\n/** Uploaded part metadata used by the resume planner. */\nexport interface ResumePartInfo {\n /** SHA-1 stored by B2 for this uploaded part. */\n readonly contentSha1: string\n /** Byte length stored by B2 for this uploaded part. */\n readonly contentLength: number\n}\n\nconst LIST_PARTS_PAGE_SIZE = 100\n\n/** Information about an unfinished large file eligible for resume. */\nexport interface ResumeCandidate {\n /** ID of the unfinished large file. */\n readonly fileId: LargeFileId\n /** SHA-1 of each part already uploaded, indexed by 1-based part number. */\n readonly uploadedPartSha1s: ReadonlyMap<number, string>\n}\n\n/**\n * Finds an unfinished large file matching the given bucket and file name.\n * Returns `null` when no compatible candidate exists.\n *\n * With criteria, the newest compatible candidate is selected; incompatible\n * same-name uploads are ignored and optionally reported via\n * `onCandidateRejected`.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param bucketId - Target bucket of the upload.\n * @param fileName - Destination file name of the upload.\n * @param criteria - Upload identity and option checks.\n *\n * @returns A {@link ResumeCandidate} describing the candidate and its uploaded parts, or `null`.\n */\nexport async function findResumeCandidate(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n fileName: string,\n criteria: ResumeCandidateCriteria,\n): Promise<ResumeCandidate | null> {\n const discoverySignal = createResumeDiscoverySignal(criteria)\n try {\n return await findResumeCandidateWithSignal(\n raw,\n accountInfo,\n bucketId,\n fileName,\n criteria,\n discoverySignal.signal,\n )\n } finally {\n discoverySignal.dispose()\n }\n}\n\nasync function findResumeCandidateWithSignal(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n fileName: string,\n criteria: ResumeCandidateCriteria,\n signal: AbortSignal | undefined,\n): Promise<ResumeCandidate | null> {\n const matches: Array<{ file: UnfinishedLargeFile; sequence: number }> = []\n const maxListPages = criteria.maxListPages ?? DEFAULT_MAX_RESUME_LIST_PAGES\n const maxPartCandidates = criteria.maxPartCandidates ?? DEFAULT_MAX_RESUME_PART_CANDIDATES\n let sequence = 0\n let pageCount = 0\n const explicitResumeFileId = criteria.resumeFileId\n let startFileId: LargeFileId | undefined = explicitResumeFileId\n let truncated = false\n\n while (pageCount < maxListPages) {\n signal?.throwIfAborted()\n const unfinished = await abortableRequest(\n raw.listUnfinishedLargeFiles(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n bucketId,\n maxFileCount: explicitResumeFileId !== undefined ? 1 : 100,\n namePrefix: fileName,\n ...(startFileId !== undefined ? { startFileId } : {}),\n },\n signal !== undefined ? { signal } : undefined,\n ),\n signal,\n )\n pageCount++\n\n for (const file of unfinished.files) {\n const isMatch =\n explicitResumeFileId !== undefined\n ? file.fileId === explicitResumeFileId\n : file.fileName === fileName\n if (isMatch) {\n matches.push({ file, sequence })\n }\n sequence++\n }\n\n if (explicitResumeFileId !== undefined) break\n if (unfinished.nextFileId === null) break\n startFileId = unfinished.nextFileId\n truncated = pageCount >= maxListPages\n }\n\n if (truncated) {\n emitCandidateRejected(criteria, {\n requestedFileName: fileName,\n reason: 'search-truncated',\n })\n }\n\n matches.sort(compareNewestFirst)\n\n let partCandidatesInspected = 0\n for (const match of matches) {\n signal?.throwIfAborted()\n const rejection = candidateMetadataRejectReason(match.file, fileName, criteria)\n if (rejection !== null) {\n notifyCandidateRejected(criteria, match.file, fileName, rejection)\n continue\n }\n\n if (partCandidatesInspected >= maxPartCandidates) {\n notifyCandidateRejected(criteria, match.file, fileName, 'candidate-limit')\n break\n }\n\n partCandidatesInspected++\n const fileId = largeFileIdOf(match.file.fileId)\n const uploadedPartsResult = await collectResumePartInfo(raw, accountInfo, fileId, {\n maxPages: criteria.maxPartPages ?? DEFAULT_MAX_RESUME_PART_PAGES,\n maxParts: criteria.parts.length,\n ...(signal !== undefined ? { signal } : {}),\n })\n const uploadedParts = uploadedPartsResult.parts\n if (uploadedPartsResult.truncated || !uploadedPartsMatchPlan(uploadedParts, criteria.parts)) {\n notifyCandidateRejected(criteria, match.file, fileName, 'part-length-mismatch')\n continue\n }\n\n return { fileId, uploadedPartSha1s: partInfoToSha1s(uploadedParts) }\n }\n\n return null\n}\n\ninterface CollectResumePartInfoOptions {\n readonly signal?: AbortSignal\n readonly maxPages?: number\n readonly maxParts?: number\n}\n\nasync function collectResumePartInfo(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n options: CollectResumePartInfoOptions,\n): Promise<{ readonly parts: Map<number, ResumePartInfo>; readonly truncated: boolean }> {\n const parts = new Map<number, ResumePartInfo>()\n const maxPages = options.maxPages ?? Number.POSITIVE_INFINITY\n const maxParts = options.maxParts ?? Number.POSITIVE_INFINITY\n let startPartNumber: number | undefined\n let pageCount = 0\n\n while (pageCount < maxPages) {\n options.signal?.throwIfAborted()\n // Fetch one part beyond the local plan so a candidate with extra uploaded\n // parts is detected and rejected instead of silently reused.\n const remainingParts =\n maxParts === Number.POSITIVE_INFINITY\n ? undefined\n : Math.max(1, Math.min(LIST_PARTS_PAGE_SIZE, maxParts - parts.size + 1))\n const page = await abortableRequest(\n raw.listParts(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n fileId,\n ...(startPartNumber !== undefined ? { startPartNumber } : {}),\n ...(remainingParts !== undefined ? { maxPartCount: remainingParts } : {}),\n },\n options.signal !== undefined ? { signal: options.signal } : undefined,\n ),\n options.signal,\n )\n pageCount++\n for (const part of page.parts) {\n parts.set(part.partNumber, {\n contentSha1: part.contentSha1,\n contentLength: part.contentLength,\n })\n if (parts.size > maxParts) return { parts, truncated: true }\n }\n if (page.nextPartNumber === null) return { parts, truncated: false }\n assertAdvancingPartCursor(fileId, startPartNumber, page.nextPartNumber)\n startPartNumber = page.nextPartNumber\n }\n\n return { parts, truncated: true }\n}\n\nfunction compareNewestFirst(\n a: { file: UnfinishedLargeFile; sequence: number },\n b: { file: UnfinishedLargeFile; sequence: number },\n): number {\n const aTime = a.file.uploadTimestamp ?? Number.NEGATIVE_INFINITY\n const bTime = b.file.uploadTimestamp ?? Number.NEGATIVE_INFINITY\n if (aTime !== bTime) return bTime - aTime\n return b.sequence - a.sequence\n}\n\nfunction candidateMetadataRejectReason(\n candidate: UnfinishedLargeFile,\n fileName: string,\n criteria: ResumeCandidateCriteria,\n): ResumeCandidateRejectedReason | null {\n if (candidate.fileName !== fileName) return 'file-name-mismatch'\n if (\n criteria.contentType === 'b2/x-auto' &&\n criteria.resumeFileId === undefined &&\n candidate.contentType !== 'b2/x-auto'\n ) {\n return 'content-type-mismatch'\n }\n if (criteria.contentType !== 'b2/x-auto' && candidate.contentType !== criteria.contentType) {\n return 'content-type-mismatch'\n }\n\n const candidateInfo = splitResumeFileInfo(candidate.fileInfo ?? {})\n if (!recordEquals(candidateInfo.fileInfo, criteria.fileInfo)) return 'file-info-mismatch'\n if (\n candidateInfo.sourceSize !== undefined &&\n candidateInfo.sourceSize !== String(criteria.sourceSize)\n ) {\n return 'source-size-mismatch'\n }\n if (\n candidateInfo.partSize !== undefined &&\n candidateInfo.partSize !== String(criteria.partSize)\n ) {\n return 'part-size-mismatch'\n }\n if (\n criteria.customUploadTimestamp !== undefined &&\n candidate.uploadTimestamp !== criteria.customUploadTimestamp\n ) {\n return 'upload-timestamp-mismatch'\n }\n\n const encryptionRejectReason = serverSideEncryptionRejectReason(\n candidate.serverSideEncryption,\n criteria.serverSideEncryption,\n criteria.defaultServerSideEncryptionUnreadable === true,\n )\n if (encryptionRejectReason !== null) return encryptionRejectReason\n if (\n !fileRetentionMatches(\n candidate.fileRetention,\n criteria.fileRetention,\n criteria.defaultFileRetention,\n criteria.defaultFileRetentionUnreadable === true,\n candidate.uploadTimestamp,\n )\n ) {\n return 'retention-mismatch'\n }\n if (!legalHoldMatches(candidate.legalHold, criteria.legalHold)) {\n return 'legal-hold-mismatch'\n }\n\n return null\n}\n\nfunction notifyCandidateRejected(\n criteria: ResumeCandidateCriteria,\n candidate: UnfinishedLargeFile,\n requestedFileName: string,\n reason: ResumeCandidateRejectedReason,\n): void {\n emitCandidateRejected(criteria, {\n fileId: largeFileIdOf(candidate.fileId),\n requestedFileName,\n candidateFileName: candidate.fileName,\n reason,\n })\n}\n\nfunction emitCandidateRejected(\n criteria: ResumeCandidateCriteria,\n event: ResumeCandidateRejectedEvent,\n): void {\n try {\n criteria.onCandidateRejected?.(event)\n } catch {\n // Diagnostic listeners should not make an otherwise valid upload fail.\n }\n}\n\nfunction uploadedPartsMatchPlan(\n uploadedParts: ReadonlyMap<number, ResumePartInfo>,\n plans: readonly ResumePartPlan[],\n): boolean {\n for (const [partNumber, part] of uploadedParts) {\n const planned = plans[partNumber - 1]\n if (planned === undefined) return false\n if (planned.partNumber !== partNumber) return false\n if (planned.length !== part.contentLength) return false\n }\n return true\n}\n\nfunction partInfoToSha1s(parts: ReadonlyMap<number, ResumePartInfo>): Map<number, string> {\n const sha1s = new Map<number, string>()\n for (const [partNumber, part] of parts) {\n sha1s.set(partNumber, part.contentSha1)\n }\n return sha1s\n}\n\nfunction recordEquals(a: Record<string, string>, b: Record<string, string>): boolean {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) return false\n for (const key of aKeys) {\n if (a[key] !== b[key]) return false\n }\n return true\n}\n\ninterface SplitResumeFileInfo {\n readonly fileInfo: Record<string, string>\n readonly sourceSize?: string\n readonly partSize?: string\n}\n\nfunction splitResumeFileInfo(fileInfo: Record<string, string>): SplitResumeFileInfo {\n const userFileInfo: Record<string, string> = Object.create(null) as Record<string, string>\n let sourceSize: string | undefined\n let partSize: string | undefined\n for (const [key, value] of Object.entries(fileInfo)) {\n if (key === RESUME_SOURCE_SIZE_INFO_KEY) {\n sourceSize = value\n } else if (key === RESUME_PART_SIZE_INFO_KEY) {\n partSize = value\n } else {\n userFileInfo[key] = value\n }\n }\n return {\n fileInfo: userFileInfo,\n ...(sourceSize !== undefined ? { sourceSize } : {}),\n ...(partSize !== undefined ? { partSize } : {}),\n }\n}\n\nfunction fileRetentionMatches(\n candidate: ReadableFileRetention | undefined,\n expected: FileRetentionValue | undefined,\n defaultExpected: BucketDefaultRetention | undefined,\n defaultUnreadable: boolean,\n uploadTimestamp: number | undefined,\n): boolean {\n if (expected === undefined && defaultUnreadable) return false\n if (expected === undefined && defaultExpected !== undefined) {\n if (defaultExpected.mode === null || defaultExpected.mode === BucketRetentionMode.None) {\n if (candidate === undefined) return true\n if (!candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueEquals(candidate.value, null)\n }\n if (candidate === undefined || !candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueMatchesBucketDefault(candidate.value, defaultExpected, uploadTimestamp)\n }\n if (expected === undefined) {\n if (candidate === undefined) return true\n if (!candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueEquals(candidate.value, null)\n }\n if (candidate === undefined || !candidate.isClientAuthorizedToRead) return false\n return fileRetentionValueEquals(candidate.value, expected)\n}\n\nfunction fileRetentionValueMatchesBucketDefault(\n candidate: FileRetentionValue | null,\n expected: BucketRetentionPolicy,\n uploadTimestamp: number | undefined,\n): boolean {\n if (expected.period === null) return false\n if (candidate?.mode !== expected.mode || candidate.retainUntilTimestamp === null) return false\n if (uploadTimestamp === undefined) return false\n return candidate.retainUntilTimestamp === uploadTimestamp + retentionPeriodMillis(expected.period)\n}\n\nfunction retentionPeriodMillis(period: BucketRetentionPolicy['period']): number {\n if (period === null) return 0\n const days = period.unit === 'days' ? period.duration : period.duration * 365\n return days * 24 * 60 * 60 * 1000\n}\n\nfunction fileRetentionValueEquals(\n a: FileRetentionValue | null,\n b: FileRetentionValue | null,\n): boolean {\n return (\n (a?.mode ?? null) === (b?.mode ?? null) &&\n (a?.retainUntilTimestamp ?? null) === (b?.retainUntilTimestamp ?? null)\n )\n}\n\nfunction legalHoldMatches(\n candidate: ReadableLegalHold | undefined,\n expected: LegalHoldValue | undefined,\n): boolean {\n if (expected === undefined) {\n if (candidate === undefined) return true\n if (!candidate.isClientAuthorizedToRead) return false\n return candidate.value === null || candidate.value === 'off'\n }\n if (candidate === undefined || !candidate.isClientAuthorizedToRead) return false\n return candidate.value === expected\n}\n\ninterface ResumeDiscoverySignal {\n readonly signal?: AbortSignal\n dispose(): void\n}\n\nfunction createResumeDiscoverySignal(criteria: ResumeCandidateCriteria): ResumeDiscoverySignal {\n if (criteria.signal !== undefined) {\n return {\n signal: criteria.signal,\n dispose() {},\n }\n }\n\n if (criteria.discoveryTimeoutMs === undefined) {\n return {\n dispose() {},\n }\n }\n\n const timeoutMs = criteria.discoveryTimeoutMs\n if (timeoutMs === Number.POSITIVE_INFINITY) {\n return {\n dispose() {},\n }\n }\n\n const controller = new AbortController()\n const timeout = setTimeout(\n () => {\n controller.abort(resumeDiscoveryTimeoutReason(timeoutMs))\n },\n Math.max(0, timeoutMs),\n )\n\n return {\n signal: controller.signal,\n dispose() {\n clearTimeout(timeout)\n },\n }\n}\n\nasync function abortableRequest<T>(\n request: Promise<T>,\n signal: AbortSignal | undefined,\n): Promise<T> {\n if (signal === undefined) return request\n if (signal.aborted) throw resumeAbortReason(signal)\n\n let removeAbortListener: (() => void) | undefined\n const aborted = new Promise<never>((_resolve, reject) => {\n const onAbort = () => reject(resumeAbortReason(signal))\n signal.addEventListener('abort', onAbort, { once: true })\n removeAbortListener = () => signal.removeEventListener('abort', onAbort)\n })\n\n try {\n return await Promise.race([request, aborted])\n } finally {\n removeAbortListener?.()\n void request.catch(() => {})\n }\n}\n\nfunction resumeAbortReason(signal: AbortSignal): unknown {\n return signal.reason ?? resumeAbortFallbackReason()\n}\n\nfunction resumeAbortFallbackReason(): Error {\n if (typeof DOMException === 'function') {\n return new DOMException('Resume discovery aborted', 'AbortError')\n }\n const error = new Error('Resume discovery aborted')\n error.name = 'AbortError'\n return error\n}\n\nfunction resumeDiscoveryTimeoutReason(timeoutMs: number): Error {\n if (typeof DOMException === 'function') {\n return new DOMException(`Resume discovery timed out after ${timeoutMs} ms`, 'TimeoutError')\n }\n const error = new Error(`Resume discovery timed out after ${timeoutMs} ms`)\n error.name = 'TimeoutError'\n return error\n}\n\ntype ListedEncryption = PublicEncryptionSetting | undefined\n\nfunction serverSideEncryptionRejectReason(\n candidate: ListedEncryption,\n expected: EncryptionSetting | BucketDefaultServerSideEncryption | undefined,\n defaultUnreadable: boolean,\n): 'encryption-mismatch' | 'sse-c-unsupported' | null {\n if (expected?.mode === EncryptionMode.SseC) return 'sse-c-unsupported'\n if (expected === undefined && defaultUnreadable) return 'encryption-mismatch'\n\n const actual = normalizeEncryption(candidate)\n if (expected === undefined) {\n if (candidate === undefined) return null\n if (actual === undefined) return 'encryption-mismatch'\n if (actual.mode === EncryptionMode.None) return null\n if (actual.mode === EncryptionMode.SseB2) return null\n return actual.mode === EncryptionMode.SseC ? 'sse-c-unsupported' : 'encryption-mismatch'\n }\n\n const normalizedExpected = normalizeEncryption(expected)\n if (normalizedExpected?.mode === EncryptionMode.None && candidate === undefined) return null\n if (actual === undefined || normalizedExpected === undefined) return 'encryption-mismatch'\n if (actual.mode !== normalizedExpected.mode) return 'encryption-mismatch'\n if (actual.mode === EncryptionMode.None) return null\n return actual.algorithm === normalizedExpected.algorithm ? null : 'encryption-mismatch'\n}\n\ninterface NormalizedEncryption {\n readonly mode: EncryptionMode\n readonly algorithm?: string\n}\n\nfunction normalizeEncryption(\n encryption: EncryptionSetting | ListedEncryption,\n): NormalizedEncryption | undefined {\n if (encryption === undefined) return undefined\n // Real B2 responses may spell no encryption as `{ mode: null, algorithm: null }`.\n if (encryption.mode === null || encryption.mode === EncryptionMode.None) {\n return { mode: EncryptionMode.None }\n }\n if (encryption.mode !== EncryptionMode.SseB2 && encryption.mode !== EncryptionMode.SseC) {\n return undefined\n }\n return {\n mode: encryption.mode,\n algorithm: encryption.algorithm,\n }\n}\n\nfunction assertAdvancingPartCursor(\n fileId: LargeFileId,\n previous: number | undefined,\n next: number,\n): void {\n if (!Number.isInteger(next) || next < 1 || (previous !== undefined && next <= previous)) {\n throw new Error(\n `uploadLargeFile: listParts returned a non-advancing nextPartNumber for ${fileId}; aborting resume.`,\n )\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  const require_errors_index = require("../errors/index.cjs");
2
+ const require_encryption = require("../types/encryption.cjs");
2
3
  const require_retry = require("../http/retry.cjs");
3
4
  //#region src/upload/retry.ts
4
5
  var freshUrlRetryOverride = { maxRetries: 0 };
@@ -53,6 +54,9 @@ async function fetchFreshPartUploadUrl(raw, accountInfo, fileId, signal) {
53
54
  authorizationToken: resp.authorizationToken
54
55
  };
55
56
  }
57
+ function uploadPartEncryption(encryption) {
58
+ return encryption?.mode === require_encryption.EncryptionMode.SseC ? encryption : void 0;
59
+ }
56
60
  /**
57
61
  * Uploads one multipart part with fresh-URL retry.
58
62
  *
@@ -75,16 +79,19 @@ function uploadPartWithFreshUrl(raw, accountInfo, fileId, options) {
75
79
  fetchFresh: () => fetchFreshPartUploadUrl(raw, accountInfo, fileId, options.signal),
76
80
  returnEntry: (entry) => accountInfo.returnPartUploadUrl(fileId, entry),
77
81
  evictEntry: (entry) => accountInfo.evictPartUploadUrl(fileId, entry),
78
- upload: (entry) => raw.uploadPart(entry.uploadUrl, {
79
- authorization: entry.authorizationToken,
80
- partNumber: options.partNumber,
81
- contentLength: options.contentLength,
82
- contentSha1: options.contentSha1,
83
- ...options.serverSideEncryption !== void 0 ? { serverSideEncryption: options.serverSideEncryption } : {}
84
- }, options.data, {
85
- ...options.signal !== void 0 ? { signal: options.signal } : {},
86
- ...options.retry !== void 0 ? { retry: options.retry } : {}
87
- })
82
+ upload: (entry) => {
83
+ const serverSideEncryption = uploadPartEncryption(options.serverSideEncryption);
84
+ return raw.uploadPart(entry.uploadUrl, {
85
+ authorization: entry.authorizationToken,
86
+ partNumber: options.partNumber,
87
+ contentLength: options.contentLength,
88
+ contentSha1: options.contentSha1,
89
+ ...serverSideEncryption !== void 0 ? { serverSideEncryption } : {}
90
+ }, options.data, {
91
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
92
+ ...options.retry !== void 0 ? { retry: options.retry } : {}
93
+ });
94
+ }
88
95
  });
89
96
  }
90
97
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"retry.cjs","names":[],"sources":["../../src/upload/retry.ts"],"sourcesContent":["import type { AccountInfo, UploadUrlEntry } from '../auth/account-info.ts'\nimport {\n B2Error,\n B2SsrfError,\n BadAuthTokenError,\n BadRequestError,\n BadUploadUrlError,\n NetworkError,\n UploadResponseBodyError,\n} from '../errors/index.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from '../http/retry.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { UploadPartResponse } from '../types/upload.ts'\n\n/** Event emitted before an upload is retried against a fresh upload URL. */\nexport interface UploadRetryEvent {\n /** File name being uploaded. */\n readonly fileName: string\n /** Multipart part number, or `null` for a single-request file upload. */\n readonly partNumber: number | null\n /** One-based retry attempt that is about to run. */\n readonly attempt: number\n /** Maximum number of retry attempts allowed for this upload operation. */\n readonly maxRetries: number\n /** Backoff delay in milliseconds before the fresh URL is fetched. */\n readonly delayMs: number\n /** Classified error that triggered the fresh-URL retry. */\n readonly error: B2Error | NetworkError\n}\n\n/** Callback invoked before an upload retry fetches a fresh upload URL. */\nexport type UploadRetryListener = (event: UploadRetryEvent) => void\n\n/** Shared public options for upload-layer fresh-URL retries. */\nexport interface UploadRetryOptions {\n /** Retry settings shared with the main transport retry configuration. */\n readonly retry?: Partial<RetryOptions> | undefined\n /** Callback invoked before a fresh-URL upload retry. */\n readonly onUploadRetry?: UploadRetryListener | undefined\n /**\n * Whether ambiguous failures after an upload POST should be retried,\n * including response-body read failures and transport errors where B2 may\n * have stored the payload before the success response was lost.\n * Defaults to false. Set true only when duplicate versions or parts are\n * acceptable.\n */\n readonly retryResponseBodyFailures?: boolean | undefined\n}\n\ninterface UploadLayerRetryOptions extends Omit<UploadRetryOptions, 'retryResponseBodyFailures'> {\n readonly retryResponseBodyFailures: boolean\n /** Abort signal for cancelling upload attempts and retry backoff sleeps. */\n readonly signal?: AbortSignal | undefined\n}\n\ninterface FreshUrlRetryOptions<T> extends UploadLayerRetryOptions {\n readonly fileName: string\n readonly partNumber: number | null\n readonly checkout: () => UploadUrlEntry | null\n readonly fetchFresh: () => Promise<UploadUrlEntry>\n readonly returnEntry: (entry: UploadUrlEntry) => void\n readonly evictEntry: (entry: UploadUrlEntry) => void\n readonly upload: (entry: UploadUrlEntry) => Promise<T>\n}\n\nconst freshUrlRetryOverride: Partial<RetryOptions> = { maxRetries: 0 }\n\n/**\n * Resolves the public default for `retryResponseBodyFailures`. Callers must\n * opt into replaying ambiguous upload POST failures for every upload mode.\n *\n * @param value - Caller-provided override, if any.\n *\n * @returns The boolean value passed to the upload retry helper.\n */\nexport function resolveRetryResponseBodyFailures(value: boolean | undefined): boolean {\n return value ?? false\n}\n\n/**\n * Fetches a small-file upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param bucketId - Bucket to upload into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh upload URL entry.\n */\nexport async function fetchFreshUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n bucketId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\n/**\n * Fetches a large-file part upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh part upload URL entry.\n */\nexport async function fetchFreshPartUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadPartUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n fileId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\ninterface UploadPartWithFreshUrlOptions extends UploadLayerRetryOptions {\n /** File name associated with the large-file upload. */\n readonly fileName: string\n /** One-based part number. */\n readonly partNumber: number\n /** Part bytes to upload. */\n readonly data: BodyInit\n /** Number of bytes in the part. */\n readonly contentLength: number\n /** SHA-1 hex digest of the part bytes. */\n readonly contentSha1: string\n /** Server-side encryption settings for this part. */\n readonly serverSideEncryption?: EncryptionSetting | undefined\n}\n\n/**\n * Uploads one multipart part with fresh-URL retry.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param options - Part upload parameters and retry settings.\n *\n * @returns The uploaded part response.\n */\nexport function uploadPartWithFreshUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n options: UploadPartWithFreshUrlOptions,\n): Promise<UploadPartResponse> {\n return withFreshUploadUrlRetry({\n fileName: options.fileName,\n partNumber: options.partNumber,\n retry: options.retry,\n signal: options.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: options.retryResponseBodyFailures,\n checkout: () => accountInfo.checkoutPartUploadUrl(fileId),\n fetchFresh: () => fetchFreshPartUploadUrl(raw, accountInfo, fileId, options.signal),\n returnEntry: (entry) => accountInfo.returnPartUploadUrl(fileId, entry),\n evictEntry: (entry) => accountInfo.evictPartUploadUrl(fileId, entry),\n upload: (entry) =>\n raw.uploadPart(\n entry.uploadUrl,\n {\n authorization: entry.authorizationToken,\n partNumber: options.partNumber,\n contentLength: options.contentLength,\n contentSha1: options.contentSha1,\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n },\n options.data,\n {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n ),\n })\n}\n\n/**\n * Runs an upload operation with B2's documented retry flow: evict the failed\n * upload URL, back off, fetch a fresh upload URL, and retry there.\n *\n * For single-request file uploads, sending the POST again after a lost success\n * response can create a duplicate file version. Multipart retries re-send the\n * same part number instead. Response-body retry defaults are caller-specific:\n * single-request uploads keep them off by default, while multipart callers can\n * opt in with `retryResponseBodyFailures: true` when replaying the same part\n * number is acceptable.\n *\n * @param options - URL checkout, upload, eviction, and retry callbacks.\n *\n * @returns The successful upload result.\n */\nexport async function withFreshUploadUrlRetry<T>(options: FreshUrlRetryOptions<T>): Promise<T> {\n const retryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options.retry }\n\n for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {\n let uploadEntry: UploadUrlEntry | undefined\n let uploadStarted = false\n\n try {\n options.signal?.throwIfAborted()\n uploadEntry =\n attempt === 0\n ? (options.checkout() ?? (await options.fetchFresh()))\n : await options.fetchFresh()\n\n uploadStarted = true\n const result = await options.upload(uploadEntry)\n options.returnEntry(uploadEntry)\n return result\n } catch (err) {\n const retryError = normalizeUploadRetryError(err, options)\n if (uploadEntry !== undefined) {\n if (isUploadRateLimitError(retryError)) {\n options.returnEntry(uploadEntry)\n } else {\n options.evictEntry(uploadEntry)\n }\n }\n if (options.signal?.aborted) {\n throw err\n }\n if (isUploadRateLimitError(retryError) && uploadEntry !== undefined) {\n throw retryError\n }\n if (\n !isUploadRetryable(retryError, { ...options, uploadStarted }) ||\n attempt === retryOptions.maxRetries\n ) {\n throw retryError\n }\n\n const retryAttempt = attempt + 1\n const retryAfter = retryError instanceof B2Error ? retryError.retryAfter : undefined\n const delayMs = computeBackoff(attempt, retryOptions, retryAfter)\n notifyUploadRetry(options, {\n fileName: options.fileName,\n partNumber: options.partNumber,\n attempt: retryAttempt,\n maxRetries: retryOptions.maxRetries,\n delayMs,\n error: retryError,\n })\n await sleep(delayMs, options.signal)\n }\n }\n\n // Unreachable at runtime: the loop returns on success or throws from the\n // final failed attempt. This satisfies TypeScript's return-path analysis.\n /* v8 ignore next -- defensive return-path guard. */\n throw new NetworkError('Upload retry budget exhausted')\n}\n\nfunction notifyUploadRetry(options: UploadLayerRetryOptions, event: UploadRetryEvent): void {\n try {\n options.onUploadRetry?.(event)\n } catch {\n // Telemetry observers must not replace the underlying upload failure or\n // prevent a retry that can recover with a fresh upload URL.\n }\n}\n\nfunction isUploadRetryable(\n err: unknown,\n options: UploadLayerRetryOptions & {\n readonly partNumber: number | null\n readonly uploadStarted: boolean\n },\n): err is B2Error | NetworkError {\n if (err instanceof NetworkError) {\n if (err.cause instanceof B2SsrfError) return false\n if (!options.uploadStarted) return true\n return options.retryResponseBodyFailures === true\n }\n if (err instanceof BadAuthTokenError) return true\n if (isUploadUrlInvalidationError(err)) return true\n return err instanceof B2Error && err.retryable\n}\n\nfunction isUploadRateLimitError(err: unknown): err is B2Error {\n return err instanceof B2Error && err.status === 429\n}\n\nfunction normalizeUploadRetryError(err: unknown, options: UploadLayerRetryOptions): unknown {\n if (err instanceof B2Error || err instanceof NetworkError) return err\n if (err instanceof UploadResponseBodyError) {\n if (!options.retryResponseBodyFailures) return err\n return new NetworkError(err.message, err)\n }\n if (err instanceof DOMException && err.name === 'AbortError') return err\n if (err instanceof TypeError || err instanceof SyntaxError || err instanceof DOMException) {\n const message = err instanceof Error ? err.message : 'Upload response read failed'\n return new NetworkError(message, err)\n }\n return err\n}\n\nfunction isUploadUrlInvalidationError(err: unknown): boolean {\n if (err instanceof BadUploadUrlError) return true\n return err instanceof BadRequestError && /upload url/i.test(err.message)\n}\n"],"mappings":";;;AAmEA,IAAM,wBAA+C,EAAE,YAAY,EAAE;;;;;;;;;AAUrE,SAAgB,iCAAiC,OAAqC;CACpF,OAAO,SAAS;AAClB;;;;;;;;;;;AAYA,eAAsB,oBACpB,KACA,aACA,UACA,QACyB;CACzB,MAAM,OAAO,MAAM,IAAI,aACrB,YAAY,UAAU,GACtB,YAAY,aAAa,GACzB,EACE,SACF,GACA;EACE,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC,OAAO;CACT,CACF;CACA,OAAO;EAAE,WAAW,KAAK;EAAW,oBAAoB,KAAK;CAAmB;AAClF;;;;;;;;;;;AAYA,eAAsB,wBACpB,KACA,aACA,QACA,QACyB;CACzB,MAAM,OAAO,MAAM,IAAI,iBACrB,YAAY,UAAU,GACtB,YAAY,aAAa,GACzB,EACE,OACF,GACA;EACE,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC,OAAO;CACT,CACF;CACA,OAAO;EAAE,WAAW,KAAK;EAAW,oBAAoB,KAAK;CAAmB;AAClF;;;;;;;;;;;AA2BA,SAAgB,uBACd,KACA,aACA,QACA,SAC6B;CAC7B,OAAO,wBAAwB;EAC7B,UAAU,QAAQ;EAClB,YAAY,QAAQ;EACpB,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,eAAe,QAAQ;EACvB,2BAA2B,QAAQ;EACnC,gBAAgB,YAAY,sBAAsB,MAAM;EACxD,kBAAkB,wBAAwB,KAAK,aAAa,QAAQ,QAAQ,MAAM;EAClF,cAAc,UAAU,YAAY,oBAAoB,QAAQ,KAAK;EACrE,aAAa,UAAU,YAAY,mBAAmB,QAAQ,KAAK;EACnE,SAAS,UACP,IAAI,WACF,MAAM,WACN;GACE,eAAe,MAAM;GACrB,YAAY,QAAQ;GACpB,eAAe,QAAQ;GACvB,aAAa,QAAQ;GACrB,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;EACP,GACA,QAAQ,MACR;GACE,GAAI,QAAQ,WAAW,KAAA,IAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;GACjE,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAChE,CACF;CACJ,CAAC;AACH;;;;;;;;;;;;;;;;AAiBA,eAAsB,wBAA2B,SAA8C;CAC7F,MAAM,eAAe;EAAE,GAAG,cAAA;EAAuB,GAAG,QAAQ;CAAM;CAElE,KAAK,IAAI,UAAU,GAAG,WAAW,aAAa,YAAY,WAAW;EACnE,IAAI;EACJ,IAAI,gBAAgB;EAEpB,IAAI;GACF,QAAQ,QAAQ,eAAe;GAC/B,cACE,YAAY,IACP,QAAQ,SAAS,KAAM,MAAM,QAAQ,WAAW,IACjD,MAAM,QAAQ,WAAW;GAE/B,gBAAgB;GAChB,MAAM,SAAS,MAAM,QAAQ,OAAO,WAAW;GAC/C,QAAQ,YAAY,WAAW;GAC/B,OAAO;EACT,SAAS,KAAK;GACZ,MAAM,aAAa,0BAA0B,KAAK,OAAO;GACzD,IAAI,gBAAgB,KAAA,GAAW;IAC7B,IAAI,uBAAuB,UAAU,GACnC,QAAQ,YAAY,WAAW;SAE/B,QAAQ,WAAW,WAAW;GAElC;GACA,IAAI,QAAQ,QAAQ,SAClB,MAAM;GAER,IAAI,uBAAuB,UAAU,KAAK,gBAAgB,KAAA,GACxD,MAAM;GAER,IACE,CAAC,kBAAkB,YAAY;IAAE,GAAG;IAAS;GAAc,CAAC,KAC5D,YAAY,aAAa,YAEzB,MAAM;GAGR,MAAM,eAAe,UAAU;GAC/B,MAAM,aAAa,sBAAsB,qBAAA,UAAU,WAAW,aAAa,KAAA;GAC3E,MAAM,UAAU,cAAA,eAAe,SAAS,cAAc,UAAU;GAChE,kBAAkB,SAAS;IACzB,UAAU,QAAQ;IAClB,YAAY,QAAQ;IACpB,SAAS;IACT,YAAY,aAAa;IACzB;IACA,OAAO;GACT,CAAC;GACD,MAAM,cAAA,MAAM,SAAS,QAAQ,MAAM;EACrC;CACF;;CAKA,MAAM,IAAI,qBAAA,aAAa,+BAA+B;AACxD;AAEA,SAAS,kBAAkB,SAAkC,OAA+B;CAC1F,IAAI;EACF,QAAQ,gBAAgB,KAAK;CAC/B,QAAQ,CAGR;AACF;AAEA,SAAS,kBACP,KACA,SAI+B;CAC/B,IAAI,eAAe,qBAAA,cAAc;EAC/B,IAAI,IAAI,iBAAiB,qBAAA,aAAa,OAAO;EAC7C,IAAI,CAAC,QAAQ,eAAe,OAAO;EACnC,OAAO,QAAQ,8BAA8B;CAC/C;CACA,IAAI,eAAe,qBAAA,mBAAmB,OAAO;CAC7C,IAAI,6BAA6B,GAAG,GAAG,OAAO;CAC9C,OAAO,eAAe,qBAAA,WAAW,IAAI;AACvC;AAEA,SAAS,uBAAuB,KAA8B;CAC5D,OAAO,eAAe,qBAAA,WAAW,IAAI,WAAW;AAClD;AAEA,SAAS,0BAA0B,KAAc,SAA2C;CAC1F,IAAI,eAAe,qBAAA,WAAW,eAAe,qBAAA,cAAc,OAAO;CAClE,IAAI,eAAe,qBAAA,yBAAyB;EAC1C,IAAI,CAAC,QAAQ,2BAA2B,OAAO;EAC/C,OAAO,IAAI,qBAAA,aAAa,IAAI,SAAS,GAAG;CAC1C;CACA,IAAI,eAAe,gBAAgB,IAAI,SAAS,cAAc,OAAO;CACrE,IAAI,eAAe,aAAa,eAAe,eAAe,eAAe,cAAc;EACzF,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;EACrD,OAAO,IAAI,qBAAA,aAAa,SAAS,GAAG;CACtC;CACA,OAAO;AACT;AAEA,SAAS,6BAA6B,KAAuB;CAC3D,IAAI,eAAe,qBAAA,mBAAmB,OAAO;CAC7C,OAAO,eAAe,qBAAA,mBAAmB,cAAc,KAAK,IAAI,OAAO;AACzE"}
1
+ {"version":3,"file":"retry.cjs","names":[],"sources":["../../src/upload/retry.ts"],"sourcesContent":["import type { AccountInfo, UploadUrlEntry } from '../auth/account-info.ts'\nimport {\n B2Error,\n B2SsrfError,\n BadAuthTokenError,\n BadRequestError,\n BadUploadUrlError,\n NetworkError,\n UploadResponseBodyError,\n} from '../errors/index.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from '../http/retry.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { EncryptionMode, type EncryptionSetting } from '../types/encryption.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { UploadPartResponse } from '../types/upload.ts'\n\n/** Event emitted before an upload is retried against a fresh upload URL. */\nexport interface UploadRetryEvent {\n /** File name being uploaded. */\n readonly fileName: string\n /** Multipart part number, or `null` for a single-request file upload. */\n readonly partNumber: number | null\n /** One-based retry attempt that is about to run. */\n readonly attempt: number\n /** Maximum number of retry attempts allowed for this upload operation. */\n readonly maxRetries: number\n /** Backoff delay in milliseconds before the fresh URL is fetched. */\n readonly delayMs: number\n /** Classified error that triggered the fresh-URL retry. */\n readonly error: B2Error | NetworkError\n}\n\n/** Callback invoked before an upload retry fetches a fresh upload URL. */\nexport type UploadRetryListener = (event: UploadRetryEvent) => void\n\n/** Shared public options for upload-layer fresh-URL retries. */\nexport interface UploadRetryOptions {\n /** Retry settings shared with the main transport retry configuration. */\n readonly retry?: Partial<RetryOptions> | undefined\n /** Callback invoked before a fresh-URL upload retry. */\n readonly onUploadRetry?: UploadRetryListener | undefined\n /**\n * Whether ambiguous failures after an upload POST should be retried,\n * including response-body read failures and transport errors where B2 may\n * have stored the payload before the success response was lost.\n * Defaults to false. Set true only when duplicate versions or parts are\n * acceptable.\n */\n readonly retryResponseBodyFailures?: boolean | undefined\n}\n\ninterface UploadLayerRetryOptions extends Omit<UploadRetryOptions, 'retryResponseBodyFailures'> {\n readonly retryResponseBodyFailures: boolean\n /** Abort signal for cancelling upload attempts and retry backoff sleeps. */\n readonly signal?: AbortSignal | undefined\n}\n\ninterface FreshUrlRetryOptions<T> extends UploadLayerRetryOptions {\n readonly fileName: string\n readonly partNumber: number | null\n readonly checkout: () => UploadUrlEntry | null\n readonly fetchFresh: () => Promise<UploadUrlEntry>\n readonly returnEntry: (entry: UploadUrlEntry) => void\n readonly evictEntry: (entry: UploadUrlEntry) => void\n readonly upload: (entry: UploadUrlEntry) => Promise<T>\n}\n\nconst freshUrlRetryOverride: Partial<RetryOptions> = { maxRetries: 0 }\n\n/**\n * Resolves the public default for `retryResponseBodyFailures`. Callers must\n * opt into replaying ambiguous upload POST failures for every upload mode.\n *\n * @param value - Caller-provided override, if any.\n *\n * @returns The boolean value passed to the upload retry helper.\n */\nexport function resolveRetryResponseBodyFailures(value: boolean | undefined): boolean {\n return value ?? false\n}\n\n/**\n * Fetches a small-file upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param bucketId - Bucket to upload into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh upload URL entry.\n */\nexport async function fetchFreshUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n bucketId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\n/**\n * Fetches a large-file part upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh part upload URL entry.\n */\nexport async function fetchFreshPartUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadPartUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n fileId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\ninterface UploadPartWithFreshUrlOptions extends UploadLayerRetryOptions {\n /** File name associated with the large-file upload. */\n readonly fileName: string\n /** One-based part number. */\n readonly partNumber: number\n /** Part bytes to upload. */\n readonly data: BodyInit\n /** Number of bytes in the part. */\n readonly contentLength: number\n /** SHA-1 hex digest of the part bytes. */\n readonly contentSha1: string\n /** Server-side encryption settings for this part. */\n readonly serverSideEncryption?: EncryptionSetting | undefined\n}\n\nfunction uploadPartEncryption(\n encryption: EncryptionSetting | undefined,\n): EncryptionSetting | undefined {\n // B2-managed encryption is configured on b2_start_large_file. b2_upload_part\n // only accepts customer-key headers, so SSE-B2 must not be repeated per part.\n return encryption?.mode === EncryptionMode.SseC ? encryption : undefined\n}\n\n/**\n * Uploads one multipart part with fresh-URL retry.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param options - Part upload parameters and retry settings.\n *\n * @returns The uploaded part response.\n */\nexport function uploadPartWithFreshUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n options: UploadPartWithFreshUrlOptions,\n): Promise<UploadPartResponse> {\n return withFreshUploadUrlRetry({\n fileName: options.fileName,\n partNumber: options.partNumber,\n retry: options.retry,\n signal: options.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: options.retryResponseBodyFailures,\n checkout: () => accountInfo.checkoutPartUploadUrl(fileId),\n fetchFresh: () => fetchFreshPartUploadUrl(raw, accountInfo, fileId, options.signal),\n returnEntry: (entry) => accountInfo.returnPartUploadUrl(fileId, entry),\n evictEntry: (entry) => accountInfo.evictPartUploadUrl(fileId, entry),\n upload: (entry) => {\n const serverSideEncryption = uploadPartEncryption(options.serverSideEncryption)\n return raw.uploadPart(\n entry.uploadUrl,\n {\n authorization: entry.authorizationToken,\n partNumber: options.partNumber,\n contentLength: options.contentLength,\n contentSha1: options.contentSha1,\n ...(serverSideEncryption !== undefined ? { serverSideEncryption } : {}),\n },\n options.data,\n {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n )\n },\n })\n}\n\n/**\n * Runs an upload operation with B2's documented retry flow: evict the failed\n * upload URL, back off, fetch a fresh upload URL, and retry there.\n *\n * For single-request file uploads, sending the POST again after a lost success\n * response can create a duplicate file version. Multipart retries re-send the\n * same part number instead. Response-body retry defaults are caller-specific:\n * single-request uploads keep them off by default, while multipart callers can\n * opt in with `retryResponseBodyFailures: true` when replaying the same part\n * number is acceptable.\n *\n * @param options - URL checkout, upload, eviction, and retry callbacks.\n *\n * @returns The successful upload result.\n */\nexport async function withFreshUploadUrlRetry<T>(options: FreshUrlRetryOptions<T>): Promise<T> {\n const retryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options.retry }\n\n for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {\n let uploadEntry: UploadUrlEntry | undefined\n let uploadStarted = false\n\n try {\n options.signal?.throwIfAborted()\n uploadEntry =\n attempt === 0\n ? (options.checkout() ?? (await options.fetchFresh()))\n : await options.fetchFresh()\n\n uploadStarted = true\n const result = await options.upload(uploadEntry)\n options.returnEntry(uploadEntry)\n return result\n } catch (err) {\n const retryError = normalizeUploadRetryError(err, options)\n if (uploadEntry !== undefined) {\n if (isUploadRateLimitError(retryError)) {\n options.returnEntry(uploadEntry)\n } else {\n options.evictEntry(uploadEntry)\n }\n }\n if (options.signal?.aborted) {\n throw err\n }\n if (isUploadRateLimitError(retryError) && uploadEntry !== undefined) {\n throw retryError\n }\n if (\n !isUploadRetryable(retryError, { ...options, uploadStarted }) ||\n attempt === retryOptions.maxRetries\n ) {\n throw retryError\n }\n\n const retryAttempt = attempt + 1\n const retryAfter = retryError instanceof B2Error ? retryError.retryAfter : undefined\n const delayMs = computeBackoff(attempt, retryOptions, retryAfter)\n notifyUploadRetry(options, {\n fileName: options.fileName,\n partNumber: options.partNumber,\n attempt: retryAttempt,\n maxRetries: retryOptions.maxRetries,\n delayMs,\n error: retryError,\n })\n await sleep(delayMs, options.signal)\n }\n }\n\n // Unreachable at runtime: the loop returns on success or throws from the\n // final failed attempt. This satisfies TypeScript's return-path analysis.\n /* v8 ignore next -- defensive return-path guard. */\n throw new NetworkError('Upload retry budget exhausted')\n}\n\nfunction notifyUploadRetry(options: UploadLayerRetryOptions, event: UploadRetryEvent): void {\n try {\n options.onUploadRetry?.(event)\n } catch {\n // Telemetry observers must not replace the underlying upload failure or\n // prevent a retry that can recover with a fresh upload URL.\n }\n}\n\nfunction isUploadRetryable(\n err: unknown,\n options: UploadLayerRetryOptions & {\n readonly partNumber: number | null\n readonly uploadStarted: boolean\n },\n): err is B2Error | NetworkError {\n if (err instanceof NetworkError) {\n if (err.cause instanceof B2SsrfError) return false\n if (!options.uploadStarted) return true\n return options.retryResponseBodyFailures === true\n }\n if (err instanceof BadAuthTokenError) return true\n if (isUploadUrlInvalidationError(err)) return true\n return err instanceof B2Error && err.retryable\n}\n\nfunction isUploadRateLimitError(err: unknown): err is B2Error {\n return err instanceof B2Error && err.status === 429\n}\n\nfunction normalizeUploadRetryError(err: unknown, options: UploadLayerRetryOptions): unknown {\n if (err instanceof B2Error || err instanceof NetworkError) return err\n if (err instanceof UploadResponseBodyError) {\n if (!options.retryResponseBodyFailures) return err\n return new NetworkError(err.message, err)\n }\n if (err instanceof DOMException && err.name === 'AbortError') return err\n if (err instanceof TypeError || err instanceof SyntaxError || err instanceof DOMException) {\n const message = err instanceof Error ? err.message : 'Upload response read failed'\n return new NetworkError(message, err)\n }\n return err\n}\n\nfunction isUploadUrlInvalidationError(err: unknown): boolean {\n if (err instanceof BadUploadUrlError) return true\n return err instanceof BadRequestError && /upload url/i.test(err.message)\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/upload/retry.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/upload/retry.js"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/upload/retry.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/upload/retry.js"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { B2Error, B2SsrfError, BadAuthTokenError, BadRequestError, BadUploadUrlError, NetworkError, UploadResponseBodyError } from "../errors/index.js";
2
+ import { EncryptionMode } from "../types/encryption.js";
2
3
  import { DEFAULT_RETRY_OPTIONS, computeBackoff, sleep } from "../http/retry.js";
3
4
  //#region src/upload/retry.ts
4
5
  var freshUrlRetryOverride = { maxRetries: 0 };
@@ -53,6 +54,9 @@ async function fetchFreshPartUploadUrl(raw, accountInfo, fileId, signal) {
53
54
  authorizationToken: resp.authorizationToken
54
55
  };
55
56
  }
57
+ function uploadPartEncryption(encryption) {
58
+ return encryption?.mode === EncryptionMode.SseC ? encryption : void 0;
59
+ }
56
60
  /**
57
61
  * Uploads one multipart part with fresh-URL retry.
58
62
  *
@@ -75,16 +79,19 @@ function uploadPartWithFreshUrl(raw, accountInfo, fileId, options) {
75
79
  fetchFresh: () => fetchFreshPartUploadUrl(raw, accountInfo, fileId, options.signal),
76
80
  returnEntry: (entry) => accountInfo.returnPartUploadUrl(fileId, entry),
77
81
  evictEntry: (entry) => accountInfo.evictPartUploadUrl(fileId, entry),
78
- upload: (entry) => raw.uploadPart(entry.uploadUrl, {
79
- authorization: entry.authorizationToken,
80
- partNumber: options.partNumber,
81
- contentLength: options.contentLength,
82
- contentSha1: options.contentSha1,
83
- ...options.serverSideEncryption !== void 0 ? { serverSideEncryption: options.serverSideEncryption } : {}
84
- }, options.data, {
85
- ...options.signal !== void 0 ? { signal: options.signal } : {},
86
- ...options.retry !== void 0 ? { retry: options.retry } : {}
87
- })
82
+ upload: (entry) => {
83
+ const serverSideEncryption = uploadPartEncryption(options.serverSideEncryption);
84
+ return raw.uploadPart(entry.uploadUrl, {
85
+ authorization: entry.authorizationToken,
86
+ partNumber: options.partNumber,
87
+ contentLength: options.contentLength,
88
+ contentSha1: options.contentSha1,
89
+ ...serverSideEncryption !== void 0 ? { serverSideEncryption } : {}
90
+ }, options.data, {
91
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
92
+ ...options.retry !== void 0 ? { retry: options.retry } : {}
93
+ });
94
+ }
88
95
  });
89
96
  }
90
97
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"retry.js","names":[],"sources":["../../src/upload/retry.ts"],"sourcesContent":["import type { AccountInfo, UploadUrlEntry } from '../auth/account-info.ts'\nimport {\n B2Error,\n B2SsrfError,\n BadAuthTokenError,\n BadRequestError,\n BadUploadUrlError,\n NetworkError,\n UploadResponseBodyError,\n} from '../errors/index.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from '../http/retry.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { UploadPartResponse } from '../types/upload.ts'\n\n/** Event emitted before an upload is retried against a fresh upload URL. */\nexport interface UploadRetryEvent {\n /** File name being uploaded. */\n readonly fileName: string\n /** Multipart part number, or `null` for a single-request file upload. */\n readonly partNumber: number | null\n /** One-based retry attempt that is about to run. */\n readonly attempt: number\n /** Maximum number of retry attempts allowed for this upload operation. */\n readonly maxRetries: number\n /** Backoff delay in milliseconds before the fresh URL is fetched. */\n readonly delayMs: number\n /** Classified error that triggered the fresh-URL retry. */\n readonly error: B2Error | NetworkError\n}\n\n/** Callback invoked before an upload retry fetches a fresh upload URL. */\nexport type UploadRetryListener = (event: UploadRetryEvent) => void\n\n/** Shared public options for upload-layer fresh-URL retries. */\nexport interface UploadRetryOptions {\n /** Retry settings shared with the main transport retry configuration. */\n readonly retry?: Partial<RetryOptions> | undefined\n /** Callback invoked before a fresh-URL upload retry. */\n readonly onUploadRetry?: UploadRetryListener | undefined\n /**\n * Whether ambiguous failures after an upload POST should be retried,\n * including response-body read failures and transport errors where B2 may\n * have stored the payload before the success response was lost.\n * Defaults to false. Set true only when duplicate versions or parts are\n * acceptable.\n */\n readonly retryResponseBodyFailures?: boolean | undefined\n}\n\ninterface UploadLayerRetryOptions extends Omit<UploadRetryOptions, 'retryResponseBodyFailures'> {\n readonly retryResponseBodyFailures: boolean\n /** Abort signal for cancelling upload attempts and retry backoff sleeps. */\n readonly signal?: AbortSignal | undefined\n}\n\ninterface FreshUrlRetryOptions<T> extends UploadLayerRetryOptions {\n readonly fileName: string\n readonly partNumber: number | null\n readonly checkout: () => UploadUrlEntry | null\n readonly fetchFresh: () => Promise<UploadUrlEntry>\n readonly returnEntry: (entry: UploadUrlEntry) => void\n readonly evictEntry: (entry: UploadUrlEntry) => void\n readonly upload: (entry: UploadUrlEntry) => Promise<T>\n}\n\nconst freshUrlRetryOverride: Partial<RetryOptions> = { maxRetries: 0 }\n\n/**\n * Resolves the public default for `retryResponseBodyFailures`. Callers must\n * opt into replaying ambiguous upload POST failures for every upload mode.\n *\n * @param value - Caller-provided override, if any.\n *\n * @returns The boolean value passed to the upload retry helper.\n */\nexport function resolveRetryResponseBodyFailures(value: boolean | undefined): boolean {\n return value ?? false\n}\n\n/**\n * Fetches a small-file upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param bucketId - Bucket to upload into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh upload URL entry.\n */\nexport async function fetchFreshUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n bucketId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\n/**\n * Fetches a large-file part upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh part upload URL entry.\n */\nexport async function fetchFreshPartUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadPartUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n fileId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\ninterface UploadPartWithFreshUrlOptions extends UploadLayerRetryOptions {\n /** File name associated with the large-file upload. */\n readonly fileName: string\n /** One-based part number. */\n readonly partNumber: number\n /** Part bytes to upload. */\n readonly data: BodyInit\n /** Number of bytes in the part. */\n readonly contentLength: number\n /** SHA-1 hex digest of the part bytes. */\n readonly contentSha1: string\n /** Server-side encryption settings for this part. */\n readonly serverSideEncryption?: EncryptionSetting | undefined\n}\n\n/**\n * Uploads one multipart part with fresh-URL retry.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param options - Part upload parameters and retry settings.\n *\n * @returns The uploaded part response.\n */\nexport function uploadPartWithFreshUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n options: UploadPartWithFreshUrlOptions,\n): Promise<UploadPartResponse> {\n return withFreshUploadUrlRetry({\n fileName: options.fileName,\n partNumber: options.partNumber,\n retry: options.retry,\n signal: options.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: options.retryResponseBodyFailures,\n checkout: () => accountInfo.checkoutPartUploadUrl(fileId),\n fetchFresh: () => fetchFreshPartUploadUrl(raw, accountInfo, fileId, options.signal),\n returnEntry: (entry) => accountInfo.returnPartUploadUrl(fileId, entry),\n evictEntry: (entry) => accountInfo.evictPartUploadUrl(fileId, entry),\n upload: (entry) =>\n raw.uploadPart(\n entry.uploadUrl,\n {\n authorization: entry.authorizationToken,\n partNumber: options.partNumber,\n contentLength: options.contentLength,\n contentSha1: options.contentSha1,\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n },\n options.data,\n {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n ),\n })\n}\n\n/**\n * Runs an upload operation with B2's documented retry flow: evict the failed\n * upload URL, back off, fetch a fresh upload URL, and retry there.\n *\n * For single-request file uploads, sending the POST again after a lost success\n * response can create a duplicate file version. Multipart retries re-send the\n * same part number instead. Response-body retry defaults are caller-specific:\n * single-request uploads keep them off by default, while multipart callers can\n * opt in with `retryResponseBodyFailures: true` when replaying the same part\n * number is acceptable.\n *\n * @param options - URL checkout, upload, eviction, and retry callbacks.\n *\n * @returns The successful upload result.\n */\nexport async function withFreshUploadUrlRetry<T>(options: FreshUrlRetryOptions<T>): Promise<T> {\n const retryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options.retry }\n\n for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {\n let uploadEntry: UploadUrlEntry | undefined\n let uploadStarted = false\n\n try {\n options.signal?.throwIfAborted()\n uploadEntry =\n attempt === 0\n ? (options.checkout() ?? (await options.fetchFresh()))\n : await options.fetchFresh()\n\n uploadStarted = true\n const result = await options.upload(uploadEntry)\n options.returnEntry(uploadEntry)\n return result\n } catch (err) {\n const retryError = normalizeUploadRetryError(err, options)\n if (uploadEntry !== undefined) {\n if (isUploadRateLimitError(retryError)) {\n options.returnEntry(uploadEntry)\n } else {\n options.evictEntry(uploadEntry)\n }\n }\n if (options.signal?.aborted) {\n throw err\n }\n if (isUploadRateLimitError(retryError) && uploadEntry !== undefined) {\n throw retryError\n }\n if (\n !isUploadRetryable(retryError, { ...options, uploadStarted }) ||\n attempt === retryOptions.maxRetries\n ) {\n throw retryError\n }\n\n const retryAttempt = attempt + 1\n const retryAfter = retryError instanceof B2Error ? retryError.retryAfter : undefined\n const delayMs = computeBackoff(attempt, retryOptions, retryAfter)\n notifyUploadRetry(options, {\n fileName: options.fileName,\n partNumber: options.partNumber,\n attempt: retryAttempt,\n maxRetries: retryOptions.maxRetries,\n delayMs,\n error: retryError,\n })\n await sleep(delayMs, options.signal)\n }\n }\n\n // Unreachable at runtime: the loop returns on success or throws from the\n // final failed attempt. This satisfies TypeScript's return-path analysis.\n /* v8 ignore next -- defensive return-path guard. */\n throw new NetworkError('Upload retry budget exhausted')\n}\n\nfunction notifyUploadRetry(options: UploadLayerRetryOptions, event: UploadRetryEvent): void {\n try {\n options.onUploadRetry?.(event)\n } catch {\n // Telemetry observers must not replace the underlying upload failure or\n // prevent a retry that can recover with a fresh upload URL.\n }\n}\n\nfunction isUploadRetryable(\n err: unknown,\n options: UploadLayerRetryOptions & {\n readonly partNumber: number | null\n readonly uploadStarted: boolean\n },\n): err is B2Error | NetworkError {\n if (err instanceof NetworkError) {\n if (err.cause instanceof B2SsrfError) return false\n if (!options.uploadStarted) return true\n return options.retryResponseBodyFailures === true\n }\n if (err instanceof BadAuthTokenError) return true\n if (isUploadUrlInvalidationError(err)) return true\n return err instanceof B2Error && err.retryable\n}\n\nfunction isUploadRateLimitError(err: unknown): err is B2Error {\n return err instanceof B2Error && err.status === 429\n}\n\nfunction normalizeUploadRetryError(err: unknown, options: UploadLayerRetryOptions): unknown {\n if (err instanceof B2Error || err instanceof NetworkError) return err\n if (err instanceof UploadResponseBodyError) {\n if (!options.retryResponseBodyFailures) return err\n return new NetworkError(err.message, err)\n }\n if (err instanceof DOMException && err.name === 'AbortError') return err\n if (err instanceof TypeError || err instanceof SyntaxError || err instanceof DOMException) {\n const message = err instanceof Error ? err.message : 'Upload response read failed'\n return new NetworkError(message, err)\n }\n return err\n}\n\nfunction isUploadUrlInvalidationError(err: unknown): boolean {\n if (err instanceof BadUploadUrlError) return true\n return err instanceof BadRequestError && /upload url/i.test(err.message)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"retry.js","names":[],"sources":["../../src/upload/retry.ts"],"sourcesContent":["import type { AccountInfo, UploadUrlEntry } from '../auth/account-info.ts'\nimport {\n B2Error,\n B2SsrfError,\n BadAuthTokenError,\n BadRequestError,\n BadUploadUrlError,\n NetworkError,\n UploadResponseBodyError,\n} from '../errors/index.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from '../http/retry.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { EncryptionMode, type EncryptionSetting } from '../types/encryption.ts'\nimport type { BucketId, LargeFileId } from '../types/ids.ts'\nimport type { UploadPartResponse } from '../types/upload.ts'\n\n/** Event emitted before an upload is retried against a fresh upload URL. */\nexport interface UploadRetryEvent {\n /** File name being uploaded. */\n readonly fileName: string\n /** Multipart part number, or `null` for a single-request file upload. */\n readonly partNumber: number | null\n /** One-based retry attempt that is about to run. */\n readonly attempt: number\n /** Maximum number of retry attempts allowed for this upload operation. */\n readonly maxRetries: number\n /** Backoff delay in milliseconds before the fresh URL is fetched. */\n readonly delayMs: number\n /** Classified error that triggered the fresh-URL retry. */\n readonly error: B2Error | NetworkError\n}\n\n/** Callback invoked before an upload retry fetches a fresh upload URL. */\nexport type UploadRetryListener = (event: UploadRetryEvent) => void\n\n/** Shared public options for upload-layer fresh-URL retries. */\nexport interface UploadRetryOptions {\n /** Retry settings shared with the main transport retry configuration. */\n readonly retry?: Partial<RetryOptions> | undefined\n /** Callback invoked before a fresh-URL upload retry. */\n readonly onUploadRetry?: UploadRetryListener | undefined\n /**\n * Whether ambiguous failures after an upload POST should be retried,\n * including response-body read failures and transport errors where B2 may\n * have stored the payload before the success response was lost.\n * Defaults to false. Set true only when duplicate versions or parts are\n * acceptable.\n */\n readonly retryResponseBodyFailures?: boolean | undefined\n}\n\ninterface UploadLayerRetryOptions extends Omit<UploadRetryOptions, 'retryResponseBodyFailures'> {\n readonly retryResponseBodyFailures: boolean\n /** Abort signal for cancelling upload attempts and retry backoff sleeps. */\n readonly signal?: AbortSignal | undefined\n}\n\ninterface FreshUrlRetryOptions<T> extends UploadLayerRetryOptions {\n readonly fileName: string\n readonly partNumber: number | null\n readonly checkout: () => UploadUrlEntry | null\n readonly fetchFresh: () => Promise<UploadUrlEntry>\n readonly returnEntry: (entry: UploadUrlEntry) => void\n readonly evictEntry: (entry: UploadUrlEntry) => void\n readonly upload: (entry: UploadUrlEntry) => Promise<T>\n}\n\nconst freshUrlRetryOverride: Partial<RetryOptions> = { maxRetries: 0 }\n\n/**\n * Resolves the public default for `retryResponseBodyFailures`. Callers must\n * opt into replaying ambiguous upload POST failures for every upload mode.\n *\n * @param value - Caller-provided override, if any.\n *\n * @returns The boolean value passed to the upload retry helper.\n */\nexport function resolveRetryResponseBodyFailures(value: boolean | undefined): boolean {\n return value ?? false\n}\n\n/**\n * Fetches a small-file upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param bucketId - Bucket to upload into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh upload URL entry.\n */\nexport async function fetchFreshUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n bucketId: BucketId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n bucketId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\n/**\n * Fetches a large-file part upload URL, bypassing the pool.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param signal - Optional abort signal for the fresh URL request.\n *\n * @returns A fresh part upload URL entry.\n */\nexport async function fetchFreshPartUploadUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n signal?: AbortSignal,\n): Promise<UploadUrlEntry> {\n const resp = await raw.getUploadPartUrl(\n accountInfo.getApiUrl(),\n accountInfo.getAuthToken(),\n {\n fileId,\n },\n {\n ...(signal !== undefined ? { signal } : {}),\n retry: freshUrlRetryOverride,\n },\n )\n return { uploadUrl: resp.uploadUrl, authorizationToken: resp.authorizationToken }\n}\n\ninterface UploadPartWithFreshUrlOptions extends UploadLayerRetryOptions {\n /** File name associated with the large-file upload. */\n readonly fileName: string\n /** One-based part number. */\n readonly partNumber: number\n /** Part bytes to upload. */\n readonly data: BodyInit\n /** Number of bytes in the part. */\n readonly contentLength: number\n /** SHA-1 hex digest of the part bytes. */\n readonly contentSha1: string\n /** Server-side encryption settings for this part. */\n readonly serverSideEncryption?: EncryptionSetting | undefined\n}\n\nfunction uploadPartEncryption(\n encryption: EncryptionSetting | undefined,\n): EncryptionSetting | undefined {\n // B2-managed encryption is configured on b2_start_large_file. b2_upload_part\n // only accepts customer-key headers, so SSE-B2 must not be repeated per part.\n return encryption?.mode === EncryptionMode.SseC ? encryption : undefined\n}\n\n/**\n * Uploads one multipart part with fresh-URL retry.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - Large file to upload a part into.\n * @param options - Part upload parameters and retry settings.\n *\n * @returns The uploaded part response.\n */\nexport function uploadPartWithFreshUrl(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: LargeFileId,\n options: UploadPartWithFreshUrlOptions,\n): Promise<UploadPartResponse> {\n return withFreshUploadUrlRetry({\n fileName: options.fileName,\n partNumber: options.partNumber,\n retry: options.retry,\n signal: options.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: options.retryResponseBodyFailures,\n checkout: () => accountInfo.checkoutPartUploadUrl(fileId),\n fetchFresh: () => fetchFreshPartUploadUrl(raw, accountInfo, fileId, options.signal),\n returnEntry: (entry) => accountInfo.returnPartUploadUrl(fileId, entry),\n evictEntry: (entry) => accountInfo.evictPartUploadUrl(fileId, entry),\n upload: (entry) => {\n const serverSideEncryption = uploadPartEncryption(options.serverSideEncryption)\n return raw.uploadPart(\n entry.uploadUrl,\n {\n authorization: entry.authorizationToken,\n partNumber: options.partNumber,\n contentLength: options.contentLength,\n contentSha1: options.contentSha1,\n ...(serverSideEncryption !== undefined ? { serverSideEncryption } : {}),\n },\n options.data,\n {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n )\n },\n })\n}\n\n/**\n * Runs an upload operation with B2's documented retry flow: evict the failed\n * upload URL, back off, fetch a fresh upload URL, and retry there.\n *\n * For single-request file uploads, sending the POST again after a lost success\n * response can create a duplicate file version. Multipart retries re-send the\n * same part number instead. Response-body retry defaults are caller-specific:\n * single-request uploads keep them off by default, while multipart callers can\n * opt in with `retryResponseBodyFailures: true` when replaying the same part\n * number is acceptable.\n *\n * @param options - URL checkout, upload, eviction, and retry callbacks.\n *\n * @returns The successful upload result.\n */\nexport async function withFreshUploadUrlRetry<T>(options: FreshUrlRetryOptions<T>): Promise<T> {\n const retryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options.retry }\n\n for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {\n let uploadEntry: UploadUrlEntry | undefined\n let uploadStarted = false\n\n try {\n options.signal?.throwIfAborted()\n uploadEntry =\n attempt === 0\n ? (options.checkout() ?? (await options.fetchFresh()))\n : await options.fetchFresh()\n\n uploadStarted = true\n const result = await options.upload(uploadEntry)\n options.returnEntry(uploadEntry)\n return result\n } catch (err) {\n const retryError = normalizeUploadRetryError(err, options)\n if (uploadEntry !== undefined) {\n if (isUploadRateLimitError(retryError)) {\n options.returnEntry(uploadEntry)\n } else {\n options.evictEntry(uploadEntry)\n }\n }\n if (options.signal?.aborted) {\n throw err\n }\n if (isUploadRateLimitError(retryError) && uploadEntry !== undefined) {\n throw retryError\n }\n if (\n !isUploadRetryable(retryError, { ...options, uploadStarted }) ||\n attempt === retryOptions.maxRetries\n ) {\n throw retryError\n }\n\n const retryAttempt = attempt + 1\n const retryAfter = retryError instanceof B2Error ? retryError.retryAfter : undefined\n const delayMs = computeBackoff(attempt, retryOptions, retryAfter)\n notifyUploadRetry(options, {\n fileName: options.fileName,\n partNumber: options.partNumber,\n attempt: retryAttempt,\n maxRetries: retryOptions.maxRetries,\n delayMs,\n error: retryError,\n })\n await sleep(delayMs, options.signal)\n }\n }\n\n // Unreachable at runtime: the loop returns on success or throws from the\n // final failed attempt. This satisfies TypeScript's return-path analysis.\n /* v8 ignore next -- defensive return-path guard. */\n throw new NetworkError('Upload retry budget exhausted')\n}\n\nfunction notifyUploadRetry(options: UploadLayerRetryOptions, event: UploadRetryEvent): void {\n try {\n options.onUploadRetry?.(event)\n } catch {\n // Telemetry observers must not replace the underlying upload failure or\n // prevent a retry that can recover with a fresh upload URL.\n }\n}\n\nfunction isUploadRetryable(\n err: unknown,\n options: UploadLayerRetryOptions & {\n readonly partNumber: number | null\n readonly uploadStarted: boolean\n },\n): err is B2Error | NetworkError {\n if (err instanceof NetworkError) {\n if (err.cause instanceof B2SsrfError) return false\n if (!options.uploadStarted) return true\n return options.retryResponseBodyFailures === true\n }\n if (err instanceof BadAuthTokenError) return true\n if (isUploadUrlInvalidationError(err)) return true\n return err instanceof B2Error && err.retryable\n}\n\nfunction isUploadRateLimitError(err: unknown): err is B2Error {\n return err instanceof B2Error && err.status === 429\n}\n\nfunction normalizeUploadRetryError(err: unknown, options: UploadLayerRetryOptions): unknown {\n if (err instanceof B2Error || err instanceof NetworkError) return err\n if (err instanceof UploadResponseBodyError) {\n if (!options.retryResponseBodyFailures) return err\n return new NetworkError(err.message, err)\n }\n if (err instanceof DOMException && err.name === 'AbortError') return err\n if (err instanceof TypeError || err instanceof SyntaxError || err instanceof DOMException) {\n const message = err instanceof Error ? err.message : 'Upload response read failed'\n return new NetworkError(message, err)\n }\n return err\n}\n\nfunction isUploadUrlInvalidationError(err: unknown): boolean {\n if (err instanceof BadUploadUrlError) return true\n return err instanceof BadRequestError && /upload url/i.test(err.message)\n}\n"],"mappings":"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"}
@@ -26,38 +26,42 @@ async function uploadSmallFile(raw, accountInfo, options) {
26
26
  const sha1 = new require_hash.IncrementalSha1();
27
27
  await sha1.update(data);
28
28
  const sha1Hex = await sha1.digest();
29
- const tracker = new require_progress.ProgressTracker(options.onProgress, data.byteLength, 1);
30
- const result = await require_retry.withFreshUploadUrlRetry({
31
- fileName: options.fileName,
32
- partNumber: null,
33
- retry: options.retry,
34
- signal: options.signal,
35
- onUploadRetry: options.onUploadRetry,
36
- retryResponseBodyFailures: require_retry.resolveRetryResponseBodyFailures(options.retryResponseBodyFailures),
37
- checkout: () => accountInfo.checkoutUploadUrl(options.bucketId),
38
- fetchFresh: () => require_retry.fetchFreshUploadUrl(raw, accountInfo, options.bucketId, options.signal),
39
- returnEntry: (entry) => accountInfo.returnUploadUrl(options.bucketId, entry),
40
- evictEntry: (entry) => accountInfo.evictUploadUrl(options.bucketId, entry),
41
- upload: (entry) => raw.uploadFile(entry.uploadUrl, {
42
- authorization: entry.authorizationToken,
29
+ const tracker = new require_progress.ProgressTracker(options.onProgress, data.byteLength, 1, { ...options.progressIntervalMillis !== void 0 ? { minIntervalMs: options.progressIntervalMillis } : {} });
30
+ try {
31
+ const result = await require_retry.withFreshUploadUrlRetry({
43
32
  fileName: options.fileName,
44
- contentType: options.contentType ?? "b2/x-auto",
45
- contentLength: data.byteLength,
46
- contentSha1: sha1Hex,
47
- ...options.fileInfo !== void 0 ? { fileInfo: options.fileInfo } : {},
48
- ...options.serverSideEncryption !== void 0 ? { serverSideEncryption: options.serverSideEncryption } : {},
49
- ...options.fileRetention !== void 0 ? { fileRetention: options.fileRetention } : {},
50
- ...options.legalHold !== void 0 ? { legalHold: options.legalHold } : {},
51
- ...options.lastModifiedMillis !== void 0 ? { lastModifiedMillis: options.lastModifiedMillis } : {},
52
- ...options.customUploadTimestamp !== void 0 ? { customUploadTimestamp: options.customUploadTimestamp } : {}
53
- }, data, {
54
- ...options.signal !== void 0 ? { signal: options.signal } : {},
55
- ...options.retry !== void 0 ? { retry: options.retry } : {}
56
- })
57
- });
58
- tracker.addBytes(data.byteLength);
59
- tracker.completePart();
60
- return result;
33
+ partNumber: null,
34
+ retry: options.retry,
35
+ signal: options.signal,
36
+ onUploadRetry: options.onUploadRetry,
37
+ retryResponseBodyFailures: require_retry.resolveRetryResponseBodyFailures(options.retryResponseBodyFailures),
38
+ checkout: () => accountInfo.checkoutUploadUrl(options.bucketId),
39
+ fetchFresh: () => require_retry.fetchFreshUploadUrl(raw, accountInfo, options.bucketId, options.signal),
40
+ returnEntry: (entry) => accountInfo.returnUploadUrl(options.bucketId, entry),
41
+ evictEntry: (entry) => accountInfo.evictUploadUrl(options.bucketId, entry),
42
+ upload: (entry) => raw.uploadFile(entry.uploadUrl, {
43
+ authorization: entry.authorizationToken,
44
+ fileName: options.fileName,
45
+ contentType: options.contentType ?? "b2/x-auto",
46
+ contentLength: data.byteLength,
47
+ contentSha1: sha1Hex,
48
+ ...options.fileInfo !== void 0 ? { fileInfo: options.fileInfo } : {},
49
+ ...options.serverSideEncryption !== void 0 ? { serverSideEncryption: options.serverSideEncryption } : {},
50
+ ...options.fileRetention !== void 0 ? { fileRetention: options.fileRetention } : {},
51
+ ...options.legalHold !== void 0 ? { legalHold: options.legalHold } : {},
52
+ ...options.lastModifiedMillis !== void 0 ? { lastModifiedMillis: options.lastModifiedMillis } : {},
53
+ ...options.customUploadTimestamp !== void 0 ? { customUploadTimestamp: options.customUploadTimestamp } : {}
54
+ }, data, {
55
+ ...options.signal !== void 0 ? { signal: options.signal } : {},
56
+ ...options.retry !== void 0 ? { retry: options.retry } : {}
57
+ })
58
+ });
59
+ tracker.addBytes(data.byteLength);
60
+ tracker.completePart();
61
+ return result;
62
+ } finally {
63
+ tracker.dispose();
64
+ }
61
65
  }
62
66
  async function readSmallFileSource(source, signal) {
63
67
  signal?.throwIfAborted();
@@ -1 +1 @@
1
- {"version":3,"file":"single.cjs","names":[],"sources":["../../src/upload/single.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport { type ProgressListener, ProgressTracker } from '../streams/progress.ts'\nimport { type ContentSource, collectStreamExactly } from '../streams/source.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { FileVersion } from '../types/file.ts'\nimport type { BucketId } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport { DEFAULT_CONTENT_TYPE } from '../util/defaults.ts'\nimport {\n fetchFreshUploadUrl,\n resolveRetryResponseBodyFailures,\n type UploadRetryOptions,\n withFreshUploadUrlRetry,\n} from './retry.ts'\n\n/** Options for uploading a small file in a single HTTP request. */\nexport interface UploadFileOptions extends UploadRetryOptions {\n /** Target bucket for the upload. */\n readonly bucketId: BucketId\n /** Full B2 file name including any path prefix. */\n readonly fileName: string\n /** Content to upload. */\n readonly source: ContentSource\n /** MIME type. Defaults to `b2/x-auto` for server-side detection. */\n readonly contentType?: string\n /** Custom file info key/value pairs stored with the file. */\n readonly fileInfo?: Record<string, string>\n /** Server-side encryption settings. */\n readonly serverSideEncryption?: EncryptionSetting\n /** File retention policy applied at upload time. */\n readonly fileRetention?: FileRetentionValue\n /** Legal hold status applied at upload time. */\n readonly legalHold?: LegalHoldValue\n /** Override the last-modified timestamp (epoch millis). */\n readonly lastModifiedMillis?: number\n /**\n * B2 upload timestamp override in milliseconds since epoch.\n * Sets the file version `uploadTimestamp`; distinct from `lastModifiedMillis` metadata.\n * Requires B2 account enablement for Custom Upload Timestamp.\n */\n readonly customUploadTimestamp?: number\n /** Callback invoked with upload progress updates. */\n readonly onProgress?: ProgressListener\n /** Signal to abort the upload. */\n readonly signal?: AbortSignal\n}\n\n/**\n * Uploads a file in a single HTTP request (suitable for files up to ~100 MB).\n *\n * The entire file content is read into memory, SHA-1 hashed, and sent in one\n * `b2_upload_file` call. For files larger than the recommended part size, use\n * {@link uploadLargeFile} which splits the file into parts uploaded in parallel.\n *\n * Upload URLs are pooled via {@link AccountInfo} and recycled on success or\n * evicted on failure.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state (tokens, URLs, upload URL pool).\n * @param options - Upload parameters.\n *\n * @returns The resulting {@link FileVersion} metadata.\n */\nexport async function uploadSmallFile(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadFileOptions,\n): Promise<FileVersion> {\n const data = await readSmallFileSource(options.source, options.signal)\n if (data.byteLength !== options.source.size) {\n throw new Error(\n `uploadSmallFile: source byte count does not match advertised size ` +\n `(expected ${options.source.size} bytes, got ${data.byteLength} bytes).`,\n )\n }\n const sha1 = new IncrementalSha1()\n await sha1.update(data)\n const sha1Hex = await sha1.digest()\n\n // Single-request uploads send the whole payload in one shot, so the\n // tracker reports a single \"part\" worth of progress: one byte burst at\n // completion and a parts-completed transition from 0 → 1. The tracker\n // is created (rather than calling the listener directly) so consumers\n // see the same {bytesTransferred, totalBytes, partsCompleted,\n // totalParts, elapsedMs} shape they get from `uploadLargeFile`.\n const tracker = new ProgressTracker(options.onProgress, data.byteLength, 1)\n\n const result = await withFreshUploadUrlRetry({\n fileName: options.fileName,\n partNumber: null,\n retry: options.retry,\n signal: options.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(options.retryResponseBodyFailures),\n checkout: () => accountInfo.checkoutUploadUrl(options.bucketId),\n fetchFresh: () => fetchFreshUploadUrl(raw, accountInfo, options.bucketId, options.signal),\n returnEntry: (entry) => accountInfo.returnUploadUrl(options.bucketId, entry),\n evictEntry: (entry) => accountInfo.evictUploadUrl(options.bucketId, entry),\n upload: (entry) =>\n raw.uploadFile(\n entry.uploadUrl,\n {\n authorization: entry.authorizationToken,\n fileName: options.fileName,\n contentType: options.contentType ?? DEFAULT_CONTENT_TYPE,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n ...(options.fileInfo !== undefined ? { fileInfo: options.fileInfo } : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.fileRetention !== undefined ? { fileRetention: options.fileRetention } : {}),\n ...(options.legalHold !== undefined ? { legalHold: options.legalHold } : {}),\n ...(options.lastModifiedMillis !== undefined\n ? { lastModifiedMillis: options.lastModifiedMillis }\n : {}),\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: options.customUploadTimestamp }\n : {}),\n },\n data,\n {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n ),\n })\n\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n return result\n}\n\nasync function readSmallFileSource(\n source: ContentSource,\n signal: AbortSignal | undefined,\n): Promise<Uint8Array<ArrayBuffer>> {\n signal?.throwIfAborted()\n if (!source.canSlice) {\n return collectStreamExactly(source.stream(), source.size, signal)\n }\n const data = new Uint8Array(\n await (signal === undefined ? source.toArrayBuffer() : source.toArrayBuffer({ signal })),\n )\n signal?.throwIfAborted()\n return data\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAiEA,eAAsB,gBACpB,KACA,aACA,SACsB;CACtB,MAAM,OAAO,MAAM,oBAAoB,QAAQ,QAAQ,QAAQ,MAAM;CACrE,IAAI,KAAK,eAAe,QAAQ,OAAO,MACrC,MAAM,IAAI,MACR,+EACe,QAAQ,OAAO,KAAK,cAAc,KAAK,WAAW,SACnE;CAEF,MAAM,OAAO,IAAI,aAAA,gBAAgB;CACjC,MAAM,KAAK,OAAO,IAAI;CACtB,MAAM,UAAU,MAAM,KAAK,OAAO;CAQlC,MAAM,UAAU,IAAI,iBAAA,gBAAgB,QAAQ,YAAY,KAAK,YAAY,CAAC;CAE1E,MAAM,SAAS,MAAM,cAAA,wBAAwB;EAC3C,UAAU,QAAQ;EAClB,YAAY;EACZ,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,eAAe,QAAQ;EACvB,2BAA2B,cAAA,iCAAiC,QAAQ,yBAAyB;EAC7F,gBAAgB,YAAY,kBAAkB,QAAQ,QAAQ;EAC9D,kBAAkB,cAAA,oBAAoB,KAAK,aAAa,QAAQ,UAAU,QAAQ,MAAM;EACxF,cAAc,UAAU,YAAY,gBAAgB,QAAQ,UAAU,KAAK;EAC3E,aAAa,UAAU,YAAY,eAAe,QAAQ,UAAU,KAAK;EACzE,SAAS,UACP,IAAI,WACF,MAAM,WACN;GACE,eAAe,MAAM;GACrB,UAAU,QAAQ;GAClB,aAAa,QAAQ,eAAA;GACrB,eAAe,KAAK;GACpB,aAAa;GACb,GAAI,QAAQ,aAAa,KAAA,IAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;GACvE,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;GACL,GAAI,QAAQ,kBAAkB,KAAA,IAAY,EAAE,eAAe,QAAQ,cAAc,IAAI,CAAC;GACtF,GAAI,QAAQ,cAAc,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;GAC1E,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,mBAAmB,IACjD,CAAC;GACL,GAAI,QAAQ,0BAA0B,KAAA,IAClC,EAAE,uBAAuB,QAAQ,sBAAsB,IACvD,CAAC;EACP,GACA,MACA;GACE,GAAI,QAAQ,WAAW,KAAA,IAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;GACjE,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAChE,CACF;CACJ,CAAC;CAED,QAAQ,SAAS,KAAK,UAAU;CAChC,QAAQ,aAAa;CACrB,OAAO;AACT;AAEA,eAAe,oBACb,QACA,QACkC;CAClC,QAAQ,eAAe;CACvB,IAAI,CAAC,OAAO,UACV,OAAO,eAAA,qBAAqB,OAAO,OAAO,GAAG,OAAO,MAAM,MAAM;CAElE,MAAM,OAAO,IAAI,WACf,OAAO,WAAW,KAAA,IAAY,OAAO,cAAc,IAAI,OAAO,cAAc,EAAE,OAAO,CAAC,EACxF;CACA,QAAQ,eAAe;CACvB,OAAO;AACT"}
1
+ {"version":3,"file":"single.cjs","names":[],"sources":["../../src/upload/single.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport { type ProgressListener, ProgressTracker } from '../streams/progress.ts'\nimport { type ContentSource, collectStreamExactly } from '../streams/source.ts'\nimport type { EncryptionSetting } from '../types/encryption.ts'\nimport type { FileVersion } from '../types/file.ts'\nimport type { BucketId } from '../types/ids.ts'\nimport type { FileRetentionValue, LegalHoldValue } from '../types/lock.ts'\nimport { DEFAULT_CONTENT_TYPE } from '../util/defaults.ts'\nimport {\n fetchFreshUploadUrl,\n resolveRetryResponseBodyFailures,\n type UploadRetryOptions,\n withFreshUploadUrlRetry,\n} from './retry.ts'\n\n/** Options for uploading a small file in a single HTTP request. */\nexport interface UploadFileOptions extends UploadRetryOptions {\n /** Target bucket for the upload. */\n readonly bucketId: BucketId\n /** Full B2 file name including any path prefix. */\n readonly fileName: string\n /** Content to upload. */\n readonly source: ContentSource\n /** MIME type. Defaults to `b2/x-auto` for server-side detection. */\n readonly contentType?: string\n /** Custom file info key/value pairs stored with the file. */\n readonly fileInfo?: Record<string, string>\n /** Server-side encryption settings. */\n readonly serverSideEncryption?: EncryptionSetting\n /** File retention policy applied at upload time. */\n readonly fileRetention?: FileRetentionValue\n /** Legal hold status applied at upload time. */\n readonly legalHold?: LegalHoldValue\n /** Override the last-modified timestamp (epoch millis). */\n readonly lastModifiedMillis?: number\n /**\n * B2 upload timestamp override in milliseconds since epoch.\n * Sets the file version `uploadTimestamp`; distinct from `lastModifiedMillis` metadata.\n * Requires B2 account enablement for Custom Upload Timestamp.\n */\n readonly customUploadTimestamp?: number\n /** Callback invoked with upload progress updates. */\n readonly onProgress?: ProgressListener\n /**\n * Minimum milliseconds between byte-only progress callbacks. Defaults to\n * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.\n * Part-completion progress callbacks are always emitted immediately.\n */\n readonly progressIntervalMillis?: number\n /** Signal to abort the upload. */\n readonly signal?: AbortSignal\n}\n\n/**\n * Uploads a file in a single HTTP request (suitable for files up to ~100 MB).\n *\n * The entire file content is read into memory, SHA-1 hashed, and sent in one\n * `b2_upload_file` call. For files larger than the recommended part size, use\n * {@link uploadLargeFile} which splits the file into parts uploaded in parallel.\n *\n * Upload URLs are pooled via {@link AccountInfo} and recycled on success or\n * evicted on failure.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state (tokens, URLs, upload URL pool).\n * @param options - Upload parameters.\n *\n * @returns The resulting {@link FileVersion} metadata.\n */\nexport async function uploadSmallFile(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: UploadFileOptions,\n): Promise<FileVersion> {\n const data = await readSmallFileSource(options.source, options.signal)\n if (data.byteLength !== options.source.size) {\n throw new Error(\n `uploadSmallFile: source byte count does not match advertised size ` +\n `(expected ${options.source.size} bytes, got ${data.byteLength} bytes).`,\n )\n }\n const sha1 = new IncrementalSha1()\n await sha1.update(data)\n const sha1Hex = await sha1.digest()\n\n // Single-request uploads send the whole payload in one shot, so the\n // tracker reports a single \"part\" worth of progress: one byte burst at\n // completion and a parts-completed transition from 0 → 1. The tracker\n // is created (rather than calling the listener directly) so consumers\n // see the same {bytesTransferred, totalBytes, partsCompleted,\n // totalParts, elapsedMs} shape they get from `uploadLargeFile`.\n const tracker = new ProgressTracker(options.onProgress, data.byteLength, 1, {\n ...(options.progressIntervalMillis !== undefined\n ? { minIntervalMs: options.progressIntervalMillis }\n : {}),\n })\n\n try {\n const result = await withFreshUploadUrlRetry({\n fileName: options.fileName,\n partNumber: null,\n retry: options.retry,\n signal: options.signal,\n onUploadRetry: options.onUploadRetry,\n retryResponseBodyFailures: resolveRetryResponseBodyFailures(\n options.retryResponseBodyFailures,\n ),\n checkout: () => accountInfo.checkoutUploadUrl(options.bucketId),\n fetchFresh: () => fetchFreshUploadUrl(raw, accountInfo, options.bucketId, options.signal),\n returnEntry: (entry) => accountInfo.returnUploadUrl(options.bucketId, entry),\n evictEntry: (entry) => accountInfo.evictUploadUrl(options.bucketId, entry),\n upload: (entry) =>\n raw.uploadFile(\n entry.uploadUrl,\n {\n authorization: entry.authorizationToken,\n fileName: options.fileName,\n contentType: options.contentType ?? DEFAULT_CONTENT_TYPE,\n contentLength: data.byteLength,\n contentSha1: sha1Hex,\n ...(options.fileInfo !== undefined ? { fileInfo: options.fileInfo } : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.fileRetention !== undefined\n ? { fileRetention: options.fileRetention }\n : {}),\n ...(options.legalHold !== undefined ? { legalHold: options.legalHold } : {}),\n ...(options.lastModifiedMillis !== undefined\n ? { lastModifiedMillis: options.lastModifiedMillis }\n : {}),\n ...(options.customUploadTimestamp !== undefined\n ? { customUploadTimestamp: options.customUploadTimestamp }\n : {}),\n },\n data,\n {\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n ...(options.retry !== undefined ? { retry: options.retry } : {}),\n },\n ),\n })\n\n tracker.addBytes(data.byteLength)\n tracker.completePart()\n return result\n } finally {\n tracker.dispose()\n }\n}\n\nasync function readSmallFileSource(\n source: ContentSource,\n signal: AbortSignal | undefined,\n): Promise<Uint8Array<ArrayBuffer>> {\n signal?.throwIfAborted()\n if (!source.canSlice) {\n return collectStreamExactly(source.stream(), source.size, signal)\n }\n const data = new Uint8Array(\n await (signal === undefined ? source.toArrayBuffer() : source.toArrayBuffer({ signal })),\n )\n signal?.throwIfAborted()\n return data\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuEA,eAAsB,gBACpB,KACA,aACA,SACsB;CACtB,MAAM,OAAO,MAAM,oBAAoB,QAAQ,QAAQ,QAAQ,MAAM;CACrE,IAAI,KAAK,eAAe,QAAQ,OAAO,MACrC,MAAM,IAAI,MACR,+EACe,QAAQ,OAAO,KAAK,cAAc,KAAK,WAAW,SACnE;CAEF,MAAM,OAAO,IAAI,aAAA,gBAAgB;CACjC,MAAM,KAAK,OAAO,IAAI;CACtB,MAAM,UAAU,MAAM,KAAK,OAAO;CAQlC,MAAM,UAAU,IAAI,iBAAA,gBAAgB,QAAQ,YAAY,KAAK,YAAY,GAAG,EAC1E,GAAI,QAAQ,2BAA2B,KAAA,IACnC,EAAE,eAAe,QAAQ,uBAAuB,IAChD,CAAC,EACP,CAAC;CAED,IAAI;EACF,MAAM,SAAS,MAAM,cAAA,wBAAwB;GAC3C,UAAU,QAAQ;GAClB,YAAY;GACZ,OAAO,QAAQ;GACf,QAAQ,QAAQ;GAChB,eAAe,QAAQ;GACvB,2BAA2B,cAAA,iCACzB,QAAQ,yBACV;GACA,gBAAgB,YAAY,kBAAkB,QAAQ,QAAQ;GAC9D,kBAAkB,cAAA,oBAAoB,KAAK,aAAa,QAAQ,UAAU,QAAQ,MAAM;GACxF,cAAc,UAAU,YAAY,gBAAgB,QAAQ,UAAU,KAAK;GAC3E,aAAa,UAAU,YAAY,eAAe,QAAQ,UAAU,KAAK;GACzE,SAAS,UACP,IAAI,WACF,MAAM,WACN;IACE,eAAe,MAAM;IACrB,UAAU,QAAQ;IAClB,aAAa,QAAQ,eAAA;IACrB,eAAe,KAAK;IACpB,aAAa;IACb,GAAI,QAAQ,aAAa,KAAA,IAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;IACvE,GAAI,QAAQ,yBAAyB,KAAA,IACjC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;IACL,GAAI,QAAQ,kBAAkB,KAAA,IAC1B,EAAE,eAAe,QAAQ,cAAc,IACvC,CAAC;IACL,GAAI,QAAQ,cAAc,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;IAC1E,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,mBAAmB,IACjD,CAAC;IACL,GAAI,QAAQ,0BAA0B,KAAA,IAClC,EAAE,uBAAuB,QAAQ,sBAAsB,IACvD,CAAC;GACP,GACA,MACA;IACE,GAAI,QAAQ,WAAW,KAAA,IAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;IACjE,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;GAChE,CACF;EACJ,CAAC;EAED,QAAQ,SAAS,KAAK,UAAU;EAChC,QAAQ,aAAa;EACrB,OAAO;CACT,UAAU;EACR,QAAQ,QAAQ;CAClB;AACF;AAEA,eAAe,oBACb,QACA,QACkC;CAClC,QAAQ,eAAe;CACvB,IAAI,CAAC,OAAO,UACV,OAAO,eAAA,qBAAqB,OAAO,OAAO,GAAG,OAAO,MAAM,MAAM;CAElE,MAAM,OAAO,IAAI,WACf,OAAO,WAAW,KAAA,IAAY,OAAO,cAAc,IAAI,OAAO,cAAc,EAAE,OAAO,CAAC,EACxF;CACA,QAAQ,eAAe;CACvB,OAAO;AACT"}
@@ -35,6 +35,12 @@ export interface UploadFileOptions extends UploadRetryOptions {
35
35
  readonly customUploadTimestamp?: number;
36
36
  /** Callback invoked with upload progress updates. */
37
37
  readonly onProgress?: ProgressListener;
38
+ /**
39
+ * Minimum milliseconds between byte-only progress callbacks. Defaults to
40
+ * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.
41
+ * Part-completion progress callbacks are always emitted immediately.
42
+ */
43
+ readonly progressIntervalMillis?: number;
38
44
  /** Signal to abort the upload. */
39
45
  readonly signal?: AbortSignal;
40
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../src/upload/single.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,KAAK,gBAAgB,EAAmB,MAAM,wBAAwB,CAAA;AAC/E,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,sBAAsB,CAAA;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAE1E,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,YAAY,CAAA;AAEnB,mEAAmE;AACnE,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,uCAAuC;IACvC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,iBAAiB,CAAA;IACjD,oDAAoD;IACpD,QAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAA;IAC3C,gDAAgD;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IACpC;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IACvC,qDAAqD;IACrD,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAA;IACtC,kCAAkC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAgEtB"}
1
+ {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../src/upload/single.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,KAAK,gBAAgB,EAAmB,MAAM,wBAAwB,CAAA;AAC/E,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,sBAAsB,CAAA;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAE1E,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,YAAY,CAAA;AAEnB,mEAAmE;AACnE,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,uCAAuC;IACvC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,iBAAiB,CAAA;IACjD,oDAAoD;IACpD,QAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAA;IAC3C,gDAAgD;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IACpC;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IACvC,qDAAqD;IACrD,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAA;IACtC;;;;OAIG;IACH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;IACxC,kCAAkC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CA4EtB"}
@@ -35,6 +35,12 @@ export interface UploadFileOptions extends UploadRetryOptions {
35
35
  readonly customUploadTimestamp?: number;
36
36
  /** Callback invoked with upload progress updates. */
37
37
  readonly onProgress?: ProgressListener;
38
+ /**
39
+ * Minimum milliseconds between byte-only progress callbacks. Defaults to
40
+ * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.
41
+ * Part-completion progress callbacks are always emitted immediately.
42
+ */
43
+ readonly progressIntervalMillis?: number;
38
44
  /** Signal to abort the upload. */
39
45
  readonly signal?: AbortSignal;
40
46
  }