@openclaw/fs-safe 0.11.0 → 0.13.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 (416) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +15 -8
  3. package/dist/absolute-path.d.ts.map +1 -1
  4. package/dist/absolute-path.js +32 -11
  5. package/dist/advanced.d.ts +3 -1
  6. package/dist/advanced.d.ts.map +1 -1
  7. package/dist/advanced.js +3 -1
  8. package/dist/archive-entry.d.ts.map +1 -1
  9. package/dist/archive-entry.js +4 -3
  10. package/dist/archive-gzip-tail.d.ts.map +1 -1
  11. package/dist/archive-gzip-tail.js +13 -9
  12. package/dist/archive-input.d.ts.map +1 -1
  13. package/dist/archive-input.js +6 -2
  14. package/dist/archive-merge.d.ts.map +1 -1
  15. package/dist/archive-merge.js +15 -2
  16. package/dist/archive-native.d.ts.map +1 -1
  17. package/dist/archive-native.js +7 -19
  18. package/dist/archive-plan.js +1 -1
  19. package/dist/archive-read.d.ts.map +1 -1
  20. package/dist/archive-read.js +55 -46
  21. package/dist/archive-staging.d.ts.map +1 -1
  22. package/dist/archive-staging.js +43 -10
  23. package/dist/archive-tar-inspect.d.ts.map +1 -1
  24. package/dist/archive-tar-inspect.js +4 -1
  25. package/dist/archive-zip-admission.d.ts +1 -1
  26. package/dist/archive-zip-admission.d.ts.map +1 -1
  27. package/dist/archive-zip-admission.js +2 -2
  28. package/dist/archive-zip-directory.d.ts +3 -0
  29. package/dist/archive-zip-directory.d.ts.map +1 -1
  30. package/dist/archive-zip-directory.js +13 -2
  31. package/dist/archive-zip-loader.d.ts +3 -2
  32. package/dist/archive-zip-loader.d.ts.map +1 -1
  33. package/dist/archive-zip-loader.js +30 -4
  34. package/dist/archive-zip-manifest.d.ts +5 -0
  35. package/dist/archive-zip-manifest.d.ts.map +1 -0
  36. package/dist/archive-zip-manifest.js +22 -0
  37. package/dist/archive-zip-names.d.ts +6 -1
  38. package/dist/archive-zip-names.d.ts.map +1 -1
  39. package/dist/archive-zip-names.js +50 -17
  40. package/dist/archive-zip-preflight.d.ts.map +1 -1
  41. package/dist/archive-zip-preflight.js +3 -2
  42. package/dist/archive.d.ts.map +1 -1
  43. package/dist/archive.js +9 -4
  44. package/dist/bounded-read.js +2 -2
  45. package/dist/darwin-acl.d.ts +4 -0
  46. package/dist/darwin-acl.d.ts.map +1 -0
  47. package/dist/darwin-acl.js +24 -0
  48. package/dist/deny-mutations.d.ts.map +1 -1
  49. package/dist/deny-mutations.js +8 -2
  50. package/dist/device-path.d.ts.map +1 -1
  51. package/dist/device-path.js +5 -3
  52. package/dist/directory-durability.d.ts.map +1 -1
  53. package/dist/directory-durability.js +67 -23
  54. package/dist/directory-entry-path.d.ts +3 -0
  55. package/dist/directory-entry-path.d.ts.map +1 -0
  56. package/dist/directory-entry-path.js +21 -0
  57. package/dist/directory-guard.d.ts +17 -1
  58. package/dist/directory-guard.d.ts.map +1 -1
  59. package/dist/directory-guard.js +134 -48
  60. package/dist/directory-mode-node.d.ts +12 -0
  61. package/dist/directory-mode-node.d.ts.map +1 -1
  62. package/dist/directory-mode-node.js +102 -4
  63. package/dist/effective-uid.d.ts +2 -0
  64. package/dist/effective-uid.d.ts.map +1 -0
  65. package/dist/effective-uid.js +25 -0
  66. package/dist/file-handle-transfer.d.ts.map +1 -1
  67. package/dist/file-handle-transfer.js +98 -27
  68. package/dist/file-hash.d.ts.map +1 -1
  69. package/dist/file-hash.js +12 -2
  70. package/dist/file-lock-sync.d.ts.map +1 -1
  71. package/dist/file-lock-sync.js +36 -6
  72. package/dist/file-lock.d.ts.map +1 -1
  73. package/dist/file-lock.js +29 -9
  74. package/dist/file-observation.d.ts +1 -1
  75. package/dist/file-observation.d.ts.map +1 -1
  76. package/dist/file-store-boundary.d.ts +6 -2
  77. package/dist/file-store-boundary.d.ts.map +1 -1
  78. package/dist/file-store-boundary.js +20 -65
  79. package/dist/file-store-copy-source.d.ts +5 -0
  80. package/dist/file-store-copy-source.d.ts.map +1 -0
  81. package/dist/file-store-copy-source.js +31 -0
  82. package/dist/file-store-path.d.ts.map +1 -1
  83. package/dist/file-store-path.js +4 -1
  84. package/dist/file-store-prune.d.ts.map +1 -1
  85. package/dist/file-store-prune.js +9 -1
  86. package/dist/file-store-sync-directory.d.ts +16 -0
  87. package/dist/file-store-sync-directory.d.ts.map +1 -0
  88. package/dist/file-store-sync-directory.js +349 -0
  89. package/dist/file-store.d.ts.map +1 -1
  90. package/dist/file-store.js +11 -28
  91. package/dist/filename.d.ts +1 -0
  92. package/dist/filename.d.ts.map +1 -1
  93. package/dist/filename.js +85 -23
  94. package/dist/fs.d.ts.map +1 -1
  95. package/dist/fs.js +3 -2
  96. package/dist/guarded-mkdir.d.ts +10 -0
  97. package/dist/guarded-mkdir.d.ts.map +1 -1
  98. package/dist/guarded-mkdir.js +217 -33
  99. package/dist/guest.d.ts.map +1 -1
  100. package/dist/guest.js +16 -5
  101. package/dist/home-dir.d.ts.map +1 -1
  102. package/dist/home-dir.js +73 -10
  103. package/dist/install-path.d.ts +6 -0
  104. package/dist/install-path.d.ts.map +1 -1
  105. package/dist/install-path.js +67 -19
  106. package/dist/json-durable-queue-ownership.d.ts +8 -0
  107. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  108. package/dist/json-durable-queue-ownership.js +134 -43
  109. package/dist/json-durable-queue-paths.d.ts +11 -0
  110. package/dist/json-durable-queue-paths.d.ts.map +1 -0
  111. package/dist/json-durable-queue-paths.js +42 -0
  112. package/dist/json-durable-queue-read.d.ts +6 -0
  113. package/dist/json-durable-queue-read.d.ts.map +1 -0
  114. package/dist/json-durable-queue-read.js +61 -0
  115. package/dist/json-durable-queue.d.ts +1 -1
  116. package/dist/json-durable-queue.d.ts.map +1 -1
  117. package/dist/json-durable-queue.js +83 -134
  118. package/dist/json-store.d.ts.map +1 -1
  119. package/dist/json-store.js +5 -1
  120. package/dist/json.d.ts.map +1 -1
  121. package/dist/json.js +54 -22
  122. package/dist/local-file-access.d.ts.map +1 -1
  123. package/dist/local-file-access.js +4 -0
  124. package/dist/local-file-descriptor.d.ts +17 -0
  125. package/dist/local-file-descriptor.d.ts.map +1 -0
  126. package/dist/local-file-descriptor.js +84 -0
  127. package/dist/local-roots.d.ts.map +1 -1
  128. package/dist/local-roots.js +35 -7
  129. package/dist/move-path-cleanup.d.ts +2 -0
  130. package/dist/move-path-cleanup.d.ts.map +1 -1
  131. package/dist/move-path-cleanup.js +44 -18
  132. package/dist/move-path.d.ts.map +1 -1
  133. package/dist/move-path.js +31 -6
  134. package/dist/native-binding.d.ts +21 -0
  135. package/dist/native-binding.d.ts.map +1 -1
  136. package/dist/native-directory-observation.d.ts +17 -0
  137. package/dist/native-directory-observation.d.ts.map +1 -0
  138. package/dist/native-directory-observation.js +37 -0
  139. package/dist/native-parent-admission.d.ts +31 -0
  140. package/dist/native-parent-admission.d.ts.map +1 -0
  141. package/dist/native-parent-admission.js +124 -0
  142. package/dist/native-pinned-write-windows.d.ts +0 -1
  143. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  144. package/dist/native-pinned-write-windows.js +0 -3
  145. package/dist/native-pinned-write.d.ts.map +1 -1
  146. package/dist/native-pinned-write.js +309 -40
  147. package/dist/output.d.ts.map +1 -1
  148. package/dist/output.js +15 -5
  149. package/dist/overwrite-file-handle.d.ts.map +1 -1
  150. package/dist/overwrite-file-handle.js +5 -1
  151. package/dist/owner-dacl.d.ts.map +1 -1
  152. package/dist/owner-dacl.js +2 -0
  153. package/dist/path-policy.d.ts.map +1 -1
  154. package/dist/path-policy.js +7 -2
  155. package/dist/path-prefix.d.ts +7 -0
  156. package/dist/path-prefix.d.ts.map +1 -0
  157. package/dist/path-prefix.js +82 -0
  158. package/dist/path-scope-lexical.d.ts +14 -0
  159. package/dist/path-scope-lexical.d.ts.map +1 -0
  160. package/dist/path-scope-lexical.js +37 -0
  161. package/dist/path-segment-route.d.ts +7 -0
  162. package/dist/path-segment-route.d.ts.map +1 -0
  163. package/dist/path-segment-route.js +24 -0
  164. package/dist/path-suffix-aliases.d.ts +10 -0
  165. package/dist/path-suffix-aliases.d.ts.map +1 -0
  166. package/dist/path-suffix-aliases.js +386 -0
  167. package/dist/path.d.ts.map +1 -1
  168. package/dist/path.js +35 -6
  169. package/dist/permissions-windows.d.ts.map +1 -1
  170. package/dist/permissions-windows.js +14 -3
  171. package/dist/permissions.d.ts.map +1 -1
  172. package/dist/permissions.js +37 -8
  173. package/dist/pinned-mutation-admission.d.ts +25 -0
  174. package/dist/pinned-mutation-admission.d.ts.map +1 -0
  175. package/dist/pinned-mutation-admission.js +425 -0
  176. package/dist/pinned-mutation-observation.d.ts +34 -0
  177. package/dist/pinned-mutation-observation.d.ts.map +1 -0
  178. package/dist/pinned-mutation-observation.js +142 -0
  179. package/dist/pinned-mutation-shared-route.d.ts +24 -0
  180. package/dist/pinned-mutation-shared-route.d.ts.map +1 -0
  181. package/dist/pinned-mutation-shared-route.js +70 -0
  182. package/dist/pinned-open.d.ts +6 -0
  183. package/dist/pinned-open.d.ts.map +1 -1
  184. package/dist/pinned-open.js +28 -10
  185. package/dist/pinned-write-types.d.ts +75 -0
  186. package/dist/pinned-write-types.d.ts.map +1 -0
  187. package/dist/pinned-write-types.js +1 -0
  188. package/dist/pinned-write.d.ts +7 -33
  189. package/dist/pinned-write.d.ts.map +1 -1
  190. package/dist/pinned-write.js +152 -17
  191. package/dist/private-directory.d.ts.map +1 -1
  192. package/dist/private-directory.js +2 -0
  193. package/dist/private-producer-handoff.d.ts +16 -0
  194. package/dist/private-producer-handoff.d.ts.map +1 -0
  195. package/dist/private-producer-handoff.js +272 -0
  196. package/dist/private-temp-workspace.d.ts +2 -39
  197. package/dist/private-temp-workspace.d.ts.map +1 -1
  198. package/dist/private-temp-workspace.js +183 -77
  199. package/dist/publish-file.d.ts.map +1 -1
  200. package/dist/publish-file.js +33 -29
  201. package/dist/regular-file.d.ts.map +1 -1
  202. package/dist/regular-file.js +56 -45
  203. package/dist/replace-directory.d.ts.map +1 -1
  204. package/dist/replace-directory.js +12 -5
  205. package/dist/replace-file-temp-owner.d.ts +1 -0
  206. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  207. package/dist/replace-file-temp-owner.js +12 -1
  208. package/dist/replace-file.d.ts.map +1 -1
  209. package/dist/replace-file.js +24 -24
  210. package/dist/root-boundary.d.ts +29 -0
  211. package/dist/root-boundary.d.ts.map +1 -0
  212. package/dist/root-boundary.js +182 -0
  213. package/dist/root-context.d.ts +12 -1
  214. package/dist/root-context.d.ts.map +1 -1
  215. package/dist/root-context.js +89 -16
  216. package/dist/root-directory-creation.d.ts +13 -0
  217. package/dist/root-directory-creation.d.ts.map +1 -0
  218. package/dist/root-directory-creation.js +212 -0
  219. package/dist/root-directory-list.d.ts +16 -4
  220. package/dist/root-directory-list.d.ts.map +1 -1
  221. package/dist/root-directory-list.js +182 -33
  222. package/dist/root-directory.d.ts +23 -0
  223. package/dist/root-directory.d.ts.map +1 -0
  224. package/dist/root-directory.js +141 -0
  225. package/dist/root-errors.d.ts.map +1 -1
  226. package/dist/root-errors.js +12 -1
  227. package/dist/root-file-final-admission.d.ts +21 -0
  228. package/dist/root-file-final-admission.d.ts.map +1 -0
  229. package/dist/root-file-final-admission.js +83 -0
  230. package/dist/root-file.d.ts.map +1 -1
  231. package/dist/root-file.js +103 -24
  232. package/dist/root-impl.d.ts +1 -0
  233. package/dist/root-impl.d.ts.map +1 -1
  234. package/dist/root-impl.js +316 -325
  235. package/dist/root-move-noreplace.d.ts +14 -0
  236. package/dist/root-move-noreplace.d.ts.map +1 -0
  237. package/dist/root-move-noreplace.js +202 -0
  238. package/dist/root-move-preflight.d.ts +8 -0
  239. package/dist/root-move-preflight.d.ts.map +1 -0
  240. package/dist/root-move-preflight.js +16 -0
  241. package/dist/root-observed-path.d.ts +9 -0
  242. package/dist/root-observed-path.d.ts.map +1 -0
  243. package/dist/root-observed-path.js +95 -0
  244. package/dist/root-path-errors.d.ts +12 -0
  245. package/dist/root-path-errors.d.ts.map +1 -0
  246. package/dist/root-path-errors.js +13 -0
  247. package/dist/root-path-existing.d.ts +2 -0
  248. package/dist/root-path-existing.d.ts.map +1 -1
  249. package/dist/root-path-existing.js +63 -22
  250. package/dist/root-path-observation.d.ts +63 -0
  251. package/dist/root-path-observation.d.ts.map +1 -0
  252. package/dist/root-path-observation.js +180 -0
  253. package/dist/root-path-stat.d.ts +5 -0
  254. package/dist/root-path-stat.d.ts.map +1 -0
  255. package/dist/root-path-stat.js +101 -0
  256. package/dist/root-path-symlink.d.ts.map +1 -1
  257. package/dist/root-path-symlink.js +23 -4
  258. package/dist/root-path.d.ts +13 -0
  259. package/dist/root-path.d.ts.map +1 -1
  260. package/dist/root-path.js +263 -73
  261. package/dist/root-paths-lexical.d.ts +9 -0
  262. package/dist/root-paths-lexical.d.ts.map +1 -0
  263. package/dist/root-paths-lexical.js +22 -0
  264. package/dist/root-paths.d.ts +3 -29
  265. package/dist/root-paths.d.ts.map +1 -1
  266. package/dist/root-paths.js +89 -178
  267. package/dist/root-read-admission.d.ts +26 -0
  268. package/dist/root-read-admission.d.ts.map +1 -0
  269. package/dist/root-read-admission.js +94 -0
  270. package/dist/root-remove-identity.d.ts +15 -0
  271. package/dist/root-remove-identity.d.ts.map +1 -0
  272. package/dist/root-remove-identity.js +89 -0
  273. package/dist/root-remove-receipt.d.ts +17 -0
  274. package/dist/root-remove-receipt.d.ts.map +1 -0
  275. package/dist/root-remove-receipt.js +37 -0
  276. package/dist/root-remove.d.ts +2 -1
  277. package/dist/root-remove.d.ts.map +1 -1
  278. package/dist/root-remove.js +172 -10
  279. package/dist/root-walk.d.ts.map +1 -1
  280. package/dist/root-walk.js +2 -1
  281. package/dist/root-write-admission.d.ts +68 -0
  282. package/dist/root-write-admission.d.ts.map +1 -0
  283. package/dist/root-write-admission.js +322 -0
  284. package/dist/root-write-compatibility.d.ts +13 -0
  285. package/dist/root-write-compatibility.d.ts.map +1 -0
  286. package/dist/root-write-compatibility.js +74 -0
  287. package/dist/root-write-complete-parent.d.ts +42 -0
  288. package/dist/root-write-complete-parent.d.ts.map +1 -0
  289. package/dist/root-write-complete-parent.js +195 -0
  290. package/dist/root-write-mode.d.ts +2 -0
  291. package/dist/root-write-mode.d.ts.map +1 -1
  292. package/dist/root-write-mode.js +20 -7
  293. package/dist/root-write-publication.d.ts +24 -0
  294. package/dist/root-write-publication.d.ts.map +1 -0
  295. package/dist/root-write-publication.js +85 -0
  296. package/dist/root-write-verification.d.ts.map +1 -1
  297. package/dist/root-write-verification.js +18 -7
  298. package/dist/safe-path-segment.d.ts.map +1 -1
  299. package/dist/safe-path-segment.js +3 -1
  300. package/dist/secret-file.d.ts.map +1 -1
  301. package/dist/secret-file.js +62 -24
  302. package/dist/secret-read-async.d.ts.map +1 -1
  303. package/dist/secret-read-async.js +18 -13
  304. package/dist/secret-read-policy.d.ts.map +1 -1
  305. package/dist/secret-read-policy.js +5 -1
  306. package/dist/secure-file-windows.d.ts +10 -0
  307. package/dist/secure-file-windows.d.ts.map +1 -0
  308. package/dist/secure-file-windows.js +186 -0
  309. package/dist/secure-file.d.ts.map +1 -1
  310. package/dist/secure-file.js +98 -10
  311. package/dist/secure-temp-dir.d.ts +6 -3
  312. package/dist/secure-temp-dir.d.ts.map +1 -1
  313. package/dist/secure-temp-dir.js +121 -101
  314. package/dist/secure-temp-repair.d.ts +35 -0
  315. package/dist/secure-temp-repair.d.ts.map +1 -0
  316. package/dist/secure-temp-repair.js +106 -0
  317. package/dist/sibling-staged-file.d.ts +3 -1
  318. package/dist/sibling-staged-file.d.ts.map +1 -1
  319. package/dist/sibling-staged-file.js +181 -50
  320. package/dist/sibling-temp.d.ts.map +1 -1
  321. package/dist/sibling-temp.js +27 -12
  322. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  323. package/dist/sidecar-lock-acquire.js +45 -15
  324. package/dist/sidecar-lock-root.d.ts.map +1 -1
  325. package/dist/sidecar-lock-root.js +4 -2
  326. package/dist/sidecar-lock.d.ts.map +1 -1
  327. package/dist/sidecar-lock.js +2 -3
  328. package/dist/staged-directory.d.ts +14 -5
  329. package/dist/staged-directory.d.ts.map +1 -1
  330. package/dist/staged-directory.js +54 -3
  331. package/dist/standalone-publication-path.d.ts +2 -0
  332. package/dist/standalone-publication-path.d.ts.map +1 -0
  333. package/dist/standalone-publication-path.js +6 -0
  334. package/dist/stat-observation.d.ts +11 -0
  335. package/dist/stat-observation.d.ts.map +1 -0
  336. package/dist/stat-observation.js +64 -0
  337. package/dist/strict-file-identity.d.ts.map +1 -1
  338. package/dist/strict-file-identity.js +39 -2
  339. package/dist/symlink-parents.d.ts.map +1 -1
  340. package/dist/symlink-parents.js +7 -2
  341. package/dist/temp-target.d.ts +2 -0
  342. package/dist/temp-target.d.ts.map +1 -1
  343. package/dist/temp-target.js +133 -4
  344. package/dist/temp-workspace-admission.d.ts +22 -0
  345. package/dist/temp-workspace-admission.d.ts.map +1 -0
  346. package/dist/temp-workspace-admission.js +374 -0
  347. package/dist/temp-workspace-child-admission.d.ts +13 -0
  348. package/dist/temp-workspace-child-admission.d.ts.map +1 -0
  349. package/dist/temp-workspace-child-admission.js +95 -0
  350. package/dist/temp-workspace-descriptor.d.ts +48 -0
  351. package/dist/temp-workspace-descriptor.d.ts.map +1 -0
  352. package/dist/temp-workspace-descriptor.js +363 -0
  353. package/dist/temp-workspace-identity.d.ts +15 -0
  354. package/dist/temp-workspace-identity.d.ts.map +1 -0
  355. package/dist/temp-workspace-identity.js +41 -0
  356. package/dist/temp-workspace-owner.d.ts +7 -6
  357. package/dist/temp-workspace-owner.d.ts.map +1 -1
  358. package/dist/temp-workspace-owner.js +121 -61
  359. package/dist/temp-workspace-permissions.d.ts +4 -0
  360. package/dist/temp-workspace-permissions.d.ts.map +1 -0
  361. package/dist/temp-workspace-permissions.js +32 -0
  362. package/dist/temp-workspace-types.d.ts +40 -0
  363. package/dist/temp-workspace-types.d.ts.map +1 -0
  364. package/dist/temp-workspace-types.js +1 -0
  365. package/dist/temp.d.ts +1 -1
  366. package/dist/temp.d.ts.map +1 -1
  367. package/dist/temp.js +1 -1
  368. package/dist/test-hooks.d.ts +7 -0
  369. package/dist/test-hooks.d.ts.map +1 -1
  370. package/dist/text-atomic.d.ts.map +1 -1
  371. package/dist/text-atomic.js +3 -1
  372. package/dist/trash.d.ts.map +1 -1
  373. package/dist/trash.js +54 -8
  374. package/dist/walk.d.ts.map +1 -1
  375. package/dist/walk.js +20 -16
  376. package/dist/windows-owner.d.ts.map +1 -1
  377. package/dist/windows-owner.js +5 -0
  378. package/dist/windows-path-alias.d.ts +39 -0
  379. package/dist/windows-path-alias.d.ts.map +1 -0
  380. package/dist/windows-path-alias.js +153 -0
  381. package/docs/advanced.md +28 -1
  382. package/docs/archive.md +29 -2
  383. package/docs/atomic.md +27 -3
  384. package/docs/contributing.md +4 -1
  385. package/docs/copy.md +4 -1
  386. package/docs/durability.md +18 -2
  387. package/docs/errors.md +14 -6
  388. package/docs/file-store.md +30 -3
  389. package/docs/filename.md +21 -7
  390. package/docs/guest.md +5 -0
  391. package/docs/install-path.md +61 -15
  392. package/docs/install.md +12 -8
  393. package/docs/json-store.md +5 -1
  394. package/docs/json.md +11 -0
  395. package/docs/mutation-policy-proof.md +65 -0
  396. package/docs/native-helper.md +28 -9
  397. package/docs/native.md +46 -10
  398. package/docs/output.md +33 -11
  399. package/docs/path-prefix.md +64 -0
  400. package/docs/path-suffix-aliases.md +159 -0
  401. package/docs/path.md +12 -1
  402. package/docs/permissions.md +26 -1
  403. package/docs/private-file-store.md +14 -0
  404. package/docs/public-api.md +14 -0
  405. package/docs/quickstart.md +1 -1
  406. package/docs/reading.md +8 -1
  407. package/docs/root.md +21 -4
  408. package/docs/secret-file.md +3 -0
  409. package/docs/secure-file.md +21 -16
  410. package/docs/security-model.md +76 -9
  411. package/docs/sidecar-lock.md +28 -1
  412. package/docs/store.md +27 -2
  413. package/docs/temp.md +262 -34
  414. package/docs/test-hooks.md +14 -0
  415. package/docs/writing.md +38 -8
  416. package/package.json +10 -10
@@ -1,3 +1,4 @@
1
+ import { types } from "node:util";
1
2
  import { ArchiveFormatError, ArchiveSecurityError } from "./archive-errors.js";
2
3
  import { stripArchivePath, validateArchiveEntryPath } from "./archive-entry.js";
3
4
  import { updateCrc32 } from "./archive-crc32.js";
@@ -40,7 +41,10 @@ function utf8(bytes) {
40
41
  return zipFormat("invalid UTF-8 name");
41
42
  }
42
43
  }
43
- function key(name) {
44
+ // Canonical identity only; this does not replace raw path validation.
45
+ export function zipPathKey(name) {
46
+ if (name && name !== "." && !name.includes("/") && !name.includes("\\"))
47
+ return name;
44
48
  return stripArchivePath(name, 0) ?? "";
45
49
  }
46
50
  function originalName(name, rawName, flags) {
@@ -69,37 +73,66 @@ export function admitZipNames(params) {
69
73
  const { central, local, flags, centralExtra, localExtra, seen } = params;
70
74
  if (!central.length || !local.length)
71
75
  zipFormat("empty entry name");
76
+ // Reuse only within this synchronous call; shared backing bytes can change
77
+ // concurrently even though admission does not yield while checking names.
78
+ const sameName = !types.isSharedArrayBuffer(central.buffer) &&
79
+ !types.isSharedArrayBuffer(local.buffer) && central.equals(local);
72
80
  const centralRaw = central.toString("latin1");
73
- const localRaw = local.toString("latin1");
81
+ const localRaw = sameName ? centralRaw : local.toString("latin1");
74
82
  const centralUtf8 = originalName(central, centralRaw, flags);
75
- const localUtf8 = originalName(local, localRaw, flags);
83
+ const localUtf8 = sameName ? centralUtf8 : originalName(local, localRaw, flags);
76
84
  const centralUnicode = unicodeName(central, centralExtra);
77
- const localUnicode = unicodeName(local, localExtra);
78
- const centralKey = key(centralRaw);
79
- if (centralKey !== key(localRaw)) {
85
+ const centralField = centralExtra.get(0x7075);
86
+ const localField = localExtra.get(0x7075);
87
+ // Only immutable identical fields share their CRC-bound name admission.
88
+ const sameUnicode = (!centralField || !types.isSharedArrayBuffer(centralField.buffer)) &&
89
+ (!localField || !types.isSharedArrayBuffer(localField.buffer)) &&
90
+ (centralField === localField ||
91
+ (centralField !== undefined && localField !== undefined && centralField.equals(localField)));
92
+ const localUnicode = sameName && sameUnicode ? centralUnicode : unicodeName(local, localExtra);
93
+ const centralKey = zipPathKey(centralRaw);
94
+ if (!sameName && centralKey !== zipPathKey(localRaw)) {
80
95
  zipFormat("central and local names disagree");
81
96
  }
82
97
  const interpretations = [centralUtf8, localUtf8, centralUnicode, localUnicode].filter((value) => value !== undefined);
83
- const interpretationKey = interpretations.length ? key(interpretations[0]) : undefined;
84
- if (interpretations.some((value) => key(value) !== interpretationKey)) {
98
+ // Canonical paths erase terminal separators. Preserve their kind meaning in
99
+ // every interpretation, including Unicode overrides of legacy-encoded names.
100
+ const directory = /[/\\]$/.test(centralRaw);
101
+ if (/[/\\]$/.test(localRaw) !== directory ||
102
+ interpretations.some((value) => /[/\\]$/.test(value) !== directory)) {
103
+ zipFormat("conflicting terminal directory markers");
104
+ }
105
+ const interpretationKey = interpretations.length ? zipPathKey(interpretations[0]) : undefined;
106
+ if (interpretations.some((value) => value !== interpretations[0] && zipPathKey(value) !== interpretationKey)) {
85
107
  zipFormat("conflicting Unicode name interpretations");
86
108
  }
87
109
  // JSZip checks the central Unicode field against the local name. A slash-only
88
110
  // spelling difference must not make one decoder ignore a meaningful override.
89
111
  if (centralUnicode && !central.equals(local) &&
90
- key(centralUnicode) !== key(local.toString("utf8"))) {
112
+ zipPathKey(centralUnicode) !== zipPathKey(local.toString("utf8"))) {
91
113
  zipFormat("Unicode override disagrees with local decoder name");
92
114
  }
93
- if (!centralUnicode && localUnicode && key(localUnicode) !== key(local.toString("utf8"))) {
115
+ if (!centralUnicode && localUnicode && zipPathKey(localUnicode) !== zipPathKey(local.toString("utf8"))) {
94
116
  zipFormat("local-only Unicode override changes the name");
95
117
  }
96
- const identities = new Set([centralKey]);
97
- if (centralUnicode !== undefined)
98
- identities.add(key(Buffer.from(centralUnicode).toString("latin1")));
99
- if ([...identities].some((identity) => seen.has(identity))) {
118
+ const unicodeKey = centralUnicode === undefined
119
+ ? undefined : zipPathKey(Buffer.from(centralUnicode).toString("latin1"));
120
+ if (seen.has(centralKey) ||
121
+ (unicodeKey !== undefined && unicodeKey !== centralKey && seen.has(unicodeKey))) {
100
122
  throw new ArchiveSecurityError("entry-path", "zip archive contains duplicate or colliding entry names");
101
123
  }
102
- for (const identity of identities)
103
- seen.add(identity);
104
- return centralUnicode ?? centralUtf8 ?? (central.every((byte) => byte < 128) ? central.toString("ascii") : undefined);
124
+ seen.add(centralKey);
125
+ if (unicodeKey !== undefined && unicodeKey !== centralKey)
126
+ seen.add(unicodeKey);
127
+ const path = centralUnicode ?? centralUtf8 ?? (central.every((byte) => byte < 128) ? central.toString("ascii") : undefined);
128
+ const portablePath = centralUnicode ?? localUtf8 ?? (sameName && path !== undefined ? path : local.toString("utf8"));
129
+ // Reuse the admitted interpretation, never the Latin-1 Unicode collision key.
130
+ // Unflagged legacy names can decode differently and need their own key.
131
+ const portableKey = portablePath === centralRaw ? centralKey
132
+ : interpretations.includes(portablePath) ? interpretationKey : zipPathKey(portablePath);
133
+ return {
134
+ path,
135
+ portableKey,
136
+ directory,
137
+ };
105
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"archive-zip-preflight.d.ts","sourceRoot":"","sources":["../src/archive-zip-preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,iCAAiC,EAAE,MAAM,wBAAwB,CAAC;AAC3E,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,MAAM,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAO9B"}
1
+ {"version":3,"file":"archive-zip-preflight.d.ts","sourceRoot":"","sources":["../src/archive-zip-preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,EAAE,iCAAiC,EAAE,MAAM,wBAAwB,CAAC;AAC3E,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,MAAM,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAQ9B"}
@@ -7,6 +7,7 @@ export async function loadZipArchiveWithPreflight(buffer, limits) {
7
7
  if (buffer.byteLength > resolvedLimits.maxArchiveBytes) {
8
8
  throw new ArchiveLimitError(ARCHIVE_LIMIT_ERROR_CODE.ARCHIVE_SIZE_EXCEEDS_LIMIT);
9
9
  }
10
- const entryCount = admitZipBuffer(buffer, resolvedLimits);
11
- return await loadAdmittedZipArchive(buffer, entryCount);
10
+ const entries = [];
11
+ admitZipBuffer(buffer, resolvedLimits, entry => { entries.push(entry); });
12
+ return await loadAdmittedZipArchive(buffer, entries);
12
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"AA4DA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,6BAA6B,EAC7B,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,iCAAiC,EACjC,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,8BAA8B,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAC;AAiNpC,wBAAsB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CjF"}
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"AA4DA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlE,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,6BAA6B,EAC7B,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,iCAAiC,EACjC,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,8BAA8B,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAC;AAiNpC,wBAAsB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDjF"}
package/dist/archive.js CHANGED
@@ -22,6 +22,7 @@ import { stageArchiveFileForExtraction } from "./archive-input.js";
22
22
  import { getNativeBinding } from "./native.js";
23
23
  import { resolveArchiveFilteredEntryPolicy, shouldExtractArchiveEntry, } from "./archive-policy.js";
24
24
  import { writeSiblingTempFile } from "./sibling-temp.js";
25
+ import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
25
26
  import { realpathSync } from "./realpath.js";
26
27
  export { isWindowsDrivePath, normalizeArchiveEntryPath, resolveArchiveOutputPath, stripArchivePath, validateArchiveEntryPath, } from "./archive-entry.js";
27
28
  export { resolveArchiveKind, resolvePackedRootDir } from "./archive-kind.js";
@@ -51,7 +52,7 @@ function resolveZipOutputPath(params) {
51
52
  const canonicalPath = stripArchivePath(params.entryPath, 0);
52
53
  if (!canonicalPath)
53
54
  return null;
54
- const relPath = stripArchivePath(canonicalPath, params.strip);
55
+ const relPath = params.strip === 0 ? canonicalPath : stripArchivePath(canonicalPath, params.strip);
55
56
  if (!relPath) {
56
57
  return null;
57
58
  }
@@ -203,19 +204,23 @@ async function extractZip(params) {
203
204
  }
204
205
  }
205
206
  export async function extractArchive(params) {
207
+ const archivePath = params.archivePath;
208
+ const destDir = params.destDir;
206
209
  const onFiltered = resolveArchiveFilteredEntryPolicy(params.onFiltered);
207
- const kind = params.kind ?? resolveArchiveKind(params.archivePath);
210
+ const kind = params.kind ?? resolveArchiveKind(archivePath);
208
211
  if (!kind) {
209
- throw new Error(`unsupported archive: ${params.archivePath}`);
212
+ throw new Error(`unsupported archive: ${archivePath}`);
210
213
  }
211
214
  const label = kind === "zip" ? "extract zip" : "extract tar";
212
215
  const limits = resolveExtractLimits(params.limits);
213
216
  const tarLimits = resolveTarMeterLimits(limits);
214
217
  const native = getNativeBinding();
218
+ assertNoWindowsPathAlias(archivePath, "filesystem", "archive source uses a Windows filesystem namespace alias");
219
+ assertNoWindowsPathAlias(destDir, "filesystem", "archive destination uses a Windows filesystem namespace alias");
215
220
  // Read the declared public fields before private adapters copy options: class
216
221
  // getters and inherited policy must survive identically on every backend.
217
222
  const options = {
218
- archivePath: params.archivePath, destDir: params.destDir,
223
+ archivePath, destDir,
219
224
  durable: params.durable,
220
225
  stripComponents: params.stripComponents, limits,
221
226
  entryModes: params.entryModes, entryFilter: params.entryFilter, onFiltered,
@@ -54,7 +54,7 @@ export async function readBoundedAsync(maxBytes, readChunk, options = {}) {
54
54
  // initial read; virtual files can report zero or stale sizes thereafter.
55
55
  const currentSize = bytesRead < buffer.length ? observeRegularFileSize?.() : undefined;
56
56
  total = addReadBytes(total, bytesRead, maxBytes, createLimitError);
57
- if (currentSize !== undefined && bytesRead >= currentSize)
57
+ if (currentSize !== undefined && currentSize > 0 && bytesRead >= currentSize)
58
58
  return finishReadBuffer(buffer, total, allocate);
59
59
  }
60
60
  while (true) {
@@ -120,7 +120,7 @@ export function readBoundedSync(maxBytes, readChunk, options = {}) {
120
120
  return finishReadBuffer(buffer, 0);
121
121
  const currentSize = bytesRead < buffer.length ? observeRegularFileSize?.() : undefined;
122
122
  total = addReadBytes(total, bytesRead, maxBytes, createLimitError);
123
- if (currentSize !== undefined && bytesRead >= currentSize)
123
+ if (currentSize !== undefined && currentSize > 0 && bytesRead >= currentSize)
124
124
  return finishReadBuffer(buffer, total);
125
125
  }
126
126
  while (true) {
@@ -0,0 +1,4 @@
1
+ import type { NativeDarwinAclFacts } from "./native-binding.js";
2
+ /** Internal descriptor facts only; callers own identity, lifetime, and ACL policy. */
3
+ export declare function inspectDarwinAcl(fd: number): NativeDarwinAclFacts;
4
+ //# sourceMappingURL=darwin-acl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin-acl.d.ts","sourceRoot":"","sources":["../src/darwin-acl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,oBAAoB,CAmBjE"}
@@ -0,0 +1,24 @@
1
+ import { FsSafeError } from "./errors.js";
2
+ import { getNativeBinding } from "./native.js";
3
+ /** Internal descriptor facts only; callers own identity, lifetime, and ACL policy. */
4
+ export function inspectDarwinAcl(fd) {
5
+ if (!Number.isInteger(fd) || fd < 0 || fd > 0x7fff_ffff) {
6
+ throw new FsSafeError("permission-unverified", "Darwin ACL inspection requires a valid descriptor");
7
+ }
8
+ const native = getNativeBinding();
9
+ if (typeof native?.inspectDarwinAcl !== "function") {
10
+ throw new FsSafeError("helper-unavailable", "Darwin ACL inspection requires the matching native capability");
11
+ }
12
+ let facts;
13
+ try {
14
+ facts = native.inspectDarwinAcl(fd);
15
+ }
16
+ catch (cause) {
17
+ throw new FsSafeError("permission-unverified", "Darwin descriptor ACL could not be inspected", { cause });
18
+ }
19
+ const state = facts && typeof facts === "object" && "state" in facts ? facts.state : undefined;
20
+ if (state !== "absent" && state !== "empty" && state !== "present") {
21
+ throw new FsSafeError("permission-unverified", "Darwin ACL inspection returned invalid facts");
22
+ }
23
+ return { state };
24
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"deny-mutations.d.ts","sourceRoot":"","sources":["../src/deny-mutations.ts"],"names":[],"mappings":"AAKA,wBAAsB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAI1F;AAMD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAqBF,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GAAG,SAAS,EACtC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,kBAAkB,GAAG,SAAS,EAC7C,UAAU,EAAE,kBAAkB,GAAG,SAAS,GACzC,kBAAkB,GAAG,SAAS,CAWhC"}
1
+ {"version":3,"file":"deny-mutations.d.ts","sourceRoot":"","sources":["../src/deny-mutations.ts"],"names":[],"mappings":"AASA,wBAAsB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAQ1F;AAMD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAsBF,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GAAG,SAAS,EACtC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,kBAAkB,GAAG,SAAS,EAC7C,UAAU,EAAE,kBAAkB,GAAG,SAAS,GACzC,kBAAkB,GAAG,SAAS,CAWhC"}
@@ -2,10 +2,15 @@ import path from "node:path";
2
2
  import { FsSafeError } from "./errors.js";
3
3
  import { assertNoNulPathInput, isPathInside } from "./path.js";
4
4
  import { resolvePathViaExistingAncestor } from "./root-path-existing.js";
5
+ import { assertNoWindowsPathAlias, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
5
6
  export async function resolveMutationComparablePaths(rawPath) {
6
7
  assertNoNulPathInput(rawPath, "path contains a NUL byte");
7
- const resolved = path.resolve(rawPath);
8
- return new Set([resolved, await resolvePathViaExistingAncestor(resolved)]);
8
+ assertNoWindowsPathAlias(rawPath, "filesystem", "mutation path uses a Windows filesystem namespace alias");
9
+ const resolved = resolvePathPreservingWindowsRoot(rawPath);
10
+ assertNoWindowsPathAlias(resolved, "filesystem", "mutation path uses a Windows filesystem namespace alias");
11
+ const canonical = await resolvePathViaExistingAncestor(resolved);
12
+ assertNoWindowsPathAlias(canonical, "filesystem", "mutation path uses a Windows filesystem namespace alias");
13
+ return new Set([resolved, canonical]);
9
14
  }
10
15
  function isSamePath(left, right) {
11
16
  return isPathInside(left, right) && isPathInside(right, left);
@@ -20,6 +25,7 @@ function policyPathEntries(entries) {
20
25
  throw new FsSafeError("invalid-path", "deny mutation paths must be non-empty");
21
26
  }
22
27
  assertNoNulPathInput(entry, "deny mutation path contains a NUL byte");
28
+ assertNoWindowsPathAlias(entry, "filesystem", "deny mutation path uses a Windows filesystem namespace alias");
23
29
  if (!path.isAbsolute(entry)) {
24
30
  throw new FsSafeError("invalid-path", "deny mutation paths must be absolute");
25
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"device-path.d.ts","sourceRoot":"","sources":["../src/device-path.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,0BAA0B,GAClC,cAAc,GACd,UAAU,GACV,gBAAgB,CAAC;AAErB,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,0BAA0B,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B,CAAC;AAcF,eAAO,MAAM,6BAA6B,EAAE,WAAW,CAAC,MAAM,CAgC5D,CAAC;AAsEH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjE;AAcD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,2BAAgC,GACxC,yBAAyB,GAAG,SAAS,CAWvC;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAET;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,2BAA2B,GACpC,IAAI,CAON"}
1
+ {"version":3,"file":"device-path.d.ts","sourceRoot":"","sources":["../src/device-path.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,0BAA0B,GAClC,cAAc,GACd,UAAU,GACV,gBAAgB,CAAC;AAErB,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,0BAA0B,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B,CAAC;AAcF,eAAO,MAAM,6BAA6B,EAAE,WAAW,CAAC,MAAM,CAgC5D,CAAC;AA2EH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjE;AAcD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,2BAAgC,GACxC,yBAAyB,GAAG,SAAS,CAWvC;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAET;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,2BAA2B,GACpC,IAAI,CAON"}
@@ -96,9 +96,11 @@ function matchPosixDeviceReadPath(filePath, cwd) {
96
96
  }
97
97
  function normalizeWindowsDeviceBaseName(filePath) {
98
98
  const normalized = trimTrailingWindowsSeparators(filePath.replace(/\//g, "\\"));
99
- const lastSegment = normalized.split("\\").filter(Boolean).at(-1) ?? normalized;
100
- const withoutStream = lastSegment.split(":")[0] ?? lastSegment;
101
- const stem = withoutStream.split(".")[0] ?? withoutStream;
99
+ const start = normalized.lastIndexOf("\\") + 1;
100
+ const stream = normalized.indexOf(":", start);
101
+ const extension = normalized.indexOf(".", start);
102
+ const end = Math.min(stream < 0 ? normalized.length : stream, extension < 0 ? normalized.length : extension);
103
+ const stem = normalized.slice(start, end);
102
104
  return trimTrailingWindowsIgnoredChars(stem).toUpperCase();
103
105
  }
104
106
  export function isWindowsReservedDeviceName(name) {
@@ -1 +1 @@
1
- {"version":3,"file":"directory-durability.d.ts","sourceRoot":"","sources":["../src/directory-durability.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAM7C,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG7E,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,GAAG;IACvD,UAAU,EAAE,oBAAoB,GAAG;QAAE,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC;CAC7D,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wBAAwB,CAAC,EAAE,gBAAgB,CAAC;IAC5C,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD,CAAC;AAgKF,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EACpC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CAa1B;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EACpC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,gBAAgB,EACpC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,oBAAoB,CAuCtB;AAED,wBAAsB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAMvE;AAuBD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,uBAAuB,CAAC,CA8ElC"}
1
+ {"version":3,"file":"directory-durability.d.ts","sourceRoot":"","sources":["../src/directory-durability.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAM7C,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI7E,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,GAAG;IACvD,UAAU,EAAE,oBAAoB,GAAG;QAAE,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC;CAC7D,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wBAAwB,CAAC,EAAE,gBAAgB,CAAC;IAC5C,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD,CAAC;AAwOF,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EACpC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CAe1B;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EACpC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAqB/B;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,gBAAgB,EACpC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,oBAAoB,CAyCtB;AAED,wBAAsB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAMvE;AAiCD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,uBAAuB,CAAC,CA2FlC"}
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { ensureAbsoluteDirectory } from "./absolute-path.js";
5
5
  import { FsSafeError } from "./errors.js";
6
6
  import { sameFileIdentity } from "./file-identity.js";
7
+ import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathPreservingWindowsRoot } from "./windows-path-alias.js";
7
8
  import { realpathSync } from "./realpath.js";
8
9
  function directoryOpenFlags() {
9
10
  if (process.platform === "win32") {
@@ -42,39 +43,67 @@ function assertDirectory(identity, pathname, label) {
42
43
  throw new FsSafeError("not-file", `${label} must be a real directory: ${pathname}`);
43
44
  }
44
45
  }
46
+ function ownDirectoryReceipt(receipt) {
47
+ const pathname = receipt.path;
48
+ const realPath = receipt.realPath;
49
+ const identity = receipt.identity;
50
+ return { path: pathname, realPath, identity };
51
+ }
52
+ function assertDirectoryReceiptPaths(receipt, label) {
53
+ assertNoWindowsPathAlias(receipt.path, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
54
+ assertNoWindowsPathAlias(receipt.realPath, "filesystem", `${label} real path uses a Windows filesystem namespace alias`);
55
+ }
45
56
  async function createDirectoryReceipt(directoryPath, label) {
46
- const resolvedPath = path.resolve(directoryPath);
47
- const identity = fsSync.lstatSync(resolvedPath);
57
+ assertNoWindowsPathAlias(directoryPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
58
+ const resolvedPath = resolvePathPreservingWindowsRoot(directoryPath);
59
+ assertNoWindowsPathAlias(resolvedPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
60
+ const operationPath = pathForWindowsFilesystem(resolvedPath);
61
+ const identity = fsSync.lstatSync(operationPath);
48
62
  assertDirectory(identity, resolvedPath, label);
63
+ const realPath = realpathSync.native(operationPath);
64
+ assertNoWindowsPathAlias(realPath, "filesystem", `${label} real path uses a Windows filesystem namespace alias`);
49
65
  return {
50
66
  path: resolvedPath,
51
- realPath: realpathSync.native(resolvedPath),
67
+ realPath,
52
68
  identity,
53
69
  };
54
70
  }
55
71
  function createDirectoryReceiptSync(directoryPath, label) {
56
- const resolvedPath = path.resolve(directoryPath);
57
- const identity = fsSync.lstatSync(resolvedPath);
72
+ assertNoWindowsPathAlias(directoryPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
73
+ const resolvedPath = resolvePathPreservingWindowsRoot(directoryPath);
74
+ assertNoWindowsPathAlias(resolvedPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
75
+ const operationPath = pathForWindowsFilesystem(resolvedPath);
76
+ const identity = fsSync.lstatSync(operationPath);
58
77
  assertDirectory(identity, resolvedPath, label);
78
+ const realPath = realpathSync(operationPath);
79
+ assertNoWindowsPathAlias(realPath, "filesystem", `${label} real path uses a Windows filesystem namespace alias`);
59
80
  return {
60
81
  path: resolvedPath,
61
- realPath: realpathSync(resolvedPath),
82
+ realPath,
62
83
  identity,
63
84
  };
64
85
  }
65
86
  async function assertDirectoryReceiptCurrent(receipt, label) {
66
- const currentIdentity = fsSync.lstatSync(receipt.path);
87
+ assertDirectoryReceiptPaths(receipt, label);
88
+ const operationPath = pathForWindowsFilesystem(receipt.path);
89
+ const currentIdentity = fsSync.lstatSync(operationPath);
67
90
  assertDirectory(currentIdentity, receipt.path, label);
91
+ const realPath = realpathSync.native(operationPath);
92
+ assertNoWindowsPathAlias(realPath, "filesystem", `${label} real path uses a Windows filesystem namespace alias`);
68
93
  if (!sameFileIdentity(receipt.identity, currentIdentity) ||
69
- (realpathSync.native(receipt.path)) !== receipt.realPath) {
94
+ realPath !== receipt.realPath) {
70
95
  throw new FsSafeError("path-mismatch", `${label} changed during durable directory operation: ${receipt.path}`);
71
96
  }
72
97
  }
73
98
  function assertDirectoryReceiptCurrentSync(receipt, label) {
74
- const currentIdentity = fsSync.lstatSync(receipt.path);
99
+ assertDirectoryReceiptPaths(receipt, label);
100
+ const operationPath = pathForWindowsFilesystem(receipt.path);
101
+ const currentIdentity = fsSync.lstatSync(operationPath);
75
102
  assertDirectory(currentIdentity, receipt.path, label);
103
+ const realPath = realpathSync(operationPath);
104
+ assertNoWindowsPathAlias(realPath, "filesystem", `${label} real path uses a Windows filesystem namespace alias`);
76
105
  if (!sameFileIdentity(receipt.identity, currentIdentity) ||
77
- realpathSync(receipt.path) !== receipt.realPath) {
106
+ realPath !== receipt.realPath) {
78
107
  throw new FsSafeError("path-mismatch", `${label} changed during durable directory operation: ${receipt.path}`);
79
108
  }
80
109
  }
@@ -88,19 +117,21 @@ async function assertOpenDirectoryCurrent(handle, receipt, label) {
88
117
  }
89
118
  class PinnedDirectoryImpl {
90
119
  receipt;
120
+ #authority;
91
121
  #handle;
92
122
  #label;
93
123
  #closed = false;
94
124
  constructor(handle, receipt, label) {
95
125
  this.#handle = handle;
96
- this.receipt = receipt;
126
+ this.#authority = receipt;
127
+ this.receipt = ownDirectoryReceipt(receipt);
97
128
  this.#label = label;
98
129
  }
99
130
  async assertCurrent() {
100
131
  if (this.#closed) {
101
132
  throw new FsSafeError("helper-failed", `${this.#label} pin is already closed`);
102
133
  }
103
- await assertOpenDirectoryCurrent(this.#handle, this.receipt, this.#label);
134
+ await assertOpenDirectoryCurrent(this.#handle, this.#authority, this.#label);
104
135
  }
105
136
  async sync() {
106
137
  await this.assertCurrent();
@@ -127,9 +158,11 @@ class PinnedDirectoryImpl {
127
158
  }
128
159
  export async function pinDirectory(directory, options = {}) {
129
160
  const label = options.label ?? "directory";
130
- const receipt = typeof directory === "string" ? await createDirectoryReceipt(directory, label) : directory;
161
+ const receipt = typeof directory === "string"
162
+ ? await createDirectoryReceipt(directory, label)
163
+ : ownDirectoryReceipt(directory);
131
164
  await assertDirectoryReceiptCurrent(receipt, label);
132
- const handle = await fs.open(receipt.path, directoryOpenFlags());
165
+ const handle = await fs.open(pathForWindowsFilesystem(receipt.path), directoryOpenFlags());
133
166
  try {
134
167
  await assertOpenDirectoryCurrent(handle, receipt, label);
135
168
  return new PinnedDirectoryImpl(handle, receipt, label);
@@ -141,7 +174,9 @@ export async function pinDirectory(directory, options = {}) {
141
174
  }
142
175
  export async function syncDirectory(directory, options = {}) {
143
176
  const label = options.label ?? "directory";
144
- const receipt = typeof directory === "string" ? await createDirectoryReceipt(directory, label) : directory;
177
+ const receipt = typeof directory === "string"
178
+ ? await createDirectoryReceipt(directory, label)
179
+ : ownDirectoryReceipt(directory);
145
180
  let pinned;
146
181
  try {
147
182
  pinned = await pinDirectory(receipt, { label });
@@ -162,11 +197,13 @@ export async function syncDirectory(directory, options = {}) {
162
197
  }
163
198
  export function syncDirectorySync(directory, options = {}) {
164
199
  const label = options.label ?? "directory";
165
- const receipt = typeof directory === "string" ? createDirectoryReceiptSync(directory, label) : directory;
200
+ const receipt = typeof directory === "string"
201
+ ? createDirectoryReceiptSync(directory, label)
202
+ : ownDirectoryReceipt(directory);
166
203
  assertDirectoryReceiptCurrentSync(receipt, label);
167
204
  let descriptor;
168
205
  try {
169
- descriptor = fsSync.openSync(receipt.path, directoryOpenFlags());
206
+ descriptor = fsSync.openSync(pathForWindowsFilesystem(receipt.path), directoryOpenFlags());
170
207
  }
171
208
  catch (error) {
172
209
  if (!isWindowsDirectoryOpenUnsupported(error)) {
@@ -211,7 +248,9 @@ export function syncDirectoryBestEffortSync(directoryPath) {
211
248
  }
212
249
  }
213
250
  async function findExistingAncestorReceipt(targetPath, label) {
214
- let currentPath = path.resolve(targetPath);
251
+ assertNoWindowsPathAlias(targetPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
252
+ let currentPath = resolvePathPreservingWindowsRoot(targetPath);
253
+ assertNoWindowsPathAlias(currentPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
215
254
  while (true) {
216
255
  try {
217
256
  return await createDirectoryReceipt(currentPath, label);
@@ -229,12 +268,16 @@ async function findExistingAncestorReceipt(targetPath, label) {
229
268
  }
230
269
  }
231
270
  export async function ensureDurableDirectory(options) {
232
- const directoryPath = path.resolve(options.directoryPath);
233
271
  const label = options.label ?? "directory";
272
+ const requestedDirectoryPath = options.directoryPath;
273
+ assertNoWindowsPathAlias(requestedDirectoryPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
274
+ const directoryPath = resolvePathPreservingWindowsRoot(requestedDirectoryPath);
275
+ assertNoWindowsPathAlias(directoryPath, "filesystem", `${label} path uses a Windows filesystem namespace alias`);
234
276
  const ancestorReceipt = await findExistingAncestorReceipt(directoryPath, label);
235
277
  const targetExists = ancestorReceipt.path === directoryPath;
236
- if (options.expectedExistingIdentity &&
237
- (!targetExists || !sameFileIdentity(options.expectedExistingIdentity, ancestorReceipt.identity))) {
278
+ const expectedExistingIdentity = options.expectedExistingIdentity;
279
+ if (expectedExistingIdentity &&
280
+ (!targetExists || !sameFileIdentity(expectedExistingIdentity, ancestorReceipt.identity))) {
238
281
  throw new FsSafeError("path-mismatch", `${label} changed before durable directory pinning: ${directoryPath}`);
239
282
  }
240
283
  const ancestor = await pinDirectory(ancestorReceipt, { label });
@@ -242,8 +285,9 @@ export async function ensureDurableDirectory(options) {
242
285
  try {
243
286
  await ancestor.assertCurrent();
244
287
  if (!targetExists) {
245
- if (options.create) {
246
- await options.create(directoryPath);
288
+ const create = options.create;
289
+ if (create) {
290
+ await Reflect.apply(create, options, [directoryPath]);
247
291
  }
248
292
  else {
249
293
  const created = await ensureAbsoluteDirectory(directoryPath, {
@@ -0,0 +1,3 @@
1
+ /** Strip only trailing separators: lstat must inspect the entry, not follow a leaf link. */
2
+ export declare function directoryEntryPath(dir: string, platform?: NodeJS.Platform): string;
3
+ //# sourceMappingURL=directory-entry-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-entry-path.d.ts","sourceRoot":"","sources":["../src/directory-entry-path.ts"],"names":[],"mappings":"AAEA,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,kBAAmB,GAAG,MAAM,CAenF"}
@@ -0,0 +1,21 @@
1
+ import path from "node:path";
2
+ /** Strip only trailing separators: lstat must inspect the entry, not follow a leaf link. */
3
+ export function directoryEntryPath(dir, platform = process.platform) {
4
+ const windows = platform === "win32";
5
+ if (typeof dir === "string") {
6
+ const last = dir[dir.length - 1];
7
+ if (last !== "/" && (!windows || last !== "\\"))
8
+ return dir;
9
+ }
10
+ let rootLength = (windows ? path.win32 : path.posix).parse(dir).root.length;
11
+ if (windows && /^[\\/]{2}[?.][\\/]UNC[\\/]/i.test(dir)) {
12
+ // Node parses the namespace prefix as the root; retain the complete UNC share.
13
+ const uncRoot = path.win32.parse(`\\\\${dir.slice(8)}`).root;
14
+ if (uncRoot.length > 1)
15
+ rootLength = Math.max(rootLength, uncRoot.length + 6);
16
+ }
17
+ let end = dir.length;
18
+ while (end > rootLength && (dir[end - 1] === "/" || (windows && dir[end - 1] === "\\")))
19
+ end--;
20
+ return end === rootLength || end === dir.length ? dir : dir.slice(0, end);
21
+ }
@@ -1,4 +1,5 @@
1
1
  import type { BigIntStats, Stats } from "node:fs";
2
+ import { type ExactStatIdentity, type StatObservationReceipt } from "./stat-observation.js";
2
3
  export type AsyncDirectoryGuard<T extends Stats | BigIntStats = Stats> = {
3
4
  dir: string;
4
5
  realPath: string;
@@ -21,6 +22,7 @@ export declare function assertDirectoryIdentitySync(observedPath: string, expect
21
22
  }): void;
22
23
  export declare function createAsyncDirectoryGuard(dir: string, options: {
23
24
  bigint: true;
25
+ initial?: BigIntStats;
24
26
  }): Promise<AsyncDirectoryGuard<BigIntStats>>;
25
27
  export declare function createAsyncDirectoryGuard(dir: string, options?: {
26
28
  bigint?: false;
@@ -37,5 +39,19 @@ export declare function createNearestExistingDirectoryGuard(rootReal: string, ta
37
39
  }): Promise<AnyAsyncDirectoryGuard>;
38
40
  export declare function createNearestExistingSyncDirectoryGuard(rootReal: string, targetPath: string): SyncDirectoryGuard;
39
41
  export declare function inspectDirectoryIdentity(dir: string, expected?: Pick<BigIntStats, "dev" | "ino">): Promise<BigIntStats>;
40
- export declare function inspectDirectoryIdentitySync(dir: string, expected?: Pick<BigIntStats, "dev" | "ino">): BigIntStats;
42
+ export declare function observeDirectoryIdentitySync(dir: string, options: {
43
+ bigint: true;
44
+ }): BigIntStats;
45
+ export declare function observeDirectoryIdentitySync(dir: string, options?: {
46
+ bigint?: false;
47
+ }): Stats;
48
+ export declare function inspectDirectoryIdentitySync(dir: string, expected?: Pick<BigIntStats, "dev" | "ino">, initial?: BigIntStats, platform?: NodeJS.Platform): BigIntStats;
49
+ export type DirectoryObservationGuard = StatObservationReceipt & {
50
+ dir: string;
51
+ realPath: string;
52
+ };
53
+ export declare function extendDirectoryObservationGuard(observation: StatObservationReceipt, dir: string, realPath: string): DirectoryObservationGuard;
54
+ export declare function inspectDirectoryObservationSync(dir: string, expected?: ExactStatIdentity): StatObservationReceipt;
55
+ export declare function assertDirectoryObservationSync(dir: string, expected: ExactStatIdentity): Stats | BigIntStats;
56
+ export declare function assertDirectoryObservationGuardSync(guard: DirectoryObservationGuard): void;
41
57
  //# sourceMappingURL=directory-guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"directory-guard.d.ts","sourceRoot":"","sources":["../src/directory-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAUlD,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,KAAK,GAAG,WAAW,GAAG,KAAK,IAAI;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,CAAC,KAAK,GAAG,WAAW,CAAC,CAAC;AAE9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAGnF;AAED,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,IAAI,CAAC,iBAAiB,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE,IAAI,CAKN;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7H,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACnH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAStH,wBAAsB,yBAAyB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5F;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAMxE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,kBAAkB,GAAG,sBAAsB,GAAG,IAAI,CAajG;AAED,wBAAgB,mCAAmC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACxH,wBAAgB,mCAAmC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAqBzJ,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,kBAAkB,CAcpB;AAGD,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAE7H;AAmBD,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,GAC1C,WAAW,CAQb"}
1
+ {"version":3,"file":"directory-guard.d.ts","sourceRoot":"","sources":["../src/directory-guard.ts"],"names":[],"mappings":"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"}