@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
@@ -0,0 +1,68 @@
1
+ # Exact file comparison
2
+
3
+ `sameFileContentsSync()` compares the bytes of two already-open regular files,
4
+ starting at offset zero. It uses bounded buffers and completes positive short
5
+ reads independently on each descriptor. A `true` result requires matching bytes
6
+ and observed EOF on both inputs; a difference can return `false` immediately.
7
+
8
+ ```ts
9
+ import fs from "node:fs";
10
+ import { sameFileContentsSync } from "@openclaw/fs-safe/advanced";
11
+
12
+ const source = fs.openSync("/trusted/source.sqlite", "r");
13
+ try {
14
+ const copy = fs.openSync("/trusted/copy.sqlite", "r");
15
+ try {
16
+ console.log(sameFileContentsSync(source, copy, { maxBytes: 256 * 1024 * 1024 }));
17
+ } finally {
18
+ fs.closeSync(copy);
19
+ }
20
+ } finally {
21
+ fs.closeSync(source);
22
+ }
23
+ ```
24
+
25
+ ## Signature
26
+
27
+ ```ts
28
+ type SameFileContentsOptions = { maxBytes?: number };
29
+
30
+ function sameFileContentsSync(
31
+ leftFd: number,
32
+ rightFd: number,
33
+ options?: SameFileContentsOptions,
34
+ ): boolean;
35
+ ```
36
+
37
+ Both descriptors must be open regular files. Nonregular inputs throw
38
+ `FsSafeError("not-file")`; underlying filesystem errors propagate unchanged.
39
+ Passing the same descriptor twice is allowed, but does not bypass validation,
40
+ the byte limit, or reads. File sizes are checked against the limit, but are not
41
+ used as proof that contents match or that EOF has been reached.
42
+
43
+ ## Bounds and ownership
44
+
45
+ `maxBytes` is a limit for each file, not their combined size. It accepts a
46
+ non-negative safe integer or `Infinity`; omission imposes no caller-selected
47
+ limit. Invalid limits throw `RangeError` before filesystem work. Comparisons
48
+ cannot exceed `Number.MAX_SAFE_INTEGER` bytes because positions must remain
49
+ exactly representable.
50
+
51
+ A reported file size above the limit throws `FsSafeError("too-large")` before
52
+ reading. At the limit, the comparison reads at most one additional byte from
53
+ each input to prove EOF; any observed overflow throws the same error. A
54
+ matching prefix is never reported as complete equality. An early mismatch
55
+ does not scan the remaining bytes or promise to detect later errors or growth.
56
+ A zero-byte limit admits two empty files. Memory use is at most two 1 MiB
57
+ payload buffers, regardless of file size.
58
+
59
+ The operation neither changes the descriptors' current offsets nor closes
60
+ them, including on failure. It performs no writes, hashing, pathname lookup,
61
+ or identity comparison. Callers retain path admission, hardlink policy,
62
+ descriptor lifetime, and any before/after mutation-fingerprint checks. A
63
+ comparison is not a snapshot of concurrently modified files; applications
64
+ requiring stable contents must retain their existing coordination and checks.
65
+
66
+ Use [`readFileWindowFullySync()`](positional-read.md) for a selected byte
67
+ window and [bounded descriptor reads](advanced.md#files-and-identity) when the
68
+ caller needs the file contents in memory.
package/docs/json.md CHANGED
@@ -146,10 +146,11 @@ where lower latency matters more than crash-durability.
146
146
 
147
147
  Synchronous variant. It pretty-prints with two spaces, appends a newline,
148
148
  creates parents at `0o700`, writes at `0o600`, and synchronizes the parent
149
- directory best-effort. File-mode tightening carries the staged bigint identity
150
- through rename and applies `fchmod` only when the reopened descriptor and current
151
- pathname still name that same single-link regular file; a swap is preserved and
152
- skips this best-effort step. It has no options bag. On `EPERM`/`EEXIST`, its legacy
149
+ directory best-effort. A retained staging descriptor carries the exact bigint
150
+ identity through rename and file-mode tightening. Publication and cleanup never
151
+ adopt a substituted temporary file: a changed identity, type or link count rejects
152
+ the write and leaves the replacement untouched. A swap detected after publication
153
+ also rejects without deleting or changing the replacement. It has no options bag. On `EPERM`/`EEXIST`, its legacy
153
154
  compatibility path removes the existing destination and retries the staged-file
154
155
  rename, so that fallback is temporarily non-atomic while retaining the staged
155
156
  file's `0600` mode; use the async `writeJson()`/`replaceFileAtomic()` surfaces
@@ -83,6 +83,8 @@ An existing non-directory component cannot be traversed further, including by
83
83
  The asynchronous helper opens the candidate through the matched [`Root`](root.md),
84
84
  so no-follow, identity, hardlink, device-path, and byte-limit checks happen at
85
85
  the read itself.
86
+ Link policies are captured once before root initialization and reused for every
87
+ candidate, so replacing options while a read is pending cannot weaken admission.
86
88
 
87
89
  ```ts
88
90
  type ReadLocalFileFromRootsOptions = LocalRootsInputOptions & {
@@ -39,14 +39,18 @@ sentinel. The same rejection object must escape, no callback may follow refusal,
39
39
  and the owned stage must be gone before fixture teardown.
40
40
 
41
41
  Windows workers exercise buffer `Root.write` through a stable final-file symlink,
42
- then refuse before staging a newly created placeholder, before publishing over a
43
- new placeholder, and before publishing to an existing symlink-selected destination.
44
- They verify alias binding, destination preservation, observed placeholder/stage
45
- states, and cleanup before fixture teardown. The default native-off and explicit
42
+ then refuse before stage creation for a missing destination, before publishing a
43
+ complete stage to that still-missing destination, and before publishing to an
44
+ existing symlink-selected destination. Missing destinations must remain absent at
45
+ every authority callback and after refusal. The workers verify alias binding,
46
+ destination preservation, complete single-link stages, and cleanup before fixture
47
+ teardown. The default native-off and explicit
46
48
  `verify-content-with-lock` native-require configurations both select the existing
47
- Windows JS buffer writer. The compatibility route is expected not to load the
48
- addon; the receipt does not mislabel this as native publication or evidence that
49
- content-verification fallback or lock contention was exercised.
49
+ Windows JS buffer writer. In native-require mode, the compatibility route loads
50
+ the addon to publish its retained sidecar lock through `Root.create`; the payload
51
+ writer remains JS. The receipt does not mislabel this as native payload
52
+ publication or evidence that content-verification fallback or lock contention
53
+ was exercised.
50
54
 
51
55
  ## Bounds and interpretation
52
56
 
package/docs/native.md CHANGED
@@ -76,14 +76,14 @@ whether a path, archive entry, mode, owner, or cleanup policy is acceptable.
76
76
  or add-on CRT descriptor namespace.
77
77
 
78
78
  The internal macOS `inspectDarwinAcl(fd)` capability reports `absent`, `empty`,
79
- or `present` for the opened object's extended ACL. It synchronously owns a
80
- close-on-exec duplicate for inspection, leaves the caller's descriptor and file
81
- position alone, and never reopens a pathname. Darwin's `acl_get_entry` returns
79
+ or `present` for the opened object's extended ACL. It synchronously borrows the
80
+ caller's descriptor, preserving its file position and POSIX record locks, and
81
+ never reopens a pathname. Keep the descriptor open until inspection returns.
82
+ Darwin's `acl_get_entry` returns
82
83
  zero for an entry; end-of-list is accepted only for the first entry of a valid,
83
84
  privately owned empty ACL. Unsupported, malformed, and failed inspection is not
84
- reported as absence. These facts do not classify individual ACE permissions,
85
- prove volume ownership enforcement, or add ACL enforcement to private writers
86
- and secure readers outside the clone path.
85
+ reported as absence. These facts do not classify individual ACE permissions or
86
+ prove volume ownership enforcement; each caller applies its own security policy.
87
87
 
88
88
  ## Archives
89
89
 
@@ -267,8 +267,9 @@ infer native loading from timing.
267
267
  ## Loader security
268
268
 
269
269
  Importing fs-safe never executes a child process. Linux libc selection uses
270
- the Node process report, conventional musl library filenames, and the ELF
271
- `PT_INTERP` field of `process.execPath`. If all probes are inconclusive, the
270
+ the Node process report, then the ELF `PT_INTERP` field of `process.execPath`,
271
+ then conventional musl library filenames. An installed compatibility loader
272
+ does not override the running executable's interpreter. If all probes are inconclusive, the
272
273
  loader conservatively attempts the glibc package and lets normal module loading
273
274
  fail into `auto` fallback. The loader requires only the package selected from
274
275
  the detected target; it never probes unrelated packages, downloads code, or
package/docs/path.md CHANGED
@@ -44,7 +44,7 @@ opened or mutated.
44
44
 
45
45
  ### `isPathInsideWithRealpath(rootDir, target, opts?)`
46
46
 
47
- Synchronous. Same as `isPathInside`, but resolves both inputs through `realpath` first. Use this when you want the canonical answer and either input might be a symlink.
47
+ Synchronous. First requires lexical containment with `isPathInside`, then resolves both inputs through `realpath` and checks containment again. A lexically outside path is rejected even if its resolved target is inside the root.
48
48
 
49
49
  ```ts
50
50
  isPathInsideWithRealpath("/srv/uploads", "/srv/symlink-to-elsewhere"); // false
@@ -121,7 +121,7 @@ The check is intentionally not a normal consumer policy knob. Safe read APIs rej
121
121
 
122
122
  ### `isNotFoundPathError(err)`
123
123
 
124
- `true` if the error is a `NodeJS.ErrnoException` with code `ENOENT` (file or directory missing).
124
+ `true` if the error has code `ENOENT` (file or directory missing) or `ENOTDIR` (a path component is not a directory).
125
125
 
126
126
  ```ts
127
127
  try {
@@ -207,8 +207,8 @@ import {
207
207
  } from "@openclaw/fs-safe/advanced";
208
208
  ```
209
209
 
210
- - `assertNoPathAliasEscape({ rootRealPath, candidatePath, policy })` — async. Asserts the candidate's resolved real path is inside the root. Configurable via `PATH_ALIAS_POLICIES` (which currently ships only the default `"strict"` policy).
211
- - `assertNoHardlinkedFinalPath({ filePath })` — async. Throws if the file at `filePath` has `nlink > 1`.
210
+ - `assertNoPathAliasEscape({ absolutePath, rootPath, boundaryLabel, policy? })` — async. Applies root path resolution and final hardlink checks. `policy` defaults to `PATH_ALIAS_POLICIES.strict`; `PATH_ALIAS_POLICIES.unlinkTarget` permits final symlink and hardlink aliases for unlink operations.
211
+ - `assertNoHardlinkedFinalPath({ filePath, root, boundaryLabel, allowFinalHardlinkForUnlink? })` — async. Rejects a regular file with `nlink > 1`; missing paths and nonregular resolved entries are ignored. Setting `allowFinalHardlinkForUnlink: true` skips this check for unlink operations.
212
212
 
213
213
  Use these when writing a custom helper that wants the same guards `root()` uses but with different surrounding logic.
214
214
 
@@ -87,6 +87,12 @@ The advanced options retain `currentUserSid` as an explicit classification
87
87
  override and `principalTranslationFailed: true` as an immediate unverified
88
88
  result. The optional `principalSids` translation cache is still accepted but
89
89
  is no longer needed because the query returns SIDs directly.
90
+ Injected executors must return the same structured success JSON as the built-in
91
+ query: valid `ownerSid` and `currentUserSid` strings, an explicit boolean
92
+ `remote`, and complete DACL facts (`complete`, `daclPresent`, and `aces`).
93
+ Missing or nonboolean locality leaves both inspectors unverified; only
94
+ `remote: false` establishes locality for owner trust. An explicit `remote: true`
95
+ retains the ACL report but never grants trusted ownership.
90
96
  The existing classifier assigns principals to trusted, world, or group;
91
97
  trusted defaults include the current user, SYSTEM, and Administrators.
92
98
  The built-in query has a fixed 30-second process deadline. A command failure or timeout returns an
@@ -20,6 +20,9 @@ The root subpath also exports `openLocalFileSafely`, `readLocalFileSafely`, and
20
20
  `resolveOpenedFileRealPathForHandle` for trusted absolute-file composition.
21
21
  They do not create a root boundary around arbitrary caller input; prefer
22
22
  `root()` for untrusted paths.
23
+ The handle resolver verifies exact descriptor and pathname identities, with one
24
+ bounded retry for unknown Windows observations. It borrows the handle without
25
+ reading, reopening, closing it, or changing its cursor.
23
26
 
24
27
  The error helpers are `categorizeFsSafeError` and `FsSafeErrorDetails`. The
25
28
  deprecated native-configuration bridge retains the `FsSafePythonConfig` type.
@@ -135,6 +138,8 @@ The durability surface also exports the synchronous strict
135
138
  `Sha256FileSyncInput`, `Sha256FileOptions`, and `Sha256FileResult`.
136
139
  `sha256FileSync()` provides synchronous pathname or borrowed-descriptor hashing
137
140
  with the same byte-budget and digest-result contracts as `sha256File()`.
141
+ `DirectoryReceipt<T>` accepts `Stats` or `BigIntStats` input metadata; its default
142
+ type argument and returned durability receipts remain numeric `Stats`.
138
143
 
139
144
  ## Archives
140
145
 
@@ -60,7 +60,7 @@ await fs.move("notes/today.txt", "notes/archive/today.txt", { overwrite: true })
60
60
  await fs.remove("notes/archive/today.txt");
61
61
  ```
62
62
 
63
- `move()` defaults to no clobber. That mode requires the native helper so a concurrent target cannot be replaced between an absence check and the rename; without it, the call fails with `helper-unavailable`. Pass `{ overwrite: true }` when replacing the target is intentional. `remove()` works on files and empty directories. For non-empty directories, list and remove children first or use [`replaceDirectoryAtomic`](atomic.md#replacedirectoryatomic).
63
+ `move()` defaults to no clobber. That mode requires the native helper so a concurrent target cannot be replaced between an absence check and the rename; without it, the call fails with `helper-unavailable`. Pass `{ overwrite: true }` when replacing the target is intentional. `remove()` removes files and empty directories by default. To remove a non-empty directory, pass `{ recursive: true }`; use `maxEntries`, `maxDepth`, and `signal` to bound the work. See [`root()`](root.md) for removal ordering, limits, and partial-removal semantics.
64
64
 
65
65
  ## 5. Inspect
66
66
 
package/docs/reading.md CHANGED
@@ -28,7 +28,7 @@ Regardless of shape, every read goes through the same boundary checks:
28
28
  4. Reject `..` traversal and absolute spellings when they resolve outside the root. In-root absolute spellings remain accepted; `readAbsolute` makes that intent explicit.
29
29
  5. Open with `O_NOFOLLOW` where available. Any remaining symlink in the path triggers `symlink` unless the call's `symlinks` policy is `follow-within-root`.
30
30
  6. Compare the pre-open bigint path identity with the open fd, then perform one best-effort final admission: check the captured root identity, compare the policy-aware pathname with the fd, freshly canonicalize and re-admit that target inside the captured root, compare its exact bigint identity without following a final symlink with the fd, and check the root again. Both final pathname observations run even when their spellings match. An observed swap triggers `path-mismatch` or `outside-workspace`; a missing final path triggers `not-found`.
31
- 7. If `hardlinks: "reject"`, refuse files with `nlink > 1` (`hardlink`).
31
+ 7. If `hardlinks: "reject"`, refuse files with `nlink > 1` (`hardlink`), including links introduced before either fresh final pathname observation. Root-file helpers apply the same final check when `rejectHardlinks` is enabled; directory admission is unaffected.
32
32
  8. If `maxBytes` is set, refuse reads larger than the cap (`too-large`).
33
33
 
34
34
  The final fence closes a rejected descriptor before any Root read consumes bytes or
@@ -100,7 +100,7 @@ type RootReadOptions = {
100
100
  hardlinks?: "reject" | "allow"; // override defaults.hardlinks
101
101
  maxBytes?: number; // refuse reads larger than this many bytes
102
102
  nonBlockingRead?: boolean; // compatibility hint; safe opens are already nonblocking where supported
103
- symlinks?: "reject" | "follow-within-root"; // override defaults.symlinks
103
+ symlinks?: "reject" | "follow-within-root" | "follow-parents-within-root"; // override defaults.symlinks
104
104
  };
105
105
  ```
106
106
 
@@ -110,6 +110,9 @@ descriptor, and current pathname identities remain exact bigints through the
110
110
  append boundary; rounded-equal replacements and persistent unknown Windows
111
111
  identities reject before chmod or writing bytes. With
112
112
  `rejectSymlinkParents: true`, it also rejects symlinked ancestor directories.
113
+ Supported option values are captured once before filesystem work, so replacing
114
+ the content, encoding, mode or cap cannot change an in-flight append. Byte-array
115
+ contents remain caller-owned; leave them unchanged until the append completes.
113
116
 
114
117
  On POSIX, `O_NONBLOCK` prevents a no-reader FIFO substituted before open from
115
118
  stalling admission. A confirmed non-regular target is refused before chmod or
package/docs/root.md CHANGED
@@ -49,6 +49,10 @@ Every `maxBytes` value must be a non-negative safe integer or positive `Infinity
49
49
 
50
50
  Every method on the returned handle accepts paths relative to the root and rejects anything that would escape it.
51
51
 
52
+ Explicit path, data, and copy-source arguments select the operation. Properties
53
+ with those names in an options object do not replace them; a supplied source
54
+ Root retains ownership of source admission and read policy.
55
+
52
56
  ### Reads
53
57
 
54
58
  ```ts
@@ -167,6 +171,8 @@ cleanup, and filesystem requirements.
167
171
  `append` accepts `prependNewlineIfNeeded: true` to separate text from existing
168
172
  content when neither side supplies a newline. String data uses its `encoding`
169
173
  for the newline check, including UTF-16LE; Buffer data uses a single LF byte.
174
+ Empty strings and Buffers add no separator; an empty append still creates a
175
+ missing file.
170
176
 
171
177
  These five methods and `copyIn` also accept `durable?: boolean`: the per-call value overrides
172
178
  `Root.defaults.durable`, which defaults to `true` when omitted. An explicitly
@@ -308,6 +314,13 @@ from that dispatch. A thrown value rejects the operation unchanged; an async
308
314
  or thenable-returning callback rejects with `TypeError` before that mutation.
309
315
  Synchronous return values are ignored. Callbacks can run multiple times and
310
316
  must inspect current authority each time.
317
+ Directory creation rechecks the retained parent after the callback and before
318
+ submitting mkdir, so a replacement is rejected before creating that component.
319
+ Overwrite moves recheck the retained root, parents, source identity and both
320
+ routes after the callback, including destination parents that were missing
321
+ during preparation. Removals recheck cancellation, retained ancestry and exact
322
+ leaf identity before dispatch; `force` tolerates a missing leaf, not replaced
323
+ ancestry. Removing an admitted hardlink still leaves its other names intact.
311
324
 
312
325
  Already dispatched I/O cannot be revoked. Identity-checked cleanup, final
313
326
  permissions, and durability finish under the existing operation owner even
@@ -408,6 +421,12 @@ fs.rootWithSep // rootReal with a trailing separator, for prefix comparisons
408
421
  fs.defaults // the RootDefaults you passed
409
422
  ```
410
423
 
424
+ The path properties are readonly metadata. Each Root retains the canonical
425
+ directory and exact identity admitted when it was created; changing object
426
+ properties is not a supported way to retarget it. Create another Root to use a
427
+ different directory. The `defaults` reference is readonly, while the supplied
428
+ object's option values remain live for later calls.
429
+
411
430
  ## Failure semantics
412
431
 
413
432
  Boundary and policy failures throw `FsSafeError` with a `code`. Parsing callbacks
@@ -113,6 +113,10 @@ If an already validated descriptor fails while reading, both readers throw an
113
113
  operational `FsSafeError` with `code: "read-failed"`; inspect `cause` for the
114
114
  underlying Node filesystem code such as `EIO`.
115
115
 
116
+ A synchronous reader closes its descriptor once. A close failure preserves an
117
+ earlier read or identity-validation error; after a successful read, the close
118
+ failure is reported before trimming or rejecting empty content.
119
+
116
120
  Use the async strict reader when a service cannot start safely without the
117
121
  credential:
118
122
 
@@ -55,6 +55,7 @@ invocation is not mutation authority. A failing final parser keeps its error
55
55
  even if guard ownership has also changed.
56
56
  `manager.reset()` invalidates admission bookkeeping but preserves a pending
57
57
  Root guard; let its original attempt settle before retrying that guarded path.
58
+ It stops compromise monitoring for forgotten holders, including callbacks from checks already in flight.
58
59
 
59
60
  Always release locks in a `finally` block. Application-managed graceful shutdown can await `release()` or `manager.drain()` before terminating. Explicit `process.exit()`, uncaught failures, crashes, default signal handling, and fatal termination (including `SIGKILL`) do not reliably run asynchronous Root cleanup and may leave sidecars. Recover only after an application-owned liveness policy proves the holder cannot still be writing.
60
61
 
@@ -64,7 +65,7 @@ Each new sidecar also carries an internal random ownership token encoded as JSON
64
65
 
65
66
  The raw sidecar bytes are not a canonical JSON representation: tools that trim or rewrite the trailing whitespace invalidate the ownership token, so release leaves the changed sidecar in place and fails closed. The token distinguishes cooperating acquisitions; it is not a secret and does not make pathname compare-and-remove atomic against a hostile process that can replace files outside the lock protocol.
66
67
 
67
- `release()` propagates an I/O failure that prevents deletion of an unchanged, owned sidecar; it never reports successful cleanup while leaving that lock behind. The handle and manager retain the exact cleanup receipt after a failure, so the same handle can retry `release()` and `manager.drain()` can retry retained cleanup. A changed sidecar remains an ownership mismatch rather than a deletion failure and is left untouched. If both a `withFileLock()` callback and release fail, the release error is the primary `SuppressedError.error` and the callback failure remains available as `SuppressedError.suppressed`. Failed asynchronous acquisition cleanup uses the same shape, with the cleanup error primary and the acquisition failure suppressed. On Node runtimes without the global `SuppressedError` constructor, fs-safe returns the equivalent `Error` shape with the same name and properties.
68
+ `release()` propagates an I/O failure that prevents deletion of an unchanged, owned sidecar; it never reports successful cleanup while leaving that lock behind. The handle and manager retain the exact cleanup receipt after a failure, so the same handle can retry `release()` and `manager.drain()` can retry retained cleanup. A changed sidecar remains an ownership mismatch rather than a deletion failure and is left untouched. If both a `withFileLock()` or `withFileLockSync()` callback and release fail, the release error is the primary `SuppressedError.error` and the callback failure remains available as `SuppressedError.suppressed`. Failed asynchronous acquisition cleanup uses the same shape, with the cleanup error primary and the acquisition failure suppressed. On Node runtimes without the global `SuppressedError` constructor, fs-safe returns the equivalent `Error` shape with the same name and properties.
68
69
 
69
70
  ## API
70
71
 
@@ -336,6 +337,12 @@ sidecar no longer matches or after a verification I/O failure. This is
336
337
  detection, not revocation of work already in progress. Asynchronous checks are
337
338
  serialized, so a slow verification never overlaps the next timer tick.
338
339
 
340
+ Ownership-only checks compare serialized bytes, tokens, and file identities
341
+ without decoding an unused default JSON payload. Stale-policy reads still
342
+ decode the payload. Explicit `parsePayload` callbacks keep their existing
343
+ verification and asynchronous-cleanup calls, receivers, and errors;
344
+ synchronous release continues without invoking a custom parser.
345
+
339
346
  The compromise-check interval is validated before payload evaluation or
340
347
  filesystem acquisition. Omit it or pass `0` to disable monitoring; enabled
341
348
  intervals must be finite and between 1 and 2,147,483,647 milliseconds. Values
@@ -438,6 +445,7 @@ error.
438
445
  The sync payload, reclaim, and parsing callbacks must also be synchronous. This
439
446
  shape is appropriate for a short boot migration; it is a poor fit for a server
440
447
  request because retry backoff uses a blocking wait.
448
+ Synchronous `shouldReclaim` and `shouldRemoveStaleLock` reject Promise or thenable results with `TypeError` before deleting the observed sidecar; an asynchronous result is never approval.
441
449
 
442
450
  If termination skips the relevant cleanup handler or cleanup fails, the sidecar remains. In particular, `process.exit()` skips asynchronous Root cleanup; await explicit release or drain during application-managed graceful shutdown. Once `staleMs` elapses (or your `shouldReclaim` returns true), acquisition fails closed by default instead of deleting by path.
443
451
 
@@ -49,7 +49,7 @@ remain with the caller.
49
49
 
50
50
  ```ts
51
51
  function stageFileInDirectory(options: {
52
- directory: string | DirectoryReceipt;
52
+ directory: string | DirectoryReceipt<Stats | BigIntStats>;
53
53
  content: string | Uint8Array;
54
54
  mode?: number;
55
55
  }): Promise<StagedFile>;
@@ -81,8 +81,9 @@ Creation uses an exclusive, no-follow, close-on-exec open of a generated direct
81
81
  child name. Writes use that descriptor. Inspection uses non-following metadata
82
82
  operations, never a potentially blocking reopen of the leaf.
83
83
 
84
- A supplied directory receipt must still match at admission. Its numeric
85
- identity must be exactly representable; ambiguous identity fails closed.
84
+ A supplied directory receipt must still match at admission. Caller receipts can
85
+ carry numeric `Stats` or exact `BigIntStats`; untracked numeric identities must
86
+ be exactly representable. Ambiguous identity fails closed.
86
87
  Returned receipts are frozen descriptive snapshots, not mutable authority.
87
88
  Changing a supplied receipt after admission cannot retarget the lifecycle.
88
89
 
package/docs/store.md CHANGED
@@ -89,7 +89,9 @@ claim before publication. If another consumer acknowledged, quarantined, or
89
89
  replaced that claim, the migration rejects with `FsSafeError("path-mismatch")`
90
90
  and leaves the newer generation or failed evidence intact. A stale migration
91
91
  rejects both single and batch loads; ordinary callback failures retain their
92
- existing single-load rejection and batch-skip behavior.
92
+ existing single-load rejection and batch-skip behavior. A caller or migration
93
+ error with code `ENOENT` is still a failure, not a missing queue entry; only a
94
+ claim that is absent or disappears before reading returns `null` from a single load.
93
95
 
94
96
  On Windows, migration releases its read pin once at this publication boundary
95
97
  because an open target can block replacement. It rechecks the exact pathname
package/docs/temp.md CHANGED
@@ -155,12 +155,15 @@ uses guarded pathname-recursive removal. This fallback never recursively
155
155
  removes the public workspace name, but it is not atomic conditional deletion: a
156
156
  same-privilege peer that discovers and replaces the private quarantine after
157
157
  verification can still redirect the final pathname removal.
158
+ If admitting a cleanup parent fails and closing its descriptor also fails,
159
+ creation rejects with both failures in an `AggregateError`. This does not select
160
+ compatible fallback or retry the indeterminate descriptor close.
158
161
 
159
162
  Set `cleanupSafety: "require-bounded"` when that concurrent attacker is in scope.
160
163
  Creation then requires native no-replace directory rename, native owned-tree
161
164
  removal, and a readable retained parent descriptor **before** child creation.
162
165
  On POSIX, the final requested `dirMode` must also include owner read
163
- and search (`(dirMode & 0o500) === 0o500`). Preflight failure throws
166
+ and search (`(dirMode & 0o500) === 0o500`). An unavailable capability throws
164
167
  `FsSafeError("helper-unavailable")` without creating a child or calling a scoped
165
168
  callback. The child descriptor is opened
166
169
  while the new directory still has its private creation mode, before an explicit
package/docs/types.md CHANGED
@@ -128,6 +128,8 @@ type RootOptions = {
128
128
  ## `RootReadOptions` / `RootWriteOptions` / `RootCopyOptions`
129
129
 
130
130
  ```ts
131
+ import type { CopyCloneMode, RootCopyPublicationReceipt } from "@openclaw/fs-safe";
132
+
131
133
  type RootReadOptions = Pick<RootDefaults, "hardlinks" | "maxBytes" | "nonBlockingRead" | "symlinks">;
132
134
  type RootWriteOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "durable" | "mkdir" | "mode" | "renameIdentity" | "mutationSymlinks"> & {
133
135
  encoding?: BufferEncoding;
@@ -135,6 +137,11 @@ type RootWriteOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutatio
135
137
  };
136
138
  type RootCopyOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "durable" | "maxBytes" | "mkdir" | "mode" | "mutationSymlinks"> & {
137
139
  sourceHardlinks?: "reject" | "allow";
140
+ overwrite?: boolean;
141
+ clone?: CopyCloneMode;
142
+ signal?: AbortSignal;
143
+ preserveSourceMode?: boolean;
144
+ onDestinationPublished?: (receipt: RootCopyPublicationReceipt) => void;
138
145
  };
139
146
  type RootOpenWritableOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "mkdir" | "mode" | "mutationSymlinks"> & {
140
147
  writeMode?: "replace" | "append" | "update";
@@ -150,8 +157,17 @@ type RootAppendOptions = RootWriteOptions & {
150
157
  type RootMoveOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "mutationSymlinks"> & {
151
158
  overwrite?: boolean;
152
159
  };
153
- type RootRemoveOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "mutationSymlinks">;
154
- type RootMkdirOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "mutationSymlinks">;
160
+ type RootRemoveOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "mutationSymlinks"> & {
161
+ recursive?: boolean;
162
+ force?: boolean;
163
+ order?: "filesystem" | "sorted";
164
+ maxEntries?: number;
165
+ maxDepth?: number;
166
+ signal?: AbortSignal;
167
+ };
168
+ type RootMkdirOptions = Pick<RootDefaults, "assertBeforeMutation" | "denyMutations" | "mutationSymlinks"> & {
169
+ private?: boolean;
170
+ };
155
171
  ```
156
172
 
157
173
  Per-method option shapes. Each picks the `RootDefaults` keys that apply, plus method-specific extras.
package/docs/walk.md CHANGED
@@ -47,6 +47,10 @@ type WalkDirectoryFailure = {
47
47
 
48
48
  `depth` starts at `1` for direct children of `rootDir`. `relativePath` is always relative to the supplied root. `scannedEntryCount` counts directory entries examined, including entries filtered out by `include`.
49
49
 
50
+ Each entry's `path` is absolute and retains the normalized spelling of the
51
+ supplied root, including followed directory aliases. Paths do not switch to
52
+ the canonical symlink target during descent.
53
+
50
54
  `walkDirectory()` and `walkDirectorySync()` always return `failedDirs`; the property remains optional on the exported `WalkDirectoryResult` type so existing callers that manually construct the legacy result shape remain source-compatible. It lists every directory whose `realpath`/`readdir` threw, so its contents are absent from `entries`. `error` is the thrown value (a `NodeJS.ErrnoException` at runtime), so callers can distinguish a benign missing-directory race (`ENOENT`) from a real read failure (`EACCES`, `EIO`, `ESTALE`, …). The walk-root failure has an empty `relativePath` and `depth: 0`. Failures resolving a symlink's target kind are not reported here.
51
55
 
52
56
  ## Options
@@ -227,6 +231,9 @@ its exact identity, and rechecks it and the Root identity around each metadata
227
231
  batch or individual filesystem-order observation. Sorted batches contain no
228
232
  await or caller code between their before/after checks. It tracks canonical
229
233
  directories to stop symlink cycles.
234
+ Directory rechecks retain exact identities while using ordinary numeric metadata
235
+ when it represents those identities without rounding. Large identities and
236
+ Windows unknown-identity retries keep the bigint inspection path.
230
237
  Neither mode holds a descriptor for every path component, so it is not a process sandbox against a hostile peer that
231
238
  can continuously swap and restore directories. Each individual lookup retains
232
239
  the documented Node `Root` boundary checks.
package/docs/writing.md CHANGED
@@ -45,8 +45,14 @@ wrong file. Resolve an intended alias explicitly with `Root.resolve()` before
45
45
  passing its canonical path to a mutation.
46
46
 
47
47
  A failure before the final rename leaves the destination at its previous
48
- contents. A successful rename publishes the complete replacement. This
49
- old-or-new guarantee does not apply to `append()` or `openWritable()`, which
48
+ contents. A successful rename publishes the complete replacement. Buffered
49
+ Windows replacement writes also keep a missing destination absent while staging;
50
+ they do not reserve an empty file at the final name. An ordinary writable file created
51
+ concurrently may be replaced under `overwrite: true`. Immediately before rename,
52
+ the writer rechecks the selected destination's type and link count, admits a raced
53
+ file's access, and verifies retained file/parent identities and mutation policy.
54
+
55
+ The old-or-new guarantee does not apply to `append()` or `openWritable()`, which
50
56
  write in place, or to lower-level atomic helpers when their explicitly
51
57
  non-atomic permission-error copy fallback is enabled.
52
58
 
@@ -154,11 +160,17 @@ claimed exclusively first and content is written afterward, so observers can
154
160
  briefly see an empty file; failure cleanup removes a claimed file only when its
155
161
  identity is unchanged.
156
162
 
163
+ After a successful create-only write, failure to close its owned file handle
164
+ rejects the operation and leaves the complete file present. Ordinary buffered
165
+ creation in the JavaScript fallback preserves an earlier write or verification
166
+ failure if close also fails. Native, atomic, and streamed creation retain their
167
+ existing publication and cleanup diagnostics.
168
+
157
169
  ```ts
158
170
  try {
159
171
  await fs.create("config/seed.json", initial);
160
172
  } catch (err) {
161
- if (err instanceof FsSafeError && err.code !== "already-exists") throw err;
173
+ if (!(err instanceof FsSafeError) || err.code !== "already-exists") throw err;
162
174
  }
163
175
  ```
164
176
 
@@ -201,7 +213,8 @@ already published complete destination. See [receipt meanings](staged-file.md).
201
213
 
202
214
  Pass an `AsyncIterable<Uint8Array>` to `create()` when bytes come from a database,
203
215
  network response, or another incremental producer. Buffers are accepted chunks.
204
- The writer consumes each chunk completely before requesting the next one; it
216
+ The writer borrows `Uint8Array` slices without copying their payloads and counts
217
+ their actual byte bounds. It consumes each chunk completely before requesting the next one; it
205
218
  does not collect the full input in memory or expose a writable descriptor.
206
219
 
207
220
  ```ts
@@ -603,7 +616,7 @@ await fs.write("state.json", body); // succeeds on rclone FUSE
603
616
 
604
617
  **Security note.** `verify-content-with-lock` proves that the bytes observed after rename match the requested write and prevents *cooperating* writers from interleaving. It does **not** prove that the destination still names the temp-file object, retain fd-relative parent pinning, or stop a same-UID process that ignores the advisory lock. Do not use this option on directories writable by untrusted same-UID processes. Strict identity verification remains the default.
605
618
 
606
- Windows `Root.write()` and `Root.writeJson()` honor this policy both as a Root default and as a per-call option. The Windows buffered writer acquires the same Root compatibility lock before creating parents, placeholders, or content. It keeps staging writable until publication, then applies the final mode through the retained destination descriptor. When content verification accepts a changed rename identity, that destination remains pinned through file sync, parent sync, and final strict identity checks.
619
+ Windows `Root.write()` and `Root.writeJson()` honor this policy both as a Root default and as a per-call option. The Windows buffered writer acquires the same Root compatibility lock before creating parents or staging content. It keeps staging writable until publication, then applies the final mode through the retained destination descriptor. When content verification accepts a changed rename identity, that destination remains pinned through file sync, parent sync, and final strict identity checks.
607
620
 
608
621
  The Windows buffered compatibility path resolves permitted in-root aliases before choosing its lock and binds publication to that effective destination. With the existing lock protocol, effective path components beneath the Root must contain only lower-case ASCII letters, digits, `.`, `_`, or `-`, with no trailing `.`. Unsupported spellings, including missing upper-case or non-ASCII names, fail with `path-alias` before mutation; no filesystem case-sensitivity or Unicode-folding behavior is guessed. This restriction does not apply to strict writes. Opaque Windows pathname identities still use strict verification against the retained original descriptor: they never, by themselves, authorize content-based acceptance of a replacement.
609
622
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/fs-safe",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "Capability-style filesystem roots for Node.js apps that handle untrusted relative paths.",
5
5
  "keywords": [
6
6
  "filesystem",
@@ -29,7 +29,6 @@
29
29
  "dist/windows-security-bridge.ps1",
30
30
  "dist/**/*.js",
31
31
  "dist/**/*.d.ts",
32
- "dist/**/*.d.ts.map",
33
32
  "docs/**/*.md",
34
33
  "docs/assets/readme-banner.jpg",
35
34
  "README.md",
@@ -170,13 +169,13 @@
170
169
  "archive:producer-smoke": "node scripts/archive-producer-smoke.mjs"
171
170
  },
172
171
  "optionalDependencies": {
173
- "@openclaw/fs-safe-darwin-arm64": "0.16.0",
174
- "@openclaw/fs-safe-darwin-x64": "0.16.0",
175
- "@openclaw/fs-safe-linux-arm64-gnu": "0.16.0",
176
- "@openclaw/fs-safe-linux-arm64-musl": "0.16.0",
177
- "@openclaw/fs-safe-linux-x64-gnu": "0.16.0",
178
- "@openclaw/fs-safe-linux-x64-musl": "0.16.0",
179
- "@openclaw/fs-safe-win32-x64-msvc": "0.16.0",
172
+ "@openclaw/fs-safe-darwin-arm64": "0.18.0",
173
+ "@openclaw/fs-safe-darwin-x64": "0.18.0",
174
+ "@openclaw/fs-safe-linux-arm64-gnu": "0.18.0",
175
+ "@openclaw/fs-safe-linux-arm64-musl": "0.18.0",
176
+ "@openclaw/fs-safe-linux-x64-gnu": "0.18.0",
177
+ "@openclaw/fs-safe-linux-x64-musl": "0.18.0",
178
+ "@openclaw/fs-safe-win32-x64-msvc": "0.18.0",
180
179
  "jszip": "^3.10.2"
181
180
  },
182
181
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"absolute-path.d.ts","sourceRoot":"","sources":["../src/absolute-path.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAUhE,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAU5D,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,GAAG;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAmL7D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAchE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnF;AA4BD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,6BAA6B,CAAC,CA+ExC;AAED,wBAAsB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBzF;AAED,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,4BAA4B,CAAC,CA2BvC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,eAAe,EAAE,mBAAmB,EAAE,cAAc,EACpD,KAAK,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,KAAK,uBAAuB,GAClF,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAC/G,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,EAAE,4BAA4B,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,KAAK,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAC1G,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,2BAA2B,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,GAClC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EACL,6BAA6B,EAC7B,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,6BAA6B,EAClC,KAAK,oCAAoC,GAC1C,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,wBAAwB,EACxB,kCAAkC,EAClC,eAAe,EACf,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,yBAAyB,EACzB,SAAS,EACT,8BAA8B,EAC9B,qBAAqB,EACrB,sBAAsB,EACtB,oCAAoC,EACpC,6BAA6B,EAC7B,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,KAAK,6BAA6B,GACnC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,6BAA6B,EAC7B,eAAe,EACf,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,QAAQ,EACb,QAAQ,EACR,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,2BAA2B,EAC3B,mBAAmB,EACnB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"archive-crc32.d.ts","sourceRoot":"","sources":["../src/archive-crc32.ts"],"names":[],"mappings":"AAYA,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOpE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"archive-deadline.d.ts","sourceRoot":"","sources":["../src/archive-deadline.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,sBAAsB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACjE,2BAA2B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAsB,gCAAgC,CAAC,CAAC,EACtD,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAWD,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAST;AAED,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAuDD,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GAChD,OAAO,CAAC,CAAC,CAAC,CAkBZ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"archive-durability.d.ts","sourceRoot":"","sources":["../src/archive-durability.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAI9B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMtC,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,MAAM,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC1C,CAAC;AACF,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,UAAU,EAAE,IAAI,CAAC;IACjB,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,WAAW,EAAE,qBAAqB,CAAC;IACnC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACvC,WAAW,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,GAAG,OAAO,CAAC,IAAI,CAAC,CA4FhB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"archive-entry.d.ts","sourceRoot":"","sources":["../src/archive-entry.ts"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,IAAI,CAgEN;AAGD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1F;AAED,wBAAgB,8BAA8B,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAgBlG;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAWT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"archive-errors.d.ts","sourceRoot":"","sources":["../src/archive-errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAE9D,MAAM,MAAM,wBAAwB,GAChC,2BAA2B,GAC3B,qBAAqB,GACrB,+BAA+B,GAC/B,gBAAgB,GAChB,YAAY,GACZ,YAAY,CAAC;AAEjB,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IAExC,YAAY,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAIlF;CACF;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IAEtC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAIlD;CACF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKpE;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErE"}