@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":"local.js","names":[],"sources":["../../../src/sync/scanners/local.ts"],"sourcesContent":["import {\n isDownloadStagingDirectorySegment,\n isManagedDownloadStagingRoot,\n} from '../download-staging.ts'\nimport { localFilesystemErrorReason } from '../filesystem-errors.ts'\nimport {\n directoryMayContainSyncPaths,\n pathPassesSyncFilters,\n pathSkippedByRegExpInputLimit,\n} from '../filters.ts'\nimport { localFileIdentityFromStats } from '../local-file-identity.ts'\nimport { registerLocalFilesystemRoot } from '../local-filesystem-root.ts'\nimport { compareSyncRelativePaths } from '../path-order.ts'\nimport { isReservedSyncTempFileName } from '../path-safety.ts'\nimport { validateSyncFilters } from '../regexp-safety.ts'\nimport { emitScannerSkip, regexpInputTooLongSkip } from '../scan-events.ts'\nimport { assertScanEntryLimit, scanEntryLimit } from '../scan-limit.ts'\nimport type { LocalSyncPath, SyncErrorEvent, SyncFolder, SyncScanOptions } from '../types.ts'\n\ntype LocalDirent = {\n readonly name: string\n isDirectory(): boolean\n isFile(): boolean\n}\n\ntype LocalStats = {\n readonly dev: number\n readonly ino: number\n readonly mtimeMs: number\n readonly ctimeMs: number\n readonly size: number\n isFile(): boolean\n}\n\ntype LocalNodeDeps = {\n readdir(path: string, options: { readonly withFileTypes: true }): Promise<LocalDirent[]>\n lstat(path: string): Promise<LocalStats>\n join(...paths: string[]): string\n relative(from: string, to: string): string\n resolve(...paths: string[]): string\n sep: string\n}\n\n/**\n * Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.\n * A root directory read failure aborts the scan with an error diagnostic. Per-entry file or\n * directory failures are reported through `onError` and the scan continues over readable siblings.\n * SDK-managed partial download file names are skipped so unfinished internal\n * temp files are not synchronized.\n * The current implementation collects matching entries before sorting, so memory usage is\n * proportional to the number of matched files.\n */\nexport class LocalFolder implements SyncFolder {\n readonly type = 'local' as const\n readonly appliesScanFilters = true as const\n readonly appliesScanSorting = true as const\n /** Resolved absolute path to the local root directory. */\n readonly root: string\n\n /**\n * Creates a new LocalFolder for the given root directory.\n * @param root - Absolute or relative path to the local directory to scan.\n */\n constructor(root: string) {\n this.root = resolvePathAtConstruction(root)\n registerLocalFilesystemRoot(this)\n }\n\n /**\n * Recursively walks the directory and yields files in sync path order.\n * @param options - Optional scan controls.\n */\n async *scan(options: SyncScanOptions = {}): AsyncGenerator<LocalSyncPath> {\n validateSyncFilters(options)\n const nodeDeps = await loadLocalNodeDeps()\n const root = nodeDeps.resolve(this.root)\n const collected: LocalSyncPath[] = []\n await this.walk(root, root, collected, options, scanEntryLimit(options), nodeDeps)\n collected.sort((a, b) => compareSyncRelativePaths(a.relativePath, b.relativePath))\n for (const entry of collected) {\n throwIfScanAborted(options)\n yield entry\n }\n }\n\n /**\n * Recursively collects files from {@link dir} into {@link out}.\n * @param root - Resolved scan root used for relative path calculation.\n * @param dir - Absolute path of the directory to scan.\n * @param out - Accumulator array that receives discovered file entries.\n * @param options - Optional scan controls.\n * @param maxScanEntries - Maximum number of entries to retain before failing.\n * @param nodeDeps - Lazy-loaded Node filesystem and path helpers.\n */\n private async walk(\n root: string,\n dir: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n ): Promise<void> {\n throwIfScanAborted(options)\n let entries: LocalDirent[]\n try {\n entries = await nodeDeps.readdir(dir, { withFileTypes: true })\n } catch (err) {\n const error = this.emitScanError(\n options,\n relativePathFromRoot(root, dir, nodeDeps),\n 'directory',\n err,\n )\n if (dir === root) throw error\n return\n }\n\n for (const entry of entries) {\n throwIfScanAborted(options)\n const fullPath = nodeDeps.join(dir, entry.name)\n const rel = relativePathFromRoot(root, fullPath, nodeDeps)\n if (\n isDownloadStagingDirectorySegment(rel) &&\n entry.isDirectory() &&\n isDownloadStagingDirectorySegment(entry.name) &&\n (await isManagedDownloadStagingRoot(fullPath))\n ) {\n continue\n }\n if (rel.includes('\\\\')) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'unsafe-name',\n message: `Skipped local path ${JSON.stringify(rel)}: backslashes are not safe sync path characters`,\n })\n continue\n }\n if (isReservedSyncTempFileName(entry.name)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'stale-download-partial',\n message: `Skipped local path ${JSON.stringify(rel)}: reserved SDK partial download file`,\n })\n continue\n }\n // Symlinks, FIFOs, sockets, and device nodes are not syncable files.\n // Ignore them without poisoning delete-mode orphan handling for unrelated paths.\n if (entry.isDirectory()) {\n if (directoryMayContainSyncPaths(rel, options)) {\n await this.walk(root, fullPath, out, options, maxScanEntries, nodeDeps)\n }\n } else if (entry.isFile()) {\n if (!pathPassesSyncFilters(rel, options)) {\n if (pathSkippedByRegExpInputLimit(rel, options)) {\n emitScannerSkip(options, regexpInputTooLongSkip(rel))\n }\n continue\n }\n let s: LocalStats\n try {\n s = await nodeDeps.lstat(fullPath)\n /* v8 ignore start -- lstat race after a Dirent file result is not deterministic */\n if (!s.isFile()) {\n this.emitScanError(options, rel, 'file', new Error('not a regular file'))\n continue\n }\n /* v8 ignore stop */\n } catch (err) {\n /* v8 ignore next -- stat TOCTOU failures are not deterministic to trigger */\n this.emitScanError(options, relativePathFromRoot(root, fullPath, nodeDeps), 'file', err)\n continue\n }\n assertScanEntryLimit(out.length + 1, maxScanEntries)\n out.push({\n relativePath: rel,\n absolutePath: fullPath,\n modTimeMillis: Math.floor(s.mtimeMs),\n size: s.size,\n fileIdentity: localFileIdentityFromStats(s),\n })\n }\n }\n }\n\n private emitScanError(\n options: SyncScanOptions,\n path: string,\n kind: 'directory' | 'file',\n err: unknown,\n ): Error {\n const event: SyncErrorEvent = {\n type: 'error',\n path,\n size: 0,\n message: `failed to scan local ${kind}: ${localFilesystemErrorReason(err)}`,\n }\n options.onError?.(event)\n return new Error(event.message)\n }\n}\n\nasync function loadLocalNodeDeps(): Promise<LocalNodeDeps> {\n const [fsPromises, path] = await Promise.all([import('node:fs/promises'), import('node:path')])\n return {\n readdir: fsPromises.readdir as LocalNodeDeps['readdir'],\n lstat: fsPromises.lstat as LocalNodeDeps['lstat'],\n join: path.join,\n relative: path.relative,\n resolve: path.resolve,\n sep: path.sep,\n }\n}\n\nfunction resolvePathAtConstruction(root: string): string {\n const processLike = (\n globalThis as {\n process?: { cwd?: () => string; platform?: string }\n }\n ).process\n if (typeof processLike?.cwd !== 'function') return root\n\n const cwd = processLike.cwd()\n if (processLike.platform === 'win32') return resolveWindowsPath(cwd, root)\n return resolvePosixPath(cwd, root)\n}\n\nfunction resolvePosixPath(cwd: string, root: string): string {\n const joined = root.startsWith('/') ? root : `${cwd}/${root}`\n const resolved = normalizePathSegments(joined.split('/'), '/')\n return resolved === '' ? '/' : `/${resolved}`\n}\n\nfunction resolveWindowsPath(cwd: string, root: string): string {\n const normalizedRoot = root.replaceAll('/', '\\\\')\n const normalizedCwd = cwd.replaceAll('/', '\\\\')\n const drive = /^[A-Za-z]:/.exec(normalizedCwd)?.[0] ?? ''\n const cwdUnc = splitUncPath(normalizedCwd)\n if (/^\\\\\\\\/.test(normalizedRoot)) return normalizeUncPath(normalizedRoot)\n if (/^[A-Za-z]:\\\\/.test(normalizedRoot)) {\n const prefix = normalizedRoot.slice(0, 2)\n const rest = normalizedRoot.slice(3).split('\\\\')\n return joinWindowsRoot(prefix, normalizePathSegments(rest, '\\\\'))\n }\n if (/^[A-Za-z]:/.test(normalizedRoot)) {\n throw new Error('LocalFolder root must not be a drive-relative Windows path')\n }\n if (normalizedRoot.startsWith('\\\\')) {\n const rest = normalizePathSegments(normalizedRoot.slice(1).split('\\\\'), '\\\\')\n return joinWindowsRoot(cwdUnc?.prefix ?? drive, rest)\n }\n if (cwdUnc !== undefined) {\n const resolved = normalizePathSegments([...cwdUnc.rest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(cwdUnc.prefix, resolved)\n }\n const base = /^[A-Za-z]:\\\\/.test(normalizedCwd) ? normalizedCwd : `${drive}\\\\`\n const prefix = /^[A-Za-z]:/.exec(base)?.[0] ?? drive\n const baseRest = base.slice(prefix.length).replace(/^\\\\/, '').split('\\\\')\n const resolved = normalizePathSegments([...baseRest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(prefix, resolved)\n}\n\nfunction normalizeUncPath(path: string): string {\n const unc = splitUncPath(path)\n if (unc === undefined) return path\n return joinWindowsRoot(unc.prefix, normalizePathSegments(unc.rest, '\\\\'))\n}\n\nfunction splitUncPath(\n path: string,\n): { readonly prefix: string; readonly rest: string[] } | undefined {\n if (!path.startsWith('\\\\\\\\')) return undefined\n const parts = path.split('\\\\').filter((part) => part !== '')\n const [server, share, ...rest] = parts\n if (server === undefined || share === undefined) return undefined\n return { prefix: `\\\\\\\\${server}\\\\${share}`, rest }\n}\n\nfunction joinWindowsRoot(prefix: string, rest: string): string {\n return rest === '' ? `${prefix}\\\\` : `${prefix}\\\\${rest}`\n}\n\nfunction normalizePathSegments(segments: readonly string[], separator: '/' | '\\\\'): string {\n const out: string[] = []\n for (const segment of segments) {\n if (segment === '' || segment === '.') continue\n if (segment === '..') {\n out.pop()\n continue\n }\n out.push(segment)\n }\n return out.join(separator)\n}\n\nfunction relativePathFromRoot(root: string, path: string, nodeDeps: LocalNodeDeps): string {\n return nodeDeps.relative(root, path).split(nodeDeps.sep).join('/')\n}\n\nfunction throwIfScanAborted(options: SyncScanOptions): void {\n if (options.signal?.aborted === true) {\n throw options.signal.reason ?? new DOMException('Aborted', 'AbortError')\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"local.js","names":[],"sources":["../../../src/sync/scanners/local.ts"],"sourcesContent":["import {\n isDownloadStagingDirectorySegment,\n isManagedDownloadStagingRoot,\n} from '../download-staging.ts'\nimport { localFilesystemErrorReason } from '../filesystem-errors.ts'\nimport {\n directoryMayContainSyncPaths,\n pathPassesSyncFilters,\n pathSkippedByRegExpInputLimit,\n} from '../filters.ts'\nimport { localFileIdentityFromStats } from '../local-file-identity.ts'\nimport { registerLocalFilesystemRoot } from '../local-filesystem-root.ts'\nimport { compareSyncRelativePaths } from '../path-order.ts'\nimport { isReservedSyncTempFileName } from '../path-safety.ts'\nimport { validateSyncFilters } from '../regexp-safety.ts'\nimport { emitScannerSkip, regexpInputTooLongSkip } from '../scan-events.ts'\nimport { assertScanEntryLimit, scanEntryLimit } from '../scan-limit.ts'\nimport type { LocalSyncPath, SyncErrorEvent, SyncFolder, SyncScanOptions } from '../types.ts'\n\ntype LocalDirent = {\n readonly name: string\n isDirectory(): boolean\n isFile(): boolean\n isSymbolicLink(): boolean\n}\n\ntype LocalStats = {\n readonly dev: number\n readonly ino: number\n readonly mtimeMs: number\n readonly ctimeMs: number\n readonly size: number\n isDirectory(): boolean\n isFile(): boolean\n}\n\ntype LocalNodeDeps = {\n readdir(path: string, options: { readonly withFileTypes: true }): Promise<LocalDirent[]>\n lstat(path: string): Promise<LocalStats>\n stat(path: string): Promise<LocalStats>\n join(...paths: string[]): string\n relative(from: string, to: string): string\n realpath(path: string): Promise<string>\n resolve(...paths: string[]): string\n isAbsolute(path: string): boolean\n sep: string\n}\n\n/**\n * Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.\n * A root directory read failure aborts the scan with an error diagnostic. Per-entry file or\n * directory failures are reported through `onError` and the scan continues over readable siblings.\n * SDK-managed partial download file names are skipped so unfinished internal\n * temp files are not synchronized.\n * The current implementation collects matching entries before sorting, so memory usage is\n * proportional to the number of matched files.\n */\nexport class LocalFolder implements SyncFolder {\n readonly type = 'local' as const\n readonly appliesScanFilters = true as const\n readonly appliesScanSorting = true as const\n /** Resolved absolute path to the local root directory. */\n readonly root: string\n\n /**\n * Creates a new LocalFolder for the given root directory.\n * @param root - Absolute or relative path to the local directory to scan.\n */\n constructor(root: string) {\n this.root = resolvePathAtConstruction(root)\n registerLocalFilesystemRoot(this)\n }\n\n /**\n * Recursively walks the directory and yields files in sync path order.\n * @param options - Optional scan controls.\n */\n async *scan(options: SyncScanOptions = {}): AsyncGenerator<LocalSyncPath> {\n validateSyncFilters(options)\n const nodeDeps = await loadLocalNodeDeps()\n const root = nodeDeps.resolve(this.root)\n const followSymlinks =\n options.localSymlinks === 'follow' && options.requireLocalSafePaths !== true\n let scanRoot = root\n const collected: LocalSyncPath[] = []\n const activeDirectoryIds = new Set<string>()\n const followedDirectoryIds = new Set<string>()\n if (followSymlinks) {\n try {\n scanRoot = await nodeDeps.realpath(root)\n const rootStats = await nodeDeps.stat(scanRoot)\n if (rootStats.isDirectory()) activeDirectoryIds.add(localNodeIdentity(rootStats))\n } catch {\n // Root read errors are reported by walk(), preserving the existing diagnostic shape.\n }\n }\n await this.walk(\n scanRoot,\n scanRoot,\n '',\n collected,\n options,\n scanEntryLimit(options),\n nodeDeps,\n activeDirectoryIds,\n followedDirectoryIds,\n )\n collected.sort((a, b) => compareSyncRelativePaths(a.relativePath, b.relativePath))\n for (const entry of collected) {\n throwIfScanAborted(options)\n yield entry\n }\n }\n\n /**\n * Recursively collects files from {@link dir} into {@link out}.\n * @param root - Resolved scan root used for relative path calculation.\n * @param dir - Absolute path of the directory to scan.\n * @param dirRel - Sync-relative path represented by {@link dir}.\n * @param out - Accumulator array that receives discovered file entries.\n * @param options - Optional scan controls.\n * @param maxScanEntries - Maximum number of entries to retain before failing.\n * @param nodeDeps - Lazy-loaded Node filesystem and path helpers.\n * @param activeDirectoryIds - Directory identities in the current recursion stack.\n * @param followedDirectoryIds - Followed symlink directory identities already traversed.\n */\n private async walk(\n root: string,\n dir: string,\n dirRel: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n activeDirectoryIds: Set<string>,\n followedDirectoryIds: Set<string>,\n ): Promise<void> {\n throwIfScanAborted(options)\n let entries: LocalDirent[]\n try {\n entries = await nodeDeps.readdir(dir, { withFileTypes: true })\n } catch (err) {\n const error = this.emitScanError(options, dirRel, 'directory', err)\n if (dir === root) throw error\n return\n }\n\n for (const entry of entries) {\n throwIfScanAborted(options)\n const fullPath = nodeDeps.join(dir, entry.name)\n const rel = joinSyncRelativePath(dirRel, entry.name)\n if (\n isDownloadStagingDirectorySegment(rel) &&\n entry.isDirectory() &&\n isDownloadStagingDirectorySegment(entry.name) &&\n (await isManagedDownloadStagingRoot(fullPath))\n ) {\n continue\n }\n if (rel.includes('\\\\')) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'unsafe-name',\n message: `Skipped local path ${JSON.stringify(rel)}: backslashes are not safe sync path characters`,\n })\n continue\n }\n if (isReservedSyncTempFileName(entry.name)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'stale-download-partial',\n message: `Skipped local path ${JSON.stringify(rel)}: reserved SDK partial download file`,\n })\n continue\n }\n // Symlinks, FIFOs, sockets, and device nodes are not syncable files.\n // Ignore them without poisoning delete-mode orphan handling for unrelated paths.\n if (entry.isDirectory()) {\n if (directoryMayContainSyncPaths(rel, options)) {\n await this.walkDirectory(\n root,\n fullPath,\n rel,\n out,\n options,\n maxScanEntries,\n nodeDeps,\n activeDirectoryIds,\n followedDirectoryIds,\n )\n }\n } else if (entry.isFile()) {\n await this.collectFile(fullPath, rel, out, options, maxScanEntries, nodeDeps)\n } else if (entry.isSymbolicLink()) {\n await this.handleSymlink(\n root,\n fullPath,\n rel,\n out,\n options,\n maxScanEntries,\n nodeDeps,\n activeDirectoryIds,\n followedDirectoryIds,\n )\n }\n }\n }\n\n private async walkDirectory(\n root: string,\n dir: string,\n rel: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n activeDirectoryIds: Set<string>,\n followedDirectoryIds: Set<string>,\n knownStats?: LocalStats,\n ): Promise<void> {\n let stats = knownStats\n if (stats === undefined) {\n try {\n stats = await nodeDeps.stat(dir)\n } catch (err) {\n /* v8 ignore start -- stat TOCTOU failures after a Dirent directory result are not deterministic */\n this.emitScanError(options, rel, 'directory', err)\n return\n /* v8 ignore stop */\n }\n }\n /* v8 ignore start -- stat TOCTOU races after a Dirent directory result are not deterministic */\n if (!stats.isDirectory()) {\n this.emitScanError(options, rel, 'directory', new Error('not a directory'))\n return\n }\n /* v8 ignore stop */\n\n const identity = localNodeIdentity(stats)\n if (activeDirectoryIds.has(identity)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'local-symlink-loop',\n message: `Skipped local path ${JSON.stringify(rel)}: symlink would revisit an ancestor directory`,\n })\n return\n }\n\n activeDirectoryIds.add(identity)\n try {\n await this.walk(\n root,\n dir,\n rel,\n out,\n options,\n maxScanEntries,\n nodeDeps,\n activeDirectoryIds,\n followedDirectoryIds,\n )\n } finally {\n activeDirectoryIds.delete(identity)\n }\n }\n\n private async collectFile(\n fullPath: string,\n rel: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n knownStats?: LocalStats,\n ): Promise<void> {\n if (!pathPassesSyncFilters(rel, options)) {\n if (pathSkippedByRegExpInputLimit(rel, options)) {\n emitScannerSkip(options, regexpInputTooLongSkip(rel))\n }\n return\n }\n\n let s = knownStats\n if (s === undefined) {\n try {\n s = await nodeDeps.lstat(fullPath)\n /* v8 ignore start -- lstat race after a Dirent file result is not deterministic */\n if (!s.isFile()) {\n this.emitScanError(options, rel, 'file', new Error('not a regular file'))\n return\n }\n /* v8 ignore stop */\n } catch (err) {\n /* v8 ignore start -- stat TOCTOU failures are not deterministic to trigger */\n this.emitScanError(options, rel, 'file', err)\n return\n /* v8 ignore stop */\n }\n }\n\n assertScanEntryLimit(out.length + 1, maxScanEntries)\n out.push({\n relativePath: rel,\n absolutePath: fullPath,\n modTimeMillis: Math.floor(s.mtimeMs),\n size: s.size,\n fileIdentity: localFileIdentityFromStats(s),\n })\n }\n\n private async handleSymlink(\n root: string,\n fullPath: string,\n rel: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n activeDirectoryIds: Set<string>,\n followedDirectoryIds: Set<string>,\n ): Promise<void> {\n if ((options.localSymlinks ?? 'skip') === 'skip' || options.requireLocalSafePaths === true) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'local-symlink',\n message: `Skipped local path ${JSON.stringify(rel)}: local symlinks are disabled`,\n })\n return\n }\n\n let targetPath: string\n let targetStats: LocalStats\n try {\n targetPath = await nodeDeps.realpath(fullPath)\n targetStats = await nodeDeps.stat(targetPath)\n } catch (err) {\n this.emitScanError(options, rel, 'symlink', err)\n return\n }\n\n if (!isPathInsideRoot(root, targetPath, nodeDeps)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'local-symlink',\n message: `Skipped local path ${JSON.stringify(rel)}: symlink target is outside the sync root`,\n })\n return\n }\n\n if (targetStats.isDirectory()) {\n if (directoryMayContainSyncPaths(rel, options)) {\n const identity = localNodeIdentity(targetStats)\n if (followedDirectoryIds.has(identity)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'local-symlink-loop',\n message: `Skipped local path ${JSON.stringify(rel)}: symlink target was already visited`,\n })\n return\n }\n followedDirectoryIds.add(identity)\n await this.walkDirectory(\n root,\n targetPath,\n rel,\n out,\n options,\n maxScanEntries,\n nodeDeps,\n activeDirectoryIds,\n followedDirectoryIds,\n targetStats,\n )\n }\n return\n }\n\n if (targetStats.isFile()) {\n await this.collectFile(targetPath, rel, out, options, maxScanEntries, nodeDeps, targetStats)\n return\n }\n\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'local-symlink',\n message: `Skipped local path ${JSON.stringify(rel)}: symlink target is not a regular file or directory`,\n })\n }\n\n private emitScanError(\n options: SyncScanOptions,\n path: string,\n kind: 'directory' | 'file' | 'symlink',\n err: unknown,\n ): Error {\n const event: SyncErrorEvent = {\n type: 'error',\n path,\n size: 0,\n message: `failed to scan local ${kind}: ${localFilesystemErrorReason(err)}`,\n }\n options.onError?.(event)\n return new Error(event.message)\n }\n}\n\nasync function loadLocalNodeDeps(): Promise<LocalNodeDeps> {\n const [fsPromises, path] = await Promise.all([import('node:fs/promises'), import('node:path')])\n return {\n readdir: fsPromises.readdir as LocalNodeDeps['readdir'],\n lstat: fsPromises.lstat as LocalNodeDeps['lstat'],\n stat: fsPromises.stat as LocalNodeDeps['stat'],\n join: path.join,\n relative: path.relative,\n realpath: fsPromises.realpath,\n resolve: path.resolve,\n isAbsolute: path.isAbsolute,\n sep: path.sep,\n }\n}\n\nfunction resolvePathAtConstruction(root: string): string {\n const processLike = (\n globalThis as {\n process?: { cwd?: () => string; platform?: string }\n }\n ).process\n if (typeof processLike?.cwd !== 'function') return root\n\n const cwd = processLike.cwd()\n if (processLike.platform === 'win32') return resolveWindowsPath(cwd, root)\n return resolvePosixPath(cwd, root)\n}\n\nfunction resolvePosixPath(cwd: string, root: string): string {\n const joined = root.startsWith('/') ? root : `${cwd}/${root}`\n const resolved = normalizePathSegments(joined.split('/'), '/')\n return resolved === '' ? '/' : `/${resolved}`\n}\n\nfunction resolveWindowsPath(cwd: string, root: string): string {\n const normalizedRoot = root.replaceAll('/', '\\\\')\n const normalizedCwd = cwd.replaceAll('/', '\\\\')\n const drive = /^[A-Za-z]:/.exec(normalizedCwd)?.[0] ?? ''\n const cwdUnc = splitUncPath(normalizedCwd)\n if (/^\\\\\\\\/.test(normalizedRoot)) return normalizeUncPath(normalizedRoot)\n if (/^[A-Za-z]:\\\\/.test(normalizedRoot)) {\n const prefix = normalizedRoot.slice(0, 2)\n const rest = normalizedRoot.slice(3).split('\\\\')\n return joinWindowsRoot(prefix, normalizePathSegments(rest, '\\\\'))\n }\n if (/^[A-Za-z]:/.test(normalizedRoot)) {\n throw new Error('LocalFolder root must not be a drive-relative Windows path')\n }\n if (normalizedRoot.startsWith('\\\\')) {\n const rest = normalizePathSegments(normalizedRoot.slice(1).split('\\\\'), '\\\\')\n return joinWindowsRoot(cwdUnc?.prefix ?? drive, rest)\n }\n if (cwdUnc !== undefined) {\n const resolved = normalizePathSegments([...cwdUnc.rest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(cwdUnc.prefix, resolved)\n }\n const base = /^[A-Za-z]:\\\\/.test(normalizedCwd) ? normalizedCwd : `${drive}\\\\`\n const prefix = /^[A-Za-z]:/.exec(base)?.[0] ?? drive\n const baseRest = base.slice(prefix.length).replace(/^\\\\/, '').split('\\\\')\n const resolved = normalizePathSegments([...baseRest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(prefix, resolved)\n}\n\nfunction normalizeUncPath(path: string): string {\n const unc = splitUncPath(path)\n if (unc === undefined) return path\n return joinWindowsRoot(unc.prefix, normalizePathSegments(unc.rest, '\\\\'))\n}\n\nfunction splitUncPath(\n path: string,\n): { readonly prefix: string; readonly rest: string[] } | undefined {\n if (!path.startsWith('\\\\\\\\')) return undefined\n const parts = path.split('\\\\').filter((part) => part !== '')\n const [server, share, ...rest] = parts\n if (server === undefined || share === undefined) return undefined\n return { prefix: `\\\\\\\\${server}\\\\${share}`, rest }\n}\n\nfunction joinWindowsRoot(prefix: string, rest: string): string {\n return rest === '' ? `${prefix}\\\\` : `${prefix}\\\\${rest}`\n}\n\nfunction normalizePathSegments(segments: readonly string[], separator: '/' | '\\\\'): string {\n const out: string[] = []\n for (const segment of segments) {\n if (segment === '' || segment === '.') continue\n if (segment === '..') {\n out.pop()\n continue\n }\n out.push(segment)\n }\n return out.join(separator)\n}\n\nfunction joinSyncRelativePath(parent: string, child: string): string {\n return parent === '' ? child : `${parent}/${child}`\n}\n\nfunction isPathInsideRoot(root: string, path: string, nodeDeps: LocalNodeDeps): boolean {\n const rel = nodeDeps.relative(root, path)\n return (\n rel === '' ||\n (!rel.startsWith(`..${nodeDeps.sep}`) && rel !== '..' && !nodeDeps.isAbsolute(rel))\n )\n}\n\nfunction localNodeIdentity(stats: LocalStats): string {\n return `${stats.dev}:${stats.ino}`\n}\n\nfunction throwIfScanAborted(options: SyncScanOptions): void {\n if (options.signal?.aborted === true) {\n throw options.signal.reason ?? new DOMException('Aborted', 'AbortError')\n }\n}\n"],"mappings":"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"}
@@ -7,9 +7,10 @@ const require_sha1_options = require("./sha1-options.cjs");
7
7
  const require_local_sha1 = require("./local-sha1.cjs");
8
8
  const require_compare = require("./policies/compare.cjs");
9
9
  const require_index$1 = require("./policies/index.cjs");
10
+ const require_filesystem_errors = require("./filesystem-errors.cjs");
10
11
  const require_path_safety = require("./path-safety.cjs");
12
+ const require_download_staging = require("./download-staging.cjs");
11
13
  const require_prefix = require("./prefix.cjs");
12
- const require_filesystem_errors = require("./filesystem-errors.cjs");
13
14
  const require_local_filesystem_root = require("./local-filesystem-root.cjs");
14
15
  const require_b2_sha1_reader = require("./b2-sha1-reader.cjs");
15
16
  const require_local_file_io = require("./local-file-io.cjs");
@@ -64,6 +65,7 @@ async function* synchronize(config) {
64
65
  ...options.exclude !== void 0 ? { exclude: options.exclude } : {},
65
66
  ...options.signal !== void 0 ? { signal: options.signal } : {},
66
67
  ...options.maxScanEntries !== void 0 ? { maxScanEntries: options.maxScanEntries } : {},
68
+ ...options.localSymlinks !== void 0 ? { localSymlinks: options.localSymlinks } : {},
67
69
  ...direction === "b2-to-local" ? { requireLocalSafePaths: true } : {},
68
70
  onError: (event) => {
69
71
  scanHadError = true;
@@ -71,7 +73,10 @@ async function* synchronize(config) {
71
73
  queueEvent(event);
72
74
  }
73
75
  };
74
- const factory = createActionFactory(config, localRootContexts);
76
+ const downloadStagingRoots = await downloadStagingRootCleanupTargets(direction, localRootContexts);
77
+ const factory = createActionFactory(config, localRootContexts, { onDownloadStagingRoot(target) {
78
+ downloadStagingRoots.set(target.managedDirectory, target);
79
+ } });
75
80
  const readB2Sha1 = dryRun ? void 0 : createB2Sha1Reader(config);
76
81
  const actionAbortController = new AbortController();
77
82
  const removeAbortForwarder = forwardAbortSignal(options.signal, actionAbortController);
@@ -127,6 +132,7 @@ async function* synchronize(config) {
127
132
  if (!completed) abortActionController(actionAbortController, new DOMException("Sync iterator closed", "AbortError"));
128
133
  removeAbortForwarder();
129
134
  await drainActions();
135
+ await removeDownloadStagingRootMarkersAndDirectoriesAfterSync(downloadStagingRoots);
130
136
  }
131
137
  async function collectPairs() {
132
138
  const pairs = [];
@@ -145,6 +151,7 @@ async function* synchronize(config) {
145
151
  return pairs;
146
152
  }
147
153
  async function* emitSha1Batch(batch) {
154
+ /* v8 ignore next -- SHA-1 batches are sliced only while index is within pairs.length */
148
155
  if (batch.length === 0) return false;
149
156
  await drainActions();
150
157
  yield* emitQueuedEvents();
@@ -174,6 +181,7 @@ async function* synchronize(config) {
174
181
  return false;
175
182
  }
176
183
  async function processPreparedBatch(batch) {
184
+ /* v8 ignore next -- callers guard empty SHA-1 batches before preparing pairs */
177
185
  if (batch.length === 0) return {
178
186
  items: [],
179
187
  aborted: false
@@ -201,6 +209,7 @@ async function* synchronize(config) {
201
209
  function planPreparedPair(pair, prepared) {
202
210
  const event = {
203
211
  type: "compare",
212
+ /* v8 ignore next -- zipFolders never emits a pair with both sides absent */
204
213
  path: (pair[0] ?? pair[1])?.relativePath ?? "",
205
214
  size: 0,
206
215
  bytesHashed: prepared.bytesHashed,
@@ -224,9 +233,9 @@ async function* synchronize(config) {
224
233
  event,
225
234
  actions: [new require_index.SkipAction(prepared.pair[1].relativePath, "not removed because scan errors occurred")]
226
235
  };
227
- if (sourceInventoryIncomplete(scanEvents) && prepared.pair[0] === null && prepared.pair[1] !== null) return {
236
+ if (scanEvents.sourceInventoryIncompleteMessage !== void 0 && prepared.pair[0] === null && prepared.pair[1] !== null) return {
228
237
  event,
229
- actions: [new require_index.SkipAction(prepared.pair[1].relativePath, scanEvents.sourceInventoryIncompleteMessage ?? "not removed because the source scan skipped unsafe B2 names")]
238
+ actions: [new require_index.SkipAction(prepared.pair[1].relativePath, scanEvents.sourceInventoryIncompleteMessage)]
230
239
  };
231
240
  return {
232
241
  event,
@@ -288,6 +297,24 @@ async function* synchronize(config) {
288
297
  while (runningActions.size > 0) await Promise.race(runningActions);
289
298
  }
290
299
  }
300
+ async function downloadStagingRootCleanupTargets(direction, localRootContexts) {
301
+ const targets = /* @__PURE__ */ new Map();
302
+ if (direction !== "b2-to-local" || localRootContexts.dest === void 0) return targets;
303
+ const target = {
304
+ managedDirectory: (await import("node:path")).join(localRootContexts.dest.realPath, require_download_staging.DOWNLOAD_STAGING_DIRECTORY_NAME),
305
+ rootRealPath: localRootContexts.dest.realPath
306
+ };
307
+ targets.set(target.managedDirectory, target);
308
+ return targets;
309
+ }
310
+ async function removeDownloadStagingRootMarkersAndDirectoriesAfterSync(targets) {
311
+ if (targets.size === 0) return;
312
+ const path = await import("node:path");
313
+ for (const target of targets.values()) {
314
+ await synchronizerTestHooks.beforeDownloadStagingRootCleanup?.(target.managedDirectory);
315
+ await require_download_staging.removeDownloadStagingRootMarkerAndDirectory(target.rootRealPath, target.managedDirectory, path);
316
+ }
317
+ }
291
318
  /**
292
319
  * Normalizes user-provided sync concurrency before it controls compare batches and transfers.
293
320
  *
@@ -328,10 +355,11 @@ function createB2Sha1Reader(config) {
328
355
  if (maxBytes < expectedBytes) throw new Error(`sha1 B2 verification skipped because contentLength ${expectedBytes} exceeds ${maxBytes} byte verification budget`);
329
356
  const serverSideEncryption = toSseCDownloadKey(config.options.encryptionProvider?.getSettingForDownload(path.selectedVersion));
330
357
  const fileName = validateB2SyncPathInAnyPrefix(readablePrefixes, path, "read");
331
- const verified = await require_b2_sha1_reader.hashReadableStreamSha1((await bucket.file(fileName).downloadById(path.selectedVersion.fileId, {
358
+ const result = await bucket.file(fileName).downloadById(path.selectedVersion.fileId, {
332
359
  ...serverSideEncryption !== void 0 ? { serverSideEncryption } : {},
333
360
  signal: deadlineSignal
334
- })).body, deadlineSignal, {
361
+ });
362
+ const verified = await require_b2_sha1_reader.hashReadableStreamSha1(result.body, deadlineSignal, {
335
363
  idleTimeoutMillis,
336
364
  maxBytes,
337
365
  expectedBytes
@@ -462,10 +490,11 @@ function toSseCDownloadKey(setting) {
462
490
  *
463
491
  * @param config - Synchronizer configuration containing source, destination, and options.
464
492
  * @param localRootContexts - Resolved filesystem roots captured before action creation.
493
+ * @param lifecycleHooks - Hooks used to report action-scoped cleanup state.
465
494
  *
466
495
  * @returns An action factory bound to the provided configuration.
467
496
  */
468
- function createActionFactory(config, localRootContexts) {
497
+ function createActionFactory(config, localRootContexts, lifecycleHooks = {}) {
469
498
  const upConfig = config;
470
499
  const downConfig = config;
471
500
  const uploadPrefix = require_prefix.asRawB2KeyPrefix(upConfig.prefix ?? b2FolderRawPrefix(config.dest) ?? "");
@@ -480,16 +509,16 @@ function createActionFactory(config, localRootContexts) {
480
509
  const root = rootContext?.root ?? upConfig.source.root ?? "";
481
510
  const fileName = dest !== void 0 ? validateB2SyncPathInPrefix(uploadPrefix, dest) : `${uploadPrefix}${relPath}`;
482
511
  if (rootContext !== void 0) await assertLocalRootContextCurrent(rootContext, relPath, { allowSymlinkRoot: true });
483
- const targetPath = rootContext === void 0 ? await resolveContainedLocalPath(root, source.relativePath, absPath) : await resolveContainedLocalPath(rootContext.realPath, source.relativePath);
484
- throwIfAborted(signal);
512
+ const targetPath = rootContext === void 0 ? await resolveContainedLocalPath(root, source.relativePath, absPath) : config.options.localSymlinks === "follow" ? await resolveContainedLocalPath(rootContext.realPath, source.relativePath, absPath) : await resolveContainedLocalPath(rootContext.realPath, source.relativePath);
513
+ throwIfAborted(actionSignal(signal));
485
514
  const fileSource = await createValidatedUploadFileSource(source, targetPath);
486
- throwIfAborted(signal);
515
+ throwIfAborted(actionSignal(signal));
487
516
  const serverSideEncryption = config.options.encryptionProvider?.getSettingForUpload(fileName, fileSource.size);
488
517
  await bucket.upload({
489
518
  fileName,
490
519
  source: fileSource,
491
520
  ...serverSideEncryption !== void 0 ? { serverSideEncryption } : {},
492
- ...signal !== void 0 ? { signal } : {}
521
+ signal: actionSignal(signal)
493
522
  });
494
523
  });
495
524
  },
@@ -508,14 +537,22 @@ function createActionFactory(config, localRootContexts) {
508
537
  const serverSideEncryption = toSseCDownloadKey(config.options.encryptionProvider?.getSettingForDownload(source.selectedVersion));
509
538
  const result = await bucket.file(b2FileName).downloadById(source.selectedVersion.fileId, {
510
539
  ...serverSideEncryption !== void 0 ? { serverSideEncryption } : {},
511
- ...signal !== void 0 ? { signal } : {}
540
+ signal: actionSignal(signal)
512
541
  });
513
542
  try {
514
543
  await require_local_file_io.writeLocalStreamInsideRoot(root, relPath, result.body, {
515
544
  expectedBytes,
516
545
  ...scannedDest !== void 0 ? { expectedDestination: scannedDest } : {},
517
546
  idleTimeoutMillis,
518
- ...signal !== void 0 ? { signal } : {}
547
+ ...lifecycleHooks.onDownloadStagingRoot !== void 0 ? { onDownloadStagingRoot: (managedDirectory) => {
548
+ const rootRealPath = localRootContexts.dest?.realPath;
549
+ if (rootRealPath === void 0) return;
550
+ lifecycleHooks.onDownloadStagingRoot?.({
551
+ managedDirectory,
552
+ rootRealPath
553
+ });
554
+ } } : {},
555
+ signal: actionSignal(signal)
519
556
  });
520
557
  } catch (err) {
521
558
  await cancelReadableStreamBody(result.body, err);
@@ -533,7 +570,7 @@ function createActionFactory(config, localRootContexts) {
533
570
  const bucket = upConfig.bucket ?? downConfig.bucket;
534
571
  assertBucket(bucket, "hide");
535
572
  return new require_index.HideAction(path, async (_relPath, signal) => {
536
- await bucket.hideFile(`${uploadPrefix}${path}`, signal === void 0 ? void 0 : { signal });
573
+ await bucket.hideFile(`${uploadPrefix}${path}`, { signal: actionSignal(signal) });
537
574
  });
538
575
  },
539
576
  hideB2Path(path) {
@@ -541,7 +578,7 @@ function createActionFactory(config, localRootContexts) {
541
578
  assertBucket(bucket, "hide");
542
579
  const b2FileName = validateB2SyncPathInPrefix(uploadPrefix, path);
543
580
  return new require_index.HideAction(path.relativePath, async (_relPath, signal) => {
544
- await bucket.hideFile(b2FileName, signal === void 0 ? void 0 : { signal });
581
+ await bucket.hideFile(b2FileName, { signal: actionSignal(signal) });
545
582
  });
546
583
  },
547
584
  deleteRemote(path) {
@@ -549,16 +586,16 @@ function createActionFactory(config, localRootContexts) {
549
586
  assertBucket(bucket, "delete");
550
587
  const b2FileName = validateB2SyncPathInPrefix(uploadPrefix, path);
551
588
  return new require_index.DeleteRemoteAction(path.relativePath, path.selectedVersion.fileId, async (fileId$1, _fileName, signal) => {
552
- await bucket.deleteFileVersion(b2FileName, require_ids.fileId(fileId$1), signal === void 0 ? void 0 : { signal });
589
+ await bucket.deleteFileVersion(b2FileName, require_ids.fileId(fileId$1), { signal: actionSignal(signal) });
553
590
  });
554
591
  },
555
592
  deleteLocal(path) {
556
593
  const rootContext = localRootContexts.dest;
557
594
  const root = rootContext?.root ?? localSyncRoot(downConfig.dest);
558
595
  return new require_index.DeleteLocalAction(path.relativePath, path.absolutePath, async (absPath, signal) => {
559
- signal?.throwIfAborted();
596
+ actionSignal(signal).throwIfAborted();
560
597
  if (absPath !== path.absolutePath) throw new Error(`Refusing to delete outside sync root: ${path.relativePath}`);
561
- signal?.throwIfAborted();
598
+ actionSignal(signal).throwIfAborted();
562
599
  try {
563
600
  if (rootContext !== void 0) await assertLocalRootContextCurrent(rootContext, path.relativePath, { allowSymlinkRoot: false });
564
601
  await require_local_file_io.deleteLocalFileInsideRoot(root, path);
@@ -584,7 +621,7 @@ function createActionFactory(config, localRootContexts) {
584
621
  fileName: targetPath,
585
622
  ...destinationServerSideEncryption !== void 0 ? { destinationServerSideEncryption } : {},
586
623
  ...sourceServerSideEncryption !== void 0 ? { sourceServerSideEncryption } : {},
587
- ...signal !== void 0 ? { signal } : {}
624
+ signal: actionSignal(signal)
588
625
  });
589
626
  });
590
627
  }
@@ -650,10 +687,15 @@ function validateB2SyncPathInPrefix(prefix, path, operation = "mutate") {
650
687
  function isB2SyncPath(path) {
651
688
  return "selectedVersion" in path;
652
689
  }
690
+ var defaultActionSignal = new AbortController().signal;
691
+ function actionSignal(signal) {
692
+ return signal ?? defaultActionSignal;
693
+ }
653
694
  function throwIfAborted(signal) {
654
- if (signal?.aborted === true) throw signal.reason ?? new DOMException("Aborted", "AbortError");
695
+ if (signal.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
655
696
  }
656
697
  async function cancelReadableStreamBody(body, reason) {
698
+ /* v8 ignore next -- writeLocalStreamInsideRoot releases the body reader before throwing */
657
699
  if (body.locked) return;
658
700
  try {
659
701
  await body.cancel(reason);
@@ -703,10 +745,7 @@ function bufferScanEvent(buffer, event, direction, scanSide) {
703
745
  else buffer.dropped++;
704
746
  }
705
747
  function* drainScanEvents(buffer) {
706
- while (buffer.events.length > 0) {
707
- const event = buffer.events.shift();
708
- if (event) yield event;
709
- }
748
+ while (buffer.events.length > 0) yield buffer.events.shift();
710
749
  if (buffer.dropped > 0) {
711
750
  yield {
712
751
  type: "skip",
@@ -721,9 +760,6 @@ function* drainScanEvents(buffer) {
721
760
  function scanHadFilesystemError(scanEvents) {
722
761
  return scanEvents.fatalFilesystemErrorMessage !== void 0;
723
762
  }
724
- function sourceInventoryIncomplete(scanEvents) {
725
- return scanEvents.sourceInventoryIncompleteMessage !== void 0;
726
- }
727
763
  function scanFilesystemError(scanEvents) {
728
764
  return scanEvents.fatalFilesystemErrorMessage === void 0 ? void 0 : new Error(scanEvents.fatalFilesystemErrorMessage);
729
765
  }
@@ -742,14 +778,26 @@ function isLocalDeleteSafetyError(err) {
742
778
  }
743
779
  async function resolveContainedLocalPath(root, relativePath, absolutePath) {
744
780
  if (root === "") throw new Error("Local sync root required for filesystem mutation");
781
+ const { realpath } = await import("node:fs/promises");
745
782
  const { isAbsolute, relative, resolve, sep } = await import("node:path");
746
783
  const safeRoot = resolve(root);
747
784
  const target = absolutePath === void 0 ? resolve(safeRoot, relativePath) : resolve(absolutePath);
748
- const pathFromRoot = relative(safeRoot, target);
785
+ let containmentRoot = safeRoot;
786
+ let pathFromRoot = relative(containmentRoot, target);
787
+ let escapesRoot = pathFromRoot === ".." || pathFromRoot.startsWith(`..${sep}`) || isAbsolute(pathFromRoot);
788
+ if (escapesRoot && absolutePath !== void 0) {
789
+ const realRoot = await realpath(safeRoot).catch(() => safeRoot);
790
+ const realPathFromRoot = relative(realRoot, target);
791
+ if (!(realPathFromRoot === ".." || realPathFromRoot.startsWith(`..${sep}`) || isAbsolute(realPathFromRoot))) {
792
+ containmentRoot = realRoot;
793
+ pathFromRoot = realPathFromRoot;
794
+ escapesRoot = false;
795
+ }
796
+ }
749
797
  /* v8 ignore next -- defense-in-depth after prior no-follow and symlink checks. */
750
- if (pathFromRoot === ".." || pathFromRoot.startsWith(`..${sep}`) || isAbsolute(pathFromRoot)) throw new Error(`Refusing to access path outside sync root: ${relativePath}`);
751
- await assertLocalRootHasNoSymlink(safeRoot, relativePath);
752
- await assertPathHasNoSymlinkComponents(safeRoot, pathFromRoot, relativePath);
798
+ if (escapesRoot) throw new Error(`Refusing to access path outside sync root: ${relativePath}`);
799
+ await assertLocalRootHasNoSymlink(containmentRoot, relativePath);
800
+ await assertPathHasNoSymlinkComponents(containmentRoot, pathFromRoot, relativePath);
753
801
  return target;
754
802
  }
755
803
  async function assertLocalRootHasNoSymlink(safeRoot, relativePath) {