@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
@@ -1,43 +1,9 @@
1
1
  import path from "node:path";
2
2
  import { FsSafeError } from "./errors.js";
3
- const COLON = 0x3a;
4
- const FORWARD_SLASH = 0x2f;
5
- const BACKSLASH = 0x5c;
6
- const DOT = 0x2e;
7
- const QUESTION_MARK = 0x3f;
8
- function isAsciiLetter(code) {
9
- return (code >= 0x41 && code <= 0x5a) || (code >= 0x61 && code <= 0x7a);
10
- }
11
- function isSeparator(code) {
12
- return code === FORWARD_SLASH || code === BACKSLASH;
13
- }
14
- function rootedDriveColonIndex(value) {
15
- if (value.length >= 3 &&
16
- isAsciiLetter(value.charCodeAt(0)) &&
17
- value.charCodeAt(1) === COLON &&
18
- isSeparator(value.charCodeAt(2))) {
19
- return 1;
20
- }
21
- if (value.length >= 7 &&
22
- isSeparator(value.charCodeAt(0)) &&
23
- isSeparator(value.charCodeAt(1)) &&
24
- (value.charCodeAt(2) === QUESTION_MARK || value.charCodeAt(2) === DOT) &&
25
- isSeparator(value.charCodeAt(3)) &&
26
- isAsciiLetter(value.charCodeAt(4)) &&
27
- value.charCodeAt(5) === COLON &&
28
- isSeparator(value.charCodeAt(6))) {
29
- return 5;
30
- }
31
- return -1;
32
- }
3
+ import { hasWindowsDrivePrefix, rootedWindowsDriveColonIndex, windowsNamespaceMarker, } from "./windows-path-syntax.js";
33
4
  function isBareWindowsNamespaceDrive(value) {
34
- return (value.length === 6 &&
35
- isSeparator(value.charCodeAt(0)) &&
36
- isSeparator(value.charCodeAt(1)) &&
37
- (value.charCodeAt(2) === QUESTION_MARK || value.charCodeAt(2) === DOT) &&
38
- isSeparator(value.charCodeAt(3)) &&
39
- isAsciiLetter(value.charCodeAt(4)) &&
40
- value.charCodeAt(5) === COLON);
5
+ return value.length === 6 && windowsNamespaceMarker(value) !== undefined &&
6
+ hasWindowsDrivePrefix(value, 4);
41
7
  }
42
8
  /**
43
9
  * Capture an ordinary Windows drive-relative path without normalizing its raw
@@ -47,9 +13,7 @@ function isBareWindowsNamespaceDrive(value) {
47
13
  export function anchorWindowsDriveRelativePath(value) {
48
14
  if (process.platform !== "win32" || path.isAbsolute(value))
49
15
  return value;
50
- if (value.length < 2 ||
51
- !isAsciiLetter(value.charCodeAt(0)) ||
52
- value.charCodeAt(1) !== COLON) {
16
+ if (!hasWindowsDrivePrefix(value)) {
53
17
  return value;
54
18
  }
55
19
  const drive = value.slice(0, 2);
@@ -64,7 +28,7 @@ export function anchorWindowsDriveRelativePath(value) {
64
28
  export function resolvePathPreservingWindowsRoot(value) {
65
29
  if (value.length === 7 &&
66
30
  process.platform === "win32" &&
67
- rootedDriveColonIndex(value) === 5) {
31
+ rootedWindowsDriveColonIndex(value) === 5) {
68
32
  return value.includes("/") ? value.replaceAll("/", "\\") : value;
69
33
  }
70
34
  const resolved = path.resolve(value);
@@ -110,7 +74,7 @@ export function resolvePathFromBasePreservingWindowsRoot(base, ...segments) {
110
74
  */
111
75
  export function pathForWindowsFilesystem(value) {
112
76
  if (process.platform !== "win32" ||
113
- rootedDriveColonIndex(value) !== 5) {
77
+ rootedWindowsDriveColonIndex(value) !== 5) {
114
78
  return value;
115
79
  }
116
80
  if (value.length === 7) {
@@ -132,7 +96,7 @@ export function hasWindowsPathAlias(value, kind, platform = process.platform) {
132
96
  return false;
133
97
  if (kind === "relative")
134
98
  return true;
135
- return firstColon !== rootedDriveColonIndex(value) || value.indexOf(":", firstColon + 1) !== -1;
99
+ return firstColon !== rootedWindowsDriveColonIndex(value) || value.indexOf(":", firstColon + 1) !== -1;
136
100
  }
137
101
  export function assertNoWindowsPathAliasForPlatform(value, kind, message, platform) {
138
102
  if (hasWindowsPathAlias(value, kind, platform)) {
@@ -0,0 +1,5 @@
1
+ export declare function isWindowsSeparator(value: string, offset: number): boolean;
2
+ export declare function hasWindowsDrivePrefix(value: string, offset?: number): boolean;
3
+ /** Classify a raw prefix without normalizing any path components. */
4
+ export declare function windowsNamespaceMarker(value: string): "." | "?" | undefined;
5
+ export declare function rootedWindowsDriveColonIndex(value: string): number;
@@ -0,0 +1,21 @@
1
+ export function isWindowsSeparator(value, offset) {
2
+ const code = value.charCodeAt(offset);
3
+ return code === 0x2f || code === 0x5c;
4
+ }
5
+ export function hasWindowsDrivePrefix(value, offset = 0) {
6
+ const letter = value.charCodeAt(offset) | 0x20;
7
+ return letter >= 0x61 && letter <= 0x7a && value.charCodeAt(offset + 1) === 0x3a;
8
+ }
9
+ /** Classify a raw prefix without normalizing any path components. */
10
+ export function windowsNamespaceMarker(value) {
11
+ const marker = value[2];
12
+ return (marker === "." || marker === "?") &&
13
+ isWindowsSeparator(value, 0) && isWindowsSeparator(value, 1) &&
14
+ isWindowsSeparator(value, 3) ? marker : undefined;
15
+ }
16
+ export function rootedWindowsDriveColonIndex(value) {
17
+ const colon = hasWindowsDrivePrefix(value)
18
+ ? 1
19
+ : windowsNamespaceMarker(value) !== undefined && hasWindowsDrivePrefix(value, 4) ? 5 : -1;
20
+ return colon >= 0 && isWindowsSeparator(value, colon + 1) ? colon : -1;
21
+ }
@@ -23,4 +23,3 @@ export declare function protectPrivateWindowsFileCommand(fd: number, targetPath:
23
23
  }>;
24
24
  export declare function verifyPrivateWindowsFileCommandSync(fd: number, targetPath: string, expectedFileIdentity: string, expectedParentIdentity: string, expectedLinks?: number): void;
25
25
  export declare function verifyPrivateWindowsFileCommand(fd: number, targetPath: string, expectedFileIdentity: string, expectedParentIdentity: string, expectedLinks?: number): Promise<void>;
26
- //# sourceMappingURL=windows-security-command.d.ts.map
@@ -3,4 +3,3 @@ import type { NativeWindowsSecurityFacts } from "./native-binding.js";
3
3
  export declare function parseWindowsSecurityCommandFacts(value: unknown): NativeWindowsSecurityFacts;
4
4
  /** Native and command observations share the same fail-closed admission policy. */
5
5
  export declare function validateSecureWindowsSecurityFacts(value: unknown): NativeWindowsSecurityFacts;
6
- //# sourceMappingURL=windows-security-facts.d.ts.map
@@ -1,7 +1,13 @@
1
1
  import type { FileHandle } from "node:fs/promises";
2
+ export type WriteFileWindowOptions = {
3
+ signal?: AbortSignal;
4
+ /** Synchronous authority check immediately before every write, including short-write retries. */
5
+ assertBeforeMutation?: () => void;
6
+ };
7
+ /** Write borrowed bytes completely; null advances the cursor, an explicit position preserves it. */
8
+ export declare function writeFileWindowFully(handle: FileHandle, bytes: Uint8Array, position: number | null, options?: WriteFileWindowOptions): Promise<void>;
2
9
  export declare function writeAllToFile(target: FileHandle | number, data: string | Uint8Array, options?: {
3
10
  encoding?: BufferEncoding;
4
11
  position?: number;
5
12
  assertBeforeMutation?: () => void;
6
13
  }): Promise<void>;
7
- //# sourceMappingURL=write-file-handle.d.ts.map
@@ -1,6 +1,29 @@
1
1
  import fs from "node:fs";
2
+ import { snapshotByteView } from "./byte-view.js";
2
3
  import { FsSafeError } from "./errors.js";
4
+ import { assertSynchronousCallbackResult } from "./mutation-authority.js";
3
5
  const WRITE_CHUNK_BYTES = 512 * 1024;
6
+ /** Write borrowed bytes completely; null advances the cursor, an explicit position preserves it. */
7
+ export async function writeFileWindowFully(handle, bytes, position, options = {}) {
8
+ const payload = snapshotByteView(bytes);
9
+ if (position !== null && (!Number.isSafeInteger(position) || position < 0 ||
10
+ !Number.isSafeInteger(position + payload.byteLength))) {
11
+ throw new RangeError("write position and window end must be non-negative safe integers");
12
+ }
13
+ const signal = options.signal;
14
+ const assertion = options.assertBeforeMutation;
15
+ signal?.throwIfAborted();
16
+ await writeAllToFile(handle, payload, {
17
+ position: position === null ? undefined : position,
18
+ assertBeforeMutation: () => {
19
+ signal?.throwIfAborted();
20
+ assertSynchronousCallbackResult(assertion === undefined ? undefined : Reflect.apply(assertion, options, []), "assertBeforeMutation");
21
+ signal?.throwIfAborted();
22
+ },
23
+ });
24
+ // A pending write must settle before cancellation releases the caller's buffer and handle.
25
+ signal?.throwIfAborted();
26
+ }
4
27
  export async function writeAllToFile(target, data, options = {}) {
5
28
  const buffer = typeof data === "string" ? Buffer.from(data, options.encoding ?? "utf8") : data;
6
29
  let offset = 0;
@@ -2,4 +2,3 @@ import fsSync from "node:fs";
2
2
  export declare function resolveNonblockingWriteFlag(constants?: Partial<Pick<typeof fsSync.constants, "O_NONBLOCK">>): number;
3
3
  export declare function isNonRegularWriteOpenError(error: unknown, filePath: string, flags: number): Promise<boolean>;
4
4
  export declare function isNonRegularWriteOpenErrorSync(error: unknown, filePath: string, flags: number): boolean;
5
- //# sourceMappingURL=write-open-flags.d.ts.map
@@ -13,14 +13,7 @@ function isNonblockingWriteEnxio(error, flags) {
13
13
  // A no-reader FIFO rejects a nonblocking write-only open before fstat is possible.
14
14
  // Reclassify only a confirmed non-regular path; inconclusive races keep the errno.
15
15
  export async function isNonRegularWriteOpenError(error, filePath, flags) {
16
- if (!isNonblockingWriteEnxio(error, flags))
17
- return false;
18
- try {
19
- return !fsSync.lstatSync(filePath).isFile();
20
- }
21
- catch {
22
- return false;
23
- }
16
+ return isNonRegularWriteOpenErrorSync(error, filePath, flags);
24
17
  }
25
18
  export function isNonRegularWriteOpenErrorSync(error, filePath, flags) {
26
19
  if (!isNonblockingWriteEnxio(error, flags))
@@ -1,2 +1 @@
1
1
  export declare function serializePathWrite<T>(key: string, run: () => Promise<T>): Promise<T>;
2
- //# sourceMappingURL=write-queue.d.ts.map
@@ -1,10 +1,7 @@
1
1
  const writeQueues = new Map();
2
2
  export async function serializePathWrite(key, run) {
3
3
  const previous = writeQueues.get(key) ?? Promise.resolve();
4
- const task = (async () => {
5
- await previous.catch(() => undefined);
6
- return await run();
7
- })();
4
+ const task = previous.then(() => run());
8
5
  const done = task.then(() => undefined, () => undefined);
9
6
  writeQueues.set(key, done);
10
7
  try {
package/docs/advanced.md CHANGED
@@ -19,7 +19,7 @@ import {
19
19
 
20
20
  ## What lives here
21
21
 
22
- The exports group into a handful of themes. Each documented helper has its own page; everything else is reference-only and tracked here.
22
+ The exports group into a handful of themes. Documented helpers link to their contract below or a dedicated page; everything else is reference-only and tracked here.
23
23
 
24
24
  ### Path scopes and root paths
25
25
 
@@ -71,7 +71,9 @@ Operational filesystem failures such as permissions or I/O errors are rethrown.
71
71
  | `readFileDescriptorBounded`, `readFileDescriptorBoundedSync`, `readFileHandleBounded` | – | Incremental whole-file reads for already-open descriptors/handles. They consume at most `maxBytes + 1`, do not close the input, and throw `FsSafeError("too-large")` on overflow. |
72
72
  | `createDirectory`, `createDirectorySync`, `createFileSync` | [Exclusive leaf creation](creation.md) | Create one exclusive entry under an existing trusted parent, optionally with private permissions; file creation returns an owned disposable descriptor. |
73
73
  | `readFileWindowFully`, `readFileWindowFullySync`, `ReadFileWindowOptions` | [positional-read.md](positional-read.md) | Fill a caller-owned buffer at an explicit file position, completing short reads and returning the EOF count without moving or closing the descriptor. |
74
+ | `writeFileWindowFully`, `WriteFileWindowOptions` | [Borrowed-handle writes](#borrowed-handle-writes) | Write all supplied bytes at an explicit position or the current cursor, completing short writes with cancellation and per-write authority checks. |
74
75
  | `copyFileHandle`, `copyFileDescriptorSync`, `CopyFileHandleOptions` | [copy.md](copy.md#borrowed-filehandle-transfers) | Copy caller-owned regular files through async handles or sync descriptors from position zero with byte limits and synchronous callbacks; preserves cursors and leaves publication and cleanup to the caller. |
76
+ | `sameFileContentsSync`, `SameFileContentsOptions` | [Exact file comparison](file-contents.md) | Compare borrowed regular-file descriptors byte for byte through EOF with bounded memory and an optional per-file byte limit, preserving both cursors and lifetimes. |
75
77
  | `overwriteFileHandle`, `OverwriteFileHandleOptions` | [in-place-write.md](in-place-write.md) | Overwrite a borrowed read/write handle with prefix-only preparation and best-effort rollback; preserves its inode, cursor, and caller-owned lifetime. |
76
78
  | `openRootFile`, `openRootFileSync`, `canUseRootFileOpen`, `matchRootFileOpenFailure`, related types | – | Low-level root-bounded open; rejects every symlink component by default, with `symlinks: "follow-parents-within-root"` for contained parent aliases or `"follow-within-root"` for final links too. |
77
79
  | `appendRegularFile`, `appendRegularFileSync`, `readRegularFile`, `readRegularFileSync`, `statRegularFile`, `statRegularFileSync`, `resolveRegularFileAppendFlags`, `AppendRegularFileOptions`, `RegularFileStatResult` | [regular-file.md](regular-file.md) | Type-checked regular-file I/O. |
@@ -151,6 +153,71 @@ component is followed by another segment, both helpers throw
151
153
  `FsSafeError("not-file")` before the platform can expose that state as POSIX
152
154
  `ENOTDIR` or Windows `ENOENT`.
153
155
 
156
+ #### Borrowed-handle writes
157
+
158
+ Use `writeFileWindowFully()` when you already own a writable file handle and
159
+ need to complete a byte-window write, including positive short writes.
160
+
161
+ ```ts
162
+ import { root } from "@openclaw/fs-safe";
163
+ import { writeFileWindowFully } from "@openclaw/fs-safe/advanced";
164
+
165
+ const workspace = await root("/srv/workspace");
166
+ await using opened = await workspace.openWritable("record.bin", { writeMode: "update" });
167
+ await writeFileWindowFully(opened.handle, Buffer.from([1, 2, 3]), 16);
168
+ ```
169
+
170
+ ```ts
171
+ type WriteFileWindowOptions = {
172
+ signal?: AbortSignal;
173
+ assertBeforeMutation?: () => void;
174
+ };
175
+
176
+ function writeFileWindowFully(
177
+ handle: import("node:fs/promises").FileHandle,
178
+ bytes: Uint8Array,
179
+ position: number | null,
180
+ options?: WriteFileWindowOptions,
181
+ ): Promise<void>;
182
+ ```
183
+
184
+ A numeric `position` writes at that offset without moving the handle's cursor.
185
+ It and the exclusive window end (`position + bytes.byteLength`) must be
186
+ non-negative safe integers; invalid ranges throw `RangeError` before mutation.
187
+ Bounds come from the intrinsic byte view, ignoring shadowed metadata properties.
188
+ Pass `null` to write at and advance the current cursor. Each syscall writes at
189
+ most 512 KiB. A write that makes no progress throws
190
+ `FsSafeError("helper-failed")`; filesystem errors propagate unchanged.
191
+ Empty input still validates the range and checks cancellation, but performs no
192
+ I/O and does not call `assertBeforeMutation`.
193
+
194
+ The caller must supply a writable regular-file handle, opened **without append
195
+ mode** for numeric positions. Some operating systems ignore positioned-write
196
+ offsets on append handles, and this helper does not inspect file type or open
197
+ flags. Opening, path admission, identity checks, and closing remain the caller's
198
+ responsibility. Keep the handle open and the borrowed bytes unchanged, attached,
199
+ and accessible until the promise settles; avoid concurrent I/O when it can change
200
+ the intended contents or shared cursor. The helper does not acquire a lock.
201
+
202
+ `assertBeforeMutation` runs synchronously immediately before every write,
203
+ including short-write retries. A thrown value propagates unchanged; a Promise or
204
+ thenable return rejects with `TypeError` before that write. The callback must not
205
+ modify the payload or handle. It does not run as a final completion check; the
206
+ caller owns any authority check before later publication or other mutations.
207
+
208
+ `signal` is checked at admission, before and after each authority callback, and
209
+ after each pending write settles. Cancellation waits for an in-flight write and
210
+ then rejects with the signal's reason without starting another syscall. If that
211
+ write fails, its filesystem error or zero-progress failure takes precedence over cancellation. Already
212
+ written bytes remain changed; there is no rollback or hidden write after the
213
+ promise settles.
214
+
215
+ The helper neither truncates an existing suffix nor changes permissions,
216
+ synchronizes, or closes the handle. Callers retain those responsibilities and
217
+ any wider transaction policy. For complete replacement with best-effort
218
+ rollback, use [`overwriteFileHandle()`](in-place-write.md); for root-bounded
219
+ atomic replacement, use [`Root.write()`](writing.md).
220
+
154
221
  ### Local roots and file URLs
155
222
 
156
223
  | Export | Page | Notes |
package/docs/archive.md CHANGED
@@ -11,6 +11,14 @@ These TAR routes work with all optional dependencies omitted and need no
11
11
  runtime interpreter, download, install script, or consumer compiler toolchain.
12
12
  ZIP fallback still requires optional `jszip`.
13
13
 
14
+ The shared TAR parser reuses the already-validated owned path for ordinary
15
+ members. Original header names and USTAR prefixes still undergo validation
16
+ even when PAX or GNU metadata supplies an override; effective override paths
17
+ retain their separate checks. Empty USTAR prefixes retain field decoding and
18
+ padding checks; path validation applies to nonempty prefixes. Joining an
19
+ admitted prefix and name with a separator preserves their checked components,
20
+ so the parser does not repeat the same component validation on the joined path.
21
+
14
22
  `auto` prefers an available native binding; a native operation failure is
15
23
  terminal and never retries through WASM. `require` rejects a missing binding
16
24
  with `FsSafeError("helper-unavailable")`, including for zstd/bzip2 suffix
@@ -31,6 +39,7 @@ await extractArchive({
31
39
  timeoutMs: 15_000, // hard budget; active destination mutation is joined
32
40
  stripComponents: 0, // tar-style strip-leading-dirs
33
41
  entryModes: "clamp", // default; use "preserve" for archive rwx bits
42
+ entryUmask: 0, // default; remove these bits from final modes
34
43
  entryFilter: ({ path, kind, size }) => "extract",
35
44
  onFiltered: "reject-archive", // default; opt into "skip-entry" explicitly
36
45
  limits: {
@@ -50,7 +59,7 @@ await extractArchive({
50
59
  type ExtractArchiveOptions = {
51
60
  archivePath: string; // absolute path to the archive
52
61
  destDir: string; // absolute destination directory; must already exist
53
- timeoutMs: number; // positive wall-clock budget; <= 0/non-finite disables it
62
+ timeoutMs: number; // positive elapsed-time budget; <= 0/non-finite disables it
54
63
  durable?: boolean; // false; opt into syncing published files and directories before completion
55
64
  kind?: ArchiveKind; // "zip" | "tar" | "tar-zstd" | "tar-bzip2"
56
65
  stripComponents?: number; // strip N leading dirs from entry paths
@@ -58,6 +67,7 @@ type ExtractArchiveOptions = {
58
67
  limits?: ArchiveExtractLimits;
59
68
  logger?: ArchiveLogger; // { info?, warn? }
60
69
  entryModes?: "clamp" | "preserve";
70
+ entryUmask?: number; // integer 0..0o777; defaults to 0
61
71
  entryFilter?: (entry: { path: string; kind: ArchiveEntryKind; size: number }) =>
62
72
  "extract" | "skip";
63
73
  onFiltered?: "reject-archive" | "skip-entry";
@@ -71,6 +81,12 @@ once, deepest first, and finally the destination directory. All work stays insid
71
81
  the extraction deadline; active syncs are joined before rejection. File sync
72
82
  failures use the same error surface as `Root.copyIn()`; directory I/O failures
73
83
  also reject, with the existing platform limitations on directory flushing.
84
+
85
+ Deadline checks use a monotonic clock, including before queued mutations start
86
+ and before reporting success. Synchronous caller code can delay the timer, but
87
+ cannot permit the next operation after the budget expires. This does not
88
+ interrupt a callback halfway through execution or replace its own thrown error;
89
+ active destination mutations are still joined before timeout rejection.
74
90
  Files whose final mode prevents reading, including `0o000` and write-only files,
75
91
  sync once through the copy's retained descriptor during publication. Permissions
76
92
  are never widened to reopen them. Directory modes are finalized after the file
@@ -103,6 +119,15 @@ including a mode containing only stripped special bits, stays zero under
103
119
  directories; ZIP UNIX creator records with zero attributes are explicit zero,
104
120
  while non-UNIX ZIP records use the absent-metadata defaults.
105
121
 
122
+ `entryUmask` removes permission bits after the selected mode policy: final modes
123
+ are the policy result `& ~entryUmask`. It applies to files, explicit directories,
124
+ and implicit parent directories, including existing destination directories.
125
+ The destination root and private staging modes are unchanged. The default `0`
126
+ preserves existing behavior; invalid masks reject before extraction begins.
127
+ fs-safe neither reads nor changes the process umask. Pass
128
+ `entryUmask: process.umask()` explicitly when that is the caller's policy.
129
+ Windows retains the POSIX-mode limitations described below.
130
+
106
131
  TAR mode fields containing only NUL/ASCII-space padding use absent defaults.
107
132
  Both backends recognize GNU binary modes, including signed values,
108
133
  within JavaScript's safe-integer range before masking permission bits.
@@ -116,7 +141,7 @@ stay `0o600` and directories `0o700` until publication. Files receive their fina
116
141
  mode through the guarded copy's owned writer descriptor. Directories are pinned
117
142
  before descending and finalized after their children, including empty and
118
143
  restrictive directories. Explicit accepted directory modes win regardless of
119
- archive order; implicit parents receive `0o755`. Existing destination directories
144
+ archive order; implicit parents receive `0o755 & ~entryUmask`. Existing destination directories
120
145
  also receive the requested final mode. They are never temporarily widened to
121
146
  allow child writes; insufficient write/search access still rejects.
122
147
 
@@ -154,6 +179,13 @@ between native and JavaScript paths rather than reimplementing it in Rust.
154
179
 
155
180
  ZIP extraction and bounded reads admit every physical central-directory record and its referenced local header before either decoder can normalize or collapse names. Raw names and valid Unicode Path names must pass traversal checks before stripping, filtering, or selecting a requested member; duplicate or colliding names reject with `entry-path`, even in unrelated or skipped members. Materially conflicting local/central or Unicode interpretations, malformed critical metadata, and ambiguous framing reject with `ArchiveFormatError`. Harmless internal separator and dot-component equivalence is allowed only after validation; every raw and Unicode interpretation must also agree on whether its name ends in `/` or `\`. Ordinary legacy filename decoding remains backend-selected. Native ZIP extraction groups nearby metadata reads into at most two 4 KiB read-ahead buffers per admission pass; larger records retain separately bounded reads. Buffered record views remain stable across eviction, and cached work periodically yields for deadline checks.
156
181
 
182
+ ZIP end-record admission searches the bounded comment window for signatures
183
+ while retaining complete comment-length and ambiguity checks. Dense signature
184
+ sequences fall back to the bounded byte scan.
185
+ The separate `readZipCentralDirectoryEntryCount(buffer)` hint uses bounded
186
+ reverse searches for comments and retains its latest-valid-record selection;
187
+ it does not replace strict archive admission.
188
+
157
189
  ZIP admission establishes each entry's kind before callbacks: a high-word UNIX
158
190
  symlink type takes precedence regardless of creator, followed by the DOS directory
159
191
  bit, the exact UNIX directory type, or a terminal slash/backslash. Native manifests
@@ -185,6 +217,10 @@ decoded validation. Unicode Path admission is shared only when both the raw name
185
217
  and the complete Unicode fields match; different fields still verify their own
186
218
  CRC and interpretation. Shared backing memory is checked independently. Decoded
187
219
  name validation is not reused across entries or archives.
220
+ UTF-8-flagged ASCII names in nonshared backing memory reuse their raw-path
221
+ validation, and an identical decoded spelling reuses its canonical key. Shared
222
+ name bytes still undergo independent decoding and validation; Unicode Path
223
+ fields retain their own CRC and interpretation checks.
188
224
 
189
225
  `stripComponents` removes leading nonempty, non-`.` path components after
190
226
  normalizing separators. For example, `./pkg/hello.txt` with
@@ -202,6 +238,9 @@ directory paths. For example, `./pkg//state\cache/value` is presented as
202
238
  `pkg/state/cache/value`, even with `stripComponents: 1`. Case and Unicode
203
239
  spelling are preserved. Local PAX `path`, GNU long-name, and supported ZIP
204
240
  Unicode Path names use the same canonicalization.
241
+ Callbacks follow physical archive order, including ZIP names that look like
242
+ integer object keys. The public ZIP loader's `files` object retains ordinary
243
+ JavaScript object enumeration and mutation behavior.
205
244
 
206
245
  Raw paths undergo traversal, absolute/drive-path, and NUL validation **before**
207
246
  canonicalization; normalization cannot turn an unsafe path into an accepted
package/docs/atomic.md CHANGED
@@ -16,7 +16,7 @@ import {
16
16
 
17
17
  Write `content` to a sibling temp file in the destination directory, apply the parent-directory and final file modes through verified descriptors, optionally `fsync` the file descriptor, optionally `fsync` the parent directory after rename, then atomically rename over the destination. No permission change follows a caller-supplied pathname.
18
18
 
19
- On POSIX, the parent is opened with no-follow and directory-only flags, checked against its pre-open identity, and mode-adjusted through that descriptor. A replacement symlink is rejected rather than followed. If the directory cannot be opened for descriptor access, the operation fails closed instead of retrying by pathname. Windows does not enforce POSIX directory modes and Node cannot consistently open directory descriptors there, so `dirMode` is passed only to `mkdir`; no pathname `chmod` fallback is attempted.
19
+ On POSIX, the parent is opened with no-follow and directory-only flags, checked against its exact pre-open device/inode identity, and mode-adjusted through that descriptor. A replacement symlink is rejected rather than followed. If the directory cannot be opened for descriptor access, the operation fails closed instead of retrying by pathname. Windows does not enforce POSIX directory modes and Node cannot consistently open directory descriptors there, so `dirMode` is passed only to `mkdir`; no pathname `chmod` fallback is attempted.
20
20
 
21
21
  Async replacements to the same destination are serialized inside the current process, so two overlapping `replaceFileAtomic()` calls do not interleave their temp-write/rename phases. Use a sidecar lock when multiple processes may write the same target.
22
22
 
@@ -92,10 +92,13 @@ await replaceFileAtomic({
92
92
 
93
93
  If `beforeRename` throws, the rename is skipped and the owned temp file is removed — the destination is unchanged. Cleanup unlinks only the exact admitted single-link file; a substitute observed at the temp name is preserved and removed from cleanup authority. The same identity is rechecked before every rename retry, when entering copy fallback, and at the final name after rename. A post-rename verification failure reports the race without rolling back or deleting the published name.
94
94
 
95
- JavaScript permits `beforeRename` callbacks to throw any value, including
95
+ JavaScript permits `beforeRename` callbacks and filesystem adapters to throw any value, including
96
96
  `undefined`, `null`, `false`, signed zero, `0n`, an empty string, and `NaN`.
97
- Once such an operation failure reaches temp-owner settlement, atomic replacement
98
- preserves that value when cleanup and close succeed. With
97
+ Atomic replacement preserves such operational failures when cleanup and close
98
+ succeed, including rename and post-rename verification failures. Rename retry
99
+ and copy-fallback classification reads the error code once without coercion;
100
+ missing or unreadable codes preserve the original failure. A rejected call has
101
+ no success receipt even if an adapter committed its rename before throwing. With
99
102
  `throwOnCleanupError: true`, an additional owned-temp cleanup failure keeps the
100
103
  existing cleanup wrapper whose `cause` is the original thrown value. A later
101
104
  descriptor-close failure is reported in an `AggregateError`, in operation/cleanup
@@ -150,6 +153,28 @@ must not have aliases. The policy reads `nlink` from a pinned destination
150
153
  descriptor, not pathname metadata, before rename and rechecks it in the copy
151
154
  fallback.
152
155
 
156
+ The asynchronous helper closes a successfully admitted hardlink-check pin
157
+ best-effort, including synchronous adapter throws and rejected close promises.
158
+ The synchronous helper reports a close failure after successful admission.
159
+
160
+ Source and pinned destination admission compare exact bigint device/inode
161
+ observations, so distinct identities that round to the same JavaScript number
162
+ cannot authorize a copy. Unknown Windows identities get one bounded reinspection
163
+ of the same descriptor or path; incomplete or inconsistent observations fail
164
+ closed without reopening. Injected filesystem adapters must honor the
165
+ `{ bigint: true }` stat option. Source admission reuses that exact pair instead
166
+ of immediately repeating it with numeric metadata.
167
+
168
+ Copy-source close is best-effort. A failed pinned-destination admission also
169
+ preserves its selected failure when close fails. These cleanup rules include
170
+ synchronous throws and rejected promises from custom asynchronous adapters.
171
+
172
+ The best-effort parent-directory synchronization helper also ignores either form
173
+ of close failure. Parent-directory mode admission and its close remain fail-closed.
174
+ A compatibility-publication handle that was not adopted also receives one
175
+ best-effort close, preserving the selected verification or previous-handle close
176
+ failure. The retained owner's close failures remain reportable.
177
+
153
178
  The default `copyFallbackRestore: "none"` preserves the existing fallback
154
179
  contract: a failed copy can leave a partial destination. For state files where
155
180
  preserving the old bytes is more important, choose `"restore-original"` and set
@@ -349,7 +374,10 @@ the preflight cap fails with `FsSafeError("too-large")`.
349
374
  If another writer changes source entries during the fallback, the staged copy
350
375
  throws `ESTALE` before commit when possible. If the destination has already
351
376
  been committed, cleanup still preserves the changed source entries and throws
352
- `ESTALE`. Directory manifests retain an exact bigint device/inode receipt from
377
+ `ESTALE`. Copied file and symlink manifests retain exact bigint identities and
378
+ nanosecond timestamps, so rounded file IDs cannot authorize copying or removal
379
+ of a different entry. Hardlink groups also use exact identities. Directory
380
+ manifests retain an exact bigint device/inode receipt from
353
381
  copy admission. Each directory is rechecked after traversal, and the source root
354
382
  is checked again before publication. Cleanup checks the same receipt before
355
383
  removing children, then invokes mutation authority and rechecks the receipt and
@@ -366,6 +394,11 @@ unlink is verified through a remaining manifested alias and its exact resulting
366
394
  identity becomes the next cleanup receipt. This accounts for the operation's
367
395
  own link-count and ctime changes without suppressing unexpected external
368
396
  mutations.
397
+ On Windows, opening a regular source may advance its ctime while all other
398
+ fingerprint fields match. That exception applies only to opening; post-copy
399
+ verification and cleanup retain their full fingerprint checks.
400
+ Copied aliases share each verified open-time update. Changes observed between
401
+ copies still reject instead of being mistaken for an owned open transition.
369
402
 
370
403
  ### Mutation authority and publication receipts
371
404
 
@@ -404,6 +437,11 @@ thenable, or any other value fails with a `TypeError`; rejected asynchronous
404
437
  results are consumed. Perform asynchronous policy checks before calling the
405
438
  helper and use the authority callback to recheck the current owner at each
406
439
  mutation boundary. All callbacks are captured before the first await.
440
+ Copied source leaves are checked again immediately after authority returns and
441
+ before unlink is submitted. Supplying any of the three callbacks also
442
+ retains the original source-parent route and renews copied-directory ancestry
443
+ before cleanup. Substituted entries are preserved; pathname checks and unlink
444
+ remain a best-effort sequence, not atomic.
407
445
 
408
446
  `onDestinationPublished` runs exactly once after a successful rename resolves,
409
447
  before awaited post-rename directory checks or source cleanup. It receives a
@@ -157,6 +157,10 @@ pnpm archive:producer-smoke ./consumer require
157
157
  This uses a child bound to canonical cwd/device/inode running `/usr/bin/tar -czf - .`
158
158
  with unchanged stdout, and npm tar, on synthetic Unicode/newline/long-name files,
159
159
  then the installed package API for exact payload hashes and bounded reads.
160
+ The consumer must be separate from the source checkout; package resolution must
161
+ stay within its own `node_modules`, including pnpm's local `.pnpm` layout.
162
+ Workspace self-resolution, upward resolution, and external package links reject
163
+ before package imports or archive fixture creation.
160
164
  It also rejects a valid PAX override attached to an invalid raw UTF-8 field.
161
165
  The `require` command must resolve the freshly packed native binding; the
162
166
  `off` command uses the installed WASM asset. No live user files are read.
package/docs/copy.md CHANGED
@@ -178,6 +178,8 @@ These are low-level operations on caller-owned absolute paths, not Root-relative
178
178
 
179
179
  An already aborted signal prevents dispatch. In-flight cancellation stops cancellable traversal and waits for admitted native writes to finish before rejecting. APFS and Btrfs bulk operations cannot be interrupted once dispatched. An aborted or failed call can therefore leave a destination, including a complete bulk clone. It remains caller-owned; after settlement, the caller decides whether to retain or remove it. Do not start cleanup by racing the cloning promise against an abort promise.
180
180
 
181
+ Tree copying preserves caller abort handlers and receives cancellation even when a caller handler stops event propagation, including native cloning and byte-copy fallbacks.
182
+
181
183
  Completion is not a crash-durability guarantee. The API is suitable for reconstructible templates and checkouts; it does not sync every file or replace application-level publication and recovery rules.
182
184
 
183
185
  A close-only rejection reports descriptor settlement, not whether bytes reached stable storage. The destination can already be complete when a close fails, just as other failed or cancelled calls can leave caller-owned output. Inspect or remove that output only after the copying promise settles and under the same source and destination authority assumptions.
package/docs/creation.md CHANGED
@@ -42,12 +42,16 @@ POSIX creation requests `0700` for directories and `0600` for files by default;
42
42
  the umask may restrict those permissions further. Existing directory privacy
43
43
  checks never broaden permissions.
44
44
 
45
- Native private file creation checks the retained descriptor's actual owner and
45
+ Private POSIX `Root.create()` and `createJson()` writes check the retained descriptor's actual owner and
46
46
  permissions before writing payload bytes, after producer and authority callbacks,
47
- and at publication. A successful `chmod` is insufficient: filesystems that do not
47
+ and at publication, including JavaScript fallback writes. Payload writes require
48
+ the temporary `0600` mode even when the requested final mode differs.
49
+ Private ownership, permissions and ACLs are checked before preparing that mode,
50
+ including after authority callbacks; valid restrictive initial modes remain supported.
51
+ A successful `chmod` is insufficient: filesystems that do not
48
52
  enforce owner-only permissions reject before payload writes. The requested final
49
53
  mode is verified too; a failure after publication preserves the completed file
50
- and reports its published outcome.
54
+ and staged creation reports its published outcome.
51
55
 
52
56
  On macOS (Darwin), private creation also requires an ACL-free result. The native
53
57
  helper must provide `inspectDarwinAcl`; native `off`, a missing helper, or an
@@ -113,7 +117,7 @@ thenables reject before mutation. Parent and file identity checks are repeated
113
117
  after the callback. Final permission checks, descriptor settlement and cleanup
114
118
  retain the operation's cleanup ownership after publication.
115
119
 
116
- Failure does not always mean the final path is absent. Private-file errors
120
+ Failure does not always mean the final path is absent. Staged private-file errors
117
121
  after publication or ambiguous publication preserve the destination and carry
118
122
  `details.publication.status` (`published` or `indeterminate`), the target path and
119
123
  staging cleanup outcome. Cleanup and close failures retain the original error
@@ -89,6 +89,29 @@ or reconstructed numeric identity is accepted only when both components are
89
89
  safe integers and, on Windows, nonzero. Rounded or unknown caller identities
90
90
  fail with `path-mismatch` rather than authorizing a different directory.
91
91
 
92
+ Caller-supplied receipts may use `DirectoryReceipt<BigIntStats>` with the result
93
+ of `lstat(path, { bigint: true })`. `pinDirectory()`, `syncDirectory()`,
94
+ `syncDirectorySync()`, `publishFileExclusive()`'s `parentReceipt`, and
95
+ `stageFileInDirectory()` accept both numeric and bigint receipt inputs.
96
+ `DirectoryReceipt` without a type argument and all returned durability receipts
97
+ still expose numeric `Stats`, including working type predicates and Date
98
+ properties. Bigint metadata is projected from the supplied observation, retaining
99
+ fractional timestamps and the private exact device/inode identity.
100
+
101
+ ```ts
102
+ import { lstatSync, realpathSync, type BigIntStats } from "node:fs";
103
+ import { syncDirectorySync, type DirectoryReceipt } from "@openclaw/fs-safe/durability";
104
+
105
+ const directoryPath = "/srv/backups/sqlite";
106
+ const receipt: DirectoryReceipt<BigIntStats> = {
107
+ path: directoryPath,
108
+ realPath: realpathSync(directoryPath),
109
+ identity: lstatSync(directoryPath, { bigint: true }),
110
+ };
111
+ // Keep this receipt across the application's publication operation.
112
+ const outcome = syncDirectorySync(receipt);
113
+ ```
114
+
92
115
  Call `close()` in `finally`. Closing is idempotent; using a closed pin fails.
93
116
 
94
117
  These checks intentionally reject a moved or replaced pathname. For one file's
@@ -276,6 +299,11 @@ pathname without reopening the file and repeat the symlink and file-type checks.
276
299
  POSIX opens are nonblocking, so a raced FIFO or device is rejected after
277
300
  descriptor inspection rather than waiting for a writer.
278
301
 
302
+ A pathname hash reports failure to close its owned descriptor after successful
303
+ hashing. If hashing, admission, or cancellation already failed, that original
304
+ failure remains primary even when close also fails. This also applies to
305
+ `sha256FileSync()`; borrowed handles and descriptors remain caller-owned.
306
+
279
307
  When the optional binding is active, hashing runs as an async native task and
280
308
  does not occupy the JavaScript event loop with digest updates. With native mode
281
309
  `off`, or in `auto` when no binding loads, the fallback performs asynchronous
@@ -347,6 +375,13 @@ this receipt instead of inferring ownership from path existence. The original
347
375
  failure remains available as `cause`. Failures before target creation retain
348
376
  their existing error shape and do not claim a cleanup result.
349
377
 
378
+ Source and target identities are checked again after successful or unsupported
379
+ directory synchronization, while their descriptors remain owned. A late
380
+ verification failure retains its strategy's verification phase and is not a
381
+ directory-sync failure. Completed copied targets stay pinned during conditional
382
+ cleanup; substituted entries remain untouched. Returned numeric metadata comes
383
+ from the retained target descriptor and grants no continuing pathname authority.
384
+
350
385
  ### Directory-sync failure policy
351
386
 
352
387
  `onSyncFailure` applies only after target creation and content/identity fencing