@backblaze-labs/b2-sdk 0.2.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 (590) hide show
  1. package/CHANGELOG.md +86 -1
  2. package/README.md +38 -7
  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/file.cjs.map +1 -1
  6. package/dist/auth/reauth-coalescer.cjs +65 -0
  7. package/dist/auth/reauth-coalescer.cjs.map +1 -0
  8. package/dist/auth/reauth-coalescer.d.cts +34 -0
  9. package/dist/auth/reauth-coalescer.d.cts.map +1 -0
  10. package/dist/auth/reauth-coalescer.d.ts +34 -0
  11. package/dist/auth/reauth-coalescer.d.ts.map +1 -0
  12. package/dist/auth/reauth-coalescer.js +65 -0
  13. package/dist/auth/reauth-coalescer.js.map +1 -0
  14. package/dist/backup/client.cjs +206 -0
  15. package/dist/backup/client.cjs.map +1 -0
  16. package/dist/backup/client.d.cts +238 -0
  17. package/dist/backup/client.d.cts.map +1 -0
  18. package/dist/backup/client.d.ts +238 -0
  19. package/dist/backup/client.d.ts.map +1 -0
  20. package/dist/backup/client.js +206 -0
  21. package/dist/backup/client.js.map +1 -0
  22. package/dist/backup/index.cjs +15 -0
  23. package/dist/backup/index.d.cts +22 -0
  24. package/dist/backup/index.d.cts.map +1 -0
  25. package/dist/backup/index.d.ts +22 -0
  26. package/dist/backup/index.d.ts.map +1 -0
  27. package/dist/backup/index.js +7 -0
  28. package/dist/backup/raw.cjs +168 -0
  29. package/dist/backup/raw.cjs.map +1 -0
  30. package/dist/backup/raw.d.cts +122 -0
  31. package/dist/backup/raw.d.cts.map +1 -0
  32. package/dist/backup/raw.d.ts +122 -0
  33. package/dist/backup/raw.d.ts.map +1 -0
  34. package/dist/backup/raw.js +168 -0
  35. package/dist/backup/raw.js.map +1 -0
  36. package/dist/bucket-validation.cjs +111 -0
  37. package/dist/bucket-validation.cjs.map +1 -0
  38. package/dist/bucket-validation.d.cts +27 -0
  39. package/dist/bucket-validation.d.cts.map +1 -0
  40. package/dist/bucket-validation.d.ts +27 -0
  41. package/dist/bucket-validation.d.ts.map +1 -0
  42. package/dist/bucket-validation.js +109 -0
  43. package/dist/bucket-validation.js.map +1 -0
  44. package/dist/bucket.cjs +125 -74
  45. package/dist/bucket.cjs.map +1 -1
  46. package/dist/bucket.d.cts +156 -61
  47. package/dist/bucket.d.cts.map +1 -1
  48. package/dist/bucket.d.ts +156 -61
  49. package/dist/bucket.d.ts.map +1 -1
  50. package/dist/bucket.js +125 -74
  51. package/dist/bucket.js.map +1 -1
  52. package/dist/client.cjs +29 -8
  53. package/dist/client.cjs.map +1 -1
  54. package/dist/client.d.cts +30 -9
  55. package/dist/client.d.cts.map +1 -1
  56. package/dist/client.d.ts +30 -9
  57. package/dist/client.d.ts.map +1 -1
  58. package/dist/client.js +29 -8
  59. package/dist/client.js.map +1 -1
  60. package/dist/copy/large.cjs +5 -3
  61. package/dist/copy/large.cjs.map +1 -1
  62. package/dist/copy/large.d.cts.map +1 -1
  63. package/dist/copy/large.d.ts.map +1 -1
  64. package/dist/copy/large.js +5 -3
  65. package/dist/copy/large.js.map +1 -1
  66. package/dist/download/checksum.cjs +6 -2
  67. package/dist/download/checksum.cjs.map +1 -1
  68. package/dist/download/checksum.js +6 -2
  69. package/dist/download/checksum.js.map +1 -1
  70. package/dist/download/parallel.cjs +52 -15
  71. package/dist/download/parallel.cjs.map +1 -1
  72. package/dist/download/parallel.d.cts +8 -1
  73. package/dist/download/parallel.d.cts.map +1 -1
  74. package/dist/download/parallel.d.ts +8 -1
  75. package/dist/download/parallel.d.ts.map +1 -1
  76. package/dist/download/parallel.js +52 -15
  77. package/dist/download/parallel.js.map +1 -1
  78. package/dist/download/single.cjs +179 -19
  79. package/dist/download/single.cjs.map +1 -1
  80. package/dist/download/single.d.cts +10 -4
  81. package/dist/download/single.d.cts.map +1 -1
  82. package/dist/download/single.d.ts +10 -4
  83. package/dist/download/single.d.ts.map +1 -1
  84. package/dist/download/single.js +179 -19
  85. package/dist/download/single.js.map +1 -1
  86. package/dist/errors/index.cjs +196 -3
  87. package/dist/errors/index.cjs.map +1 -1
  88. package/dist/errors/index.d.cts +134 -0
  89. package/dist/errors/index.d.cts.map +1 -1
  90. package/dist/errors/index.d.ts +134 -0
  91. package/dist/errors/index.d.ts.map +1 -1
  92. package/dist/errors/index.js +183 -4
  93. package/dist/errors/index.js.map +1 -1
  94. package/dist/http/non-idempotent-mutations.cjs +38 -0
  95. package/dist/http/non-idempotent-mutations.cjs.map +1 -0
  96. package/dist/http/non-idempotent-mutations.d.cts +25 -0
  97. package/dist/http/non-idempotent-mutations.d.cts.map +1 -0
  98. package/dist/http/non-idempotent-mutations.d.ts +25 -0
  99. package/dist/http/non-idempotent-mutations.d.ts.map +1 -0
  100. package/dist/http/non-idempotent-mutations.js +35 -0
  101. package/dist/http/non-idempotent-mutations.js.map +1 -0
  102. package/dist/http/retry.cjs +1 -1
  103. package/dist/http/retry.cjs.map +1 -1
  104. package/dist/http/retry.js +1 -1
  105. package/dist/http/retry.js.map +1 -1
  106. package/dist/http/transport.cjs +62 -23
  107. package/dist/http/transport.cjs.map +1 -1
  108. package/dist/http/transport.d.cts +30 -3
  109. package/dist/http/transport.d.cts.map +1 -1
  110. package/dist/http/transport.d.ts +30 -3
  111. package/dist/http/transport.d.ts.map +1 -1
  112. package/dist/http/transport.js +60 -22
  113. package/dist/http/transport.js.map +1 -1
  114. package/dist/http/user-agent.cjs +12 -1
  115. package/dist/http/user-agent.cjs.map +1 -1
  116. package/dist/http/user-agent.d.cts +8 -0
  117. package/dist/http/user-agent.d.cts.map +1 -1
  118. package/dist/http/user-agent.d.ts +8 -0
  119. package/dist/http/user-agent.d.ts.map +1 -1
  120. package/dist/http/user-agent.js +13 -3
  121. package/dist/http/user-agent.js.map +1 -1
  122. package/dist/index.cjs +50 -2
  123. package/dist/index.d.cts +15 -12
  124. package/dist/index.d.cts.map +1 -1
  125. package/dist/index.d.ts +15 -12
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +13 -10
  128. package/dist/notifications/index.cjs +3 -0
  129. package/dist/notifications/index.d.cts +2 -0
  130. package/dist/notifications/index.d.cts.map +1 -1
  131. package/dist/notifications/index.d.ts +2 -0
  132. package/dist/notifications/index.d.ts.map +1 -1
  133. package/dist/notifications/index.js +2 -1
  134. package/dist/object.cjs +13 -2
  135. package/dist/object.cjs.map +1 -1
  136. package/dist/object.d.cts +11 -3
  137. package/dist/object.d.cts.map +1 -1
  138. package/dist/object.d.ts +11 -3
  139. package/dist/object.d.ts.map +1 -1
  140. package/dist/object.js +13 -2
  141. package/dist/object.js.map +1 -1
  142. package/dist/partner/account-info.d.cts +43 -0
  143. package/dist/partner/account-info.d.cts.map +1 -0
  144. package/dist/partner/account-info.d.ts +43 -0
  145. package/dist/partner/account-info.d.ts.map +1 -0
  146. package/dist/partner/auth-clone.cjs +64 -0
  147. package/dist/partner/auth-clone.cjs.map +1 -0
  148. package/dist/partner/auth-clone.d.cts +27 -0
  149. package/dist/partner/auth-clone.d.cts.map +1 -0
  150. package/dist/partner/auth-clone.d.ts +27 -0
  151. package/dist/partner/auth-clone.d.ts.map +1 -0
  152. package/dist/partner/auth-clone.js +63 -0
  153. package/dist/partner/auth-clone.js.map +1 -0
  154. package/dist/partner/auth-core.cjs +156 -0
  155. package/dist/partner/auth-core.cjs.map +1 -0
  156. package/dist/partner/auth-core.d.cts +111 -0
  157. package/dist/partner/auth-core.d.cts.map +1 -0
  158. package/dist/partner/auth-core.d.ts +111 -0
  159. package/dist/partner/auth-core.d.ts.map +1 -0
  160. package/dist/partner/auth-core.js +156 -0
  161. package/dist/partner/auth-core.js.map +1 -0
  162. package/dist/partner/auth-shape.cjs +36 -0
  163. package/dist/partner/auth-shape.cjs.map +1 -0
  164. package/dist/partner/auth-shape.d.cts +12 -0
  165. package/dist/partner/auth-shape.d.cts.map +1 -0
  166. package/dist/partner/auth-shape.d.ts +12 -0
  167. package/dist/partner/auth-shape.d.ts.map +1 -0
  168. package/dist/partner/auth-shape.js +36 -0
  169. package/dist/partner/auth-shape.js.map +1 -0
  170. package/dist/partner/client.cjs +270 -0
  171. package/dist/partner/client.cjs.map +1 -0
  172. package/dist/partner/client.d.cts +357 -0
  173. package/dist/partner/client.d.cts.map +1 -0
  174. package/dist/partner/client.d.ts +357 -0
  175. package/dist/partner/client.d.ts.map +1 -0
  176. package/dist/partner/client.js +270 -0
  177. package/dist/partner/client.js.map +1 -0
  178. package/dist/partner/endpoint-url.cjs +109 -0
  179. package/dist/partner/endpoint-url.cjs.map +1 -0
  180. package/dist/partner/endpoint-url.d.cts +74 -0
  181. package/dist/partner/endpoint-url.d.cts.map +1 -0
  182. package/dist/partner/endpoint-url.d.ts +74 -0
  183. package/dist/partner/endpoint-url.d.ts.map +1 -0
  184. package/dist/partner/endpoint-url.js +106 -0
  185. package/dist/partner/endpoint-url.js.map +1 -0
  186. package/dist/partner/in-memory.cjs +135 -0
  187. package/dist/partner/in-memory.cjs.map +1 -0
  188. package/dist/partner/in-memory.d.cts +99 -0
  189. package/dist/partner/in-memory.d.cts.map +1 -0
  190. package/dist/partner/in-memory.d.ts +99 -0
  191. package/dist/partner/in-memory.d.ts.map +1 -0
  192. package/dist/partner/in-memory.js +135 -0
  193. package/dist/partner/in-memory.js.map +1 -0
  194. package/dist/partner/index.cjs +27 -0
  195. package/dist/partner/index.d.cts +32 -0
  196. package/dist/partner/index.d.cts.map +1 -0
  197. package/dist/partner/index.d.ts +32 -0
  198. package/dist/partner/index.d.ts.map +1 -0
  199. package/dist/partner/index.js +9 -0
  200. package/dist/partner/raw.cjs +400 -0
  201. package/dist/partner/raw.cjs.map +1 -0
  202. package/dist/partner/raw.d.cts +220 -0
  203. package/dist/partner/raw.d.cts.map +1 -0
  204. package/dist/partner/raw.d.ts +220 -0
  205. package/dist/partner/raw.d.ts.map +1 -0
  206. package/dist/partner/raw.js +398 -0
  207. package/dist/partner/raw.js.map +1 -0
  208. package/dist/partner/redaction-placeholders.cjs +10 -0
  209. package/dist/partner/redaction-placeholders.cjs.map +1 -0
  210. package/dist/partner/redaction-placeholders.d.cts +5 -0
  211. package/dist/partner/redaction-placeholders.d.cts.map +1 -0
  212. package/dist/partner/redaction-placeholders.d.ts +5 -0
  213. package/dist/partner/redaction-placeholders.d.ts.map +1 -0
  214. package/dist/partner/redaction-placeholders.js +9 -0
  215. package/dist/partner/redaction-placeholders.js.map +1 -0
  216. package/dist/partner/redaction.cjs +292 -0
  217. package/dist/partner/redaction.cjs.map +1 -0
  218. package/dist/partner/redaction.d.cts +158 -0
  219. package/dist/partner/redaction.d.cts.map +1 -0
  220. package/dist/partner/redaction.d.ts +158 -0
  221. package/dist/partner/redaction.d.ts.map +1 -0
  222. package/dist/partner/redaction.js +281 -0
  223. package/dist/partner/redaction.js.map +1 -0
  224. package/dist/raw/encoding.cjs +29 -10
  225. package/dist/raw/encoding.cjs.map +1 -1
  226. package/dist/raw/encoding.d.cts +3 -2
  227. package/dist/raw/encoding.d.cts.map +1 -1
  228. package/dist/raw/encoding.d.ts +3 -2
  229. package/dist/raw/encoding.d.ts.map +1 -1
  230. package/dist/raw/encoding.js +29 -10
  231. package/dist/raw/encoding.js.map +1 -1
  232. package/dist/raw/index.cjs +131 -44
  233. package/dist/raw/index.cjs.map +1 -1
  234. package/dist/raw/index.d.cts +21 -15
  235. package/dist/raw/index.d.cts.map +1 -1
  236. package/dist/raw/index.d.ts +21 -15
  237. package/dist/raw/index.d.ts.map +1 -1
  238. package/dist/raw/index.js +114 -45
  239. package/dist/raw/index.js.map +1 -1
  240. package/dist/raw/url.cjs +111 -0
  241. package/dist/raw/url.cjs.map +1 -0
  242. package/dist/raw/url.d.cts +41 -0
  243. package/dist/raw/url.d.cts.map +1 -0
  244. package/dist/raw/url.d.ts +41 -0
  245. package/dist/raw/url.d.ts.map +1 -0
  246. package/dist/raw/url.js +110 -0
  247. package/dist/raw/url.js.map +1 -0
  248. package/dist/s3/sigv4.cjs +15 -10
  249. package/dist/s3/sigv4.cjs.map +1 -1
  250. package/dist/s3/sigv4.js +15 -10
  251. package/dist/s3/sigv4.js.map +1 -1
  252. package/dist/simulator/index.cjs +1579 -257
  253. package/dist/simulator/index.cjs.map +1 -1
  254. package/dist/simulator/index.d.cts +124 -11
  255. package/dist/simulator/index.d.cts.map +1 -1
  256. package/dist/simulator/index.d.ts +124 -11
  257. package/dist/simulator/index.d.ts.map +1 -1
  258. package/dist/simulator/index.js +1568 -262
  259. package/dist/simulator/index.js.map +1 -1
  260. package/dist/simulator/partner-capabilities.cjs +77 -0
  261. package/dist/simulator/partner-capabilities.cjs.map +1 -0
  262. package/dist/simulator/partner-capabilities.d.cts +53 -0
  263. package/dist/simulator/partner-capabilities.d.cts.map +1 -0
  264. package/dist/simulator/partner-capabilities.d.ts +53 -0
  265. package/dist/simulator/partner-capabilities.d.ts.map +1 -0
  266. package/dist/simulator/partner-capabilities.js +73 -0
  267. package/dist/simulator/partner-capabilities.js.map +1 -0
  268. package/dist/simulator/partner.cjs +713 -0
  269. package/dist/simulator/partner.cjs.map +1 -0
  270. package/dist/simulator/partner.d.cts +186 -0
  271. package/dist/simulator/partner.d.cts.map +1 -0
  272. package/dist/simulator/partner.d.ts +186 -0
  273. package/dist/simulator/partner.d.ts.map +1 -0
  274. package/dist/simulator/partner.js +713 -0
  275. package/dist/simulator/partner.js.map +1 -0
  276. package/dist/simulator/validation.cjs +732 -25
  277. package/dist/simulator/validation.cjs.map +1 -1
  278. package/dist/simulator/validation.d.cts +145 -6
  279. package/dist/simulator/validation.d.cts.map +1 -1
  280. package/dist/simulator/validation.d.ts +145 -6
  281. package/dist/simulator/validation.d.ts.map +1 -1
  282. package/dist/simulator/validation.js +705 -26
  283. package/dist/simulator/validation.js.map +1 -1
  284. package/dist/streams/file-source.cjs +2 -2
  285. package/dist/streams/file-source.cjs.map +1 -1
  286. package/dist/streams/file-source.js +2 -2
  287. package/dist/streams/file-source.js.map +1 -1
  288. package/dist/streams/hash.cjs +246 -13
  289. package/dist/streams/hash.cjs.map +1 -1
  290. package/dist/streams/hash.d.cts +37 -12
  291. package/dist/streams/hash.d.cts.map +1 -1
  292. package/dist/streams/hash.d.ts +37 -12
  293. package/dist/streams/hash.d.ts.map +1 -1
  294. package/dist/streams/hash.js +246 -15
  295. package/dist/streams/hash.js.map +1 -1
  296. package/dist/streams/index.cjs +3 -1
  297. package/dist/streams/index.d.cts +1 -1
  298. package/dist/streams/index.d.cts.map +1 -1
  299. package/dist/streams/index.d.ts +1 -1
  300. package/dist/streams/index.d.ts.map +1 -1
  301. package/dist/streams/index.js +3 -3
  302. package/dist/streams/progress.cjs +63 -4
  303. package/dist/streams/progress.cjs.map +1 -1
  304. package/dist/streams/progress.d.cts +28 -2
  305. package/dist/streams/progress.d.cts.map +1 -1
  306. package/dist/streams/progress.d.ts +28 -2
  307. package/dist/streams/progress.d.ts.map +1 -1
  308. package/dist/streams/progress.js +63 -4
  309. package/dist/streams/progress.js.map +1 -1
  310. package/dist/streams/source.cjs +2 -1
  311. package/dist/streams/source.cjs.map +1 -1
  312. package/dist/streams/source.js +2 -1
  313. package/dist/streams/source.js.map +1 -1
  314. package/dist/sync/b2-sha1-reader.cjs +6 -2
  315. package/dist/sync/b2-sha1-reader.cjs.map +1 -1
  316. package/dist/sync/b2-sha1-reader.d.cts.map +1 -1
  317. package/dist/sync/b2-sha1-reader.d.ts.map +1 -1
  318. package/dist/sync/b2-sha1-reader.js +6 -2
  319. package/dist/sync/b2-sha1-reader.js.map +1 -1
  320. package/dist/sync/download-staging.cjs +156 -43
  321. package/dist/sync/download-staging.cjs.map +1 -1
  322. package/dist/sync/download-staging.d.cts +26 -2
  323. package/dist/sync/download-staging.d.cts.map +1 -1
  324. package/dist/sync/download-staging.d.ts +26 -2
  325. package/dist/sync/download-staging.d.ts.map +1 -1
  326. package/dist/sync/download-staging.js +155 -44
  327. package/dist/sync/download-staging.js.map +1 -1
  328. package/dist/sync/filters.cjs.map +1 -1
  329. package/dist/sync/filters.js.map +1 -1
  330. package/dist/sync/index.d.cts +1 -1
  331. package/dist/sync/index.d.cts.map +1 -1
  332. package/dist/sync/index.d.ts +1 -1
  333. package/dist/sync/index.d.ts.map +1 -1
  334. package/dist/sync/local-file-io.cjs +15 -6
  335. package/dist/sync/local-file-io.cjs.map +1 -1
  336. package/dist/sync/local-file-io.d.cts +3 -0
  337. package/dist/sync/local-file-io.d.cts.map +1 -1
  338. package/dist/sync/local-file-io.d.ts +3 -0
  339. package/dist/sync/local-file-io.d.ts.map +1 -1
  340. package/dist/sync/local-file-io.js +15 -6
  341. package/dist/sync/local-file-io.js.map +1 -1
  342. package/dist/sync/local-sha1.cjs +6 -15
  343. package/dist/sync/local-sha1.cjs.map +1 -1
  344. package/dist/sync/local-sha1.d.cts +0 -8
  345. package/dist/sync/local-sha1.d.cts.map +1 -1
  346. package/dist/sync/local-sha1.d.ts +0 -8
  347. package/dist/sync/local-sha1.d.ts.map +1 -1
  348. package/dist/sync/local-sha1.js +7 -15
  349. package/dist/sync/local-sha1.js.map +1 -1
  350. package/dist/sync/pairing.cjs +1 -0
  351. package/dist/sync/pairing.cjs.map +1 -1
  352. package/dist/sync/pairing.js +1 -0
  353. package/dist/sync/pairing.js.map +1 -1
  354. package/dist/sync/policies/compare.cjs +5 -3
  355. package/dist/sync/policies/compare.cjs.map +1 -1
  356. package/dist/sync/policies/compare.d.cts.map +1 -1
  357. package/dist/sync/policies/compare.d.ts.map +1 -1
  358. package/dist/sync/policies/compare.js +6 -4
  359. package/dist/sync/policies/compare.js.map +1 -1
  360. package/dist/sync/policies/index.cjs +4 -10
  361. package/dist/sync/policies/index.cjs.map +1 -1
  362. package/dist/sync/policies/index.js +4 -10
  363. package/dist/sync/policies/index.js.map +1 -1
  364. package/dist/sync/scanners/b2.cjs +4 -2
  365. package/dist/sync/scanners/b2.cjs.map +1 -1
  366. package/dist/sync/scanners/b2.d.cts.map +1 -1
  367. package/dist/sync/scanners/b2.d.ts.map +1 -1
  368. package/dist/sync/scanners/b2.js +4 -2
  369. package/dist/sync/scanners/b2.js.map +1 -1
  370. package/dist/sync/scanners/local.cjs +150 -33
  371. package/dist/sync/scanners/local.cjs.map +1 -1
  372. package/dist/sync/scanners/local.d.cts +6 -0
  373. package/dist/sync/scanners/local.d.cts.map +1 -1
  374. package/dist/sync/scanners/local.d.ts +6 -0
  375. package/dist/sync/scanners/local.d.ts.map +1 -1
  376. package/dist/sync/scanners/local.js +150 -33
  377. package/dist/sync/scanners/local.js.map +1 -1
  378. package/dist/sync/synchronizer.cjs +79 -31
  379. package/dist/sync/synchronizer.cjs.map +1 -1
  380. package/dist/sync/synchronizer.d.cts +1 -0
  381. package/dist/sync/synchronizer.d.cts.map +1 -1
  382. package/dist/sync/synchronizer.d.ts +1 -0
  383. package/dist/sync/synchronizer.d.ts.map +1 -1
  384. package/dist/sync/synchronizer.js +79 -31
  385. package/dist/sync/synchronizer.js.map +1 -1
  386. package/dist/sync/types.d.cts +19 -3
  387. package/dist/sync/types.d.cts.map +1 -1
  388. package/dist/sync/types.d.ts +19 -3
  389. package/dist/sync/types.d.ts.map +1 -1
  390. package/dist/types/auth.cjs +4 -0
  391. package/dist/types/auth.cjs.map +1 -1
  392. package/dist/types/auth.d.cts +4 -0
  393. package/dist/types/auth.d.cts.map +1 -1
  394. package/dist/types/auth.d.ts +4 -0
  395. package/dist/types/auth.d.ts.map +1 -1
  396. package/dist/types/auth.js +4 -0
  397. package/dist/types/auth.js.map +1 -1
  398. package/dist/types/backup.d.cts +85 -0
  399. package/dist/types/backup.d.cts.map +1 -0
  400. package/dist/types/backup.d.ts +85 -0
  401. package/dist/types/backup.d.ts.map +1 -0
  402. package/dist/types/bucket.cjs +81 -11
  403. package/dist/types/bucket.cjs.map +1 -1
  404. package/dist/types/bucket.d.cts +194 -41
  405. package/dist/types/bucket.d.cts.map +1 -1
  406. package/dist/types/bucket.d.ts +194 -41
  407. package/dist/types/bucket.d.ts.map +1 -1
  408. package/dist/types/bucket.js +67 -12
  409. package/dist/types/bucket.js.map +1 -1
  410. package/dist/types/download.cjs +62 -0
  411. package/dist/types/download.cjs.map +1 -0
  412. package/dist/types/download.d.cts +100 -16
  413. package/dist/types/download.d.cts.map +1 -1
  414. package/dist/types/download.d.ts +100 -16
  415. package/dist/types/download.d.ts.map +1 -1
  416. package/dist/types/download.js +61 -0
  417. package/dist/types/download.js.map +1 -0
  418. package/dist/types/encryption.cjs +76 -229
  419. package/dist/types/encryption.cjs.map +1 -1
  420. package/dist/types/encryption.d.cts +48 -6
  421. package/dist/types/encryption.d.cts.map +1 -1
  422. package/dist/types/encryption.d.ts +48 -6
  423. package/dist/types/encryption.d.ts.map +1 -1
  424. package/dist/types/encryption.js +74 -229
  425. package/dist/types/encryption.js.map +1 -1
  426. package/dist/types/errors.cjs +9 -0
  427. package/dist/types/errors.cjs.map +1 -1
  428. package/dist/types/errors.d.cts +1 -1
  429. package/dist/types/errors.d.cts.map +1 -1
  430. package/dist/types/errors.d.ts +1 -1
  431. package/dist/types/errors.d.ts.map +1 -1
  432. package/dist/types/errors.js +9 -0
  433. package/dist/types/errors.js.map +1 -1
  434. package/dist/types/file.cjs +3 -0
  435. package/dist/types/file.cjs.map +1 -1
  436. package/dist/types/file.d.cts +140 -18
  437. package/dist/types/file.d.cts.map +1 -1
  438. package/dist/types/file.d.ts +140 -18
  439. package/dist/types/file.d.ts.map +1 -1
  440. package/dist/types/file.js +3 -1
  441. package/dist/types/file.js.map +1 -1
  442. package/dist/types/ids.cjs +30 -0
  443. package/dist/types/ids.cjs.map +1 -1
  444. package/dist/types/ids.d.cts +32 -0
  445. package/dist/types/ids.d.cts.map +1 -1
  446. package/dist/types/ids.d.ts +32 -0
  447. package/dist/types/ids.d.ts.map +1 -1
  448. package/dist/types/ids.js +28 -1
  449. package/dist/types/ids.js.map +1 -1
  450. package/dist/types/index.d.cts +16 -12
  451. package/dist/types/index.d.cts.map +1 -1
  452. package/dist/types/index.d.ts +16 -12
  453. package/dist/types/index.d.ts.map +1 -1
  454. package/dist/types/key.d.cts +4 -3
  455. package/dist/types/key.d.cts.map +1 -1
  456. package/dist/types/key.d.ts +4 -3
  457. package/dist/types/key.d.ts.map +1 -1
  458. package/dist/types/lock.cjs.map +1 -1
  459. package/dist/types/lock.d.cts +14 -0
  460. package/dist/types/lock.d.cts.map +1 -1
  461. package/dist/types/lock.d.ts +14 -0
  462. package/dist/types/lock.d.ts.map +1 -1
  463. package/dist/types/lock.js.map +1 -1
  464. package/dist/types/notifications.cjs +31 -1
  465. package/dist/types/notifications.cjs.map +1 -1
  466. package/dist/types/notifications.d.cts +31 -4
  467. package/dist/types/notifications.d.cts.map +1 -1
  468. package/dist/types/notifications.d.ts +31 -4
  469. package/dist/types/notifications.d.ts.map +1 -1
  470. package/dist/types/notifications.js +30 -2
  471. package/dist/types/notifications.js.map +1 -1
  472. package/dist/types/partner.cjs +32 -0
  473. package/dist/types/partner.cjs.map +1 -0
  474. package/dist/types/partner.d.cts +386 -0
  475. package/dist/types/partner.d.cts.map +1 -0
  476. package/dist/types/partner.d.ts +386 -0
  477. package/dist/types/partner.d.ts.map +1 -0
  478. package/dist/types/partner.js +29 -0
  479. package/dist/types/partner.js.map +1 -0
  480. package/dist/types/upload.d.cts +35 -18
  481. package/dist/types/upload.d.cts.map +1 -1
  482. package/dist/types/upload.d.ts +35 -18
  483. package/dist/types/upload.d.ts.map +1 -1
  484. package/dist/upload/abort-scope.cjs +0 -45
  485. package/dist/upload/abort-scope.cjs.map +1 -1
  486. package/dist/upload/abort-scope.d.cts +0 -22
  487. package/dist/upload/abort-scope.d.cts.map +1 -1
  488. package/dist/upload/abort-scope.d.ts +0 -22
  489. package/dist/upload/abort-scope.d.ts.map +1 -1
  490. package/dist/upload/abort-scope.js +1 -44
  491. package/dist/upload/abort-scope.js.map +1 -1
  492. package/dist/upload/finish.cjs +3 -8
  493. package/dist/upload/finish.cjs.map +1 -1
  494. package/dist/upload/finish.d.cts.map +1 -1
  495. package/dist/upload/finish.d.ts.map +1 -1
  496. package/dist/upload/finish.js +1 -6
  497. package/dist/upload/finish.js.map +1 -1
  498. package/dist/upload/large.cjs +15 -8
  499. package/dist/upload/large.cjs.map +1 -1
  500. package/dist/upload/large.d.cts +31 -8
  501. package/dist/upload/large.d.cts.map +1 -1
  502. package/dist/upload/large.d.ts +31 -8
  503. package/dist/upload/large.d.ts.map +1 -1
  504. package/dist/upload/large.js +15 -8
  505. package/dist/upload/large.js.map +1 -1
  506. package/dist/upload/options.cjs.map +1 -1
  507. package/dist/upload/options.d.cts +24 -0
  508. package/dist/upload/options.d.cts.map +1 -1
  509. package/dist/upload/options.d.ts +24 -0
  510. package/dist/upload/options.d.ts.map +1 -1
  511. package/dist/upload/options.js.map +1 -1
  512. package/dist/upload/resume.cjs +6 -4
  513. package/dist/upload/resume.cjs.map +1 -1
  514. package/dist/upload/resume.d.cts +9 -5
  515. package/dist/upload/resume.d.cts.map +1 -1
  516. package/dist/upload/resume.d.ts +9 -5
  517. package/dist/upload/resume.d.ts.map +1 -1
  518. package/dist/upload/resume.js +6 -4
  519. package/dist/upload/resume.js.map +1 -1
  520. package/dist/upload/retry.cjs +25 -13
  521. package/dist/upload/retry.cjs.map +1 -1
  522. package/dist/upload/retry.d.cts.map +1 -1
  523. package/dist/upload/retry.d.ts.map +1 -1
  524. package/dist/upload/retry.js +25 -13
  525. package/dist/upload/retry.js.map +1 -1
  526. package/dist/upload/single.cjs +35 -30
  527. package/dist/upload/single.cjs.map +1 -1
  528. package/dist/upload/single.d.cts +12 -0
  529. package/dist/upload/single.d.cts.map +1 -1
  530. package/dist/upload/single.d.ts +12 -0
  531. package/dist/upload/single.d.ts.map +1 -1
  532. package/dist/upload/single.js +35 -30
  533. package/dist/upload/single.js.map +1 -1
  534. package/dist/upload/stream.cjs +18 -5
  535. package/dist/upload/stream.cjs.map +1 -1
  536. package/dist/upload/stream.d.cts +12 -0
  537. package/dist/upload/stream.d.cts.map +1 -1
  538. package/dist/upload/stream.d.ts +12 -0
  539. package/dist/upload/stream.d.ts.map +1 -1
  540. package/dist/upload/stream.js +15 -2
  541. package/dist/upload/stream.js.map +1 -1
  542. package/dist/util/abort.cjs +114 -0
  543. package/dist/util/abort.cjs.map +1 -0
  544. package/dist/util/abort.d.cts +65 -0
  545. package/dist/util/abort.d.cts.map +1 -0
  546. package/dist/util/abort.d.ts +65 -0
  547. package/dist/util/abort.d.ts.map +1 -0
  548. package/dist/util/abort.js +109 -0
  549. package/dist/util/abort.js.map +1 -0
  550. package/dist/util/defaults.cjs +3 -0
  551. package/dist/util/defaults.cjs.map +1 -1
  552. package/dist/util/defaults.d.cts +2 -0
  553. package/dist/util/defaults.d.cts.map +1 -1
  554. package/dist/util/defaults.d.ts +2 -0
  555. package/dist/util/defaults.d.ts.map +1 -1
  556. package/dist/util/defaults.js +3 -1
  557. package/dist/util/defaults.js.map +1 -1
  558. package/dist/util/md5.cjs +211 -0
  559. package/dist/util/md5.cjs.map +1 -0
  560. package/dist/util/md5.d.cts +43 -0
  561. package/dist/util/md5.d.cts.map +1 -0
  562. package/dist/util/md5.d.ts +43 -0
  563. package/dist/util/md5.d.ts.map +1 -0
  564. package/dist/util/md5.js +209 -0
  565. package/dist/util/md5.js.map +1 -0
  566. package/dist/util/normalize.cjs +5 -5
  567. package/dist/util/normalize.cjs.map +1 -1
  568. package/dist/util/normalize.d.cts +7 -7
  569. package/dist/util/normalize.d.cts.map +1 -1
  570. package/dist/util/normalize.d.ts +7 -7
  571. package/dist/util/normalize.d.ts.map +1 -1
  572. package/dist/util/normalize.js +5 -5
  573. package/dist/util/normalize.js.map +1 -1
  574. package/dist/util/paginator.cjs +7 -1
  575. package/dist/util/paginator.cjs.map +1 -1
  576. package/dist/util/paginator.d.cts +3 -1
  577. package/dist/util/paginator.d.cts.map +1 -1
  578. package/dist/util/paginator.d.ts +3 -1
  579. package/dist/util/paginator.d.ts.map +1 -1
  580. package/dist/util/paginator.js +7 -1
  581. package/dist/util/paginator.js.map +1 -1
  582. package/dist/version.cjs +56 -4
  583. package/dist/version.cjs.map +1 -1
  584. package/dist/version.d.cts +53 -4
  585. package/dist/version.d.cts.map +1 -1
  586. package/dist/version.d.ts +53 -4
  587. package/dist/version.d.ts.map +1 -1
  588. package/dist/version.js +52 -5
  589. package/dist/version.js.map +1 -1
  590. package/package.json +47 -18
@@ -1 +1 @@
1
- {"version":3,"file":"parallel.js","names":[],"sources":["../../src/download/parallel.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport { B2Error, classifyError, NetworkError } from '../errors/index.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from '../http/retry.ts'\nimport type { RawClient } from '../raw/index.ts'\nimport { collectStream } from '../streams/collect.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport type { B2ErrorResponse } from '../types/errors.ts'\nimport type { FileId } from '../types/ids.ts'\nimport { DEFAULT_TRANSFER_CONCURRENCY } from '../util/defaults.ts'\nimport { normalizeSha1 } from '../util/normalize.ts'\nimport { byteRangeHeader, planRanges } from '../util/plan-ranges.ts'\nimport { normalizeVerifiableSha1 } from '../util/sha1.ts'\nimport { utf8Decoder } from '../util/text-codec.ts'\nimport { assertDownloadSha1, assertDownloadSha1HeaderAgreement } from './checksum.ts'\n\n/** Options for downloading a file using concurrent byte-range requests. */\nexport interface ParallelDownloadOptions {\n /** ID of the file to download. */\n readonly fileId: FileId\n /** Total file size in bytes (must be known in advance). */\n readonly totalSize: number\n /** Size of each ranged chunk in bytes. Defaults to 10 MB. */\n readonly rangeSize?: number\n /** Maximum number of chunks fetched in parallel. Defaults to 4. */\n readonly concurrency?: number\n /**\n * Extra retry attempts per range on transient failures. Defaults to 0 because\n * `B2Client` already applies `RetryTransport`; set this only when supplying a\n * raw client that does not already retry transport failures.\n */\n readonly maxRetries?: number\n /** Signal to abort the download. */\n readonly signal?: AbortSignal\n}\n\ninterface RangeDownloadResult {\n readonly data: Uint8Array\n readonly contentSha1: string | null\n}\n\n/**\n * Creates a readable stream that downloads a file using parallel byte-range requests.\n *\n * The file is split into fixed-size ranges fetched in a **sliding\n * window** keyed off the consumer's read pace. The window size is\n * `concurrency * 2`: up to `concurrency` ranges are in flight at once,\n * plus up to `concurrency` completed-but-not-yet-emitted ranges buffered\n * ahead of the read head. New fetches kick off only when the consumer\n * reads a chunk, so a slow downstream pipe (e.g. a saturated network\n * sink or a `pipeTo` consumer that drains slowly) backpressures into\n * the SDK and bounds peak memory to `(concurrency * 2) * rangeSize`.\n *\n * The previous eager implementation scheduled every range into\n * `Promise.all` up front; a slow head-of-line range could hold the\n * entire file in memory while later ranges finished and waited.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - Parallel download parameters (file ID, size, concurrency).\n *\n * @returns A `ReadableStream` that yields file bytes in order.\n */\nexport function createParallelDownloadStream(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: ParallelDownloadOptions,\n): ReadableStream<Uint8Array> {\n const rangeSize = options.rangeSize ?? 10 * 1024 * 1024\n const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY\n const totalSize = options.totalSize\n // The high-level B2Client already wraps the raw transport in RetryTransport.\n // Keep the parallel-download outer retry disabled by default so each range\n // has one retry budget unless callers explicitly opt into an extra raw-client\n // retry layer.\n const retryOptions = {\n ...DEFAULT_RETRY_OPTIONS,\n maxRetries: options.maxRetries ?? 0,\n }\n const abort = options.signal\n\n const ranges = planRanges(totalSize, rangeSize)\n\n // `inflight` holds currently-fetching range promises; `buffer` holds\n // completed ranges waiting for their slot in the emit order. Total\n // scheduled-but-not-emitted = inflight.size + buffer.size is capped\n // at `windowSize`, so peak memory is bounded regardless of any\n // single range's latency.\n const windowSize = concurrency * 2\n const inflight = new Map<number, Promise<void>>()\n const buffer = new Map<number, RangeDownloadResult>()\n let assembledSha1: IncrementalSha1 | null = null\n let nextToSchedule = 0\n let nextToEmit = 0\n let expectedSha1: string | null | undefined\n let firstError: unknown = null\n\n function scheduleNext(): void {\n while (\n firstError === null &&\n // Honour abort here so a completed range that triggers a top-up\n // doesn't queue one final fetch after the caller aborted. Without\n // this gate, one extra range request fires post-abort before the\n // `pull()` loop notices.\n abort?.aborted !== true &&\n nextToSchedule < ranges.length &&\n inflight.size + buffer.size < windowSize\n ) {\n const range = ranges[nextToSchedule]\n if (range === undefined) break\n const idx = nextToSchedule\n nextToSchedule++\n const task = (async () => {\n try {\n const result = await fetchRangeWithRetry(\n raw,\n accountInfo,\n options.fileId,\n range.start,\n range.end,\n totalSize,\n retryOptions,\n abort,\n )\n buffer.set(idx, result)\n } catch (err) {\n if (firstError === null) firstError = err\n } finally {\n inflight.delete(idx)\n }\n })()\n inflight.set(idx, task)\n }\n }\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n // Pre-warm: kick off the initial window so the first `pull` has\n // something to await. An already-aborted signal surfaces as a\n // stream error rather than a synchronous throw, matching the\n // contract callers had with the previous eager implementation.\n try {\n abort?.throwIfAborted()\n scheduleNext()\n } catch (err) {\n controller.error(err)\n }\n },\n async pull(controller) {\n try {\n // Wait until the next in-order chunk is available.\n while (!buffer.has(nextToEmit)) {\n abort?.throwIfAborted()\n if (firstError !== null) throw firstError\n // Zero-byte downloads have no planned ranges and close here. For\n // non-empty downloads, this guard prevents a future refactor from\n // stalling the stream if it leaves both maps empty mid-stream.\n if (inflight.size === 0) {\n controller.close()\n return\n }\n await Promise.race(inflight.values())\n }\n\n const result = buffer.get(nextToEmit)\n if (result !== undefined) {\n buffer.delete(nextToEmit)\n nextToEmit++\n const rangeSha1 = normalizeVerifiableSha1(result.contentSha1)\n if (expectedSha1 === undefined) {\n expectedSha1 = rangeSha1\n } else {\n // B2 range responses should agree on the same whole-file SHA-1;\n // any value or presence change makes verification untrustworthy.\n assertDownloadSha1HeaderAgreement(expectedSha1, rangeSha1)\n }\n if (expectedSha1 !== null) {\n assembledSha1 ??= new IncrementalSha1()\n await assembledSha1.update(result.data)\n }\n controller.enqueue(result.data)\n }\n\n // Top up the window now that we freed a slot by emitting.\n scheduleNext()\n\n if (\n nextToEmit >= ranges.length &&\n buffer.size === 0 &&\n inflight.size === 0 &&\n firstError === null\n ) {\n if (expectedSha1 !== undefined && expectedSha1 !== null && assembledSha1 !== null) {\n assertDownloadSha1(expectedSha1, await assembledSha1.digest())\n }\n controller.close()\n }\n } catch (err) {\n controller.error(err)\n }\n },\n cancel() {\n // Abort propagation handles in-flight requests; just drop buffered\n // data so it can be GC'd promptly.\n buffer.clear()\n },\n })\n}\n\n/**\n * Fetches a single byte range with bounded retry on transient failures.\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param fileId - ID of the file being downloaded.\n * @param start - Inclusive byte offset where the range begins.\n * @param end - Inclusive byte offset where the range ends.\n * @param totalSize - Expected complete file size.\n * @param retryOptions - Retry settings controlling attempts and backoff.\n * @param signal - Optional abort signal that cancels the range and any pending retry.\n *\n * @returns The range's bytes, or throws after exhausting all retry attempts.\n */\nasync function fetchRangeWithRetry(\n raw: RawClient,\n accountInfo: AccountInfo,\n fileId: FileId,\n start: number,\n end: number,\n totalSize: number,\n retryOptions: RetryOptions,\n signal: AbortSignal | undefined,\n): Promise<RangeDownloadResult> {\n let lastError: unknown\n for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {\n if (attempt > 0) {\n const retryAfter =\n lastError instanceof B2Error && lastError.retryAfter !== undefined\n ? lastError.retryAfter\n : undefined\n const delay = computeBackoff(attempt - 1, retryOptions, retryAfter)\n await sleep(delay, signal)\n }\n try {\n signal?.throwIfAborted()\n const resp = await raw.downloadFileById(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n fileId,\n {\n range: byteRangeHeader(start, end),\n ...(signal !== undefined ? { signal } : {}),\n },\n )\n if (resp.status < 200 || resp.status >= 300) {\n throw await classifyDownloadResponseError(resp)\n }\n if (!resp.body) throw new Error('Download chunk has no body')\n const data = await collectStream(resp.body)\n validateRangeResponse(resp, start, end, totalSize, data.byteLength)\n return {\n data,\n contentSha1: normalizeSha1(resp.headers.get('X-Bz-Content-Sha1')),\n }\n } catch (err) {\n lastError = err\n // Honour AbortSignal cancellation: don't retry past an abort.\n if (signal?.aborted) throw err\n if (err instanceof DOMException && err.name === 'AbortError') throw err\n if (!isRetryableRangeError(err) || attempt === retryOptions.maxRetries) {\n throw err\n }\n }\n }\n throw lastError instanceof Error ? lastError : new Error('Range download failed after retries')\n}\n\nclass RangeValidationError extends Error {\n readonly retryable = false\n\n constructor(message: string) {\n super(message)\n this.name = 'RangeValidationError'\n }\n}\n\nfunction validateRangeResponse(\n response: { headers: Headers; status: number },\n start: number,\n end: number,\n totalSize: number,\n byteLength: number,\n): void {\n const expectedLength = end - start + 1\n if (response.status !== 206) {\n throw new RangeValidationError(\n `Expected HTTP 206 Partial Content for range ${start}-${end}, got ${response.status}`,\n )\n }\n\n const contentRange = response.headers.get('Content-Range')\n if (contentRange === null) {\n throw new RangeValidationError(`Missing Content-Range for range ${start}-${end}`)\n }\n\n const match = contentRange.match(/^bytes (\\d+)-(\\d+)\\/(\\d+|\\*)$/)\n if (match === null) {\n throw new RangeValidationError(\n `Invalid Content-Range for range ${start}-${end}: ${contentRange}`,\n )\n }\n\n const actualStart = Number.parseInt(match[1] ?? '', 10)\n const actualEnd = Number.parseInt(match[2] ?? '', 10)\n const actualTotal = match[3] ?? ''\n if (actualStart !== start || actualEnd !== end) {\n throw new RangeValidationError(\n `Content-Range ${contentRange} does not match requested range ${start}-${end}`,\n )\n }\n\n if (actualTotal === '*') {\n throw new RangeValidationError(`Content-Range ${contentRange} does not include total size`)\n }\n\n const parsedTotal = Number.parseInt(actualTotal, 10)\n if (parsedTotal !== totalSize) {\n throw new RangeValidationError(\n `Content-Range ${contentRange} does not match expected total size ${totalSize}`,\n )\n }\n\n if (byteLength !== expectedLength) {\n throw new RangeValidationError(\n `Expected ${expectedLength} bytes for range ${start}-${end}, got ${byteLength}`,\n )\n }\n}\n\nasync function classifyDownloadResponseError(response: {\n headers: Headers\n status: number\n body: ReadableStream<Uint8Array> | null\n}): Promise<B2Error> {\n let errorBody: B2ErrorResponse = {\n status: response.status,\n code: 'internal_error',\n message: `HTTP ${response.status}`,\n }\n\n if (response.body !== null) {\n const bytes = await collectStream(response.body)\n try {\n const parsed = JSON.parse(utf8Decoder.decode(bytes)) as Partial<B2ErrorResponse>\n errorBody = {\n status: response.status,\n code: parsed.code ?? 'internal_error',\n message: parsed.message ?? `HTTP ${response.status}`,\n }\n } catch {\n // Keep the synthetic errorBody above when the response body is not JSON.\n }\n }\n\n const retryAfterHeader = response.headers.get('Retry-After')\n const retryAfter = retryAfterHeader !== null ? Number.parseInt(retryAfterHeader, 10) : undefined\n const requestId = response.headers.get('X-Bz-Request-Id') ?? undefined\n\n return classifyError(errorBody, {\n ...(retryAfter !== undefined ? { retryAfter } : {}),\n ...(requestId !== undefined ? { requestId } : {}),\n })\n}\n\nfunction isRetryableRangeError(err: unknown): boolean {\n if (err instanceof B2Error || err instanceof NetworkError) return err.retryable\n if (hasRetryableFlag(err)) return err.retryable\n // Bare FetchTransport surfaces network failures as TypeError. Validation\n // failures use RangeValidationError above, so they never land here.\n return err instanceof TypeError\n}\n\nfunction hasRetryableFlag(err: unknown): err is { retryable: boolean } {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'retryable' in err &&\n typeof (err as { retryable?: unknown }).retryable === 'boolean'\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"parallel.js","names":[],"sources":["../../src/download/parallel.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport { B2Error, classifyError, NetworkError } from '../errors/index.ts'\nimport { computeBackoff, DEFAULT_RETRY_OPTIONS, type RetryOptions, sleep } from '../http/retry.ts'\nimport type { RawClient, SseCDownloadKey } from '../raw/index.ts'\nimport { collectStream } from '../streams/collect.ts'\nimport { IncrementalSha1 } from '../streams/hash.ts'\nimport { redactSseCKeyMaterial } from '../types/encryption.ts'\nimport type { B2ErrorResponse } from '../types/errors.ts'\nimport type { FileId } from '../types/ids.ts'\nimport { DEFAULT_DOWNLOAD_RANGE_SIZE, DEFAULT_TRANSFER_CONCURRENCY } from '../util/defaults.ts'\nimport { normalizeSha1 } from '../util/normalize.ts'\nimport { byteRangeHeader, planRanges } from '../util/plan-ranges.ts'\nimport { normalizeVerifiableSha1 } from '../util/sha1.ts'\nimport { utf8Decoder } from '../util/text-codec.ts'\nimport { assertDownloadSha1, assertDownloadSha1HeaderAgreement } from './checksum.ts'\n\n/** Options for downloading a file using concurrent byte-range requests. */\nexport interface ParallelDownloadOptions {\n /** ID of the file to download. */\n readonly fileId: FileId\n /** Total file size in bytes (must be known in advance). */\n readonly totalSize: number\n /** Size of each ranged chunk in bytes. Defaults to 10 MB. */\n readonly rangeSize?: number\n /** Maximum number of chunks fetched in parallel. Defaults to 4. */\n readonly concurrency?: number\n /**\n * SSE-C decryption parameters, required if the file was uploaded with SSE-C.\n * Internal diagnostics redact the copied options object, but the key is still\n * sent in plaintext SSE-C HTTP headers. Custom transports should not log\n * request headers that may contain customer-provided keys.\n */\n readonly serverSideEncryption?: SseCDownloadKey\n /**\n * Extra retry attempts per range on transient failures. Defaults to 0 because\n * `B2Client` already applies `RetryTransport`; set this only when supplying a\n * raw client that does not already retry transport failures.\n */\n readonly maxRetries?: number\n /** Signal to abort the download. */\n readonly signal?: AbortSignal\n}\n\ninterface RangeDownloadResult {\n readonly data: Uint8Array\n readonly contentSha1: string | null\n}\n\ninterface FetchRangeWithRetryParams {\n readonly raw: RawClient\n readonly accountInfo: AccountInfo\n readonly fileId: FileId\n readonly start: number\n readonly end: number\n readonly totalSize: number\n readonly serverSideEncryption: SseCDownloadKey | undefined\n readonly retryOptions: RetryOptions\n readonly signal: AbortSignal | undefined\n}\n\n/**\n * Creates a readable stream that downloads a file using parallel byte-range requests.\n *\n * The file is split into fixed-size ranges fetched in a **sliding\n * window** keyed off the consumer's read pace. The window size is\n * `concurrency * 2`: up to `concurrency` ranges are in flight at once,\n * plus up to `concurrency` completed-but-not-yet-emitted ranges buffered\n * ahead of the read head. New fetches kick off only when the consumer\n * reads a chunk, so a slow downstream pipe (e.g. a saturated network\n * sink or a `pipeTo` consumer that drains slowly) backpressures into\n * the SDK and bounds peak memory to `(concurrency * 2) * rangeSize`.\n *\n * The previous eager implementation scheduled every range into\n * `Promise.all` up front; a slow head-of-line range could hold the\n * entire file in memory while later ranges finished and waited.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - Parallel download parameters (file ID, size, concurrency).\n *\n * @returns A `ReadableStream` that yields file bytes in order.\n */\nexport function createParallelDownloadStream(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: ParallelDownloadOptions,\n): ReadableStream<Uint8Array> {\n const rangeSize = options.rangeSize ?? DEFAULT_DOWNLOAD_RANGE_SIZE\n const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY\n const totalSize = options.totalSize\n const serverSideEncryption =\n options.serverSideEncryption !== undefined\n ? redactSseCKeyMaterial(options.serverSideEncryption, { label: 'SseCDownloadKey' })\n : undefined\n // The high-level B2Client already wraps the raw transport in RetryTransport.\n // Keep the parallel-download outer retry disabled by default so each range\n // has one retry budget unless callers explicitly opt into an extra raw-client\n // retry layer.\n const retryOptions = {\n ...DEFAULT_RETRY_OPTIONS,\n maxRetries: options.maxRetries ?? 0,\n }\n const internalAbort = new AbortController()\n const abort = internalAbort.signal\n let removeCallerAbortListener: (() => void) | undefined\n if (options.signal !== undefined) {\n if (options.signal.aborted) {\n internalAbort.abort(options.signal.reason)\n } else {\n const callerSignal = options.signal\n const abortFromCaller = () => internalAbort.abort(callerSignal.reason)\n callerSignal.addEventListener('abort', abortFromCaller, { once: true })\n removeCallerAbortListener = () => callerSignal.removeEventListener('abort', abortFromCaller)\n }\n }\n\n const ranges = planRanges(totalSize, rangeSize)\n\n // `inflight` holds currently-fetching range promises; `buffer` holds\n // completed ranges waiting for their slot in the emit order. Total\n // scheduled-but-not-emitted = inflight.size + buffer.size is capped\n // at `windowSize`, so peak memory is bounded regardless of any\n // single range's latency.\n const windowSize = concurrency * 2\n const inflight = new Map<number, Promise<void>>()\n const buffer = new Map<number, RangeDownloadResult>()\n let assembledSha1: IncrementalSha1 | null = null\n let nextToSchedule = 0\n let nextToEmit = 0\n let expectedSha1: string | null | undefined\n let firstError: unknown = null\n\n function abortInflight(reason?: unknown): void {\n if (!abort.aborted) internalAbort.abort(reason)\n }\n\n function cleanupCallerAbortListener(): void {\n removeCallerAbortListener?.()\n removeCallerAbortListener = undefined\n }\n\n function scheduleNext(): void {\n while (\n firstError === null &&\n // Honour abort here so a completed range that triggers a top-up\n // doesn't queue one final fetch after the caller aborted. Without\n // this gate, one extra range request fires post-abort before the\n // `pull()` loop notices.\n abort?.aborted !== true &&\n nextToSchedule < ranges.length &&\n inflight.size + buffer.size < windowSize\n ) {\n const range = ranges[nextToSchedule]\n if (range === undefined) break\n const idx = nextToSchedule\n nextToSchedule++\n const task = (async () => {\n try {\n const result = await fetchRangeWithRetry({\n raw,\n accountInfo,\n fileId: options.fileId,\n start: range.start,\n end: range.end,\n totalSize,\n serverSideEncryption,\n retryOptions,\n signal: abort,\n })\n buffer.set(idx, result)\n } catch (err) {\n if (firstError === null) {\n firstError = err\n abortInflight(err)\n }\n } finally {\n inflight.delete(idx)\n }\n })()\n inflight.set(idx, task)\n }\n }\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n // Pre-warm: kick off the initial window so the first `pull` has\n // something to await. An already-aborted signal surfaces as a\n // stream error rather than a synchronous throw, matching the\n // contract callers had with the previous eager implementation.\n try {\n abort?.throwIfAborted()\n scheduleNext()\n } catch (err) {\n cleanupCallerAbortListener()\n controller.error(err)\n }\n },\n async pull(controller) {\n try {\n // Wait until the next in-order chunk is available.\n while (!buffer.has(nextToEmit)) {\n abort?.throwIfAborted()\n if (firstError !== null) throw firstError\n // Zero-byte downloads have no planned ranges and close here. For\n // non-empty downloads, this guard prevents a future refactor from\n // stalling the stream if it leaves both maps empty mid-stream.\n if (inflight.size === 0) {\n cleanupCallerAbortListener()\n controller.close()\n return\n }\n await Promise.race(inflight.values())\n }\n\n const result = buffer.get(nextToEmit)\n if (result !== undefined) {\n buffer.delete(nextToEmit)\n nextToEmit++\n const rangeSha1 = normalizeVerifiableSha1(result.contentSha1)\n if (expectedSha1 === undefined) {\n expectedSha1 = rangeSha1\n } else {\n // B2 range responses should agree on the same whole-file SHA-1;\n // any value or presence change makes verification untrustworthy.\n assertDownloadSha1HeaderAgreement(expectedSha1, rangeSha1)\n }\n if (expectedSha1 !== null) {\n assembledSha1 ??= new IncrementalSha1()\n await assembledSha1.update(result.data)\n }\n controller.enqueue(result.data)\n }\n\n // Top up the window now that we freed a slot by emitting.\n scheduleNext()\n\n if (\n nextToEmit >= ranges.length &&\n buffer.size === 0 &&\n inflight.size === 0 &&\n firstError === null\n ) {\n if (expectedSha1 !== undefined && expectedSha1 !== null && assembledSha1 !== null) {\n assertDownloadSha1(expectedSha1, await assembledSha1.digest())\n }\n cleanupCallerAbortListener()\n controller.close()\n }\n } catch (err) {\n abortInflight(err)\n cleanupCallerAbortListener()\n controller.error(err)\n }\n },\n cancel(reason) {\n abortInflight(reason)\n cleanupCallerAbortListener()\n // Abort propagation handles in-flight requests; just drop buffered\n // data so it can be GC'd promptly.\n buffer.clear()\n },\n })\n}\n\n/**\n * Fetches a single byte range with bounded retry on transient failures.\n * @param params - Range request parameters, retry settings, and cancellation.\n *\n * @returns The range's bytes, or throws after exhausting all retry attempts.\n */\nasync function fetchRangeWithRetry(\n params: FetchRangeWithRetryParams,\n): Promise<RangeDownloadResult> {\n const {\n raw,\n accountInfo,\n fileId,\n start,\n end,\n totalSize,\n serverSideEncryption,\n retryOptions,\n signal,\n } = params\n let lastError: unknown\n for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {\n if (attempt > 0) {\n const retryAfter =\n lastError instanceof B2Error && lastError.retryAfter !== undefined\n ? lastError.retryAfter\n : undefined\n const delay = computeBackoff(attempt - 1, retryOptions, retryAfter)\n await sleep(delay, signal)\n }\n try {\n signal?.throwIfAborted()\n const resp = await raw.downloadFileById(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n fileId,\n {\n range: byteRangeHeader(start, end),\n ...(serverSideEncryption !== undefined ? { serverSideEncryption } : {}),\n ...(signal !== undefined ? { signal } : {}),\n },\n )\n if (resp.status < 200 || resp.status >= 300) {\n throw await classifyDownloadResponseError(resp)\n }\n if (!resp.body) throw new Error('Download chunk has no body')\n const data = await collectStream(resp.body)\n validateRangeResponse(resp, start, end, totalSize, data.byteLength)\n return {\n data,\n contentSha1: normalizeSha1(resp.headers.get('X-Bz-Content-Sha1')),\n }\n } catch (err) {\n lastError = err\n // Honour AbortSignal cancellation: don't retry past an abort.\n if (signal?.aborted) throw err\n if (err instanceof DOMException && err.name === 'AbortError') throw err\n if (!isRetryableRangeError(err) || attempt === retryOptions.maxRetries) {\n throw err\n }\n }\n }\n throw lastError instanceof Error ? lastError : new Error('Range download failed after retries')\n}\n\nclass RangeValidationError extends Error {\n readonly retryable = false\n\n constructor(message: string) {\n super(message)\n this.name = 'RangeValidationError'\n }\n}\n\nfunction validateRangeResponse(\n response: { headers: Headers; status: number },\n start: number,\n end: number,\n totalSize: number,\n byteLength: number,\n): void {\n const expectedLength = end - start + 1\n if (response.status !== 206) {\n throw new RangeValidationError(\n `Expected HTTP 206 Partial Content for range ${start}-${end}, got ${response.status}`,\n )\n }\n\n const contentRange = response.headers.get('Content-Range')\n if (contentRange === null) {\n throw new RangeValidationError(`Missing Content-Range for range ${start}-${end}`)\n }\n\n const match = contentRange.match(/^bytes (\\d+)-(\\d+)\\/(\\d+|\\*)$/)\n if (match === null) {\n throw new RangeValidationError(\n `Invalid Content-Range for range ${start}-${end}: ${contentRange}`,\n )\n }\n\n const actualStart = Number.parseInt(match[1] ?? '', 10)\n const actualEnd = Number.parseInt(match[2] ?? '', 10)\n const actualTotal = match[3] ?? ''\n if (actualStart !== start || actualEnd !== end) {\n throw new RangeValidationError(\n `Content-Range ${contentRange} does not match requested range ${start}-${end}`,\n )\n }\n\n if (actualTotal === '*') {\n throw new RangeValidationError(`Content-Range ${contentRange} does not include total size`)\n }\n\n const parsedTotal = Number.parseInt(actualTotal, 10)\n if (parsedTotal !== totalSize) {\n throw new RangeValidationError(\n `Content-Range ${contentRange} does not match expected total size ${totalSize}`,\n )\n }\n\n if (byteLength !== expectedLength) {\n throw new RangeValidationError(\n `Expected ${expectedLength} bytes for range ${start}-${end}, got ${byteLength}`,\n )\n }\n}\n\nasync function classifyDownloadResponseError(response: {\n headers: Headers\n status: number\n body: ReadableStream<Uint8Array> | null\n}): Promise<B2Error> {\n let errorBody: B2ErrorResponse = {\n status: response.status,\n code: 'internal_error',\n message: `HTTP ${response.status}`,\n }\n\n if (response.body !== null) {\n const bytes = await collectStream(response.body)\n try {\n const parsed = JSON.parse(utf8Decoder.decode(bytes)) as Partial<B2ErrorResponse>\n errorBody = {\n status: response.status,\n code: parsed.code ?? 'internal_error',\n message: parsed.message ?? `HTTP ${response.status}`,\n }\n } catch {\n // Keep the synthetic errorBody above when the response body is not JSON.\n }\n }\n\n const retryAfterHeader = response.headers.get('Retry-After')\n const retryAfter = retryAfterHeader !== null ? Number.parseInt(retryAfterHeader, 10) : undefined\n const requestId = response.headers.get('X-Bz-Request-Id') ?? undefined\n\n return classifyError(errorBody, {\n ...(retryAfter !== undefined ? { retryAfter } : {}),\n ...(requestId !== undefined ? { requestId } : {}),\n })\n}\n\nfunction isRetryableRangeError(err: unknown): boolean {\n if (err instanceof B2Error || err instanceof NetworkError) return err.retryable\n if (hasRetryableFlag(err)) return err.retryable\n // Bare FetchTransport surfaces network failures as TypeError. Validation\n // failures use RangeValidationError above, so they never land here.\n return err instanceof TypeError\n}\n\nfunction hasRetryableFlag(err: unknown): err is { retryable: boolean } {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'retryable' in err &&\n typeof (err as { retryable?: unknown }).retryable === 'boolean'\n )\n}\n"],"mappings":"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"}
@@ -2,6 +2,9 @@ const require_ids = require("../types/ids.cjs");
2
2
  const require_best_effort = require("../util/best-effort.cjs");
3
3
  const require_encoding = require("../raw/encoding.cjs");
4
4
  const require_progress = require("../streams/progress.cjs");
5
+ const require_download = require("../types/download.cjs");
6
+ const require_encryption = require("../types/encryption.cjs");
7
+ const require_lock = require("../types/lock.cjs");
5
8
  const require_normalize = require("../util/normalize.cjs");
6
9
  const require_checksum = require("./checksum.cjs");
7
10
  //#region src/download/single.ts
@@ -151,12 +154,11 @@ function emptyStream() {
151
154
  * @returns A stream wrapped for checksum verification and progress reporting.
152
155
  */
153
156
  function prepareDownloadBody(body, headers, options) {
154
- return instrumentProgress(options.method !== "HEAD" && options.range === void 0 ? require_checksum.verifyDownloadStream(body, headers.contentSha1) : body, headers.contentLength, options.onProgress);
157
+ return instrumentProgress(options.method !== "HEAD" && options.range === void 0 ? require_checksum.verifyDownloadStream(body, headers.contentSha1) : body, headers.contentLength, options.onProgress, options.progressIntervalMillis);
155
158
  }
156
159
  /**
157
- * Wraps a body stream with a `TransformStream` that increments a
158
- * {@link ProgressTracker} for each chunk and reports `partsCompleted: 1`
159
- * when the stream finishes.
160
+ * Wraps a body stream so the SDK increments a {@link ProgressTracker} for
161
+ * each chunk and reports `partsCompleted: 1` when the stream finishes.
160
162
  *
161
163
  * When `listener` is undefined the function short-circuits and returns
162
164
  * the original stream, so unobserved downloads pay no overhead.
@@ -164,22 +166,48 @@ function prepareDownloadBody(body, headers, options) {
164
166
  * @param body - The download response body to wrap.
165
167
  * @param totalBytes - Expected total bytes (response `Content-Length`).
166
168
  * @param listener - Caller-supplied progress callback, or undefined.
169
+ * @param progressIntervalMillis - Optional byte-progress throttle interval.
167
170
  *
168
171
  * @returns A stream that emits the same bytes and reports progress.
169
172
  */
170
- function instrumentProgress(body, totalBytes, listener) {
173
+ function instrumentProgress(body, totalBytes, listener, progressIntervalMillis) {
171
174
  if (listener === void 0) return body;
172
- const tracker = new require_progress.ProgressTracker(listener, totalBytes, 1);
173
- const transform = new TransformStream({
174
- transform(chunk, controller) {
175
- tracker.addBytes(chunk.byteLength);
176
- controller.enqueue(chunk);
175
+ const tracker = new require_progress.ProgressTracker(listener, totalBytes, 1, { ...progressIntervalMillis !== void 0 ? { minIntervalMs: progressIntervalMillis } : {} });
176
+ const reader = body.getReader();
177
+ let released = false;
178
+ function releaseReader() {
179
+ if (released) return;
180
+ released = true;
181
+ reader.releaseLock();
182
+ }
183
+ return new ReadableStream({
184
+ async pull(controller) {
185
+ try {
186
+ const { done, value } = await reader.read();
187
+ if (done) {
188
+ tracker.completePart();
189
+ tracker.dispose();
190
+ releaseReader();
191
+ controller.close();
192
+ return;
193
+ }
194
+ tracker.addBytes(value.byteLength);
195
+ controller.enqueue(value);
196
+ } catch (err) {
197
+ tracker.dispose();
198
+ releaseReader();
199
+ throw err;
200
+ }
177
201
  },
178
- flush() {
179
- tracker.completePart();
202
+ async cancel(reason) {
203
+ tracker.dispose();
204
+ try {
205
+ await reader.cancel(reason);
206
+ } finally {
207
+ releaseReader();
208
+ }
180
209
  }
181
210
  });
182
- return body.pipeThrough(transform);
183
211
  }
184
212
  /**
185
213
  * Extracts B2-specific download headers into a structured object.
@@ -188,16 +216,148 @@ function instrumentProgress(body, totalBytes, listener) {
188
216
  * @returns The parsed download metadata.
189
217
  */
190
218
  function extractDownloadHeaders(headers) {
219
+ const headerParseIssues = [];
191
220
  const fileInfo = require_encoding.parseFileInfoHeaders(headers);
221
+ const clientUnauthorizedToRead = parseClientUnauthorizedToRead(headers, headerParseIssues);
222
+ const contentDisposition = optionalHeader(headers, require_download.DownloadHeaderName.ContentDisposition);
223
+ const contentLanguage = optionalHeader(headers, require_download.DownloadHeaderName.ContentLanguage);
224
+ const contentEncoding = optionalHeader(headers, require_download.DownloadHeaderName.ContentEncoding);
225
+ const cacheControl = optionalHeader(headers, require_download.DownloadHeaderName.CacheControl);
226
+ const expires = optionalHeader(headers, require_download.DownloadHeaderName.Expires);
227
+ const contentRange = optionalHeader(headers, require_download.DownloadHeaderName.ContentRange);
228
+ const serverSideEncryption = parseDownloadServerSideEncryption(headers, headerParseIssues);
229
+ const fileRetention = parseDownloadFileRetention(headers, clientUnauthorizedToRead, headerParseIssues);
230
+ const legalHold = parseDownloadLegalHold(headers, clientUnauthorizedToRead, headerParseIssues);
192
231
  return {
193
- contentType: headers.get("Content-Type") ?? "application/octet-stream",
194
- contentLength: Number.parseInt(headers.get("Content-Length") ?? "0", 10),
195
- contentSha1: require_normalize.normalizeSha1(headers.get("X-Bz-Content-Sha1")),
196
- fileId: require_ids.fileId(headers.get("X-Bz-File-Id") ?? ""),
197
- fileName: decodeURIComponent(headers.get("X-Bz-File-Name") ?? ""),
232
+ contentType: headers.get(require_download.DownloadHeaderName.ContentType) ?? "application/octet-stream",
233
+ contentLength: Number.parseInt(headers.get(require_download.DownloadHeaderName.ContentLength) ?? "0", 10),
234
+ ...contentDisposition !== void 0 ? { contentDisposition } : {},
235
+ ...contentLanguage !== void 0 ? { contentLanguage } : {},
236
+ ...contentEncoding !== void 0 ? { contentEncoding } : {},
237
+ ...cacheControl !== void 0 ? { cacheControl } : {},
238
+ ...expires !== void 0 ? { expires } : {},
239
+ ...contentRange !== void 0 ? { contentRange } : {},
240
+ contentSha1: require_normalize.normalizeSha1(headers.get(require_download.DownloadHeaderName.ContentSha1)),
241
+ fileId: require_ids.fileId(headers.get(require_download.DownloadHeaderName.FileId) ?? ""),
242
+ fileName: decodeURIComponent(headers.get(require_download.DownloadHeaderName.FileName) ?? ""),
198
243
  fileInfo,
199
- uploadTimestamp: Number.parseInt(headers.get("X-Bz-Upload-Timestamp") ?? "0", 10)
244
+ uploadTimestamp: Number.parseInt(headers.get(require_download.DownloadHeaderName.UploadTimestamp) ?? "0", 10),
245
+ ...serverSideEncryption !== void 0 ? { serverSideEncryption } : {},
246
+ ...fileRetention !== void 0 ? { fileRetention } : {},
247
+ ...legalHold !== void 0 ? { legalHold } : {},
248
+ ...clientUnauthorizedToRead !== void 0 ? { clientUnauthorizedToRead } : {},
249
+ ...headerParseIssues.length > 0 ? { headerParseIssues } : {}
250
+ };
251
+ }
252
+ function optionalHeader(headers, name) {
253
+ return headers.get(name) ?? void 0;
254
+ }
255
+ function parseDownloadServerSideEncryption(headers, headerParseIssues) {
256
+ const managedAlgorithm = optionalHeader(headers, require_download.DownloadHeaderName.ServerSideEncryption);
257
+ if (managedAlgorithm !== void 0) {
258
+ if (managedAlgorithm !== require_encryption.EncryptionAlgorithm.Aes256) {
259
+ headerParseIssues.push({
260
+ headerName: require_download.DownloadHeaderName.ServerSideEncryption,
261
+ value: managedAlgorithm
262
+ });
263
+ return;
264
+ }
265
+ return {
266
+ mode: require_encryption.EncryptionMode.SseB2,
267
+ algorithm: managedAlgorithm
268
+ };
269
+ }
270
+ const customerAlgorithm = optionalHeader(headers, require_download.DownloadHeaderName.ServerSideEncryptionCustomerAlgorithm);
271
+ const customerKeyMd5 = optionalHeader(headers, require_download.DownloadHeaderName.ServerSideEncryptionCustomerKeyMd5);
272
+ if (customerAlgorithm === void 0 || customerKeyMd5 === void 0) return void 0;
273
+ if (customerAlgorithm !== require_encryption.EncryptionAlgorithm.Aes256) {
274
+ headerParseIssues.push({
275
+ headerName: require_download.DownloadHeaderName.ServerSideEncryptionCustomerAlgorithm,
276
+ value: customerAlgorithm
277
+ });
278
+ return;
279
+ }
280
+ return {
281
+ mode: require_encryption.EncryptionMode.SseC,
282
+ algorithm: customerAlgorithm,
283
+ customerKeyMd5
284
+ };
285
+ }
286
+ function parseDownloadFileRetention(headers, clientUnauthorizedToRead, headerParseIssues) {
287
+ if (clientUnauthorizedToRead?.includes(require_download.DownloadClientUnauthorizedToReadMarker.FileRetentionMode) === true || clientUnauthorizedToRead?.includes(require_download.DownloadClientUnauthorizedToReadMarker.FileRetentionRetainUntilTimestamp) === true) return {
288
+ isClientAuthorizedToRead: false,
289
+ value: null
200
290
  };
291
+ const rawMode = optionalHeader(headers, require_download.DownloadHeaderName.FileRetentionMode);
292
+ const rawRetainUntilTimestamp = optionalHeader(headers, require_download.DownloadHeaderName.FileRetentionRetainUntilTimestamp);
293
+ if (rawMode === void 0 && rawRetainUntilTimestamp === void 0) return void 0;
294
+ return {
295
+ isClientAuthorizedToRead: true,
296
+ value: {
297
+ mode: parseRetentionMode(rawMode, headerParseIssues),
298
+ retainUntilTimestamp: parseRetentionTimestamp(rawRetainUntilTimestamp, headerParseIssues)
299
+ }
300
+ };
301
+ }
302
+ function parseRetentionMode(rawMode, headerParseIssues) {
303
+ if (rawMode === void 0) return null;
304
+ if (rawMode === require_lock.RetentionMode.Compliance || rawMode === require_lock.RetentionMode.Governance) return rawMode;
305
+ headerParseIssues.push({
306
+ headerName: require_download.DownloadHeaderName.FileRetentionMode,
307
+ value: rawMode
308
+ });
309
+ return null;
310
+ }
311
+ function parseRetentionTimestamp(rawTimestamp, headerParseIssues) {
312
+ if (rawTimestamp === void 0) return null;
313
+ if (!/^\d+$/.test(rawTimestamp)) {
314
+ headerParseIssues.push({
315
+ headerName: require_download.DownloadHeaderName.FileRetentionRetainUntilTimestamp,
316
+ value: rawTimestamp
317
+ });
318
+ return null;
319
+ }
320
+ const parsed = Number.parseInt(rawTimestamp, 10);
321
+ if (Number.isFinite(parsed)) return parsed;
322
+ headerParseIssues.push({
323
+ headerName: require_download.DownloadHeaderName.FileRetentionRetainUntilTimestamp,
324
+ value: rawTimestamp
325
+ });
326
+ return null;
327
+ }
328
+ function parseDownloadLegalHold(headers, clientUnauthorizedToRead, headerParseIssues) {
329
+ if (clientUnauthorizedToRead?.includes(require_download.DownloadClientUnauthorizedToReadMarker.FileLegalHold)) return {
330
+ isClientAuthorizedToRead: false,
331
+ value: null
332
+ };
333
+ const rawLegalHold = optionalHeader(headers, require_download.DownloadHeaderName.FileLegalHold);
334
+ if (rawLegalHold === void 0) return void 0;
335
+ if (rawLegalHold === require_lock.LegalHoldValue.On || rawLegalHold === require_lock.LegalHoldValue.Off) return {
336
+ isClientAuthorizedToRead: true,
337
+ value: rawLegalHold
338
+ };
339
+ headerParseIssues.push({
340
+ headerName: require_download.DownloadHeaderName.FileLegalHold,
341
+ value: rawLegalHold
342
+ });
343
+ return {
344
+ isClientAuthorizedToRead: true,
345
+ value: null
346
+ };
347
+ }
348
+ function parseClientUnauthorizedToRead(headers, headerParseIssues) {
349
+ const value = optionalHeader(headers, require_download.DownloadHeaderName.ClientUnauthorizedToRead);
350
+ if (value === void 0) return void 0;
351
+ const headerNames = value.split(",").map((header) => header.trim()).filter((header) => header.length > 0);
352
+ const knownHeaderNames = headerNames.filter(isDownloadClientUnauthorizedToReadMarker);
353
+ for (const headerName of headerNames) if (!isDownloadClientUnauthorizedToReadMarker(headerName)) headerParseIssues.push({
354
+ headerName: require_download.DownloadHeaderName.ClientUnauthorizedToRead,
355
+ value: headerName
356
+ });
357
+ return knownHeaderNames.length > 0 ? knownHeaderNames : void 0;
358
+ }
359
+ function isDownloadClientUnauthorizedToReadMarker(headerName) {
360
+ return Object.values(require_download.DownloadClientUnauthorizedToReadMarker).includes(headerName);
201
361
  }
202
362
  //#endregion
203
363
  exports.downloadById = downloadById;
@@ -1 +1 @@
1
- {"version":3,"file":"single.cjs","names":[],"sources":["../../src/download/single.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport { parseFileInfoHeaders } from '../raw/encoding.ts'\nimport type { DownloadFileOptions, RawClient, SseCDownloadKey } from '../raw/index.ts'\nimport { type ProgressListener, ProgressTracker } from '../streams/progress.ts'\nimport type { DownloadHeaders } from '../types/download.ts'\nimport { type FileId, fileId as fileIdOf } from '../types/ids.ts'\nimport { bestEffort } from '../util/best-effort.ts'\nimport { normalizeSha1 } from '../util/normalize.ts'\nimport { verifyDownloadStream } from './checksum.ts'\n\n/** Result of a single-request file download. */\nexport interface DownloadResult {\n /** Parsed B2 response headers (content type, SHA-1, file info, etc.). */\n readonly headers: DownloadHeaders\n /**\n * Streaming body of the downloaded file.\n *\n * If checksum verification fails, the stream errors after bytes have already\n * flowed; discard any partially written output on `ChecksumMismatchError`.\n */\n readonly body: ReadableStream<Uint8Array>\n}\n\n/**\n * Result of a HEAD-style metadata fetch. Unlike {@link DownloadResult},\n * this shape has **no** `body` field — the SDK consumes and discards the\n * (logically empty) HEAD response body internally so callers never have\n * to remember to `body.cancel()` after a metadata-only fetch.\n */\nexport interface HeadResult {\n /** Parsed B2 response headers (content type, SHA-1, file info, etc.). */\n readonly headers: DownloadHeaders\n}\n\n/** Shared download options exposed at the high-level facade. */\ninterface DownloadCommonOptions {\n /** HTTP method. Defaults to `'GET'`. Use `'HEAD'` to fetch only response headers without streaming the body. */\n readonly method?: 'GET' | 'HEAD'\n /** Optional HTTP Range header value (e.g. `bytes=0-999`). */\n readonly range?: string\n /** SSE-C decryption parameters, required if the file was uploaded with SSE-C. */\n readonly serverSideEncryption?: SseCDownloadKey\n /** Override the response `Content-Disposition` header. */\n readonly b2ContentDisposition?: string\n /** Override the response `Content-Language` header. */\n readonly b2ContentLanguage?: string\n /** Override the response `Content-Encoding` header. */\n readonly b2ContentEncoding?: string\n /** Override the response `Content-Type` header. */\n readonly b2ContentType?: string\n /** Override the response `Cache-Control` header. */\n readonly b2CacheControl?: string\n /** Override the response `Expires` header. */\n readonly b2Expires?: string\n /** Signal to abort the download. */\n readonly signal?: AbortSignal\n /**\n * Callback invoked as bytes flow through the returned `body` stream.\n *\n * Wraps the response body in a `TransformStream` that increments a\n * `ProgressTracker` per chunk and emits a `partsCompleted: 1` event when\n * the stream finishes. `totalBytes` is the response's `Content-Length`\n * header (or `null` if the server didn't send one — rare for B2).\n *\n * If the caller does not read the returned body to completion, the\n * tracker's `completePart()` event will not fire. That is intentional:\n * progress is byte-driven, not request-driven.\n */\n readonly onProgress?: ProgressListener\n}\n\n/** Options for downloading a file by its unique ID. */\nexport interface DownloadByIdOptions extends DownloadCommonOptions {\n /** ID of the file version to download. */\n readonly fileId: FileId\n}\n\n/** Options for downloading a file by bucket name and file path. */\nexport interface DownloadByNameOptions extends DownloadCommonOptions {\n /** Name of the bucket containing the file. */\n readonly bucketName: string\n /** Full file name (path) within the bucket. */\n readonly fileName: string\n}\n\n/**\n * Shared HEAD options. Mirrors {@link DownloadCommonOptions} but omits\n * `method` (always HEAD) and `onProgress` (no body to track).\n */\ntype HeadCommonOptions = Omit<DownloadCommonOptions, 'method' | 'onProgress'>\n\n/** Options for a HEAD-by-ID request. */\nexport interface HeadByIdOptions extends HeadCommonOptions {\n /** ID of the file version to inspect. */\n readonly fileId: FileId\n}\n\n/** Options for a HEAD-by-name request. */\nexport interface HeadByNameOptions extends HeadCommonOptions {\n /** Name of the bucket containing the file. */\n readonly bucketName: string\n /** Full file name (path) within the bucket. */\n readonly fileName: string\n}\n\n/**\n * Downloads a file by its unique ID in a single HTTP request.\n *\n * Returns a streaming body suitable for small-to-medium files. For large files\n * that benefit from concurrent ranged fetches, use\n * {@link createParallelDownloadStream} instead.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - Download parameters.\n *\n * @returns Parsed headers and a readable stream of file bytes.\n */\nexport async function downloadById(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: DownloadByIdOptions,\n): Promise<DownloadResult> {\n const resp = await raw.downloadFileById(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.fileId,\n toRawDownloadOptions(options),\n )\n\n const headers = extractDownloadHeaders(resp.headers)\n return {\n headers,\n // HEAD requests legitimately have no body; return an empty stream so the\n // result shape stays consistent.\n body: prepareDownloadBody(resp.body ?? emptyStream(), headers, options),\n }\n}\n\n/**\n * Downloads a file by bucket name and file path in a single HTTP request.\n *\n * Returns a streaming body suitable for small-to-medium files. For large files\n * that benefit from concurrent ranged fetches, use\n * {@link createParallelDownloadStream} instead.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - Download parameters.\n *\n * @returns Parsed headers and a readable stream of file bytes.\n */\nexport async function downloadByName(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: DownloadByNameOptions,\n): Promise<DownloadResult> {\n const resp = await raw.downloadFileByName(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.bucketName,\n options.fileName,\n toRawDownloadOptions(options),\n )\n\n const headers = extractDownloadHeaders(resp.headers)\n return {\n headers,\n body: prepareDownloadBody(resp.body ?? emptyStream(), headers, options),\n }\n}\n\n/**\n * Issues a HEAD-by-ID request and returns parsed headers only. Drains\n * the (logically empty) response body internally so callers don't have\n * to remember to `body.cancel()` themselves.\n *\n * Prefer this over `downloadById({ method: 'HEAD' })` — same wire-level\n * effect, but the caller-facing result has no `body` field at all so\n * there's nothing to clean up.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - HEAD parameters (file ID + the same response-header\n * overrides and abort signal that `downloadById` accepts).\n *\n * @returns Parsed download headers (no body field).\n */\nexport async function headById(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: HeadByIdOptions,\n): Promise<HeadResult> {\n const resp = await raw.downloadFileById(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.fileId,\n { ...toRawDownloadOptions(options), method: 'HEAD' },\n )\n // Body for HEAD is normally `null` per the fetch spec. Some transports\n // (notably the SDK's `B2Simulator`) synthesize a non-null body for\n // shape consistency. In either case, cancelling is a no-op for the\n // caller; wrap in `bestEffort` so a stream-lifecycle quirk in a\n // future runtime can't fail an otherwise-successful HEAD.\n if (resp.body !== null) {\n // Bind to a local so the type narrowing carries into the closure;\n // bare `resp.body` in the lambda would re-broaden to `... | null`.\n const body = resp.body\n await bestEffort(() => body.cancel())\n }\n return { headers: extractDownloadHeaders(resp.headers) }\n}\n\n/**\n * Issues a HEAD-by-name request and returns parsed headers only. Drains\n * the (logically empty) response body internally so callers don't have\n * to remember to `body.cancel()` themselves.\n *\n * Prefer this over `downloadByName({ method: 'HEAD' })` — same wire-level\n * effect, but the caller-facing result has no `body` field at all so\n * there's nothing to clean up.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - HEAD parameters (bucket + file name + the same\n * response-header overrides and abort signal that `downloadByName`\n * accepts).\n *\n * @returns Parsed download headers (no body field).\n */\nexport async function headByName(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: HeadByNameOptions,\n): Promise<HeadResult> {\n const resp = await raw.downloadFileByName(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.bucketName,\n options.fileName,\n { ...toRawDownloadOptions(options), method: 'HEAD' },\n )\n if (resp.body !== null) {\n // Bind to a local so the type narrowing carries into the closure;\n // bare `resp.body` in the lambda would re-broaden to `... | null`.\n const body = resp.body\n await bestEffort(() => body.cancel())\n }\n return { headers: extractDownloadHeaders(resp.headers) }\n}\n\n/**\n * Translates the public download-options shape into the raw client's\n * {@link DownloadFileOptions}, dropping the request-target fields (`fileId`,\n * `bucketName`, `fileName`) that don't apply at the transport layer.\n *\n * @param options - Caller-supplied download options.\n *\n * @returns The raw transport-layer options.\n */\nfunction toRawDownloadOptions(options: DownloadCommonOptions): DownloadFileOptions {\n return {\n ...(options.method !== undefined ? { method: options.method } : {}),\n ...(options.range !== undefined ? { range: options.range } : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.b2ContentDisposition !== undefined\n ? { b2ContentDisposition: options.b2ContentDisposition }\n : {}),\n ...(options.b2ContentLanguage !== undefined\n ? { b2ContentLanguage: options.b2ContentLanguage }\n : {}),\n ...(options.b2ContentEncoding !== undefined\n ? { b2ContentEncoding: options.b2ContentEncoding }\n : {}),\n ...(options.b2ContentType !== undefined ? { b2ContentType: options.b2ContentType } : {}),\n ...(options.b2CacheControl !== undefined ? { b2CacheControl: options.b2CacheControl } : {}),\n ...(options.b2Expires !== undefined ? { b2Expires: options.b2Expires } : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n }\n}\n\n/**\n * Builds an immediately-closed empty ReadableStream. Used as the body of a\n * HEAD download response so callers always get a stream they can `pipeTo`.\n *\n * @returns A ReadableStream that yields zero bytes and immediately closes.\n */\nfunction emptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream({\n start(controller) {\n controller.close()\n },\n })\n}\n\n/**\n * Applies stream wrappers common to single-request downloads.\n *\n * Full-body GET downloads are checksum-verified when B2 supplies a real\n * whole-file SHA-1. HEAD requests and ranged GETs are skipped because the\n * response body is empty or partial while `X-Bz-Content-Sha1` describes the\n * full file version.\n *\n * @param body - Download response body.\n * @param headers - Parsed download headers.\n * @param options - Caller-supplied download options.\n *\n * @returns A stream wrapped for checksum verification and progress reporting.\n */\nfunction prepareDownloadBody(\n body: ReadableStream<Uint8Array>,\n headers: DownloadHeaders,\n options: DownloadCommonOptions,\n): ReadableStream<Uint8Array> {\n const shouldVerify = options.method !== 'HEAD' && options.range === undefined\n const verifiedBody = shouldVerify ? verifyDownloadStream(body, headers.contentSha1) : body\n return instrumentProgress(verifiedBody, headers.contentLength, options.onProgress)\n}\n\n/**\n * Wraps a body stream with a `TransformStream` that increments a\n * {@link ProgressTracker} for each chunk and reports `partsCompleted: 1`\n * when the stream finishes.\n *\n * When `listener` is undefined the function short-circuits and returns\n * the original stream, so unobserved downloads pay no overhead.\n *\n * @param body - The download response body to wrap.\n * @param totalBytes - Expected total bytes (response `Content-Length`).\n * @param listener - Caller-supplied progress callback, or undefined.\n *\n * @returns A stream that emits the same bytes and reports progress.\n */\nfunction instrumentProgress(\n body: ReadableStream<Uint8Array>,\n totalBytes: number,\n listener: ProgressListener | undefined,\n): ReadableStream<Uint8Array> {\n if (listener === undefined) return body\n const tracker = new ProgressTracker(listener, totalBytes, 1)\n const transform = new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n tracker.addBytes(chunk.byteLength)\n controller.enqueue(chunk)\n },\n flush() {\n tracker.completePart()\n },\n })\n return body.pipeThrough(transform)\n}\n\n/**\n * Extracts B2-specific download headers into a structured object.\n * @param headers - The HTTP response headers from the download.\n *\n * @returns The parsed download metadata.\n */\nfunction extractDownloadHeaders(headers: Headers): DownloadHeaders {\n const fileInfo = parseFileInfoHeaders(headers)\n\n return {\n contentType: headers.get('Content-Type') ?? 'application/octet-stream',\n contentLength: Number.parseInt(headers.get('Content-Length') ?? '0', 10),\n // B2 sends the literal `'none'` for multipart-finished files; collapse\n // to `null` so the typed `string | null` actually means \"no SHA-1\".\n contentSha1: normalizeSha1(headers.get('X-Bz-Content-Sha1')),\n fileId: fileIdOf(headers.get('X-Bz-File-Id') ?? ''),\n fileName: decodeURIComponent(headers.get('X-Bz-File-Name') ?? ''),\n fileInfo,\n uploadTimestamp: Number.parseInt(headers.get('X-Bz-Upload-Timestamp') ?? '0', 10),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"single.cjs","names":[],"sources":["../../src/download/single.ts"],"sourcesContent":["import type { AccountInfo } from '../auth/account-info.ts'\nimport { parseFileInfoHeaders } from '../raw/encoding.ts'\nimport type { DownloadFileOptions, RawClient, SseCDownloadKey } from '../raw/index.ts'\nimport { type ProgressListener, ProgressTracker } from '../streams/progress.ts'\nimport {\n DownloadClientUnauthorizedToReadMarker,\n DownloadHeaderName,\n type DownloadHeaderParseIssue,\n type DownloadHeaders,\n type DownloadServerSideEncryption,\n} from '../types/download.ts'\nimport { EncryptionAlgorithm, EncryptionMode } from '../types/encryption.ts'\nimport { type FileId, fileId as fileIdOf } from '../types/ids.ts'\nimport { type FileRetentionValue, LegalHoldValue, RetentionMode } from '../types/lock.ts'\nimport { bestEffort } from '../util/best-effort.ts'\nimport { normalizeSha1 } from '../util/normalize.ts'\nimport { verifyDownloadStream } from './checksum.ts'\n\n/** Result of a single-request file download. */\nexport interface DownloadResult {\n /** Parsed B2 response headers (content type, SHA-1, file info, etc.). */\n readonly headers: DownloadHeaders\n /**\n * Streaming body of the downloaded file.\n *\n * If checksum verification fails, the stream errors after bytes have already\n * flowed; discard any partially written output on `ChecksumMismatchError`.\n */\n readonly body: ReadableStream<Uint8Array>\n}\n\n/**\n * Result of a HEAD-style metadata fetch. Unlike {@link DownloadResult},\n * this shape has **no** `body` field — the SDK consumes and discards the\n * (logically empty) HEAD response body internally so callers never have\n * to remember to `body.cancel()` after a metadata-only fetch.\n */\nexport interface HeadResult {\n /** Parsed B2 response headers (content type, SHA-1, file info, etc.). */\n readonly headers: DownloadHeaders\n}\n\n/** Shared download options exposed at the high-level facade. */\ninterface DownloadCommonOptions {\n /** HTTP method. Defaults to `'GET'`. Use `'HEAD'` to fetch only response headers without streaming the body. */\n readonly method?: 'GET' | 'HEAD'\n /** Optional HTTP Range header value (e.g. `bytes=0-999`). */\n readonly range?: string\n /** SSE-C decryption parameters, required if the file was uploaded with SSE-C. */\n readonly serverSideEncryption?: SseCDownloadKey\n /** Override the response `Content-Disposition` header. */\n readonly b2ContentDisposition?: string\n /** Override the response `Content-Language` header. */\n readonly b2ContentLanguage?: string\n /** Override the response `Content-Encoding` header. */\n readonly b2ContentEncoding?: string\n /** Override the response `Content-Type` header. */\n readonly b2ContentType?: string\n /** Override the response `Cache-Control` header. */\n readonly b2CacheControl?: string\n /** Override the response `Expires` header. */\n readonly b2Expires?: string\n /** Signal to abort the download. */\n readonly signal?: AbortSignal\n /**\n * Callback invoked as bytes flow through the returned `body` stream.\n *\n * Wraps the response body so the SDK increments a `ProgressTracker` per\n * chunk and emits a `partsCompleted: 1` event when the stream finishes.\n * `totalBytes` is the response's `Content-Length`\n * header (or `null` if the server didn't send one — rare for B2).\n *\n * If the caller does not read the returned body to completion, the\n * tracker's `completePart()` event will not fire. That is intentional:\n * progress is byte-driven, not request-driven.\n */\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 * The final completion callback is always emitted immediately.\n */\n readonly progressIntervalMillis?: number\n}\n\n/** Options for downloading a file by its unique ID. */\nexport interface DownloadByIdOptions extends DownloadCommonOptions {\n /** ID of the file version to download. */\n readonly fileId: FileId\n}\n\n/** Options for downloading a file by bucket name and file path. */\nexport interface DownloadByNameOptions extends DownloadCommonOptions {\n /** Name of the bucket containing the file. */\n readonly bucketName: string\n /** Full file name (path) within the bucket. */\n readonly fileName: string\n}\n\n/**\n * Shared HEAD options. Mirrors {@link DownloadCommonOptions} but omits\n * `method` (always HEAD) and `onProgress` (no body to track).\n */\ntype HeadCommonOptions = Omit<\n DownloadCommonOptions,\n 'method' | 'onProgress' | 'progressIntervalMillis'\n>\n\n/** Options for a HEAD-by-ID request. */\nexport interface HeadByIdOptions extends HeadCommonOptions {\n /** ID of the file version to inspect. */\n readonly fileId: FileId\n}\n\n/** Options for a HEAD-by-name request. */\nexport interface HeadByNameOptions extends HeadCommonOptions {\n /** Name of the bucket containing the file. */\n readonly bucketName: string\n /** Full file name (path) within the bucket. */\n readonly fileName: string\n}\n\n/**\n * Downloads a file by its unique ID in a single HTTP request.\n *\n * Returns a streaming body suitable for small-to-medium files. For large files\n * that benefit from concurrent ranged fetches, use\n * {@link createParallelDownloadStream} instead.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - Download parameters.\n *\n * @returns Parsed headers and a readable stream of file bytes.\n */\nexport async function downloadById(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: DownloadByIdOptions,\n): Promise<DownloadResult> {\n const resp = await raw.downloadFileById(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.fileId,\n toRawDownloadOptions(options),\n )\n\n const headers = extractDownloadHeaders(resp.headers)\n return {\n headers,\n // HEAD requests legitimately have no body; return an empty stream so the\n // result shape stays consistent.\n body: prepareDownloadBody(resp.body ?? emptyStream(), headers, options),\n }\n}\n\n/**\n * Downloads a file by bucket name and file path in a single HTTP request.\n *\n * Returns a streaming body suitable for small-to-medium files. For large files\n * that benefit from concurrent ranged fetches, use\n * {@link createParallelDownloadStream} instead.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - Download parameters.\n *\n * @returns Parsed headers and a readable stream of file bytes.\n */\nexport async function downloadByName(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: DownloadByNameOptions,\n): Promise<DownloadResult> {\n const resp = await raw.downloadFileByName(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.bucketName,\n options.fileName,\n toRawDownloadOptions(options),\n )\n\n const headers = extractDownloadHeaders(resp.headers)\n return {\n headers,\n body: prepareDownloadBody(resp.body ?? emptyStream(), headers, options),\n }\n}\n\n/**\n * Issues a HEAD-by-ID request and returns parsed headers only. Drains\n * the (logically empty) response body internally so callers don't have\n * to remember to `body.cancel()` themselves.\n *\n * Prefer this over `downloadById({ method: 'HEAD' })` — same wire-level\n * effect, but the caller-facing result has no `body` field at all so\n * there's nothing to clean up.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - HEAD parameters (file ID + the same response-header\n * overrides and abort signal that `downloadById` accepts).\n *\n * @returns Parsed download headers (no body field).\n */\nexport async function headById(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: HeadByIdOptions,\n): Promise<HeadResult> {\n const resp = await raw.downloadFileById(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.fileId,\n { ...toRawDownloadOptions(options), method: 'HEAD' },\n )\n // Body for HEAD is normally `null` per the fetch spec. Some transports\n // (notably the SDK's `B2Simulator`) synthesize a non-null body for\n // shape consistency. In either case, cancelling is a no-op for the\n // caller; wrap in `bestEffort` so a stream-lifecycle quirk in a\n // future runtime can't fail an otherwise-successful HEAD.\n if (resp.body !== null) {\n // Bind to a local so the type narrowing carries into the closure;\n // bare `resp.body` in the lambda would re-broaden to `... | null`.\n const body = resp.body\n await bestEffort(() => body.cancel())\n }\n return { headers: extractDownloadHeaders(resp.headers) }\n}\n\n/**\n * Issues a HEAD-by-name request and returns parsed headers only. Drains\n * the (logically empty) response body internally so callers don't have\n * to remember to `body.cancel()` themselves.\n *\n * Prefer this over `downloadByName({ method: 'HEAD' })` — same wire-level\n * effect, but the caller-facing result has no `body` field at all so\n * there's nothing to clean up.\n *\n * @param raw - Low-level B2 API client.\n * @param accountInfo - Authorized account state.\n * @param options - HEAD parameters (bucket + file name + the same\n * response-header overrides and abort signal that `downloadByName`\n * accepts).\n *\n * @returns Parsed download headers (no body field).\n */\nexport async function headByName(\n raw: RawClient,\n accountInfo: AccountInfo,\n options: HeadByNameOptions,\n): Promise<HeadResult> {\n const resp = await raw.downloadFileByName(\n accountInfo.getDownloadUrl(),\n accountInfo.getAuthToken(),\n options.bucketName,\n options.fileName,\n { ...toRawDownloadOptions(options), method: 'HEAD' },\n )\n if (resp.body !== null) {\n // Bind to a local so the type narrowing carries into the closure;\n // bare `resp.body` in the lambda would re-broaden to `... | null`.\n const body = resp.body\n await bestEffort(() => body.cancel())\n }\n return { headers: extractDownloadHeaders(resp.headers) }\n}\n\n/**\n * Translates the public download-options shape into the raw client's\n * {@link DownloadFileOptions}, dropping the request-target fields (`fileId`,\n * `bucketName`, `fileName`) that don't apply at the transport layer.\n *\n * @param options - Caller-supplied download options.\n *\n * @returns The raw transport-layer options.\n */\nfunction toRawDownloadOptions(options: DownloadCommonOptions): DownloadFileOptions {\n return {\n ...(options.method !== undefined ? { method: options.method } : {}),\n ...(options.range !== undefined ? { range: options.range } : {}),\n ...(options.serverSideEncryption !== undefined\n ? { serverSideEncryption: options.serverSideEncryption }\n : {}),\n ...(options.b2ContentDisposition !== undefined\n ? { b2ContentDisposition: options.b2ContentDisposition }\n : {}),\n ...(options.b2ContentLanguage !== undefined\n ? { b2ContentLanguage: options.b2ContentLanguage }\n : {}),\n ...(options.b2ContentEncoding !== undefined\n ? { b2ContentEncoding: options.b2ContentEncoding }\n : {}),\n ...(options.b2ContentType !== undefined ? { b2ContentType: options.b2ContentType } : {}),\n ...(options.b2CacheControl !== undefined ? { b2CacheControl: options.b2CacheControl } : {}),\n ...(options.b2Expires !== undefined ? { b2Expires: options.b2Expires } : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n }\n}\n\n/**\n * Builds an immediately-closed empty ReadableStream. Used as the body of a\n * HEAD download response so callers always get a stream they can `pipeTo`.\n *\n * @returns A ReadableStream that yields zero bytes and immediately closes.\n */\nfunction emptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream({\n start(controller) {\n controller.close()\n },\n })\n}\n\n/**\n * Applies stream wrappers common to single-request downloads.\n *\n * Full-body GET downloads are checksum-verified when B2 supplies a real\n * whole-file SHA-1. HEAD requests and ranged GETs are skipped because the\n * response body is empty or partial while `X-Bz-Content-Sha1` describes the\n * full file version.\n *\n * @param body - Download response body.\n * @param headers - Parsed download headers.\n * @param options - Caller-supplied download options.\n *\n * @returns A stream wrapped for checksum verification and progress reporting.\n */\nfunction prepareDownloadBody(\n body: ReadableStream<Uint8Array>,\n headers: DownloadHeaders,\n options: DownloadCommonOptions,\n): ReadableStream<Uint8Array> {\n const shouldVerify = options.method !== 'HEAD' && options.range === undefined\n const verifiedBody = shouldVerify ? verifyDownloadStream(body, headers.contentSha1) : body\n return instrumentProgress(\n verifiedBody,\n headers.contentLength,\n options.onProgress,\n options.progressIntervalMillis,\n )\n}\n\n/**\n * Wraps a body stream so the SDK increments a {@link ProgressTracker} for\n * each chunk and reports `partsCompleted: 1` when the stream finishes.\n *\n * When `listener` is undefined the function short-circuits and returns\n * the original stream, so unobserved downloads pay no overhead.\n *\n * @param body - The download response body to wrap.\n * @param totalBytes - Expected total bytes (response `Content-Length`).\n * @param listener - Caller-supplied progress callback, or undefined.\n * @param progressIntervalMillis - Optional byte-progress throttle interval.\n *\n * @returns A stream that emits the same bytes and reports progress.\n */\nfunction instrumentProgress(\n body: ReadableStream<Uint8Array>,\n totalBytes: number,\n listener: ProgressListener | undefined,\n progressIntervalMillis: number | undefined,\n): ReadableStream<Uint8Array> {\n if (listener === undefined) return body\n const tracker = new ProgressTracker(listener, totalBytes, 1, {\n ...(progressIntervalMillis !== undefined ? { minIntervalMs: progressIntervalMillis } : {}),\n })\n const reader = body.getReader()\n let released = false\n\n function releaseReader(): void {\n if (released) return\n released = true\n reader.releaseLock()\n }\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const { done, value } = await reader.read()\n if (done) {\n tracker.completePart()\n tracker.dispose()\n releaseReader()\n controller.close()\n return\n }\n tracker.addBytes(value.byteLength)\n controller.enqueue(value)\n } catch (err) {\n tracker.dispose()\n releaseReader()\n throw err\n }\n },\n async cancel(reason) {\n tracker.dispose()\n try {\n await reader.cancel(reason)\n } finally {\n releaseReader()\n }\n },\n })\n}\n\n/**\n * Extracts B2-specific download headers into a structured object.\n * @param headers - The HTTP response headers from the download.\n *\n * @returns The parsed download metadata.\n */\nfunction extractDownloadHeaders(headers: Headers): DownloadHeaders {\n const headerParseIssues: DownloadHeaderParseIssue[] = []\n const fileInfo = parseFileInfoHeaders(headers)\n const clientUnauthorizedToRead = parseClientUnauthorizedToRead(headers, headerParseIssues)\n const contentDisposition = optionalHeader(headers, DownloadHeaderName.ContentDisposition)\n const contentLanguage = optionalHeader(headers, DownloadHeaderName.ContentLanguage)\n const contentEncoding = optionalHeader(headers, DownloadHeaderName.ContentEncoding)\n const cacheControl = optionalHeader(headers, DownloadHeaderName.CacheControl)\n const expires = optionalHeader(headers, DownloadHeaderName.Expires)\n const contentRange = optionalHeader(headers, DownloadHeaderName.ContentRange)\n const serverSideEncryption = parseDownloadServerSideEncryption(headers, headerParseIssues)\n const fileRetention = parseDownloadFileRetention(\n headers,\n clientUnauthorizedToRead,\n headerParseIssues,\n )\n const legalHold = parseDownloadLegalHold(headers, clientUnauthorizedToRead, headerParseIssues)\n\n return {\n contentType: headers.get(DownloadHeaderName.ContentType) ?? 'application/octet-stream',\n contentLength: Number.parseInt(headers.get(DownloadHeaderName.ContentLength) ?? '0', 10),\n ...(contentDisposition !== undefined ? { contentDisposition } : {}),\n ...(contentLanguage !== undefined ? { contentLanguage } : {}),\n ...(contentEncoding !== undefined ? { contentEncoding } : {}),\n ...(cacheControl !== undefined ? { cacheControl } : {}),\n ...(expires !== undefined ? { expires } : {}),\n ...(contentRange !== undefined ? { contentRange } : {}),\n // B2 sends the literal `'none'` for multipart-finished files; collapse\n // to `null` so the typed `string | null` actually means \"no SHA-1\".\n contentSha1: normalizeSha1(headers.get(DownloadHeaderName.ContentSha1)),\n fileId: fileIdOf(headers.get(DownloadHeaderName.FileId) ?? ''),\n fileName: decodeURIComponent(headers.get(DownloadHeaderName.FileName) ?? ''),\n fileInfo,\n uploadTimestamp: Number.parseInt(headers.get(DownloadHeaderName.UploadTimestamp) ?? '0', 10),\n ...(serverSideEncryption !== undefined ? { serverSideEncryption } : {}),\n ...(fileRetention !== undefined ? { fileRetention } : {}),\n ...(legalHold !== undefined ? { legalHold } : {}),\n ...(clientUnauthorizedToRead !== undefined ? { clientUnauthorizedToRead } : {}),\n ...(headerParseIssues.length > 0 ? { headerParseIssues } : {}),\n }\n}\n\nfunction optionalHeader(headers: Headers, name: string): string | undefined {\n return headers.get(name) ?? undefined\n}\n\nfunction parseDownloadServerSideEncryption(\n headers: Headers,\n headerParseIssues: DownloadHeaderParseIssue[],\n): DownloadServerSideEncryption | undefined {\n const managedAlgorithm = optionalHeader(headers, DownloadHeaderName.ServerSideEncryption)\n if (managedAlgorithm !== undefined) {\n if (managedAlgorithm !== EncryptionAlgorithm.Aes256) {\n headerParseIssues.push({\n headerName: DownloadHeaderName.ServerSideEncryption,\n value: managedAlgorithm,\n })\n return undefined\n }\n return { mode: EncryptionMode.SseB2, algorithm: managedAlgorithm }\n }\n\n const customerAlgorithm = optionalHeader(\n headers,\n DownloadHeaderName.ServerSideEncryptionCustomerAlgorithm,\n )\n const customerKeyMd5 = optionalHeader(\n headers,\n DownloadHeaderName.ServerSideEncryptionCustomerKeyMd5,\n )\n if (customerAlgorithm === undefined || customerKeyMd5 === undefined) return undefined\n if (customerAlgorithm !== EncryptionAlgorithm.Aes256) {\n headerParseIssues.push({\n headerName: DownloadHeaderName.ServerSideEncryptionCustomerAlgorithm,\n value: customerAlgorithm,\n })\n return undefined\n }\n return { mode: EncryptionMode.SseC, algorithm: customerAlgorithm, customerKeyMd5 }\n}\n\nfunction parseDownloadFileRetention(\n headers: Headers,\n clientUnauthorizedToRead: DownloadHeaders['clientUnauthorizedToRead'],\n headerParseIssues: DownloadHeaderParseIssue[],\n): DownloadHeaders['fileRetention'] {\n if (\n clientUnauthorizedToRead?.includes(DownloadClientUnauthorizedToReadMarker.FileRetentionMode) ===\n true ||\n clientUnauthorizedToRead?.includes(\n DownloadClientUnauthorizedToReadMarker.FileRetentionRetainUntilTimestamp,\n ) === true\n ) {\n return { isClientAuthorizedToRead: false, value: null }\n }\n\n const rawMode = optionalHeader(headers, DownloadHeaderName.FileRetentionMode)\n const rawRetainUntilTimestamp = optionalHeader(\n headers,\n DownloadHeaderName.FileRetentionRetainUntilTimestamp,\n )\n if (rawMode === undefined && rawRetainUntilTimestamp === undefined) return undefined\n return {\n isClientAuthorizedToRead: true,\n value: {\n mode: parseRetentionMode(rawMode, headerParseIssues),\n retainUntilTimestamp: parseRetentionTimestamp(rawRetainUntilTimestamp, headerParseIssues),\n },\n }\n}\n\nfunction parseRetentionMode(\n rawMode: string | undefined,\n headerParseIssues: DownloadHeaderParseIssue[],\n): FileRetentionValue['mode'] {\n if (rawMode === undefined) return null\n if (rawMode === RetentionMode.Compliance || rawMode === RetentionMode.Governance) {\n return rawMode\n }\n headerParseIssues.push({ headerName: DownloadHeaderName.FileRetentionMode, value: rawMode })\n return null\n}\n\nfunction parseRetentionTimestamp(\n rawTimestamp: string | undefined,\n headerParseIssues: DownloadHeaderParseIssue[],\n): number | null {\n if (rawTimestamp === undefined) return null\n if (!/^\\d+$/.test(rawTimestamp)) {\n headerParseIssues.push({\n headerName: DownloadHeaderName.FileRetentionRetainUntilTimestamp,\n value: rawTimestamp,\n })\n return null\n }\n const parsed = Number.parseInt(rawTimestamp, 10)\n if (Number.isFinite(parsed)) return parsed\n headerParseIssues.push({\n headerName: DownloadHeaderName.FileRetentionRetainUntilTimestamp,\n value: rawTimestamp,\n })\n return null\n}\n\nfunction parseDownloadLegalHold(\n headers: Headers,\n clientUnauthorizedToRead: DownloadHeaders['clientUnauthorizedToRead'],\n headerParseIssues: DownloadHeaderParseIssue[],\n): DownloadHeaders['legalHold'] {\n if (clientUnauthorizedToRead?.includes(DownloadClientUnauthorizedToReadMarker.FileLegalHold)) {\n return { isClientAuthorizedToRead: false, value: null }\n }\n\n const rawLegalHold = optionalHeader(headers, DownloadHeaderName.FileLegalHold)\n if (rawLegalHold === undefined) return undefined\n if (rawLegalHold === LegalHoldValue.On || rawLegalHold === LegalHoldValue.Off) {\n return { isClientAuthorizedToRead: true, value: rawLegalHold }\n }\n headerParseIssues.push({ headerName: DownloadHeaderName.FileLegalHold, value: rawLegalHold })\n return { isClientAuthorizedToRead: true, value: null }\n}\n\nfunction parseClientUnauthorizedToRead(\n headers: Headers,\n headerParseIssues: DownloadHeaderParseIssue[],\n): DownloadHeaders['clientUnauthorizedToRead'] {\n const value = optionalHeader(headers, DownloadHeaderName.ClientUnauthorizedToRead)\n if (value === undefined) return undefined\n const headerNames = value\n .split(',')\n .map((header) => header.trim())\n .filter((header) => header.length > 0)\n const knownHeaderNames = headerNames.filter(isDownloadClientUnauthorizedToReadMarker)\n for (const headerName of headerNames) {\n if (!isDownloadClientUnauthorizedToReadMarker(headerName)) {\n headerParseIssues.push({\n headerName: DownloadHeaderName.ClientUnauthorizedToRead,\n value: headerName,\n })\n }\n }\n return knownHeaderNames.length > 0 ? knownHeaderNames : undefined\n}\n\nfunction isDownloadClientUnauthorizedToReadMarker(\n headerName: string,\n): headerName is DownloadClientUnauthorizedToReadMarker {\n return Object.values(DownloadClientUnauthorizedToReadMarker).includes(\n headerName as DownloadClientUnauthorizedToReadMarker,\n )\n}\n"],"mappings":"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"}
@@ -50,9 +50,9 @@ interface DownloadCommonOptions {
50
50
  /**
51
51
  * Callback invoked as bytes flow through the returned `body` stream.
52
52
  *
53
- * Wraps the response body in a `TransformStream` that increments a
54
- * `ProgressTracker` per chunk and emits a `partsCompleted: 1` event when
55
- * the stream finishes. `totalBytes` is the response's `Content-Length`
53
+ * Wraps the response body so the SDK increments a `ProgressTracker` per
54
+ * chunk and emits a `partsCompleted: 1` event when the stream finishes.
55
+ * `totalBytes` is the response's `Content-Length`
56
56
  * header (or `null` if the server didn't send one — rare for B2).
57
57
  *
58
58
  * If the caller does not read the returned body to completion, the
@@ -60,6 +60,12 @@ interface DownloadCommonOptions {
60
60
  * progress is byte-driven, not request-driven.
61
61
  */
62
62
  readonly onProgress?: ProgressListener;
63
+ /**
64
+ * Minimum milliseconds between byte-only progress callbacks. Defaults to
65
+ * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.
66
+ * The final completion callback is always emitted immediately.
67
+ */
68
+ readonly progressIntervalMillis?: number;
63
69
  }
64
70
  /** Options for downloading a file by its unique ID. */
65
71
  export interface DownloadByIdOptions extends DownloadCommonOptions {
@@ -77,7 +83,7 @@ export interface DownloadByNameOptions extends DownloadCommonOptions {
77
83
  * Shared HEAD options. Mirrors {@link DownloadCommonOptions} but omits
78
84
  * `method` (always HEAD) and `onProgress` (no body to track).
79
85
  */
80
- type HeadCommonOptions = Omit<DownloadCommonOptions, 'method' | 'onProgress'>;
86
+ type HeadCommonOptions = Omit<DownloadCommonOptions, 'method' | 'onProgress' | 'progressIntervalMillis'>;
81
87
  /** Options for a HEAD-by-ID request. */
82
88
  export interface HeadByIdOptions extends HeadCommonOptions {
83
89
  /** ID of the file version to inspect. */
@@ -1 +1 @@
1
- {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../src/download/single.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../src/download/single.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAE1D,OAAO,KAAK,EAAuB,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACtF,OAAO,EAAE,KAAK,gBAAgB,EAAmB,MAAM,wBAAwB,CAAA;AAC/E,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,KAAK,MAAM,EAAsB,MAAM,iBAAiB,CAAA;AAMjE,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;CAC1C;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAClC;AAED,gEAAgE;AAChE,UAAU,qBAAqB;IAC7B,gHAAgH;IAChH,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IAChC,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,iFAAiF;IACjF,QAAQ,CAAC,oBAAoB,CAAC,EAAE,eAAe,CAAA;IAC/C,0DAA0D;IAC1D,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IACtC,uDAAuD;IACvD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,uDAAuD;IACvD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,mDAAmD;IACnD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,oDAAoD;IACpD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;IAC7B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAA;IACtC;;;;OAIG;IACH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;CACzC;AAED,uDAAuD;AACvD,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,mEAAmE;AACnE,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED;;;GAGG;AACH,KAAK,iBAAiB,GAAG,IAAI,CAC3B,qBAAqB,EACrB,QAAQ,GAAG,YAAY,GAAG,wBAAwB,CACnD,CAAA;AAED,wCAAwC;AACxC,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,0CAA0C;AAC1C,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAezB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAczB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,UAAU,CAAC,CAmBrB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,UAAU,CAAC,CAerB"}
@@ -50,9 +50,9 @@ interface DownloadCommonOptions {
50
50
  /**
51
51
  * Callback invoked as bytes flow through the returned `body` stream.
52
52
  *
53
- * Wraps the response body in a `TransformStream` that increments a
54
- * `ProgressTracker` per chunk and emits a `partsCompleted: 1` event when
55
- * the stream finishes. `totalBytes` is the response's `Content-Length`
53
+ * Wraps the response body so the SDK increments a `ProgressTracker` per
54
+ * chunk and emits a `partsCompleted: 1` event when the stream finishes.
55
+ * `totalBytes` is the response's `Content-Length`
56
56
  * header (or `null` if the server didn't send one — rare for B2).
57
57
  *
58
58
  * If the caller does not read the returned body to completion, the
@@ -60,6 +60,12 @@ interface DownloadCommonOptions {
60
60
  * progress is byte-driven, not request-driven.
61
61
  */
62
62
  readonly onProgress?: ProgressListener;
63
+ /**
64
+ * Minimum milliseconds between byte-only progress callbacks. Defaults to
65
+ * the SDK's 100 ms progress interval; set to 0 for per-chunk callbacks.
66
+ * The final completion callback is always emitted immediately.
67
+ */
68
+ readonly progressIntervalMillis?: number;
63
69
  }
64
70
  /** Options for downloading a file by its unique ID. */
65
71
  export interface DownloadByIdOptions extends DownloadCommonOptions {
@@ -77,7 +83,7 @@ export interface DownloadByNameOptions extends DownloadCommonOptions {
77
83
  * Shared HEAD options. Mirrors {@link DownloadCommonOptions} but omits
78
84
  * `method` (always HEAD) and `onProgress` (no body to track).
79
85
  */
80
- type HeadCommonOptions = Omit<DownloadCommonOptions, 'method' | 'onProgress'>;
86
+ type HeadCommonOptions = Omit<DownloadCommonOptions, 'method' | 'onProgress' | 'progressIntervalMillis'>;
81
87
  /** Options for a HEAD-by-ID request. */
82
88
  export interface HeadByIdOptions extends HeadCommonOptions {
83
89
  /** ID of the file version to inspect. */
@@ -1 +1 @@
1
- {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../src/download/single.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"single.d.ts","sourceRoot":"","sources":["../../src/download/single.js"],"names":[],"mappings":"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"}