@openclaw/fs-safe 0.9.0 → 0.11.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 (326) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/LICENSE +1 -0
  3. package/README.md +52 -4
  4. package/dist/absolute-path.d.ts.map +1 -1
  5. package/dist/absolute-path.js +3 -2
  6. package/dist/advanced.d.ts +5 -0
  7. package/dist/advanced.d.ts.map +1 -1
  8. package/dist/advanced.js +5 -0
  9. package/dist/archive-crc32.d.ts.map +1 -1
  10. package/dist/archive-crc32.js +6 -1
  11. package/dist/archive-deadline.d.ts.map +1 -1
  12. package/dist/archive-deadline.js +3 -4
  13. package/dist/archive-durability.d.ts +6 -6
  14. package/dist/archive-durability.d.ts.map +1 -1
  15. package/dist/archive-durability.js +1 -1
  16. package/dist/archive-entry.d.ts.map +1 -1
  17. package/dist/archive-entry.js +4 -5
  18. package/dist/archive-gzip-tail.d.ts +3 -0
  19. package/dist/archive-gzip-tail.d.ts.map +1 -1
  20. package/dist/archive-gzip-tail.js +23 -3
  21. package/dist/archive-input.d.ts.map +1 -1
  22. package/dist/archive-input.js +4 -2
  23. package/dist/archive-merge.d.ts +5 -1
  24. package/dist/archive-merge.d.ts.map +1 -1
  25. package/dist/archive-merge.js +16 -13
  26. package/dist/archive-native.d.ts.map +1 -1
  27. package/dist/archive-native.js +7 -6
  28. package/dist/archive-parser.wasm +0 -0
  29. package/dist/archive-read.d.ts.map +1 -1
  30. package/dist/archive-read.js +83 -74
  31. package/dist/archive-staging.d.ts +6 -3
  32. package/dist/archive-staging.d.ts.map +1 -1
  33. package/dist/archive-staging.js +42 -22
  34. package/dist/archive-tar-stream.d.ts +11 -4
  35. package/dist/archive-tar-stream.d.ts.map +1 -1
  36. package/dist/archive-tar-stream.js +23 -10
  37. package/dist/archive-tar-wasm.d.ts.map +1 -1
  38. package/dist/archive-tar-wasm.js +18 -14
  39. package/dist/archive-zip-admission.d.ts +1 -1
  40. package/dist/archive-zip-admission.d.ts.map +1 -1
  41. package/dist/archive-zip-admission.js +48 -12
  42. package/dist/archive-zip-loader.d.ts +6 -0
  43. package/dist/archive-zip-loader.d.ts.map +1 -0
  44. package/dist/archive-zip-loader.js +38 -0
  45. package/dist/archive-zip-names.d.ts.map +1 -1
  46. package/dist/archive-zip-names.js +13 -8
  47. package/dist/archive-zip-preflight.d.ts +2 -3
  48. package/dist/archive-zip-preflight.d.ts.map +1 -1
  49. package/dist/archive-zip-preflight.js +2 -34
  50. package/dist/archive.d.ts.map +1 -1
  51. package/dist/archive.js +12 -10
  52. package/dist/bounded-read.d.ts +12 -0
  53. package/dist/bounded-read.d.ts.map +1 -1
  54. package/dist/bounded-read.js +82 -45
  55. package/dist/clone-metadata.d.ts +19 -0
  56. package/dist/clone-metadata.d.ts.map +1 -0
  57. package/dist/clone-metadata.js +32 -0
  58. package/dist/copy-file-input.d.ts +22 -0
  59. package/dist/copy-file-input.d.ts.map +1 -0
  60. package/dist/copy-file-input.js +69 -0
  61. package/dist/copy-policy.d.ts +3 -0
  62. package/dist/copy-policy.d.ts.map +1 -0
  63. package/dist/copy-policy.js +8 -0
  64. package/dist/copy-publication.d.ts +10 -1
  65. package/dist/copy-publication.d.ts.map +1 -1
  66. package/dist/copy-publication.js +27 -0
  67. package/dist/copy-tree-portable.d.ts +9 -0
  68. package/dist/copy-tree-portable.d.ts.map +1 -0
  69. package/dist/copy-tree-portable.js +222 -0
  70. package/dist/copy.d.ts +16 -0
  71. package/dist/copy.d.ts.map +1 -0
  72. package/dist/copy.js +125 -0
  73. package/dist/directory-durability.d.ts.map +1 -1
  74. package/dist/directory-durability.js +5 -4
  75. package/dist/directory-guard.d.ts +11 -1
  76. package/dist/directory-guard.d.ts.map +1 -1
  77. package/dist/directory-guard.js +53 -11
  78. package/dist/durability.d.ts +1 -1
  79. package/dist/durability.d.ts.map +1 -1
  80. package/dist/durability.js +1 -1
  81. package/dist/error-detail.d.ts.map +1 -1
  82. package/dist/error-detail.js +4 -1
  83. package/dist/file-handle-transfer.d.ts +14 -0
  84. package/dist/file-handle-transfer.d.ts.map +1 -0
  85. package/dist/file-handle-transfer.js +64 -0
  86. package/dist/file-hash.d.ts +9 -2
  87. package/dist/file-hash.d.ts.map +1 -1
  88. package/dist/file-hash.js +135 -39
  89. package/dist/file-lock-sync.d.ts.map +1 -1
  90. package/dist/file-lock-sync.js +8 -4
  91. package/dist/file-store-boundary.d.ts.map +1 -1
  92. package/dist/file-store-boundary.js +7 -5
  93. package/dist/file-store-path.d.ts +3 -0
  94. package/dist/file-store-path.d.ts.map +1 -0
  95. package/dist/file-store-path.js +27 -0
  96. package/dist/file-store-prune.d.ts.map +1 -1
  97. package/dist/file-store-prune.js +6 -4
  98. package/dist/file-store-sync-write.d.ts.map +1 -1
  99. package/dist/file-store-sync-write.js +56 -44
  100. package/dist/file-store.d.ts.map +1 -1
  101. package/dist/file-store.js +2 -18
  102. package/dist/filename.d.ts.map +1 -1
  103. package/dist/filename.js +4 -13
  104. package/dist/guarded-mkdir.d.ts +1 -0
  105. package/dist/guarded-mkdir.d.ts.map +1 -1
  106. package/dist/guarded-mkdir.js +4 -2
  107. package/dist/guarded-mutation.d.ts +2 -0
  108. package/dist/guarded-mutation.d.ts.map +1 -1
  109. package/dist/guarded-mutation.js +8 -4
  110. package/dist/guest-dispatch-python.d.ts +2 -0
  111. package/dist/guest-dispatch-python.d.ts.map +1 -0
  112. package/dist/guest-dispatch-python.js +117 -0
  113. package/dist/guest-native-python.d.ts +4 -0
  114. package/dist/guest-native-python.d.ts.map +1 -0
  115. package/dist/guest-native-python.js +135 -0
  116. package/dist/guest.d.ts +9 -0
  117. package/dist/guest.d.ts.map +1 -0
  118. package/dist/guest.js +413 -0
  119. package/dist/home-dir.d.ts.map +1 -1
  120. package/dist/home-dir.js +9 -7
  121. package/dist/index.d.ts +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/install-path.d.ts.map +1 -1
  124. package/dist/install-path.js +5 -8
  125. package/dist/json-durable-queue-directory.js +3 -3
  126. package/dist/json-durable-queue.d.ts.map +1 -1
  127. package/dist/json-durable-queue.js +19 -18
  128. package/dist/json.d.ts.map +1 -1
  129. package/dist/json.js +2 -1
  130. package/dist/local-roots.d.ts.map +1 -1
  131. package/dist/local-roots.js +24 -25
  132. package/dist/move-path-stage.d.ts +8 -0
  133. package/dist/move-path-stage.d.ts.map +1 -0
  134. package/dist/move-path-stage.js +56 -0
  135. package/dist/move-path.d.ts.map +1 -1
  136. package/dist/move-path.js +30 -34
  137. package/dist/mutation-authority.d.ts +9 -0
  138. package/dist/mutation-authority.d.ts.map +1 -0
  139. package/dist/mutation-authority.js +36 -0
  140. package/dist/native-binding.d.ts +29 -1
  141. package/dist/native-binding.d.ts.map +1 -1
  142. package/dist/native-operations.d.ts +1 -1
  143. package/dist/native-operations.d.ts.map +1 -1
  144. package/dist/native-operations.js +11 -5
  145. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  146. package/dist/native-pinned-write-windows.js +19 -7
  147. package/dist/native-pinned-write.d.ts.map +1 -1
  148. package/dist/native-pinned-write.js +3 -1
  149. package/dist/native-staged-file.d.ts +3 -3
  150. package/dist/native-staged-file.d.ts.map +1 -1
  151. package/dist/native-staged-file.js +35 -8
  152. package/dist/opened-realpath.d.ts.map +1 -1
  153. package/dist/opened-realpath.js +5 -4
  154. package/dist/output.d.ts +2 -0
  155. package/dist/output.d.ts.map +1 -1
  156. package/dist/output.js +2 -0
  157. package/dist/overwrite-file-handle.d.ts +8 -0
  158. package/dist/overwrite-file-handle.d.ts.map +1 -0
  159. package/dist/overwrite-file-handle.js +42 -0
  160. package/dist/path-case.d.ts +7 -0
  161. package/dist/path-case.d.ts.map +1 -0
  162. package/dist/path-case.js +136 -0
  163. package/dist/path.d.ts.map +1 -1
  164. package/dist/path.js +5 -2
  165. package/dist/permissions-windows.d.ts +1 -1
  166. package/dist/permissions-windows.d.ts.map +1 -1
  167. package/dist/permissions-windows.js +85 -53
  168. package/dist/pinned-open.d.ts.map +1 -1
  169. package/dist/pinned-open.js +3 -1
  170. package/dist/pinned-operation.js +1 -1
  171. package/dist/pinned-write.d.ts +7 -3
  172. package/dist/pinned-write.d.ts.map +1 -1
  173. package/dist/pinned-write.js +51 -30
  174. package/dist/positional-read.d.ts +9 -0
  175. package/dist/positional-read.d.ts.map +1 -0
  176. package/dist/positional-read.js +36 -0
  177. package/dist/private-temp-workspace.d.ts.map +1 -1
  178. package/dist/private-temp-workspace.js +6 -4
  179. package/dist/publish-copy-stage.d.ts +13 -0
  180. package/dist/publish-copy-stage.d.ts.map +1 -0
  181. package/dist/publish-copy-stage.js +47 -0
  182. package/dist/publish-file.d.ts.map +1 -1
  183. package/dist/publish-file.js +6 -5
  184. package/dist/realpath.d.ts +4 -0
  185. package/dist/realpath.d.ts.map +1 -0
  186. package/dist/realpath.js +43 -0
  187. package/dist/recursive-mkdir-path.d.ts +3 -0
  188. package/dist/recursive-mkdir-path.d.ts.map +1 -0
  189. package/dist/recursive-mkdir-path.js +8 -0
  190. package/dist/replace-directory.d.ts.map +1 -1
  191. package/dist/replace-directory.js +2 -1
  192. package/dist/replace-file-copy-fallback.d.ts.map +1 -1
  193. package/dist/replace-file-copy-fallback.js +23 -31
  194. package/dist/replace-file-copy-source.d.ts.map +1 -1
  195. package/dist/replace-file-copy-source.js +7 -12
  196. package/dist/replace-file-mode.d.ts +3 -0
  197. package/dist/replace-file-mode.d.ts.map +1 -0
  198. package/dist/replace-file-mode.js +10 -0
  199. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  200. package/dist/replace-file-temp-owner.js +6 -2
  201. package/dist/replace-file.d.ts +1 -0
  202. package/dist/replace-file.d.ts.map +1 -1
  203. package/dist/replace-file.js +14 -8
  204. package/dist/root-context.d.ts +3 -0
  205. package/dist/root-context.d.ts.map +1 -1
  206. package/dist/root-context.js +53 -28
  207. package/dist/root-create-input.d.ts +10 -0
  208. package/dist/root-create-input.d.ts.map +1 -0
  209. package/dist/root-create-input.js +80 -0
  210. package/dist/root-directory-list.d.ts +26 -0
  211. package/dist/root-directory-list.d.ts.map +1 -0
  212. package/dist/root-directory-list.js +219 -0
  213. package/dist/root-entries.d.ts +11 -0
  214. package/dist/root-entries.d.ts.map +1 -0
  215. package/dist/root-entries.js +61 -0
  216. package/dist/root-errors.d.ts +6 -5
  217. package/dist/root-errors.d.ts.map +1 -1
  218. package/dist/root-errors.js +16 -12
  219. package/dist/root-file.d.ts +2 -0
  220. package/dist/root-file.d.ts.map +1 -1
  221. package/dist/root-file.js +12 -4
  222. package/dist/root-impl.d.ts +17 -51
  223. package/dist/root-impl.d.ts.map +1 -1
  224. package/dist/root-impl.js +358 -234
  225. package/dist/root-options.d.ts +77 -0
  226. package/dist/root-options.d.ts.map +1 -0
  227. package/dist/root-options.js +18 -0
  228. package/dist/root-path-existing.d.ts +5 -0
  229. package/dist/root-path-existing.d.ts.map +1 -1
  230. package/dist/root-path-existing.js +59 -3
  231. package/dist/root-path-symlink.d.ts.map +1 -1
  232. package/dist/root-path-symlink.js +3 -2
  233. package/dist/root-path.d.ts +1 -0
  234. package/dist/root-path.d.ts.map +1 -1
  235. package/dist/root-path.js +74 -162
  236. package/dist/root-paths.d.ts.map +1 -1
  237. package/dist/root-paths.js +13 -9
  238. package/dist/root-remove.d.ts +5 -0
  239. package/dist/root-remove.d.ts.map +1 -0
  240. package/dist/root-remove.js +286 -0
  241. package/dist/root-symlink-policy.d.ts +14 -0
  242. package/dist/root-symlink-policy.d.ts.map +1 -0
  243. package/dist/root-symlink-policy.js +34 -0
  244. package/dist/root-walk.d.ts +5 -4
  245. package/dist/root-walk.d.ts.map +1 -1
  246. package/dist/root-walk.js +99 -50
  247. package/dist/root-write-mode.d.ts.map +1 -1
  248. package/dist/root-write-mode.js +3 -5
  249. package/dist/root.d.ts +4 -1
  250. package/dist/root.d.ts.map +1 -1
  251. package/dist/secret-file.d.ts.map +1 -1
  252. package/dist/secret-file.js +2 -1
  253. package/dist/secret-read-async.d.ts.map +1 -1
  254. package/dist/secret-read-async.js +2 -1
  255. package/dist/secure-file.d.ts.map +1 -1
  256. package/dist/secure-file.js +25 -8
  257. package/dist/secure-temp-dir.d.ts.map +1 -1
  258. package/dist/secure-temp-dir.js +2 -1
  259. package/dist/sibling-staged-file.d.ts +1 -0
  260. package/dist/sibling-staged-file.d.ts.map +1 -1
  261. package/dist/sibling-staged-file.js +42 -8
  262. package/dist/sibling-temp.d.ts +2 -0
  263. package/dist/sibling-temp.d.ts.map +1 -1
  264. package/dist/sibling-temp.js +6 -4
  265. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  266. package/dist/sidecar-lock-acquire.js +17 -5
  267. package/dist/sidecar-lock-policy.d.ts +2 -0
  268. package/dist/sidecar-lock-policy.d.ts.map +1 -1
  269. package/dist/sidecar-lock-policy.js +20 -1
  270. package/dist/staged-directory.d.ts.map +1 -1
  271. package/dist/staged-directory.js +4 -3
  272. package/dist/temp-cleanup.d.ts.map +1 -1
  273. package/dist/temp-cleanup.js +3 -2
  274. package/dist/temp-target.d.ts +14 -12
  275. package/dist/temp-target.d.ts.map +1 -1
  276. package/dist/temp-target.js +12 -6
  277. package/dist/timing.d.ts +1 -0
  278. package/dist/timing.d.ts.map +1 -1
  279. package/dist/timing.js +25 -6
  280. package/dist/trash.d.ts.map +1 -1
  281. package/dist/trash.js +9 -7
  282. package/dist/unicode-path.d.ts +3 -0
  283. package/dist/unicode-path.d.ts.map +1 -0
  284. package/dist/unicode-path.js +13 -0
  285. package/dist/walk.d.ts.map +1 -1
  286. package/dist/walk.js +9 -28
  287. package/dist/windows-owner.d.ts +9 -12
  288. package/dist/windows-owner.d.ts.map +1 -1
  289. package/dist/windows-owner.js +24 -58
  290. package/dist/write-file-handle.d.ts +7 -0
  291. package/dist/write-file-handle.d.ts.map +1 -0
  292. package/dist/write-file-handle.js +26 -0
  293. package/docs/advanced.md +22 -4
  294. package/docs/archive.md +44 -9
  295. package/docs/atomic.md +24 -1
  296. package/docs/config.md +1 -0
  297. package/docs/contributing.md +36 -1
  298. package/docs/copy.md +155 -0
  299. package/docs/directory-identity.md +85 -0
  300. package/docs/durability.md +53 -3
  301. package/docs/entries.md +109 -0
  302. package/docs/errors.md +4 -4
  303. package/docs/file-store.md +15 -0
  304. package/docs/guest.md +141 -0
  305. package/docs/in-place-write.md +81 -0
  306. package/docs/index.md +2 -0
  307. package/docs/install.md +31 -0
  308. package/docs/local-roots.md +8 -1
  309. package/docs/native-helper.md +10 -3
  310. package/docs/native.md +18 -1
  311. package/docs/output.md +32 -6
  312. package/docs/path-case.md +64 -0
  313. package/docs/path-scope.md +1 -1
  314. package/docs/permissions.md +29 -10
  315. package/docs/positional-read.md +63 -0
  316. package/docs/public-api.md +31 -2
  317. package/docs/root.md +196 -6
  318. package/docs/secure-file.md +2 -0
  319. package/docs/security-model.md +14 -0
  320. package/docs/sidecar-lock.md +12 -3
  321. package/docs/temp.md +35 -6
  322. package/docs/timing.md +2 -0
  323. package/docs/types.md +19 -12
  324. package/docs/walk.md +54 -5
  325. package/docs/writing.md +173 -5
  326. package/package.json +19 -8
@@ -1,9 +1,11 @@
1
1
  import { syncFileBestEffortSync } from "./file-sync.js";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import fsSync, {} from "node:fs";
4
+ import path from "node:path";
4
5
  import { FsSafeError } from "./errors.js";
5
6
  import { nativeOpenFlags, removeNativeCreatedFileIfStillPinned, writeNativeInput, } from "./native-operations.js";
6
7
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
8
+ import { assertFinalSymlinkRejected } from "./root-symlink-policy.js";
7
9
  export function sameNativeIdentity(left, right) {
8
10
  return left.dev === right.dev && left.ino === right.ino;
9
11
  }
@@ -27,6 +29,7 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
27
29
  let completed = false;
28
30
  try {
29
31
  tempName = `.fs-safe-${randomUUID()}.tmp`;
32
+ params.assertBeforeMutation?.();
30
33
  tempFd = binding.openBeneath(parentFd, tempName, nativeOpenFlags(fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_EXCL)).fd;
31
34
  const verificationIdentity = inspectFileIdentitySync(() => fsSync.fstatSync(tempFd, { bigint: true }));
32
35
  tempIdentity = verificationIdentity;
@@ -34,9 +37,13 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
34
37
  // can remove owner access. Keep the unpublished inode private and
35
38
  // reopenable until the published name has been identity-fenced.
36
39
  fsSync.fchmodSync(tempFd, 0o600);
37
- await writeNativeInput(tempFd, params.input, params.maxBytes);
40
+ await writeNativeInput(tempFd, params.input, params.maxBytes, params.assertBeforeMutation);
38
41
  if (params.sync !== false)
39
42
  syncFileBestEffortSync(tempFd);
43
+ if (params.input.kind === "file")
44
+ await params.input.verifySource();
45
+ assertFinalSymlinkRejected(path.join(parentPath, params.basename), params.rejectFinalSymlink);
46
+ params.assertBeforeMutation?.();
40
47
  if (params.overwrite === false) {
41
48
  binding.renameNoReplace(parentFd, tempName, parentFd, params.basename);
42
49
  }
@@ -44,6 +51,7 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
44
51
  binding.renameReplace(parentFd, tempName, parentFd, params.basename);
45
52
  }
46
53
  renamed = true;
54
+ params.onPublished?.(verificationIdentity);
47
55
  targetFd = binding.openBeneath(parentFd, params.basename, nativeOpenFlags(fsSync.constants.O_RDONLY)).fd;
48
56
  const targetStat = inspectFileIdentitySync(() => fsSync.fstatSync(targetFd, { bigint: true }), verificationIdentity);
49
57
  const targetIdentity = binding.fstatIdentity(targetFd);
@@ -61,12 +69,16 @@ export async function runPinnedWriteWindows(binding, params, root, parentFd, par
61
69
  catch (error) {
62
70
  closeWriteFd(targetFd);
63
71
  targetFd = undefined;
64
- removeNativeCreatedFileIfStillPinned({
65
- parentPath,
66
- parentFd,
67
- basename: params.basename,
68
- created: tempIdentity,
69
- });
72
+ // Staged copies and streamed creates preserve publication for caller recovery.
73
+ if (params.input.kind === "buffer" ||
74
+ (params.input.kind === "stream" && !params.input.stageBeforePublish)) {
75
+ removeNativeCreatedFileIfStillPinned({
76
+ parentPath,
77
+ parentFd,
78
+ basename: params.basename,
79
+ created: tempIdentity,
80
+ });
81
+ }
70
82
  throw error;
71
83
  }
72
84
  if (params.sync !== false)
@@ -1 +1 @@
1
- {"version":3,"file":"native-pinned-write.d.ts","sourceRoot":"","sources":["../src/native-pinned-write.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA0FvH"}
1
+ {"version":3,"file":"native-pinned-write.d.ts","sourceRoot":"","sources":["../src/native-pinned-write.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAK3D,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2FvH"}
@@ -59,6 +59,7 @@ import { runPinnedWriteWindows, sameNativeIdentity } from "./native-pinned-write
59
59
  import { assertNativeStaging, writeNativeStage } from "./native-staged-file.js";
60
60
  import { describeStagedDirectory, exactIdentityMatches } from "./staged-directory.js";
61
61
  import { inspectFileIdentitySync } from "./strict-file-identity.js";
62
+ import { realpathSync } from "./realpath.js";
62
63
  export async function runPinnedWriteNative(binding, params) {
63
64
  const env_1 = { stack: [], error: void 0, hasError: false };
64
65
  try {
@@ -100,10 +101,11 @@ export async function runPinnedWriteNative(binding, params) {
100
101
  throw new FsSafeError("path-mismatch", "root path changed during native write");
101
102
  }
102
103
  if (params.mkdir) {
104
+ params.assertBeforeMutation?.();
103
105
  binding.mkdirBeneath(root.fd, params.relativeParentPath, 0o777);
104
106
  }
105
107
  parentFd = binding.openBeneath(root.fd, params.relativeParentPath, directoryFlags).fd;
106
- const parentPath = fsSync.realpathSync.native(params.relativeParentPath
108
+ const parentPath = realpathSync.native(params.relativeParentPath
107
109
  ? path.join(params.rootPath, ...params.relativeParentPath.split("/"))
108
110
  : params.rootPath);
109
111
  const directory = windows ? undefined : describeStagedDirectory(parentFd, parentPath);
@@ -8,14 +8,14 @@ export type NativeStagingBinding = NativeBinding & Required<Pick<NativeBinding,
8
8
  export declare function assertNativeStaging(binding: NativeBinding): asserts binding is NativeStagingBinding;
9
9
  declare class NativeStagedFile implements StagedFile {
10
10
  #private;
11
- constructor(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], portableNames: boolean, publishedMode: number, sync: boolean);
12
- static create(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], input: PinnedWriteInput, mode: number, maxBytes?: number, portableNames?: boolean, sync?: boolean): Promise<NativeStagedFile>;
11
+ constructor(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], portableNames: boolean, publishedMode: number, sync: boolean, assertBeforeMutation?: () => void);
12
+ static create(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], input: PinnedWriteInput, mode: number, maxBytes?: number, portableNames?: boolean, sync?: boolean, assertBeforeMutation?: () => void): Promise<NativeStagedFile>;
13
13
  static write(binding: NativeStagingBinding, parentFd: number, directory: StagedFileReceipt["directory"], params: PinnedWriteParams, parentGuard: AnyAsyncDirectoryGuard): Promise<FileIdentityStat>;
14
14
  get receipt(): StagedFileReceipt;
15
15
  assertCurrent(): Promise<void>;
16
16
  publish(basename: string, options: {
17
17
  overwrite: boolean;
18
- }): Promise<PublishedFileReceipt>;
18
+ }, onPublished?: PinnedWriteParams["onPublished"]): Promise<PublishedFileReceipt>;
19
19
  cleanup(): Promise<StagedFileCleanupReceipt>;
20
20
  [Symbol.asyncDispose](): Promise<void>;
21
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"native-staged-file.d.ts","sourceRoot":"","sources":["../src/native-staged-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAKlE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,EACV,wBAAwB,EAGxB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG,QAAQ,CAAC,IAAI,CAC9D,aAAa,EACb,kBAAkB,GAAG,mBAAmB,GAAG,kBAAkB,CAC9D,CAAC,CAAC;AAEH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,IAAI,oBAAoB,CAUnG;AA6BD,cAAM,gBAAiB,YAAW,UAAU;;IAW1C,YACE,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,OAAO,EAQd;IAGD,OAAa,MAAM,CACjB,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAEjB,aAAa,UAAO,EACpB,IAAI,UAAO,GACV,OAAO,CAAC,gBAAgB,CAAC,CAc3B;IAED,OAAa,KAAK,CAChB,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAU3B;IAED,IAAI,OAAO,IAAI,iBAAiB,CAK/B;IAoFK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAEK,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqD9F;IA6CK,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAMjD;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAO3C;CACF;AAED,eAAO,MAAM,iBAAiB,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,UAAU,CAClF,CAAC;AAC1B,eAAO,MAAM,gBAAgB,+BAAyB,CAAC;AAEvD,YAAY,EACV,oBAAoB,EAAE,UAAU,EAAE,wBAAwB,EAAE,wBAAwB,EACpF,qBAAqB,EAAE,iBAAiB,GACzC,MAAM,wBAAwB,CAAC;AAEhC,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACrC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,UAAU,CAAC,CAUtB"}
1
+ {"version":3,"file":"native-staged-file.d.ts","sourceRoot":"","sources":["../src/native-staged-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAMlE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,EACV,wBAAwB,EAGxB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG,QAAQ,CAAC,IAAI,CAC9D,aAAa,EACb,kBAAkB,GAAG,mBAAmB,GAAG,kBAAkB,CAC9D,CAAC,CAAC;AAEH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,IAAI,oBAAoB,CAUnG;AA6BD,cAAM,gBAAiB,YAAW,UAAU;;IAa1C,YACE,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,OAAO,EACb,oBAAoB,CAAC,EAAE,MAAM,IAAI,EASlC;IAGD,OAAa,MAAM,CACjB,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAEjB,aAAa,UAAO,EACpB,IAAI,UAAO,EACX,oBAAoB,CAAC,EAAE,MAAM,IAAI,GAChC,OAAO,CAAC,gBAAgB,CAAC,CAc3B;IAED,OAAa,KAAK,CAChB,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,EACzC,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAc3B;IAED,IAAI,OAAO,IAAI,iBAAiB,CAK/B;IA8FK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAEK,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,EAC/B,WAAW,CAAC,EAAE,iBAAiB,CAAC,aAAa,CAAC,GAC7C,OAAO,CAAC,oBAAoB,CAAC,CAyD/B;IA6CK,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAMjD;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAO3C;CACF;AAED,eAAO,MAAM,iBAAiB,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,UAAU,CAClF,CAAC;AAC1B,eAAO,MAAM,gBAAgB,+BAAyB,CAAC;AAEvD,YAAY,EACV,oBAAoB,EAAE,UAAU,EAAE,wBAAwB,EAAE,wBAAwB,EACpF,qBAAqB,EAAE,iBAAiB,GACzC,MAAM,wBAAwB,CAAC;AAEhC,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACrC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,UAAU,CAAC,CAUtB"}
@@ -54,9 +54,13 @@ import { requireNativeBinding } from "./native.js";
54
54
  import { syncFileBestEffortSync } from "./file-sync.js";
55
55
  import { randomUUID } from "node:crypto";
56
56
  import fs from "node:fs";
57
+ import path from "node:path";
57
58
  import { FsSafeError } from "./errors.js";
59
+ import { MutationAuthorityError } from "./mutation-authority.js";
58
60
  import { writeNativeInput } from "./native-operations.js";
61
+ import { assertNativeCopyCompleted, createNativeCopyFile } from "./copy-file-input.js";
59
62
  import { assertStagedDirectoryCurrent, openStagedDirectory } from "./staged-directory.js";
63
+ import { assertFinalSymlinkRejected } from "./root-symlink-policy.js";
60
64
  export function assertNativeStaging(binding) {
61
65
  if ([
62
66
  binding.createStagedFile,
@@ -93,24 +97,27 @@ class NativeStagedFile {
93
97
  #portableNames;
94
98
  #publishedMode;
95
99
  #sync;
100
+ #assertBeforeMutation;
96
101
  #name = `.fs-safe-${randomUUID()}.tmp`;
97
102
  #state = { status: "open", publication: NOT_PUBLISHED };
98
103
  #receipt;
99
- constructor(binding, parentFd, directory, portableNames, publishedMode, sync) {
104
+ #rejectFinalSymlink = false;
105
+ constructor(binding, parentFd, directory, portableNames, publishedMode, sync, assertBeforeMutation) {
100
106
  this.#binding = binding;
101
107
  this.#parentFd = parentFd;
102
108
  this.#directory = directory;
103
109
  this.#portableNames = portableNames;
104
110
  this.#publishedMode = publishedMode;
105
111
  this.#sync = sync;
112
+ this.#assertBeforeMutation = assertBeforeMutation;
106
113
  }
107
114
  // Takes ownership of parentFd, including all construction and preparation failures.
108
115
  static async create(binding, parentFd, directory, input, mode, maxBytes,
109
116
  // Public staging uses portable names; existing POSIX writes accept literal names.
110
- portableNames = true, sync = true) {
117
+ portableNames = true, sync = true, assertBeforeMutation) {
111
118
  let staged;
112
119
  try {
113
- staged = new NativeStagedFile(binding, parentFd, directory, portableNames, mode, sync);
120
+ staged = new NativeStagedFile(binding, parentFd, directory, portableNames, mode, sync, assertBeforeMutation);
114
121
  }
115
122
  catch (error) {
116
123
  try {
@@ -129,8 +136,11 @@ class NativeStagedFile {
129
136
  try {
130
137
  // This owner never escapes. Only the internal verifier borrows its fd;
131
138
  // public descriptor methods remain await-free and cannot race disposal.
132
- const staged = __addDisposableResource(env_1, await NativeStagedFile.create(binding, parentFd, directory, params.input, params.mode, params.maxBytes, false, params.sync), true);
133
- const published = await staged.publish(params.basename, { overwrite: params.overwrite !== false });
139
+ const staged = __addDisposableResource(env_1, await NativeStagedFile.create(binding, parentFd, directory, params.input, params.mode, params.maxBytes, false, params.sync, params.assertBeforeMutation), true);
140
+ staged.#rejectFinalSymlink = params.rejectFinalSymlink === true;
141
+ if (params.input.kind === "file")
142
+ await params.input.verifySource();
143
+ const published = await staged.publish(params.basename, { overwrite: params.overwrite !== false }, params.onPublished);
134
144
  const identity = published.staged.identity;
135
145
  await params.verifyPublished?.(staged.#file(), identity, parentGuard);
136
146
  return { dev: identity.dev, ino: identity.ino };
@@ -190,10 +200,22 @@ class NativeStagedFile {
190
200
  // The exclusive open performs no fallible post-open checks. Store its fd
191
201
  // before every subsequent operation, including the first metadata read.
192
202
  const state = this.#open();
193
- state.fileFd = this.#binding.createStagedFile(this.#parentFd, this.#name);
203
+ this.#assertBeforeMutation?.();
204
+ const copied = input.kind === "file"
205
+ ? await createNativeCopyFile(this.#binding, input, this.#parentFd, this.#name, maxBytes, false)
206
+ : undefined;
207
+ state.fileFd = copied?.fd;
208
+ if (state.fileFd === undefined) {
209
+ this.#assertBeforeMutation?.();
210
+ state.fileFd = this.#binding.createStagedFile(this.#parentFd, this.#name);
211
+ }
194
212
  const fd = state.fileFd;
213
+ if (input.kind === "file")
214
+ assertNativeCopyCompleted(input, copied);
215
+ this.#assertBeforeMutation?.();
195
216
  fs.fchmodSync(fd, 0o600);
196
- await writeNativeInput(fd, input, maxBytes);
217
+ if (!copied)
218
+ await writeNativeInput(fd, input, maxBytes, this.#assertBeforeMutation);
197
219
  if (this.#sync)
198
220
  syncFileBestEffortSync(fd);
199
221
  const stat = fs.fstatSync(fd, { bigint: true });
@@ -230,7 +252,7 @@ class NativeStagedFile {
230
252
  async assertCurrent() {
231
253
  this.#assertCurrent();
232
254
  }
233
- async publish(basename, options) {
255
+ async publish(basename, options, onPublished) {
234
256
  const overwrite = options?.overwrite;
235
257
  try {
236
258
  const state = this.#open();
@@ -239,6 +261,8 @@ class NativeStagedFile {
239
261
  throw new FsSafeError("invalid-path", "publication needs a distinct basename and explicit overwrite policy");
240
262
  }
241
263
  this.#assertCurrent();
264
+ assertFinalSymlinkRejected(path.join(this.#directory.realPath, basename), this.#rejectFinalSymlink);
265
+ this.#assertBeforeMutation?.();
242
266
  try {
243
267
  if (overwrite) {
244
268
  this.#binding.renameReplace(this.#parentFd, this.#name, this.#parentFd, basename);
@@ -262,6 +286,7 @@ class NativeStagedFile {
262
286
  overwrite,
263
287
  });
264
288
  state.publication = receipt;
289
+ onPublished?.(receipt.staged.identity);
265
290
  const stagedMode = this.#assertNamed(basename);
266
291
  assertStagedDirectoryCurrent(this.#directory);
267
292
  // Keep contents private until the published name passes its identity
@@ -282,6 +307,8 @@ class NativeStagedFile {
282
307
  return receipt;
283
308
  }
284
309
  catch (error) {
310
+ if (error instanceof MutationAuthorityError)
311
+ throw error;
285
312
  // Closure rejects further use, not the recorded outcome of an earlier publication.
286
313
  const publication = this.#state.status === "closed"
287
314
  ? this.#state.receipt.publication
@@ -1 +1 @@
1
- {"version":3,"file":"opened-realpath.d.ts","sourceRoot":"","sources":["../src/opened-realpath.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG7E,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACxC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AACpD,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,gBAAgB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;CAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"opened-realpath.d.ts","sourceRoot":"","sources":["../src/opened-realpath.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI7E,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACxC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AACpD,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,gBAAgB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;CAAE,CAAC,CAAC"}
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { openedPathResolutionError } from "./opened-file-failure.js";
5
5
  import { sameFileIdentity } from "./file-identity.js";
6
6
  import { isNotFoundPathError } from "./path.js";
7
+ import { realpathSync } from "./realpath.js";
7
8
  export async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
8
9
  const handleStat = fsSync.fstatSync(handle.fd);
9
10
  return (await resolveOpenedFileRealPathForFd(handle.fd, handleStat, ioPath)).realPath;
@@ -16,7 +17,7 @@ export async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
16
17
  : [];
17
18
  for (const fdPath of fdCandidates) {
18
19
  try {
19
- const fdRealPath = fsSync.realpathSync.native(fdPath);
20
+ const fdRealPath = realpathSync.native(fdPath);
20
21
  const fdRealStat = statOptions ? fsSync.statSync(fdRealPath, statOptions) : fsSync.statSync(fdRealPath);
21
22
  if (sameFileIdentity(handleStat, fdRealStat)) {
22
23
  return { realPath: fdRealPath, stat: fdRealStat };
@@ -27,7 +28,7 @@ export async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
27
28
  }
28
29
  }
29
30
  try {
30
- const ioRealPath = fsSync.realpathSync.native(ioPath);
31
+ const ioRealPath = realpathSync.native(ioPath);
31
32
  const ioRealStat = statOptions ? fsSync.statSync(ioRealPath, statOptions) : fsSync.statSync(ioRealPath);
32
33
  if (sameFileIdentity(handleStat, ioRealStat)) {
33
34
  return { realPath: ioRealPath, stat: ioRealStat };
@@ -53,7 +54,7 @@ export async function resolveOpenedFileRealPathForFd(fd, handleStat, ioPath) {
53
54
  async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptions) {
54
55
  let parentReal;
55
56
  try {
56
- parentReal = fsSync.realpathSync.native(path.dirname(ioPath));
57
+ parentReal = realpathSync.native(path.dirname(ioPath));
57
58
  }
58
59
  catch (err) {
59
60
  if (isNotFoundPathError(err)) {
@@ -76,7 +77,7 @@ async function resolveOpenedFileRealPathFromParent(handleStat, ioPath, statOptio
76
77
  try {
77
78
  const candidateStat = statOptions ? fsSync.lstatSync(candidatePath, statOptions) : fsSync.lstatSync(candidatePath);
78
79
  if (candidateStat.isFile() && sameFileIdentity(handleStat, candidateStat)) {
79
- const realPath = fsSync.realpathSync.native(candidatePath);
80
+ const realPath = realpathSync.native(candidatePath);
80
81
  const stat = statOptions ? fsSync.statSync(realPath, statOptions) : fsSync.statSync(realPath);
81
82
  if (sameFileIdentity(handleStat, stat))
82
83
  return { realPath, stat };
package/dist/output.d.ts CHANGED
@@ -5,6 +5,8 @@ export type ExternalFileWriteOptions<T = void> = {
5
5
  maxBytes?: number;
6
6
  mode?: number;
7
7
  staging?: "workspace" | "sibling";
8
+ /** Isolate sibling producers; workspace staging is already private. */
9
+ producerIsolation?: "private-directory";
8
10
  fallbackFileName?: string;
9
11
  };
10
12
  export type ExternalFileWriteResult<T = void> = {
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,wBAAwB,CAAC,CAAC,GAAG,IAAI,IAAI;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,IAAI,IAAI;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,CAAC;CACX,CAAC;AAyDF,wBAAsB,2BAA2B,CAAC,CAAC,GAAG,IAAI,EACxD,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAgDrC"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,wBAAwB,CAAC,CAAC,GAAG,IAAI,IAAI;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAClC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,IAAI,IAAI;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,CAAC;CACX,CAAC;AAyDF,wBAAsB,2BAA2B,CAAC,CAAC,GAAG,IAAI,EACxD,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAiDrC"}
package/dist/output.js CHANGED
@@ -74,6 +74,7 @@ export async function writeExternalFileWithinRoot(options) {
74
74
  const result = await writeExternalFileViaSibling({
75
75
  finalPath: siblingFinalPath,
76
76
  write: options.write,
77
+ producerIsolation: options.producerIsolation,
77
78
  fallbackFileName: options.fallbackFileName,
78
79
  maxBytes,
79
80
  mode: options.mode,
@@ -113,6 +114,7 @@ async function writeExternalFileViaSibling(params) {
113
114
  const { result } = await writeCallbackSibling({
114
115
  tempPath: buildSiblingTempPath(finalPath, params.fallbackFileName),
115
116
  write: params.write,
117
+ producerIsolation: params.producerIsolation,
116
118
  resolveFinalPath: () => finalPath,
117
119
  mode: params.mode,
118
120
  maxBytes: params.maxBytes,
@@ -0,0 +1,8 @@
1
+ import type { FileHandle } from "node:fs/promises";
2
+ export type OverwriteFileHandleOptions = {
3
+ /** Admit the whole write once, after rollback preparation and before any mutation. */
4
+ beforeWrite?: () => void;
5
+ };
6
+ /** Overwrite a borrowed, non-append read/write handle with best-effort failure rollback. */
7
+ export declare function overwriteFileHandle(handle: FileHandle, data: Uint8Array, options?: OverwriteFileHandleOptions): Promise<void>;
8
+ //# sourceMappingURL=overwrite-file-handle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overwrite-file-handle.d.ts","sourceRoot":"","sources":["../src/overwrite-file-handle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMnD,MAAM,MAAM,0BAA0B,GAAG;IACvC,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAEF,4FAA4F;AAC5F,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -0,0 +1,42 @@
1
+ import { FsSafeError } from "./errors.js";
2
+ import { assertSynchronousCallbackResult } from "./mutation-authority.js";
3
+ import { readFileWindowFully } from "./positional-read.js";
4
+ import { writeAllToFile } from "./write-file-handle.js";
5
+ /** Overwrite a borrowed, non-append read/write handle with best-effort failure rollback. */
6
+ export async function overwriteFileHandle(handle, data, options = {}) {
7
+ const payload = data.subarray(0, data.byteLength);
8
+ const payloadBytes = payload.byteLength;
9
+ const stat = await handle.stat();
10
+ if (!stat.isFile()) {
11
+ throw new FsSafeError("not-file", "overwrite handle must be a regular file");
12
+ }
13
+ const originalSize = stat.size;
14
+ if (!Number.isSafeInteger(originalSize) || originalSize < 0) {
15
+ throw new RangeError("file size must be a non-negative safe integer");
16
+ }
17
+ const prefixBytes = Math.min(payloadBytes, originalSize);
18
+ const originalPrefix = Buffer.allocUnsafe(prefixBytes);
19
+ if (await readFileWindowFully(handle, originalPrefix, 0) !== prefixBytes) {
20
+ throw new FsSafeError("read-failed", "file ended before overwrite rollback preparation completed");
21
+ }
22
+ assertSynchronousCallbackResult(options.beforeWrite?.(), "beforeWrite");
23
+ let prefixStarted = false;
24
+ try {
25
+ // Leave existing bytes intact until any additional storage has been written.
26
+ if (payloadBytes > originalSize) {
27
+ await writeAllToFile(handle, payload.subarray(originalSize), { position: originalSize });
28
+ }
29
+ prefixStarted = true;
30
+ await writeAllToFile(handle, payload.subarray(0, prefixBytes), { position: 0 });
31
+ if (payloadBytes < originalSize) {
32
+ await handle.truncate(payloadBytes);
33
+ }
34
+ }
35
+ catch (error) {
36
+ if (prefixStarted) {
37
+ await writeAllToFile(handle, originalPrefix, { position: 0 }).catch(() => undefined);
38
+ }
39
+ await handle.truncate(originalSize).catch(() => undefined);
40
+ throw error;
41
+ }
42
+ }
@@ -0,0 +1,7 @@
1
+ export type ProbePathCaseOptions = {
2
+ /** Allow an exclusively created empty probe when existing entries provide no answer. Defaults to true. */
3
+ allowTemporaryProbe?: boolean;
4
+ };
5
+ /** Observe local ASCII case behavior; unknown observations never imply an operating-system default. */
6
+ export declare function probePathCaseInsensitiveSync(targetPath: string, options?: ProbePathCaseOptions): boolean | undefined;
7
+ //# sourceMappingURL=path-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-case.d.ts","sourceRoot":"","sources":["../src/path-case.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,oBAAoB,GAAG;IACjC,0GAA0G;IAC1G,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAmFF,uGAAuG;AACvG,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,oBAAyB,GACjC,OAAO,GAAG,SAAS,CAqCrB"}
@@ -0,0 +1,136 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs, {} from "node:fs";
3
+ import path from "node:path";
4
+ import { assertDirectoryIdentitySync, inspectDirectoryIdentitySync } from "./directory-guard.js";
5
+ import { sameFileIdentityForCleanup } from "./file-identity.js";
6
+ import { isNotFoundPathError } from "./path.js";
7
+ import { realpathSync } from "./realpath.js";
8
+ import { writeTempFileSync } from "./replace-file-descriptor.js";
9
+ import { SyncAtomicTempOwner } from "./replace-file-temp-owner.js";
10
+ import { inspectFileIdentitySync } from "./strict-file-identity.js";
11
+ function swapAsciiCase(value) {
12
+ return value.replace(/[A-Za-z]/g, character => {
13
+ const lower = character.toLowerCase();
14
+ return character === lower ? character.toUpperCase() : lower;
15
+ });
16
+ }
17
+ function probeEntry(directory, name, names) {
18
+ const alternate = swapAsciiCase(name);
19
+ if (alternate === name)
20
+ return undefined;
21
+ const bothListed = names.has(name) && names.has(alternate);
22
+ const originalPath = path.join(directory, name);
23
+ let original;
24
+ let observed;
25
+ try {
26
+ original = inspectFileIdentitySync(() => fs.lstatSync(originalPath, { bigint: true }));
27
+ try {
28
+ const other = inspectFileIdentitySync(() => fs.lstatSync(path.join(directory, alternate), { bigint: true }));
29
+ const sameIdentity = sameFileIdentityForCleanup(original, other);
30
+ if (sameIdentity || bothListed) {
31
+ // Matching inodes can belong to newly linked case-distinct names.
32
+ const currentNames = new Set(fs.readdirSync(directory));
33
+ const bothCurrent = currentNames.has(name) && currentNames.has(alternate);
34
+ if (bothListed && !bothCurrent)
35
+ return undefined;
36
+ observed = sameIdentity && !bothCurrent;
37
+ }
38
+ else {
39
+ observed = false;
40
+ }
41
+ }
42
+ catch (error) {
43
+ if (bothListed || !isNotFoundPathError(error))
44
+ return undefined;
45
+ observed = false;
46
+ }
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ // Disappearance during lookup is not evidence that case variants are distinct.
52
+ inspectFileIdentitySync(() => fs.lstatSync(originalPath, { bigint: true }), original);
53
+ return observed;
54
+ }
55
+ function probeTemporaryEntry(directory) {
56
+ const name = `.fs-safe-case-probe-${randomUUID()}`;
57
+ const owner = new SyncAtomicTempOwner(path.join(directory, name));
58
+ try {
59
+ owner.start();
60
+ owner.adopt(writeTempFileSync({
61
+ fsModule: fs,
62
+ tempPath: owner.pathname,
63
+ content: "",
64
+ mode: 0o600,
65
+ sync: false,
66
+ onIdentity: owner.onIdentity,
67
+ }));
68
+ owner.assertCurrent(fs);
69
+ const observed = probeEntry(directory, name, new Set(fs.readdirSync(directory)));
70
+ owner.assertCurrent(fs);
71
+ return observed;
72
+ }
73
+ finally {
74
+ // Failed cleanup invalidates the observation; the existing owner retains its exit retry.
75
+ owner.finish({ fsModule: fs, throwOnCleanupError: true });
76
+ }
77
+ }
78
+ function probeDirectory(directory, allowTemporaryProbe, preferredName) {
79
+ const canonical = realpathSync.native(directory);
80
+ const identity = inspectDirectoryIdentitySync(canonical);
81
+ const names = new Set(fs.readdirSync(canonical));
82
+ let observed = preferredName === undefined ? undefined : probeEntry(canonical, preferredName, names);
83
+ for (const name of names) {
84
+ if (observed !== undefined)
85
+ break;
86
+ observed = probeEntry(canonical, name, names);
87
+ }
88
+ if (observed === undefined && allowTemporaryProbe)
89
+ observed = probeTemporaryEntry(canonical);
90
+ assertDirectoryIdentitySync(canonical, identity);
91
+ return realpathSync.native(directory) === canonical ? observed : undefined;
92
+ }
93
+ /** Observe local ASCII case behavior; unknown observations never imply an operating-system default. */
94
+ export function probePathCaseInsensitiveSync(targetPath, options = {}) {
95
+ const resolved = path.resolve(targetPath);
96
+ const allowTemporaryProbe = options.allowTemporaryProbe !== false;
97
+ let targetExists = true;
98
+ try {
99
+ fs.lstatSync(resolved);
100
+ }
101
+ catch (error) {
102
+ if (!isNotFoundPathError(error))
103
+ return undefined;
104
+ targetExists = false;
105
+ }
106
+ if (targetExists) {
107
+ try {
108
+ return probeDirectory(path.dirname(resolved), allowTemporaryProbe, path.basename(resolved));
109
+ }
110
+ catch {
111
+ return undefined;
112
+ }
113
+ }
114
+ let directory = path.dirname(resolved);
115
+ for (;;) {
116
+ let exists = false;
117
+ try {
118
+ exists = fs.statSync(directory).isDirectory();
119
+ }
120
+ catch {
121
+ // A missing or unreadable component can still have a readable existing ancestor.
122
+ }
123
+ if (exists) {
124
+ try {
125
+ return probeDirectory(directory, allowTemporaryProbe);
126
+ }
127
+ catch {
128
+ return undefined;
129
+ }
130
+ }
131
+ const parent = path.dirname(directory);
132
+ if (parent === directory)
133
+ return undefined;
134
+ directory = parent;
135
+ }
136
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAMzB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC;AAM1B,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWvE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAI1E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,SAA6B,GAAG,IAAI,CAIjG;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CA4BlE;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAa/F;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChE,OAAO,CAUT;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG,IAAI,CAMhE;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BpE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAOrF"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC;AAM1B,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWvE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAI1E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,SAA6B,GAAG,IAAI,CAIjG;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CA8BlE;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAa/F;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChE,OAAO,CAUT;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG,IAAI,CAMhE;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BpE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAOrF"}
package/dist/path.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { FsSafeError } from "./errors.js";
4
+ import { realpathSync } from "./realpath.js";
4
5
  import { isDriveRelativePath } from "./safe-path-segment.js";
5
6
  export { assertNoUnsafeDeviceReadPath, isUnsafeDeviceReadPath, matchUnsafeDeviceReadPath, } from "./device-path.js";
6
7
  const NOT_FOUND_CODES = new Set(["ENOENT", "ENOTDIR"]);
@@ -49,7 +50,9 @@ export function isPathInside(root, target) {
49
50
  target.charCodeAt(0) === POSIX_SEPARATOR_CHAR_CODE &&
50
51
  !target.includes("/..") &&
51
52
  (target === root ||
52
- (target.startsWith(root) && target.charCodeAt(root.length) === POSIX_SEPARATOR_CHAR_CODE))) {
53
+ (target.startsWith(root) &&
54
+ (root.charCodeAt(root.length - 1) === POSIX_SEPARATOR_CHAR_CODE ||
55
+ target.charCodeAt(root.length) === POSIX_SEPARATOR_CHAR_CODE)))) {
53
56
  return true;
54
57
  }
55
58
  const resolvedRoot = path.resolve(root);
@@ -74,7 +77,7 @@ export function safeRealpathSync(targetPath, cache) {
74
77
  return cached;
75
78
  }
76
79
  try {
77
- const resolved = fs.realpathSync(targetPath);
80
+ const resolved = realpathSync(targetPath);
78
81
  cache?.set(targetPath, resolved);
79
82
  cache?.set(resolved, resolved);
80
83
  return resolved;
@@ -1,5 +1,5 @@
1
1
  import { type PermissionCommandFailure } from "./permission-exec.js";
2
- import type { PermissionCheck, PermissionCheckOptions, SafeStatResult } from "./permissions.js";
2
+ import { type PermissionCheck, type PermissionCheckOptions, type SafeStatResult } from "./permissions.js";
3
3
  export type PermissionExec = (command: string, args: string[]) => Promise<{
4
4
  stdout: string;
5
5
  stderr: string;
@@ -1 +1 @@
1
- {"version":3,"file":"permissions-windows.d.ts","sourceRoot":"","sources":["../src/permissions-windows.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"permissions-windows.d.ts","sourceRoot":"","sources":["../src/permissions-windows.ts"],"names":[],"mappings":"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"}