@backblaze-labs/b2-sdk 0.1.0 → 0.2.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 (701) hide show
  1. package/CHANGELOG.md +110 -5
  2. package/README.md +144 -33
  3. package/dist/_virtual/_b2-sdk-version-json.cjs +4 -0
  4. package/dist/_virtual/_b2-sdk-version-json.js +4 -0
  5. package/dist/auth/account-info.d.cts +32 -0
  6. package/dist/auth/account-info.d.cts.map +1 -1
  7. package/dist/auth/account-info.d.ts +32 -0
  8. package/dist/auth/account-info.d.ts.map +1 -1
  9. package/dist/auth/file.cjs +408 -207
  10. package/dist/auth/file.cjs.map +1 -1
  11. package/dist/auth/file.d.cts +77 -3
  12. package/dist/auth/file.d.cts.map +1 -1
  13. package/dist/auth/file.d.ts +77 -3
  14. package/dist/auth/file.d.ts.map +1 -1
  15. package/dist/auth/file.js +407 -207
  16. package/dist/auth/file.js.map +1 -1
  17. package/dist/auth/in-memory.cjs +212 -183
  18. package/dist/auth/in-memory.cjs.map +1 -1
  19. package/dist/auth/in-memory.d.cts +8 -0
  20. package/dist/auth/in-memory.d.cts.map +1 -1
  21. package/dist/auth/in-memory.d.ts +8 -0
  22. package/dist/auth/in-memory.d.ts.map +1 -1
  23. package/dist/auth/in-memory.js +211 -182
  24. package/dist/auth/in-memory.js.map +1 -1
  25. package/dist/auth/index.cjs +7 -9
  26. package/dist/auth/index.d.cts +3 -2
  27. package/dist/auth/index.d.cts.map +1 -1
  28. package/dist/auth/index.d.ts +3 -2
  29. package/dist/auth/index.d.ts.map +1 -1
  30. package/dist/auth/index.js +2 -8
  31. package/dist/auth/realms.cjs +80 -7
  32. package/dist/auth/realms.cjs.map +1 -1
  33. package/dist/auth/realms.d.cts +27 -4
  34. package/dist/auth/realms.d.cts.map +1 -1
  35. package/dist/auth/realms.d.ts +27 -4
  36. package/dist/auth/realms.d.ts.map +1 -1
  37. package/dist/auth/realms.js +80 -9
  38. package/dist/auth/realms.js.map +1 -1
  39. package/dist/auth/upload-url-pool.cjs +55 -51
  40. package/dist/auth/upload-url-pool.cjs.map +1 -1
  41. package/dist/auth/upload-url-pool.js +55 -51
  42. package/dist/auth/upload-url-pool.js.map +1 -1
  43. package/dist/bucket.cjs +785 -787
  44. package/dist/bucket.cjs.map +1 -1
  45. package/dist/bucket.d.cts +35 -47
  46. package/dist/bucket.d.cts.map +1 -1
  47. package/dist/bucket.d.ts +35 -47
  48. package/dist/bucket.d.ts.map +1 -1
  49. package/dist/bucket.js +780 -782
  50. package/dist/bucket.js.map +1 -1
  51. package/dist/client.cjs +246 -228
  52. package/dist/client.cjs.map +1 -1
  53. package/dist/client.d.cts +25 -17
  54. package/dist/client.d.cts.map +1 -1
  55. package/dist/client.d.ts +25 -17
  56. package/dist/client.d.ts.map +1 -1
  57. package/dist/client.js +243 -225
  58. package/dist/client.js.map +1 -1
  59. package/dist/copy/large.cjs +114 -71
  60. package/dist/copy/large.cjs.map +1 -1
  61. package/dist/copy/large.d.cts +6 -0
  62. package/dist/copy/large.d.cts.map +1 -1
  63. package/dist/copy/large.d.ts +6 -0
  64. package/dist/copy/large.d.ts.map +1 -1
  65. package/dist/copy/large.js +112 -69
  66. package/dist/copy/large.js.map +1 -1
  67. package/dist/download/checksum.cjs +89 -0
  68. package/dist/download/checksum.cjs.map +1 -0
  69. package/dist/download/checksum.d.cts +40 -0
  70. package/dist/download/checksum.d.cts.map +1 -0
  71. package/dist/download/checksum.d.ts +40 -0
  72. package/dist/download/checksum.d.ts.map +1 -0
  73. package/dist/download/checksum.js +87 -0
  74. package/dist/download/checksum.js.map +1 -0
  75. package/dist/download/parallel.cjs +214 -118
  76. package/dist/download/parallel.cjs.map +1 -1
  77. package/dist/download/parallel.d.cts +5 -1
  78. package/dist/download/parallel.d.cts.map +1 -1
  79. package/dist/download/parallel.d.ts +5 -1
  80. package/dist/download/parallel.d.ts.map +1 -1
  81. package/dist/download/parallel.js +212 -116
  82. package/dist/download/parallel.js.map +1 -1
  83. package/dist/download/single.cjs +188 -97
  84. package/dist/download/single.cjs.map +1 -1
  85. package/dist/download/single.d.cts +6 -1
  86. package/dist/download/single.d.cts.map +1 -1
  87. package/dist/download/single.d.ts +6 -1
  88. package/dist/download/single.d.ts.map +1 -1
  89. package/dist/download/single.js +186 -98
  90. package/dist/download/single.js.map +1 -1
  91. package/dist/errors/index.cjs +699 -243
  92. package/dist/errors/index.cjs.map +1 -1
  93. package/dist/errors/index.d.cts +285 -82
  94. package/dist/errors/index.d.cts.map +1 -1
  95. package/dist/errors/index.d.ts +285 -82
  96. package/dist/errors/index.d.ts.map +1 -1
  97. package/dist/errors/index.js +678 -261
  98. package/dist/errors/index.js.map +1 -1
  99. package/dist/http/retry.cjs +45 -28
  100. package/dist/http/retry.cjs.map +1 -1
  101. package/dist/http/retry.d.cts +15 -2
  102. package/dist/http/retry.d.cts.map +1 -1
  103. package/dist/http/retry.d.ts +15 -2
  104. package/dist/http/retry.d.ts.map +1 -1
  105. package/dist/http/retry.js +46 -31
  106. package/dist/http/retry.js.map +1 -1
  107. package/dist/http/transport.cjs +438 -140
  108. package/dist/http/transport.cjs.map +1 -1
  109. package/dist/http/transport.d.cts +21 -2
  110. package/dist/http/transport.d.cts.map +1 -1
  111. package/dist/http/transport.d.ts +21 -2
  112. package/dist/http/transport.d.ts.map +1 -1
  113. package/dist/http/transport.js +437 -140
  114. package/dist/http/transport.js.map +1 -1
  115. package/dist/http/url-guard.cjs +154 -89
  116. package/dist/http/url-guard.cjs.map +1 -1
  117. package/dist/http/url-guard.d.cts +25 -3
  118. package/dist/http/url-guard.d.cts.map +1 -1
  119. package/dist/http/url-guard.d.ts +25 -3
  120. package/dist/http/url-guard.d.ts.map +1 -1
  121. package/dist/http/url-guard.js +152 -90
  122. package/dist/http/url-guard.js.map +1 -1
  123. package/dist/http/user-agent.cjs +84 -44
  124. package/dist/http/user-agent.cjs.map +1 -1
  125. package/dist/http/user-agent.js +84 -46
  126. package/dist/http/user-agent.js.map +1 -1
  127. package/dist/index.cjs +101 -77
  128. package/dist/index.d.cts +27 -21
  129. package/dist/index.d.cts.map +1 -1
  130. package/dist/index.d.ts +27 -21
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +15 -71
  133. package/dist/internal/b2-naming.cjs +66 -0
  134. package/dist/internal/b2-naming.cjs.map +1 -0
  135. package/dist/internal/b2-naming.d.cts +43 -0
  136. package/dist/internal/b2-naming.d.cts.map +1 -0
  137. package/dist/internal/b2-naming.d.ts +43 -0
  138. package/dist/internal/b2-naming.d.ts.map +1 -0
  139. package/dist/internal/b2-naming.js +60 -0
  140. package/dist/internal/b2-naming.js.map +1 -0
  141. package/dist/internal/upload-retry-options.cjs +21 -0
  142. package/dist/internal/upload-retry-options.cjs.map +1 -0
  143. package/dist/internal/upload-retry-options.d.cts +12 -0
  144. package/dist/internal/upload-retry-options.d.cts.map +1 -0
  145. package/dist/internal/upload-retry-options.d.ts +12 -0
  146. package/dist/internal/upload-retry-options.d.ts.map +1 -0
  147. package/dist/internal/upload-retry-options.js +21 -0
  148. package/dist/internal/upload-retry-options.js.map +1 -0
  149. package/dist/internal/url-redaction.cjs +31 -0
  150. package/dist/internal/url-redaction.cjs.map +1 -0
  151. package/dist/internal/url-redaction.d.cts +17 -0
  152. package/dist/internal/url-redaction.d.cts.map +1 -0
  153. package/dist/internal/url-redaction.d.ts +17 -0
  154. package/dist/internal/url-redaction.d.ts.map +1 -0
  155. package/dist/internal/url-redaction.js +31 -0
  156. package/dist/internal/url-redaction.js.map +1 -0
  157. package/dist/notifications/index.cjs +4 -6
  158. package/dist/notifications/index.d.cts +1 -1
  159. package/dist/notifications/index.d.cts.map +1 -1
  160. package/dist/notifications/index.d.ts +1 -1
  161. package/dist/notifications/index.d.ts.map +1 -1
  162. package/dist/notifications/index.js +1 -6
  163. package/dist/notifications/webhook.cjs +195 -85
  164. package/dist/notifications/webhook.cjs.map +1 -1
  165. package/dist/notifications/webhook.d.cts.map +1 -1
  166. package/dist/notifications/webhook.d.ts.map +1 -1
  167. package/dist/notifications/webhook.js +195 -87
  168. package/dist/notifications/webhook.js.map +1 -1
  169. package/dist/object.cjs +253 -210
  170. package/dist/object.cjs.map +1 -1
  171. package/dist/object.d.cts +9 -55
  172. package/dist/object.d.cts.map +1 -1
  173. package/dist/object.d.ts +9 -55
  174. package/dist/object.d.ts.map +1 -1
  175. package/dist/object.js +249 -206
  176. package/dist/object.js.map +1 -1
  177. package/dist/raw/encoding.cjs +74 -35
  178. package/dist/raw/encoding.cjs.map +1 -1
  179. package/dist/raw/encoding.js +74 -38
  180. package/dist/raw/encoding.js.map +1 -1
  181. package/dist/raw/index.cjs +678 -587
  182. package/dist/raw/index.cjs.map +1 -1
  183. package/dist/raw/index.d.cts +121 -18
  184. package/dist/raw/index.d.cts.map +1 -1
  185. package/dist/raw/index.d.ts +121 -18
  186. package/dist/raw/index.d.ts.map +1 -1
  187. package/dist/raw/index.js +674 -589
  188. package/dist/raw/index.js.map +1 -1
  189. package/dist/s3/index.cjs +355 -18
  190. package/dist/s3/index.cjs.map +1 -1
  191. package/dist/s3/index.d.cts +233 -5
  192. package/dist/s3/index.d.cts.map +1 -1
  193. package/dist/s3/index.d.ts +233 -5
  194. package/dist/s3/index.d.ts.map +1 -1
  195. package/dist/s3/index.js +351 -22
  196. package/dist/s3/index.js.map +1 -1
  197. package/dist/s3/sigv4.cjs +149 -0
  198. package/dist/s3/sigv4.cjs.map +1 -0
  199. package/dist/s3/sigv4.d.cts +43 -0
  200. package/dist/s3/sigv4.d.cts.map +1 -0
  201. package/dist/s3/sigv4.d.ts +43 -0
  202. package/dist/s3/sigv4.d.ts.map +1 -0
  203. package/dist/s3/sigv4.js +148 -0
  204. package/dist/s3/sigv4.js.map +1 -0
  205. package/dist/s3/validation.cjs +69 -0
  206. package/dist/s3/validation.cjs.map +1 -0
  207. package/dist/s3/validation.d.cts +43 -0
  208. package/dist/s3/validation.d.cts.map +1 -0
  209. package/dist/s3/validation.d.ts +43 -0
  210. package/dist/s3/validation.d.ts.map +1 -0
  211. package/dist/s3/validation.js +66 -0
  212. package/dist/s3/validation.js.map +1 -0
  213. package/dist/simulator/capabilities.cjs +63 -48
  214. package/dist/simulator/capabilities.cjs.map +1 -1
  215. package/dist/simulator/capabilities.js +63 -49
  216. package/dist/simulator/capabilities.js.map +1 -1
  217. package/dist/simulator/index.cjs +2124 -1548
  218. package/dist/simulator/index.cjs.map +1 -1
  219. package/dist/simulator/index.d.cts +79 -11
  220. package/dist/simulator/index.d.cts.map +1 -1
  221. package/dist/simulator/index.d.ts +79 -11
  222. package/dist/simulator/index.d.ts.map +1 -1
  223. package/dist/simulator/index.js +2112 -1546
  224. package/dist/simulator/index.js.map +1 -1
  225. package/dist/simulator/validation.cjs +191 -153
  226. package/dist/simulator/validation.cjs.map +1 -1
  227. package/dist/simulator/validation.d.cts +3 -21
  228. package/dist/simulator/validation.d.cts.map +1 -1
  229. package/dist/simulator/validation.d.ts +3 -21
  230. package/dist/simulator/validation.d.ts.map +1 -1
  231. package/dist/simulator/validation.js +188 -162
  232. package/dist/simulator/validation.js.map +1 -1
  233. package/dist/streams/collect.cjs +74 -24
  234. package/dist/streams/collect.cjs.map +1 -1
  235. package/dist/streams/collect.d.cts +14 -1
  236. package/dist/streams/collect.d.cts.map +1 -1
  237. package/dist/streams/collect.d.ts +14 -1
  238. package/dist/streams/collect.d.ts.map +1 -1
  239. package/dist/streams/collect.js +74 -25
  240. package/dist/streams/collect.js.map +1 -1
  241. package/dist/streams/file-source.cjs +287 -0
  242. package/dist/streams/file-source.cjs.map +1 -0
  243. package/dist/streams/file-source.d.cts +96 -0
  244. package/dist/streams/file-source.d.cts.map +1 -0
  245. package/dist/streams/file-source.d.ts +96 -0
  246. package/dist/streams/file-source.d.ts.map +1 -0
  247. package/dist/streams/file-source.js +286 -0
  248. package/dist/streams/file-source.js.map +1 -0
  249. package/dist/streams/hash.cjs +207 -115
  250. package/dist/streams/hash.cjs.map +1 -1
  251. package/dist/streams/hash.d.cts +5 -4
  252. package/dist/streams/hash.d.cts.map +1 -1
  253. package/dist/streams/hash.d.ts +5 -4
  254. package/dist/streams/hash.d.ts.map +1 -1
  255. package/dist/streams/hash.js +208 -95
  256. package/dist/streams/hash.js.map +1 -1
  257. package/dist/streams/index.cjs +12 -12
  258. package/dist/streams/index.d.cts +3 -3
  259. package/dist/streams/index.d.cts.map +1 -1
  260. package/dist/streams/index.d.ts +3 -3
  261. package/dist/streams/index.d.ts.map +1 -1
  262. package/dist/streams/index.js +2 -10
  263. package/dist/streams/progress.cjs +60 -46
  264. package/dist/streams/progress.cjs.map +1 -1
  265. package/dist/streams/progress.js +60 -46
  266. package/dist/streams/progress.js.map +1 -1
  267. package/dist/streams/source.cjs +316 -146
  268. package/dist/streams/source.cjs.map +1 -1
  269. package/dist/streams/source.d.cts +56 -18
  270. package/dist/streams/source.d.cts.map +1 -1
  271. package/dist/streams/source.d.ts +56 -18
  272. package/dist/streams/source.d.ts.map +1 -1
  273. package/dist/streams/source.js +312 -149
  274. package/dist/streams/source.js.map +1 -1
  275. package/dist/sync/actions/index.cjs +236 -184
  276. package/dist/sync/actions/index.cjs.map +1 -1
  277. package/dist/sync/actions/index.d.cts +29 -21
  278. package/dist/sync/actions/index.d.cts.map +1 -1
  279. package/dist/sync/actions/index.d.ts +29 -21
  280. package/dist/sync/actions/index.d.ts.map +1 -1
  281. package/dist/sync/actions/index.js +236 -190
  282. package/dist/sync/actions/index.js.map +1 -1
  283. package/dist/sync/b2-sha1-reader.cjs +148 -0
  284. package/dist/sync/b2-sha1-reader.cjs.map +1 -0
  285. package/dist/sync/b2-sha1-reader.d.cts +58 -0
  286. package/dist/sync/b2-sha1-reader.d.cts.map +1 -0
  287. package/dist/sync/b2-sha1-reader.d.ts +58 -0
  288. package/dist/sync/b2-sha1-reader.d.ts.map +1 -0
  289. package/dist/sync/b2-sha1-reader.js +145 -0
  290. package/dist/sync/b2-sha1-reader.js.map +1 -0
  291. package/dist/sync/download-staging.cjs +265 -0
  292. package/dist/sync/download-staging.cjs.map +1 -0
  293. package/dist/sync/download-staging.d.cts +54 -0
  294. package/dist/sync/download-staging.d.cts.map +1 -0
  295. package/dist/sync/download-staging.d.ts +54 -0
  296. package/dist/sync/download-staging.d.ts.map +1 -0
  297. package/dist/sync/download-staging.js +259 -0
  298. package/dist/sync/download-staging.js.map +1 -0
  299. package/dist/sync/filesystem-errors.cjs +32 -0
  300. package/dist/sync/filesystem-errors.cjs.map +1 -0
  301. package/dist/sync/filesystem-errors.d.cts +8 -0
  302. package/dist/sync/filesystem-errors.d.cts.map +1 -0
  303. package/dist/sync/filesystem-errors.d.ts +8 -0
  304. package/dist/sync/filesystem-errors.d.ts.map +1 -0
  305. package/dist/sync/filesystem-errors.js +32 -0
  306. package/dist/sync/filesystem-errors.js.map +1 -0
  307. package/dist/sync/filters.cjs +217 -0
  308. package/dist/sync/filters.cjs.map +1 -0
  309. package/dist/sync/filters.d.cts +51 -0
  310. package/dist/sync/filters.d.cts.map +1 -0
  311. package/dist/sync/filters.d.ts +51 -0
  312. package/dist/sync/filters.d.ts.map +1 -0
  313. package/dist/sync/filters.js +213 -0
  314. package/dist/sync/filters.js.map +1 -0
  315. package/dist/sync/index.cjs +39 -22
  316. package/dist/sync/index.d.cts +14 -9
  317. package/dist/sync/index.d.cts.map +1 -1
  318. package/dist/sync/index.d.ts +14 -9
  319. package/dist/sync/index.d.ts.map +1 -1
  320. package/dist/sync/index.js +9 -20
  321. package/dist/sync/local-file-identity.cjs +61 -0
  322. package/dist/sync/local-file-identity.cjs.map +1 -0
  323. package/dist/sync/local-file-identity.d.cts +37 -0
  324. package/dist/sync/local-file-identity.d.cts.map +1 -0
  325. package/dist/sync/local-file-identity.d.ts +37 -0
  326. package/dist/sync/local-file-identity.d.ts.map +1 -0
  327. package/dist/sync/local-file-identity.js +60 -0
  328. package/dist/sync/local-file-identity.js.map +1 -0
  329. package/dist/sync/local-file-io.cjs +364 -0
  330. package/dist/sync/local-file-io.cjs.map +1 -0
  331. package/dist/sync/local-file-io.d.cts +75 -0
  332. package/dist/sync/local-file-io.d.cts.map +1 -0
  333. package/dist/sync/local-file-io.d.ts +75 -0
  334. package/dist/sync/local-file-io.d.ts.map +1 -0
  335. package/dist/sync/local-file-io.js +360 -0
  336. package/dist/sync/local-file-io.js.map +1 -0
  337. package/dist/sync/local-filesystem-root.cjs +27 -0
  338. package/dist/sync/local-filesystem-root.cjs.map +1 -0
  339. package/dist/sync/local-filesystem-root.d.cts +18 -0
  340. package/dist/sync/local-filesystem-root.d.cts.map +1 -0
  341. package/dist/sync/local-filesystem-root.d.ts +18 -0
  342. package/dist/sync/local-filesystem-root.d.ts.map +1 -0
  343. package/dist/sync/local-filesystem-root.js +26 -0
  344. package/dist/sync/local-filesystem-root.js.map +1 -0
  345. package/dist/sync/local-sha1.cjs +119 -0
  346. package/dist/sync/local-sha1.cjs.map +1 -0
  347. package/dist/sync/local-sha1.d.cts +39 -0
  348. package/dist/sync/local-sha1.d.cts.map +1 -0
  349. package/dist/sync/local-sha1.d.ts +39 -0
  350. package/dist/sync/local-sha1.d.ts.map +1 -0
  351. package/dist/sync/local-sha1.js +117 -0
  352. package/dist/sync/local-sha1.js.map +1 -0
  353. package/dist/sync/pairing.cjs +118 -29
  354. package/dist/sync/pairing.cjs.map +1 -1
  355. package/dist/sync/pairing.d.cts +7 -2
  356. package/dist/sync/pairing.d.cts.map +1 -1
  357. package/dist/sync/pairing.d.ts +7 -2
  358. package/dist/sync/pairing.d.ts.map +1 -1
  359. package/dist/sync/pairing.js +120 -31
  360. package/dist/sync/pairing.js.map +1 -1
  361. package/dist/sync/path-order.cjs +30 -0
  362. package/dist/sync/path-order.cjs.map +1 -0
  363. package/dist/sync/path-order.d.cts +28 -0
  364. package/dist/sync/path-order.d.cts.map +1 -0
  365. package/dist/sync/path-order.d.ts +28 -0
  366. package/dist/sync/path-order.d.ts.map +1 -0
  367. package/dist/sync/path-order.js +29 -0
  368. package/dist/sync/path-order.js.map +1 -0
  369. package/dist/sync/path-safety.cjs +111 -0
  370. package/dist/sync/path-safety.cjs.map +1 -0
  371. package/dist/sync/path-safety.d.cts +78 -0
  372. package/dist/sync/path-safety.d.cts.map +1 -0
  373. package/dist/sync/path-safety.d.ts +78 -0
  374. package/dist/sync/path-safety.d.ts.map +1 -0
  375. package/dist/sync/path-safety.js +105 -0
  376. package/dist/sync/path-safety.js.map +1 -0
  377. package/dist/sync/paths.d.cts +19 -0
  378. package/dist/sync/paths.d.cts.map +1 -0
  379. package/dist/sync/paths.d.ts +19 -0
  380. package/dist/sync/paths.d.ts.map +1 -0
  381. package/dist/sync/policies/compare.cjs +389 -11
  382. package/dist/sync/policies/compare.cjs.map +1 -1
  383. package/dist/sync/policies/compare.d.cts +100 -2
  384. package/dist/sync/policies/compare.d.cts.map +1 -1
  385. package/dist/sync/policies/compare.d.ts +100 -2
  386. package/dist/sync/policies/compare.d.ts.map +1 -1
  387. package/dist/sync/policies/compare.js +387 -13
  388. package/dist/sync/policies/compare.js.map +1 -1
  389. package/dist/sync/policies/index.cjs +76 -65
  390. package/dist/sync/policies/index.cjs.map +1 -1
  391. package/dist/sync/policies/index.d.cts +35 -6
  392. package/dist/sync/policies/index.d.cts.map +1 -1
  393. package/dist/sync/policies/index.d.ts +35 -6
  394. package/dist/sync/policies/index.d.ts.map +1 -1
  395. package/dist/sync/policies/index.js +76 -65
  396. package/dist/sync/policies/index.js.map +1 -1
  397. package/dist/sync/prefix.cjs +96 -0
  398. package/dist/sync/prefix.cjs.map +1 -0
  399. package/dist/sync/prefix.d.cts +55 -0
  400. package/dist/sync/prefix.d.cts.map +1 -0
  401. package/dist/sync/prefix.d.ts +55 -0
  402. package/dist/sync/prefix.d.ts.map +1 -0
  403. package/dist/sync/prefix.js +92 -0
  404. package/dist/sync/prefix.js.map +1 -0
  405. package/dist/sync/regexp-safety.cjs +192 -0
  406. package/dist/sync/regexp-safety.cjs.map +1 -0
  407. package/dist/sync/regexp-safety.d.cts +29 -0
  408. package/dist/sync/regexp-safety.d.cts.map +1 -0
  409. package/dist/sync/regexp-safety.d.ts +29 -0
  410. package/dist/sync/regexp-safety.d.ts.map +1 -0
  411. package/dist/sync/regexp-safety.js +190 -0
  412. package/dist/sync/regexp-safety.js.map +1 -0
  413. package/dist/sync/scan-events.cjs +33 -0
  414. package/dist/sync/scan-events.cjs.map +1 -0
  415. package/dist/sync/scan-events.d.cts +17 -0
  416. package/dist/sync/scan-events.d.cts.map +1 -0
  417. package/dist/sync/scan-events.d.ts +17 -0
  418. package/dist/sync/scan-events.d.ts.map +1 -0
  419. package/dist/sync/scan-events.js +32 -0
  420. package/dist/sync/scan-events.js.map +1 -0
  421. package/dist/sync/scan-limit.cjs +33 -0
  422. package/dist/sync/scan-limit.cjs.map +1 -0
  423. package/dist/sync/scan-limit.d.cts +21 -0
  424. package/dist/sync/scan-limit.d.cts.map +1 -0
  425. package/dist/sync/scan-limit.d.ts +21 -0
  426. package/dist/sync/scan-limit.d.ts.map +1 -0
  427. package/dist/sync/scan-limit.js +31 -0
  428. package/dist/sync/scan-limit.js.map +1 -0
  429. package/dist/sync/scanners/b2.cjs +239 -55
  430. package/dist/sync/scanners/b2.cjs.map +1 -1
  431. package/dist/sync/scanners/b2.d.cts +26 -7
  432. package/dist/sync/scanners/b2.d.cts.map +1 -1
  433. package/dist/sync/scanners/b2.d.ts +26 -7
  434. package/dist/sync/scanners/b2.d.ts.map +1 -1
  435. package/dist/sync/scanners/b2.js +239 -55
  436. package/dist/sync/scanners/b2.js.map +1 -1
  437. package/dist/sync/scanners/local.cjs +215 -56
  438. package/dist/sync/scanners/local.cjs.map +1 -1
  439. package/dist/sync/scanners/local.d.cts +22 -7
  440. package/dist/sync/scanners/local.d.cts.map +1 -1
  441. package/dist/sync/scanners/local.d.ts +22 -7
  442. package/dist/sync/scanners/local.d.ts.map +1 -1
  443. package/dist/sync/scanners/local.js +216 -57
  444. package/dist/sync/scanners/local.js.map +1 -1
  445. package/dist/sync/sha1-metadata.cjs +94 -0
  446. package/dist/sync/sha1-metadata.cjs.map +1 -0
  447. package/dist/sync/sha1-metadata.d.cts +82 -0
  448. package/dist/sync/sha1-metadata.d.cts.map +1 -0
  449. package/dist/sync/sha1-metadata.d.ts +82 -0
  450. package/dist/sync/sha1-metadata.d.ts.map +1 -0
  451. package/dist/sync/sha1-metadata.js +89 -0
  452. package/dist/sync/sha1-metadata.js.map +1 -0
  453. package/dist/sync/sha1-options.cjs +23 -0
  454. package/dist/sync/sha1-options.cjs.map +1 -0
  455. package/dist/sync/sha1-options.d.cts +14 -0
  456. package/dist/sync/sha1-options.d.cts.map +1 -0
  457. package/dist/sync/sha1-options.d.ts +14 -0
  458. package/dist/sync/sha1-options.d.ts.map +1 -0
  459. package/dist/sync/sha1-options.js +21 -0
  460. package/dist/sync/sha1-options.js.map +1 -0
  461. package/dist/sync/synchronizer.cjs +782 -197
  462. package/dist/sync/synchronizer.cjs.map +1 -1
  463. package/dist/sync/synchronizer.d.cts +47 -1
  464. package/dist/sync/synchronizer.d.cts.map +1 -1
  465. package/dist/sync/synchronizer.d.ts +47 -1
  466. package/dist/sync/synchronizer.d.ts.map +1 -1
  467. package/dist/sync/synchronizer.js +779 -173
  468. package/dist/sync/synchronizer.js.map +1 -1
  469. package/dist/sync/types.d.cts +208 -16
  470. package/dist/sync/types.d.cts.map +1 -1
  471. package/dist/sync/types.d.ts +208 -16
  472. package/dist/sync/types.d.ts.map +1 -1
  473. package/dist/types/auth.cjs +76 -56
  474. package/dist/types/auth.cjs.map +1 -1
  475. package/dist/types/auth.d.cts +67 -9
  476. package/dist/types/auth.d.cts.map +1 -1
  477. package/dist/types/auth.d.ts +67 -9
  478. package/dist/types/auth.d.ts.map +1 -1
  479. package/dist/types/auth.js +77 -57
  480. package/dist/types/auth.js.map +1 -1
  481. package/dist/types/bucket.cjs +74 -38
  482. package/dist/types/bucket.cjs.map +1 -1
  483. package/dist/types/bucket.js +75 -41
  484. package/dist/types/bucket.js.map +1 -1
  485. package/dist/types/encryption.cjs +364 -327
  486. package/dist/types/encryption.cjs.map +1 -1
  487. package/dist/types/encryption.d.cts +16 -0
  488. package/dist/types/encryption.d.cts.map +1 -1
  489. package/dist/types/encryption.d.ts +16 -0
  490. package/dist/types/encryption.d.ts.map +1 -1
  491. package/dist/types/encryption.js +364 -310
  492. package/dist/types/encryption.js.map +1 -1
  493. package/dist/types/errors.cjs +47 -0
  494. package/dist/types/errors.cjs.map +1 -0
  495. package/dist/types/errors.d.cts +13 -4
  496. package/dist/types/errors.d.cts.map +1 -1
  497. package/dist/types/errors.d.ts +13 -4
  498. package/dist/types/errors.d.ts.map +1 -1
  499. package/dist/types/errors.js +47 -0
  500. package/dist/types/errors.js.map +1 -0
  501. package/dist/types/file.cjs +36 -19
  502. package/dist/types/file.cjs.map +1 -1
  503. package/dist/types/file.d.cts +2 -2
  504. package/dist/types/file.d.cts.map +1 -1
  505. package/dist/types/file.d.ts +2 -2
  506. package/dist/types/file.d.ts.map +1 -1
  507. package/dist/types/file.js +37 -21
  508. package/dist/types/file.js.map +1 -1
  509. package/dist/types/ids.cjs +53 -9
  510. package/dist/types/ids.cjs.map +1 -1
  511. package/dist/types/ids.js +54 -15
  512. package/dist/types/ids.js.map +1 -1
  513. package/dist/types/index.d.cts +12 -11
  514. package/dist/types/index.d.cts.map +1 -1
  515. package/dist/types/index.d.ts +12 -11
  516. package/dist/types/index.d.ts.map +1 -1
  517. package/dist/types/key.d.cts +44 -8
  518. package/dist/types/key.d.cts.map +1 -1
  519. package/dist/types/key.d.ts +44 -8
  520. package/dist/types/key.d.ts.map +1 -1
  521. package/dist/types/lock.cjs +33 -13
  522. package/dist/types/lock.cjs.map +1 -1
  523. package/dist/types/lock.js +34 -15
  524. package/dist/types/lock.js.map +1 -1
  525. package/dist/types/notifications.cjs +44 -22
  526. package/dist/types/notifications.cjs.map +1 -1
  527. package/dist/types/notifications.js +45 -23
  528. package/dist/types/notifications.js.map +1 -1
  529. package/dist/types/upload.d.cts +39 -5
  530. package/dist/types/upload.d.cts.map +1 -1
  531. package/dist/types/upload.d.ts +39 -5
  532. package/dist/types/upload.d.ts.map +1 -1
  533. package/dist/upload/abort-scope.cjs +91 -0
  534. package/dist/upload/abort-scope.cjs.map +1 -0
  535. package/dist/upload/abort-scope.d.cts +48 -0
  536. package/dist/upload/abort-scope.d.cts.map +1 -0
  537. package/dist/upload/abort-scope.d.ts +48 -0
  538. package/dist/upload/abort-scope.d.ts.map +1 -0
  539. package/dist/upload/abort-scope.js +88 -0
  540. package/dist/upload/abort-scope.js.map +1 -0
  541. package/dist/upload/cancel.cjs +183 -8
  542. package/dist/upload/cancel.cjs.map +1 -1
  543. package/dist/upload/cancel.d.cts +110 -2
  544. package/dist/upload/cancel.d.cts.map +1 -1
  545. package/dist/upload/cancel.d.ts +110 -2
  546. package/dist/upload/cancel.d.ts.map +1 -1
  547. package/dist/upload/cancel.js +178 -9
  548. package/dist/upload/cancel.js.map +1 -1
  549. package/dist/upload/concurrency.cjs +79 -52
  550. package/dist/upload/concurrency.cjs.map +1 -1
  551. package/dist/upload/concurrency.js +79 -53
  552. package/dist/upload/concurrency.js.map +1 -1
  553. package/dist/upload/finish.cjs +59 -0
  554. package/dist/upload/finish.cjs.map +1 -0
  555. package/dist/upload/finish.d.cts +26 -0
  556. package/dist/upload/finish.d.cts.map +1 -0
  557. package/dist/upload/finish.d.ts +26 -0
  558. package/dist/upload/finish.d.ts.map +1 -0
  559. package/dist/upload/finish.js +59 -0
  560. package/dist/upload/finish.js.map +1 -0
  561. package/dist/upload/large.cjs +301 -218
  562. package/dist/upload/large.cjs.map +1 -1
  563. package/dist/upload/large.d.cts +76 -9
  564. package/dist/upload/large.d.cts.map +1 -1
  565. package/dist/upload/large.d.ts +76 -9
  566. package/dist/upload/large.d.ts.map +1 -1
  567. package/dist/upload/large.js +301 -218
  568. package/dist/upload/large.js.map +1 -1
  569. package/dist/upload/options.cjs +28 -0
  570. package/dist/upload/options.cjs.map +1 -0
  571. package/dist/upload/options.d.cts +104 -0
  572. package/dist/upload/options.d.cts.map +1 -0
  573. package/dist/upload/options.d.ts +104 -0
  574. package/dist/upload/options.d.ts.map +1 -0
  575. package/dist/upload/options.js +27 -0
  576. package/dist/upload/options.js.map +1 -0
  577. package/dist/upload/resume.cjs +333 -33
  578. package/dist/upload/resume.cjs.map +1 -1
  579. package/dist/upload/resume.d.cts +82 -12
  580. package/dist/upload/resume.d.cts.map +1 -1
  581. package/dist/upload/resume.d.ts +82 -12
  582. package/dist/upload/resume.d.ts.map +1 -1
  583. package/dist/upload/resume.js +330 -33
  584. package/dist/upload/resume.js.map +1 -1
  585. package/dist/upload/retry.cjs +186 -0
  586. package/dist/upload/retry.cjs.map +1 -0
  587. package/dist/upload/retry.d.cts +127 -0
  588. package/dist/upload/retry.d.cts.map +1 -0
  589. package/dist/upload/retry.d.ts +127 -0
  590. package/dist/upload/retry.d.ts.map +1 -0
  591. package/dist/upload/retry.js +182 -0
  592. package/dist/upload/retry.js.map +1 -0
  593. package/dist/upload/single.cjs +68 -44
  594. package/dist/upload/single.cjs.map +1 -1
  595. package/dist/upload/single.d.cts +2 -1
  596. package/dist/upload/single.d.cts.map +1 -1
  597. package/dist/upload/single.d.ts +2 -1
  598. package/dist/upload/single.d.ts.map +1 -1
  599. package/dist/upload/single.js +68 -44
  600. package/dist/upload/single.js.map +1 -1
  601. package/dist/upload/stream.cjs +317 -193
  602. package/dist/upload/stream.cjs.map +1 -1
  603. package/dist/upload/stream.d.cts +3 -1
  604. package/dist/upload/stream.d.cts.map +1 -1
  605. package/dist/upload/stream.d.ts +3 -1
  606. package/dist/upload/stream.d.ts.map +1 -1
  607. package/dist/upload/stream.js +316 -192
  608. package/dist/upload/stream.js.map +1 -1
  609. package/dist/util/best-effort.cjs +42 -8
  610. package/dist/util/best-effort.cjs.map +1 -1
  611. package/dist/util/best-effort.d.cts +2 -1
  612. package/dist/util/best-effort.d.cts.map +1 -1
  613. package/dist/util/best-effort.d.ts +2 -1
  614. package/dist/util/best-effort.d.ts.map +1 -1
  615. package/dist/util/best-effort.js +43 -9
  616. package/dist/util/best-effort.js.map +1 -1
  617. package/dist/util/bytes.cjs +23 -0
  618. package/dist/util/bytes.cjs.map +1 -0
  619. package/dist/util/bytes.d.cts +15 -0
  620. package/dist/util/bytes.d.cts.map +1 -0
  621. package/dist/util/bytes.d.ts +15 -0
  622. package/dist/util/bytes.d.ts.map +1 -0
  623. package/dist/util/bytes.js +23 -0
  624. package/dist/util/bytes.js.map +1 -0
  625. package/dist/util/crypto.cjs +68 -0
  626. package/dist/util/crypto.cjs.map +1 -0
  627. package/dist/util/crypto.d.cts +26 -0
  628. package/dist/util/crypto.d.cts.map +1 -0
  629. package/dist/util/crypto.d.ts +26 -0
  630. package/dist/util/crypto.d.ts.map +1 -0
  631. package/dist/util/crypto.js +66 -0
  632. package/dist/util/crypto.js.map +1 -0
  633. package/dist/util/defaults.cjs +25 -9
  634. package/dist/util/defaults.cjs.map +1 -1
  635. package/dist/util/defaults.js +26 -11
  636. package/dist/util/defaults.js.map +1 -1
  637. package/dist/util/error-reason.cjs +41 -0
  638. package/dist/util/error-reason.cjs.map +1 -0
  639. package/dist/util/error-reason.d.cts +9 -0
  640. package/dist/util/error-reason.d.cts.map +1 -0
  641. package/dist/util/error-reason.d.ts +9 -0
  642. package/dist/util/error-reason.d.ts.map +1 -0
  643. package/dist/util/error-reason.js +41 -0
  644. package/dist/util/error-reason.js.map +1 -0
  645. package/dist/util/http.cjs +23 -0
  646. package/dist/util/http.cjs.map +1 -0
  647. package/dist/util/http.d.cts +13 -0
  648. package/dist/util/http.d.cts.map +1 -0
  649. package/dist/util/http.d.ts +13 -0
  650. package/dist/util/http.d.ts.map +1 -0
  651. package/dist/util/http.js +23 -0
  652. package/dist/util/http.js.map +1 -0
  653. package/dist/util/normalize.cjs +66 -7
  654. package/dist/util/normalize.cjs.map +1 -1
  655. package/dist/util/normalize.js +67 -10
  656. package/dist/util/normalize.js.map +1 -1
  657. package/dist/util/paginator.cjs +63 -14
  658. package/dist/util/paginator.cjs.map +1 -1
  659. package/dist/util/paginator.js +64 -16
  660. package/dist/util/paginator.js.map +1 -1
  661. package/dist/util/plan-ranges.cjs +47 -22
  662. package/dist/util/plan-ranges.cjs.map +1 -1
  663. package/dist/util/plan-ranges.js +48 -24
  664. package/dist/util/plan-ranges.js.map +1 -1
  665. package/dist/util/sha1.cjs +27 -0
  666. package/dist/util/sha1.cjs.map +1 -0
  667. package/dist/util/sha1.d.cts +17 -0
  668. package/dist/util/sha1.d.cts.map +1 -0
  669. package/dist/util/sha1.d.ts +17 -0
  670. package/dist/util/sha1.d.ts.map +1 -0
  671. package/dist/util/sha1.js +26 -0
  672. package/dist/util/sha1.js.map +1 -0
  673. package/dist/util/text-codec.cjs +29 -5
  674. package/dist/util/text-codec.cjs.map +1 -1
  675. package/dist/util/text-codec.js +30 -7
  676. package/dist/util/text-codec.js.map +1 -1
  677. package/dist/util/to-error.cjs +18 -4
  678. package/dist/util/to-error.cjs.map +1 -1
  679. package/dist/util/to-error.js +19 -5
  680. package/dist/util/to-error.js.map +1 -1
  681. package/dist/version.cjs +17 -5
  682. package/dist/version.cjs.map +1 -1
  683. package/dist/version.d.cts +3 -3
  684. package/dist/version.d.ts +3 -3
  685. package/dist/version.js +19 -6
  686. package/dist/version.js.map +1 -1
  687. package/package.json +19 -16
  688. package/dist/auth/index.cjs.map +0 -1
  689. package/dist/auth/index.js.map +0 -1
  690. package/dist/index.cjs.map +0 -1
  691. package/dist/index.js.map +0 -1
  692. package/dist/notifications/index.cjs.map +0 -1
  693. package/dist/notifications/index.js.map +0 -1
  694. package/dist/package.json.cjs +0 -9
  695. package/dist/package.json.cjs.map +0 -1
  696. package/dist/package.json.js +0 -9
  697. package/dist/package.json.js.map +0 -1
  698. package/dist/streams/index.cjs.map +0 -1
  699. package/dist/streams/index.js.map +0 -1
  700. package/dist/sync/index.cjs.map +0 -1
  701. package/dist/sync/index.js.map +0 -1
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Reads one non-empty stream chunk with an idle timeout and optional abort signal.
3
+ * Empty chunks are not progress; too many consecutive empty chunks fail with the
4
+ * same stalled-read diagnostic used for pending reads.
5
+ *
6
+ * @param reader - Locked reader to read from.
7
+ * @param timeoutMillis - Idle timeout in milliseconds for this read.
8
+ * @param stalledMessage - Error message used when the read makes no progress.
9
+ * @param signal - Optional abort signal to observe while reading.
10
+ *
11
+ * @returns The next stream read result.
12
+ *
13
+ * @internal
14
+ */
15
+ export declare function readStreamChunkWithTimeout(reader: ReadableStreamDefaultReader<Uint8Array>, timeoutMillis: number, stalledMessage: string, signal?: AbortSignal): Promise<ReadableStreamReadResult<Uint8Array>>;
16
+ /**
17
+ * Hashes a B2 response body as SHA-1 with idle timeout, abort, and size checks.
18
+ *
19
+ * @param body - Response body stream to hash.
20
+ * @param signal - Optional abort signal to observe while reading.
21
+ * @param options - Optional timeout and byte-count limits.
22
+ *
23
+ * @returns The computed SHA-1 and number of bytes read.
24
+ *
25
+ * @internal
26
+ */
27
+ export declare function hashReadableStreamSha1(body: ReadableStream<Uint8Array>, signal?: AbortSignal, options?: {
28
+ readonly idleTimeoutMillis: number;
29
+ readonly maxBytes: number;
30
+ readonly expectedBytes: number;
31
+ }): Promise<{
32
+ readonly contentSha1: string;
33
+ readonly bytesRead: number;
34
+ }>;
35
+ /**
36
+ * Applies an absolute verification deadline while forwarding parent aborts.
37
+ *
38
+ * @param signal - Optional parent abort signal.
39
+ * @param timeoutMillis - Absolute deadline in milliseconds.
40
+ * @param run - Operation to run with the derived deadline signal.
41
+ *
42
+ * @returns The operation result.
43
+ *
44
+ * @internal
45
+ */
46
+ export declare function withSha1VerificationDeadline<T>(signal: AbortSignal | undefined, timeoutMillis: number, run: (signal: AbortSignal) => Promise<T>): Promise<T>;
47
+ /**
48
+ * Bounds B2 SHA-1 verification downloads to the selected object's size and optional ceiling.
49
+ *
50
+ * @param contentLength - Selected B2 object byte length.
51
+ * @param ceiling - Optional lower verification budget.
52
+ *
53
+ * @returns The byte budget to enforce.
54
+ *
55
+ * @internal
56
+ */
57
+ export declare function normalizeSha1VerificationMaxBytes(contentLength: number, ceiling: number | undefined): number;
58
+ //# sourceMappingURL=b2-sha1-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"b2-sha1-reader.d.ts","sourceRoot":"","sources":["../../src/sync/b2-sha1-reader.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;GAaG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,2BAA2B,CAAC,UAAU,CAAC,EAC/C,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAe/C;AA2CD;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B,GACA,OAAO,CAAC;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCvE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAClD,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACvC,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,iCAAiC,CAC/C,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,MAAM,CAKR"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Reads one non-empty stream chunk with an idle timeout and optional abort signal.
3
+ * Empty chunks are not progress; too many consecutive empty chunks fail with the
4
+ * same stalled-read diagnostic used for pending reads.
5
+ *
6
+ * @param reader - Locked reader to read from.
7
+ * @param timeoutMillis - Idle timeout in milliseconds for this read.
8
+ * @param stalledMessage - Error message used when the read makes no progress.
9
+ * @param signal - Optional abort signal to observe while reading.
10
+ *
11
+ * @returns The next stream read result.
12
+ *
13
+ * @internal
14
+ */
15
+ export declare function readStreamChunkWithTimeout(reader: ReadableStreamDefaultReader<Uint8Array>, timeoutMillis: number, stalledMessage: string, signal?: AbortSignal): Promise<ReadableStreamReadResult<Uint8Array>>;
16
+ /**
17
+ * Hashes a B2 response body as SHA-1 with idle timeout, abort, and size checks.
18
+ *
19
+ * @param body - Response body stream to hash.
20
+ * @param signal - Optional abort signal to observe while reading.
21
+ * @param options - Optional timeout and byte-count limits.
22
+ *
23
+ * @returns The computed SHA-1 and number of bytes read.
24
+ *
25
+ * @internal
26
+ */
27
+ export declare function hashReadableStreamSha1(body: ReadableStream<Uint8Array>, signal?: AbortSignal, options?: {
28
+ readonly idleTimeoutMillis: number;
29
+ readonly maxBytes: number;
30
+ readonly expectedBytes: number;
31
+ }): Promise<{
32
+ readonly contentSha1: string;
33
+ readonly bytesRead: number;
34
+ }>;
35
+ /**
36
+ * Applies an absolute verification deadline while forwarding parent aborts.
37
+ *
38
+ * @param signal - Optional parent abort signal.
39
+ * @param timeoutMillis - Absolute deadline in milliseconds.
40
+ * @param run - Operation to run with the derived deadline signal.
41
+ *
42
+ * @returns The operation result.
43
+ *
44
+ * @internal
45
+ */
46
+ export declare function withSha1VerificationDeadline<T>(signal: AbortSignal | undefined, timeoutMillis: number, run: (signal: AbortSignal) => Promise<T>): Promise<T>;
47
+ /**
48
+ * Bounds B2 SHA-1 verification downloads to the selected object's size and optional ceiling.
49
+ *
50
+ * @param contentLength - Selected B2 object byte length.
51
+ * @param ceiling - Optional lower verification budget.
52
+ *
53
+ * @returns The byte budget to enforce.
54
+ *
55
+ * @internal
56
+ */
57
+ export declare function normalizeSha1VerificationMaxBytes(contentLength: number, ceiling: number | undefined): number;
58
+ //# sourceMappingURL=b2-sha1-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"b2-sha1-reader.d.ts","sourceRoot":"","sources":["../../src/sync/b2-sha1-reader.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;GAaG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,2BAA2B,CAAC,UAAU,CAAC,EAC/C,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAe/C;AA2CD;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B,GACA,OAAO,CAAC;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCvE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAClD,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACvC,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,iCAAiC,CAC/C,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,MAAM,CAKR"}
@@ -0,0 +1,145 @@
1
+ import { IncrementalSha1 } from "../streams/hash.js";
2
+ import { normalizeSha1TimeoutMillis } from "./sha1-options.js";
3
+ //#region src/sync/b2-sha1-reader.ts
4
+ var MAX_CONSECUTIVE_EMPTY_READ_CHUNKS = 1024;
5
+ /**
6
+ * Reads one non-empty stream chunk with an idle timeout and optional abort signal.
7
+ * Empty chunks are not progress; too many consecutive empty chunks fail with the
8
+ * same stalled-read diagnostic used for pending reads.
9
+ *
10
+ * @param reader - Locked reader to read from.
11
+ * @param timeoutMillis - Idle timeout in milliseconds for this read.
12
+ * @param stalledMessage - Error message used when the read makes no progress.
13
+ * @param signal - Optional abort signal to observe while reading.
14
+ *
15
+ * @returns The next stream read result.
16
+ *
17
+ * @internal
18
+ */
19
+ async function readStreamChunkWithTimeout(reader, timeoutMillis, stalledMessage, signal) {
20
+ let emptyChunks = 0;
21
+ while (true) {
22
+ const result = await readRawStreamChunkWithTimeout(reader, timeoutMillis, stalledMessage, signal);
23
+ if (result.done || result.value.byteLength > 0) return result;
24
+ emptyChunks += 1;
25
+ if (emptyChunks > MAX_CONSECUTIVE_EMPTY_READ_CHUNKS) throw new Error(stalledMessage);
26
+ }
27
+ }
28
+ async function readRawStreamChunkWithTimeout(reader, timeoutMillis, stalledMessage, signal) {
29
+ signal?.throwIfAborted();
30
+ let timeout;
31
+ let removeAbortListener;
32
+ const readPromise = reader.read();
33
+ const timeoutPromise = timeoutMillis === Number.POSITIVE_INFINITY ? void 0 : new Promise((_, reject) => {
34
+ timeout = setTimeout(() => {
35
+ reject(new Error(stalledMessage));
36
+ }, timeoutMillis);
37
+ });
38
+ const abortPromise = signal === void 0 ? void 0 : new Promise((_, reject) => {
39
+ const onAbort = () => reject(signal.reason ?? /* @__PURE__ */ new Error("aborted"));
40
+ signal.addEventListener("abort", onAbort, { once: true });
41
+ removeAbortListener = () => signal.removeEventListener("abort", onAbort);
42
+ });
43
+ try {
44
+ if (timeoutPromise === void 0 && abortPromise === void 0) return await readPromise;
45
+ const candidates = [readPromise];
46
+ if (timeoutPromise !== void 0) candidates.push(timeoutPromise);
47
+ if (abortPromise !== void 0) candidates.push(abortPromise);
48
+ return await Promise.race(candidates);
49
+ } finally {
50
+ if (timeout !== void 0) clearTimeout(timeout);
51
+ removeAbortListener?.();
52
+ readPromise.catch(() => {});
53
+ }
54
+ }
55
+ /**
56
+ * Hashes a B2 response body as SHA-1 with idle timeout, abort, and size checks.
57
+ *
58
+ * @param body - Response body stream to hash.
59
+ * @param signal - Optional abort signal to observe while reading.
60
+ * @param options - Optional timeout and byte-count limits.
61
+ *
62
+ * @returns The computed SHA-1 and number of bytes read.
63
+ *
64
+ * @internal
65
+ */
66
+ async function hashReadableStreamSha1(body, signal, options) {
67
+ const hash = new IncrementalSha1();
68
+ const reader = body.getReader();
69
+ const idleTimeoutMillis = options?.idleTimeoutMillis ?? normalizeSha1TimeoutMillis(void 0);
70
+ const maxBytes = options?.maxBytes ?? Number.POSITIVE_INFINITY;
71
+ const expectedBytes = options?.expectedBytes;
72
+ let bytesRead = 0;
73
+ try {
74
+ while (true) {
75
+ const { done, value } = await readStreamChunkWithTimeout(reader, idleTimeoutMillis, `sha1 B2 read stalled for ${idleTimeoutMillis} ms`, signal);
76
+ if (done) break;
77
+ bytesRead += value.byteLength;
78
+ if (bytesRead > maxBytes) throw new Error(`sha1 B2 read exceeded ${maxBytes} byte verification budget`);
79
+ await hash.update(value);
80
+ }
81
+ if (expectedBytes !== void 0 && bytesRead !== expectedBytes) throw new Error(`sha1 B2 read ended after ${bytesRead} bytes, expected ${expectedBytes}`);
82
+ return {
83
+ contentSha1: await hash.digest(),
84
+ bytesRead
85
+ };
86
+ } catch (err) {
87
+ reader.cancel(err).catch(() => {});
88
+ throw err;
89
+ } finally {
90
+ reader.releaseLock();
91
+ }
92
+ }
93
+ /**
94
+ * Applies an absolute verification deadline while forwarding parent aborts.
95
+ *
96
+ * @param signal - Optional parent abort signal.
97
+ * @param timeoutMillis - Absolute deadline in milliseconds.
98
+ * @param run - Operation to run with the derived deadline signal.
99
+ *
100
+ * @returns The operation result.
101
+ *
102
+ * @internal
103
+ */
104
+ async function withSha1VerificationDeadline(signal, timeoutMillis, run) {
105
+ const controller = new AbortController();
106
+ const abortFromParent = () => controller.abort(signal?.reason);
107
+ if (signal?.aborted) abortFromParent();
108
+ signal?.addEventListener("abort", abortFromParent, { once: true });
109
+ let timeout;
110
+ const timeoutPromise = new Promise((_, reject) => {
111
+ timeout = setTimeout(() => {
112
+ const error = /* @__PURE__ */ new Error(`sha1 B2 verification exceeded ${timeoutMillis} ms`);
113
+ controller.abort(error);
114
+ reject(error);
115
+ }, timeoutMillis);
116
+ });
117
+ const runPromise = run(controller.signal);
118
+ try {
119
+ return await Promise.race([runPromise, timeoutPromise]);
120
+ } finally {
121
+ if (timeout !== void 0) clearTimeout(timeout);
122
+ signal?.removeEventListener("abort", abortFromParent);
123
+ runPromise.catch(() => {});
124
+ }
125
+ }
126
+ /**
127
+ * Bounds B2 SHA-1 verification downloads to the selected object's size and optional ceiling.
128
+ *
129
+ * @param contentLength - Selected B2 object byte length.
130
+ * @param ceiling - Optional lower verification budget.
131
+ *
132
+ * @returns The byte budget to enforce.
133
+ *
134
+ * @internal
135
+ */
136
+ function normalizeSha1VerificationMaxBytes(contentLength, ceiling) {
137
+ const contentBudget = Math.max(0, Math.floor(contentLength));
138
+ if (ceiling === void 0) return contentBudget;
139
+ if (!Number.isFinite(ceiling) || ceiling < 0) return contentBudget;
140
+ return Math.min(contentBudget, Math.floor(ceiling));
141
+ }
142
+ //#endregion
143
+ export { hashReadableStreamSha1, normalizeSha1VerificationMaxBytes, readStreamChunkWithTimeout, withSha1VerificationDeadline };
144
+
145
+ //# sourceMappingURL=b2-sha1-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"b2-sha1-reader.js","names":[],"sources":["../../src/sync/b2-sha1-reader.ts"],"sourcesContent":["import { IncrementalSha1 } from '../streams/hash.ts'\nimport { normalizeSha1TimeoutMillis } from './sha1-options.ts'\n\nconst MAX_CONSECUTIVE_EMPTY_READ_CHUNKS = 1024\n\n/**\n * Reads one non-empty stream chunk with an idle timeout and optional abort signal.\n * Empty chunks are not progress; too many consecutive empty chunks fail with the\n * same stalled-read diagnostic used for pending reads.\n *\n * @param reader - Locked reader to read from.\n * @param timeoutMillis - Idle timeout in milliseconds for this read.\n * @param stalledMessage - Error message used when the read makes no progress.\n * @param signal - Optional abort signal to observe while reading.\n *\n * @returns The next stream read result.\n *\n * @internal\n */\nexport async function readStreamChunkWithTimeout(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n timeoutMillis: number,\n stalledMessage: string,\n signal?: AbortSignal,\n): Promise<ReadableStreamReadResult<Uint8Array>> {\n let emptyChunks = 0\n while (true) {\n const result = await readRawStreamChunkWithTimeout(\n reader,\n timeoutMillis,\n stalledMessage,\n signal,\n )\n if (result.done || result.value.byteLength > 0) return result\n emptyChunks += 1\n if (emptyChunks > MAX_CONSECUTIVE_EMPTY_READ_CHUNKS) {\n throw new Error(stalledMessage)\n }\n }\n}\n\nasync function readRawStreamChunkWithTimeout(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n timeoutMillis: number,\n stalledMessage: string,\n signal?: AbortSignal,\n): Promise<ReadableStreamReadResult<Uint8Array>> {\n signal?.throwIfAborted()\n\n let timeout: ReturnType<typeof setTimeout> | undefined\n let removeAbortListener: (() => void) | undefined\n const readPromise = reader.read()\n const timeoutPromise =\n timeoutMillis === Number.POSITIVE_INFINITY\n ? undefined\n : new Promise<never>((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error(stalledMessage))\n }, timeoutMillis)\n })\n const abortPromise =\n signal === undefined\n ? undefined\n : new Promise<never>((_, reject) => {\n const onAbort = () => reject(signal.reason ?? new Error('aborted'))\n signal.addEventListener('abort', onAbort, { once: true })\n removeAbortListener = () => signal.removeEventListener('abort', onAbort)\n })\n\n try {\n if (timeoutPromise === undefined && abortPromise === undefined) return await readPromise\n const candidates = [readPromise]\n if (timeoutPromise !== undefined) candidates.push(timeoutPromise)\n if (abortPromise !== undefined) candidates.push(abortPromise)\n return await Promise.race(candidates)\n } finally {\n if (timeout !== undefined) clearTimeout(timeout)\n removeAbortListener?.()\n void readPromise.catch(() => {})\n }\n}\n\n/**\n * Hashes a B2 response body as SHA-1 with idle timeout, abort, and size checks.\n *\n * @param body - Response body stream to hash.\n * @param signal - Optional abort signal to observe while reading.\n * @param options - Optional timeout and byte-count limits.\n *\n * @returns The computed SHA-1 and number of bytes read.\n *\n * @internal\n */\nexport async function hashReadableStreamSha1(\n body: ReadableStream<Uint8Array>,\n signal?: AbortSignal,\n options?: {\n readonly idleTimeoutMillis: number\n readonly maxBytes: number\n readonly expectedBytes: number\n },\n): Promise<{ readonly contentSha1: string; readonly bytesRead: number }> {\n const hash = new IncrementalSha1()\n const reader = body.getReader()\n const idleTimeoutMillis = options?.idleTimeoutMillis ?? normalizeSha1TimeoutMillis(undefined)\n const maxBytes = options?.maxBytes ?? Number.POSITIVE_INFINITY\n const expectedBytes = options?.expectedBytes\n let bytesRead = 0\n try {\n while (true) {\n const { done, value } = await readStreamChunkWithTimeout(\n reader,\n idleTimeoutMillis,\n `sha1 B2 read stalled for ${idleTimeoutMillis} ms`,\n signal,\n )\n if (done) break\n bytesRead += value.byteLength\n if (bytesRead > maxBytes) {\n throw new Error(`sha1 B2 read exceeded ${maxBytes} byte verification budget`)\n }\n await hash.update(value)\n }\n if (expectedBytes !== undefined && bytesRead !== expectedBytes) {\n throw new Error(`sha1 B2 read ended after ${bytesRead} bytes, expected ${expectedBytes}`)\n }\n return { contentSha1: await hash.digest(), bytesRead }\n } catch (err) {\n void reader.cancel(err).catch(() => {})\n throw err\n } finally {\n reader.releaseLock()\n }\n}\n\n/**\n * Applies an absolute verification deadline while forwarding parent aborts.\n *\n * @param signal - Optional parent abort signal.\n * @param timeoutMillis - Absolute deadline in milliseconds.\n * @param run - Operation to run with the derived deadline signal.\n *\n * @returns The operation result.\n *\n * @internal\n */\nexport async function withSha1VerificationDeadline<T>(\n signal: AbortSignal | undefined,\n timeoutMillis: number,\n run: (signal: AbortSignal) => Promise<T>,\n): Promise<T> {\n const controller = new AbortController()\n const abortFromParent = () => controller.abort(signal?.reason)\n if (signal?.aborted) abortFromParent()\n signal?.addEventListener('abort', abortFromParent, { once: true })\n\n let timeout: ReturnType<typeof setTimeout> | undefined\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeout = setTimeout(() => {\n const error = new Error(`sha1 B2 verification exceeded ${timeoutMillis} ms`)\n controller.abort(error)\n reject(error)\n }, timeoutMillis)\n })\n const runPromise = run(controller.signal)\n try {\n return await Promise.race([runPromise, timeoutPromise])\n } finally {\n if (timeout !== undefined) clearTimeout(timeout)\n signal?.removeEventListener('abort', abortFromParent)\n void runPromise.catch(() => {})\n }\n}\n\n/**\n * Bounds B2 SHA-1 verification downloads to the selected object's size and optional ceiling.\n *\n * @param contentLength - Selected B2 object byte length.\n * @param ceiling - Optional lower verification budget.\n *\n * @returns The byte budget to enforce.\n *\n * @internal\n */\nexport function normalizeSha1VerificationMaxBytes(\n contentLength: number,\n ceiling: number | undefined,\n): number {\n const contentBudget = Math.max(0, Math.floor(contentLength))\n if (ceiling === undefined) return contentBudget\n if (!Number.isFinite(ceiling) || ceiling < 0) return contentBudget\n return Math.min(contentBudget, Math.floor(ceiling))\n}\n"],"mappings":"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"}
@@ -0,0 +1,265 @@
1
+ const require_path_safety = require("./path-safety.cjs");
2
+ //#region src/sync/download-staging.ts
3
+ /** @internal */
4
+ var DOWNLOAD_STAGING_DIRECTORY_NAME = ".b2sdk-download-staging";
5
+ /** @internal */
6
+ var DOWNLOAD_STAGING_MARKER_NAME = ".b2sdk-staging-marker.partial";
7
+ var CANONICAL_DOWNLOAD_STAGING_DIRECTORY_NAME = canonicalLocalFilesystemSegment(DOWNLOAD_STAGING_DIRECTORY_NAME);
8
+ var DOWNLOAD_STAGING_ENTRY_SUFFIX = ".download";
9
+ var STALE_DOWNLOAD_STAGING_AGE_MS = 1440 * 60 * 1e3;
10
+ var MAX_STAGING_CLEANUP_CONCURRENCY = 8;
11
+ var MAX_CLEANUP_WARNING_ENTRIES = 3;
12
+ /** @internal */
13
+ var DOWNLOAD_STAGING_ACTIVITY_ENTRY_LIMIT = 1024;
14
+ var reapedManagedDirectories = /* @__PURE__ */ new Map();
15
+ /**
16
+ * Checks whether a single path segment matches the SDK-managed staging directory name.
17
+ * @param segment - Candidate path segment.
18
+ *
19
+ * @returns True when the segment is the reserved staging directory name under
20
+ * local filesystem canonicalization.
21
+ *
22
+ * @internal
23
+ */
24
+ function isDownloadStagingDirectorySegment(segment) {
25
+ return segment !== void 0 && canonicalLocalFilesystemSegment(segment) === CANONICAL_DOWNLOAD_STAGING_DIRECTORY_NAME;
26
+ }
27
+ /**
28
+ * Creates a private SDK-managed staging directory under a local sync root.
29
+ * @param rootRealPath - Resolved local sync root path.
30
+ * @param path - Node path module used for platform-specific path operations.
31
+ * @param randomUUID - UUID provider used to create unique staging entries.
32
+ * @param statForDeviceCheck - Stat function used to verify filesystem devices.
33
+ * @param beforeStagingMarkerWrite - Test hook called before marker creation.
34
+ *
35
+ * @returns The resolved staging directory path.
36
+ *
37
+ * @internal
38
+ */
39
+ async function createDownloadStagingDirectory(rootRealPath, path, randomUUID, statForDeviceCheck, beforeStagingMarkerWrite) {
40
+ const { chmod, lstat, mkdir, readdir, realpath, rm } = await import("node:fs/promises");
41
+ const managedDirectory = path.join(rootRealPath, DOWNLOAD_STAGING_DIRECTORY_NAME);
42
+ try {
43
+ await mkdir(managedDirectory, { mode: PRIVATE_DOWNLOAD_DIRECTORY_MODE });
44
+ } catch (err) {
45
+ if (!require_path_safety.hasErrorCode(err, "EEXIST")) throw err;
46
+ }
47
+ if (!(await lstat(managedDirectory)).isDirectory()) throw new Error(`unsafe local destination path: ${DOWNLOAD_STAGING_DIRECTORY_NAME} is not a directory`);
48
+ const realManagedDirectory = await realpath(managedDirectory);
49
+ require_path_safety.assertPathInsideRoot(rootRealPath, realManagedDirectory, path);
50
+ await assertDownloadPathSameDevice(rootRealPath, realManagedDirectory, statForDeviceCheck, "unsafe local destination path: cannot stage download across filesystems");
51
+ if (!await isManagedDownloadStagingRoot(realManagedDirectory)) {
52
+ if ((await readdir(realManagedDirectory)).length > 0 && !await isManagedDownloadStagingRoot(realManagedDirectory)) throw new Error(`unsafe local destination path: ${DOWNLOAD_STAGING_DIRECTORY_NAME} is reserved for SDK download staging`);
53
+ }
54
+ await beforeStagingMarkerWrite?.(realManagedDirectory);
55
+ await writeStagingMarker(realManagedDirectory, path);
56
+ /* v8 ignore next -- best-effort chmod */
57
+ await chmod(realManagedDirectory, PRIVATE_DOWNLOAD_DIRECTORY_MODE).catch(() => {});
58
+ await reapStaleDownloadStagingDirectoriesOnce(realManagedDirectory, path, Date.now());
59
+ const stagingDirectory = path.join(realManagedDirectory, `${Date.now()}-${randomUUID()}${DOWNLOAD_STAGING_ENTRY_SUFFIX}`);
60
+ await mkdir(stagingDirectory, { mode: PRIVATE_DOWNLOAD_DIRECTORY_MODE });
61
+ /* v8 ignore next -- best-effort chmod */
62
+ await chmod(stagingDirectory, PRIVATE_DOWNLOAD_DIRECTORY_MODE).catch(() => {});
63
+ try {
64
+ const realStagingDirectory = await realpath(stagingDirectory);
65
+ require_path_safety.assertPathInsideRoot(realManagedDirectory, realStagingDirectory, path);
66
+ await assertDownloadPathSameDevice(rootRealPath, realStagingDirectory, statForDeviceCheck, "unsafe local destination path: cannot stage download across filesystems");
67
+ await beforeStagingMarkerWrite?.(realStagingDirectory);
68
+ await writeStagingMarker(realStagingDirectory, path);
69
+ return realStagingDirectory;
70
+ } catch (err) {
71
+ /* v8 ignore next -- best-effort cleanup */
72
+ await rm(stagingDirectory, {
73
+ recursive: true,
74
+ force: true
75
+ }).catch(() => {});
76
+ throw err;
77
+ }
78
+ }
79
+ /**
80
+ * Returns true when a scan-root entry is an SDK-managed download staging root.
81
+ * @param directory - Candidate directory to inspect.
82
+ *
83
+ * @returns True when the directory contains SDK staging markers.
84
+ *
85
+ * @internal
86
+ */
87
+ async function isManagedDownloadStagingRoot(directory) {
88
+ const { lstat, readdir } = await import("node:fs/promises");
89
+ const path = await import("node:path");
90
+ try {
91
+ if ((await lstat(path.join(directory, ".b2sdk-staging-marker.partial"))).isFile()) return true;
92
+ } catch (err) {
93
+ if (!require_path_safety.hasErrorCode(err, "ENOENT")) return false;
94
+ }
95
+ let entries;
96
+ try {
97
+ entries = await readdir(directory, { withFileTypes: true });
98
+ } catch {
99
+ return false;
100
+ }
101
+ for (const entry of entries) {
102
+ if (!entry.isDirectory() || !entry.name.endsWith(DOWNLOAD_STAGING_ENTRY_SUFFIX)) continue;
103
+ try {
104
+ if ((await lstat(path.join(directory, entry.name, ".b2sdk-staging-marker.partial"))).isFile()) return true;
105
+ } catch {}
106
+ }
107
+ return false;
108
+ }
109
+ var PRIVATE_DOWNLOAD_FILE_MODE = 384;
110
+ var PRIVATE_DOWNLOAD_DIRECTORY_MODE = 448;
111
+ async function writeStagingMarker(directory, path) {
112
+ const { constants } = await import("node:fs");
113
+ const { lstat, open } = await import("node:fs/promises");
114
+ const markerPath = path.join(directory, DOWNLOAD_STAGING_MARKER_NAME);
115
+ let handle;
116
+ try {
117
+ handle = await open(markerPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | require_path_safety.noFollowFlag(constants), PRIVATE_DOWNLOAD_FILE_MODE);
118
+ /* v8 ignore next -- best-effort chmod */
119
+ await handle.chmod(PRIVATE_DOWNLOAD_FILE_MODE).catch(() => {});
120
+ } catch (err) {
121
+ if (require_path_safety.hasErrorCode(err, "EEXIST") || require_path_safety.hasErrorCode(err, "ELOOP")) {
122
+ if ((await lstat(markerPath).catch(() => void 0))?.isFile() === true) return;
123
+ throw new Error("unsafe local destination path: staging marker is not a regular file");
124
+ }
125
+ throw err;
126
+ } finally {
127
+ /* v8 ignore next -- best-effort close */
128
+ await handle?.close().catch(() => {});
129
+ }
130
+ }
131
+ /**
132
+ * Verifies that a candidate path is on the same filesystem device as the root.
133
+ * @param rootRealPath - Resolved local sync root path.
134
+ * @param candidateRealPath - Resolved candidate path to compare.
135
+ * @param statForDeviceCheck - Stat function used to read device IDs.
136
+ * @param message - Error message used when devices differ.
137
+ *
138
+ * @internal
139
+ */
140
+ async function assertDownloadPathSameDevice(rootRealPath, candidateRealPath, statForDeviceCheck, message) {
141
+ const [rootStats, candidateStats] = await Promise.all([statForDeviceCheck(rootRealPath), statForDeviceCheck(candidateRealPath)]);
142
+ if (rootStats.dev !== candidateStats.dev) throw new Error(message);
143
+ }
144
+ async function reapStaleDownloadStagingDirectoriesOnce(managedDirectory, path, nowMillis) {
145
+ const previous = reapedManagedDirectories.get(managedDirectory);
146
+ if (previous !== void 0) {
147
+ await previous;
148
+ return;
149
+ }
150
+ const next = reapStaleDownloadStagingDirectories(managedDirectory, path, nowMillis).finally(() => {
151
+ if (reapedManagedDirectories.get(managedDirectory) === next) reapedManagedDirectories.delete(managedDirectory);
152
+ });
153
+ reapedManagedDirectories.set(managedDirectory, next);
154
+ await next;
155
+ }
156
+ async function reapStaleDownloadStagingDirectories(managedDirectory, path, nowMillis) {
157
+ const { readdir, realpath, rm } = await import("node:fs/promises");
158
+ let entries;
159
+ try {
160
+ entries = await readdir(managedDirectory, { withFileTypes: true });
161
+ } catch (err) {
162
+ if (require_path_safety.hasErrorCode(err, "ENOENT")) return;
163
+ emitCleanupWarning("failed to inspect B2 SDK download staging entries");
164
+ return;
165
+ }
166
+ const cleanupErrors = [];
167
+ await forEachWithConcurrency(entries, MAX_STAGING_CLEANUP_CONCURRENCY, async (entry) => {
168
+ if (!entry.isDirectory() || !entry.name.endsWith(DOWNLOAD_STAGING_ENTRY_SUFFIX)) return;
169
+ const candidate = path.join(managedDirectory, entry.name);
170
+ const activity = await readManagedStagingEntryActivity(candidate, path);
171
+ if (activity === void 0 || !stagingActivityIsStale(activity, nowMillis)) return;
172
+ const realCandidate = await realpath(candidate).catch(() => {
173
+ cleanupErrors.push({
174
+ entryName: entry.name,
175
+ operation: "inspect"
176
+ });
177
+ });
178
+ if (realCandidate === void 0) return;
179
+ try {
180
+ require_path_safety.assertPathInsideRoot(managedDirectory, realCandidate, path);
181
+ const latestActivity = await readManagedStagingEntryActivity(candidate, path);
182
+ if (latestActivity === void 0 || latestActivity.signature !== activity.signature || !stagingActivityIsStale(latestActivity, nowMillis)) return;
183
+ await rm(realCandidate, {
184
+ recursive: true,
185
+ force: true
186
+ });
187
+ } catch {
188
+ cleanupErrors.push({
189
+ entryName: entry.name,
190
+ operation: "remove"
191
+ });
192
+ }
193
+ });
194
+ if (cleanupErrors.length > 0) {
195
+ const noun = cleanupErrors.length === 1 ? "entry" : "entries";
196
+ emitCleanupWarning(`failed to reap ${cleanupErrors.length} stale B2 SDK download staging ${noun}: ${cleanupErrors.slice(0, MAX_CLEANUP_WARNING_ENTRIES).map(formatCleanupWarning).join("; ")}`);
197
+ }
198
+ }
199
+ async function readManagedStagingEntryActivity(candidate, path) {
200
+ const { lstat, readdir } = await import("node:fs/promises");
201
+ try {
202
+ const [directoryStats, markerStats] = await Promise.all([lstat(candidate), lstat(path.join(candidate, DOWNLOAD_STAGING_MARKER_NAME))]);
203
+ if (!directoryStats.isDirectory() || !markerStats.isFile()) return void 0;
204
+ const entries = await readdir(candidate, { withFileTypes: true });
205
+ if (entries.length > 1024) return void 0;
206
+ const statsParts = [`.:${stagingStatsSignature(directoryStats)}`, `${DOWNLOAD_STAGING_MARKER_NAME}:${stagingStatsSignature(markerStats)}`];
207
+ let newestActivityMs = Math.max(stagingStatsActivityMs(directoryStats), stagingStatsActivityMs(markerStats));
208
+ for (const entry of [...entries].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
209
+ const stats = await lstat(path.join(candidate, entry.name));
210
+ statsParts.push(`${entry.name}:${stagingStatsSignature(stats)}`);
211
+ newestActivityMs = Math.max(newestActivityMs, stagingStatsActivityMs(stats));
212
+ }
213
+ return {
214
+ newestActivityMs,
215
+ signature: statsParts.join("|")
216
+ };
217
+ } catch {
218
+ return;
219
+ }
220
+ }
221
+ function stagingStatsActivityMs(stats) {
222
+ return stats.mtimeMs;
223
+ }
224
+ function stagingStatsSignature(stats) {
225
+ return `${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeMs}:${stats.ctimeMs}`;
226
+ }
227
+ function stagingActivityIsStale(activity, nowMillis) {
228
+ return nowMillis - activity.newestActivityMs >= STALE_DOWNLOAD_STAGING_AGE_MS;
229
+ }
230
+ function formatCleanupWarning(error) {
231
+ return `${error.operation} ${safeWarningName(error.entryName)}`;
232
+ }
233
+ function safeWarningName(name) {
234
+ const chars = Array.from(name);
235
+ const bounded = chars.slice(0, 80).join("");
236
+ const suffix = chars.length > 80 ? "..." : "";
237
+ return JSON.stringify(`${bounded.replace(/[^A-Za-z0-9._-]/g, "?")}${suffix}`);
238
+ }
239
+ function canonicalLocalFilesystemSegment(segment) {
240
+ return segment.normalize("NFC").toLocaleLowerCase("en-US");
241
+ }
242
+ async function forEachWithConcurrency(items, concurrency, fn) {
243
+ let index = 0;
244
+ const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
245
+ while (index < items.length) {
246
+ const item = items[index];
247
+ index += 1;
248
+ if (item !== void 0) await fn(item);
249
+ }
250
+ });
251
+ await Promise.all(workers);
252
+ }
253
+ function emitCleanupWarning(message) {
254
+ globalThis.process?.emitWarning?.(message, { code: "B2SDK_DOWNLOAD_STAGING_CLEANUP_FAILED" });
255
+ }
256
+ //#endregion
257
+ exports.DOWNLOAD_STAGING_ACTIVITY_ENTRY_LIMIT = DOWNLOAD_STAGING_ACTIVITY_ENTRY_LIMIT;
258
+ exports.DOWNLOAD_STAGING_DIRECTORY_NAME = DOWNLOAD_STAGING_DIRECTORY_NAME;
259
+ exports.DOWNLOAD_STAGING_MARKER_NAME = DOWNLOAD_STAGING_MARKER_NAME;
260
+ exports.assertDownloadPathSameDevice = assertDownloadPathSameDevice;
261
+ exports.createDownloadStagingDirectory = createDownloadStagingDirectory;
262
+ exports.isDownloadStagingDirectorySegment = isDownloadStagingDirectorySegment;
263
+ exports.isManagedDownloadStagingRoot = isManagedDownloadStagingRoot;
264
+
265
+ //# sourceMappingURL=download-staging.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-staging.cjs","names":[],"sources":["../../src/sync/download-staging.ts"],"sourcesContent":["import { assertPathInsideRoot, hasErrorCode, noFollowFlag } from './path-safety.ts'\n\ntype DeviceStat = { readonly dev: number | bigint }\ntype DeviceStatFn = (path: string) => Promise<DeviceStat>\n\n/** @internal */\nexport const DOWNLOAD_STAGING_DIRECTORY_NAME = '.b2sdk-download-staging'\n/** @internal */\nexport const DOWNLOAD_STAGING_MARKER_NAME = '.b2sdk-staging-marker.partial'\n\nconst CANONICAL_DOWNLOAD_STAGING_DIRECTORY_NAME = canonicalLocalFilesystemSegment(\n DOWNLOAD_STAGING_DIRECTORY_NAME,\n)\nconst DOWNLOAD_STAGING_ENTRY_SUFFIX = '.download'\nconst STALE_DOWNLOAD_STAGING_AGE_MS = 24 * 60 * 60 * 1000\nconst MAX_STAGING_CLEANUP_CONCURRENCY = 8\nconst MAX_CLEANUP_WARNING_ENTRIES = 3\n/** @internal */\nexport const DOWNLOAD_STAGING_ACTIVITY_ENTRY_LIMIT = 1024\nconst reapedManagedDirectories = new Map<string, Promise<void>>()\n\ntype StagingActivitySnapshot = {\n readonly newestActivityMs: number\n readonly signature: string\n}\n\ntype CleanupWarning = {\n readonly entryName: string\n readonly operation: 'inspect' | 'remove'\n}\n\n/**\n * Checks whether a single path segment matches the SDK-managed staging directory name.\n * @param segment - Candidate path segment.\n *\n * @returns True when the segment is the reserved staging directory name under\n * local filesystem canonicalization.\n *\n * @internal\n */\nexport function isDownloadStagingDirectorySegment(segment: string | undefined): boolean {\n return (\n segment !== undefined &&\n canonicalLocalFilesystemSegment(segment) === CANONICAL_DOWNLOAD_STAGING_DIRECTORY_NAME\n )\n}\n\n/**\n * Creates a private SDK-managed staging directory under a local sync root.\n * @param rootRealPath - Resolved local sync root path.\n * @param path - Node path module used for platform-specific path operations.\n * @param randomUUID - UUID provider used to create unique staging entries.\n * @param statForDeviceCheck - Stat function used to verify filesystem devices.\n * @param beforeStagingMarkerWrite - Test hook called before marker creation.\n *\n * @returns The resolved staging directory path.\n *\n * @internal\n */\nexport async function createDownloadStagingDirectory(\n rootRealPath: string,\n path: typeof import('node:path'),\n randomUUID: () => string,\n statForDeviceCheck: DeviceStatFn,\n beforeStagingMarkerWrite?: (directory: string) => Promise<void> | void,\n): Promise<string> {\n const { chmod, lstat, mkdir, readdir, realpath, rm } = await import('node:fs/promises')\n const managedDirectory = path.join(rootRealPath, DOWNLOAD_STAGING_DIRECTORY_NAME)\n try {\n await mkdir(managedDirectory, { mode: PRIVATE_DOWNLOAD_DIRECTORY_MODE })\n } catch (err) {\n if (!hasErrorCode(err, 'EEXIST')) throw err\n }\n const managedStats = await lstat(managedDirectory)\n if (!managedStats.isDirectory()) {\n throw new Error(\n `unsafe local destination path: ${DOWNLOAD_STAGING_DIRECTORY_NAME} is not a directory`,\n )\n }\n const realManagedDirectory = await realpath(managedDirectory)\n assertPathInsideRoot(rootRealPath, realManagedDirectory, path)\n await assertDownloadPathSameDevice(\n rootRealPath,\n realManagedDirectory,\n statForDeviceCheck,\n 'unsafe local destination path: cannot stage download across filesystems',\n )\n\n if (!(await isManagedDownloadStagingRoot(realManagedDirectory))) {\n const entries = await readdir(realManagedDirectory)\n if (entries.length > 0 && !(await isManagedDownloadStagingRoot(realManagedDirectory))) {\n throw new Error(\n `unsafe local destination path: ${DOWNLOAD_STAGING_DIRECTORY_NAME} is reserved for SDK download staging`,\n )\n }\n }\n await beforeStagingMarkerWrite?.(realManagedDirectory)\n await writeStagingMarker(realManagedDirectory, path)\n /* v8 ignore next -- best-effort chmod */\n await chmod(realManagedDirectory, PRIVATE_DOWNLOAD_DIRECTORY_MODE).catch(() => {})\n await reapStaleDownloadStagingDirectoriesOnce(realManagedDirectory, path, Date.now())\n\n const stagingDirectory = path.join(\n realManagedDirectory,\n `${Date.now()}-${randomUUID()}${DOWNLOAD_STAGING_ENTRY_SUFFIX}`,\n )\n await mkdir(stagingDirectory, { mode: PRIVATE_DOWNLOAD_DIRECTORY_MODE })\n /* v8 ignore next -- best-effort chmod */\n await chmod(stagingDirectory, PRIVATE_DOWNLOAD_DIRECTORY_MODE).catch(() => {})\n try {\n const realStagingDirectory = await realpath(stagingDirectory)\n assertPathInsideRoot(realManagedDirectory, realStagingDirectory, path)\n await assertDownloadPathSameDevice(\n rootRealPath,\n realStagingDirectory,\n statForDeviceCheck,\n 'unsafe local destination path: cannot stage download across filesystems',\n )\n await beforeStagingMarkerWrite?.(realStagingDirectory)\n await writeStagingMarker(realStagingDirectory, path)\n return realStagingDirectory\n } catch (err) {\n /* v8 ignore next -- best-effort cleanup */\n await rm(stagingDirectory, { recursive: true, force: true }).catch(() => {})\n throw err\n }\n}\n\n/**\n * Returns true when a scan-root entry is an SDK-managed download staging root.\n * @param directory - Candidate directory to inspect.\n *\n * @returns True when the directory contains SDK staging markers.\n *\n * @internal\n */\nexport async function isManagedDownloadStagingRoot(directory: string): Promise<boolean> {\n const { lstat, readdir } = await import('node:fs/promises')\n const path = await import('node:path')\n\n try {\n const markerStats = await lstat(path.join(directory, DOWNLOAD_STAGING_MARKER_NAME))\n if (markerStats.isFile()) return true\n } catch (err) {\n if (!hasErrorCode(err, 'ENOENT')) return false\n }\n\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(directory, { withFileTypes: true })\n } catch {\n return false\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith(DOWNLOAD_STAGING_ENTRY_SUFFIX)) continue\n try {\n const markerStats = await lstat(\n path.join(directory, entry.name, DOWNLOAD_STAGING_MARKER_NAME),\n )\n if (markerStats.isFile()) return true\n } catch {\n // Keep checking siblings; one corrupt entry should not hide user content.\n }\n }\n return false\n}\n\nconst PRIVATE_DOWNLOAD_FILE_MODE = 0o600\nconst PRIVATE_DOWNLOAD_DIRECTORY_MODE = 0o700\n\nasync function writeStagingMarker(\n directory: string,\n path: typeof import('node:path'),\n): Promise<void> {\n const { constants } = await import('node:fs')\n const { lstat, open } = await import('node:fs/promises')\n const markerPath = path.join(directory, DOWNLOAD_STAGING_MARKER_NAME)\n let handle: Awaited<ReturnType<typeof open>> | undefined\n try {\n handle = await open(\n markerPath,\n constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollowFlag(constants),\n PRIVATE_DOWNLOAD_FILE_MODE,\n )\n /* v8 ignore next -- best-effort chmod */\n await handle.chmod(PRIVATE_DOWNLOAD_FILE_MODE).catch(() => {})\n } catch (err) {\n if (hasErrorCode(err, 'EEXIST') || hasErrorCode(err, 'ELOOP')) {\n const markerStats = await lstat(markerPath).catch(() => undefined)\n if (markerStats?.isFile() === true) return\n throw new Error('unsafe local destination path: staging marker is not a regular file')\n }\n throw err\n } finally {\n /* v8 ignore next -- best-effort close */\n await handle?.close().catch(() => {})\n }\n}\n\n/**\n * Verifies that a candidate path is on the same filesystem device as the root.\n * @param rootRealPath - Resolved local sync root path.\n * @param candidateRealPath - Resolved candidate path to compare.\n * @param statForDeviceCheck - Stat function used to read device IDs.\n * @param message - Error message used when devices differ.\n *\n * @internal\n */\nexport async function assertDownloadPathSameDevice(\n rootRealPath: string,\n candidateRealPath: string,\n statForDeviceCheck: DeviceStatFn,\n message: string,\n): Promise<void> {\n const [rootStats, candidateStats] = await Promise.all([\n statForDeviceCheck(rootRealPath),\n statForDeviceCheck(candidateRealPath),\n ])\n if (rootStats.dev !== candidateStats.dev) throw new Error(message)\n}\n\nasync function reapStaleDownloadStagingDirectoriesOnce(\n managedDirectory: string,\n path: typeof import('node:path'),\n nowMillis: number,\n): Promise<void> {\n const previous = reapedManagedDirectories.get(managedDirectory)\n if (previous !== undefined) {\n await previous\n return\n }\n\n const next = reapStaleDownloadStagingDirectories(managedDirectory, path, nowMillis).finally(\n () => {\n if (reapedManagedDirectories.get(managedDirectory) === next) {\n reapedManagedDirectories.delete(managedDirectory)\n }\n },\n )\n reapedManagedDirectories.set(managedDirectory, next)\n await next\n}\n\nasync function reapStaleDownloadStagingDirectories(\n managedDirectory: string,\n path: typeof import('node:path'),\n nowMillis: number,\n): Promise<void> {\n const { readdir, realpath, rm } = await import('node:fs/promises')\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(managedDirectory, { withFileTypes: true })\n } catch (err) {\n if (hasErrorCode(err, 'ENOENT')) return\n emitCleanupWarning('failed to inspect B2 SDK download staging entries')\n return\n }\n\n const cleanupErrors: CleanupWarning[] = []\n await forEachWithConcurrency(entries, MAX_STAGING_CLEANUP_CONCURRENCY, async (entry) => {\n if (!entry.isDirectory() || !entry.name.endsWith(DOWNLOAD_STAGING_ENTRY_SUFFIX)) return\n const candidate = path.join(managedDirectory, entry.name)\n const activity = await readManagedStagingEntryActivity(candidate, path)\n if (activity === undefined || !stagingActivityIsStale(activity, nowMillis)) return\n const realCandidate = await realpath(candidate).catch(() => {\n cleanupErrors.push({ entryName: entry.name, operation: 'inspect' })\n return undefined\n })\n if (realCandidate === undefined) return\n try {\n assertPathInsideRoot(managedDirectory, realCandidate, path)\n const latestActivity = await readManagedStagingEntryActivity(candidate, path)\n if (\n latestActivity === undefined ||\n latestActivity.signature !== activity.signature ||\n !stagingActivityIsStale(latestActivity, nowMillis)\n ) {\n return\n }\n await rm(realCandidate, { recursive: true, force: true })\n } catch {\n cleanupErrors.push({ entryName: entry.name, operation: 'remove' })\n }\n })\n\n if (cleanupErrors.length > 0) {\n const noun = cleanupErrors.length === 1 ? 'entry' : 'entries'\n emitCleanupWarning(\n `failed to reap ${cleanupErrors.length} stale B2 SDK download staging ${noun}: ${cleanupErrors\n .slice(0, MAX_CLEANUP_WARNING_ENTRIES)\n .map(formatCleanupWarning)\n .join('; ')}`,\n )\n }\n}\n\nasync function readManagedStagingEntryActivity(\n candidate: string,\n path: typeof import('node:path'),\n): Promise<StagingActivitySnapshot | undefined> {\n const { lstat, readdir } = await import('node:fs/promises')\n\n try {\n const [directoryStats, markerStats] = await Promise.all([\n lstat(candidate),\n lstat(path.join(candidate, DOWNLOAD_STAGING_MARKER_NAME)),\n ])\n if (!directoryStats.isDirectory() || !markerStats.isFile()) return undefined\n\n const entries = await readdir(candidate, { withFileTypes: true })\n if (entries.length > DOWNLOAD_STAGING_ACTIVITY_ENTRY_LIMIT) return undefined\n\n const statsParts = [\n `.:${stagingStatsSignature(directoryStats)}`,\n `${DOWNLOAD_STAGING_MARKER_NAME}:${stagingStatsSignature(markerStats)}`,\n ]\n let newestActivityMs = Math.max(\n stagingStatsActivityMs(directoryStats),\n stagingStatsActivityMs(markerStats),\n )\n\n for (const entry of [...entries].sort((a, b) =>\n a.name < b.name ? -1 : a.name > b.name ? 1 : 0,\n )) {\n const stats = await lstat(path.join(candidate, entry.name))\n statsParts.push(`${entry.name}:${stagingStatsSignature(stats)}`)\n newestActivityMs = Math.max(newestActivityMs, stagingStatsActivityMs(stats))\n }\n\n return { newestActivityMs, signature: statsParts.join('|') }\n } catch {\n return undefined\n }\n}\n\nfunction stagingStatsActivityMs(stats: { readonly mtimeMs: number }) {\n return stats.mtimeMs\n}\n\nfunction stagingStatsSignature(stats: {\n readonly ctimeMs: number\n readonly dev: number | bigint\n readonly ino: number | bigint\n readonly mtimeMs: number\n readonly size: number\n}): string {\n return `${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeMs}:${stats.ctimeMs}`\n}\n\nfunction stagingActivityIsStale(activity: StagingActivitySnapshot, nowMillis: number): boolean {\n return nowMillis - activity.newestActivityMs >= STALE_DOWNLOAD_STAGING_AGE_MS\n}\n\nfunction formatCleanupWarning(error: CleanupWarning): string {\n return `${error.operation} ${safeWarningName(error.entryName)}`\n}\n\nfunction safeWarningName(name: string): string {\n const chars = Array.from(name)\n const bounded = chars.slice(0, 80).join('')\n const suffix = chars.length > 80 ? '...' : ''\n return JSON.stringify(`${bounded.replace(/[^A-Za-z0-9._-]/g, '?')}${suffix}`)\n}\n\nfunction canonicalLocalFilesystemSegment(segment: string): string {\n return segment.normalize('NFC').toLocaleLowerCase('en-US')\n}\n\nasync function forEachWithConcurrency<T>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T) => Promise<void>,\n): Promise<void> {\n let index = 0\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {\n while (index < items.length) {\n const item = items[index]\n index += 1\n if (item !== undefined) await fn(item)\n }\n })\n await Promise.all(workers)\n}\n\nfunction emitCleanupWarning(message: string): void {\n const processLike = (\n globalThis as {\n process?: {\n emitWarning?: (warning: string, options?: { readonly code?: string }) => void\n }\n }\n ).process\n processLike?.emitWarning?.(message, { code: 'B2SDK_DOWNLOAD_STAGING_CLEANUP_FAILED' })\n}\n"],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ type DeviceStat = {
2
+ readonly dev: number | bigint;
3
+ };
4
+ type DeviceStatFn = (path: string) => Promise<DeviceStat>;
5
+ /** @internal */
6
+ export declare const DOWNLOAD_STAGING_DIRECTORY_NAME = ".b2sdk-download-staging";
7
+ /** @internal */
8
+ export declare const DOWNLOAD_STAGING_MARKER_NAME = ".b2sdk-staging-marker.partial";
9
+ /** @internal */
10
+ export declare const DOWNLOAD_STAGING_ACTIVITY_ENTRY_LIMIT = 1024;
11
+ /**
12
+ * Checks whether a single path segment matches the SDK-managed staging directory name.
13
+ * @param segment - Candidate path segment.
14
+ *
15
+ * @returns True when the segment is the reserved staging directory name under
16
+ * local filesystem canonicalization.
17
+ *
18
+ * @internal
19
+ */
20
+ export declare function isDownloadStagingDirectorySegment(segment: string | undefined): boolean;
21
+ /**
22
+ * Creates a private SDK-managed staging directory under a local sync root.
23
+ * @param rootRealPath - Resolved local sync root path.
24
+ * @param path - Node path module used for platform-specific path operations.
25
+ * @param randomUUID - UUID provider used to create unique staging entries.
26
+ * @param statForDeviceCheck - Stat function used to verify filesystem devices.
27
+ * @param beforeStagingMarkerWrite - Test hook called before marker creation.
28
+ *
29
+ * @returns The resolved staging directory path.
30
+ *
31
+ * @internal
32
+ */
33
+ export declare function createDownloadStagingDirectory(rootRealPath: string, path: typeof import('node:path'), randomUUID: () => string, statForDeviceCheck: DeviceStatFn, beforeStagingMarkerWrite?: (directory: string) => Promise<void> | void): Promise<string>;
34
+ /**
35
+ * Returns true when a scan-root entry is an SDK-managed download staging root.
36
+ * @param directory - Candidate directory to inspect.
37
+ *
38
+ * @returns True when the directory contains SDK staging markers.
39
+ *
40
+ * @internal
41
+ */
42
+ export declare function isManagedDownloadStagingRoot(directory: string): Promise<boolean>;
43
+ /**
44
+ * Verifies that a candidate path is on the same filesystem device as the root.
45
+ * @param rootRealPath - Resolved local sync root path.
46
+ * @param candidateRealPath - Resolved candidate path to compare.
47
+ * @param statForDeviceCheck - Stat function used to read device IDs.
48
+ * @param message - Error message used when devices differ.
49
+ *
50
+ * @internal
51
+ */
52
+ export declare function assertDownloadPathSameDevice(rootRealPath: string, candidateRealPath: string, statForDeviceCheck: DeviceStatFn, message: string): Promise<void>;
53
+ export {};
54
+ //# sourceMappingURL=download-staging.d.ts.map