@openclaw/fs-safe 0.16.0 → 0.18.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 (705) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +8 -1
  3. package/dist/absolute-path.d.ts +0 -1
  4. package/dist/absolute-path.js +2 -8
  5. package/dist/advanced.d.ts +2 -1
  6. package/dist/advanced.js +2 -0
  7. package/dist/archive-crc32.d.ts +0 -1
  8. package/dist/archive-deadline.d.ts +0 -1
  9. package/dist/archive-deadline.js +22 -23
  10. package/dist/archive-durability.d.ts +0 -1
  11. package/dist/archive-entry.d.ts +0 -1
  12. package/dist/archive-errors.d.ts +0 -1
  13. package/dist/archive-gzip-tail.d.ts +0 -1
  14. package/dist/archive-input.d.ts +0 -1
  15. package/dist/archive-kind.d.ts +0 -1
  16. package/dist/archive-limits.d.ts +0 -1
  17. package/dist/archive-merge.d.ts +3 -4
  18. package/dist/archive-merge.js +17 -7
  19. package/dist/archive-native.d.ts +3 -14
  20. package/dist/archive-native.js +46 -70
  21. package/dist/archive-options.d.ts +9 -2
  22. package/dist/archive-parser-errors.d.ts +0 -1
  23. package/dist/archive-parser.wasm +0 -0
  24. package/dist/archive-plan.d.ts +10 -1
  25. package/dist/archive-plan.js +31 -21
  26. package/dist/archive-policy.d.ts +0 -1
  27. package/dist/archive-read.d.ts +0 -1
  28. package/dist/archive-staging.d.ts +0 -1
  29. package/dist/archive-tar-inspect.d.ts +0 -1
  30. package/dist/archive-tar-stream.d.ts +0 -1
  31. package/dist/archive-tar-wasm.d.ts +0 -1
  32. package/dist/archive-tar.d.ts +0 -1
  33. package/dist/archive-zip-admission.d.ts +0 -1
  34. package/dist/archive-zip-count.d.ts +0 -1
  35. package/dist/archive-zip-count.js +21 -1
  36. package/dist/archive-zip-directory.d.ts +0 -1
  37. package/dist/archive-zip-directory.js +23 -1
  38. package/dist/archive-zip-entry.d.ts +0 -1
  39. package/dist/archive-zip-integrity.d.ts +0 -1
  40. package/dist/archive-zip-loader.d.ts +2 -1
  41. package/dist/archive-zip-loader.js +7 -0
  42. package/dist/archive-zip-manifest.d.ts +0 -1
  43. package/dist/archive-zip-names.d.ts +0 -1
  44. package/dist/archive-zip-names.js +7 -2
  45. package/dist/archive-zip-preflight.d.ts +0 -1
  46. package/dist/archive.d.ts +0 -1
  47. package/dist/archive.js +93 -164
  48. package/dist/async-lock.d.ts +0 -1
  49. package/dist/atomic.d.ts +0 -1
  50. package/dist/bounded-read-stream.d.ts +0 -1
  51. package/dist/bounded-read.d.ts +0 -1
  52. package/dist/byte-budget.d.ts +0 -1
  53. package/dist/byte-view.d.ts +2 -0
  54. package/dist/byte-view.js +13 -0
  55. package/dist/clone-metadata.d.ts +0 -1
  56. package/dist/config.d.ts +0 -1
  57. package/dist/containment.d.ts +0 -1
  58. package/dist/copy-file-input.d.ts +0 -1
  59. package/dist/copy-policy.d.ts +0 -1
  60. package/dist/copy-publication.d.ts +0 -1
  61. package/dist/copy-tree-portable.d.ts +0 -1
  62. package/dist/copy-tree-portable.js +9 -6
  63. package/dist/copy.d.ts +0 -1
  64. package/dist/copy.js +5 -5
  65. package/dist/create-directory.d.ts +0 -2
  66. package/dist/create-directory.js +3 -22
  67. package/dist/create-file-async.d.ts +0 -1
  68. package/dist/create-file.d.ts +0 -1
  69. package/dist/create-file.js +3 -14
  70. package/dist/create-owned-file.d.ts +0 -1
  71. package/dist/create.d.ts +1 -2
  72. package/dist/create.js +1 -1
  73. package/dist/creation-darwin.d.ts +0 -2
  74. package/dist/creation-darwin.js +0 -9
  75. package/dist/creation-file-state.d.ts +0 -1
  76. package/dist/creation-path.d.ts +2 -1
  77. package/dist/creation-path.js +12 -0
  78. package/dist/creation-permissions.d.ts +0 -1
  79. package/dist/creation-permissions.js +28 -38
  80. package/dist/deny-mutations.d.ts +2 -3
  81. package/dist/deny-mutations.js +55 -35
  82. package/dist/device-path.d.ts +0 -1
  83. package/dist/directory-durability.d.ts +6 -7
  84. package/dist/directory-entry-path.d.ts +0 -1
  85. package/dist/directory-guard.d.ts +2 -7
  86. package/dist/directory-guard.js +25 -56
  87. package/dist/directory-mode-node.d.ts +0 -1
  88. package/dist/directory-mode-owner.d.ts +0 -1
  89. package/dist/directory-receipt.d.ts +2 -3
  90. package/dist/directory-receipt.js +15 -19
  91. package/dist/durability.d.ts +0 -1
  92. package/dist/effective-uid.d.ts +0 -1
  93. package/dist/error-detail.d.ts +0 -1
  94. package/dist/errors.d.ts +0 -1
  95. package/dist/file-cleanup.d.ts +1 -1
  96. package/dist/file-cleanup.js +7 -4
  97. package/dist/file-contents.d.ts +5 -0
  98. package/dist/file-contents.js +40 -0
  99. package/dist/file-handle-transfer.d.ts +0 -1
  100. package/dist/file-hash.d.ts +0 -1
  101. package/dist/file-hash.js +186 -70
  102. package/dist/file-identity.d.ts +0 -1
  103. package/dist/file-lock-sync-acquisition.d.ts +22 -0
  104. package/dist/file-lock-sync-acquisition.js +98 -0
  105. package/dist/file-lock-sync-admission.d.ts +0 -2
  106. package/dist/file-lock-sync-admission.js +9 -48
  107. package/dist/file-lock-sync-root-acquire.d.ts +0 -1
  108. package/dist/file-lock-sync-root-acquire.js +35 -98
  109. package/dist/file-lock-sync-root-arbitration.d.ts +0 -1
  110. package/dist/file-lock-sync-root-held.d.ts +1 -3
  111. package/dist/file-lock-sync-root-held.js +7 -5
  112. package/dist/file-lock-sync-root-io.d.ts +0 -1
  113. package/dist/file-lock-sync-root-mutation.d.ts +4 -5
  114. package/dist/file-lock-sync-root-mutation.js +7 -9
  115. package/dist/file-lock-sync-root-options.d.ts +0 -1
  116. package/dist/file-lock-sync-root-registration.d.ts +0 -1
  117. package/dist/file-lock-sync-root.d.ts +1 -2
  118. package/dist/file-lock-sync-root.js +14 -87
  119. package/dist/file-lock-sync-stale-admission.d.ts +2 -7
  120. package/dist/file-lock-sync-stale-admission.js +24 -23
  121. package/dist/file-lock-sync.d.ts +0 -1
  122. package/dist/file-lock-sync.js +46 -128
  123. package/dist/file-lock.d.ts +0 -1
  124. package/dist/file-observation.d.ts +0 -1
  125. package/dist/file-store-boundary.d.ts +0 -2
  126. package/dist/file-store-boundary.js +6 -26
  127. package/dist/file-store-copy-source.d.ts +1 -2
  128. package/dist/file-store-copy-source.js +1 -1
  129. package/dist/file-store-limit.d.ts +1 -2
  130. package/dist/file-store-limit.js +2 -3
  131. package/dist/file-store-path.d.ts +0 -1
  132. package/dist/file-store-prune.d.ts +0 -1
  133. package/dist/file-store-sync-directory.d.ts +0 -1
  134. package/dist/file-store-sync-directory.js +194 -231
  135. package/dist/file-store-sync-write.d.ts +0 -1
  136. package/dist/file-store-sync-write.js +16 -26
  137. package/dist/file-store.d.ts +0 -1
  138. package/dist/file-store.js +6 -7
  139. package/dist/file-sync.d.ts +0 -1
  140. package/dist/filename.d.ts +0 -1
  141. package/dist/filename.js +1 -7
  142. package/dist/fs.d.ts +0 -1
  143. package/dist/guarded-mkdir.d.ts +0 -1
  144. package/dist/guarded-mkdir.js +6 -27
  145. package/dist/guarded-mutation.d.ts +0 -7
  146. package/dist/guarded-mutation.js +6 -11
  147. package/dist/guest-dispatch-python.d.ts +0 -1
  148. package/dist/guest-dispatch-python.js +41 -90
  149. package/dist/guest-native-python.d.ts +0 -1
  150. package/dist/guest.d.ts +0 -1
  151. package/dist/home-dir.d.ts +0 -1
  152. package/dist/index.d.ts +0 -1
  153. package/dist/install-path.d.ts +0 -1
  154. package/dist/install-path.js +2 -5
  155. package/dist/json-document-store.d.ts +0 -1
  156. package/dist/json-durable-queue-directory.d.ts +13 -1
  157. package/dist/json-durable-queue-directory.js +134 -0
  158. package/dist/json-durable-queue-ownership.d.ts +0 -1
  159. package/dist/json-durable-queue-ownership.js +43 -66
  160. package/dist/json-durable-queue-read.d.ts +0 -1
  161. package/dist/json-durable-queue-read.js +6 -6
  162. package/dist/json-durable-queue.d.ts +0 -1
  163. package/dist/json-durable-queue.js +17 -139
  164. package/dist/json-store.d.ts +0 -1
  165. package/dist/json-stringify.d.ts +0 -1
  166. package/dist/json.d.ts +0 -1
  167. package/dist/json.js +38 -90
  168. package/dist/local-file-access.d.ts +0 -1
  169. package/dist/local-file-access.js +3 -10
  170. package/dist/local-file-descriptor.d.ts +0 -1
  171. package/dist/local-roots.d.ts +0 -1
  172. package/dist/local-roots.js +19 -21
  173. package/dist/lock-config.d.ts +0 -1
  174. package/dist/move-path-cleanup.d.ts +5 -20
  175. package/dist/move-path-cleanup.js +57 -21
  176. package/dist/move-path-stage.d.ts +0 -1
  177. package/dist/move-path.d.ts +0 -1
  178. package/dist/move-path.js +62 -39
  179. package/dist/mutation-authority.d.ts +0 -1
  180. package/dist/native-binding.d.ts +0 -1
  181. package/dist/native-config.d.ts +0 -1
  182. package/dist/native-directory-observation.d.ts +0 -1
  183. package/dist/native-fallback-warning.d.ts +0 -1
  184. package/dist/native-operations.d.ts +1 -5
  185. package/dist/native-operations.js +2 -6
  186. package/dist/native-parent-admission.d.ts +0 -1
  187. package/dist/native-pinned-write-windows.d.ts +0 -1
  188. package/dist/native-pinned-write.d.ts +0 -1
  189. package/dist/native-pinned-write.js +4 -10
  190. package/dist/native-policy-directory-observation.d.ts +0 -1
  191. package/dist/native-policy-parent-windows.d.ts +0 -1
  192. package/dist/native-rename-outcome.d.ts +0 -1
  193. package/dist/native-staged-file.d.ts +17 -4
  194. package/dist/native-staged-file.js +63 -68
  195. package/dist/native.d.ts +0 -1
  196. package/dist/native.js +2 -2
  197. package/dist/opened-file-failure.d.ts +0 -1
  198. package/dist/opened-realpath.d.ts +0 -1
  199. package/dist/opened-realpath.js +11 -2
  200. package/dist/output.d.ts +0 -1
  201. package/dist/overwrite-file-handle.d.ts +0 -1
  202. package/dist/owner-dacl.d.ts +0 -1
  203. package/dist/path-case.d.ts +0 -1
  204. package/dist/path-policy.d.ts +0 -1
  205. package/dist/path-prefix.d.ts +0 -1
  206. package/dist/path-scope-lexical.d.ts +0 -1
  207. package/dist/path-segment-route.d.ts +0 -1
  208. package/dist/path-suffix-aliases.d.ts +0 -1
  209. package/dist/path.d.ts +0 -1
  210. package/dist/path.js +2 -1
  211. package/dist/permission-exec.d.ts +0 -1
  212. package/dist/permission-exec.js +19 -25
  213. package/dist/permissions-public.d.ts +0 -1
  214. package/dist/permissions-windows.d.ts +2 -10
  215. package/dist/permissions-windows.js +10 -30
  216. package/dist/permissions.d.ts +0 -1
  217. package/dist/permissions.js +11 -33
  218. package/dist/pinned-mutation-admission.d.ts +0 -1
  219. package/dist/pinned-mutation-observation.d.ts +0 -1
  220. package/dist/pinned-mutation-shared-route.d.ts +0 -1
  221. package/dist/pinned-open.d.ts +1 -1
  222. package/dist/pinned-open.js +1 -1
  223. package/dist/pinned-operation.d.ts +0 -1
  224. package/dist/pinned-write-input.d.ts +0 -1
  225. package/dist/pinned-write-input.js +11 -1
  226. package/dist/pinned-write-mode.d.ts +3 -4
  227. package/dist/pinned-write-mode.js +15 -8
  228. package/dist/pinned-write-staged.d.ts +0 -1
  229. package/dist/pinned-write-staged.js +10 -11
  230. package/dist/pinned-write-types.d.ts +9 -21
  231. package/dist/pinned-write.d.ts +0 -1
  232. package/dist/pinned-write.js +17 -13
  233. package/dist/positional-read.d.ts +0 -1
  234. package/dist/private-directory.d.ts +0 -1
  235. package/dist/private-producer-handoff-sync.d.ts +0 -1
  236. package/dist/private-producer-handoff-sync.js +9 -51
  237. package/dist/private-producer-handoff.d.ts +20 -1
  238. package/dist/private-producer-handoff.js +69 -46
  239. package/dist/private-temp-workspace.d.ts +0 -1
  240. package/dist/private-temp-workspace.js +11 -36
  241. package/dist/publish-copy-stage.d.ts +0 -1
  242. package/dist/publish-file-failure.d.ts +0 -1
  243. package/dist/publish-file.d.ts +2 -3
  244. package/dist/publish-file.js +56 -96
  245. package/dist/read-open-flags.d.ts +0 -1
  246. package/dist/read-opened-file.d.ts +0 -1
  247. package/dist/realpath.d.ts +0 -1
  248. package/dist/recursive-mkdir-path.d.ts +0 -1
  249. package/dist/regular-file.d.ts +0 -1
  250. package/dist/regular-file.js +107 -178
  251. package/dist/replace-directory.d.ts +0 -1
  252. package/dist/replace-file-copy-fallback.d.ts +0 -1
  253. package/dist/replace-file-copy-fallback.js +42 -29
  254. package/dist/replace-file-copy-source.d.ts +0 -1
  255. package/dist/replace-file-copy-source.js +19 -23
  256. package/dist/replace-file-descriptor.d.ts +0 -1
  257. package/dist/replace-file-descriptor.js +16 -17
  258. package/dist/replace-file-mode.d.ts +0 -1
  259. package/dist/replace-file-rename-policy.d.ts +0 -1
  260. package/dist/replace-file-temp-owner.d.ts +12 -13
  261. package/dist/replace-file-temp-owner.js +72 -91
  262. package/dist/replace-file.d.ts +0 -1
  263. package/dist/replace-file.js +9 -13
  264. package/dist/retained-directory-replacement.d.ts +0 -1
  265. package/dist/root-boundary.d.ts +0 -1
  266. package/dist/root-context.d.ts +0 -1
  267. package/dist/root-create-input.d.ts +0 -1
  268. package/dist/root-directory-creation.d.ts +0 -1
  269. package/dist/root-directory-list.d.ts +0 -1
  270. package/dist/root-directory-list.js +20 -3
  271. package/dist/root-directory.d.ts +0 -1
  272. package/dist/root-entries.d.ts +0 -1
  273. package/dist/root-errors.d.ts +0 -1
  274. package/dist/root-file-final-admission.d.ts +1 -2
  275. package/dist/root-file-final-admission.js +5 -2
  276. package/dist/root-file.d.ts +0 -1
  277. package/dist/root-file.js +3 -2
  278. package/dist/root-impl.d.ts +2 -10
  279. package/dist/root-impl.js +164 -111
  280. package/dist/root-move-noreplace.d.ts +2 -1
  281. package/dist/root-move-noreplace.js +2 -2
  282. package/dist/root-move-preflight.d.ts +0 -1
  283. package/dist/root-observed-path.d.ts +0 -1
  284. package/dist/root-options.d.ts +0 -1
  285. package/dist/root-path-errors.d.ts +0 -1
  286. package/dist/root-path-existing.d.ts +3 -1
  287. package/dist/root-path-existing.js +39 -18
  288. package/dist/root-path-observation.d.ts +0 -1
  289. package/dist/root-path-stat.d.ts +0 -1
  290. package/dist/root-path.d.ts +0 -1
  291. package/dist/root-path.js +60 -188
  292. package/dist/root-paths-lexical.d.ts +0 -1
  293. package/dist/root-paths.d.ts +0 -1
  294. package/dist/root-read-admission.d.ts +0 -1
  295. package/dist/root-read-admission.js +31 -39
  296. package/dist/root-remove-identity.d.ts +0 -1
  297. package/dist/root-remove-receipt.d.ts +0 -1
  298. package/dist/root-remove.d.ts +0 -1
  299. package/dist/root-remove.js +15 -1
  300. package/dist/root-symlink-policy.d.ts +0 -1
  301. package/dist/root-walk.d.ts +0 -1
  302. package/dist/root-write-admission.d.ts +0 -1
  303. package/dist/root-write-compatibility.d.ts +0 -1
  304. package/dist/root-write-complete-parent.d.ts +0 -1
  305. package/dist/root-write-lock-binding.d.ts +0 -1
  306. package/dist/root-write-mode.d.ts +0 -1
  307. package/dist/root-write-publication.d.ts +0 -1
  308. package/dist/root-write-verification.d.ts +0 -1
  309. package/dist/root.d.ts +0 -1
  310. package/dist/safe-path-segment.d.ts +1 -2
  311. package/dist/safe-path-segment.js +2 -5
  312. package/dist/secret-file.d.ts +0 -1
  313. package/dist/secret-file.js +7 -17
  314. package/dist/secret-read-async.d.ts +0 -1
  315. package/dist/secret-read-async.js +5 -5
  316. package/dist/secret-read-policy.d.ts +0 -1
  317. package/dist/secret.d.ts +0 -1
  318. package/dist/secure-file-windows.d.ts +0 -6
  319. package/dist/secure-file-windows.js +13 -28
  320. package/dist/secure-file.d.ts +0 -1
  321. package/dist/secure-file.js +9 -9
  322. package/dist/secure-temp-dir.d.ts +0 -1
  323. package/dist/secure-temp-repair.d.ts +0 -1
  324. package/dist/sibling-staged-file.d.ts +0 -1
  325. package/dist/sibling-staged-file.js +32 -39
  326. package/dist/sibling-temp.d.ts +0 -1
  327. package/dist/sidecar-lock-acquire.d.ts +1 -2
  328. package/dist/sidecar-lock-acquire.js +35 -58
  329. package/dist/sidecar-lock-admission-context.d.ts +0 -1
  330. package/dist/sidecar-lock-admission-parser.d.ts +0 -1
  331. package/dist/sidecar-lock-admission.d.ts +1 -5
  332. package/dist/sidecar-lock-admission.js +1 -7
  333. package/dist/sidecar-lock-handle.d.ts +3 -1
  334. package/dist/sidecar-lock-handle.js +6 -0
  335. package/dist/sidecar-lock-policy.d.ts +3 -1
  336. package/dist/sidecar-lock-policy.js +16 -0
  337. package/dist/sidecar-lock-reclaim.d.ts +1 -2
  338. package/dist/sidecar-lock-reclaim.js +11 -8
  339. package/dist/sidecar-lock-registration.d.ts +13 -0
  340. package/dist/sidecar-lock-registration.js +47 -0
  341. package/dist/sidecar-lock-root.d.ts +0 -1
  342. package/dist/sidecar-lock-stale-admission.d.ts +0 -1
  343. package/dist/sidecar-lock-target.d.ts +0 -1
  344. package/dist/sidecar-lock-types.d.ts +0 -1
  345. package/dist/sidecar-lock.d.ts +0 -1
  346. package/dist/sidecar-lock.js +19 -88
  347. package/dist/staged-directory.d.ts +2 -3
  348. package/dist/staged-file-settlement.d.ts +0 -1
  349. package/dist/staged-file-types.d.ts +0 -1
  350. package/dist/standalone-publication-path.d.ts +0 -1
  351. package/dist/stat-observation.d.ts +0 -1
  352. package/dist/store.d.ts +0 -1
  353. package/dist/strict-file-identity.d.ts +1 -2
  354. package/dist/strict-file-identity.js +9 -9
  355. package/dist/string-coerce.d.ts +0 -1
  356. package/dist/suppressed-error.d.ts +0 -1
  357. package/dist/symlink-parents.d.ts +0 -1
  358. package/dist/symlink-parents.js +2 -27
  359. package/dist/temp-cleanup.d.ts +0 -1
  360. package/dist/temp-target.d.ts +0 -1
  361. package/dist/temp-target.js +7 -46
  362. package/dist/temp-workspace-admission.d.ts +0 -8
  363. package/dist/temp-workspace-admission.js +0 -4
  364. package/dist/temp-workspace-child-admission.d.ts +0 -4
  365. package/dist/temp-workspace-child-admission.js +0 -12
  366. package/dist/temp-workspace-descriptor.d.ts +0 -6
  367. package/dist/temp-workspace-descriptor.js +0 -2
  368. package/dist/temp-workspace-identity.d.ts +0 -1
  369. package/dist/temp-workspace-owner.d.ts +1 -1
  370. package/dist/temp-workspace-owner.js +49 -26
  371. package/dist/temp-workspace-permissions.d.ts +0 -1
  372. package/dist/temp-workspace-types.d.ts +0 -1
  373. package/dist/temp.d.ts +0 -1
  374. package/dist/test-hooks.d.ts +0 -1
  375. package/dist/text-atomic.d.ts +0 -1
  376. package/dist/timing.d.ts +0 -1
  377. package/dist/trash.d.ts +0 -1
  378. package/dist/types.d.ts +0 -1
  379. package/dist/unicode-path.d.ts +0 -1
  380. package/dist/unicode-path.js +3 -0
  381. package/dist/walk.d.ts +0 -1
  382. package/dist/walk.js +4 -2
  383. package/dist/windows-command.d.ts +0 -1
  384. package/dist/windows-owner.d.ts +0 -1
  385. package/dist/windows-owner.js +4 -1
  386. package/dist/windows-path-alias.d.ts +0 -1
  387. package/dist/windows-path-alias.js +7 -43
  388. package/dist/windows-path-syntax.d.ts +5 -0
  389. package/dist/windows-path-syntax.js +21 -0
  390. package/dist/windows-security-command.d.ts +0 -1
  391. package/dist/windows-security-facts.d.ts +0 -1
  392. package/dist/write-file-handle.d.ts +7 -1
  393. package/dist/write-file-handle.js +23 -0
  394. package/dist/write-open-flags.d.ts +0 -1
  395. package/dist/write-open-flags.js +1 -8
  396. package/dist/write-queue.d.ts +0 -1
  397. package/dist/write-queue.js +1 -4
  398. package/docs/advanced.md +68 -1
  399. package/docs/archive.md +41 -2
  400. package/docs/atomic.md +43 -5
  401. package/docs/contributing.md +4 -0
  402. package/docs/copy.md +2 -0
  403. package/docs/creation.md +8 -4
  404. package/docs/durability.md +35 -0
  405. package/docs/file-contents.md +68 -0
  406. package/docs/json.md +5 -4
  407. package/docs/local-roots.md +2 -0
  408. package/docs/mutation-policy-proof.md +11 -7
  409. package/docs/native.md +9 -8
  410. package/docs/path.md +4 -4
  411. package/docs/permissions.md +6 -0
  412. package/docs/public-api.md +5 -0
  413. package/docs/quickstart.md +1 -1
  414. package/docs/reading.md +2 -2
  415. package/docs/regular-file.md +3 -0
  416. package/docs/root.md +19 -0
  417. package/docs/secret-file.md +4 -0
  418. package/docs/sidecar-lock.md +9 -1
  419. package/docs/staged-file.md +4 -3
  420. package/docs/store.md +3 -1
  421. package/docs/temp.md +4 -1
  422. package/docs/types.md +18 -2
  423. package/docs/walk.md +7 -0
  424. package/docs/writing.md +18 -5
  425. package/package.json +8 -9
  426. package/dist/absolute-path.d.ts.map +0 -1
  427. package/dist/advanced.d.ts.map +0 -1
  428. package/dist/archive-crc32.d.ts.map +0 -1
  429. package/dist/archive-deadline.d.ts.map +0 -1
  430. package/dist/archive-durability.d.ts.map +0 -1
  431. package/dist/archive-entry.d.ts.map +0 -1
  432. package/dist/archive-errors.d.ts.map +0 -1
  433. package/dist/archive-gzip-tail.d.ts.map +0 -1
  434. package/dist/archive-input.d.ts.map +0 -1
  435. package/dist/archive-kind.d.ts.map +0 -1
  436. package/dist/archive-limits.d.ts.map +0 -1
  437. package/dist/archive-merge.d.ts.map +0 -1
  438. package/dist/archive-native.d.ts.map +0 -1
  439. package/dist/archive-options.d.ts.map +0 -1
  440. package/dist/archive-parser-errors.d.ts.map +0 -1
  441. package/dist/archive-plan.d.ts.map +0 -1
  442. package/dist/archive-policy.d.ts.map +0 -1
  443. package/dist/archive-read.d.ts.map +0 -1
  444. package/dist/archive-staging.d.ts.map +0 -1
  445. package/dist/archive-tar-inspect.d.ts.map +0 -1
  446. package/dist/archive-tar-stream.d.ts.map +0 -1
  447. package/dist/archive-tar-wasm.d.ts.map +0 -1
  448. package/dist/archive-tar.d.ts.map +0 -1
  449. package/dist/archive-zip-admission.d.ts.map +0 -1
  450. package/dist/archive-zip-count.d.ts.map +0 -1
  451. package/dist/archive-zip-directory.d.ts.map +0 -1
  452. package/dist/archive-zip-entry.d.ts.map +0 -1
  453. package/dist/archive-zip-integrity.d.ts.map +0 -1
  454. package/dist/archive-zip-loader.d.ts.map +0 -1
  455. package/dist/archive-zip-manifest.d.ts.map +0 -1
  456. package/dist/archive-zip-names.d.ts.map +0 -1
  457. package/dist/archive-zip-preflight.d.ts.map +0 -1
  458. package/dist/archive.d.ts.map +0 -1
  459. package/dist/async-lock.d.ts.map +0 -1
  460. package/dist/atomic.d.ts.map +0 -1
  461. package/dist/bounded-read-stream.d.ts.map +0 -1
  462. package/dist/bounded-read.d.ts.map +0 -1
  463. package/dist/byte-budget.d.ts.map +0 -1
  464. package/dist/clone-metadata.d.ts.map +0 -1
  465. package/dist/config.d.ts.map +0 -1
  466. package/dist/containment.d.ts.map +0 -1
  467. package/dist/copy-file-input.d.ts.map +0 -1
  468. package/dist/copy-policy.d.ts.map +0 -1
  469. package/dist/copy-publication.d.ts.map +0 -1
  470. package/dist/copy-tree-portable.d.ts.map +0 -1
  471. package/dist/copy.d.ts.map +0 -1
  472. package/dist/create-directory.d.ts.map +0 -1
  473. package/dist/create-file-async.d.ts.map +0 -1
  474. package/dist/create-file.d.ts.map +0 -1
  475. package/dist/create-owned-file.d.ts.map +0 -1
  476. package/dist/create.d.ts.map +0 -1
  477. package/dist/creation-darwin.d.ts.map +0 -1
  478. package/dist/creation-file-state.d.ts.map +0 -1
  479. package/dist/creation-path.d.ts.map +0 -1
  480. package/dist/creation-permissions.d.ts.map +0 -1
  481. package/dist/deny-mutations.d.ts.map +0 -1
  482. package/dist/device-path.d.ts.map +0 -1
  483. package/dist/directory-durability.d.ts.map +0 -1
  484. package/dist/directory-entry-path.d.ts.map +0 -1
  485. package/dist/directory-guard.d.ts.map +0 -1
  486. package/dist/directory-mode-node.d.ts.map +0 -1
  487. package/dist/directory-mode-owner.d.ts.map +0 -1
  488. package/dist/directory-receipt.d.ts.map +0 -1
  489. package/dist/durability.d.ts.map +0 -1
  490. package/dist/effective-uid.d.ts.map +0 -1
  491. package/dist/error-detail.d.ts.map +0 -1
  492. package/dist/errors.d.ts.map +0 -1
  493. package/dist/file-cleanup.d.ts.map +0 -1
  494. package/dist/file-handle-transfer.d.ts.map +0 -1
  495. package/dist/file-hash.d.ts.map +0 -1
  496. package/dist/file-identity.d.ts.map +0 -1
  497. package/dist/file-lock-sync-admission.d.ts.map +0 -1
  498. package/dist/file-lock-sync-root-acquire.d.ts.map +0 -1
  499. package/dist/file-lock-sync-root-arbitration.d.ts.map +0 -1
  500. package/dist/file-lock-sync-root-held.d.ts.map +0 -1
  501. package/dist/file-lock-sync-root-io.d.ts.map +0 -1
  502. package/dist/file-lock-sync-root-mutation.d.ts.map +0 -1
  503. package/dist/file-lock-sync-root-options.d.ts.map +0 -1
  504. package/dist/file-lock-sync-root-registration.d.ts.map +0 -1
  505. package/dist/file-lock-sync-root.d.ts.map +0 -1
  506. package/dist/file-lock-sync-stale-admission.d.ts.map +0 -1
  507. package/dist/file-lock-sync.d.ts.map +0 -1
  508. package/dist/file-lock.d.ts.map +0 -1
  509. package/dist/file-observation.d.ts.map +0 -1
  510. package/dist/file-store-boundary.d.ts.map +0 -1
  511. package/dist/file-store-copy-source.d.ts.map +0 -1
  512. package/dist/file-store-limit.d.ts.map +0 -1
  513. package/dist/file-store-path.d.ts.map +0 -1
  514. package/dist/file-store-prune.d.ts.map +0 -1
  515. package/dist/file-store-sync-directory.d.ts.map +0 -1
  516. package/dist/file-store-sync-write.d.ts.map +0 -1
  517. package/dist/file-store.d.ts.map +0 -1
  518. package/dist/file-sync.d.ts.map +0 -1
  519. package/dist/filename.d.ts.map +0 -1
  520. package/dist/fs.d.ts.map +0 -1
  521. package/dist/guarded-mkdir.d.ts.map +0 -1
  522. package/dist/guarded-mutation.d.ts.map +0 -1
  523. package/dist/guest-dispatch-python.d.ts.map +0 -1
  524. package/dist/guest-native-python.d.ts.map +0 -1
  525. package/dist/guest.d.ts.map +0 -1
  526. package/dist/home-dir.d.ts.map +0 -1
  527. package/dist/index.d.ts.map +0 -1
  528. package/dist/install-path.d.ts.map +0 -1
  529. package/dist/json-document-store.d.ts.map +0 -1
  530. package/dist/json-durable-queue-directory.d.ts.map +0 -1
  531. package/dist/json-durable-queue-ownership.d.ts.map +0 -1
  532. package/dist/json-durable-queue-paths.d.ts +0 -11
  533. package/dist/json-durable-queue-paths.d.ts.map +0 -1
  534. package/dist/json-durable-queue-paths.js +0 -42
  535. package/dist/json-durable-queue-read.d.ts.map +0 -1
  536. package/dist/json-durable-queue.d.ts.map +0 -1
  537. package/dist/json-store.d.ts.map +0 -1
  538. package/dist/json-stringify.d.ts.map +0 -1
  539. package/dist/json.d.ts.map +0 -1
  540. package/dist/local-file-access.d.ts.map +0 -1
  541. package/dist/local-file-descriptor.d.ts.map +0 -1
  542. package/dist/local-roots.d.ts.map +0 -1
  543. package/dist/lock-config.d.ts.map +0 -1
  544. package/dist/move-path-cleanup.d.ts.map +0 -1
  545. package/dist/move-path-stage.d.ts.map +0 -1
  546. package/dist/move-path.d.ts.map +0 -1
  547. package/dist/mutation-authority.d.ts.map +0 -1
  548. package/dist/native-binding.d.ts.map +0 -1
  549. package/dist/native-config.d.ts.map +0 -1
  550. package/dist/native-directory-observation.d.ts.map +0 -1
  551. package/dist/native-fallback-warning.d.ts.map +0 -1
  552. package/dist/native-operations.d.ts.map +0 -1
  553. package/dist/native-parent-admission.d.ts.map +0 -1
  554. package/dist/native-pinned-write-windows.d.ts.map +0 -1
  555. package/dist/native-pinned-write.d.ts.map +0 -1
  556. package/dist/native-policy-directory-observation.d.ts.map +0 -1
  557. package/dist/native-policy-parent-windows.d.ts.map +0 -1
  558. package/dist/native-rename-outcome.d.ts.map +0 -1
  559. package/dist/native-staged-file.d.ts.map +0 -1
  560. package/dist/native.d.ts.map +0 -1
  561. package/dist/opened-file-failure.d.ts.map +0 -1
  562. package/dist/opened-realpath.d.ts.map +0 -1
  563. package/dist/output.d.ts.map +0 -1
  564. package/dist/overwrite-file-handle.d.ts.map +0 -1
  565. package/dist/owner-dacl.d.ts.map +0 -1
  566. package/dist/path-case.d.ts.map +0 -1
  567. package/dist/path-policy.d.ts.map +0 -1
  568. package/dist/path-prefix.d.ts.map +0 -1
  569. package/dist/path-scope-lexical.d.ts.map +0 -1
  570. package/dist/path-segment-route.d.ts.map +0 -1
  571. package/dist/path-suffix-aliases.d.ts.map +0 -1
  572. package/dist/path.d.ts.map +0 -1
  573. package/dist/permission-exec.d.ts.map +0 -1
  574. package/dist/permissions-public.d.ts.map +0 -1
  575. package/dist/permissions-windows.d.ts.map +0 -1
  576. package/dist/permissions.d.ts.map +0 -1
  577. package/dist/pinned-mutation-admission.d.ts.map +0 -1
  578. package/dist/pinned-mutation-observation.d.ts.map +0 -1
  579. package/dist/pinned-mutation-shared-route.d.ts.map +0 -1
  580. package/dist/pinned-open.d.ts.map +0 -1
  581. package/dist/pinned-operation.d.ts.map +0 -1
  582. package/dist/pinned-write-input.d.ts.map +0 -1
  583. package/dist/pinned-write-mode.d.ts.map +0 -1
  584. package/dist/pinned-write-staged.d.ts.map +0 -1
  585. package/dist/pinned-write-types.d.ts.map +0 -1
  586. package/dist/pinned-write.d.ts.map +0 -1
  587. package/dist/positional-read.d.ts.map +0 -1
  588. package/dist/private-directory.d.ts.map +0 -1
  589. package/dist/private-producer-handoff-sync.d.ts.map +0 -1
  590. package/dist/private-producer-handoff.d.ts.map +0 -1
  591. package/dist/private-temp-workspace.d.ts.map +0 -1
  592. package/dist/publish-copy-stage.d.ts.map +0 -1
  593. package/dist/publish-file-failure.d.ts.map +0 -1
  594. package/dist/publish-file.d.ts.map +0 -1
  595. package/dist/read-open-flags.d.ts.map +0 -1
  596. package/dist/read-opened-file.d.ts.map +0 -1
  597. package/dist/realpath.d.ts.map +0 -1
  598. package/dist/recursive-mkdir-path.d.ts.map +0 -1
  599. package/dist/regular-file.d.ts.map +0 -1
  600. package/dist/replace-directory.d.ts.map +0 -1
  601. package/dist/replace-file-copy-fallback.d.ts.map +0 -1
  602. package/dist/replace-file-copy-source.d.ts.map +0 -1
  603. package/dist/replace-file-descriptor.d.ts.map +0 -1
  604. package/dist/replace-file-mode.d.ts.map +0 -1
  605. package/dist/replace-file-rename-policy.d.ts.map +0 -1
  606. package/dist/replace-file-temp-owner.d.ts.map +0 -1
  607. package/dist/replace-file.d.ts.map +0 -1
  608. package/dist/retained-directory-replacement.d.ts.map +0 -1
  609. package/dist/root-boundary.d.ts.map +0 -1
  610. package/dist/root-context.d.ts.map +0 -1
  611. package/dist/root-create-input.d.ts.map +0 -1
  612. package/dist/root-directory-creation.d.ts.map +0 -1
  613. package/dist/root-directory-list.d.ts.map +0 -1
  614. package/dist/root-directory.d.ts.map +0 -1
  615. package/dist/root-entries.d.ts.map +0 -1
  616. package/dist/root-errors.d.ts.map +0 -1
  617. package/dist/root-file-final-admission.d.ts.map +0 -1
  618. package/dist/root-file.d.ts.map +0 -1
  619. package/dist/root-impl.d.ts.map +0 -1
  620. package/dist/root-move-noreplace.d.ts.map +0 -1
  621. package/dist/root-move-preflight.d.ts.map +0 -1
  622. package/dist/root-observed-path.d.ts.map +0 -1
  623. package/dist/root-options.d.ts.map +0 -1
  624. package/dist/root-path-errors.d.ts.map +0 -1
  625. package/dist/root-path-existing.d.ts.map +0 -1
  626. package/dist/root-path-observation.d.ts.map +0 -1
  627. package/dist/root-path-stat.d.ts.map +0 -1
  628. package/dist/root-path-symlink.d.ts +0 -7
  629. package/dist/root-path-symlink.d.ts.map +0 -1
  630. package/dist/root-path-symlink.js +0 -55
  631. package/dist/root-path.d.ts.map +0 -1
  632. package/dist/root-paths-lexical.d.ts.map +0 -1
  633. package/dist/root-paths.d.ts.map +0 -1
  634. package/dist/root-read-admission.d.ts.map +0 -1
  635. package/dist/root-remove-identity.d.ts.map +0 -1
  636. package/dist/root-remove-receipt.d.ts.map +0 -1
  637. package/dist/root-remove.d.ts.map +0 -1
  638. package/dist/root-symlink-policy.d.ts.map +0 -1
  639. package/dist/root-walk.d.ts.map +0 -1
  640. package/dist/root-write-admission.d.ts.map +0 -1
  641. package/dist/root-write-compatibility.d.ts.map +0 -1
  642. package/dist/root-write-complete-parent.d.ts.map +0 -1
  643. package/dist/root-write-lock-binding.d.ts.map +0 -1
  644. package/dist/root-write-mode.d.ts.map +0 -1
  645. package/dist/root-write-publication.d.ts.map +0 -1
  646. package/dist/root-write-verification.d.ts.map +0 -1
  647. package/dist/root.d.ts.map +0 -1
  648. package/dist/safe-path-segment.d.ts.map +0 -1
  649. package/dist/secret-file.d.ts.map +0 -1
  650. package/dist/secret-read-async.d.ts.map +0 -1
  651. package/dist/secret-read-policy.d.ts.map +0 -1
  652. package/dist/secret.d.ts.map +0 -1
  653. package/dist/secure-file-windows.d.ts.map +0 -1
  654. package/dist/secure-file.d.ts.map +0 -1
  655. package/dist/secure-temp-dir.d.ts.map +0 -1
  656. package/dist/secure-temp-repair.d.ts.map +0 -1
  657. package/dist/sibling-staged-file.d.ts.map +0 -1
  658. package/dist/sibling-temp.d.ts.map +0 -1
  659. package/dist/sidecar-lock-acquire.d.ts.map +0 -1
  660. package/dist/sidecar-lock-admission-context.d.ts.map +0 -1
  661. package/dist/sidecar-lock-admission-parser.d.ts.map +0 -1
  662. package/dist/sidecar-lock-admission.d.ts.map +0 -1
  663. package/dist/sidecar-lock-handle.d.ts.map +0 -1
  664. package/dist/sidecar-lock-policy.d.ts.map +0 -1
  665. package/dist/sidecar-lock-reclaim.d.ts.map +0 -1
  666. package/dist/sidecar-lock-root.d.ts.map +0 -1
  667. package/dist/sidecar-lock-stale-admission.d.ts.map +0 -1
  668. package/dist/sidecar-lock-target.d.ts.map +0 -1
  669. package/dist/sidecar-lock-types.d.ts.map +0 -1
  670. package/dist/sidecar-lock.d.ts.map +0 -1
  671. package/dist/staged-directory.d.ts.map +0 -1
  672. package/dist/staged-file-settlement.d.ts.map +0 -1
  673. package/dist/staged-file-types.d.ts.map +0 -1
  674. package/dist/standalone-publication-path.d.ts.map +0 -1
  675. package/dist/stat-observation.d.ts.map +0 -1
  676. package/dist/store.d.ts.map +0 -1
  677. package/dist/strict-file-identity.d.ts.map +0 -1
  678. package/dist/string-coerce.d.ts.map +0 -1
  679. package/dist/suppressed-error.d.ts.map +0 -1
  680. package/dist/symlink-parents.d.ts.map +0 -1
  681. package/dist/temp-cleanup.d.ts.map +0 -1
  682. package/dist/temp-target.d.ts.map +0 -1
  683. package/dist/temp-workspace-admission.d.ts.map +0 -1
  684. package/dist/temp-workspace-child-admission.d.ts.map +0 -1
  685. package/dist/temp-workspace-descriptor.d.ts.map +0 -1
  686. package/dist/temp-workspace-identity.d.ts.map +0 -1
  687. package/dist/temp-workspace-owner.d.ts.map +0 -1
  688. package/dist/temp-workspace-permissions.d.ts.map +0 -1
  689. package/dist/temp-workspace-types.d.ts.map +0 -1
  690. package/dist/temp.d.ts.map +0 -1
  691. package/dist/test-hooks.d.ts.map +0 -1
  692. package/dist/text-atomic.d.ts.map +0 -1
  693. package/dist/timing.d.ts.map +0 -1
  694. package/dist/trash.d.ts.map +0 -1
  695. package/dist/types.d.ts.map +0 -1
  696. package/dist/unicode-path.d.ts.map +0 -1
  697. package/dist/walk.d.ts.map +0 -1
  698. package/dist/windows-command.d.ts.map +0 -1
  699. package/dist/windows-owner.d.ts.map +0 -1
  700. package/dist/windows-path-alias.d.ts.map +0 -1
  701. package/dist/windows-security-command.d.ts.map +0 -1
  702. package/dist/windows-security-facts.d.ts.map +0 -1
  703. package/dist/write-file-handle.d.ts.map +0 -1
  704. package/dist/write-open-flags.d.ts.map +0 -1
  705. package/dist/write-queue.d.ts.map +0 -1
@@ -44,4 +44,3 @@ export declare function matchRootFileOpenFailure<T>(failure: RootFileOpenFailure
44
44
  }): T;
45
45
  export declare function openRootFile(params: OpenRootFileParams): Promise<RootFileOpenResult>;
46
46
  export {};
47
- //# sourceMappingURL=root-file.d.ts.map
package/dist/root-file.js CHANGED
@@ -70,14 +70,15 @@ export function matchRootFileOpenFailure(failure, handlers) {
70
70
  return handlers.fallback(failure);
71
71
  }
72
72
  function openRootFileResolved(params) {
73
+ const rejectHardlinks = params.rejectHardlinks ?? true;
73
74
  const opened = openPinnedFileSync({
74
75
  filePath: params.absolutePath,
75
76
  resolvedPath: params.resolvedPath,
76
- rejectHardlinks: params.rejectHardlinks ?? true,
77
+ rejectHardlinks,
77
78
  maxBytes: params.maxBytes,
78
79
  allowedType: params.allowedType,
79
80
  ioFs: params.ioFs,
80
- finalAdmission: createRootFileFinalAdmission(params.ioFs, params.rootObservation, params.boundaryLabel),
81
+ finalAdmission: createRootFileFinalAdmission(params.ioFs, params.rootObservation, params.boundaryLabel, rejectHardlinks),
81
82
  });
82
83
  if (!opened.ok) {
83
84
  return opened;
@@ -62,14 +62,12 @@ export interface Root {
62
62
  walk(relativePath: string, options: RootWalkOptions): AsyncIterableIterator<RootWalkEntry>;
63
63
  }
64
64
  export declare class RootHandle implements Root {
65
- private readonly rootGuard;
66
- private readonly rootIdentity;
65
+ private readonly context;
67
66
  readonly rootDir: string;
68
67
  readonly rootReal: string;
69
68
  readonly rootWithSep: string;
70
69
  readonly defaults: RootDefaults;
71
70
  constructor(context: RootContext, defaults?: RootDefaults);
72
- private get context();
73
71
  private mutationOptions;
74
72
  resolve(relativePath: string): Promise<string>;
75
73
  open(relativePath: string, options?: RootOpenOptions): Promise<OpenResult>;
@@ -119,12 +117,6 @@ export declare function readLocalFileSafely(params: {
119
117
  export declare function openLocalFileSafely(params: {
120
118
  filePath: string;
121
119
  }): Promise<OpenResult>;
122
- export type WritableOpenResult = {
123
- handle: FileHandle;
124
- containment: ContainmentGuarantee;
120
+ export type WritableOpenResult = OpenResult & {
125
121
  createdForWrite: boolean;
126
- realPath: string;
127
- stat: Stats;
128
- [Symbol.asyncDispose](): Promise<void>;
129
122
  };
130
- //# sourceMappingURL=root-impl.d.ts.map
package/dist/root-impl.js CHANGED
@@ -73,18 +73,19 @@ import { PATH_ALIAS_POLICIES } from "./path-policy.js";
73
73
  import { assertNoNulPathInput, hasNodeErrorCode, isNotFoundPathError, isSymlinkOpenError, } from "./path.js";
74
74
  import { readOpenedFileSafely } from "./read-opened-file.js";
75
75
  import { cleanupPinnedFilePath } from "./file-cleanup.js";
76
+ import { sameFileIdentity } from "./file-identity.js";
76
77
  import { removePathIfIdentityUnchanged } from "./replace-file-temp-owner.js";
77
78
  import { realpathSync } from "./realpath.js";
78
79
  import { mkdirPathFallback, prepareRootWriteTarget, tryMkdirAtExactParent } from "./root-directory-creation.js";
79
80
  import { isNonRegularWriteOpenError, resolveNonblockingWriteFlag } from "./write-open-flags.js";
80
- import { resolveRootPath, resolveRootPathForRemoval } from "./root-path.js";
81
+ import { resolveRootPath, resolveRootPathSync, resolveRootPathForRemoval } from "./root-path.js";
81
82
  import { RemovalPathReceipts } from "./root-remove-receipt.js";
82
83
  import { admitPathInsideRoot } from "./root-boundary.js";
83
84
  import { listDirectoryPath, openRootDirectoryListing } from "./root-directory-list.js";
84
85
  import { statResolvedPathInRoot } from "./root-path-stat.js";
85
86
  import { entriesInRoot } from "./root-entries.js";
86
87
  import { assertMoveMutationAllowed } from "./root-move-preflight.js";
87
- import { assertRootIdentityCurrent, assertValidRootDestinationPath, assertValidRootRelativePath, ensureTrailingSep, expandRelativePathWithHome, resolvePathInRoot, resolveRootContext, rootRelativeReadPath, } from "./root-context.js";
88
+ import { assertRootIdentityCurrent, assertRootIdentityCurrentSync, assertValidRootDestinationPath, assertValidRootRelativePath, ensureTrailingSep, expandRelativePathWithHome, resolvePathInRoot, resolveRootContext, rootRelativeReadPath, } from "./root-context.js";
88
89
  import { fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, normalizePinnedWriteError, outsideWorkspaceError, } from "./root-errors.js";
89
90
  import { getFsSafeTestHooks } from "./test-hooks.js";
90
91
  import { stringifyJsonDocument } from "./json-stringify.js";
@@ -99,7 +100,7 @@ import { finishRootFallbackWrite } from "./root-write-publication.js";
99
100
  import { withRootFallbackCompatibilityLock } from "./root-write-compatibility.js";
100
101
  import { assertRootFallbackWritePath } from "./root-write-lock-binding.js";
101
102
  import { inspectFileIdentity, inspectFileIdentitySync } from "./strict-file-identity.js";
102
- import { movePathNoReplaceNative } from "./root-move-noreplace.js";
103
+ import { admitMoveSourceStat, movePathNoReplaceNative } from "./root-move-noreplace.js";
103
104
  import { admitRootReadHandle, inspectOpenedPathIdentitySync } from "./root-read-admission.js";
104
105
  import { createCopyPublicationObserver, onCopyPublication, onCopySourceAdmission } from "./copy-publication.js";
105
106
  import { writeAllToFile } from "./write-file-handle.js";
@@ -186,30 +187,19 @@ async function openVerifiedLocalFile(filePath, options) {
186
187
  }
187
188
  }
188
189
  export class RootHandle {
189
- rootGuard;
190
- rootIdentity;
190
+ context;
191
191
  rootDir;
192
192
  rootReal;
193
193
  rootWithSep;
194
194
  defaults;
195
195
  constructor(context, defaults = {}) {
196
- this.rootGuard = context.rootGuard;
197
- this.rootIdentity = context.rootIdentity;
196
+ this.context = context;
198
197
  this.rootDir = context.rootDir;
199
198
  this.rootReal = context.rootReal;
200
199
  this.rootWithSep = context.rootWithSep;
201
200
  this.defaults = defaults;
202
201
  registerFileLockSyncRootAdapter(this, context, defaults);
203
202
  }
204
- get context() {
205
- return {
206
- rootDir: this.rootDir,
207
- rootGuard: this.rootGuard,
208
- rootIdentity: this.rootIdentity,
209
- rootReal: this.rootReal,
210
- rootWithSep: this.rootWithSep,
211
- };
212
- }
213
203
  mutationOptions(options) {
214
204
  return {
215
205
  ...options,
@@ -224,9 +214,9 @@ export class RootHandle {
224
214
  }
225
215
  async open(relativePath, options = {}) {
226
216
  return await openFileInRoot(this.context, {
227
- relativePath,
228
217
  ...readDefaults(this.defaults),
229
218
  ...options,
219
+ relativePath,
230
220
  });
231
221
  }
232
222
  async read(relativePath, options = {}) {
@@ -246,9 +236,11 @@ export class RootHandle {
246
236
  return JSON.parse(await this.readText(relativePath, options));
247
237
  }
248
238
  async readAbsolute(filePath, options = {}) {
249
- return await readPathInRoot(this.context, {
250
- filePath,
251
- ...mergeReadOptions(this.defaults, options),
239
+ const context = this.context;
240
+ const readOptions = mergeReadOptions(this.defaults, options);
241
+ return await readFileInRoot(context, {
242
+ relativePath: rootRelativeReadPath(context, filePath),
243
+ ...readOptions,
252
244
  });
253
245
  }
254
246
  reader(options = {}) {
@@ -260,10 +252,11 @@ export class RootHandle {
260
252
  assertValidRootDestinationPath(relativePath);
261
253
  const writeMode = options.writeMode ?? "replace";
262
254
  const target = await openWritableFileInRoot(this.context, {
263
- relativePath,
264
255
  mkdir: this.defaults.mkdir,
265
256
  mode: this.defaults.mode,
266
257
  ...this.mutationOptions(options),
258
+ relativePath,
259
+ expectedWritePath: undefined,
267
260
  append: writeMode === "append",
268
261
  truncateExisting: writeMode === "replace",
269
262
  }).catch(rethrowMutationAuthorityError);
@@ -272,11 +265,11 @@ export class RootHandle {
272
265
  async append(relativePath, data, options = {}) {
273
266
  assertValidRootDestinationPath(relativePath);
274
267
  await appendFileInRoot(this.context, {
275
- relativePath,
276
- data,
277
268
  mkdir: this.defaults.mkdir,
278
269
  mode: this.defaults.mode,
279
270
  ...this.mutationOptions(options),
271
+ relativePath,
272
+ data,
280
273
  durable: options.durable ?? this.defaults.durable ?? true,
281
274
  }).catch(rethrowMutationAuthorityError);
282
275
  }
@@ -285,33 +278,34 @@ export class RootHandle {
285
278
  validateRemoveOptions(options);
286
279
  options.signal?.throwIfAborted();
287
280
  await removePathInRoot(this.context, {
288
- relativePath,
289
281
  ...this.mutationOptions(options),
282
+ relativePath,
290
283
  }).catch(rethrowMutationAuthorityError);
291
284
  }
292
285
  async mkdir(relativePath, options = {}) {
293
286
  assertValidRootDestinationPath(relativePath);
294
287
  await mkdirPathInRoot(this.context, {
295
- relativePath,
296
288
  ...this.mutationOptions(options),
289
+ relativePath,
290
+ allowRoot: false,
297
291
  }).catch(rethrowMutationAuthorityError);
298
292
  }
299
293
  async ensureRoot(options = {}) {
300
294
  await mkdirPathInRoot(this.context, {
295
+ ...this.mutationOptions(options),
301
296
  relativePath: "",
302
297
  allowRoot: true,
303
- ...this.mutationOptions(options),
304
298
  }).catch(rethrowMutationAuthorityError);
305
299
  }
306
300
  async write(relativePath, data, options = {}) {
307
301
  assertValidRootDestinationPath(relativePath);
308
302
  await writeFileInRoot(this.context, {
309
- relativePath,
310
- data,
311
303
  mkdir: this.defaults.mkdir,
312
304
  mode: this.defaults.mode,
313
305
  renameIdentity: this.defaults.renameIdentity,
314
306
  ...this.mutationOptions(options),
307
+ relativePath,
308
+ data,
315
309
  durable: options.durable ?? this.defaults.durable ?? true,
316
310
  }).catch(rethrowMutationAuthorityError);
317
311
  }
@@ -319,11 +313,11 @@ export class RootHandle {
319
313
  assertValidRootDestinationPath(relativePath);
320
314
  const durable = options.durable ?? this.defaults.durable ?? true;
321
315
  await writeFileInRoot(this.context, {
322
- relativePath,
323
- data,
324
316
  mkdir: this.defaults.mkdir,
325
317
  mode: this.defaults.mode,
326
318
  ...this.mutationOptions(createInputOptions(data, options, this.defaults.maxBytes)),
319
+ relativePath,
320
+ data,
327
321
  durable: durable !== false,
328
322
  strictFileSync: durable === "file",
329
323
  overwrite: false,
@@ -343,12 +337,13 @@ export class RootHandle {
343
337
  options.signal?.throwIfAborted();
344
338
  assertValidRootDestinationPath(relativePath);
345
339
  const { maxBytes, ...copyOptions } = this.mutationOptions(options);
340
+ const copySource = typeof source === "string" ? source : { root: source.root, relativePath: source.relativePath };
346
341
  await copyFileInRoot(this.context, {
347
- source: typeof source === "string" ? source : { root: source.root, relativePath: source.relativePath },
348
- relativePath,
349
342
  maxBytes: normalizeMaxBytes(maxBytes, { defaultValue: this.defaults.maxBytes }),
350
343
  mkdir: this.defaults.mkdir,
351
344
  ...copyOptions,
345
+ source: copySource,
346
+ relativePath,
352
347
  mode: options.mode ?? this.defaults.mode,
353
348
  durable: options.durable ?? this.defaults.durable ?? true,
354
349
  verifyPublished: options[onCopyPublication],
@@ -409,7 +404,7 @@ export class RootHandle {
409
404
  walk(relativePath, options) {
410
405
  assertValidRootRelativePath(relativePath);
411
406
  return walkRoot({
412
- rootReal: this.rootReal,
407
+ rootReal: this.context.rootReal,
413
408
  stat: relative => this.stat(relative),
414
409
  list: async (relative, listingOptions) => {
415
410
  validatePinnedOperationPayload({ relativePath: relative });
@@ -468,15 +463,6 @@ async function readFileInRoot(root, params) {
468
463
  await opened.handle.close().catch(() => { });
469
464
  }
470
465
  }
471
- async function readPathInRoot(root, params) {
472
- const relativePath = rootRelativeReadPath(root, params.filePath);
473
- return await readFileInRoot(root, {
474
- relativePath,
475
- hardlinks: params.hardlinks,
476
- maxBytes: params.maxBytes,
477
- symlinks: params.symlinks,
478
- });
479
- }
480
466
  export async function readLocalFileSafely(params) {
481
467
  const maxBytes = normalizeMaxBytes(params.maxBytes);
482
468
  const opened = await openLocalFileSafely({ filePath: params.filePath });
@@ -502,7 +488,7 @@ function buildAtomicWriteTempPath(targetPath) {
502
488
  function rootWriteQueueKey(root, relativePath) {
503
489
  return `${root.rootReal}\0${relativePath}`;
504
490
  }
505
- async function openWritableFileInRoot(root, params) {
491
+ async function openWritableFileInRoot(root, params, options) {
506
492
  const guardedTarget = params.denyMutations === undefined && params.mutationSymlinks === undefined
507
493
  ? undefined
508
494
  : await resolveGuardedWriteTargetInRoot(root, {
@@ -566,6 +552,17 @@ async function openWritableFileInRoot(root, params) {
566
552
  if (!isNotFoundPathError(err)) {
567
553
  throw err;
568
554
  }
555
+ if (options?.createIfMissing === false) {
556
+ const parentGuard = writePathSelection?.parentGuard ??
557
+ await createAsyncDirectoryGuard(path.dirname(ioPath), { bigint: true });
558
+ assertRootIdentityCurrentSync(root);
559
+ if (!admitPathInsideRoot({
560
+ rootPath: root.rootReal, candidatePath: parentGuard.realPath, rootIdentity: root.rootIdentity,
561
+ }))
562
+ throw outsideWorkspaceError();
563
+ assertSyncDirectoryGuard(parentGuard);
564
+ return { missing: true, targetPath: ioPath, parentGuard, writeSelection: writePathSelection };
565
+ }
569
566
  if (writePathSelection)
570
567
  await refreshRootWritePathSelection(writePathSelection);
571
568
  params.assertBeforeMutation?.();
@@ -723,8 +720,9 @@ async function appendFileInRoot(root, params) {
723
720
  if (params.prependNewlineIfNeeded === true &&
724
721
  !target.createdForWrite &&
725
722
  target.stat.size > 0 &&
723
+ params.data.length > 0 &&
726
724
  ((typeof params.data === "string" && !params.data.startsWith("\n")) ||
727
- (Buffer.isBuffer(params.data) && params.data.length > 0 && params.data[0] !== 0x0a))) {
725
+ (Buffer.isBuffer(params.data) && params.data[0] !== 0x0a))) {
728
726
  const newline = Buffer.from("\n", typeof params.data === "string" ? params.encoding : "utf8");
729
727
  const tail = Buffer.alloc(newline.length);
730
728
  const { bytesRead } = await target.handle.read(tail, 0, tail.length, Math.max(0, target.stat.size - tail.length));
@@ -789,16 +787,11 @@ async function mkdirPathInRoot(root, params) {
789
787
  const policy = params.denyMutations === undefined && params.mutationSymlinks === undefined
790
788
  ? undefined
791
789
  : snapshotPinnedMutationPolicy(params.denyMutations, params.mutationSymlinks);
790
+ const resolution = { relativePath: params.relativePath, allowRoot: params.allowRoot, ...policy };
792
791
  const resolveCurrent = policy
793
- ? async () => await resolvePinnedPathInRoot(root, {
794
- ...params,
795
- denyMutations: policy.denyMutations,
796
- mutationSymlinks: policy.mutationSymlinks,
797
- })
792
+ ? async () => await resolvePinnedPathInRoot(root, resolution)
798
793
  : undefined;
799
- const resolved = resolveCurrent
800
- ? await resolveCurrent()
801
- : await resolvePinnedPathInRoot(root, params);
794
+ const resolved = await resolvePinnedPathInRoot(root, resolution);
802
795
  const prepared = policy && resolved.relativePosix !== ""
803
796
  ? await preparePinnedWriteMutationAdmission({
804
797
  rootReal: resolved.rootReal,
@@ -994,20 +987,9 @@ async function copyFileInRoot(root, params) {
994
987
  }
995
988
  }
996
989
  async function resolvePinnedPathInRoot(root, params) {
997
- return await resolvePinnedOperationPathInRoot(root, {
998
- allowRoot: params.allowRoot,
999
- denyMutations: params.denyMutations,
1000
- mutationSymlinks: params.mutationSymlinks,
1001
- protectDenyMutationAncestors: params.remove === true,
1002
- relativePath: params.relativePath,
1003
- policy: params.remove ? PATH_ALIAS_POLICIES.unlinkTarget : PATH_ALIAS_POLICIES.strict,
1004
- removalReceipts: params.removalReceipts,
1005
- });
1006
- }
1007
- async function resolvePinnedOperationPathInRoot(root, params) {
1008
990
  const resolved = await resolvePinnedRootPathInRoot(root, {
1009
991
  relativePath: params.relativePath,
1010
- policy: params.policy,
992
+ policy: params.remove ? PATH_ALIAS_POLICIES.unlinkTarget : PATH_ALIAS_POLICIES.strict,
1011
993
  mutationSymlinks: params.mutationSymlinks,
1012
994
  removalReceipts: params.removalReceipts,
1013
995
  });
@@ -1034,7 +1016,7 @@ async function resolvePinnedOperationPathInRoot(root, params) {
1034
1016
  }
1035
1017
  resolved.canonicalPath = admittedCanonicalPath.path;
1036
1018
  await assertMutationNotDenied(resolved.canonicalPath, params.denyMutations, {
1037
- protectAncestors: params.protectDenyMutationAncestors,
1019
+ protectAncestors: params.remove === true,
1038
1020
  });
1039
1021
  return { rootReal: resolved.rootReal, resolved: resolved.canonicalPath, relativePosix };
1040
1022
  }
@@ -1085,6 +1067,8 @@ async function listPathFallback(root, relativePath, withFileTypes) {
1085
1067
  return await listDirectoryPath(root, resolved.resolved, withFileTypes, resolved.receipt);
1086
1068
  }
1087
1069
  async function movePathFallback(root, params) {
1070
+ const originalRoutes = params.overwrite && params.assertBeforeMutation
1071
+ ? await Promise.all([params.fromRelative, params.toRelative].map(expandRelativePathWithHome)) : undefined;
1088
1072
  const source = await resolvePathInRoot(root, params.fromRelative, {
1089
1073
  aliasErrorCode: "path-alias",
1090
1074
  allowFinalSymlink: true,
@@ -1120,9 +1104,14 @@ async function movePathFallback(root, params) {
1120
1104
  targetStat?.isSymbolicLink() === true);
1121
1105
  },
1122
1106
  });
1123
- let sourceStat;
1107
+ let sourceIdentity;
1124
1108
  try {
1125
- sourceStat = fsSync.lstatSync(source.resolved);
1109
+ if (params.overwrite && params.assertBeforeMutation) {
1110
+ sourceIdentity = inspectFileIdentitySync(() => admitMoveSourceStat(fsSync.lstatSync(source.resolved, { bigint: true }), true));
1111
+ }
1112
+ else {
1113
+ admitMoveSourceStat(fsSync.lstatSync(source.resolved), params.overwrite);
1114
+ }
1126
1115
  }
1127
1116
  catch (error) {
1128
1117
  if (isNotFoundPathError(error)) {
@@ -1130,19 +1119,10 @@ async function movePathFallback(root, params) {
1130
1119
  }
1131
1120
  throw error;
1132
1121
  }
1133
- if (sourceStat.isSymbolicLink()) {
1134
- throw new FsSafeError("symlink", "symlink not allowed");
1135
- }
1136
- if (sourceStat.isFile() && sourceStat.nlink > 1) {
1137
- throw hardlinkedPathNotAllowedError();
1138
- }
1139
- if (!params.overwrite && sourceStat.isDirectory()) {
1140
- throw new FsSafeError("invalid-path", "directory moves require overwrite: true");
1122
+ if (!pinnedTarget) {
1123
+ throw new FsSafeError("path-mismatch", "destination admission was not completed");
1141
1124
  }
1142
1125
  if (!params.overwrite) {
1143
- if (!pinnedTarget) {
1144
- throw new FsSafeError("path-mismatch", "destination admission was not completed");
1145
- }
1146
1126
  await movePathNoReplaceNative(root, params, {
1147
1127
  sourcePath: source.resolved,
1148
1128
  sourceParentPath: path.dirname(pinnedSource.canonicalPath),
@@ -1151,8 +1131,9 @@ async function movePathFallback(root, params) {
1151
1131
  });
1152
1132
  return;
1153
1133
  }
1154
- const sourceParentGuard = await createAsyncDirectoryGuard(path.dirname(source.resolved));
1155
- const targetParentGuard = await createNearestExistingDirectoryGuard(target.rootReal, path.dirname(target.resolved));
1134
+ const guardOptions = { bigint: sourceIdentity !== undefined };
1135
+ const sourceParentGuard = await createAsyncDirectoryGuard(path.dirname(source.resolved), guardOptions);
1136
+ const targetParentGuard = await createNearestExistingDirectoryGuard(target.rootReal, path.dirname(target.resolved), guardOptions);
1156
1137
  await getFsSafeTestHooks()?.beforeRootFallbackMutation?.("move", target.resolved);
1157
1138
  await assertAsyncDirectoryGuard(sourceParentGuard);
1158
1139
  await assertAsyncDirectoryGuard(targetParentGuard);
@@ -1160,6 +1141,31 @@ async function movePathFallback(root, params) {
1160
1141
  assertFinalSymlinkRejected(source.resolved, params.mutationSymlinks !== undefined);
1161
1142
  assertFinalSymlinkRejected(target.resolved, params.mutationSymlinks !== undefined);
1162
1143
  params.assertBeforeMutation?.();
1144
+ if (sourceIdentity) {
1145
+ assertRootIdentityCurrentSync(root);
1146
+ assertSyncDirectoryGuard(sourceParentGuard);
1147
+ assertSyncDirectoryGuard(targetParentGuard);
1148
+ for (const [route, selected, expected, policy] of [
1149
+ [originalRoutes[0], source.resolved, pinnedSource.canonicalPath, PATH_ALIAS_POLICIES.strict],
1150
+ [originalRoutes[1], target.resolved, pinnedTarget.canonicalPath, PATH_ALIAS_POLICIES.unlinkTarget],
1151
+ ]) {
1152
+ for (const absolutePath of new Set([path.isAbsolute(route) ? route : `${root.rootWithSep}${route}`, selected])) {
1153
+ try {
1154
+ const current = resolveRootPathSync({
1155
+ absolutePath, rootPath: root.rootReal, rootCanonicalPath: root.rootReal,
1156
+ rootIdentity: root.rootIdentity, boundaryLabel: "root", policy,
1157
+ ...mutationSymlinkResolution(params.mutationSymlinks),
1158
+ });
1159
+ if (current.canonicalPath !== expected)
1160
+ throw new FsSafeError("path-mismatch", "move route changed during authorization");
1161
+ }
1162
+ catch (error) {
1163
+ throw normalizePinnedPathError(error);
1164
+ }
1165
+ }
1166
+ }
1167
+ inspectFileIdentitySync(() => admitMoveSourceStat(fsSync.lstatSync(source.resolved, { bigint: true }), true), sourceIdentity);
1168
+ }
1163
1169
  await fs.rename(source.resolved, target.resolved);
1164
1170
  }
1165
1171
  catch (error) {
@@ -1197,48 +1203,59 @@ async function writeFileFallbackUnlocked(root, params, expectedWritePath) {
1197
1203
  await writeMissingFileFallback(root, params, expectedWritePath);
1198
1204
  return;
1199
1205
  }
1200
- const { opened: target, identity: targetIdentity, writeSelection: retainedSelection } = await openWritableFileInRoot(root, {
1206
+ const admissionParams = {
1201
1207
  relativePath: params.relativePath,
1202
1208
  mkdir: params.mkdir,
1203
- // Private, writable placeholder: Windows cannot rename over a read-only file.
1204
- mode: 0o600,
1205
1209
  denyMutations: params.denyMutations,
1206
1210
  assertBeforeMutation: params.assertBeforeMutation,
1207
1211
  mutationSymlinks: params.mutationSymlinks,
1208
1212
  truncateExisting: false,
1209
1213
  expectedWritePath,
1210
- });
1214
+ };
1215
+ const admission = await openWritableFileInRoot(root, admissionParams, { createIfMissing: false });
1216
+ const existing = "missing" in admission ? undefined : admission;
1217
+ const target = existing?.opened;
1218
+ const retainedSelection = existing?.writeSelection;
1219
+ const missingSelection = "missing" in admission ? admission.writeSelection : undefined;
1211
1220
  const policyEnabled = params.denyMutations !== undefined || params.mutationSymlinks !== undefined;
1212
- const destinationPath = retainedSelection?.selectedPath ?? target.realPath;
1213
- const mode = params.mode ?? (target.stat.mode & 0o777);
1214
- if (policyEnabled && !retainedSelection) {
1215
- await target.handle.close().catch(() => undefined);
1221
+ const destinationPath = "missing" in admission ? admission.targetPath
1222
+ : retainedSelection?.selectedPath ?? admission.opened.realPath;
1223
+ let mode = params.mode ?? (target ? target.stat.mode & 0o777 : undefined);
1224
+ if (policyEnabled && !retainedSelection && !missingSelection) {
1225
+ await target?.handle.close().catch(() => undefined);
1216
1226
  throw new FsSafeError("path-mismatch", "write admission state was not retained");
1217
1227
  }
1218
- const destinationGuard = retainedSelection?.parentGuard ??
1228
+ const destinationGuard = "missing" in admission ? admission.parentGuard : retainedSelection?.parentGuard ??
1219
1229
  await createAsyncDirectoryGuard(path.dirname(destinationPath), { bigint: true }).catch(async (error) => {
1220
- await target.handle.close().catch(() => undefined);
1230
+ await target?.handle.close().catch(() => undefined);
1221
1231
  throw error;
1222
1232
  });
1223
1233
  let tempPath = null;
1224
1234
  let unregisterTempPath = null;
1225
1235
  let writtenHandle;
1226
1236
  let writtenIdentity;
1227
- let placeholderIdentity;
1228
- let published = false;
1237
+ let lateTargetHandle;
1229
1238
  try {
1230
- if (target.createdForWrite)
1231
- placeholderIdentity = targetIdentity;
1232
1239
  tempPath = buildAtomicWriteTempPath(destinationPath);
1233
1240
  if (retainedSelection) {
1234
- await refreshRetainedRootWriteAdmission(root, retainedSelection, true, target.handle.fd);
1241
+ await refreshRetainedRootWriteAdmission(root, retainedSelection, true, target?.handle.fd);
1242
+ }
1243
+ else if (missingSelection) {
1244
+ await refreshRootWritePathSelection(missingSelection);
1235
1245
  }
1236
1246
  params.assertBeforeMutation?.();
1237
1247
  if (retainedSelection) {
1238
- assertRootWriteSelectionSync(root, retainedSelection, true, target.handle.fd);
1248
+ assertRootWriteSelectionSync(root, retainedSelection, true, target?.handle.fd);
1249
+ }
1250
+ else if (missingSelection) {
1251
+ assertRootWritePathSelectionSync(root, missingSelection);
1239
1252
  }
1253
+ assertRootIdentityCurrentSync(root);
1254
+ assertSyncDirectoryGuard(destinationGuard);
1240
1255
  writtenHandle = await fs.open(tempPath, OPEN_WRITE_CREATE_FLAGS, 0o600);
1241
1256
  writtenIdentity = fsSync.fstatSync(writtenHandle.fd, { bigint: true });
1257
+ // Preserve the creation mask when no existing destination supplies a mode.
1258
+ mode ??= Number(writtenIdentity.mode & 511n);
1242
1259
  unregisterTempPath = registerTempPathForExit(tempPath, { identity: writtenIdentity, singleLinkFile: true });
1243
1260
  await writeAllToFile(writtenHandle, params.data, {
1244
1261
  encoding: params.encoding, assertBeforeMutation: params.assertBeforeMutation,
@@ -1253,24 +1270,42 @@ async function writeFileFallbackUnlocked(root, params, expectedWritePath) {
1253
1270
  root, targetPath: commitTempPath, fd: commitHandle.fd,
1254
1271
  expectedIdentity: commitIdentity, parentGuard: destinationGuard,
1255
1272
  });
1256
- if (target.createdForWrite) {
1257
- await cleanupPinnedFilePath({
1258
- pathname: destinationPath, handle: target.handle, identity: placeholderIdentity, parentGuard: destinationGuard,
1259
- });
1273
+ assertRootIdentityCurrentSync(root);
1274
+ assertSyncDirectoryGuard(destinationGuard);
1275
+ let publicationIdentity = inspectFallbackReplacementDestination(destinationPath);
1276
+ // A raced file needs its own access admission, not the old handle's rights.
1277
+ if (publicationIdentity && (!existing || !sameFileIdentity(publicationIdentity, existing.identity))) {
1278
+ const admitted = await openWritableFileInRoot(root, {
1279
+ ...admissionParams, mkdir: false, expectedWritePath: destinationPath,
1280
+ }, { createIfMissing: false });
1281
+ lateTargetHandle = "missing" in admitted ? undefined : admitted.opened.handle;
1282
+ publicationIdentity = "missing" in admitted ? undefined : admitted.identity;
1283
+ await lateTargetHandle?.close();
1260
1284
  }
1261
1285
  // Windows cannot replace a destination while its old handle remains open.
1262
- await target.handle.close();
1286
+ await target?.handle.close();
1263
1287
  if (retainedSelection) {
1264
- await refreshRetainedRootWriteAdmission(root, retainedSelection, !target.createdForWrite);
1288
+ await refreshRetainedRootWriteAdmission(root, retainedSelection, true);
1289
+ }
1290
+ else if (missingSelection) {
1291
+ await refreshRootWritePathSelection(missingSelection);
1265
1292
  }
1266
1293
  assertFinalSymlinkRejected(destinationPath, params.mutationSymlinks !== undefined);
1267
1294
  params.assertBeforeMutation?.();
1268
1295
  if (retainedSelection) {
1269
- assertRootWriteSelectionSync(root, retainedSelection, !target.createdForWrite);
1296
+ assertRootWriteSelectionSync(root, retainedSelection, true);
1297
+ }
1298
+ else if (missingSelection) {
1299
+ assertRootWritePathSelectionSync(root, missingSelection);
1300
+ }
1301
+ assertRootIdentityCurrentSync(root);
1302
+ assertSyncDirectoryGuard(destinationGuard);
1303
+ const current = inspectFallbackReplacementDestination(destinationPath);
1304
+ if (publicationIdentity ? !current || !sameFileIdentity(current, publicationIdentity) : current) {
1305
+ throw new FsSafeError("path-mismatch", "write destination changed before publication");
1270
1306
  }
1271
1307
  await fs.rename(commitTempPath, destinationPath);
1272
1308
  tempPath = null;
1273
- published = true;
1274
1309
  });
1275
1310
  unregisterTempPath();
1276
1311
  unregisterTempPath = null;
@@ -1283,12 +1318,8 @@ async function writeFileFallbackUnlocked(root, params, expectedWritePath) {
1283
1318
  });
1284
1319
  }
1285
1320
  finally {
1286
- if (!published && target.createdForWrite) {
1287
- await cleanupPinnedFilePath({
1288
- pathname: destinationPath, handle: target.handle, identity: placeholderIdentity, parentGuard: destinationGuard,
1289
- });
1290
- }
1291
- await target.handle.close().catch(() => undefined);
1321
+ await target?.handle.close().catch(() => undefined);
1322
+ await lateTargetHandle?.close().catch(() => undefined);
1292
1323
  if (tempPath && writtenHandle) {
1293
1324
  await cleanupPinnedFilePath({
1294
1325
  pathname: tempPath, handle: writtenHandle, identity: writtenIdentity, parentGuard: destinationGuard,
@@ -1298,6 +1329,23 @@ async function writeFileFallbackUnlocked(root, params, expectedWritePath) {
1298
1329
  unregisterTempPath?.();
1299
1330
  }
1300
1331
  }
1332
+ function inspectFallbackReplacementDestination(targetPath) {
1333
+ let current;
1334
+ try {
1335
+ current = inspectFileIdentitySync(() => fsSync.lstatSync(targetPath, { bigint: true }));
1336
+ }
1337
+ catch (error) {
1338
+ if (isNotFoundPathError(error))
1339
+ return;
1340
+ throw error;
1341
+ }
1342
+ if (current.isSymbolicLink() || !current.isFile()) {
1343
+ throw new FsSafeError("path-mismatch", "write destination changed before publication");
1344
+ }
1345
+ if (current.nlink > 1n)
1346
+ throw hardlinkedPathNotAllowedError();
1347
+ return current;
1348
+ }
1301
1349
  async function writeMissingFileFallback(root, params, expectedWritePath) {
1302
1350
  const guardedTarget = params.denyMutations === undefined && params.mutationSymlinks === undefined
1303
1351
  ? undefined
@@ -1324,6 +1372,7 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
1324
1372
  const parentGuard = pathSelection?.parentGuard ??
1325
1373
  await createAsyncDirectoryGuard(path.dirname(targetPath), { bigint: true });
1326
1374
  let created = false;
1375
+ let completed = false;
1327
1376
  let createdIdentity;
1328
1377
  let writtenHandle;
1329
1378
  let verifyingPublication = false;
@@ -1367,6 +1416,7 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
1367
1416
  });
1368
1417
  if (params.durable !== false)
1369
1418
  await syncDirectoryBestEffort(path.dirname(targetPath));
1419
+ completed = true;
1370
1420
  }
1371
1421
  catch (err) {
1372
1422
  if (verifyingPublication)
@@ -1384,6 +1434,9 @@ async function writeMissingFileFallback(root, params, expectedWritePath) {
1384
1434
  pathname: targetPath, handle: writtenHandle, identity: createdIdentity, parentGuard,
1385
1435
  });
1386
1436
  }
1387
- await writtenHandle?.close().catch(() => undefined);
1437
+ if (completed)
1438
+ await writtenHandle?.close();
1439
+ else
1440
+ await writtenHandle?.close().catch(() => undefined);
1388
1441
  }
1389
1442
  }
@@ -1,6 +1,8 @@
1
+ import { type BigIntStats, type Stats } from "node:fs";
1
2
  import { type DenyMutationPolicy } from "./deny-mutations.js";
2
3
  import { type RootContext } from "./root-context.js";
3
4
  import { type MutationSymlinkPolicy } from "./root-symlink-policy.js";
5
+ export declare function admitMoveSourceStat<T extends Stats | BigIntStats>(stat: T, overwrite?: boolean): T;
4
6
  export declare function movePathNoReplaceNative(root: RootContext, params: {
5
7
  assertBeforeMutation?: () => void;
6
8
  denyMutations?: DenyMutationPolicy;
@@ -11,4 +13,3 @@ export declare function movePathNoReplaceNative(root: RootContext, params: {
11
13
  targetPath: string;
12
14
  targetParentPath: string;
13
15
  }): Promise<void>;
14
- //# sourceMappingURL=root-move-noreplace.d.ts.map
@@ -58,14 +58,14 @@ function normalizeRenameNoReplaceError(error) {
58
58
  }
59
59
  return normalizeMoveError(error);
60
60
  }
61
- function admitMoveSourceStat(stat) {
61
+ export function admitMoveSourceStat(stat, overwrite = false) {
62
62
  if (stat.isSymbolicLink()) {
63
63
  throw new FsSafeError("symlink", "symlink not allowed");
64
64
  }
65
65
  if (stat.isFile() && stat.nlink > 1) {
66
66
  throw hardlinkedPathNotAllowedError();
67
67
  }
68
- if (stat.isDirectory()) {
68
+ if (!overwrite && stat.isDirectory()) {
69
69
  throw new FsSafeError("invalid-path", "directory moves require overwrite: true");
70
70
  }
71
71
  return stat;