@openclaw/fs-safe 0.10.0 → 0.12.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 (302) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/LICENSE +1 -0
  3. package/README.md +39 -6
  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 -1
  7. package/dist/advanced.d.ts.map +1 -1
  8. package/dist/advanced.js +5 -1
  9. package/dist/archive-durability.d.ts +6 -6
  10. package/dist/archive-durability.d.ts.map +1 -1
  11. package/dist/archive-durability.js +1 -1
  12. package/dist/archive-entry.d.ts.map +1 -1
  13. package/dist/archive-entry.js +8 -8
  14. package/dist/archive-gzip-tail.d.ts +1 -0
  15. package/dist/archive-gzip-tail.d.ts.map +1 -1
  16. package/dist/archive-gzip-tail.js +16 -9
  17. package/dist/archive-input.d.ts.map +1 -1
  18. package/dist/archive-input.js +4 -2
  19. package/dist/archive-merge.d.ts +5 -1
  20. package/dist/archive-merge.d.ts.map +1 -1
  21. package/dist/archive-merge.js +15 -12
  22. package/dist/archive-native.js +4 -4
  23. package/dist/archive-parser.wasm +0 -0
  24. package/dist/archive-read.d.ts.map +1 -1
  25. package/dist/archive-read.js +54 -42
  26. package/dist/archive-staging.d.ts +6 -3
  27. package/dist/archive-staging.d.ts.map +1 -1
  28. package/dist/archive-staging.js +42 -22
  29. package/dist/archive-tar-stream.d.ts.map +1 -1
  30. package/dist/archive-tar-stream.js +7 -6
  31. package/dist/archive-tar-wasm.d.ts.map +1 -1
  32. package/dist/archive-tar-wasm.js +16 -13
  33. package/dist/archive-zip-admission.d.ts +1 -1
  34. package/dist/archive-zip-admission.d.ts.map +1 -1
  35. package/dist/archive-zip-admission.js +48 -12
  36. package/dist/archive-zip-loader.d.ts +6 -0
  37. package/dist/archive-zip-loader.d.ts.map +1 -0
  38. package/dist/archive-zip-loader.js +38 -0
  39. package/dist/archive-zip-names.d.ts.map +1 -1
  40. package/dist/archive-zip-names.js +26 -9
  41. package/dist/archive-zip-preflight.d.ts +2 -3
  42. package/dist/archive-zip-preflight.d.ts.map +1 -1
  43. package/dist/archive-zip-preflight.js +2 -34
  44. package/dist/archive.d.ts.map +1 -1
  45. package/dist/archive.js +12 -10
  46. package/dist/bounded-read.d.ts +5 -0
  47. package/dist/bounded-read.d.ts.map +1 -1
  48. package/dist/bounded-read.js +18 -11
  49. package/dist/copy-file-input.d.ts +0 -1
  50. package/dist/copy-file-input.d.ts.map +1 -1
  51. package/dist/copy-file-input.js +4 -26
  52. package/dist/copy-tree-portable.d.ts.map +1 -1
  53. package/dist/copy-tree-portable.js +57 -26
  54. package/dist/copy.d.ts +1 -1
  55. package/dist/copy.d.ts.map +1 -1
  56. package/dist/copy.js +3 -1
  57. package/dist/device-path.d.ts.map +1 -1
  58. package/dist/device-path.js +5 -3
  59. package/dist/directory-durability.d.ts.map +1 -1
  60. package/dist/directory-durability.js +5 -4
  61. package/dist/directory-guard.d.ts +11 -1
  62. package/dist/directory-guard.d.ts.map +1 -1
  63. package/dist/directory-guard.js +53 -11
  64. package/dist/durability.d.ts +1 -1
  65. package/dist/durability.d.ts.map +1 -1
  66. package/dist/durability.js +1 -1
  67. package/dist/file-handle-transfer.d.ts +14 -0
  68. package/dist/file-handle-transfer.d.ts.map +1 -0
  69. package/dist/file-handle-transfer.js +64 -0
  70. package/dist/file-hash.d.ts +3 -0
  71. package/dist/file-hash.d.ts.map +1 -1
  72. package/dist/file-hash.js +99 -32
  73. package/dist/file-lock-sync.d.ts.map +1 -1
  74. package/dist/file-lock-sync.js +8 -4
  75. package/dist/file-store-boundary.d.ts.map +1 -1
  76. package/dist/file-store-boundary.js +7 -5
  77. package/dist/file-store-path.d.ts +3 -0
  78. package/dist/file-store-path.d.ts.map +1 -0
  79. package/dist/file-store-path.js +27 -0
  80. package/dist/file-store-prune.d.ts.map +1 -1
  81. package/dist/file-store-prune.js +15 -5
  82. package/dist/file-store-sync-write.d.ts.map +1 -1
  83. package/dist/file-store-sync-write.js +56 -44
  84. package/dist/file-store.d.ts.map +1 -1
  85. package/dist/file-store.js +2 -18
  86. package/dist/filename.d.ts +1 -0
  87. package/dist/filename.d.ts.map +1 -1
  88. package/dist/filename.js +32 -14
  89. package/dist/guarded-mkdir.d.ts +2 -0
  90. package/dist/guarded-mkdir.d.ts.map +1 -1
  91. package/dist/guarded-mkdir.js +52 -16
  92. package/dist/guest-dispatch-python.d.ts +2 -0
  93. package/dist/guest-dispatch-python.d.ts.map +1 -0
  94. package/dist/guest-dispatch-python.js +117 -0
  95. package/dist/guest-native-python.d.ts +4 -0
  96. package/dist/guest-native-python.d.ts.map +1 -0
  97. package/dist/guest-native-python.js +135 -0
  98. package/dist/guest.d.ts +9 -0
  99. package/dist/guest.d.ts.map +1 -0
  100. package/dist/guest.js +421 -0
  101. package/dist/index.d.ts +1 -1
  102. package/dist/index.d.ts.map +1 -1
  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 +16 -2
  106. package/dist/json-durable-queue-directory.js +3 -3
  107. package/dist/json-durable-queue-ownership.d.ts +2 -0
  108. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  109. package/dist/json-durable-queue-ownership.js +47 -3
  110. package/dist/json-durable-queue-read.d.ts +6 -0
  111. package/dist/json-durable-queue-read.d.ts.map +1 -0
  112. package/dist/json-durable-queue-read.js +59 -0
  113. package/dist/json-durable-queue.d.ts +1 -1
  114. package/dist/json-durable-queue.d.ts.map +1 -1
  115. package/dist/json-durable-queue.js +43 -84
  116. package/dist/json.d.ts.map +1 -1
  117. package/dist/json.js +2 -1
  118. package/dist/local-roots.d.ts.map +1 -1
  119. package/dist/local-roots.js +2 -1
  120. package/dist/move-path-stage.d.ts.map +1 -1
  121. package/dist/move-path-stage.js +2 -1
  122. package/dist/move-path.d.ts.map +1 -1
  123. package/dist/move-path.js +4 -3
  124. package/dist/mutation-authority.d.ts +1 -0
  125. package/dist/mutation-authority.d.ts.map +1 -1
  126. package/dist/mutation-authority.js +4 -4
  127. package/dist/native-binding.d.ts +14 -2
  128. package/dist/native-binding.d.ts.map +1 -1
  129. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  130. package/dist/native-pinned-write-windows.js +3 -2
  131. package/dist/native-pinned-write.d.ts.map +1 -1
  132. package/dist/native-pinned-write.js +2 -1
  133. package/dist/opened-realpath.d.ts.map +1 -1
  134. package/dist/opened-realpath.js +5 -4
  135. package/dist/output.d.ts +2 -0
  136. package/dist/output.d.ts.map +1 -1
  137. package/dist/output.js +2 -0
  138. package/dist/overwrite-file-handle.d.ts +8 -0
  139. package/dist/overwrite-file-handle.d.ts.map +1 -0
  140. package/dist/overwrite-file-handle.js +42 -0
  141. package/dist/path-case.d.ts +7 -0
  142. package/dist/path-case.d.ts.map +1 -0
  143. package/dist/path-case.js +136 -0
  144. package/dist/path-scope-lexical.d.ts +14 -0
  145. package/dist/path-scope-lexical.d.ts.map +1 -0
  146. package/dist/path-scope-lexical.js +27 -0
  147. package/dist/path.d.ts.map +1 -1
  148. package/dist/path.js +22 -3
  149. package/dist/permissions-windows.d.ts +1 -1
  150. package/dist/permissions-windows.d.ts.map +1 -1
  151. package/dist/permissions-windows.js +48 -6
  152. package/dist/pinned-open.d.ts.map +1 -1
  153. package/dist/pinned-open.js +3 -1
  154. package/dist/pinned-write.d.ts +2 -2
  155. package/dist/pinned-write.d.ts.map +1 -1
  156. package/dist/pinned-write.js +3 -1
  157. package/dist/private-temp-workspace.d.ts.map +1 -1
  158. package/dist/private-temp-workspace.js +6 -4
  159. package/dist/realpath.d.ts +4 -0
  160. package/dist/realpath.d.ts.map +1 -0
  161. package/dist/realpath.js +43 -0
  162. package/dist/recursive-mkdir-path.d.ts +3 -0
  163. package/dist/recursive-mkdir-path.d.ts.map +1 -0
  164. package/dist/recursive-mkdir-path.js +8 -0
  165. package/dist/replace-directory.d.ts.map +1 -1
  166. package/dist/replace-directory.js +2 -1
  167. package/dist/replace-file-copy-fallback.d.ts.map +1 -1
  168. package/dist/replace-file-copy-fallback.js +23 -31
  169. package/dist/replace-file-copy-source.d.ts.map +1 -1
  170. package/dist/replace-file-copy-source.js +7 -12
  171. package/dist/replace-file-mode.d.ts +3 -0
  172. package/dist/replace-file-mode.d.ts.map +1 -0
  173. package/dist/replace-file-mode.js +10 -0
  174. package/dist/replace-file.d.ts +1 -0
  175. package/dist/replace-file.d.ts.map +1 -1
  176. package/dist/replace-file.js +14 -8
  177. package/dist/root-boundary.d.ts +25 -0
  178. package/dist/root-boundary.d.ts.map +1 -0
  179. package/dist/root-boundary.js +177 -0
  180. package/dist/root-context.d.ts.map +1 -1
  181. package/dist/root-context.js +40 -13
  182. package/dist/root-create-input.d.ts +10 -0
  183. package/dist/root-create-input.d.ts.map +1 -0
  184. package/dist/root-create-input.js +80 -0
  185. package/dist/root-directory-list.d.ts +3 -1
  186. package/dist/root-directory-list.d.ts.map +1 -1
  187. package/dist/root-directory-list.js +31 -5
  188. package/dist/root-entries.d.ts +11 -0
  189. package/dist/root-entries.d.ts.map +1 -0
  190. package/dist/root-entries.js +61 -0
  191. package/dist/root-errors.d.ts +5 -5
  192. package/dist/root-errors.d.ts.map +1 -1
  193. package/dist/root-errors.js +13 -12
  194. package/dist/root-impl.d.ts +13 -3
  195. package/dist/root-impl.d.ts.map +1 -1
  196. package/dist/root-impl.js +93 -70
  197. package/dist/root-move-preflight.d.ts +8 -0
  198. package/dist/root-move-preflight.d.ts.map +1 -0
  199. package/dist/root-move-preflight.js +16 -0
  200. package/dist/root-options.d.ts +12 -1
  201. package/dist/root-options.d.ts.map +1 -1
  202. package/dist/root-path-existing.d.ts +2 -0
  203. package/dist/root-path-existing.d.ts.map +1 -1
  204. package/dist/root-path-existing.js +14 -5
  205. package/dist/root-path-symlink.d.ts.map +1 -1
  206. package/dist/root-path-symlink.js +3 -2
  207. package/dist/root-path.d.ts +2 -0
  208. package/dist/root-path.d.ts.map +1 -1
  209. package/dist/root-path.js +54 -26
  210. package/dist/root-paths.d.ts +2 -6
  211. package/dist/root-paths.d.ts.map +1 -1
  212. package/dist/root-paths.js +24 -32
  213. package/dist/root-remove.d.ts +5 -0
  214. package/dist/root-remove.d.ts.map +1 -0
  215. package/dist/root-remove.js +286 -0
  216. package/dist/root-symlink-policy.d.ts +2 -1
  217. package/dist/root-symlink-policy.d.ts.map +1 -1
  218. package/dist/root-symlink-policy.js +2 -2
  219. package/dist/root-walk.d.ts.map +1 -1
  220. package/dist/root-walk.js +2 -1
  221. package/dist/root-write-mode.d.ts +2 -0
  222. package/dist/root-write-mode.d.ts.map +1 -1
  223. package/dist/root-write-mode.js +21 -7
  224. package/dist/root-write-verification.d.ts.map +1 -1
  225. package/dist/root-write-verification.js +12 -3
  226. package/dist/root.d.ts +2 -1
  227. package/dist/root.d.ts.map +1 -1
  228. package/dist/safe-path-segment.d.ts.map +1 -1
  229. package/dist/safe-path-segment.js +3 -1
  230. package/dist/secret-file.d.ts.map +1 -1
  231. package/dist/secret-file.js +2 -1
  232. package/dist/secret-read-async.d.ts.map +1 -1
  233. package/dist/secret-read-async.js +2 -1
  234. package/dist/secure-file-windows.d.ts +10 -0
  235. package/dist/secure-file-windows.d.ts.map +1 -0
  236. package/dist/secure-file-windows.js +186 -0
  237. package/dist/secure-file.d.ts.map +1 -1
  238. package/dist/secure-file.js +27 -7
  239. package/dist/secure-temp-dir.d.ts.map +1 -1
  240. package/dist/secure-temp-dir.js +2 -1
  241. package/dist/sibling-staged-file.d.ts +2 -0
  242. package/dist/sibling-staged-file.d.ts.map +1 -1
  243. package/dist/sibling-staged-file.js +49 -8
  244. package/dist/sibling-temp.d.ts +2 -0
  245. package/dist/sibling-temp.d.ts.map +1 -1
  246. package/dist/sibling-temp.js +8 -5
  247. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  248. package/dist/sidecar-lock-acquire.js +16 -5
  249. package/dist/sidecar-lock-policy.d.ts +2 -0
  250. package/dist/sidecar-lock-policy.d.ts.map +1 -1
  251. package/dist/sidecar-lock-policy.js +17 -0
  252. package/dist/sidecar-lock.d.ts.map +1 -1
  253. package/dist/sidecar-lock.js +2 -3
  254. package/dist/staged-directory.d.ts.map +1 -1
  255. package/dist/staged-directory.js +4 -3
  256. package/dist/temp-target.d.ts +14 -12
  257. package/dist/temp-target.d.ts.map +1 -1
  258. package/dist/temp-target.js +15 -7
  259. package/dist/trash.d.ts.map +1 -1
  260. package/dist/trash.js +7 -5
  261. package/dist/unicode-path.d.ts +3 -0
  262. package/dist/unicode-path.d.ts.map +1 -0
  263. package/dist/unicode-path.js +13 -0
  264. package/dist/walk.d.ts.map +1 -1
  265. package/dist/walk.js +14 -12
  266. package/dist/write-file-handle.d.ts +1 -0
  267. package/dist/write-file-handle.d.ts.map +1 -1
  268. package/dist/write-file-handle.js +3 -2
  269. package/docs/advanced.md +7 -1
  270. package/docs/archive.md +31 -5
  271. package/docs/atomic.md +17 -1
  272. package/docs/config.md +1 -0
  273. package/docs/contributing.md +33 -2
  274. package/docs/copy.md +75 -6
  275. package/docs/directory-identity.md +85 -0
  276. package/docs/durability.md +40 -3
  277. package/docs/entries.md +109 -0
  278. package/docs/errors.md +3 -3
  279. package/docs/file-store.md +21 -0
  280. package/docs/filename.md +9 -2
  281. package/docs/guest.md +146 -0
  282. package/docs/in-place-write.md +81 -0
  283. package/docs/index.md +2 -0
  284. package/docs/install-path.md +59 -13
  285. package/docs/install.md +34 -0
  286. package/docs/native-helper.md +14 -5
  287. package/docs/native.md +18 -2
  288. package/docs/output.md +32 -6
  289. package/docs/path-case.md +64 -0
  290. package/docs/path-scope.md +1 -1
  291. package/docs/path.md +1 -1
  292. package/docs/permissions.md +37 -3
  293. package/docs/public-api.md +36 -2
  294. package/docs/root.md +33 -3
  295. package/docs/secure-file.md +17 -14
  296. package/docs/security-model.md +1 -1
  297. package/docs/sidecar-lock.md +12 -3
  298. package/docs/store.md +22 -1
  299. package/docs/temp.md +39 -6
  300. package/docs/types.md +1 -1
  301. package/docs/writing.md +153 -3
  302. package/package.json +14 -8
@@ -2,6 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { FsSafeError } from "./errors.js";
4
4
  import { isNotFoundPathError, isSymlinkOpenError } from "./path.js";
5
+ import { realpathSync } from "./realpath.js";
5
6
  import { resolvePathViaExistingAncestor, resolvePathViaExistingAncestorSync, } from "./root-path-existing.js";
6
7
  function normalizeSymlinkResolutionError(error, options) {
7
8
  if (isSymlinkOpenError(error) ||
@@ -15,7 +16,7 @@ function normalizeSymlinkResolutionError(error, options) {
15
16
  }
16
17
  export async function resolveSymlinkHopPath(symlinkPath, options = {}) {
17
18
  try {
18
- return path.resolve(fs.realpathSync.native(symlinkPath));
19
+ return path.resolve(realpathSync.native(symlinkPath));
19
20
  }
20
21
  catch (error) {
21
22
  normalizeSymlinkResolutionError(error, options);
@@ -25,7 +26,7 @@ export async function resolveSymlinkHopPath(symlinkPath, options = {}) {
25
26
  }
26
27
  export function resolveSymlinkHopPathSync(symlinkPath, options = {}) {
27
28
  try {
28
- return path.resolve(fs.realpathSync(symlinkPath));
29
+ return path.resolve(realpathSync(symlinkPath));
29
30
  }
30
31
  catch (error) {
31
32
  normalizeSymlinkResolutionError(error, options);
@@ -1,3 +1,4 @@
1
+ import { type RootBoundaryIdentity } from "./root-boundary.js";
1
2
  export { resolvePathViaExistingAncestorSync } from "./root-path-existing.js";
2
3
  type RootPathIntent = "read" | "write" | "create" | "delete" | "stat";
3
4
  export type RootPathAliasPolicy = {
@@ -25,6 +26,7 @@ type ResolveRootPathParams = {
25
26
  rejectUnresolvedSymlinks?: boolean;
26
27
  skipLexicalRootCheck?: boolean;
27
28
  rootCanonicalPath?: string;
29
+ rootIdentity?: RootBoundaryIdentity;
28
30
  };
29
31
  type ResolvedRootPathKind = "missing" | "file" | "directory" | "symlink" | "other";
30
32
  export type ResolvedRootPath = {
@@ -1 +1 @@
1
- {"version":3,"file":"root-path.d.ts","sourceRoot":"","sources":["../src/root-path.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yBAAyB,CAAC;AAE7E,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;aACnC,MAAM;;;;aAIN,YAAY;;;;CAIJ,CAAC;AAEX,KAAK,qBAAqB,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,oBAAoB,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEnF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAAC;AAEF,wBAAsB,eAAe,CACnC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAM3B;AAeD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,gBAAgB,CAMnF"}
1
+ {"version":3,"file":"root-path.d.ts","sourceRoot":"","sources":["../src/root-path.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,kCAAkC,EAAE,MAAM,yBAAyB,CAAC;AAE7E,KAAK,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;aACnC,MAAM;;;;aAIN,YAAY;;;;CAIJ,CAAC;AAEX,KAAK,qBAAqB,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAEF,KAAK,oBAAoB,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAEnF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAAC;AAEF,wBAAsB,eAAe,CACnC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAM3B;AAcD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,gBAAgB,CAMnF"}
package/dist/root-path.js CHANGED
@@ -2,8 +2,9 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { formatErrorDetail, shortPath } from "./error-detail.js";
4
4
  import { FsSafeError } from "./errors.js";
5
- import { assertNoNulPathInput, isNotFoundPathError, isPathInside, isPathRelativeEscape, } from "./path.js";
5
+ import { assertNoNulPathInput, isNotFoundPathError, isPathRelativeEscape, } from "./path.js";
6
6
  import { absolutePathWithRawSegments, rawPathRelativeToCanonicalRoot, resolvePathViaExistingAncestor, resolvePathViaExistingAncestorSync, } from "./root-path-existing.js";
7
+ import { admitPathInsideRoot, } from "./root-boundary.js";
7
8
  import { resolveSymlinkHopPath, resolveSymlinkHopPathSync } from "./root-path-symlink.js";
8
9
  import { assertNoDriveRelativePathSegments } from "./safe-path-segment.js";
9
10
  export { resolvePathViaExistingAncestorSync } from "./root-path-existing.js";
@@ -29,11 +30,10 @@ async function resolveRootPathInternal(params) {
29
30
  assertValidRootPathInputs(params);
30
31
  params = { ...params, absolutePath: absolutePathWithRawSegments(params.absolutePath) };
31
32
  const rootPath = path.resolve(params.rootPath);
32
- const absolutePath = path.resolve(params.absolutePath);
33
33
  const rootCanonicalPath = params.rootCanonicalPath
34
34
  ? path.resolve(params.rootCanonicalPath)
35
35
  : await resolvePathViaExistingAncestor(rootPath);
36
- return resolveRootPathLexicalAsync(prepareRootTraversal(params, rootPath, rootCanonicalPath, absolutePath));
36
+ return resolveRootPathLexicalAsync(prepareRootTraversal(params, rootPath, rootCanonicalPath));
37
37
  }
38
38
  export function resolveRootPathSync(params) {
39
39
  try {
@@ -47,25 +47,38 @@ function resolveRootPathSyncInternal(params) {
47
47
  assertValidRootPathInputs(params);
48
48
  params = { ...params, absolutePath: absolutePathWithRawSegments(params.absolutePath) };
49
49
  const rootPath = path.resolve(params.rootPath);
50
- const absolutePath = path.resolve(params.absolutePath);
51
50
  const rootCanonicalPath = params.rootCanonicalPath
52
51
  ? path.resolve(params.rootCanonicalPath)
53
52
  : resolvePathViaExistingAncestorSync(rootPath);
54
- return resolveRootPathLexicalSync(prepareRootTraversal(params, rootPath, rootCanonicalPath, absolutePath));
53
+ return resolveRootPathLexicalSync(prepareRootTraversal(params, rootPath, rootCanonicalPath));
55
54
  }
56
- function prepareRootTraversal(params, rootPath, rootCanonicalPath, absolutePath) {
55
+ function prepareRootTraversal(params, rootPath, rootCanonicalPath) {
56
+ const callerAbsolutePath = path.resolve(params.absolutePath);
57
57
  let raw = params.absolutePath;
58
- if (rawPathRelativeToRoot(rootPath, raw) === undefined) {
59
- const relative = rawPathRelativeToRoot(rootCanonicalPath, raw)
58
+ let trustedAbsolutePath = false;
59
+ const direct = admitRawPathInsideRoot(rootPath, raw, params.rootIdentity);
60
+ if (direct) {
61
+ raw = direct.path;
62
+ trustedAbsolutePath = direct.admission === "identity";
63
+ }
64
+ else {
65
+ const canonical = admitRawPathInsideRoot(rootCanonicalPath, raw, params.rootIdentity);
66
+ const relative = canonical?.relativePath
60
67
  ?? rawPathRelativeToCanonicalRoot(raw, rootCanonicalPath, params);
61
68
  if (relative === undefined) {
62
69
  throw pathEscapeError({ rootPath, absolutePath: raw, boundaryLabel: params.boundaryLabel });
63
70
  }
64
- raw = `${rootPath}${path.sep}${relative}`;
71
+ trustedAbsolutePath = canonical?.admission === "identity";
72
+ raw = relative === "" ? rootPath : `${rootPath}${path.sep}${relative}`;
65
73
  }
66
74
  return {
67
75
  params: raw === params.absolutePath ? params : { ...params, absolutePath: raw },
68
- rootPath, rootCanonicalPath, absolutePath,
76
+ rootPath,
77
+ rootCanonicalPath,
78
+ // Preserve the caller-spelling receipt for ordinary aliases. Only a
79
+ // Windows case-fold admission must return the identity-gated Root spelling,
80
+ // because downstream I/O must not reuse the ambiguous caller prefix.
81
+ absolutePath: trustedAbsolutePath ? path.resolve(raw) : callerAbsolutePath,
69
82
  };
70
83
  }
71
84
  function sanitizeRootPathError(error) {
@@ -93,7 +106,7 @@ function assertNoEmbeddedDriveRelativeSegment(filePath, label) {
93
106
  }
94
107
  function createLexicalTraversalState(params) {
95
108
  const rawAbsolutePath = params.params.absolutePath;
96
- const relative = rawPathRelativeToRoot(params.rootPath, rawAbsolutePath);
109
+ const relative = admitRawPathInsideRoot(params.rootPath, rawAbsolutePath, params.params.rootIdentity)?.relativePath;
97
110
  if (relative === undefined)
98
111
  throw new Error("Path traversal must begin at the root");
99
112
  const segments = splitTraversalSegments(relative);
@@ -124,7 +137,7 @@ function splitTraversalSegments(value) {
124
137
  segments.push(".");
125
138
  return segments;
126
139
  }
127
- function rawPathRelativeToRoot(rootPath, candidatePath) {
140
+ function admitRawPathInsideRoot(rootPath, candidatePath, rootIdentity) {
128
141
  if (!path.isAbsolute(candidatePath)) {
129
142
  return undefined;
130
143
  }
@@ -132,30 +145,36 @@ function rawPathRelativeToRoot(rootPath, candidatePath) {
132
145
  const candidate = process.platform === "win32"
133
146
  ? candidatePath.replaceAll("/", path.sep)
134
147
  : candidatePath;
148
+ if (process.platform === "win32") {
149
+ return admitPathInsideRoot({ rootPath: root, candidatePath: candidate, rootIdentity });
150
+ }
135
151
  if (candidate === root) {
136
- return "";
152
+ return { admission: "exact", path: candidate, relativePath: "" };
137
153
  }
138
154
  const rootWithSep = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
139
155
  const candidatePrefix = candidate.slice(0, rootWithSep.length);
140
- const prefixMatches = process.platform === "win32"
141
- ? candidatePrefix.toLowerCase() === rootWithSep.toLowerCase()
142
- : candidatePrefix === rootWithSep;
143
- return prefixMatches ? candidate.slice(rootWithSep.length) : undefined;
156
+ return candidatePrefix === rootWithSep
157
+ ? {
158
+ admission: "exact",
159
+ path: candidate,
160
+ relativePath: candidate.slice(rootWithSep.length),
161
+ }
162
+ : undefined;
144
163
  }
145
164
  function assertLexicalCursorInsideBoundary(context, candidatePath) {
146
- assertInsideBoundary({
165
+ return assertInsideBoundary({
147
166
  boundaryLabel: context.resolveParams.boundaryLabel,
148
167
  rootCanonicalPath: context.rootCanonicalPath,
168
+ rootIdentity: context.resolveParams.rootIdentity,
149
169
  candidatePath,
150
170
  absolutePath: context.absolutePath,
151
171
  });
152
172
  }
153
173
  function advanceCanonicalCursorForSegment(context, segment) {
154
- context.state.canonicalCursor = path.resolve(context.state.canonicalCursor, segment);
155
- assertLexicalCursorInsideBoundary(context, context.state.canonicalCursor);
174
+ context.state.canonicalCursor = assertLexicalCursorInsideBoundary(context, path.resolve(context.state.canonicalCursor, segment));
156
175
  }
157
176
  function finalizeLexicalResolution(context, kind) {
158
- assertLexicalCursorInsideBoundary(context, context.state.canonicalCursor);
177
+ context.state.canonicalCursor = assertLexicalCursorInsideBoundary(context, context.state.canonicalCursor);
159
178
  return buildResolvedRootPath({
160
179
  absolutePath: context.absolutePath,
161
180
  canonicalPath: context.state.canonicalCursor,
@@ -181,15 +200,19 @@ function lexicalStatDisposition(params) {
181
200
  return params.allowFinalSymlink && params.isLast ? "break" : "resolve-link";
182
201
  }
183
202
  function applyResolvedSymlinkHop(context, linkCanonical) {
184
- if (!isPathInside(context.rootCanonicalPath, linkCanonical)) {
203
+ let admitted;
204
+ try {
205
+ admitted = assertLexicalCursorInsideBoundary(context, linkCanonical);
206
+ }
207
+ catch {
185
208
  throw symlinkEscapeError({
186
209
  boundaryLabel: context.resolveParams.boundaryLabel,
187
210
  rootCanonicalPath: context.rootCanonicalPath,
188
211
  symlinkPath: context.state.lexicalCursor,
189
212
  });
190
213
  }
191
- context.state.canonicalCursor = linkCanonical;
192
- context.state.lexicalCursor = linkCanonical;
214
+ context.state.canonicalCursor = admitted;
215
+ context.state.lexicalCursor = admitted;
193
216
  }
194
217
  function applyParentTraversalStep(context) {
195
218
  context.state.lexicalCursor = path.resolve(context.state.lexicalCursor, "..");
@@ -380,8 +403,13 @@ function relativeInsideRoot(rootPath, targetPath) {
380
403
  return relative;
381
404
  }
382
405
  function assertInsideBoundary(params) {
383
- if (isPathInside(params.rootCanonicalPath, params.candidatePath)) {
384
- return;
406
+ const admitted = admitPathInsideRoot({
407
+ rootPath: params.rootCanonicalPath,
408
+ candidatePath: params.candidatePath,
409
+ rootIdentity: params.rootIdentity,
410
+ });
411
+ if (admitted) {
412
+ return admitted.path;
385
413
  }
386
414
  throw new Error(`Path resolves outside ${params.boundaryLabel} (${shortPath(params.rootCanonicalPath)}): ${shortPath(params.absolutePath)}`);
387
415
  }
@@ -1,4 +1,5 @@
1
1
  import { FsSafeError } from "./errors.js";
2
+ import { type ResolvePathWithinRootParams } from "./path-scope-lexical.js";
2
3
  type InvalidPathResult = {
3
4
  ok: false;
4
5
  error: string;
@@ -50,12 +51,7 @@ export type PathScope = {
50
51
  mode?: number;
51
52
  }): Promise<DirectoryResult>;
52
53
  };
53
- export declare function resolvePathWithinRoot(params: {
54
- rootDir: string;
55
- requestedPath: string;
56
- scopeLabel: string;
57
- defaultFileName?: string;
58
- }): {
54
+ export declare function resolvePathWithinRoot(params: ResolvePathWithinRootParams): {
59
55
  ok: true;
60
56
  path: string;
61
57
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"root-paths.d.ts","sourceRoot":"","sources":["../src/root-paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"root-paths.d.ts","sourceRoot":"","sources":["../src/root-paths.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAW1C,OAAO,EAAmC,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE5G,KAAK,iBAAiB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtD,KAAK,eAAe,GAChB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAC3D,KAAK,4BAA4B,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AACF,KAAK,4BAA4B,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,iBAAiB,CAAC;AACtF,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CACL,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,4BAA4B,CAAC;IACnE,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC1E,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IACvE,QAAQ,CACN,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,SAAS,CACP,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,uBAAuB,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GACpD,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7B,CAAC;AAuDF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,2BAA2B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAE3D;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCrE;AAuDD,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,eAAe,CAAC,CA2E3B;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,4BAA4B,GACnC,4BAA4B,CAwB9B;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAEvC;AAED,wBAAsB,oCAAoC,CACxD,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAEvC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAwC/E"}
@@ -5,19 +5,17 @@ import { formatErrorDetail } from "./error-detail.js";
5
5
  import { FsSafeError } from "./errors.js";
6
6
  import { assertNoNulPathInput, hasNodeErrorCode, isNodeError, isNotFoundPathError, isPathInside, isPathRelativeEscape, } from "./path.js";
7
7
  import { root as openRoot } from "./root.js";
8
+ import { realpathSync } from "./realpath.js";
9
+ import { resolvePathWithinNormalizedRoot } from "./path-scope-lexical.js";
8
10
  function invalidPath(scopeLabel) {
9
11
  return {
10
12
  ok: false,
11
13
  error: `Invalid path: must stay within ${scopeLabel}`,
12
14
  };
13
15
  }
14
- function pathStaysWithinRoot(rootDir, candidatePath) {
15
- const relative = path.relative(rootDir, candidatePath);
16
- return Boolean(relative) && !isPathRelativeEscape(relative);
17
- }
18
16
  async function resolveRealPathIfExists(targetPath) {
19
17
  try {
20
- return fsSync.realpathSync.native(targetPath);
18
+ return realpathSync.native(targetPath);
21
19
  }
22
20
  catch {
23
21
  return undefined;
@@ -29,7 +27,7 @@ async function resolveTrustedRootRealPath(rootDir) {
29
27
  if (!rootLstat.isDirectory() || rootLstat.isSymbolicLink()) {
30
28
  return undefined;
31
29
  }
32
- return fsSync.realpathSync.native(rootDir);
30
+ return realpathSync.native(rootDir);
33
31
  }
34
32
  catch {
35
33
  return undefined;
@@ -50,7 +48,7 @@ async function validateCanonicalPathWithinRoot(params) {
50
48
  if (params.expect === "file" && candidateLstat.nlink > 1) {
51
49
  return "invalid";
52
50
  }
53
- const candidateRealPath = fsSync.realpathSync.native(params.candidatePath);
51
+ const candidateRealPath = realpathSync.native(params.candidatePath);
54
52
  return isPathInside(params.rootRealPath, candidateRealPath) ? "ok" : "invalid";
55
53
  }
56
54
  catch (err) {
@@ -58,23 +56,7 @@ async function validateCanonicalPathWithinRoot(params) {
58
56
  }
59
57
  }
60
58
  export function resolvePathWithinRoot(params) {
61
- const root = path.resolve(params.rootDir);
62
- const raw = params.requestedPath.trim();
63
- if (!raw) {
64
- if (!params.defaultFileName) {
65
- return { ok: false, error: "path is required" };
66
- }
67
- const defaultPath = path.resolve(root, params.defaultFileName);
68
- if (!pathStaysWithinRoot(root, defaultPath)) {
69
- return { ok: false, error: `Invalid path: must stay within ${params.scopeLabel}` };
70
- }
71
- return { ok: true, path: defaultPath };
72
- }
73
- const resolved = path.resolve(root, raw);
74
- if (!pathStaysWithinRoot(root, resolved)) {
75
- return { ok: false, error: `Invalid path: must stay within ${params.scopeLabel}` };
76
- }
77
- return { ok: true, path: resolved };
59
+ return resolvePathWithinNormalizedRoot(params, path.resolve(params.rootDir));
78
60
  }
79
61
  export async function resolveWritablePathWithinRoot(params) {
80
62
  const lexical = resolvePathWithinRoot(params);
@@ -169,9 +151,9 @@ export async function ensureDirectoryWithinRoot(params) {
169
151
  return invalidPath(scopeLabel);
170
152
  }
171
153
  await assertNoSymlinkSegments({ rootDir, targetPath, scopeLabel });
172
- const rootReal = fsSync.realpathSync.native(rootDir);
154
+ const rootReal = realpathSync.native(rootDir);
173
155
  const nearestExistingPath = await resolveNearestExistingPath(targetPath);
174
- const nearestExistingReal = fsSync.realpathSync.native(nearestExistingPath);
156
+ const nearestExistingReal = realpathSync.native(nearestExistingPath);
175
157
  if (!isPathInside(rootReal, nearestExistingReal)) {
176
158
  return invalidPath(scopeLabel);
177
159
  }
@@ -202,12 +184,12 @@ export async function ensureDirectoryWithinRoot(params) {
202
184
  }
203
185
  }
204
186
  }
205
- const currentReal = fsSync.realpathSync.native(current);
187
+ const currentReal = realpathSync.native(current);
206
188
  if (!isPathInside(rootReal, currentReal)) {
207
189
  return invalidPath(scopeLabel);
208
190
  }
209
191
  }
210
- const targetReal = fsSync.realpathSync.native(targetPath);
192
+ const targetReal = realpathSync.native(targetPath);
211
193
  if (!isPathInside(rootReal, targetReal)) {
212
194
  return invalidPath(scopeLabel);
213
195
  }
@@ -229,12 +211,22 @@ export async function ensureDirectoryWithinRoot(params) {
229
211
  }
230
212
  export function resolvePathsWithinRoot(params) {
231
213
  const resolvedPaths = [];
214
+ let previousRootDir;
215
+ let previousResolvedRoot = "";
232
216
  for (const raw of params.requestedPaths) {
233
- const pathResult = resolvePathWithinRoot({
217
+ const request = {
234
218
  rootDir: params.rootDir,
235
219
  requestedPath: raw,
236
220
  scopeLabel: params.scopeLabel,
237
- });
221
+ };
222
+ // Relative roots may follow cwd changes made by an input iterator or getter.
223
+ const resolvedRoot = process.platform !== "win32" && typeof request.rootDir === "string" &&
224
+ request.rootDir.startsWith("/") && request.rootDir === previousRootDir
225
+ ? previousResolvedRoot
226
+ : path.resolve(request.rootDir);
227
+ previousRootDir = request.rootDir;
228
+ previousResolvedRoot = resolvedRoot;
229
+ const pathResult = resolvePathWithinNormalizedRoot(request, resolvedRoot);
238
230
  if (!pathResult.ok) {
239
231
  return { ok: false, error: pathResult.error };
240
232
  }
@@ -309,7 +301,7 @@ async function resolveCheckedPathsWithinRoot(params, allowMissingFallback) {
309
301
  return lexicalPathResult;
310
302
  }
311
303
  try {
312
- const resolvedExistingPath = fsSync.realpathSync.native(raw);
304
+ const resolvedExistingPath = realpathSync.native(raw);
313
305
  const relativePath = path.relative(rootRealPath, resolvedExistingPath);
314
306
  if (!isInRoot(relativePath)) {
315
307
  return lexicalPathResult;
@@ -351,7 +343,7 @@ async function resolveCheckedPathsWithinRoot(params, allowMissingFallback) {
351
343
  scopeLabel: params.scopeLabel,
352
344
  });
353
345
  const existingPath = await resolveNearestExistingPath(pathResult.fallbackPath);
354
- const existingRealPath = fsSync.realpathSync.native(existingPath);
346
+ const existingRealPath = realpathSync.native(existingPath);
355
347
  if (!isPathInside(rootRealPath, existingRealPath)) {
356
348
  return invalidPath(params.scopeLabel);
357
349
  }
@@ -0,0 +1,5 @@
1
+ import { type RootContext } from "./root-context.js";
2
+ import type { RootRemoveOptions } from "./root-options.js";
3
+ export declare function validateRemoveOptions(options: RootRemoveOptions): void;
4
+ export declare function removePathInRootFallback(root: RootContext, targetPath: string, options: RootRemoveOptions): Promise<void>;
5
+ //# sourceMappingURL=root-remove.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-remove.d.ts","sourceRoot":"","sources":["../src/root-remove.ts"],"names":[],"mappings":"AAeA,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAS3D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAgBtE;AA0CD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CA6Lf"}