@openclaw/fs-safe 0.11.0 → 0.13.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 (416) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +15 -8
  3. package/dist/absolute-path.d.ts.map +1 -1
  4. package/dist/absolute-path.js +32 -11
  5. package/dist/advanced.d.ts +3 -1
  6. package/dist/advanced.d.ts.map +1 -1
  7. package/dist/advanced.js +3 -1
  8. package/dist/archive-entry.d.ts.map +1 -1
  9. package/dist/archive-entry.js +4 -3
  10. package/dist/archive-gzip-tail.d.ts.map +1 -1
  11. package/dist/archive-gzip-tail.js +13 -9
  12. package/dist/archive-input.d.ts.map +1 -1
  13. package/dist/archive-input.js +6 -2
  14. package/dist/archive-merge.d.ts.map +1 -1
  15. package/dist/archive-merge.js +15 -2
  16. package/dist/archive-native.d.ts.map +1 -1
  17. package/dist/archive-native.js +7 -19
  18. package/dist/archive-plan.js +1 -1
  19. package/dist/archive-read.d.ts.map +1 -1
  20. package/dist/archive-read.js +55 -46
  21. package/dist/archive-staging.d.ts.map +1 -1
  22. package/dist/archive-staging.js +43 -10
  23. package/dist/archive-tar-inspect.d.ts.map +1 -1
  24. package/dist/archive-tar-inspect.js +4 -1
  25. package/dist/archive-zip-admission.d.ts +1 -1
  26. package/dist/archive-zip-admission.d.ts.map +1 -1
  27. package/dist/archive-zip-admission.js +2 -2
  28. package/dist/archive-zip-directory.d.ts +3 -0
  29. package/dist/archive-zip-directory.d.ts.map +1 -1
  30. package/dist/archive-zip-directory.js +13 -2
  31. package/dist/archive-zip-loader.d.ts +3 -2
  32. package/dist/archive-zip-loader.d.ts.map +1 -1
  33. package/dist/archive-zip-loader.js +30 -4
  34. package/dist/archive-zip-manifest.d.ts +5 -0
  35. package/dist/archive-zip-manifest.d.ts.map +1 -0
  36. package/dist/archive-zip-manifest.js +22 -0
  37. package/dist/archive-zip-names.d.ts +6 -1
  38. package/dist/archive-zip-names.d.ts.map +1 -1
  39. package/dist/archive-zip-names.js +50 -17
  40. package/dist/archive-zip-preflight.d.ts.map +1 -1
  41. package/dist/archive-zip-preflight.js +3 -2
  42. package/dist/archive.d.ts.map +1 -1
  43. package/dist/archive.js +9 -4
  44. package/dist/bounded-read.js +2 -2
  45. package/dist/darwin-acl.d.ts +4 -0
  46. package/dist/darwin-acl.d.ts.map +1 -0
  47. package/dist/darwin-acl.js +24 -0
  48. package/dist/deny-mutations.d.ts.map +1 -1
  49. package/dist/deny-mutations.js +8 -2
  50. package/dist/device-path.d.ts.map +1 -1
  51. package/dist/device-path.js +5 -3
  52. package/dist/directory-durability.d.ts.map +1 -1
  53. package/dist/directory-durability.js +67 -23
  54. package/dist/directory-entry-path.d.ts +3 -0
  55. package/dist/directory-entry-path.d.ts.map +1 -0
  56. package/dist/directory-entry-path.js +21 -0
  57. package/dist/directory-guard.d.ts +17 -1
  58. package/dist/directory-guard.d.ts.map +1 -1
  59. package/dist/directory-guard.js +134 -48
  60. package/dist/directory-mode-node.d.ts +12 -0
  61. package/dist/directory-mode-node.d.ts.map +1 -1
  62. package/dist/directory-mode-node.js +102 -4
  63. package/dist/effective-uid.d.ts +2 -0
  64. package/dist/effective-uid.d.ts.map +1 -0
  65. package/dist/effective-uid.js +25 -0
  66. package/dist/file-handle-transfer.d.ts.map +1 -1
  67. package/dist/file-handle-transfer.js +98 -27
  68. package/dist/file-hash.d.ts.map +1 -1
  69. package/dist/file-hash.js +12 -2
  70. package/dist/file-lock-sync.d.ts.map +1 -1
  71. package/dist/file-lock-sync.js +36 -6
  72. package/dist/file-lock.d.ts.map +1 -1
  73. package/dist/file-lock.js +29 -9
  74. package/dist/file-observation.d.ts +1 -1
  75. package/dist/file-observation.d.ts.map +1 -1
  76. package/dist/file-store-boundary.d.ts +6 -2
  77. package/dist/file-store-boundary.d.ts.map +1 -1
  78. package/dist/file-store-boundary.js +20 -65
  79. package/dist/file-store-copy-source.d.ts +5 -0
  80. package/dist/file-store-copy-source.d.ts.map +1 -0
  81. package/dist/file-store-copy-source.js +31 -0
  82. package/dist/file-store-path.d.ts.map +1 -1
  83. package/dist/file-store-path.js +4 -1
  84. package/dist/file-store-prune.d.ts.map +1 -1
  85. package/dist/file-store-prune.js +9 -1
  86. package/dist/file-store-sync-directory.d.ts +16 -0
  87. package/dist/file-store-sync-directory.d.ts.map +1 -0
  88. package/dist/file-store-sync-directory.js +349 -0
  89. package/dist/file-store.d.ts.map +1 -1
  90. package/dist/file-store.js +11 -28
  91. package/dist/filename.d.ts +1 -0
  92. package/dist/filename.d.ts.map +1 -1
  93. package/dist/filename.js +85 -23
  94. package/dist/fs.d.ts.map +1 -1
  95. package/dist/fs.js +3 -2
  96. package/dist/guarded-mkdir.d.ts +10 -0
  97. package/dist/guarded-mkdir.d.ts.map +1 -1
  98. package/dist/guarded-mkdir.js +217 -33
  99. package/dist/guest.d.ts.map +1 -1
  100. package/dist/guest.js +16 -5
  101. package/dist/home-dir.d.ts.map +1 -1
  102. package/dist/home-dir.js +73 -10
  103. package/dist/install-path.d.ts +6 -0
  104. package/dist/install-path.d.ts.map +1 -1
  105. package/dist/install-path.js +67 -19
  106. package/dist/json-durable-queue-ownership.d.ts +8 -0
  107. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  108. package/dist/json-durable-queue-ownership.js +134 -43
  109. package/dist/json-durable-queue-paths.d.ts +11 -0
  110. package/dist/json-durable-queue-paths.d.ts.map +1 -0
  111. package/dist/json-durable-queue-paths.js +42 -0
  112. package/dist/json-durable-queue-read.d.ts +6 -0
  113. package/dist/json-durable-queue-read.d.ts.map +1 -0
  114. package/dist/json-durable-queue-read.js +61 -0
  115. package/dist/json-durable-queue.d.ts +1 -1
  116. package/dist/json-durable-queue.d.ts.map +1 -1
  117. package/dist/json-durable-queue.js +83 -134
  118. package/dist/json-store.d.ts.map +1 -1
  119. package/dist/json-store.js +5 -1
  120. package/dist/json.d.ts.map +1 -1
  121. package/dist/json.js +54 -22
  122. package/dist/local-file-access.d.ts.map +1 -1
  123. package/dist/local-file-access.js +4 -0
  124. package/dist/local-file-descriptor.d.ts +17 -0
  125. package/dist/local-file-descriptor.d.ts.map +1 -0
  126. package/dist/local-file-descriptor.js +84 -0
  127. package/dist/local-roots.d.ts.map +1 -1
  128. package/dist/local-roots.js +35 -7
  129. package/dist/move-path-cleanup.d.ts +2 -0
  130. package/dist/move-path-cleanup.d.ts.map +1 -1
  131. package/dist/move-path-cleanup.js +44 -18
  132. package/dist/move-path.d.ts.map +1 -1
  133. package/dist/move-path.js +31 -6
  134. package/dist/native-binding.d.ts +21 -0
  135. package/dist/native-binding.d.ts.map +1 -1
  136. package/dist/native-directory-observation.d.ts +17 -0
  137. package/dist/native-directory-observation.d.ts.map +1 -0
  138. package/dist/native-directory-observation.js +37 -0
  139. package/dist/native-parent-admission.d.ts +31 -0
  140. package/dist/native-parent-admission.d.ts.map +1 -0
  141. package/dist/native-parent-admission.js +124 -0
  142. package/dist/native-pinned-write-windows.d.ts +0 -1
  143. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  144. package/dist/native-pinned-write-windows.js +0 -3
  145. package/dist/native-pinned-write.d.ts.map +1 -1
  146. package/dist/native-pinned-write.js +309 -40
  147. package/dist/output.d.ts.map +1 -1
  148. package/dist/output.js +15 -5
  149. package/dist/overwrite-file-handle.d.ts.map +1 -1
  150. package/dist/overwrite-file-handle.js +5 -1
  151. package/dist/owner-dacl.d.ts.map +1 -1
  152. package/dist/owner-dacl.js +2 -0
  153. package/dist/path-policy.d.ts.map +1 -1
  154. package/dist/path-policy.js +7 -2
  155. package/dist/path-prefix.d.ts +7 -0
  156. package/dist/path-prefix.d.ts.map +1 -0
  157. package/dist/path-prefix.js +82 -0
  158. package/dist/path-scope-lexical.d.ts +14 -0
  159. package/dist/path-scope-lexical.d.ts.map +1 -0
  160. package/dist/path-scope-lexical.js +37 -0
  161. package/dist/path-segment-route.d.ts +7 -0
  162. package/dist/path-segment-route.d.ts.map +1 -0
  163. package/dist/path-segment-route.js +24 -0
  164. package/dist/path-suffix-aliases.d.ts +10 -0
  165. package/dist/path-suffix-aliases.d.ts.map +1 -0
  166. package/dist/path-suffix-aliases.js +386 -0
  167. package/dist/path.d.ts.map +1 -1
  168. package/dist/path.js +35 -6
  169. package/dist/permissions-windows.d.ts.map +1 -1
  170. package/dist/permissions-windows.js +14 -3
  171. package/dist/permissions.d.ts.map +1 -1
  172. package/dist/permissions.js +37 -8
  173. package/dist/pinned-mutation-admission.d.ts +25 -0
  174. package/dist/pinned-mutation-admission.d.ts.map +1 -0
  175. package/dist/pinned-mutation-admission.js +425 -0
  176. package/dist/pinned-mutation-observation.d.ts +34 -0
  177. package/dist/pinned-mutation-observation.d.ts.map +1 -0
  178. package/dist/pinned-mutation-observation.js +142 -0
  179. package/dist/pinned-mutation-shared-route.d.ts +24 -0
  180. package/dist/pinned-mutation-shared-route.d.ts.map +1 -0
  181. package/dist/pinned-mutation-shared-route.js +70 -0
  182. package/dist/pinned-open.d.ts +6 -0
  183. package/dist/pinned-open.d.ts.map +1 -1
  184. package/dist/pinned-open.js +28 -10
  185. package/dist/pinned-write-types.d.ts +75 -0
  186. package/dist/pinned-write-types.d.ts.map +1 -0
  187. package/dist/pinned-write-types.js +1 -0
  188. package/dist/pinned-write.d.ts +7 -33
  189. package/dist/pinned-write.d.ts.map +1 -1
  190. package/dist/pinned-write.js +152 -17
  191. package/dist/private-directory.d.ts.map +1 -1
  192. package/dist/private-directory.js +2 -0
  193. package/dist/private-producer-handoff.d.ts +16 -0
  194. package/dist/private-producer-handoff.d.ts.map +1 -0
  195. package/dist/private-producer-handoff.js +272 -0
  196. package/dist/private-temp-workspace.d.ts +2 -39
  197. package/dist/private-temp-workspace.d.ts.map +1 -1
  198. package/dist/private-temp-workspace.js +183 -77
  199. package/dist/publish-file.d.ts.map +1 -1
  200. package/dist/publish-file.js +33 -29
  201. package/dist/regular-file.d.ts.map +1 -1
  202. package/dist/regular-file.js +56 -45
  203. package/dist/replace-directory.d.ts.map +1 -1
  204. package/dist/replace-directory.js +12 -5
  205. package/dist/replace-file-temp-owner.d.ts +1 -0
  206. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  207. package/dist/replace-file-temp-owner.js +12 -1
  208. package/dist/replace-file.d.ts.map +1 -1
  209. package/dist/replace-file.js +24 -24
  210. package/dist/root-boundary.d.ts +29 -0
  211. package/dist/root-boundary.d.ts.map +1 -0
  212. package/dist/root-boundary.js +182 -0
  213. package/dist/root-context.d.ts +12 -1
  214. package/dist/root-context.d.ts.map +1 -1
  215. package/dist/root-context.js +89 -16
  216. package/dist/root-directory-creation.d.ts +13 -0
  217. package/dist/root-directory-creation.d.ts.map +1 -0
  218. package/dist/root-directory-creation.js +212 -0
  219. package/dist/root-directory-list.d.ts +16 -4
  220. package/dist/root-directory-list.d.ts.map +1 -1
  221. package/dist/root-directory-list.js +182 -33
  222. package/dist/root-directory.d.ts +23 -0
  223. package/dist/root-directory.d.ts.map +1 -0
  224. package/dist/root-directory.js +141 -0
  225. package/dist/root-errors.d.ts.map +1 -1
  226. package/dist/root-errors.js +12 -1
  227. package/dist/root-file-final-admission.d.ts +21 -0
  228. package/dist/root-file-final-admission.d.ts.map +1 -0
  229. package/dist/root-file-final-admission.js +83 -0
  230. package/dist/root-file.d.ts.map +1 -1
  231. package/dist/root-file.js +103 -24
  232. package/dist/root-impl.d.ts +1 -0
  233. package/dist/root-impl.d.ts.map +1 -1
  234. package/dist/root-impl.js +316 -325
  235. package/dist/root-move-noreplace.d.ts +14 -0
  236. package/dist/root-move-noreplace.d.ts.map +1 -0
  237. package/dist/root-move-noreplace.js +202 -0
  238. package/dist/root-move-preflight.d.ts +8 -0
  239. package/dist/root-move-preflight.d.ts.map +1 -0
  240. package/dist/root-move-preflight.js +16 -0
  241. package/dist/root-observed-path.d.ts +9 -0
  242. package/dist/root-observed-path.d.ts.map +1 -0
  243. package/dist/root-observed-path.js +95 -0
  244. package/dist/root-path-errors.d.ts +12 -0
  245. package/dist/root-path-errors.d.ts.map +1 -0
  246. package/dist/root-path-errors.js +13 -0
  247. package/dist/root-path-existing.d.ts +2 -0
  248. package/dist/root-path-existing.d.ts.map +1 -1
  249. package/dist/root-path-existing.js +63 -22
  250. package/dist/root-path-observation.d.ts +63 -0
  251. package/dist/root-path-observation.d.ts.map +1 -0
  252. package/dist/root-path-observation.js +180 -0
  253. package/dist/root-path-stat.d.ts +5 -0
  254. package/dist/root-path-stat.d.ts.map +1 -0
  255. package/dist/root-path-stat.js +101 -0
  256. package/dist/root-path-symlink.d.ts.map +1 -1
  257. package/dist/root-path-symlink.js +23 -4
  258. package/dist/root-path.d.ts +13 -0
  259. package/dist/root-path.d.ts.map +1 -1
  260. package/dist/root-path.js +263 -73
  261. package/dist/root-paths-lexical.d.ts +9 -0
  262. package/dist/root-paths-lexical.d.ts.map +1 -0
  263. package/dist/root-paths-lexical.js +22 -0
  264. package/dist/root-paths.d.ts +3 -29
  265. package/dist/root-paths.d.ts.map +1 -1
  266. package/dist/root-paths.js +89 -178
  267. package/dist/root-read-admission.d.ts +26 -0
  268. package/dist/root-read-admission.d.ts.map +1 -0
  269. package/dist/root-read-admission.js +94 -0
  270. package/dist/root-remove-identity.d.ts +15 -0
  271. package/dist/root-remove-identity.d.ts.map +1 -0
  272. package/dist/root-remove-identity.js +89 -0
  273. package/dist/root-remove-receipt.d.ts +17 -0
  274. package/dist/root-remove-receipt.d.ts.map +1 -0
  275. package/dist/root-remove-receipt.js +37 -0
  276. package/dist/root-remove.d.ts +2 -1
  277. package/dist/root-remove.d.ts.map +1 -1
  278. package/dist/root-remove.js +172 -10
  279. package/dist/root-walk.d.ts.map +1 -1
  280. package/dist/root-walk.js +2 -1
  281. package/dist/root-write-admission.d.ts +68 -0
  282. package/dist/root-write-admission.d.ts.map +1 -0
  283. package/dist/root-write-admission.js +322 -0
  284. package/dist/root-write-compatibility.d.ts +13 -0
  285. package/dist/root-write-compatibility.d.ts.map +1 -0
  286. package/dist/root-write-compatibility.js +74 -0
  287. package/dist/root-write-complete-parent.d.ts +42 -0
  288. package/dist/root-write-complete-parent.d.ts.map +1 -0
  289. package/dist/root-write-complete-parent.js +195 -0
  290. package/dist/root-write-mode.d.ts +2 -0
  291. package/dist/root-write-mode.d.ts.map +1 -1
  292. package/dist/root-write-mode.js +20 -7
  293. package/dist/root-write-publication.d.ts +24 -0
  294. package/dist/root-write-publication.d.ts.map +1 -0
  295. package/dist/root-write-publication.js +85 -0
  296. package/dist/root-write-verification.d.ts.map +1 -1
  297. package/dist/root-write-verification.js +18 -7
  298. package/dist/safe-path-segment.d.ts.map +1 -1
  299. package/dist/safe-path-segment.js +3 -1
  300. package/dist/secret-file.d.ts.map +1 -1
  301. package/dist/secret-file.js +62 -24
  302. package/dist/secret-read-async.d.ts.map +1 -1
  303. package/dist/secret-read-async.js +18 -13
  304. package/dist/secret-read-policy.d.ts.map +1 -1
  305. package/dist/secret-read-policy.js +5 -1
  306. package/dist/secure-file-windows.d.ts +10 -0
  307. package/dist/secure-file-windows.d.ts.map +1 -0
  308. package/dist/secure-file-windows.js +186 -0
  309. package/dist/secure-file.d.ts.map +1 -1
  310. package/dist/secure-file.js +98 -10
  311. package/dist/secure-temp-dir.d.ts +6 -3
  312. package/dist/secure-temp-dir.d.ts.map +1 -1
  313. package/dist/secure-temp-dir.js +121 -101
  314. package/dist/secure-temp-repair.d.ts +35 -0
  315. package/dist/secure-temp-repair.d.ts.map +1 -0
  316. package/dist/secure-temp-repair.js +106 -0
  317. package/dist/sibling-staged-file.d.ts +3 -1
  318. package/dist/sibling-staged-file.d.ts.map +1 -1
  319. package/dist/sibling-staged-file.js +181 -50
  320. package/dist/sibling-temp.d.ts.map +1 -1
  321. package/dist/sibling-temp.js +27 -12
  322. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  323. package/dist/sidecar-lock-acquire.js +45 -15
  324. package/dist/sidecar-lock-root.d.ts.map +1 -1
  325. package/dist/sidecar-lock-root.js +4 -2
  326. package/dist/sidecar-lock.d.ts.map +1 -1
  327. package/dist/sidecar-lock.js +2 -3
  328. package/dist/staged-directory.d.ts +14 -5
  329. package/dist/staged-directory.d.ts.map +1 -1
  330. package/dist/staged-directory.js +54 -3
  331. package/dist/standalone-publication-path.d.ts +2 -0
  332. package/dist/standalone-publication-path.d.ts.map +1 -0
  333. package/dist/standalone-publication-path.js +6 -0
  334. package/dist/stat-observation.d.ts +11 -0
  335. package/dist/stat-observation.d.ts.map +1 -0
  336. package/dist/stat-observation.js +64 -0
  337. package/dist/strict-file-identity.d.ts.map +1 -1
  338. package/dist/strict-file-identity.js +39 -2
  339. package/dist/symlink-parents.d.ts.map +1 -1
  340. package/dist/symlink-parents.js +7 -2
  341. package/dist/temp-target.d.ts +2 -0
  342. package/dist/temp-target.d.ts.map +1 -1
  343. package/dist/temp-target.js +133 -4
  344. package/dist/temp-workspace-admission.d.ts +22 -0
  345. package/dist/temp-workspace-admission.d.ts.map +1 -0
  346. package/dist/temp-workspace-admission.js +374 -0
  347. package/dist/temp-workspace-child-admission.d.ts +13 -0
  348. package/dist/temp-workspace-child-admission.d.ts.map +1 -0
  349. package/dist/temp-workspace-child-admission.js +95 -0
  350. package/dist/temp-workspace-descriptor.d.ts +48 -0
  351. package/dist/temp-workspace-descriptor.d.ts.map +1 -0
  352. package/dist/temp-workspace-descriptor.js +363 -0
  353. package/dist/temp-workspace-identity.d.ts +15 -0
  354. package/dist/temp-workspace-identity.d.ts.map +1 -0
  355. package/dist/temp-workspace-identity.js +41 -0
  356. package/dist/temp-workspace-owner.d.ts +7 -6
  357. package/dist/temp-workspace-owner.d.ts.map +1 -1
  358. package/dist/temp-workspace-owner.js +121 -61
  359. package/dist/temp-workspace-permissions.d.ts +4 -0
  360. package/dist/temp-workspace-permissions.d.ts.map +1 -0
  361. package/dist/temp-workspace-permissions.js +32 -0
  362. package/dist/temp-workspace-types.d.ts +40 -0
  363. package/dist/temp-workspace-types.d.ts.map +1 -0
  364. package/dist/temp-workspace-types.js +1 -0
  365. package/dist/temp.d.ts +1 -1
  366. package/dist/temp.d.ts.map +1 -1
  367. package/dist/temp.js +1 -1
  368. package/dist/test-hooks.d.ts +7 -0
  369. package/dist/test-hooks.d.ts.map +1 -1
  370. package/dist/text-atomic.d.ts.map +1 -1
  371. package/dist/text-atomic.js +3 -1
  372. package/dist/trash.d.ts.map +1 -1
  373. package/dist/trash.js +54 -8
  374. package/dist/walk.d.ts.map +1 -1
  375. package/dist/walk.js +20 -16
  376. package/dist/windows-owner.d.ts.map +1 -1
  377. package/dist/windows-owner.js +5 -0
  378. package/dist/windows-path-alias.d.ts +39 -0
  379. package/dist/windows-path-alias.d.ts.map +1 -0
  380. package/dist/windows-path-alias.js +153 -0
  381. package/docs/advanced.md +28 -1
  382. package/docs/archive.md +29 -2
  383. package/docs/atomic.md +27 -3
  384. package/docs/contributing.md +4 -1
  385. package/docs/copy.md +4 -1
  386. package/docs/durability.md +18 -2
  387. package/docs/errors.md +14 -6
  388. package/docs/file-store.md +30 -3
  389. package/docs/filename.md +21 -7
  390. package/docs/guest.md +5 -0
  391. package/docs/install-path.md +61 -15
  392. package/docs/install.md +12 -8
  393. package/docs/json-store.md +5 -1
  394. package/docs/json.md +11 -0
  395. package/docs/mutation-policy-proof.md +65 -0
  396. package/docs/native-helper.md +28 -9
  397. package/docs/native.md +46 -10
  398. package/docs/output.md +33 -11
  399. package/docs/path-prefix.md +64 -0
  400. package/docs/path-suffix-aliases.md +159 -0
  401. package/docs/path.md +12 -1
  402. package/docs/permissions.md +26 -1
  403. package/docs/private-file-store.md +14 -0
  404. package/docs/public-api.md +14 -0
  405. package/docs/quickstart.md +1 -1
  406. package/docs/reading.md +8 -1
  407. package/docs/root.md +21 -4
  408. package/docs/secret-file.md +3 -0
  409. package/docs/secure-file.md +21 -16
  410. package/docs/security-model.md +76 -9
  411. package/docs/sidecar-lock.md +28 -1
  412. package/docs/store.md +27 -2
  413. package/docs/temp.md +262 -34
  414. package/docs/test-hooks.md +14 -0
  415. package/docs/writing.md +38 -8
  416. package/package.json +10 -10
package/CHANGELOG.md CHANGED
@@ -2,6 +2,125 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.13.0 - 2026-09-16
6
+
7
+ ### Highlights
8
+
9
+ - **Stronger protection against filesystem replacement races:** bind Root reads, metadata, writes, moves, and cleanup to exact file and directory identities; use atomic native rename for no-clobber moves.
10
+ - **Less overhead in guarded writes and archives:** avoid repeated path and mutation-policy work on eligible routes, reuse validated archive paths, and size native result buffers to bounded member sizes.
11
+ - **Safer Windows paths and writes:** reject NTFS stream and directory-index aliases before filesystem access, and retain destination handles through compatibility writes and verification.
12
+ - **New tools for prospective paths:** add `resolvePathPrefixSync()` and `probePathSuffixAliasesSync()` for existing-prefix traversal and bounded observations of missing suffix aliases.
13
+ - **Opt-in bounded temporary-file cleanup:** add retained-directory cleanup ownership to `tempFile()` and strengthen temporary-workspace admission and permission repair.
14
+
15
+ ### Compatibility and upgrade notes
16
+
17
+ - **No-clobber `Root.move()` now requires usable native support.** With `overwrite` omitted or `false`, native-off mode, missing bindings, or unavailable safe parent/rename support fail with `helper-unavailable`; there is no JavaScript check-and-replace fallback. Keep the matching native package installed for these moves. Directory moves still require `overwrite: true`, which retains guarded JavaScript support; use it only when replacement is intended. Post-operation verification can report an error after a rename has completed.
18
+ - Windows alternate-data-stream and directory-index aliases now reject across guarded APIs before I/O. Supported rooted and extended-drive paths retain their handling, as do released drive-relative forms in trusted-path atomic, store/queue, move, publication, and lock APIs. Existing Root destination restrictions remain distinct; ordinary colon-bearing POSIX names keep their established rules.
19
+ - POSIX secure-file ownership checks now use the process's effective user ID and fail closed when required identity facts are unavailable. Public `Stats` values remain numeric; exact writable-file verification uses private bigint receipts.
20
+ - `tempFile({ cleanupSafety: "require-bounded" })` is opt-in and requires an existing supplied root plus supported retained-parent cleanup. Unsupported admission fails before child creation. `"compatible"` remains the default; cleanup callbacks and error-suppression behavior are preserved. Bounded cleanup retains the documented [POSIX final-entry unlink limitation](https://github.com/openclaw/fs-safe/blob/v0.13.0/docs/temp.md).
21
+ - The two new path helpers are observations, not permission to access a path. Prefix resolution is read-only but is not a pinned or consistent snapshot. Suffix probing can create and remove directories under an approved writable parent, returns `undefined` when unresolved, and may preserve artifacts whose ownership cannot be verified; its budgets limit work counts and path sizes, not elapsed time.
22
+
23
+ ### Root boundaries and mutation performance
24
+
25
+ - Fence Root content reads, metadata observations, directory entries, and low-level file opens with exact captured-root, parent, and final-path identities. Admit supported native Windows root spellings without relaxing symlink or replacement rejection.
26
+ - Apply `denyMutations` and mutation-symlink policy to the actual retained parent used by `Root.write`, `Root.create`, `Root.copyIn`, `Root.openWritable`, `Root.append`, and `Root.mkdir`, including Windows buffer fallbacks. Admit missing components before creating them, and re-authorize followed final-link destinations before open, truncation, staging, and publication.
27
+ - Reuse operation-local policy observations, canonical parent guards, post-create receipts, and immutable suffix offsets for eligible Node.js mutation paths. This avoids repeated resolver work and depth-quadratic segment copies; collisions, callbacks, aliases, ambiguous routes, incomplete identity observations, and final open/publication/cleanup checks retain full admission.
28
+ - Bound repeated resolver work during deep missing-parent creation on eligible Windows and POSIX JavaScript paths. Advance only through owned directory-creation receipts, and let `Root.mkdir` reuse an exact existing-parent proof for its single missing child.
29
+ - Reuse an already admitted parent guard for private producer Roots while preserving isolated handoff, including legacy Windows delete-pending and read-only restoration behavior.
30
+ - Bind nonrecursive removal to its admitted parent and revalidate native move endpoints and explicit parent-symlink rejection before dispatch. Recheck copied-directory identities after child cleanup so concurrent replacements are preserved.
31
+
32
+ ### Credentials, permissions, and temporary files
33
+
34
+ - Snapshot secure-read, secret-reader, traversal, and borrowed-transfer policies before asynchronous work, including size/link limits, trusted directories, and selected environment values. In-flight admission can no longer be relaxed by changing shared options.
35
+ - Preserve single-read pathname and authority accessors on Node.js 22, along with callback receivers, cancellation signals, and progress callbacks across JSON, durable directory/queue, sibling-staging, and borrowed-handle operations. Windows temp admission remains active with platform adapters, and canonical prefixes are checked before inspection.
36
+ - Bind secure temporary-directory and synchronous store-directory mode repairs to no-follow descriptors and exact current identities, including concurrent mode changes during the matching-mode fast path.
37
+ - Admit temporary-workspace roots and children before use, preserve existing permissions, and bind initialization and cleanup to retained identities. Opt-in bounded temporary-file admission closes descriptors on failure.
38
+ - Retain Windows destination descriptors through buffered compatibility-write locking, content verification, mode changes, sync, and final identity checks.
39
+ - Validate descriptor-bound macOS clone ACLs before admission and publication, including absent ACLs. Once payload bytes exist, normalization or security failures are terminal `EIO` errors rather than a reason to retry with an ordinary copy.
40
+
41
+ ### Archive safety and performance
42
+
43
+ - Bind physical ZIP entry names and file/directory kinds to decoder metadata before callbacks or member selection, rejecting ambiguous interpretations consistently.
44
+ - Stop zstd and bzip2 compressed-input refills after cancellation while preserving decoded-output limits and complete archive validation.
45
+ - Reuse canonical archive paths when no components are stripped and avoid temporary ZIP collision collections, retaining validation/filter order and checks of both raw and Unicode identities.
46
+ - Reserve native archive result capacity from bounded member-size hints so small ZIP and compressed TAR reads do not allocate the caller's larger byte budget.
47
+
48
+ ### Path helpers and reliability
49
+
50
+ - Add [`resolvePathPrefixSync()`](https://github.com/openclaw/fs-safe/blob/v0.13.0/docs/path-prefix.md) under `@openclaw/fs-safe/advanced` to traverse existing path prefixes while retaining the raw missing suffix, preserving dangling aliases and propagating ambiguous resolution failures.
51
+ - Add [`probePathSuffixAliasesSync()`](https://github.com/openclaw/fs-safe/blob/v0.13.0/docs/path-suffix-aliases.md) under `@openclaw/fs-safe/advanced`, with fixed path, depth, creation, and observation budgets and conservative identity-checked cleanup.
52
+ - Sanitize fallback filenames and validate completed sibling callback names before producers run, retaining length bounds and Windows device-name rejection. Reuse Windows namespace admission for unchanged ordinary rooted-drive paths while keeping full checks for relative, normalized, malformed, namespaced, and colon-bearing forms.
53
+ - Pin asynchronous relative sidecar-lock paths and roots to their entry-time working directory through acquisition, reclaim, verification, and release. Close synchronous lock descriptors after metadata inspection failures while preserving the original error and unverified sidecar; retry vanished admitted successors under the existing identity checks and budgets.
54
+ - Report actionable guarded-write errno diagnostics while preserving error codes, categories, original causes, and already-classified failures.
55
+ - Tolerate concurrent guest parent-directory creation only after descriptor-relative no-follow admission; file and symlink competitors remain rejected. Thanks @vincentkoc.
56
+ - Show only the moon icon in the docs light-theme picker and only the sun icon in dark mode.
57
+
58
+ ### Validation and tooling
59
+
60
+ - Strengthen exact-identity, rounded-inode, Windows recovery, mutation-policy, and package-consumer regressions, with explicit test-hook provenance and bounded fixture lifetimes. Queue stress fixtures retain and drain outstanding writers before cleanup.
61
+ - Separate manual method-audit harnesses from immutable candidate and baseline checkouts, validate dispatch inputs before fan-out, and support Node 22/24 plus rebuild and same-artifact controls. Versioned benchmark receipts bind source, harness, dependencies, artifacts, native addons, and runner metadata; they detect accidental drift and are not a sandbox for hostile code.
62
+ - Expand benchmark coverage for filename sanitizers, all 17 profiles, shared mutation admission, temporary-workspace modes, and existing/missing roots at depths 4/8/32. Keep Windows-specific rows and observed-preservation claims distinct from JavaScript operation counts.
63
+ - Isolate split-credential proof runners, authenticate official Node archives before checkout, and use private, identity-checked stages and tools. Fixtures remain traversable by both dropped identities while published receipts stay in a separately admitted container; the seven behavioral cases are unchanged.
64
+ - Update development tooling to `@napi-rs/cli` 3.9.1, fast-check 4.10.0, and Vite 8.3.0 with verified registry integrity.
65
+
66
+ ## 0.12.0 - 2026-09-15
67
+
68
+ ### Highlights
69
+
70
+ - **Faster archive workloads:** reuse validated ZIP names, batch native plain-TAR reads, and reduce gzip validation and payload-buffer allocations while preserving complete archive checks.
71
+ - **Less overhead in everyday filesystem work:** reduce repeated path resolution, directory-walk work, small-hash allocations, Linux copy buffers, and lock-manager setup.
72
+ - **Stronger Windows file boundaries:** verify secure-file permissions against the descriptor supplying the bytes, retain handles through private-directory creation and cleanup, and check directory identity when Root containment relies on case folding.
73
+ - **Safer queue recovery and cleanup:** prevent stale migrations from replacing newer queue entries, preserve files refreshed during expiry pruning, and keep existing destinations intact when guest symlink moves fail.
74
+ - **Versioned install identifiers:** add `safePathSegmentHashedV2`, which hashes every trimmed ID into a fixed lowercase directory segment and avoids the deterministic aliases of the legacy readable encoder.
75
+
76
+ ### Compatibility and upgrade notes
77
+
78
+ - Windows `readSecureFile()` now requires the matching current native package for descriptor-bound owner and DACL checks. Missing or stale helpers, remote handles, denied access, and unsupported or incomplete permission facts fail closed before reading; there is no pathname ACL-command fallback. Standalone permission-reporting APIs retain their documented fallbacks.
79
+ - Windows private-directory creation rejects explicit `.` and `..` components and components ending in spaces or periods before filesystem operations. Directory association requires the complete file identity; unsupported identity classes fail closed.
80
+ - Windows native descriptor operations require the host runtime's paired libuv descriptor bridge. Missing or partial bridges reject with `ENOTSUP` instead of interpreting descriptors as raw handles or using another runtime's descriptor table.
81
+ - `safePathSegmentHashedV2` is opt-in. Legacy encoder outputs and the default encoder remain unchanged. Switching to V2 changes existing paths: use a new base directory or explicitly migrate after verifying recorded IDs, and do not silently fall back to legacy paths.
82
+
83
+ ### Archive performance and reliability
84
+
85
+ - Reuse identical local and central ZIP name validation within one entry, including matching complete Unicode Path metadata. Differing fields and shared backing memory retain independent checks; CRC, traversal, collision, and interpretation validation remain intact.
86
+ - Reuse raw archive path segments during validation, preserving platform rules, normalized component limits, and error ordering.
87
+ - Speed up native plain-TAR inspection and extraction with bounded file read-ahead, retaining complete framing, payload, trailer, and cancellation checks at parser boundaries.
88
+ - Fill one owned result buffer when reading admitted gzip TAR payloads in JavaScript, reducing retained decoded buffers while preserving complete validation and independent returned bytes.
89
+ - Validate gzip container padding with bounded buffer comparisons and one lazily allocated reusable zero window, preserving complete suffix checks, short-read handling, and cancellation cadence.
90
+ - Destroy and join ZIP decoder sources before rejecting bounded member reads, preventing abandoned decoders and retained archive buffers after byte-limit failures while preserving error classifications on Node 22 and newer.
91
+
92
+ ### Paths, reads, and copying
93
+
94
+ - Reuse normalized absolute POSIX roots within bulk lexical path resolution and avoid per-segment drive-letter validation allocations, preserving path spellings, validation order, and errors.
95
+ - Reuse resolved Windows drive paths and descendant comparisons, with existing namespace, UNC, and colon-bearing component handling retained. Classify Windows device names without intermediate segment arrays.
96
+ - Reuse lexical directory prefixes while walking, preserving traversal order, followed-link spelling, budgets, callback behavior, and directory checks.
97
+ - Size small JavaScript SHA-256 scratch buffers to the file and byte budget, growing when size hints are stale while preserving complete reads, overflow detection, cancellation, and borrowed-descriptor ownership.
98
+ - Complete positive short reads from virtual files that report size zero instead of returning a truncated prefix. Byte-limit overflow detection and borrowed-descriptor cursor behavior remain intact.
99
+ - Confirm EOF when Linux `copy_file_range` reports zero after partial progress; resume guarded byte copying when readable data remains instead of publishing a truncated copy.
100
+ - Size Linux native byte-copy buffers from existing source-size hints, bounded between 4 KiB and 1 MiB, retaining read-to-EOF behavior, sparse output, and borrowed descriptors.
101
+
102
+ ### Windows security and generated names
103
+
104
+ - Bind secure-file owner and DACL verification to the open descriptor and compare its native volume serial and file-index projection with Node's bigint receipt before reading.
105
+ - Retain parent and created-directory handles through private-directory creation, protected-DACL validation, complete identity association, and failure cleanup, preserving concurrent pathname replacements.
106
+ - Require differently cased Root prefixes to match the Root directory's exact identity, then continue under its trusted spelling. Exact-case paths retain their lexical fast path.
107
+ - Prevent filename truncation and temp-file sanitization from producing Windows reserved-device aliases. Invalid completed sibling callback components reject before hooks or producers run.
108
+
109
+ ### Queues, locks, and cleanup
110
+
111
+ - Bind durable-queue migrations to their pinned processing generation, rejecting stale callbacks after acknowledgement, quarantine, or replacement. Release the verified read pin at Windows publication so migrations can replace their target.
112
+ - Resync resumed processing claims under the transfer lock so conditional migrations cannot bypass a failed publication sync on retry.
113
+ - Recheck current file type and modification time immediately before expiry pruning removes a file, preserving fresh replacements and timestamp refreshes without requiring read access.
114
+ - Stage guest cross-device symlink moves privately before atomic replacement, preserving the existing destination and source link when creation or publication fails.
115
+ - Avoid rescanning held locks during repeated lock-manager construction, and initialize legacy reference counts during acquisition and release so nested handles retain the outer lock.
116
+
117
+ ### Validation
118
+
119
+ - Expand representative method-audit coverage to 572 workloads across JavaScript/native modes on Linux, macOS, and Windows, including 1,000-entry walks, larger TAR inventories, and small synchronous hashes, with explicit platform exclusions.
120
+ - Allow focused method audits with explicit native mode and balanced A-B-B-A or B-A-A-B measurement ordering.
121
+ - Extend walker coverage for lexical aliases and callback mutation. Keep cancellation fixture setup outside the operation deadline and drain fixture writes before cleanup on slow or failing filesystems.
122
+ - Give the Windows slow physical-package-copy sidecar proof separate setup, operation, child, and teardown budgets with bounded failure diagnostics, preserving ordinary helper deadlines.
123
+
5
124
  ## 0.11.0 - 2026-09-14
6
125
 
7
126
  ### Highlights
package/README.md CHANGED
@@ -57,7 +57,7 @@ This is a **library-level guardrail**, not OS-level isolation. It does not repla
57
57
  pnpm add @openclaw/fs-safe
58
58
  ```
59
59
 
60
- Node 22 or newer. Core root/path/json/temp helpers avoid framework dependencies. With all optional dependencies omitted, public subpaths remain safe to import and non-archive fallback-capable operations work in `auto` or `off`. Native-only features remain unavailable, and operations needing the binding in `require` mode fail with `helper-unavailable`. TAR/gzip fallback uses the bundled WASM build of the same Rust parser as native and works with optional dependencies omitted. ZIP fallback still needs optional `jszip`. See the [0.6 migration guide](docs/migrating-to-0.6.md).
60
+ Node 22 or newer. Core root/path/json/temp helpers avoid framework dependencies. With all optional dependencies omitted, public subpaths remain safe to import and fallback-capable operations work in `auto` or `off`. Native-only features, including no-clobber `Root.move()`, remain unavailable and fail with `helper-unavailable`. TAR/gzip fallback uses the bundled WASM build of the same Rust parser as native and works with optional dependencies omitted. ZIP fallback still needs optional `jszip`. See the [0.6 migration guide](docs/migrating-to-0.6.md).
61
61
 
62
62
  Bun 1.4.2 is also supported with the [Bun runtime requirements](docs/install.md#bun-runtime), including the matching Rust addon on macOS and Linux. JIT-disabled Bun works too.
63
63
 
@@ -164,7 +164,7 @@ are written, support `maxBytes` and `signal`, and recheck mutation authority
164
164
  before writes and publication. See [streamed creation](docs/writing.md#streamed-creation)
165
165
  for producer ownership and cancellation semantics.
166
166
 
167
- `write()` replaces file contents by default; pass `{ overwrite: false }` or use `create()` when an existing file should be an error. `move()` defaults to no clobber because it can otherwise delete an unrelated target while also consuming the source. Pass `{ overwrite: true }` when replacing the target is intended.
167
+ `write()` replaces file contents by default; pass `{ overwrite: false }` or use `create()` when an existing file should be an error. `move()` defaults to no clobber because it can otherwise delete an unrelated target while also consuming the source. No-clobber moves require the native helper so the collision decision and rename are one descriptor-relative operation; they fail with `helper-unavailable` rather than falling back to a replacing rename. Pass `{ overwrite: true }` when replacing the target is intended.
168
168
 
169
169
  Mutating methods accept `assertBeforeMutation: () => void` for live lease or
170
170
  cancellation checks immediately before filesystem dispatch. Root defaults and
@@ -233,7 +233,7 @@ const locked = await root("/srv/workspace", {
233
233
  await locked.write(".env", "token"); // FsSafeError code "denied-path"
234
234
  ```
235
235
 
236
- `stat()`, `exists()`, `list()`, and `entries()` are boundary-checked, but they cannot pin a later operation to the same filesystem object. Use `read()`, `open()`, `write()`, `create()`, `copyIn()`, `move()`, or `remove()` for operation-local identity checks, and inspect `containment` when the platform distinction matters.
236
+ `stat()`, `exists()`, `list()`, and `entries()` check the exact selected objects while collecting their advisory results, but they cannot pin a later operation to the same filesystem object. Use `read()`, `open()`, `write()`, `create()`, `copyIn()`, `move()`, or `remove()` for operation-local identity checks, and inspect `containment` when the platform distinction matters.
237
237
 
238
238
  ## Subpaths
239
239
 
@@ -260,7 +260,7 @@ contract. Low-level helpers that OpenClaw needs to compose higher-level APIs are
260
260
  | `@openclaw/fs-safe/walk` | budget-bounded directory walking with symlink policy, filters, and truncation accounting; not root-bounded |
261
261
  | `@openclaw/fs-safe/copy` | directory copying with `clone: "auto"`, `"always"`, or `"never"`; native APFS, Btrfs, ReFS, XFS, and ZFS cloning, portable byte copying, and clone metadata; see [directory copying](docs/copy.md) |
262
262
  | `@openclaw/fs-safe/archive` | policy-driven ZIP/TAR extraction, clamp/filter policy, metadata/path-depth limits, native gzip/zstd/bzip2, and bounded entry reads |
263
- | `@openclaw/fs-safe/advanced` | lower-level composition helpers such as path scopes, root-file open, bounded descriptor reads, [borrowed-handle copying](docs/copy.md#borrowed-filehandle-transfers), [exact directory identity](docs/directory-identity.md), [case probing](docs/path-case.md), [in-place writes](docs/in-place-write.md), install paths, filename sanitizing, temp-file targets, sibling-temp writes, local-root readers, regular-file helpers, `pathExists`, and `withTimeout`; less stable than focused public subpaths |
263
+ | `@openclaw/fs-safe/advanced` | lower-level composition helpers such as path scopes, root-file open, bounded descriptor reads, [borrowed-handle copying](docs/copy.md#borrowed-filehandle-transfers), [exact directory identity](docs/directory-identity.md), [case probing](docs/path-case.md), [suffix-alias probing](docs/path-suffix-aliases.md), [in-place writes](docs/in-place-write.md), [versioned install-ID encoding](docs/install-path.md#safepathsegmenthashedv2), filename sanitizing, temp-file targets, sibling-temp writes, local-root readers, regular-file helpers, `pathExists`, and `withTimeout`; less stable than focused public subpaths |
264
264
  | `@openclaw/fs-safe/errors` | `FsSafeError`, closed codes/categories, causes, and operation-specific details receipts |
265
265
  | `@openclaw/fs-safe/types` | shared types: `DirEntry`, `PathStat`, … |
266
266
  | `@openclaw/fs-safe/test-hooks` | hooks the test suite uses to inject races; registration requires `NODE_ENV=test` or `VITEST=true` |
@@ -391,8 +391,8 @@ const store = files.json("settings.json", { lock: true });
391
391
  await store.updateOr({ enabled: false }, (current) => ({ ...current, enabled: true }));
392
392
  ```
393
393
 
394
- `jsonStore({ filePath })` is the absolute-path convenience wrapper for the same
395
- primitive.
394
+ `jsonStore({ filePath })` is the single-path convenience wrapper for the same
395
+ primitive and exposes its resolved absolute path.
396
396
 
397
397
  Use `update()` when missing state is part of your model; use `updateOr()` for
398
398
  the common merge-into-defaults case. Standalone helpers use options bags
@@ -429,7 +429,9 @@ await media.pruneExpired({ ttlMs: 10 * 60 * 1000, recursive: true });
429
429
  The `store` subpath also includes durable JSON queue helpers for the common
430
430
  "one JSON file per work item" pattern: atomic entry writes, pending-entry loads,
431
431
  acknowledgement via `.delivered` markers, failed-entry moves, and stale temp
432
- cleanup. Retry, dedupe, and transport semantics stay with the caller.
432
+ cleanup. On Windows, every independently supplied queue path rejects NTFS
433
+ alternate-stream and directory-index namespace spellings before reads, locks,
434
+ or mutations. Retry, dedupe, and transport semantics stay with the caller.
433
435
 
434
436
  `tempWorkspace()` exposes `write()`, `writeText()`, `writeJson()`, `copyIn()`, and `read()` for
435
437
  single-file scratch workflows without hand-rolled path joins, plus a `store: FileStore` view of
@@ -438,6 +440,9 @@ Compatible creation and cleanup remain available without native support.
438
440
  Set `cleanupSafety: "require-bounded"` to require collision-safe quarantine and
439
441
  descriptor-bounded recursive cleanup before creating a child. See the
440
442
  [temp workspace contract](docs/temp.md).
443
+ On POSIX, bounded cleanup requires owner read and search in the final `dirMode`
444
+ (`0o500`); restrictive modes select compatible fallback or reject `require-bounded`
445
+ before child creation.
441
446
  Linux bounded cleanup requires the exact `openat2`/`RESOLVE_NO_XDEV` capability
442
447
  at runtime; compatible mode falls back when unavailable, while `require-bounded`
443
448
  rejects before child creation.
@@ -460,7 +465,9 @@ Use `readSecureFile()` when the caller gives you an absolute credential path
460
465
  instead of a root-relative workspace path. It opens the file first, validates the
461
466
  same handle it will read from, checks trusted directories, owner, POSIX mode or
462
467
  Windows ACLs, hardlink count, size, and optional timeout, then reads through the
463
- pinned handle.
468
+ pinned handle. On Windows, both the bytes and the owner/DACL facts come from that
469
+ handle; secure reads require the matching current native package and do not fall
470
+ back to a pathname ACL command.
464
471
 
465
472
  ```ts
466
473
  import { readSecureFile } from "@openclaw/fs-safe/secure-file";
@@ -1 +1 @@
1
- {"version":3,"file":"absolute-path.d.ts","sourceRoot":"","sources":["../src/absolute-path.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAKhE,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAU5D,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,GAAG;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAmL7D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWhE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAEnF;AAuBD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,6BAA6B,CAAC,CA+ExC;AAED,wBAAsB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAazF;AAED,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,oBAAoB,CAAC,CAgB/B;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,4BAA4B,CAAC,CA2BvC"}
1
+ {"version":3,"file":"absolute-path.d.ts","sourceRoot":"","sources":["../src/absolute-path.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAUhE,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAU5D,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,GAAG;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAmL7D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAchE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnF;AA4BD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,6BAA6B,CAAC,CA+ExC;AAED,wBAAsB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBzF;AAED,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,4BAA4B,CAAC,CA2BvC"}
@@ -6,6 +6,7 @@ import { FsSafeError } from "./errors.js";
6
6
  import { pathExists } from "./fs.js";
7
7
  import { realpathSync } from "./realpath.js";
8
8
  import { resolveRootPath } from "./root-path.js";
9
+ import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
9
10
  function resolveSymlinkPolicy(policy) {
10
11
  if (policy === undefined)
11
12
  return "reject";
@@ -68,7 +69,7 @@ async function directoryGuardFailure(err, dir, scopeLabel) {
68
69
  return { ok: false, code: err.code, error: err };
69
70
  }
70
71
  try {
71
- const stat = fsSync.lstatSync(dir);
72
+ const stat = fsSync.lstatSync(pathForWindowsFilesystem(dir));
72
73
  const failure = classifyExistingDirectorySegment(stat, scopeLabel);
73
74
  if (failure) {
74
75
  return failure;
@@ -88,7 +89,7 @@ async function resolveTrustedDirectoryPrefix(targetPath, scopeLabel) {
88
89
  let current = root;
89
90
  let currentStat;
90
91
  try {
91
- currentStat = fsSync.lstatSync(current);
92
+ currentStat = fsSync.lstatSync(pathForWindowsFilesystem(current));
92
93
  }
93
94
  catch (err) {
94
95
  const failure = classifyDirectoryLookupError(err, scopeLabel);
@@ -112,7 +113,7 @@ async function resolveTrustedDirectoryPrefix(targetPath, scopeLabel) {
112
113
  }
113
114
  const next = path.join(current, segment);
114
115
  try {
115
- const nextStat = fsSync.lstatSync(next);
116
+ const nextStat = fsSync.lstatSync(pathForWindowsFilesystem(next));
116
117
  const segmentFailure = classifyExistingDirectorySegment(nextStat, scopeLabel);
117
118
  if (segmentFailure) {
118
119
  return segmentFailure;
@@ -145,19 +146,28 @@ export function assertAbsolutePathInput(filePath) {
145
146
  if (filePath.includes("\0")) {
146
147
  throw new FsSafeError("invalid-path", "path must not contain NUL bytes");
147
148
  }
149
+ assertNoWindowsPathAlias(filePath);
148
150
  if (!path.isAbsolute(filePath)) {
149
151
  throw new FsSafeError("invalid-path", "path must be absolute");
150
152
  }
151
- return path.normalize(filePath);
153
+ const normalized = path.normalize(filePath);
154
+ assertNoWindowsPathAlias(normalized);
155
+ return normalized;
152
156
  }
153
157
  export async function findExistingAncestor(filePath) {
158
+ assertNoWindowsPathAlias(filePath);
154
159
  return (await findExistingAncestorWithStat(filePath))?.path ?? null;
155
160
  }
156
161
  async function findExistingAncestorWithStat(filePath) {
157
- let current = path.resolve(filePath);
162
+ assertNoWindowsPathAlias(filePath);
163
+ let current = resolvePathPreservingWindowsRoot(filePath);
164
+ assertNoWindowsPathAlias(current);
158
165
  while (true) {
159
166
  try {
160
- return { path: current, stat: fsSync.lstatSync(current) };
167
+ return {
168
+ path: current,
169
+ stat: fsSync.lstatSync(pathForWindowsFilesystem(current)),
170
+ };
161
171
  }
162
172
  catch (err) {
163
173
  if (err.code !== "ENOENT") {
@@ -246,26 +256,37 @@ export async function ensureAbsoluteDirectory(dirPath, options = {}) {
246
256
  return { ok: true, path: targetPath };
247
257
  }
248
258
  export async function canonicalPathFromExistingAncestor(filePath) {
259
+ assertNoWindowsPathAlias(filePath);
249
260
  const ancestor = await findExistingAncestor(filePath);
250
261
  if (!ancestor) {
251
- return path.resolve(filePath);
262
+ const resolved = resolvePathPreservingWindowsRoot(filePath);
263
+ assertNoWindowsPathAlias(resolved);
264
+ return resolved;
252
265
  }
253
266
  let canonicalAncestor = ancestor;
267
+ let resolvedAncestor;
254
268
  try {
255
- canonicalAncestor = realpathSync.native(ancestor);
269
+ resolvedAncestor = realpathSync.native(pathForWindowsFilesystem(ancestor));
256
270
  }
257
271
  catch {
258
272
  // Keep lexical path when the existing ancestor cannot be canonicalized.
259
273
  }
274
+ if (resolvedAncestor !== undefined) {
275
+ assertNoWindowsPathAlias(resolvedAncestor);
276
+ canonicalAncestor = resolvedAncestor;
277
+ }
260
278
  const relative = path.relative(ancestor, filePath);
261
- return relative ? path.join(canonicalAncestor, relative) : canonicalAncestor;
279
+ const canonicalPath = relative ? path.join(canonicalAncestor, relative) : canonicalAncestor;
280
+ assertNoWindowsPathAlias(canonicalPath);
281
+ return canonicalPath;
262
282
  }
263
283
  export async function resolveAbsolutePathForRead(filePath, options = {}) {
264
284
  const symlinks = resolveSymlinkPolicy(options.symlinks);
265
285
  const normalized = assertAbsolutePathInput(filePath);
266
286
  let canonicalPath;
267
287
  try {
268
- canonicalPath = realpathSync.native(normalized);
288
+ canonicalPath = realpathSync.native(pathForWindowsFilesystem(normalized));
289
+ assertNoWindowsPathAlias(canonicalPath);
269
290
  }
270
291
  catch (err) {
271
292
  if (err.code === "ENOENT") {
@@ -282,7 +303,7 @@ export async function resolveAbsolutePathForWrite(filePath, options = {}) {
282
303
  const symlinks = resolveSymlinkPolicy(options.symlinks);
283
304
  const normalized = assertAbsolutePathInput(filePath);
284
305
  const parentDir = path.dirname(normalized);
285
- const parentExists = await pathExists(parentDir);
306
+ const parentExists = await pathExists(pathForWindowsFilesystem(parentDir));
286
307
  if (symlinks === "reject") {
287
308
  const filesystemRoot = path.parse(normalized).root;
288
309
  await resolveRootPath({
@@ -2,6 +2,8 @@ export { createAsyncLock } from "./async-lock.js";
2
2
  export { copyFileHandle, type CopyFileHandleOptions } from "./file-handle-transfer.js";
3
3
  export { overwriteFileHandle, type OverwriteFileHandleOptions } from "./overwrite-file-handle.js";
4
4
  export { probePathCaseInsensitiveSync, type ProbePathCaseOptions } from "./path-case.js";
5
+ export { resolvePathPrefixSync, type ResolvedPathPrefix } from "./path-prefix.js";
6
+ export { probePathSuffixAliasesSync, type ProbePathSuffixAliasesOptions } from "./path-suffix-aliases.js";
5
7
  export { readDirectoryIdentity, assertDirectoryIdentitySync, type DirectoryIdentity, } from "./directory-guard.js";
6
8
  export { stageFileInDirectory, type StagedFile, type StagedFileReceipt, type PublishedFileReceipt, type StagedFilePublication, type StagedFileCleanupReceipt, type StagedFileFailureDetails, } from "./native-staged-file.js";
7
9
  export { readFileDescriptorBounded, readFileDescriptorBoundedSync, readFileHandleBounded, } from "./bounded-read.js";
@@ -19,7 +21,7 @@ export { assertNoHardlinkedFinalPath, assertNoPathAliasEscape, PATH_ALIAS_POLICI
19
21
  export { openRootFile, openRootFileSync, canUseRootFileOpen, matchRootFileOpenFailure, type OpenRootFileParams, type OpenRootFileSyncParams, type RootFileOpenFailure, type RootFileOpenFailureReason, type RootFileOpenResult, } from "./root-file.js";
20
22
  export { ROOT_PATH_ALIAS_POLICIES, resolvePathViaExistingAncestorSync, resolveRootPath, resolveRootPathSync, type ResolvedRootPath, type RootPathAliasPolicy, } from "./root-path.js";
21
23
  export { ensureDirectoryWithinRoot, pathScope, resolveExistingPathsWithinRoot, resolvePathWithinRoot, resolvePathsWithinRoot, resolveStrictExistingPathsWithinRoot, resolveWritablePathWithinRoot, type PathScope, type PathScopeOptions, type PathScopeResolveOptions, } from "./root-paths.js";
22
- export { safeDirName, safePathSegmentHashed, resolveSafeInstallDir, assertCanonicalPathWithinBase, } from "./install-path.js";
24
+ export { safeDirName, safePathSegmentHashed, safePathSegmentHashedV2, resolveSafeInstallDir, assertCanonicalPathWithinBase, } from "./install-path.js";
23
25
  export { assertNoSymlinkParents, assertNoSymlinkParentsSync, type AssertNoSymlinkParentsOptions, } from "./symlink-parents.js";
24
26
  export { movePathToTrash, type MovePathToTrashOptions } from "./trash.js";
25
27
  export { withTimeout } from "./timing.js";
@@ -1 +1 @@
1
- {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
package/dist/advanced.js CHANGED
@@ -5,6 +5,8 @@ export { createAsyncLock } from "./async-lock.js";
5
5
  export { copyFileHandle } from "./file-handle-transfer.js";
6
6
  export { overwriteFileHandle } from "./overwrite-file-handle.js";
7
7
  export { probePathCaseInsensitiveSync } from "./path-case.js";
8
+ export { resolvePathPrefixSync } from "./path-prefix.js";
9
+ export { probePathSuffixAliasesSync } from "./path-suffix-aliases.js";
8
10
  export { readDirectoryIdentity, assertDirectoryIdentitySync, } from "./directory-guard.js";
9
11
  export { stageFileInDirectory, } from "./native-staged-file.js";
10
12
  export { readFileDescriptorBounded, readFileDescriptorBoundedSync, readFileHandleBounded, } from "./bounded-read.js";
@@ -22,7 +24,7 @@ export { assertNoHardlinkedFinalPath, assertNoPathAliasEscape, PATH_ALIAS_POLICI
22
24
  export { openRootFile, openRootFileSync, canUseRootFileOpen, matchRootFileOpenFailure, } from "./root-file.js";
23
25
  export { ROOT_PATH_ALIAS_POLICIES, resolvePathViaExistingAncestorSync, resolveRootPath, resolveRootPathSync, } from "./root-path.js";
24
26
  export { ensureDirectoryWithinRoot, pathScope, resolveExistingPathsWithinRoot, resolvePathWithinRoot, resolvePathsWithinRoot, resolveStrictExistingPathsWithinRoot, resolveWritablePathWithinRoot, } from "./root-paths.js";
25
- export { safeDirName, safePathSegmentHashed, resolveSafeInstallDir, assertCanonicalPathWithinBase, } from "./install-path.js";
27
+ export { safeDirName, safePathSegmentHashed, safePathSegmentHashedV2, resolveSafeInstallDir, assertCanonicalPathWithinBase, } from "./install-path.js";
26
28
  export { assertNoSymlinkParents, assertNoSymlinkParentsSync, } from "./symlink-parents.js";
27
29
  export { movePathToTrash } from "./trash.js";
28
30
  export { withTimeout } from "./timing.js";
@@ -1 +1 @@
1
- {"version":3,"file":"archive-entry.d.ts","sourceRoot":"","sources":["../src/archive-entry.ts"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,IAAI,CA+DN;AAGD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1F;AAED,wBAAgB,8BAA8B,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAgBlG;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAWT"}
1
+ {"version":3,"file":"archive-entry.d.ts","sourceRoot":"","sources":["../src/archive-entry.ts"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,IAAI,CAgEN;AAGD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1F;AAED,wBAAgB,8BAA8B,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAgBlG;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAWT"}
@@ -21,12 +21,13 @@ export function validateArchiveEntryPath(entryPath, params) {
21
21
  throw new ArchiveSecurityError("entry-path", `archive entry contains a NUL byte: ${formatErrorDetail(entryPath)}`);
22
22
  }
23
23
  const slashNormalized = normalizeArchiveEntryPath(entryPath);
24
+ const rawSegments = slashNormalized.split("/");
24
25
  if (process.platform === "win32" &&
25
- slashNormalized.split("/").some((segment) => segment.includes(":"))) {
26
+ rawSegments.some((segment) => segment.includes(":"))) {
26
27
  throw new ArchiveSecurityError("entry-path", `archive entry uses a Windows alternate data stream path: ${formatErrorDetail(entryPath)}`);
27
28
  }
28
29
  if (process.platform === "win32" &&
29
- slashNormalized.split("/").some((segment) => isWindowsReservedDeviceName(segment))) {
30
+ rawSegments.some((segment) => isWindowsReservedDeviceName(segment))) {
30
31
  throw new ArchiveSecurityError("entry-path", `archive entry uses a reserved device path: ${formatErrorDetail(entryPath)}`);
31
32
  }
32
33
  const normalized = path.posix.normalize(slashNormalized);
@@ -40,7 +41,7 @@ export function validateArchiveEntryPath(entryPath, params) {
40
41
  if (path.posix.isAbsolute(normalized) || normalized.startsWith("//")) {
41
42
  throw new ArchiveSecurityError("entry-path", `archive entry is absolute: ${formatErrorDetail(entryPath)}`);
42
43
  }
43
- if (slashNormalized.split("/").includes("..")) {
44
+ if (rawSegments.includes("..")) {
44
45
  throw new ArchiveSecurityError("entry-path", `archive entry contains a parent segment: ${formatErrorDetail(entryPath)}`);
45
46
  }
46
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"archive-gzip-tail.d.ts","sourceRoot":"","sources":["../src/archive-gzip-tail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEvD;AAQD,gFAAgF;AAChF,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjH;AAED;8EAC8E;AAC9E,qBAAa,SAAU,SAAQ,QAAQ;IAIzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,WAAW,CAAqB;IAExC,YAA6B,OAAO,EAAE,MAAM,EAE3C;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAcxG;IAEQ,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAE9D;IAEQ,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAGpF;CACF;AAED;6EAC6E;AAC7E,wBAAsB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBvH"}
1
+ {"version":3,"file":"archive-gzip-tail.d.ts","sourceRoot":"","sources":["../src/archive-gzip-tail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAaxC,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEvD;AAQD,gFAAgF;AAChF,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CASjH;AAED;8EAC8E;AAC9E,qBAAa,SAAU,SAAQ,QAAQ;IAIzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,WAAW,CAAqB;IAExC,YAA6B,OAAO,EAAE,MAAM,EAE3C;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAcxG;IAEQ,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAE9D;IAEQ,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAGpF;CACF;AAED;6EAC6E;AAC7E,wBAAsB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBvH"}
@@ -2,6 +2,14 @@ import fsSync from "node:fs";
2
2
  import fs from "node:fs/promises";
3
3
  import { Writable } from "node:stream";
4
4
  import { ArchiveFormatError } from "./archive-errors.js";
5
+ const PADDING_WINDOW_BYTES = 65536;
6
+ let zeroPadding;
7
+ function assertZeroPadding(bytes) {
8
+ zeroPadding ??= Buffer.alloc(PADDING_WINDOW_BYTES);
9
+ if (!bytes.equals(zeroPadding.subarray(0, bytes.length))) {
10
+ throw new ArchiveFormatError("nonzero gzip container padding");
11
+ }
12
+ }
5
13
  export function isGzipBuffer(input) {
6
14
  return input[0] === 31 && input[1] === 139;
7
15
  }
@@ -14,12 +22,10 @@ function assertConsumedBoundary(consumed, size) {
14
22
  export async function validateGzipBufferTail(input, consumed, signal) {
15
23
  signal?.throwIfAborted();
16
24
  assertConsumedBoundary(consumed, input.length);
17
- for (let position = consumed; position < input.length; position += 65536) {
25
+ for (let position = consumed; position < input.length; position += PADDING_WINDOW_BYTES) {
18
26
  signal?.throwIfAborted();
19
- if (input.subarray(position, position + 65536).some(byte => byte !== 0)) {
20
- throw new ArchiveFormatError("nonzero gzip container padding");
21
- }
22
- if (position + 65536 < input.length)
27
+ assertZeroPadding(input.subarray(position, position + PADDING_WINDOW_BYTES));
28
+ if (position + PADDING_WINDOW_BYTES < input.length)
23
29
  await new Promise(resolve => setImmediate(resolve));
24
30
  }
25
31
  signal?.throwIfAborted();
@@ -75,7 +81,7 @@ export async function validateGzipContainerTail(filePath, consumed, signal) {
75
81
  assertConsumedBoundary(consumed, size);
76
82
  if (consumed === size)
77
83
  return;
78
- const buffer = Buffer.allocUnsafe(65536);
84
+ const buffer = Buffer.allocUnsafe(PADDING_WINDOW_BYTES);
79
85
  let position = consumed;
80
86
  while (position < size) {
81
87
  signal?.throwIfAborted();
@@ -83,9 +89,7 @@ export async function validateGzipContainerTail(filePath, consumed, signal) {
83
89
  signal?.throwIfAborted();
84
90
  if (bytesRead === 0)
85
91
  throw new ArchiveFormatError("truncated gzip container padding");
86
- if (buffer.subarray(0, bytesRead).some((byte) => byte !== 0)) {
87
- throw new ArchiveFormatError("nonzero gzip container padding");
88
- }
92
+ assertZeroPadding(buffer.subarray(0, bytesRead));
89
93
  position += bytesRead;
90
94
  }
91
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"archive-input.d.ts","sourceRoot":"","sources":["../src/archive-input.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAM7B,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC;AAM/E,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,kBAAkB,CAAC;CAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CAchB;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,4BAA4B,CAAC;IACrC,QAAQ,EAAE,kBAAkB,CAAC;CAC9B,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqE7B"}
1
+ {"version":3,"file":"archive-input.d.ts","sourceRoot":"","sources":["../src/archive-input.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAO7B,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC;AAM/E,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,kBAAkB,CAAC;CAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CAchB;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,4BAA4B,CAAC;IACrC,QAAQ,EAAE,kBAAkB,CAAC;CAC9B,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAwE7B"}
@@ -6,6 +6,7 @@ import { FsSafeError } from "./errors.js";
6
6
  import { inspectFileIdentity } from "./strict-file-identity.js";
7
7
  import { resolveReadOpenFlags } from "./read-open-flags.js";
8
8
  import { tempFile } from "./temp-target.js";
9
+ import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
9
10
  async function closeFileHandle(handle) {
10
11
  if (handle)
11
12
  await handle.close().catch(() => undefined);
@@ -23,11 +24,14 @@ export async function writeFileHandleFully(params) {
23
24
  }
24
25
  export async function stageArchiveFileForExtraction(params) {
25
26
  params.deadline.check();
26
- const sourcePath = path.resolve(params.archivePath);
27
+ const archivePath = params.archivePath;
28
+ assertNoWindowsPathAlias(archivePath);
29
+ const sourcePath = path.resolve(archivePath);
30
+ assertNoWindowsPathAlias(sourcePath);
27
31
  const initialStat = await inspectFileIdentity(async () => {
28
32
  const stat = fsSync.lstatSync(sourcePath, { bigint: true });
29
33
  if (stat.isSymbolicLink() || !stat.isFile()) {
30
- throw new Error(`archive is not a regular file: ${params.archivePath}`);
34
+ throw new Error(`archive is not a regular file: ${archivePath}`);
31
35
  }
32
36
  return stat;
33
37
  });
@@ -1 +1 @@
1
- {"version":3,"file":"archive-merge.d.ts","sourceRoot":"","sources":["../src/archive-merge.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAa9B,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACjG,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,CAAC;AACF,KAAK,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACtE,gBAAgB,EAAE,qBAAqB,CAAC;CACzC,CAAC;AAEF,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,kBAAkB,GAAG;IAAE,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9F,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1F"}
1
+ {"version":3,"file":"archive-merge.d.ts","sourceRoot":"","sources":["../src/archive-merge.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAc9B,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACjG,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,CAAC;AACF,KAAK,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACtE,gBAAgB,EAAE,qBAAqB,CAAC;CACzC,CAAC;AAEF,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,kBAAkB,GAAG;IAAE,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9F,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAS1F"}
@@ -14,12 +14,25 @@ import { getFsSafeTestHooks } from "./test-hooks.js";
14
14
  import { onCopyPublication } from "./copy-publication.js";
15
15
  import { syncFileBestEffortSync } from "./file-sync.js";
16
16
  import { finalizeArchivePublication } from "./archive-durability.js";
17
+ import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
17
18
  export async function mergePlannedArchiveIntoDestination(params) {
19
+ assertMergePathInputs(params);
18
20
  await mergeTree(params, params.entries, params.durable === true);
19
21
  }
20
22
  export async function mergeExtractedTreeIntoDestination(params) {
21
- const destinationGuard = await createDirectoryIdentityGuard(params.destinationRealDir);
22
- await mergeTree({ sourceDir: params.sourceDir, deadline: params.deadline, destinationGuard });
23
+ const sourceDir = params.sourceDir;
24
+ const destinationDir = params.destinationDir;
25
+ const destinationRealDir = params.destinationRealDir;
26
+ assertNoWindowsPathAlias(sourceDir);
27
+ assertNoWindowsPathAlias(destinationDir);
28
+ assertNoWindowsPathAlias(destinationRealDir);
29
+ const destinationGuard = await createDirectoryIdentityGuard(destinationRealDir);
30
+ await mergeTree({ sourceDir, deadline: params.deadline, destinationGuard });
31
+ }
32
+ function assertMergePathInputs(params) {
33
+ assertNoWindowsPathAlias(params.sourceDir);
34
+ assertNoWindowsPathAlias(params.destinationGuard.dir);
35
+ assertNoWindowsPathAlias(params.destinationGuard.realPath);
23
36
  }
24
37
  async function mergeTree(params, publication, durable = true) {
25
38
  const publishedFiles = [];
@@ -1 +1 @@
1
- {"version":3,"file":"archive-native.d.ts","sourceRoot":"","sources":["../src/archive-native.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAYnE;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;CAClD,GAAG,OAAO,CAAC,IAAI,CAAC,CA+FhB"}
1
+ {"version":3,"file":"archive-native.d.ts","sourceRoot":"","sources":["../src/archive-native.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAYnE;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;CAClD,GAAG,OAAO,CAAC,IAAI,CAAC,CAkFhB"}