@openclaw/fs-safe 0.12.0 → 0.13.1

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 (395) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +12 -7
  3. package/dist/absolute-path.d.ts.map +1 -1
  4. package/dist/absolute-path.js +32 -11
  5. package/dist/advanced.d.ts +2 -0
  6. package/dist/advanced.d.ts.map +1 -1
  7. package/dist/advanced.js +2 -0
  8. package/dist/archive-input.d.ts.map +1 -1
  9. package/dist/archive-input.js +6 -2
  10. package/dist/archive-merge.d.ts.map +1 -1
  11. package/dist/archive-merge.js +15 -2
  12. package/dist/archive-native.d.ts.map +1 -1
  13. package/dist/archive-native.js +7 -19
  14. package/dist/archive-plan.js +1 -1
  15. package/dist/archive-read.d.ts.map +1 -1
  16. package/dist/archive-read.js +18 -13
  17. package/dist/archive-staging.d.ts.map +1 -1
  18. package/dist/archive-staging.js +43 -10
  19. package/dist/archive-tar-inspect.d.ts.map +1 -1
  20. package/dist/archive-tar-inspect.js +4 -1
  21. package/dist/archive-zip-admission.d.ts +1 -1
  22. package/dist/archive-zip-admission.d.ts.map +1 -1
  23. package/dist/archive-zip-admission.js +2 -2
  24. package/dist/archive-zip-directory.d.ts +3 -0
  25. package/dist/archive-zip-directory.d.ts.map +1 -1
  26. package/dist/archive-zip-directory.js +13 -2
  27. package/dist/archive-zip-loader.d.ts +3 -2
  28. package/dist/archive-zip-loader.d.ts.map +1 -1
  29. package/dist/archive-zip-loader.js +30 -4
  30. package/dist/archive-zip-manifest.d.ts +5 -0
  31. package/dist/archive-zip-manifest.d.ts.map +1 -0
  32. package/dist/archive-zip-manifest.js +22 -0
  33. package/dist/archive-zip-names.d.ts +6 -1
  34. package/dist/archive-zip-names.d.ts.map +1 -1
  35. package/dist/archive-zip-names.js +35 -14
  36. package/dist/archive-zip-preflight.d.ts.map +1 -1
  37. package/dist/archive-zip-preflight.js +3 -2
  38. package/dist/archive.d.ts.map +1 -1
  39. package/dist/archive.js +9 -4
  40. package/dist/copy-file-input.d.ts +1 -1
  41. package/dist/copy-file-input.d.ts.map +1 -1
  42. package/dist/copy-file-input.js +2 -0
  43. package/dist/darwin-acl.d.ts +4 -0
  44. package/dist/darwin-acl.d.ts.map +1 -0
  45. package/dist/darwin-acl.js +24 -0
  46. package/dist/deny-mutations.d.ts.map +1 -1
  47. package/dist/deny-mutations.js +8 -2
  48. package/dist/directory-durability.d.ts.map +1 -1
  49. package/dist/directory-durability.js +67 -23
  50. package/dist/directory-entry-path.d.ts +3 -0
  51. package/dist/directory-entry-path.d.ts.map +1 -0
  52. package/dist/directory-entry-path.js +21 -0
  53. package/dist/directory-guard.d.ts +17 -1
  54. package/dist/directory-guard.d.ts.map +1 -1
  55. package/dist/directory-guard.js +134 -48
  56. package/dist/directory-mode-node.d.ts +12 -0
  57. package/dist/directory-mode-node.d.ts.map +1 -1
  58. package/dist/directory-mode-node.js +102 -4
  59. package/dist/effective-uid.d.ts +2 -0
  60. package/dist/effective-uid.d.ts.map +1 -0
  61. package/dist/effective-uid.js +25 -0
  62. package/dist/file-handle-transfer.d.ts.map +1 -1
  63. package/dist/file-handle-transfer.js +98 -27
  64. package/dist/file-hash.d.ts.map +1 -1
  65. package/dist/file-hash.js +3 -0
  66. package/dist/file-lock-sync.d.ts.map +1 -1
  67. package/dist/file-lock-sync.js +36 -6
  68. package/dist/file-lock.d.ts.map +1 -1
  69. package/dist/file-lock.js +29 -9
  70. package/dist/file-observation.d.ts +1 -1
  71. package/dist/file-observation.d.ts.map +1 -1
  72. package/dist/file-store-boundary.d.ts +6 -2
  73. package/dist/file-store-boundary.d.ts.map +1 -1
  74. package/dist/file-store-boundary.js +20 -65
  75. package/dist/file-store-copy-source.d.ts +5 -0
  76. package/dist/file-store-copy-source.d.ts.map +1 -0
  77. package/dist/file-store-copy-source.js +31 -0
  78. package/dist/file-store-path.d.ts.map +1 -1
  79. package/dist/file-store-path.js +4 -1
  80. package/dist/file-store-sync-directory.d.ts +16 -0
  81. package/dist/file-store-sync-directory.d.ts.map +1 -0
  82. package/dist/file-store-sync-directory.js +349 -0
  83. package/dist/file-store.d.ts.map +1 -1
  84. package/dist/file-store.js +11 -28
  85. package/dist/filename.d.ts.map +1 -1
  86. package/dist/filename.js +65 -20
  87. package/dist/fs.d.ts.map +1 -1
  88. package/dist/fs.js +3 -2
  89. package/dist/guarded-mkdir.d.ts +8 -0
  90. package/dist/guarded-mkdir.d.ts.map +1 -1
  91. package/dist/guarded-mkdir.js +176 -27
  92. package/dist/guest.d.ts.map +1 -1
  93. package/dist/guest.js +4 -1
  94. package/dist/home-dir.d.ts.map +1 -1
  95. package/dist/home-dir.js +73 -10
  96. package/dist/install-path.d.ts.map +1 -1
  97. package/dist/install-path.js +54 -19
  98. package/dist/json-durable-queue-ownership.d.ts +6 -0
  99. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  100. package/dist/json-durable-queue-ownership.js +89 -42
  101. package/dist/json-durable-queue-paths.d.ts +11 -0
  102. package/dist/json-durable-queue-paths.d.ts.map +1 -0
  103. package/dist/json-durable-queue-paths.js +42 -0
  104. package/dist/json-durable-queue-read.d.ts.map +1 -1
  105. package/dist/json-durable-queue-read.js +2 -0
  106. package/dist/json-durable-queue.d.ts.map +1 -1
  107. package/dist/json-durable-queue.js +50 -58
  108. package/dist/json-store.d.ts.map +1 -1
  109. package/dist/json-store.js +5 -1
  110. package/dist/json.d.ts.map +1 -1
  111. package/dist/json.js +54 -22
  112. package/dist/local-file-access.d.ts.map +1 -1
  113. package/dist/local-file-access.js +4 -0
  114. package/dist/local-file-descriptor.d.ts +17 -0
  115. package/dist/local-file-descriptor.d.ts.map +1 -0
  116. package/dist/local-file-descriptor.js +84 -0
  117. package/dist/local-roots.d.ts.map +1 -1
  118. package/dist/local-roots.js +35 -7
  119. package/dist/move-path-cleanup.d.ts +2 -0
  120. package/dist/move-path-cleanup.d.ts.map +1 -1
  121. package/dist/move-path-cleanup.js +44 -18
  122. package/dist/move-path.d.ts.map +1 -1
  123. package/dist/move-path.js +31 -6
  124. package/dist/native-binding.d.ts +17 -0
  125. package/dist/native-binding.d.ts.map +1 -1
  126. package/dist/native-binding.js +8 -1
  127. package/dist/native-directory-observation.d.ts +17 -0
  128. package/dist/native-directory-observation.d.ts.map +1 -0
  129. package/dist/native-directory-observation.js +37 -0
  130. package/dist/native-operations.d.ts.map +1 -1
  131. package/dist/native-operations.js +6 -4
  132. package/dist/native-parent-admission.d.ts +32 -0
  133. package/dist/native-parent-admission.d.ts.map +1 -0
  134. package/dist/native-parent-admission.js +127 -0
  135. package/dist/native-pinned-write-windows.d.ts +0 -1
  136. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  137. package/dist/native-pinned-write-windows.js +8 -9
  138. package/dist/native-pinned-write.d.ts.map +1 -1
  139. package/dist/native-pinned-write.js +314 -42
  140. package/dist/native-staged-file.d.ts +4 -4
  141. package/dist/native-staged-file.d.ts.map +1 -1
  142. package/dist/native-staged-file.js +20 -10
  143. package/dist/native.d.ts +1 -1
  144. package/dist/native.d.ts.map +1 -1
  145. package/dist/native.js +7 -2
  146. package/dist/output.d.ts.map +1 -1
  147. package/dist/output.js +15 -5
  148. package/dist/overwrite-file-handle.d.ts.map +1 -1
  149. package/dist/overwrite-file-handle.js +5 -1
  150. package/dist/owner-dacl.d.ts.map +1 -1
  151. package/dist/owner-dacl.js +2 -0
  152. package/dist/path-policy.d.ts.map +1 -1
  153. package/dist/path-policy.js +7 -2
  154. package/dist/path-prefix.d.ts +7 -0
  155. package/dist/path-prefix.d.ts.map +1 -0
  156. package/dist/path-prefix.js +82 -0
  157. package/dist/path-scope-lexical.d.ts.map +1 -1
  158. package/dist/path-scope-lexical.js +18 -8
  159. package/dist/path-segment-route.d.ts +7 -0
  160. package/dist/path-segment-route.d.ts.map +1 -0
  161. package/dist/path-segment-route.js +24 -0
  162. package/dist/path-suffix-aliases.d.ts +10 -0
  163. package/dist/path-suffix-aliases.d.ts.map +1 -0
  164. package/dist/path-suffix-aliases.js +386 -0
  165. package/dist/path.d.ts.map +1 -1
  166. package/dist/path.js +16 -5
  167. package/dist/permissions-windows.d.ts.map +1 -1
  168. package/dist/permissions-windows.js +14 -3
  169. package/dist/permissions.d.ts.map +1 -1
  170. package/dist/permissions.js +37 -8
  171. package/dist/pinned-mutation-admission.d.ts +25 -0
  172. package/dist/pinned-mutation-admission.d.ts.map +1 -0
  173. package/dist/pinned-mutation-admission.js +425 -0
  174. package/dist/pinned-mutation-observation.d.ts +34 -0
  175. package/dist/pinned-mutation-observation.d.ts.map +1 -0
  176. package/dist/pinned-mutation-observation.js +142 -0
  177. package/dist/pinned-mutation-shared-route.d.ts +24 -0
  178. package/dist/pinned-mutation-shared-route.d.ts.map +1 -0
  179. package/dist/pinned-mutation-shared-route.js +70 -0
  180. package/dist/pinned-open.d.ts +6 -0
  181. package/dist/pinned-open.d.ts.map +1 -1
  182. package/dist/pinned-open.js +28 -10
  183. package/dist/pinned-write-types.d.ts +75 -0
  184. package/dist/pinned-write-types.d.ts.map +1 -0
  185. package/dist/pinned-write-types.js +1 -0
  186. package/dist/pinned-write.d.ts +7 -33
  187. package/dist/pinned-write.d.ts.map +1 -1
  188. package/dist/pinned-write.js +151 -17
  189. package/dist/private-directory.d.ts.map +1 -1
  190. package/dist/private-directory.js +2 -0
  191. package/dist/private-producer-handoff.d.ts +16 -0
  192. package/dist/private-producer-handoff.d.ts.map +1 -0
  193. package/dist/private-producer-handoff.js +272 -0
  194. package/dist/private-temp-workspace.d.ts +2 -39
  195. package/dist/private-temp-workspace.d.ts.map +1 -1
  196. package/dist/private-temp-workspace.js +183 -77
  197. package/dist/publish-file.d.ts.map +1 -1
  198. package/dist/publish-file.js +38 -32
  199. package/dist/regular-file.d.ts.map +1 -1
  200. package/dist/regular-file.js +56 -45
  201. package/dist/replace-directory.d.ts.map +1 -1
  202. package/dist/replace-directory.js +12 -5
  203. package/dist/replace-file-temp-owner.d.ts +1 -0
  204. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  205. package/dist/replace-file-temp-owner.js +12 -1
  206. package/dist/replace-file.d.ts.map +1 -1
  207. package/dist/replace-file.js +24 -24
  208. package/dist/root-boundary.d.ts +4 -0
  209. package/dist/root-boundary.d.ts.map +1 -1
  210. package/dist/root-boundary.js +6 -1
  211. package/dist/root-context.d.ts +12 -1
  212. package/dist/root-context.d.ts.map +1 -1
  213. package/dist/root-context.js +57 -11
  214. package/dist/root-directory-creation.d.ts +13 -0
  215. package/dist/root-directory-creation.d.ts.map +1 -0
  216. package/dist/root-directory-creation.js +212 -0
  217. package/dist/root-directory-list.d.ts +16 -4
  218. package/dist/root-directory-list.d.ts.map +1 -1
  219. package/dist/root-directory-list.js +180 -39
  220. package/dist/root-directory.d.ts +23 -0
  221. package/dist/root-directory.d.ts.map +1 -0
  222. package/dist/root-directory.js +141 -0
  223. package/dist/root-errors.d.ts.map +1 -1
  224. package/dist/root-errors.js +12 -1
  225. package/dist/root-file-final-admission.d.ts +21 -0
  226. package/dist/root-file-final-admission.d.ts.map +1 -0
  227. package/dist/root-file-final-admission.js +83 -0
  228. package/dist/root-file.d.ts.map +1 -1
  229. package/dist/root-file.js +103 -24
  230. package/dist/root-impl.d.ts +1 -0
  231. package/dist/root-impl.d.ts.map +1 -1
  232. package/dist/root-impl.js +289 -317
  233. package/dist/root-move-noreplace.d.ts +14 -0
  234. package/dist/root-move-noreplace.d.ts.map +1 -0
  235. package/dist/root-move-noreplace.js +202 -0
  236. package/dist/root-observed-path.d.ts +9 -0
  237. package/dist/root-observed-path.d.ts.map +1 -0
  238. package/dist/root-observed-path.js +95 -0
  239. package/dist/root-path-errors.d.ts +12 -0
  240. package/dist/root-path-errors.d.ts.map +1 -0
  241. package/dist/root-path-errors.js +13 -0
  242. package/dist/root-path-existing.d.ts.map +1 -1
  243. package/dist/root-path-existing.js +53 -20
  244. package/dist/root-path-observation.d.ts +63 -0
  245. package/dist/root-path-observation.d.ts.map +1 -0
  246. package/dist/root-path-observation.js +180 -0
  247. package/dist/root-path-stat.d.ts +5 -0
  248. package/dist/root-path-stat.d.ts.map +1 -0
  249. package/dist/root-path-stat.js +101 -0
  250. package/dist/root-path-symlink.d.ts.map +1 -1
  251. package/dist/root-path-symlink.js +23 -4
  252. package/dist/root-path.d.ts +11 -0
  253. package/dist/root-path.d.ts.map +1 -1
  254. package/dist/root-path.js +215 -53
  255. package/dist/root-paths-lexical.d.ts +9 -0
  256. package/dist/root-paths-lexical.d.ts.map +1 -0
  257. package/dist/root-paths-lexical.js +22 -0
  258. package/dist/root-paths.d.ts +3 -25
  259. package/dist/root-paths.d.ts.map +1 -1
  260. package/dist/root-paths.js +77 -154
  261. package/dist/root-read-admission.d.ts +26 -0
  262. package/dist/root-read-admission.d.ts.map +1 -0
  263. package/dist/root-read-admission.js +94 -0
  264. package/dist/root-remove-identity.d.ts +15 -0
  265. package/dist/root-remove-identity.d.ts.map +1 -0
  266. package/dist/root-remove-identity.js +89 -0
  267. package/dist/root-remove-receipt.d.ts +17 -0
  268. package/dist/root-remove-receipt.d.ts.map +1 -0
  269. package/dist/root-remove-receipt.js +37 -0
  270. package/dist/root-remove.d.ts +2 -1
  271. package/dist/root-remove.d.ts.map +1 -1
  272. package/dist/root-remove.js +172 -10
  273. package/dist/root-write-admission.d.ts +68 -0
  274. package/dist/root-write-admission.d.ts.map +1 -0
  275. package/dist/root-write-admission.js +322 -0
  276. package/dist/root-write-compatibility.d.ts +13 -0
  277. package/dist/root-write-compatibility.d.ts.map +1 -0
  278. package/dist/root-write-compatibility.js +74 -0
  279. package/dist/root-write-complete-parent.d.ts +42 -0
  280. package/dist/root-write-complete-parent.d.ts.map +1 -0
  281. package/dist/root-write-complete-parent.js +195 -0
  282. package/dist/root-write-publication.d.ts +24 -0
  283. package/dist/root-write-publication.d.ts.map +1 -0
  284. package/dist/root-write-publication.js +85 -0
  285. package/dist/root-write-verification.d.ts.map +1 -1
  286. package/dist/root-write-verification.js +6 -4
  287. package/dist/secret-file.d.ts.map +1 -1
  288. package/dist/secret-file.js +62 -24
  289. package/dist/secret-read-async.d.ts.map +1 -1
  290. package/dist/secret-read-async.js +18 -13
  291. package/dist/secret-read-policy.d.ts.map +1 -1
  292. package/dist/secret-read-policy.js +5 -1
  293. package/dist/secure-file.d.ts.map +1 -1
  294. package/dist/secure-file.js +92 -7
  295. package/dist/secure-temp-dir.d.ts +6 -3
  296. package/dist/secure-temp-dir.d.ts.map +1 -1
  297. package/dist/secure-temp-dir.js +121 -101
  298. package/dist/secure-temp-repair.d.ts +35 -0
  299. package/dist/secure-temp-repair.d.ts.map +1 -0
  300. package/dist/secure-temp-repair.js +106 -0
  301. package/dist/sibling-staged-file.d.ts +3 -2
  302. package/dist/sibling-staged-file.d.ts.map +1 -1
  303. package/dist/sibling-staged-file.js +179 -55
  304. package/dist/sibling-temp.d.ts.map +1 -1
  305. package/dist/sibling-temp.js +27 -13
  306. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  307. package/dist/sidecar-lock-acquire.js +44 -14
  308. package/dist/sidecar-lock-root.d.ts.map +1 -1
  309. package/dist/sidecar-lock-root.js +4 -2
  310. package/dist/staged-directory.d.ts +14 -5
  311. package/dist/staged-directory.d.ts.map +1 -1
  312. package/dist/staged-directory.js +54 -3
  313. package/dist/standalone-publication-path.d.ts +2 -0
  314. package/dist/standalone-publication-path.d.ts.map +1 -0
  315. package/dist/standalone-publication-path.js +6 -0
  316. package/dist/stat-observation.d.ts +11 -0
  317. package/dist/stat-observation.d.ts.map +1 -0
  318. package/dist/stat-observation.js +64 -0
  319. package/dist/strict-file-identity.d.ts.map +1 -1
  320. package/dist/strict-file-identity.js +39 -2
  321. package/dist/symlink-parents.d.ts.map +1 -1
  322. package/dist/symlink-parents.js +7 -2
  323. package/dist/temp-target.d.ts +2 -0
  324. package/dist/temp-target.d.ts.map +1 -1
  325. package/dist/temp-target.js +130 -3
  326. package/dist/temp-workspace-admission.d.ts +22 -0
  327. package/dist/temp-workspace-admission.d.ts.map +1 -0
  328. package/dist/temp-workspace-admission.js +374 -0
  329. package/dist/temp-workspace-child-admission.d.ts +13 -0
  330. package/dist/temp-workspace-child-admission.d.ts.map +1 -0
  331. package/dist/temp-workspace-child-admission.js +95 -0
  332. package/dist/temp-workspace-descriptor.d.ts +48 -0
  333. package/dist/temp-workspace-descriptor.d.ts.map +1 -0
  334. package/dist/temp-workspace-descriptor.js +363 -0
  335. package/dist/temp-workspace-identity.d.ts +15 -0
  336. package/dist/temp-workspace-identity.d.ts.map +1 -0
  337. package/dist/temp-workspace-identity.js +41 -0
  338. package/dist/temp-workspace-owner.d.ts +7 -6
  339. package/dist/temp-workspace-owner.d.ts.map +1 -1
  340. package/dist/temp-workspace-owner.js +121 -61
  341. package/dist/temp-workspace-permissions.d.ts +4 -0
  342. package/dist/temp-workspace-permissions.d.ts.map +1 -0
  343. package/dist/temp-workspace-permissions.js +32 -0
  344. package/dist/temp-workspace-types.d.ts +40 -0
  345. package/dist/temp-workspace-types.d.ts.map +1 -0
  346. package/dist/temp-workspace-types.js +1 -0
  347. package/dist/temp.d.ts +1 -1
  348. package/dist/temp.d.ts.map +1 -1
  349. package/dist/temp.js +1 -1
  350. package/dist/test-hooks.d.ts +7 -0
  351. package/dist/test-hooks.d.ts.map +1 -1
  352. package/dist/text-atomic.d.ts.map +1 -1
  353. package/dist/text-atomic.js +3 -1
  354. package/dist/trash.d.ts.map +1 -1
  355. package/dist/trash.js +54 -8
  356. package/dist/walk.d.ts.map +1 -1
  357. package/dist/walk.js +9 -6
  358. package/dist/windows-owner.d.ts.map +1 -1
  359. package/dist/windows-owner.js +5 -0
  360. package/dist/windows-path-alias.d.ts +39 -0
  361. package/dist/windows-path-alias.d.ts.map +1 -0
  362. package/dist/windows-path-alias.js +153 -0
  363. package/docs/advanced.md +25 -0
  364. package/docs/archive.md +23 -2
  365. package/docs/atomic.md +27 -3
  366. package/docs/copy.md +3 -0
  367. package/docs/durability.md +14 -0
  368. package/docs/errors.md +14 -6
  369. package/docs/file-store.md +24 -3
  370. package/docs/filename.md +14 -7
  371. package/docs/install-path.md +2 -2
  372. package/docs/install.md +8 -7
  373. package/docs/json-store.md +5 -1
  374. package/docs/json.md +11 -0
  375. package/docs/mutation-policy-proof.md +65 -0
  376. package/docs/native-helper.md +41 -11
  377. package/docs/native.md +32 -8
  378. package/docs/output.md +33 -11
  379. package/docs/path-prefix.md +64 -0
  380. package/docs/path-suffix-aliases.md +159 -0
  381. package/docs/path.md +11 -0
  382. package/docs/private-file-store.md +14 -0
  383. package/docs/public-api.md +9 -0
  384. package/docs/quickstart.md +1 -1
  385. package/docs/reading.md +8 -1
  386. package/docs/root.md +18 -3
  387. package/docs/secret-file.md +3 -0
  388. package/docs/secure-file.md +6 -2
  389. package/docs/security-model.md +75 -8
  390. package/docs/sidecar-lock.md +28 -1
  391. package/docs/store.md +5 -1
  392. package/docs/temp.md +260 -36
  393. package/docs/test-hooks.md +14 -0
  394. package/docs/writing.md +38 -8
  395. package/package.json +10 -10
@@ -2,12 +2,11 @@ import { randomUUID } from "node:crypto";
2
2
  import fsSync from "node:fs";
3
3
  import fs from "node:fs/promises";
4
4
  import path from "node:path";
5
- import { createAsyncDirectoryGuard, createSyncDirectoryGuard } from "./directory-guard.js";
6
5
  import { FsSafeError } from "./errors.js";
6
+ import { assertNoWindowsPathAlias, resolvePathPreservingWindowsRoot } from "./windows-path-alias.js";
7
7
  import { sameFileIdentityForCleanup } from "./file-identity.js";
8
- import { withAsyncDirectoryGuards, withSyncDirectoryGuards } from "./guarded-mutation.js";
9
8
  import { getNativeBinding } from "./native.js";
10
- import { assertStagedDirectoryCurrent, openStagedDirectory } from "./staged-directory.js";
9
+ import { openTempWorkspaceCleanupParent, TempWorkspaceRetainedChild, } from "./temp-workspace-descriptor.js";
11
10
  import { getFsSafeTestHooks } from "./test-hooks.js";
12
11
  function isNativeCleanupBinding(binding) {
13
12
  return typeof binding?.renameNoReplace === "function" &&
@@ -25,9 +24,27 @@ function nativeRemovalError(result) {
25
24
  export class TempWorkspaceCleanupCapability {
26
25
  binding;
27
26
  parent;
27
+ #admission;
28
+ #safety;
28
29
  #ownedTreeRemovalAvailable;
29
- #closed = false;
30
- constructor(root, safety) {
30
+ #phase = "new";
31
+ constructor(root, safety, admission, dirMode) {
32
+ assertNoWindowsPathAlias(root, "filesystem");
33
+ const admittedRoot = admission.dir;
34
+ assertNoWindowsPathAlias(admittedRoot, "filesystem");
35
+ const resolvedRoot = resolvePathPreservingWindowsRoot(root);
36
+ assertNoWindowsPathAlias(resolvedRoot, "filesystem");
37
+ if (resolvedRoot !== resolvePathPreservingWindowsRoot(admittedRoot)) {
38
+ throw new FsSafeError("path-mismatch", "temp workspace cleanup parent differs from admitted root");
39
+ }
40
+ this.#admission = admission;
41
+ this.#safety = safety;
42
+ // POSIX enumeration reopens fd-relative ".", so retaining O_RDONLY before
43
+ // chmod cannot supply read/search authority that the final mode removes.
44
+ const childModeAllowsRemoval = process.platform === "win32" || (dirMode & 0o500) === 0o500;
45
+ if (safety === "require-bounded" && !childModeAllowsRemoval) {
46
+ throw new FsSafeError("helper-unavailable", "temp workspace owned-tree cleanup requires owner read and search in dirMode");
47
+ }
31
48
  let binding;
32
49
  try {
33
50
  binding = getNativeBinding();
@@ -39,47 +56,104 @@ export class TempWorkspaceCleanupCapability {
39
56
  this.binding = binding;
40
57
  let parent;
41
58
  try {
42
- parent = openStagedDirectory(root);
43
- assertStagedDirectoryCurrent(parent.receipt);
59
+ parent = openTempWorkspaceCleanupParent(root, admission);
44
60
  }
45
61
  catch {
46
62
  if (parent)
47
63
  fsSync.closeSync(parent.fd);
48
64
  parent = undefined;
49
65
  }
50
- this.parent = parent;
51
66
  let available = false;
52
- if (parent && isNativeCleanupBinding(binding)) {
67
+ if (childModeAllowsRemoval && parent?.access === "read" && isNativeCleanupBinding(binding)) {
68
+ let probeReady = false;
69
+ try {
70
+ admission.prepareCleanupProbe(parent.fd);
71
+ probeReady = true;
72
+ }
73
+ catch (error) {
74
+ // A descriptor that cannot be associated even provisionally must not
75
+ // reach native code or remain available to compatible cleanup.
76
+ try {
77
+ fsSync.closeSync(parent.fd);
78
+ }
79
+ catch (closeError) {
80
+ throw new AggregateError([error, closeError], "temp workspace cleanup parent probe admission and close failed");
81
+ }
82
+ parent = undefined;
83
+ }
53
84
  try {
54
- available = binding.ownedTreeRemovalAvailable(parent.fd) === true;
85
+ if (probeReady && parent) {
86
+ available = binding.ownedTreeRemovalAvailable(parent.fd) === true;
87
+ }
55
88
  }
56
89
  catch {
57
90
  // Runtime denial must select fallback or reject before child creation.
58
91
  }
59
92
  }
93
+ this.parent = parent;
60
94
  this.#ownedTreeRemovalAvailable = available;
61
- if (safety === "require-bounded" && !this.canRemoveOwnedTree) {
95
+ if (safety === "require-bounded" && !this.#ownedTreeRemovalAvailable) {
62
96
  this.close();
63
97
  throw new FsSafeError("helper-unavailable", "temp workspace owned-tree cleanup is unavailable");
64
98
  }
65
99
  }
66
100
  get canRemoveOwnedTree() {
67
- return !this.#closed && this.#ownedTreeRemovalAvailable;
101
+ return (this.#phase === "ready" || this.#phase === "sealed") &&
102
+ this.#ownedTreeRemovalAvailable;
68
103
  }
69
- assertCurrent() {
70
- if (this.#closed || !this.parent) {
104
+ prepareChildCreation() {
105
+ const replay = this.#phase === "ready";
106
+ if (this.#phase !== "new" && !replay) {
107
+ throw new FsSafeError("path-mismatch", "temp workspace cleanup parent is unavailable");
108
+ }
109
+ // A failed initial admission or receipt replay is terminal: no earlier
110
+ // authority may survive a partial revalidation.
111
+ this.#phase = "failed";
112
+ if (replay) {
113
+ if (this.parent)
114
+ this.#admission.associateAncestry(this.parent.fd);
115
+ else
116
+ this.#admission.assertAncestry();
117
+ }
118
+ else {
119
+ this.#admission.prepareChildCreation(this.parent?.fd);
120
+ }
121
+ // The retained descriptor cannot authorize cleanup until the complete
122
+ // ancestry and its exact descriptor association succeeded together.
123
+ this.#phase = "ready";
124
+ }
125
+ #assertCurrent(ancestry) {
126
+ if ((this.#phase !== "ready" && this.#phase !== "sealed") || !this.parent) {
127
+ throw new FsSafeError("path-mismatch", "temp workspace cleanup parent is unavailable");
128
+ }
129
+ if (ancestry)
130
+ this.#admission.associateAncestry(this.parent.fd);
131
+ else
132
+ this.#admission.associateCurrent(this.parent.fd);
133
+ }
134
+ admitChildDescriptor(canEnumerate) {
135
+ if (this.#phase !== "ready") {
71
136
  throw new FsSafeError("path-mismatch", "temp workspace cleanup parent is unavailable");
72
137
  }
73
- assertStagedDirectoryCurrent(this.parent.receipt);
74
- const current = fsSync.fstatSync(this.parent.fd, { bigint: true });
75
- if (!sameFileIdentityForCleanup(current, this.parent.receipt.identity)) {
76
- throw new FsSafeError("path-mismatch", "temp workspace cleanup parent changed");
138
+ // From this point the capability belongs to this successfully created
139
+ // child. Collision retries and further preparation must remain impossible.
140
+ this.#phase = "sealed";
141
+ const bounded = this.canRemoveOwnedTree && canEnumerate;
142
+ if (this.#safety === "require-bounded" && !bounded) {
143
+ throw new FsSafeError("helper-unavailable", "temp workspace owned-tree cleanup requires a readable child descriptor");
77
144
  }
145
+ return bounded;
146
+ }
147
+ assertCurrent() {
148
+ this.#assertCurrent(false);
149
+ }
150
+ assertAncestryCurrent() {
151
+ this.#assertCurrent(true);
78
152
  }
79
153
  close() {
80
- if (this.#closed)
154
+ if (this.#phase === "closed")
81
155
  return;
82
- this.#closed = true;
156
+ this.#phase = "closed";
83
157
  if (this.parent)
84
158
  fsSync.closeSync(this.parent.fd);
85
159
  }
@@ -94,21 +168,12 @@ export class TempWorkspaceCleanupOwner {
94
168
  #exitInterrupted = false;
95
169
  #result;
96
170
  #pending;
97
- constructor(dir, identity, capability) {
98
- this.#dir = dir;
99
- this.#identity = { dev: identity.dev, ino: identity.ino };
171
+ constructor(retained, capability, retainDescriptor) {
172
+ const child = retained.transfer(retainDescriptor);
173
+ this.#dir = child.dir;
174
+ this.#identity = child.identity;
100
175
  this.#capability = capability;
101
- let directory;
102
- if (capability.canRemoveOwnedTree) {
103
- directory = openStagedDirectory(dir);
104
- const current = fsSync.fstatSync(directory.fd, { bigint: true });
105
- if (!sameFileIdentityForCleanup(current, this.#identity)) {
106
- fsSync.closeSync(directory.fd);
107
- capability.close();
108
- throw new FsSafeError("path-mismatch", "temp workspace changed while retaining cleanup authority");
109
- }
110
- }
111
- this.#directory = directory;
176
+ this.#directory = child.directory;
112
177
  }
113
178
  #repeat() {
114
179
  return this.#result === "removed" ? "missing" : this.#result;
@@ -186,11 +251,10 @@ export class TempWorkspaceCleanupOwner {
186
251
  this.#capability.binding.renameNoReplace(parent.fd, path.basename(this.#dir), parent.fd, name);
187
252
  }
188
253
  else {
189
- const guard = createSyncDirectoryGuard(parent.receipt.path);
190
- withSyncDirectoryGuards([guard], () => {
191
- this.#capability.assertCurrent();
192
- fsSync.renameSync(this.#dir, quarantinePath);
193
- });
254
+ // The admitted receipt is exact and descriptor-associated. Reuse it as
255
+ // the pre/post parent fence instead of layering a numeric guard over it.
256
+ this.#capability.assertCurrent();
257
+ fsSync.renameSync(this.#dir, quarantinePath);
194
258
  }
195
259
  this.#capability.assertCurrent();
196
260
  const quarantined = fsSync.lstatSync(quarantinePath, { bigint: true });
@@ -232,17 +296,15 @@ export class TempWorkspaceCleanupOwner {
232
296
  }
233
297
  let removalError;
234
298
  try {
235
- const guard = await createAsyncDirectoryGuard(this.#capability.parent.receipt.path);
236
- await withAsyncDirectoryGuards([guard], async () => {
237
- this.#assertQuarantine(quarantine);
238
- try {
239
- await fs.rm(quarantine.path, { recursive: true, force: true });
240
- }
241
- catch (error) {
242
- removalError = error;
243
- throw error;
244
- }
245
- });
299
+ this.#assertQuarantine(quarantine);
300
+ try {
301
+ await fs.rm(quarantine.path, { recursive: true, force: true });
302
+ }
303
+ catch (error) {
304
+ removalError = error;
305
+ throw error;
306
+ }
307
+ this.#capability.assertCurrent();
246
308
  return "removed";
247
309
  }
248
310
  catch (error) {
@@ -258,17 +320,15 @@ export class TempWorkspaceCleanupOwner {
258
320
  }
259
321
  let removalError;
260
322
  try {
261
- const guard = createSyncDirectoryGuard(this.#capability.parent.receipt.path);
262
- withSyncDirectoryGuards([guard], () => {
263
- this.#assertQuarantine(quarantine);
264
- try {
265
- fsSync.rmSync(quarantine.path, { recursive: true, force: true });
266
- }
267
- catch (error) {
268
- removalError = error;
269
- throw error;
270
- }
271
- });
323
+ this.#assertQuarantine(quarantine);
324
+ try {
325
+ fsSync.rmSync(quarantine.path, { recursive: true, force: true });
326
+ }
327
+ catch (error) {
328
+ removalError = error;
329
+ throw error;
330
+ }
331
+ this.#capability.assertCurrent();
272
332
  return "removed";
273
333
  }
274
334
  catch (error) {
@@ -0,0 +1,4 @@
1
+ import type { BigIntStats, Stats } from "node:fs";
2
+ export declare function validateTempWorkspaceDirMode(mode: number): void;
3
+ export declare function assertTrustedTempWorkspaceDirectory(stat: Pick<BigIntStats, "uid" | "mode"> | Pick<Stats, "uid" | "mode">, uid: number | undefined, child?: boolean): void;
4
+ //# sourceMappingURL=temp-workspace-permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temp-workspace-permissions.d.ts","sourceRoot":"","sources":["../src/temp-workspace-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGlD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAO/D;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC,EACrE,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,KAAK,UAAQ,GACZ,IAAI,CAwBN"}
@@ -0,0 +1,32 @@
1
+ import { FsSafeError } from "./errors.js";
2
+ export function validateTempWorkspaceDirMode(mode) {
3
+ if (!Number.isInteger(mode) || mode < 0 || mode > 0o7777) {
4
+ throw new FsSafeError("insecure-permissions", "temp workspace dirMode must be permission bits");
5
+ }
6
+ if (process.platform !== "win32" && (mode & 0o022) !== 0) {
7
+ throw new FsSafeError("insecure-permissions", "temp workspace must not be group/world writable");
8
+ }
9
+ }
10
+ export function assertTrustedTempWorkspaceDirectory(stat, uid, child = false) {
11
+ if (uid === undefined)
12
+ return;
13
+ const ownedByUser = typeof stat.uid === "bigint" ? stat.uid === BigInt(uid) : stat.uid === uid;
14
+ const ownedByRoot = typeof stat.uid === "bigint" ? stat.uid === 0n : stat.uid === 0;
15
+ if (!ownedByUser && (child || !ownedByRoot)) {
16
+ throw new FsSafeError("not-owned", "temp workspace directory has an untrusted owner");
17
+ }
18
+ // A root/current-user-owned sticky directory protects children owned by us,
19
+ // including the usual shared system temp directory. Never chmod that parent.
20
+ const writable = typeof stat.mode === "bigint"
21
+ ? (stat.mode & 18n) !== 0n
22
+ : Number.isSafeInteger(stat.mode) && stat.mode >= 0 && (stat.mode & 0o022) !== 0;
23
+ const sticky = typeof stat.mode === "bigint"
24
+ ? (stat.mode & 512n) !== 0n
25
+ : Number.isSafeInteger(stat.mode) && stat.mode >= 0 && (stat.mode & 0o1000) !== 0;
26
+ if (typeof stat.mode !== "bigint" && (!Number.isSafeInteger(stat.mode) || stat.mode < 0)) {
27
+ throw new FsSafeError("insecure-permissions", "temp workspace directory permissions are invalid");
28
+ }
29
+ if (writable && (child || !sticky)) {
30
+ throw new FsSafeError("insecure-permissions", "temp workspace directory is group/world writable without sticky protection");
31
+ }
32
+ }
@@ -0,0 +1,40 @@
1
+ import type { FileStore, FileStoreSync } from "./file-store.js";
2
+ import type { TempPathIdentityReceipt } from "./temp-cleanup.js";
3
+ import type { TempWorkspaceCleanupResult, TempWorkspaceCleanupSafety } from "./temp-workspace-owner.js";
4
+ export type TempWorkspaceOptions = {
5
+ rootDir: string;
6
+ prefix: string;
7
+ dirMode?: number;
8
+ mode?: number;
9
+ cleanupSafety?: TempWorkspaceCleanupSafety;
10
+ };
11
+ export type TempWorkspace = {
12
+ dir: string;
13
+ identity: TempPathIdentityReceipt;
14
+ store: FileStore;
15
+ path(fileName: string): string;
16
+ write(fileName: string, data: string | Uint8Array): Promise<string>;
17
+ writeText(fileName: string, data: string): Promise<string>;
18
+ writeJson(fileName: string, data: unknown, options?: {
19
+ trailingNewline?: boolean;
20
+ }): Promise<string>;
21
+ copyIn(fileName: string, sourcePath: string): Promise<string>;
22
+ read(fileName: string): Promise<Buffer>;
23
+ cleanup(): Promise<TempWorkspaceCleanupResult>;
24
+ [Symbol.asyncDispose](): Promise<void>;
25
+ };
26
+ export type TempWorkspaceSync = {
27
+ dir: string;
28
+ identity: TempPathIdentityReceipt;
29
+ store: FileStoreSync;
30
+ path(fileName: string): string;
31
+ write(fileName: string, data: string | Uint8Array): string;
32
+ writeText(fileName: string, data: string): string;
33
+ writeJson(fileName: string, data: unknown, options?: {
34
+ trailingNewline?: boolean;
35
+ }): string;
36
+ read(fileName: string): Buffer;
37
+ cleanup(): TempWorkspaceCleanupResult;
38
+ [Symbol.dispose](): void;
39
+ };
40
+ //# sourceMappingURL=temp-workspace-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temp-workspace-types.d.ts","sourceRoot":"","sources":["../src/temp-workspace-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAExG,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,0BAA0B,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACtC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC/C,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IAC3D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAAC;IAC5F,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,OAAO,IAAI,0BAA0B,CAAC;IACtC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/temp.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { tempWorkspace, type TempWorkspace, type TempWorkspaceOptions, type TempWorkspaceCleanupResult, type TempWorkspaceCleanupSafety, tempWorkspaceSync, type TempWorkspaceSync, withTempWorkspace, withTempWorkspaceSync, } from "./private-temp-workspace.js";
2
2
  export type { TempPathIdentityReceipt } from "./temp-cleanup.js";
3
- export { resolveSecureTempRoot, type ResolveSecureTempRootOptions } from "./secure-temp-dir.js";
3
+ export { resolveSecureTempRoot, type ResolveSecureTempRootOptions, type SecureTempRootDescriptorAdapter, } from "./secure-temp-dir.js";
4
4
  //# sourceMappingURL=temp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"temp.d.ts","sourceRoot":"","sources":["../src/temp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"temp.d.ts","sourceRoot":"","sources":["../src/temp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,GACrC,MAAM,sBAAsB,CAAC"}
package/dist/temp.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export { tempWorkspace, tempWorkspaceSync, withTempWorkspace, withTempWorkspaceSync, } from "./private-temp-workspace.js";
2
- export { resolveSecureTempRoot } from "./secure-temp-dir.js";
2
+ export { resolveSecureTempRoot, } from "./secure-temp-dir.js";
@@ -5,10 +5,17 @@ export type FsSafeTestHooks = {
5
5
  beforeOpen?: (filePath: string, flags: number) => Promise<void> | void;
6
6
  afterOpen?: (filePath: string, handle: FileHandle) => Promise<void> | void;
7
7
  afterOpenedPathIdentityCheck?: (filePath: string, handle: FileHandle) => Promise<void> | void;
8
+ afterRootReadPathResolution?: (filePath: string) => Promise<void> | void;
9
+ beforeRootReadFinalFence?: (filePath: string, handle: FileHandle) => Promise<void> | void;
10
+ afterRootReadFinalPathIdentityCheck?: (filePath: string, handle: FileHandle) => void;
8
11
  beforeArchiveOutputMutation?: (operation: "mkdir" | "chmod", targetPath: string) => Promise<void> | void;
9
12
  beforeFileStorePruneDescend?: (dirPath: string) => Promise<void> | void;
10
13
  beforeFileStoreSyncPrivateWrite?: (filePath: string) => void;
11
14
  beforeRootFallbackMutation?: (operation: "mkdir" | "move" | "remove", targetPath: string) => Promise<void> | void;
15
+ beforePinnedWriteParentAdmission?: (targetPath: string) => Promise<void> | void;
16
+ beforeRootStatObservation?: (targetPath: string) => Promise<void> | void;
17
+ beforeRootStatInitialObservation?: (targetPath: string) => Promise<void> | void;
18
+ beforeRootListObservation?: (directoryPath: string, withFileTypes: boolean) => Promise<void> | void;
12
19
  afterPinnedWriteFallbackRename?: (targetPath: string) => Promise<void> | void;
13
20
  beforeSiblingTempWrite?: (tempPath: string) => Promise<void> | void;
14
21
  beforeSidecarLockSnapshotOpen?: (lockPath: string) => Promise<void> | void;
@@ -1 +1 @@
1
- {"version":3,"file":"test-hooks.d.ts","sourceRoot":"","sources":["../src/test-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG;IAC5B,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/D,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,4BAA4B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9F,2BAA2B,CAAC,EAAE,CAC5B,SAAS,EAAE,OAAO,GAAG,OAAO,EAC5B,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,2BAA2B,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxE,+BAA+B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,0BAA0B,CAAC,EAAE,CAC3B,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,EACtC,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,8BAA8B,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9E,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpE,6BAA6B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,2BAA2B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzE,+BAA+B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,gCAAgC,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpF,oCAAoC,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,yBAAyB,CAAC,EAAE,CAC1B,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,EAC1D,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,gBAAgB,KACvB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,0BAA0B,CAAC,EAAE,CAC3B,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,EAC1D,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,gBAAgB,KACvB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC3B,CAAC;AAQF,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAKzE"}
1
+ {"version":3,"file":"test-hooks.d.ts","sourceRoot":"","sources":["../src/test-hooks.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"text-atomic.d.ts","sourceRoot":"","sources":["../src/text-atomic.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAYf"}
1
+ {"version":3,"file":"text-atomic.d.ts","sourceRoot":"","sources":["../src/text-atomic.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAaf"}
@@ -1,9 +1,11 @@
1
1
  import { replaceFileAtomic } from "./replace-file.js";
2
+ import { admitStandalonePublicationPath } from "./standalone-publication-path.js";
2
3
  export async function writeTextAtomic(filePath, content, options) {
4
+ const admittedPath = admitStandalonePublicationPath(filePath);
3
5
  const payload = options?.trailingNewline && !content.endsWith("\n") ? `${content}\n` : content;
4
6
  const durable = options?.durable ?? true;
5
7
  await replaceFileAtomic({
6
- filePath,
8
+ filePath: admittedPath,
7
9
  content: payload,
8
10
  mode: options?.mode ?? 0o600,
9
11
  dirMode: options?.dirMode ?? (0o777 & ~process.umask()),
@@ -1 +1 @@
1
- {"version":3,"file":"trash.d.ts","sourceRoot":"","sources":["../src/trash.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACjC,CAAC;AAkLF,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CAcjB"}
1
+ {"version":3,"file":"trash.d.ts","sourceRoot":"","sources":["../src/trash.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACjC,CAAC;AA8NF,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CAgBjB"}
package/dist/trash.js CHANGED
@@ -6,6 +6,7 @@ import { guardedRenameSync, guardedRmSync } from "./guarded-mutation.js";
6
6
  import { realpathSync } from "./realpath.js";
7
7
  import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
8
8
  import { getFsSafeTestHooks } from "./test-hooks.js";
9
+ import { hasWindowsPathAlias, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
9
10
  const TRASH_DESTINATION_COLLISION_CODES = new Set(["EEXIST", "ENOTEMPTY", "ERR_FS_CP_EEXIST"]);
10
11
  const TRASH_DESTINATION_RETRY_LIMIT = 4;
11
12
  function getFsErrorCode(error) {
@@ -22,32 +23,60 @@ function isTrashDestinationCollision(error) {
22
23
  function isSameOrChildPath(candidate, parent) {
23
24
  return candidate === parent || candidate.startsWith(parent.endsWith(path.sep) ? parent : `${parent}${path.sep}`);
24
25
  }
26
+ function assertNoTrashPathAlias(value, label) {
27
+ if (hasWindowsPathAlias(value, "filesystem")) {
28
+ throw new Error(`Refusing to trash ${label} using a Windows filesystem namespace alias: ${value}`);
29
+ }
30
+ }
31
+ function collectAllowedTrashRoots(allowedRoots) {
32
+ const roots = [...(allowedRoots ?? [os.homedir(), os.tmpdir()])];
33
+ for (const root of roots)
34
+ assertNoTrashPathAlias(root, "allowed root");
35
+ return roots;
36
+ }
25
37
  function resolveAllowedTrashRoots(allowedRoots) {
26
- const roots = [...(allowedRoots ?? [os.homedir(), os.tmpdir()])].flatMap((root) => {
27
- const lexicalRoot = path.resolve(root);
38
+ const roots = allowedRoots.flatMap((root) => {
39
+ assertNoTrashPathAlias(root, "allowed root");
40
+ const lexicalRoot = resolvePathPreservingWindowsRoot(root);
41
+ assertNoTrashPathAlias(lexicalRoot, "allowed root");
42
+ let realRoot;
28
43
  try {
29
44
  // Keep both spellings: broken symlink targets cannot be realpathed and
30
45
  // may only compare equal to the caller's lexical allowed root.
31
- return [path.resolve(realpathSync.native(root)), lexicalRoot];
46
+ realRoot = realpathSync.native(root);
32
47
  }
33
48
  catch {
34
49
  return [lexicalRoot];
35
50
  }
51
+ assertNoTrashPathAlias(realRoot, "allowed root");
52
+ const resolvedRealRoot = resolvePathPreservingWindowsRoot(realRoot);
53
+ assertNoTrashPathAlias(resolvedRealRoot, "allowed root");
54
+ return [resolvedRealRoot, lexicalRoot];
36
55
  });
37
56
  return [...new Set(roots)];
38
57
  }
39
58
  function resolveTrashTargetPath(targetPath) {
59
+ assertNoTrashPathAlias(targetPath, "target path");
60
+ let realPath;
40
61
  try {
41
- return { path: path.resolve(realpathSync.native(targetPath)), resolved: true };
62
+ realPath = realpathSync.native(targetPath);
42
63
  }
43
64
  catch {
44
65
  // Broken symlinks are valid trash targets. Fall back to the lexical path,
45
66
  // then rely on lstat identity so the move renames the symlink itself.
46
- return { path: path.resolve(targetPath), resolved: false };
67
+ const lexicalPath = path.resolve(targetPath);
68
+ assertNoTrashPathAlias(lexicalPath, "target path");
69
+ return { path: lexicalPath, resolved: false };
47
70
  }
71
+ const resolvedPath = path.resolve(realPath);
72
+ assertNoTrashPathAlias(resolvedPath, "target path");
73
+ return { path: resolvedPath, resolved: true };
48
74
  }
49
75
  function assertAllowedTrashTarget(targetPath, allowedRoots) {
50
- const stat = fs.lstatSync(path.resolve(targetPath));
76
+ assertNoTrashPathAlias(targetPath, "target path");
77
+ const lexicalTarget = path.resolve(targetPath);
78
+ assertNoTrashPathAlias(lexicalTarget, "target path");
79
+ const stat = fs.lstatSync(lexicalTarget);
51
80
  const resolvedTarget = resolveTrashTargetPath(targetPath);
52
81
  const resolvedTargetPath = resolvedTarget.path;
53
82
  const isAllowed = resolveAllowedTrashRoots(allowedRoots).some((root) => resolvedTargetPath !== root && isSameOrChildPath(resolvedTargetPath, root));
@@ -55,7 +84,7 @@ function assertAllowedTrashTarget(targetPath, allowedRoots) {
55
84
  throw new Error(`Refusing to trash path outside allowed roots: ${targetPath}`);
56
85
  }
57
86
  return {
58
- path: path.resolve(targetPath),
87
+ path: lexicalTarget,
59
88
  realPath: resolvedTargetPath,
60
89
  realPathResolved: resolvedTarget.resolved,
61
90
  stat,
@@ -76,7 +105,9 @@ function assertTrashTargetGuard(guard) {
76
105
  }
77
106
  function resolveTrashDir() {
78
107
  const homeDir = os.homedir();
108
+ assertNoTrashPathAlias(homeDir, "home directory");
79
109
  const trashDir = path.join(homeDir, ".Trash");
110
+ assertNoTrashPathAlias(trashDir, "trash directory");
80
111
  fs.mkdirSync(recursiveMkdirPath(trashDir), { recursive: true, mode: 0o700 });
81
112
  const trashDirStat = fs.lstatSync(trashDir);
82
113
  if (!trashDirStat.isDirectory() || trashDirStat.isSymbolicLink()) {
@@ -84,13 +115,17 @@ function resolveTrashDir() {
84
115
  }
85
116
  const realHome = path.resolve(realpathSync.native(homeDir));
86
117
  const resolvedTrashDir = path.resolve(realpathSync.native(trashDir));
118
+ assertNoTrashPathAlias(realHome, "home directory");
119
+ assertNoTrashPathAlias(resolvedTrashDir, "trash directory");
87
120
  if (resolvedTrashDir === realHome || !isSameOrChildPath(resolvedTrashDir, realHome)) {
88
121
  throw new Error(`Trash directory escaped home directory: ${trashDir}`);
89
122
  }
90
123
  return resolvedTrashDir;
91
124
  }
92
125
  function trashBaseName(targetPath) {
126
+ assertNoTrashPathAlias(targetPath, "target path");
93
127
  const resolvedTargetPath = path.resolve(targetPath);
128
+ assertNoTrashPathAlias(resolvedTargetPath, "target path");
94
129
  if (resolvedTargetPath === path.parse(resolvedTargetPath).root) {
95
130
  throw new Error(`Refusing to trash root path: ${targetPath}`);
96
131
  }
@@ -101,18 +136,26 @@ function trashBaseName(targetPath) {
101
136
  return base;
102
137
  }
103
138
  function resolveContainedPath(root, leaf) {
139
+ assertNoTrashPathAlias(root, "destination root");
140
+ assertNoTrashPathAlias(leaf, "destination name");
104
141
  const resolvedRoot = path.resolve(root);
105
142
  const resolvedPath = path.resolve(resolvedRoot, leaf);
143
+ assertNoTrashPathAlias(resolvedRoot, "destination root");
144
+ assertNoTrashPathAlias(resolvedPath, "destination path");
106
145
  if (!isSameOrChildPath(resolvedPath, resolvedRoot) || resolvedPath === resolvedRoot) {
107
146
  throw new Error(`Trash destination escaped trash directory: ${resolvedPath}`);
108
147
  }
109
148
  return resolvedPath;
110
149
  }
111
150
  function reserveTrashDestination(trashDir, base, timestamp) {
151
+ assertNoTrashPathAlias(trashDir, "trash directory");
152
+ assertNoTrashPathAlias(base, "destination name");
112
153
  const containerPrefix = resolveContainedPath(trashDir, `.fs-safe-trash-${timestamp}-`);
113
154
  const container = fs.mkdtempSync(containerPrefix);
114
155
  const resolvedContainer = path.resolve(container);
115
156
  const resolvedTrashDir = path.resolve(trashDir);
157
+ assertNoTrashPathAlias(resolvedContainer, "destination container");
158
+ assertNoTrashPathAlias(resolvedTrashDir, "trash directory");
116
159
  if (resolvedContainer === resolvedTrashDir ||
117
160
  !isSameOrChildPath(resolvedContainer, resolvedTrashDir)) {
118
161
  throw new Error(`Trash destination escaped trash directory: ${container}`);
@@ -122,6 +165,7 @@ function reserveTrashDestination(trashDir, base, timestamp) {
122
165
  function copyTrashTargetSync(target, dest) {
123
166
  if (target.stat.isSymbolicLink()) {
124
167
  const linkTarget = fs.readlinkSync(target.path);
168
+ assertNoTrashPathAlias(linkTarget, "symlink target");
125
169
  assertTrashTargetGuard(target);
126
170
  fs.symlinkSync(linkTarget, dest);
127
171
  return;
@@ -159,8 +203,10 @@ function movePathToDestination(target, dest) {
159
203
  }
160
204
  export async function movePathToTrash(targetPath, options = {}) {
161
205
  // Avoid resolving external trash helpers through the service PATH during cleanup.
206
+ assertNoTrashPathAlias(targetPath, "target path");
207
+ const allowedRoots = collectAllowedTrashRoots(options.allowedRoots);
162
208
  const base = trashBaseName(targetPath);
163
- const target = assertAllowedTrashTarget(targetPath, options.allowedRoots);
209
+ const target = assertAllowedTrashTarget(targetPath, allowedRoots);
164
210
  const trashDir = resolveTrashDir();
165
211
  const timestamp = Date.now();
166
212
  for (let attempt = 0; attempt < TRASH_DESTINATION_RETRY_LIMIT; attempt += 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAK7B,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AACvE,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE9D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IAGnB,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACrC,CAAC;AAEF,KAAK,+BAA+B,GAAG,mBAAmB,GAAG;IAC3D,UAAU,EAAE,oBAAoB,EAAE,CAAC;CACpC,CAAC;AA+EF,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,oBAAyB,GACjC,+BAA+B,CA0DjC;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,+BAA+B,CAAC,CA0D1C"}
1
+ {"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAS7B,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AACvE,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE9D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IAGnB,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACrC,CAAC;AAEF,KAAK,+BAA+B,GAAG,mBAAmB,GAAG;IAC3D,UAAU,EAAE,oBAAoB,EAAE,CAAC;CACpC,CAAC;AA+EF,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,oBAAyB,GACjC,+BAA+B,CA2DjC;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,+BAA+B,CAAC,CA2D1C"}