@openclaw/fs-safe 0.14.0 → 0.16.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 (370) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +38 -10
  3. package/dist/advanced.d.ts +2 -1
  4. package/dist/advanced.d.ts.map +1 -1
  5. package/dist/advanced.js +2 -1
  6. package/dist/archive-kind.d.ts +0 -1
  7. package/dist/archive-kind.d.ts.map +1 -1
  8. package/dist/archive-kind.js +5 -17
  9. package/dist/archive-merge.d.ts.map +1 -1
  10. package/dist/archive-merge.js +113 -46
  11. package/dist/archive-parser.wasm +0 -0
  12. package/dist/archive-read.d.ts.map +1 -1
  13. package/dist/archive-read.js +10 -11
  14. package/dist/archive-tar-stream.d.ts +3 -0
  15. package/dist/archive-tar-stream.d.ts.map +1 -1
  16. package/dist/archive-tar-stream.js +56 -37
  17. package/dist/archive-tar-wasm.d.ts +16 -4
  18. package/dist/archive-tar-wasm.d.ts.map +1 -1
  19. package/dist/archive-tar-wasm.js +134 -34
  20. package/dist/archive-zip-directory.d.ts +4 -0
  21. package/dist/archive-zip-directory.d.ts.map +1 -1
  22. package/dist/archive-zip-directory.js +2 -0
  23. package/dist/archive-zip-entry.d.ts +6 -2
  24. package/dist/archive-zip-entry.d.ts.map +1 -1
  25. package/dist/archive-zip-entry.js +23 -8
  26. package/dist/archive-zip-integrity.d.ts.map +1 -1
  27. package/dist/archive-zip-integrity.js +3 -4
  28. package/dist/archive-zip-loader.d.ts.map +1 -1
  29. package/dist/archive-zip-loader.js +107 -31
  30. package/dist/archive-zip-names.d.ts +1 -0
  31. package/dist/archive-zip-names.d.ts.map +1 -1
  32. package/dist/archive-zip-names.js +6 -0
  33. package/dist/archive.d.ts.map +1 -1
  34. package/dist/archive.js +11 -11
  35. package/dist/bounded-read-stream.d.ts +0 -1
  36. package/dist/bounded-read-stream.d.ts.map +1 -1
  37. package/dist/bounded-read-stream.js +0 -6
  38. package/dist/clone-metadata.d.ts +1 -0
  39. package/dist/clone-metadata.d.ts.map +1 -1
  40. package/dist/clone-metadata.js +6 -2
  41. package/dist/copy-publication.d.ts +6 -0
  42. package/dist/copy-publication.d.ts.map +1 -1
  43. package/dist/copy-publication.js +3 -0
  44. package/dist/copy-tree-portable.d.ts.map +1 -1
  45. package/dist/copy-tree-portable.js +44 -24
  46. package/dist/copy.d.ts.map +1 -1
  47. package/dist/copy.js +29 -11
  48. package/dist/create-directory.d.ts +20 -0
  49. package/dist/create-directory.d.ts.map +1 -0
  50. package/dist/create-directory.js +130 -0
  51. package/dist/create-file-async.d.ts +7 -0
  52. package/dist/create-file-async.d.ts.map +1 -0
  53. package/dist/create-file-async.js +121 -0
  54. package/dist/create-file.d.ts +8 -0
  55. package/dist/create-file.d.ts.map +1 -0
  56. package/dist/create-file.js +190 -0
  57. package/dist/create-owned-file.d.ts +8 -0
  58. package/dist/create-owned-file.d.ts.map +1 -0
  59. package/dist/create-owned-file.js +16 -0
  60. package/dist/create.d.ts +4 -0
  61. package/dist/create.d.ts.map +1 -0
  62. package/dist/create.js +2 -0
  63. package/dist/creation-darwin.d.ts +7 -0
  64. package/dist/creation-darwin.d.ts.map +1 -0
  65. package/dist/creation-darwin.js +79 -0
  66. package/dist/creation-file-state.d.ts +19 -0
  67. package/dist/creation-file-state.d.ts.map +1 -0
  68. package/dist/creation-file-state.js +118 -0
  69. package/dist/creation-path.d.ts +21 -0
  70. package/dist/creation-path.d.ts.map +1 -0
  71. package/dist/creation-path.js +71 -0
  72. package/dist/creation-permissions.d.ts +19 -0
  73. package/dist/creation-permissions.d.ts.map +1 -0
  74. package/dist/creation-permissions.js +125 -0
  75. package/dist/directory-durability.d.ts +1 -1
  76. package/dist/directory-durability.d.ts.map +1 -1
  77. package/dist/directory-durability.js +22 -80
  78. package/dist/directory-guard.d.ts +3 -0
  79. package/dist/directory-guard.d.ts.map +1 -1
  80. package/dist/directory-mode-node.d.ts +2 -0
  81. package/dist/directory-mode-node.d.ts.map +1 -1
  82. package/dist/directory-mode-node.js +8 -0
  83. package/dist/directory-mode-owner.js +5 -5
  84. package/dist/directory-receipt.d.ts +24 -0
  85. package/dist/directory-receipt.d.ts.map +1 -0
  86. package/dist/directory-receipt.js +127 -0
  87. package/dist/file-cleanup.d.ts +19 -0
  88. package/dist/file-cleanup.d.ts.map +1 -0
  89. package/dist/file-cleanup.js +78 -0
  90. package/dist/file-handle-transfer.d.ts +2 -0
  91. package/dist/file-handle-transfer.d.ts.map +1 -1
  92. package/dist/file-handle-transfer.js +57 -2
  93. package/dist/file-identity.d.ts.map +1 -1
  94. package/dist/file-identity.js +18 -4
  95. package/dist/file-lock-sync-admission.d.ts +19 -0
  96. package/dist/file-lock-sync-admission.d.ts.map +1 -0
  97. package/dist/file-lock-sync-admission.js +93 -0
  98. package/dist/file-lock-sync-root-acquire.d.ts +4 -0
  99. package/dist/file-lock-sync-root-acquire.d.ts.map +1 -0
  100. package/dist/file-lock-sync-root-acquire.js +370 -0
  101. package/dist/file-lock-sync-root-arbitration.d.ts +18 -0
  102. package/dist/file-lock-sync-root-arbitration.d.ts.map +1 -0
  103. package/dist/file-lock-sync-root-arbitration.js +66 -0
  104. package/dist/file-lock-sync-root-held.d.ts +34 -0
  105. package/dist/file-lock-sync-root-held.d.ts.map +1 -0
  106. package/dist/file-lock-sync-root-held.js +393 -0
  107. package/dist/file-lock-sync-root-io.d.ts +44 -0
  108. package/dist/file-lock-sync-root-io.d.ts.map +1 -0
  109. package/dist/file-lock-sync-root-io.js +209 -0
  110. package/dist/file-lock-sync-root-mutation.d.ts +17 -0
  111. package/dist/file-lock-sync-root-mutation.d.ts.map +1 -0
  112. package/dist/file-lock-sync-root-mutation.js +277 -0
  113. package/dist/file-lock-sync-root-options.d.ts +20 -0
  114. package/dist/file-lock-sync-root-options.d.ts.map +1 -0
  115. package/dist/file-lock-sync-root-options.js +58 -0
  116. package/dist/file-lock-sync-root-registration.d.ts +2 -0
  117. package/dist/file-lock-sync-root-registration.d.ts.map +1 -0
  118. package/dist/file-lock-sync-root-registration.js +90 -0
  119. package/dist/file-lock-sync-root.d.ts +36 -0
  120. package/dist/file-lock-sync-root.d.ts.map +1 -0
  121. package/dist/file-lock-sync-root.js +361 -0
  122. package/dist/file-lock-sync-stale-admission.d.ts +24 -0
  123. package/dist/file-lock-sync-stale-admission.d.ts.map +1 -0
  124. package/dist/file-lock-sync-stale-admission.js +205 -0
  125. package/dist/file-lock-sync.d.ts.map +1 -1
  126. package/dist/file-lock-sync.js +245 -205
  127. package/dist/file-observation.d.ts +1 -1
  128. package/dist/file-observation.d.ts.map +1 -1
  129. package/dist/file-store-boundary.d.ts +2 -6
  130. package/dist/file-store-boundary.d.ts.map +1 -1
  131. package/dist/file-store-boundary.js +3 -9
  132. package/dist/file-store-prune.d.ts.map +1 -1
  133. package/dist/file-store-prune.js +5 -1
  134. package/dist/file-store-sync-write.d.ts.map +1 -1
  135. package/dist/file-store-sync-write.js +5 -8
  136. package/dist/file-store.d.ts.map +1 -1
  137. package/dist/file-store.js +47 -12
  138. package/dist/guarded-mkdir.d.ts +1 -0
  139. package/dist/guarded-mkdir.d.ts.map +1 -1
  140. package/dist/guarded-mkdir.js +36 -7
  141. package/dist/json-document-store.d.ts.map +1 -1
  142. package/dist/json-document-store.js +22 -15
  143. package/dist/json-durable-queue-ownership.d.ts +0 -1
  144. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  145. package/dist/json-durable-queue-ownership.js +0 -6
  146. package/dist/move-path.js +1 -1
  147. package/dist/native-binding.d.ts +13 -1
  148. package/dist/native-binding.d.ts.map +1 -1
  149. package/dist/native-fallback-warning.d.ts +4 -0
  150. package/dist/native-fallback-warning.d.ts.map +1 -0
  151. package/dist/native-fallback-warning.js +11 -0
  152. package/dist/native-operations.d.ts +0 -2
  153. package/dist/native-operations.d.ts.map +1 -1
  154. package/dist/native-operations.js +0 -24
  155. package/dist/native-parent-admission.d.ts +5 -2
  156. package/dist/native-parent-admission.d.ts.map +1 -1
  157. package/dist/native-parent-admission.js +27 -7
  158. package/dist/native-pinned-write-windows.d.ts +1 -1
  159. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  160. package/dist/native-pinned-write-windows.js +174 -29
  161. package/dist/native-pinned-write.d.ts.map +1 -1
  162. package/dist/native-pinned-write.js +26 -14
  163. package/dist/native-policy-parent-windows.d.ts +14 -0
  164. package/dist/native-policy-parent-windows.d.ts.map +1 -0
  165. package/dist/native-policy-parent-windows.js +209 -0
  166. package/dist/native-rename-outcome.d.ts +4 -0
  167. package/dist/native-rename-outcome.d.ts.map +1 -0
  168. package/dist/native-rename-outcome.js +8 -0
  169. package/dist/native-staged-file.d.ts +3 -2
  170. package/dist/native-staged-file.d.ts.map +1 -1
  171. package/dist/native-staged-file.js +121 -72
  172. package/dist/output.d.ts.map +1 -1
  173. package/dist/output.js +12 -8
  174. package/dist/owner-dacl.d.ts.map +1 -1
  175. package/dist/owner-dacl.js +10 -4
  176. package/dist/path-prefix.d.ts.map +1 -1
  177. package/dist/path-prefix.js +30 -8
  178. package/dist/path-suffix-aliases.d.ts +2 -0
  179. package/dist/path-suffix-aliases.d.ts.map +1 -1
  180. package/dist/path-suffix-aliases.js +25 -17
  181. package/dist/permission-exec.d.ts +2 -0
  182. package/dist/permission-exec.d.ts.map +1 -1
  183. package/dist/permission-exec.js +150 -21
  184. package/dist/permissions-windows.js +1 -1
  185. package/dist/pinned-mutation-admission.d.ts.map +1 -1
  186. package/dist/pinned-mutation-admission.js +10 -5
  187. package/dist/pinned-mutation-observation.d.ts +0 -1
  188. package/dist/pinned-mutation-observation.d.ts.map +1 -1
  189. package/dist/pinned-mutation-observation.js +0 -19
  190. package/dist/pinned-mutation-shared-route.d.ts +1 -0
  191. package/dist/pinned-mutation-shared-route.d.ts.map +1 -1
  192. package/dist/pinned-mutation-shared-route.js +1 -1
  193. package/dist/pinned-write-input.d.ts +4 -0
  194. package/dist/pinned-write-input.d.ts.map +1 -0
  195. package/dist/pinned-write-input.js +25 -0
  196. package/dist/pinned-write-mode.d.ts +5 -0
  197. package/dist/pinned-write-mode.d.ts.map +1 -0
  198. package/dist/pinned-write-mode.js +24 -0
  199. package/dist/pinned-write-staged.d.ts +6 -0
  200. package/dist/pinned-write-staged.d.ts.map +1 -0
  201. package/dist/pinned-write-staged.js +187 -0
  202. package/dist/pinned-write-types.d.ts +5 -0
  203. package/dist/pinned-write-types.d.ts.map +1 -1
  204. package/dist/pinned-write.d.ts.map +1 -1
  205. package/dist/pinned-write.js +35 -145
  206. package/dist/private-directory.d.ts.map +1 -1
  207. package/dist/private-directory.js +18 -4
  208. package/dist/private-producer-handoff-sync.d.ts +14 -0
  209. package/dist/private-producer-handoff-sync.d.ts.map +1 -0
  210. package/dist/private-producer-handoff-sync.js +114 -0
  211. package/dist/private-producer-handoff.d.ts +22 -4
  212. package/dist/private-producer-handoff.d.ts.map +1 -1
  213. package/dist/private-producer-handoff.js +140 -77
  214. package/dist/private-temp-workspace.d.ts.map +1 -1
  215. package/dist/private-temp-workspace.js +75 -121
  216. package/dist/publish-copy-stage.d.ts +2 -1
  217. package/dist/publish-copy-stage.d.ts.map +1 -1
  218. package/dist/publish-copy-stage.js +16 -7
  219. package/dist/publish-file.d.ts.map +1 -1
  220. package/dist/publish-file.js +2 -2
  221. package/dist/regular-file.d.ts.map +1 -1
  222. package/dist/regular-file.js +1 -15
  223. package/dist/replace-directory.d.ts.map +1 -1
  224. package/dist/replace-directory.js +256 -18
  225. package/dist/replace-file-copy-fallback.d.ts.map +1 -1
  226. package/dist/replace-file-copy-fallback.js +62 -70
  227. package/dist/replace-file-copy-source.d.ts.map +1 -1
  228. package/dist/replace-file-copy-source.js +10 -12
  229. package/dist/replace-file-temp-owner.d.ts +5 -9
  230. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  231. package/dist/replace-file-temp-owner.js +56 -72
  232. package/dist/replace-file.js +6 -6
  233. package/dist/retained-directory-replacement.d.ts +26 -0
  234. package/dist/retained-directory-replacement.d.ts.map +1 -0
  235. package/dist/retained-directory-replacement.js +193 -0
  236. package/dist/root-boundary.d.ts +1 -0
  237. package/dist/root-boundary.d.ts.map +1 -1
  238. package/dist/root-boundary.js +4 -0
  239. package/dist/root-context.d.ts +0 -8
  240. package/dist/root-context.d.ts.map +1 -1
  241. package/dist/root-context.js +0 -3
  242. package/dist/root-create-input.d.ts +8 -1
  243. package/dist/root-create-input.d.ts.map +1 -1
  244. package/dist/root-create-input.js +17 -4
  245. package/dist/root-directory-creation.d.ts +3 -3
  246. package/dist/root-directory-creation.d.ts.map +1 -1
  247. package/dist/root-directory-creation.js +15 -3
  248. package/dist/root-directory-list.d.ts +1 -0
  249. package/dist/root-directory-list.d.ts.map +1 -1
  250. package/dist/root-directory-list.js +1 -0
  251. package/dist/root-impl.d.ts.map +1 -1
  252. package/dist/root-impl.js +46 -17
  253. package/dist/root-move-noreplace.d.ts.map +1 -1
  254. package/dist/root-move-noreplace.js +24 -15
  255. package/dist/root-options.d.ts +12 -4
  256. package/dist/root-options.d.ts.map +1 -1
  257. package/dist/root-path-errors.d.ts +1 -0
  258. package/dist/root-path-errors.d.ts.map +1 -1
  259. package/dist/root-path-errors.js +11 -2
  260. package/dist/root-path-existing.d.ts.map +1 -1
  261. package/dist/root-path-existing.js +11 -35
  262. package/dist/root-path-stat.d.ts.map +1 -1
  263. package/dist/root-path-stat.js +59 -7
  264. package/dist/root-path.js +1 -13
  265. package/dist/root-remove.d.ts +1 -0
  266. package/dist/root-remove.d.ts.map +1 -1
  267. package/dist/root-remove.js +4 -0
  268. package/dist/root-walk.d.ts +1 -1
  269. package/dist/root-walk.d.ts.map +1 -1
  270. package/dist/root-walk.js +17 -2
  271. package/dist/root-write-admission.d.ts +0 -2
  272. package/dist/root-write-admission.d.ts.map +1 -1
  273. package/dist/root-write-admission.js +1 -15
  274. package/dist/root-write-complete-parent.d.ts.map +1 -1
  275. package/dist/root-write-complete-parent.js +7 -23
  276. package/dist/root-write-publication.js +1 -1
  277. package/dist/root-write-verification.d.ts.map +1 -1
  278. package/dist/root-write-verification.js +29 -42
  279. package/dist/secret-file.d.ts.map +1 -1
  280. package/dist/secret-file.js +3 -24
  281. package/dist/secret-read-async.d.ts.map +1 -1
  282. package/dist/secret-read-async.js +3 -24
  283. package/dist/secret-read-policy.d.ts +6 -2
  284. package/dist/secret-read-policy.d.ts.map +1 -1
  285. package/dist/secret-read-policy.js +26 -2
  286. package/dist/secure-file-windows.d.ts +6 -0
  287. package/dist/secure-file-windows.d.ts.map +1 -1
  288. package/dist/secure-file-windows.js +34 -117
  289. package/dist/secure-file.js +2 -2
  290. package/dist/sibling-temp.d.ts.map +1 -1
  291. package/dist/sibling-temp.js +23 -12
  292. package/dist/sidecar-lock-acquire.d.ts +2 -28
  293. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  294. package/dist/sidecar-lock-acquire.js +288 -199
  295. package/dist/sidecar-lock-admission-context.d.ts +19 -0
  296. package/dist/sidecar-lock-admission-context.d.ts.map +1 -0
  297. package/dist/sidecar-lock-admission-context.js +60 -0
  298. package/dist/sidecar-lock-admission-parser.d.ts +43 -0
  299. package/dist/sidecar-lock-admission-parser.d.ts.map +1 -0
  300. package/dist/sidecar-lock-admission-parser.js +113 -0
  301. package/dist/sidecar-lock-admission.d.ts +35 -0
  302. package/dist/sidecar-lock-admission.d.ts.map +1 -0
  303. package/dist/sidecar-lock-admission.js +7 -0
  304. package/dist/sidecar-lock-reclaim.d.ts +9 -4
  305. package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
  306. package/dist/sidecar-lock-reclaim.js +80 -25
  307. package/dist/sidecar-lock-root.d.ts.map +1 -1
  308. package/dist/sidecar-lock-root.js +2 -1
  309. package/dist/sidecar-lock-stale-admission.d.ts +39 -0
  310. package/dist/sidecar-lock-stale-admission.d.ts.map +1 -0
  311. package/dist/sidecar-lock-stale-admission.js +232 -0
  312. package/dist/sidecar-lock-target.d.ts +8 -0
  313. package/dist/sidecar-lock-target.d.ts.map +1 -0
  314. package/dist/sidecar-lock-target.js +55 -0
  315. package/dist/sidecar-lock.d.ts.map +1 -1
  316. package/dist/sidecar-lock.js +100 -16
  317. package/dist/staged-directory.d.ts.map +1 -1
  318. package/dist/staged-directory.js +6 -6
  319. package/dist/staged-file-settlement.d.ts +17 -0
  320. package/dist/staged-file-settlement.d.ts.map +1 -0
  321. package/dist/staged-file-settlement.js +57 -0
  322. package/dist/temp-workspace-descriptor.d.ts.map +1 -1
  323. package/dist/temp-workspace-descriptor.js +9 -27
  324. package/dist/temp-workspace-owner.d.ts.map +1 -1
  325. package/dist/temp-workspace-owner.js +8 -8
  326. package/dist/walk.d.ts +5 -1
  327. package/dist/walk.d.ts.map +1 -1
  328. package/dist/walk.js +19 -6
  329. package/dist/windows-owner.d.ts.map +1 -1
  330. package/dist/windows-owner.js +4 -3
  331. package/dist/windows-security-bridge.cs +336 -0
  332. package/dist/windows-security-bridge.ps1 +15 -0
  333. package/dist/windows-security-command.d.ts +26 -0
  334. package/dist/windows-security-command.d.ts.map +1 -0
  335. package/dist/windows-security-command.js +363 -0
  336. package/dist/windows-security-facts.d.ts +6 -0
  337. package/dist/windows-security-facts.d.ts.map +1 -0
  338. package/dist/windows-security-facts.js +108 -0
  339. package/docs/advanced.md +4 -2
  340. package/docs/archive.md +97 -46
  341. package/docs/atomic.md +85 -8
  342. package/docs/config.md +6 -2
  343. package/docs/contributing.md +44 -4
  344. package/docs/copy.md +37 -0
  345. package/docs/creation.md +128 -0
  346. package/docs/durability.md +24 -0
  347. package/docs/file-store.md +19 -0
  348. package/docs/install.md +31 -7
  349. package/docs/json-store.md +5 -0
  350. package/docs/migrating-to-0.5.md +15 -6
  351. package/docs/migrating-to-0.6.md +9 -4
  352. package/docs/native-helper.md +32 -12
  353. package/docs/native.md +38 -7
  354. package/docs/output.md +6 -0
  355. package/docs/path-prefix.md +10 -0
  356. package/docs/path-suffix-aliases.md +51 -6
  357. package/docs/permissions.md +50 -14
  358. package/docs/public-api.md +3 -2
  359. package/docs/root.md +56 -3
  360. package/docs/secret-file.md +11 -2
  361. package/docs/secure-file.md +9 -4
  362. package/docs/sidecar-lock.md +114 -8
  363. package/docs/staged-file.md +12 -3
  364. package/docs/temp.md +20 -3
  365. package/docs/walk.md +67 -1
  366. package/docs/writing.md +76 -6
  367. package/package.json +19 -16
  368. package/dist/darwin-acl.d.ts +0 -4
  369. package/dist/darwin-acl.d.ts.map +0 -1
  370. package/dist/darwin-acl.js +0 -24
@@ -0,0 +1,361 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {} from "./deny-mutations.js";
4
+ import { FsSafeError } from "./errors.js";
5
+ import { assertNoNulPathInput, isNotFoundPathError, isPathInside } from "./path.js";
6
+ import { resolveRootPathSync } from "./root-path.js";
7
+ import { isRootPathEscapeError } from "./root-path-errors.js";
8
+ import { admitPathInsideRoot } from "./root-boundary.js";
9
+ import { assertRootIdentityCurrentSync, } from "./root-context.js";
10
+ import { directoryComponentNotDirectoryError, outsideWorkspaceError, } from "./root-errors.js";
11
+ import { mutationSymlinkResolution, readSymlinkResolution, } from "./root-symlink-policy.js";
12
+ import { realpathSync } from "./realpath.js";
13
+ import { assertSynchronousCallbackResult } from "./mutation-authority.js";
14
+ import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
15
+ const retainedRootContexts = new WeakMap();
16
+ const retainedRootDefaults = new WeakMap();
17
+ /** @internal Registers only instances constructed by RootHandle itself. */
18
+ export function registerFileLockSyncRootAdapter(handle, context, defaults) {
19
+ const identity = context.rootIdentity;
20
+ if (typeof identity.dev !== "bigint" || typeof identity.ino !== "bigint")
21
+ return;
22
+ // Retain the already-created Root inputs directly. Registration adds no
23
+ // per-Root wrapper/context allocations for callers that never use sync locks.
24
+ retainedRootContexts.set(handle, context);
25
+ retainedRootDefaults.set(handle, defaults);
26
+ }
27
+ function snapshotPolicy(policy) {
28
+ if (policy === undefined)
29
+ return undefined;
30
+ const paths = policy.paths;
31
+ const prefixes = policy.prefixes;
32
+ return Object.freeze({
33
+ paths: paths === undefined ? undefined : Object.freeze([...paths]),
34
+ prefixes: prefixes === undefined ? undefined : Object.freeze([...prefixes]),
35
+ });
36
+ }
37
+ export function captureFileLockSyncRootAuthority(lockRoot) {
38
+ const adapter = lockRoot;
39
+ const retainedContext = retainedRootContexts.get(adapter);
40
+ const retainedDefaults = retainedRootDefaults.get(adapter);
41
+ if (!retainedContext || !retainedDefaults) {
42
+ throw new FsSafeError("helper-unavailable", "synchronous Root-backed file locks require a genuine fs-safe Root handle");
43
+ }
44
+ const identity = retainedContext.rootIdentity;
45
+ if (typeof identity.dev !== "bigint" || typeof identity.ino !== "bigint") {
46
+ throw new FsSafeError("helper-unavailable", "synchronous Root identity is unavailable");
47
+ }
48
+ const context = Object.freeze({
49
+ rootDir: retainedContext.rootDir,
50
+ rootGuard: retainedContext.rootGuard,
51
+ rootIdentity: Object.freeze({ dev: identity.dev, ino: identity.ino }),
52
+ rootReal: retainedContext.rootReal,
53
+ rootWithSep: retainedContext.rootWithSep,
54
+ });
55
+ const defaults = retainedDefaults;
56
+ const assertBeforeMutation = defaults.assertBeforeMutation;
57
+ const denyMutations = snapshotPolicy(defaults.denyMutations);
58
+ const hardlinks = defaults.hardlinks;
59
+ const mutationSymlinks = defaults.mutationSymlinks;
60
+ const symlinks = defaults.symlinks;
61
+ // Snapshot all defaults before the Root check and mutation-policy validation.
62
+ assertRootIdentityCurrentSync(context);
63
+ const mutation = mutationSymlinkResolution(mutationSymlinks);
64
+ const mutationPolicy = Object.freeze({
65
+ rejectSymlinks: mutation.rejectSymlinks,
66
+ rejectFinalSymlink: mutation.rejectFinalSymlink,
67
+ rejectUnresolvedSymlinks: true,
68
+ });
69
+ const readPolicy = Object.freeze({
70
+ ...readSymlinkResolution(symlinks),
71
+ rejectUnresolvedSymlinks: true,
72
+ });
73
+ return Object.freeze({
74
+ adapter,
75
+ context,
76
+ assertBeforeMutation,
77
+ denyMutations,
78
+ hardlinks,
79
+ mutationPolicy,
80
+ readPolicy,
81
+ policiesMatch: mutationPolicy.rejectSymlinks === readPolicy.rejectSymlinks &&
82
+ mutationPolicy.rejectFinalSymlink === readPolicy.rejectFinalSymlink,
83
+ });
84
+ }
85
+ export function invokeFileLockSyncRootMutationAuthority(authority) {
86
+ const assertion = authority.assertBeforeMutation;
87
+ if (!assertion)
88
+ return false;
89
+ // Match Root mutation semantics: callbacks are invoked unbound and a
90
+ // thenable result cannot authorize a synchronous filesystem mutation.
91
+ assertSynchronousCallbackResult(assertion(), "assertBeforeMutation");
92
+ return true;
93
+ }
94
+ function samePath(left, right) {
95
+ return path.relative(path.resolve(left), path.resolve(right)) === "";
96
+ }
97
+ function absoluteRootPath(authority, relativePath) {
98
+ const segments = relativePath.split(path.posix.sep);
99
+ const absolute = path.join(authority.context.rootReal, ...segments);
100
+ assertNoWindowsPathAlias(absolute, "filesystem", "sidecar lock path uses a Windows filesystem namespace alias");
101
+ return absolute;
102
+ }
103
+ function assertValidPolicyEntries(entries) {
104
+ const captured = [];
105
+ for (const entry of entries ?? []) {
106
+ if (!entry || !path.isAbsolute(entry)) {
107
+ throw new FsSafeError("invalid-path", "deny mutation paths must be non-empty absolute paths");
108
+ }
109
+ assertNoNulPathInput(entry, "deny mutation path contains a NUL byte");
110
+ assertNoWindowsPathAlias(entry, "filesystem", "deny mutation path uses a Windows filesystem namespace alias");
111
+ captured.push(resolvePathPreservingWindowsRoot(entry));
112
+ }
113
+ return captured;
114
+ }
115
+ function mutationComparablePaths(pathname) {
116
+ const resolved = resolvePathPreservingWindowsRoot(pathname);
117
+ assertNoWindowsPathAlias(resolved, "filesystem", "mutation path uses a Windows filesystem namespace alias");
118
+ let cursor = resolved;
119
+ const missing = [];
120
+ while (path.parse(cursor).root !== cursor) {
121
+ try {
122
+ fs.lstatSync(pathForWindowsFilesystem(cursor));
123
+ break;
124
+ }
125
+ catch (error) {
126
+ if (!isNotFoundPathError(error))
127
+ throw error;
128
+ missing.unshift(path.basename(cursor));
129
+ cursor = path.dirname(cursor);
130
+ }
131
+ }
132
+ // Deny policy is an authority boundary: unlike advisory key normalization,
133
+ // an ambiguous existing ancestor must not silently fall back to lexical form.
134
+ const canonicalAncestor = realpathSync.native(pathForWindowsFilesystem(cursor));
135
+ assertNoWindowsPathAlias(canonicalAncestor, "filesystem", "mutation path uses a Windows filesystem namespace alias");
136
+ const canonical = missing.length === 0
137
+ ? canonicalAncestor
138
+ : path.resolve(canonicalAncestor, ...missing);
139
+ assertNoWindowsPathAlias(canonical, "filesystem", "mutation path uses a Windows filesystem namespace alias");
140
+ return samePath(resolved, canonical) ? [resolved] : [resolved, canonical];
141
+ }
142
+ export function assertFileLockSyncRootMutationAllowed(pathname, policy, protectAncestors = false) {
143
+ if (!policy?.paths?.length && !policy?.prefixes?.length)
144
+ return;
145
+ const targets = mutationComparablePaths(pathname);
146
+ for (const entry of assertValidPolicyEntries(policy.paths)) {
147
+ for (const denied of mutationComparablePaths(entry)) {
148
+ for (const target of targets) {
149
+ if ((isPathInside(denied, target) && isPathInside(target, denied)) ||
150
+ (protectAncestors && isPathInside(target, denied))) {
151
+ throw new FsSafeError("denied-path", "path is denied by denyMutations policy");
152
+ }
153
+ }
154
+ }
155
+ }
156
+ for (const entry of assertValidPolicyEntries(policy.prefixes)) {
157
+ for (const denied of mutationComparablePaths(entry)) {
158
+ for (const target of targets) {
159
+ if (isPathInside(denied, target) || (protectAncestors && isPathInside(target, denied))) {
160
+ throw new FsSafeError("denied-path", "path is denied by denyMutations policy");
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ function resolveAdmittedPath(authority, absolutePath, policy, rootPath) {
167
+ const context = authority.context;
168
+ let resolved;
169
+ try {
170
+ resolved = resolveRootPathSync({
171
+ absolutePath,
172
+ // The shared resolver identity-gates ambiguous Windows matches against the
173
+ // original Root spelling before rebasing them to the retained canonical root.
174
+ rootPath,
175
+ rootCanonicalPath: context.rootReal,
176
+ rootIdentity: context.rootIdentity,
177
+ boundaryLabel: "sidecar lock root",
178
+ ...policy,
179
+ });
180
+ }
181
+ catch (error) {
182
+ if (isRootPathEscapeError(error)) {
183
+ throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot", { cause: error });
184
+ }
185
+ throw error;
186
+ }
187
+ const admitted = admitPathInsideRoot({
188
+ rootPath: context.rootReal,
189
+ candidatePath: resolved.canonicalPath,
190
+ rootIdentity: context.rootIdentity,
191
+ });
192
+ if (!admitted || admitted.relativePath === "" || samePath(admitted.path, context.rootReal)) {
193
+ throw outsideWorkspaceError();
194
+ }
195
+ return {
196
+ path: admitted.path,
197
+ relativePath: admitted.relativePath.split(path.sep).join(path.posix.sep),
198
+ };
199
+ }
200
+ function resolveBothPolicies(authority, absolutePath, rootPath) {
201
+ const { mutationPolicy, readPolicy, policiesMatch } = authority;
202
+ const mutation = resolveAdmittedPath(authority, absolutePath, mutationPolicy, rootPath);
203
+ const readable = policiesMatch
204
+ ? mutation
205
+ : resolveAdmittedPath(authority, absolutePath, readPolicy, rootPath);
206
+ if (!samePath(mutation.path, readable.path)) {
207
+ throw new FsSafeError("path-mismatch", "sidecar read and mutation paths resolve differently");
208
+ }
209
+ assertFileLockSyncRootMutationAllowed(mutation.path, authority.denyMutations);
210
+ return mutation;
211
+ }
212
+ function admitRequestedRootPrefix(authority, requestedPath) {
213
+ const context = authority.context;
214
+ const identityCache = process.platform === "win32" ? new Map() : undefined;
215
+ const original = admitPathInsideRoot({
216
+ rootPath: context.rootDir,
217
+ candidatePath: requestedPath,
218
+ rootIdentity: context.rootIdentity,
219
+ resolveCandidateRoot: context.rootDir !== context.rootReal,
220
+ identityCache,
221
+ });
222
+ if (original && original.relativePath !== "") {
223
+ return { path: original.path, rootPath: context.rootDir };
224
+ }
225
+ const canonical = context.rootDir === context.rootReal ? undefined : admitPathInsideRoot({
226
+ rootPath: context.rootReal,
227
+ candidatePath: requestedPath,
228
+ rootIdentity: context.rootIdentity,
229
+ identityCache,
230
+ });
231
+ if (!canonical || canonical.relativePath === "")
232
+ throw outsideWorkspaceError();
233
+ return { path: canonical.path, rootPath: context.rootReal };
234
+ }
235
+ export function admitFileLockSyncRootPath(authority, requestedPath) {
236
+ assertNoNulPathInput(requestedPath, "sidecar lock path contains a NUL byte");
237
+ const resolved = resolvePathPreservingWindowsRoot(requestedPath);
238
+ assertNoWindowsPathAlias(resolved, "filesystem", "sidecar lock path uses a Windows filesystem namespace alias");
239
+ assertRootIdentityCurrentSync(authority.context);
240
+ const prefixed = admitRequestedRootPrefix(authority, resolved);
241
+ const selected = resolveBothPolicies(authority, prefixed.path, prefixed.rootPath);
242
+ assertRootIdentityCurrentSync(authority.context);
243
+ const admitted = Object.freeze({
244
+ authority,
245
+ path: selected.path,
246
+ relativePath: selected.relativePath,
247
+ });
248
+ assertMissingParentMutationsAllowed(admitted);
249
+ return admitted;
250
+ }
251
+ export function assertFileLockSyncRootResolvedPathCurrent(pathAuthority) {
252
+ const resolved = resolveBothPolicies(pathAuthority.authority, absoluteRootPath(pathAuthority.authority, pathAuthority.relativePath), pathAuthority.authority.context.rootReal);
253
+ if (!samePath(resolved.path, pathAuthority.path)) {
254
+ throw new FsSafeError("path-mismatch", "sidecar lock path changed during operation");
255
+ }
256
+ }
257
+ function assertMissingParentMutationsAllowed(pathAuthority) {
258
+ const authority = pathAuthority.authority;
259
+ const context = authority.context;
260
+ const relativeParent = path.posix.dirname(pathAuthority.relativePath);
261
+ const relative = relativeParent === "." ? "" : relativeParent;
262
+ let current = context.rootReal;
263
+ let missing = false;
264
+ for (const segment of relative.split(path.posix.sep).filter(Boolean)) {
265
+ current = path.join(current, segment);
266
+ if (!missing) {
267
+ try {
268
+ const stat = fs.lstatSync(pathForWindowsFilesystem(current), { bigint: true });
269
+ if (stat.isSymbolicLink() || !stat.isDirectory())
270
+ throw directoryComponentNotDirectoryError();
271
+ }
272
+ catch (error) {
273
+ if (!isNotFoundPathError(error))
274
+ throw error;
275
+ missing = true;
276
+ }
277
+ }
278
+ if (missing)
279
+ assertFileLockSyncRootMutationAllowed(current, authority.denyMutations);
280
+ }
281
+ }
282
+ export function assertFileLockSyncRootPathsCurrent(paths, invokeAuthority = false, pathsAlreadyCurrent = false) {
283
+ const authority = paths[0]?.authority;
284
+ for (const pathAuthority of paths) {
285
+ if (authority && pathAuthority.authority !== authority) {
286
+ throw new FsSafeError("path-mismatch", "sidecar paths use different Root authority");
287
+ }
288
+ }
289
+ if (!pathsAlreadyCurrent) {
290
+ if (authority)
291
+ assertRootIdentityCurrentSync(authority.context);
292
+ for (const pathAuthority of paths) {
293
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
294
+ assertMissingParentMutationsAllowed(pathAuthority);
295
+ }
296
+ if (authority)
297
+ assertRootIdentityCurrentSync(authority.context);
298
+ }
299
+ if (invokeAuthority && authority && invokeFileLockSyncRootMutationAuthority(authority)) {
300
+ assertRootIdentityCurrentSync(authority.context);
301
+ for (const pathAuthority of paths) {
302
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
303
+ assertMissingParentMutationsAllowed(pathAuthority);
304
+ }
305
+ assertRootIdentityCurrentSync(authority.context);
306
+ }
307
+ }
308
+ function resolveTargetPathViaExistingAncestorSync(targetPath) {
309
+ const normalized = resolvePathPreservingWindowsRoot(targetPath);
310
+ const canonicalize = process.platform === "win32" ? realpathSync.native : realpathSync;
311
+ let cursor = normalized;
312
+ const missing = [];
313
+ while (true) {
314
+ try {
315
+ fs.lstatSync(pathForWindowsFilesystem(cursor));
316
+ try {
317
+ const canonicalAncestor = canonicalize(pathForWindowsFilesystem(cursor));
318
+ assertNoWindowsPathAlias(canonicalAncestor, "filesystem", "file-lock target ancestor uses a Windows filesystem namespace alias");
319
+ return missing.length === 0
320
+ ? resolvePathPreservingWindowsRoot(canonicalAncestor)
321
+ : resolvePathPreservingWindowsRoot(path.resolve(canonicalAncestor, ...missing));
322
+ }
323
+ catch (error) {
324
+ if (!isNotFoundPathError(error))
325
+ throw error;
326
+ // A dangling link is an existing lexical entry but not a canonical
327
+ // ancestor. Continue at its parent instead of abandoning native
328
+ // long/short-name normalization for the rest of the target path.
329
+ }
330
+ }
331
+ catch (error) {
332
+ if (!isNotFoundPathError(error))
333
+ throw error;
334
+ }
335
+ const parent = path.dirname(cursor);
336
+ if (parent === cursor) {
337
+ // Filesystem roots are expected to exist; preserve the underlying
338
+ // not-found diagnosis if a synthetic namespace violates that premise.
339
+ const canonicalAncestor = canonicalize(pathForWindowsFilesystem(cursor));
340
+ assertNoWindowsPathAlias(canonicalAncestor, "filesystem", "file-lock target ancestor uses a Windows filesystem namespace alias");
341
+ return missing.length === 0
342
+ ? resolvePathPreservingWindowsRoot(canonicalAncestor)
343
+ : resolvePathPreservingWindowsRoot(path.resolve(canonicalAncestor, ...missing));
344
+ }
345
+ missing.unshift(path.basename(cursor));
346
+ cursor = parent;
347
+ }
348
+ }
349
+ export function normalizeFileLockSyncTargetWithRoot(authority, resolvedTargetPath) {
350
+ assertNoNulPathInput(resolvedTargetPath, "file-lock target contains a NUL byte");
351
+ assertNoWindowsPathAlias(resolvedTargetPath, "filesystem", "file-lock target uses a Windows filesystem namespace alias");
352
+ assertRootIdentityCurrentSync(authority.context);
353
+ // Preserve POSIX's pathname-key behavior while making Windows resolve the
354
+ // complete existing prefix (including an existing 8.3-spelled filename).
355
+ const normalized = process.platform === "win32"
356
+ ? resolveTargetPathViaExistingAncestorSync(resolvedTargetPath)
357
+ : path.join(resolveTargetPathViaExistingAncestorSync(path.dirname(resolvedTargetPath)), path.basename(resolvedTargetPath));
358
+ assertNoWindowsPathAlias(normalized, "filesystem", "file-lock target uses a Windows filesystem namespace alias");
359
+ assertRootIdentityCurrentSync(authority.context);
360
+ return normalized;
361
+ }
@@ -0,0 +1,24 @@
1
+ import type { FileLockSyncAcquireOptions } from "./file-lock-sync.js";
2
+ import type { SidecarLockStaleRecovery } from "./sidecar-lock-types.js";
3
+ export type SyncStaleOptionsState<TPayload extends Record<string, unknown>> = {
4
+ shouldReclaimObserved?: boolean;
5
+ shouldReclaim?: FileLockSyncAcquireOptions<TPayload>["shouldReclaim"];
6
+ shouldRemoveObserved?: boolean;
7
+ shouldRemove?: FileLockSyncAcquireOptions<TPayload>["shouldRemoveStaleLock"];
8
+ };
9
+ /** Handle one exclusive-create conflict without surrendering canonical admission. */
10
+ export declare function handleSyncStaleAdmission<TPayload extends Record<string, unknown>>(params: {
11
+ hasToken(): boolean;
12
+ currentHeld(): unknown;
13
+ lockPath: string;
14
+ normalizedTargetPath: string;
15
+ options: FileLockSyncAcquireOptions<TPayload>;
16
+ parsePayload?: (raw: string) => unknown;
17
+ reclaimGuardPath: string;
18
+ retryLockFileDenial(error: unknown): boolean;
19
+ staleMs: number;
20
+ staleOptions: SyncStaleOptionsState<TPayload>;
21
+ staleRecovery?: SidecarLockStaleRecovery;
22
+ waitForRetry(): void;
23
+ }): void;
24
+ //# sourceMappingURL=file-lock-sync-stale-admission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock-sync-stale-admission.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-stale-admission.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAQtE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAExE,MAAM,MAAM,qBAAqB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC5E,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,CAAC;IACtE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,YAAY,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC,uBAAuB,CAAC,CAAC;CAC9E,CAAC;AAEF,qFAAqF;AACrF,wBAAgB,wBAAwB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE;IACzF,QAAQ,IAAI,OAAO,CAAC;IACpB,WAAW,IAAI,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAC9C,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,YAAY,IAAI,IAAI,CAAC;CACtB,GAAG,IAAI,CAiLP"}
@@ -0,0 +1,205 @@
1
+ import fs from "node:fs";
2
+ import { defaultSyncShouldReclaim, syncLockTimeout } from "./file-lock-sync-admission.js";
3
+ import { parseSidecarLockSnapshot, readSidecarLockRawSnapshotSync, removeSidecarLockIfUnchangedSync, } from "./sidecar-lock-reclaim.js";
4
+ /** Handle one exclusive-create conflict without surrendering canonical admission. */
5
+ export function handleSyncStaleAdmission(params) {
6
+ const holderChanged = {};
7
+ const assertUnheld = () => {
8
+ if (!params.hasToken()) {
9
+ throw syncLockTimeout(params.lockPath, params.normalizedTargetPath);
10
+ }
11
+ if (params.currentHeld())
12
+ throw holderChanged;
13
+ };
14
+ const retryHolderChange = (error) => {
15
+ if (error !== holderChanged)
16
+ return false;
17
+ params.waitForRetry();
18
+ return true;
19
+ };
20
+ let rawSnapshot;
21
+ let lockFileOpenDenied = false;
22
+ try {
23
+ rawSnapshot = readSidecarLockRawSnapshotSync(params.lockPath, {
24
+ rejectNonFile: true,
25
+ onOpenFailure: (error) => {
26
+ lockFileOpenDenied = true;
27
+ assertUnheld();
28
+ },
29
+ });
30
+ assertUnheld();
31
+ }
32
+ catch (error) {
33
+ if (retryHolderChange(error))
34
+ return;
35
+ try {
36
+ assertUnheld();
37
+ }
38
+ catch (boundaryError) {
39
+ if (retryHolderChange(boundaryError))
40
+ return;
41
+ throw boundaryError;
42
+ }
43
+ if (lockFileOpenDenied && params.retryLockFileDenial(error))
44
+ return;
45
+ throw error;
46
+ }
47
+ const stale = params.staleOptions;
48
+ try {
49
+ if (!stale.shouldReclaimObserved) {
50
+ assertUnheld();
51
+ stale.shouldReclaim = params.options.shouldReclaim;
52
+ stale.shouldReclaimObserved = true;
53
+ assertUnheld();
54
+ }
55
+ if (!stale.shouldRemoveObserved) {
56
+ assertUnheld();
57
+ stale.shouldRemove = params.options.shouldRemoveStaleLock;
58
+ stale.shouldRemoveObserved = true;
59
+ assertUnheld();
60
+ }
61
+ }
62
+ catch (error) {
63
+ if (retryHolderChange(error))
64
+ return;
65
+ try {
66
+ assertUnheld();
67
+ }
68
+ catch (boundaryError) {
69
+ if (retryHolderChange(boundaryError))
70
+ return;
71
+ throw boundaryError;
72
+ }
73
+ throw error;
74
+ }
75
+ const guardedParser = params.parsePayload && ((raw) => {
76
+ assertUnheld();
77
+ try {
78
+ return Reflect.apply(params.parsePayload, undefined, [raw]);
79
+ }
80
+ finally {
81
+ assertUnheld();
82
+ }
83
+ });
84
+ let snapshot;
85
+ try {
86
+ snapshot = parseSidecarLockSnapshot(rawSnapshot, guardedParser);
87
+ assertUnheld();
88
+ }
89
+ catch (error) {
90
+ if (retryHolderChange(error))
91
+ return;
92
+ throw error;
93
+ }
94
+ if (!snapshot) {
95
+ params.waitForRetry();
96
+ return;
97
+ }
98
+ const nowMs = Date.now();
99
+ let reclaim;
100
+ try {
101
+ assertUnheld();
102
+ try {
103
+ reclaim = stale.shouldReclaim
104
+ ? Reflect.apply(stale.shouldReclaim, params.options, [{
105
+ lockPath: params.lockPath,
106
+ normalizedTargetPath: params.normalizedTargetPath,
107
+ payload: snapshot.payload,
108
+ staleMs: params.staleMs,
109
+ nowMs,
110
+ heldByThisProcess: false,
111
+ }])
112
+ : defaultSyncShouldReclaim(snapshot, params.staleMs, nowMs);
113
+ }
114
+ finally {
115
+ assertUnheld();
116
+ }
117
+ }
118
+ catch (error) {
119
+ if (retryHolderChange(error))
120
+ return;
121
+ throw error;
122
+ }
123
+ if (!reclaim) {
124
+ params.waitForRetry();
125
+ return;
126
+ }
127
+ if (params.staleRecovery === "remove-if-unchanged" &&
128
+ snapshot.raw !== undefined &&
129
+ stale.shouldRemove !== undefined) {
130
+ let approved;
131
+ try {
132
+ assertUnheld();
133
+ try {
134
+ approved = Reflect.apply(stale.shouldRemove, params.options, [{
135
+ lockPath: params.lockPath,
136
+ normalizedTargetPath: params.normalizedTargetPath,
137
+ raw: snapshot.raw,
138
+ payload: snapshot.payload,
139
+ }]);
140
+ }
141
+ finally {
142
+ assertUnheld();
143
+ }
144
+ }
145
+ catch (error) {
146
+ if (retryHolderChange(error))
147
+ return;
148
+ throw error;
149
+ }
150
+ if (!approved) {
151
+ throw Object.assign(new Error(`file lock stale for ${params.normalizedTargetPath}`), {
152
+ code: "file_lock_stale",
153
+ lockPath: params.lockPath,
154
+ normalizedTargetPath: params.normalizedTargetPath,
155
+ });
156
+ }
157
+ try {
158
+ fs.mkdirSync(params.reclaimGuardPath);
159
+ }
160
+ catch (error) {
161
+ try {
162
+ assertUnheld();
163
+ }
164
+ catch (boundaryError) {
165
+ if (retryHolderChange(boundaryError))
166
+ return;
167
+ throw boundaryError;
168
+ }
169
+ if (error.code === "EEXIST") {
170
+ params.waitForRetry();
171
+ return;
172
+ }
173
+ throw error;
174
+ }
175
+ let holderInterrupted = false;
176
+ try {
177
+ assertUnheld();
178
+ if (removeSidecarLockIfUnchangedSync(params.lockPath, snapshot, assertUnheld))
179
+ return;
180
+ }
181
+ catch (error) {
182
+ if (error === holderChanged)
183
+ holderInterrupted = true;
184
+ else
185
+ throw error;
186
+ }
187
+ finally {
188
+ try {
189
+ fs.rmdirSync(params.reclaimGuardPath);
190
+ }
191
+ catch {
192
+ // A surviving reclaim guard fails closed.
193
+ }
194
+ }
195
+ if (holderInterrupted) {
196
+ params.waitForRetry();
197
+ return;
198
+ }
199
+ }
200
+ throw Object.assign(new Error(`file lock stale for ${params.normalizedTargetPath}`), {
201
+ code: "file_lock_stale",
202
+ lockPath: params.lockPath,
203
+ normalizedTargetPath: params.normalizedTargetPath,
204
+ });
205
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"file-lock-sync.d.ts","sourceRoot":"","sources":["../src/file-lock-sync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EASL,KAAK,wBAAwB,EAC9B,MAAM,2BAA2B,CAAC;AAWnC,OAAO,KAAK,EACV,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAQjC,MAAM,MAAM,0BAA0B,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,QAAQ,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,iBAAiB,EAAE,KAAK,CAAC;KAC1B,KAAK,OAAO,CAAC;IACd,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,OAAO,CAAC;IACxE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC3D,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,IAAI,OAAO,CAAC;IAC3B,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B,CAAC;AA8JF,wBAAgB,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,GAC5C,kBAAkB,CA4NpB;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,EAC7C,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAOH"}
1
+ {"version":3,"file":"file-lock-sync.d.ts","sourceRoot":"","sources":["../src/file-lock-sync.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAML,KAAK,wBAAwB,EAC9B,MAAM,2BAA2B,CAAC;AAUnC,OAAO,KAAK,EACV,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAqBjC,MAAM,MAAM,0BAA0B,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,QAAQ,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,iBAAiB,EAAE,KAAK,CAAC;KAC1B,KAAK,OAAO,CAAC;IACd,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,OAAO,CAAC;IACxE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC3D,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,IAAI,OAAO,CAAC;IAC3B,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B,CAAC;AAyFF,wBAAgB,mBAAmB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,GAC5C,kBAAkB,CAyRpB;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,EAC7C,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAQH"}