@openclaw/fs-safe 0.14.0 → 0.15.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 (235) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +10 -4
  3. package/dist/advanced.d.ts +1 -1
  4. package/dist/advanced.d.ts.map +1 -1
  5. package/dist/advanced.js +1 -1
  6. package/dist/archive-merge.d.ts.map +1 -1
  7. package/dist/archive-merge.js +113 -46
  8. package/dist/archive-read.d.ts.map +1 -1
  9. package/dist/archive-read.js +4 -4
  10. package/dist/archive-zip-directory.d.ts +4 -0
  11. package/dist/archive-zip-directory.d.ts.map +1 -1
  12. package/dist/archive-zip-directory.js +2 -0
  13. package/dist/archive-zip-entry.d.ts +6 -2
  14. package/dist/archive-zip-entry.d.ts.map +1 -1
  15. package/dist/archive-zip-entry.js +23 -8
  16. package/dist/archive-zip-integrity.d.ts.map +1 -1
  17. package/dist/archive-zip-integrity.js +3 -4
  18. package/dist/archive-zip-loader.d.ts.map +1 -1
  19. package/dist/archive-zip-loader.js +107 -31
  20. package/dist/archive-zip-names.d.ts +1 -0
  21. package/dist/archive-zip-names.d.ts.map +1 -1
  22. package/dist/archive-zip-names.js +6 -0
  23. package/dist/archive.js +6 -5
  24. package/dist/bounded-read-stream.d.ts +0 -1
  25. package/dist/bounded-read-stream.d.ts.map +1 -1
  26. package/dist/bounded-read-stream.js +0 -6
  27. package/dist/copy-publication.d.ts +6 -0
  28. package/dist/copy-publication.d.ts.map +1 -1
  29. package/dist/copy-publication.js +3 -0
  30. package/dist/copy-tree-portable.d.ts.map +1 -1
  31. package/dist/copy-tree-portable.js +44 -24
  32. package/dist/copy.d.ts.map +1 -1
  33. package/dist/copy.js +29 -11
  34. package/dist/directory-mode-owner.js +5 -5
  35. package/dist/file-handle-transfer.d.ts +2 -0
  36. package/dist/file-handle-transfer.d.ts.map +1 -1
  37. package/dist/file-handle-transfer.js +57 -2
  38. package/dist/file-identity.d.ts.map +1 -1
  39. package/dist/file-identity.js +18 -4
  40. package/dist/file-lock-sync-admission.d.ts +19 -0
  41. package/dist/file-lock-sync-admission.d.ts.map +1 -0
  42. package/dist/file-lock-sync-admission.js +93 -0
  43. package/dist/file-lock-sync-root-acquire.d.ts +4 -0
  44. package/dist/file-lock-sync-root-acquire.d.ts.map +1 -0
  45. package/dist/file-lock-sync-root-acquire.js +370 -0
  46. package/dist/file-lock-sync-root-arbitration.d.ts +18 -0
  47. package/dist/file-lock-sync-root-arbitration.d.ts.map +1 -0
  48. package/dist/file-lock-sync-root-arbitration.js +66 -0
  49. package/dist/file-lock-sync-root-held.d.ts +34 -0
  50. package/dist/file-lock-sync-root-held.d.ts.map +1 -0
  51. package/dist/file-lock-sync-root-held.js +393 -0
  52. package/dist/file-lock-sync-root-io.d.ts +44 -0
  53. package/dist/file-lock-sync-root-io.d.ts.map +1 -0
  54. package/dist/file-lock-sync-root-io.js +209 -0
  55. package/dist/file-lock-sync-root-mutation.d.ts +17 -0
  56. package/dist/file-lock-sync-root-mutation.d.ts.map +1 -0
  57. package/dist/file-lock-sync-root-mutation.js +277 -0
  58. package/dist/file-lock-sync-root-options.d.ts +20 -0
  59. package/dist/file-lock-sync-root-options.d.ts.map +1 -0
  60. package/dist/file-lock-sync-root-options.js +58 -0
  61. package/dist/file-lock-sync-root-registration.d.ts +2 -0
  62. package/dist/file-lock-sync-root-registration.d.ts.map +1 -0
  63. package/dist/file-lock-sync-root-registration.js +90 -0
  64. package/dist/file-lock-sync-root.d.ts +36 -0
  65. package/dist/file-lock-sync-root.d.ts.map +1 -0
  66. package/dist/file-lock-sync-root.js +361 -0
  67. package/dist/file-lock-sync-stale-admission.d.ts +24 -0
  68. package/dist/file-lock-sync-stale-admission.d.ts.map +1 -0
  69. package/dist/file-lock-sync-stale-admission.js +205 -0
  70. package/dist/file-lock-sync.d.ts.map +1 -1
  71. package/dist/file-lock-sync.js +245 -205
  72. package/dist/file-store-prune.d.ts.map +1 -1
  73. package/dist/file-store-prune.js +5 -1
  74. package/dist/file-store-sync-write.js +3 -3
  75. package/dist/file-store.d.ts.map +1 -1
  76. package/dist/file-store.js +47 -12
  77. package/dist/json-document-store.d.ts.map +1 -1
  78. package/dist/json-document-store.js +22 -15
  79. package/dist/json-durable-queue-ownership.d.ts +0 -1
  80. package/dist/json-durable-queue-ownership.d.ts.map +1 -1
  81. package/dist/json-durable-queue-ownership.js +0 -6
  82. package/dist/native-binding.d.ts +2 -0
  83. package/dist/native-binding.d.ts.map +1 -1
  84. package/dist/native-parent-admission.d.ts +3 -2
  85. package/dist/native-parent-admission.d.ts.map +1 -1
  86. package/dist/native-parent-admission.js +24 -5
  87. package/dist/native-pinned-write-windows.d.ts.map +1 -1
  88. package/dist/native-pinned-write-windows.js +7 -7
  89. package/dist/native-pinned-write.d.ts.map +1 -1
  90. package/dist/native-pinned-write.js +7 -11
  91. package/dist/native-policy-parent-windows.d.ts +14 -0
  92. package/dist/native-policy-parent-windows.d.ts.map +1 -0
  93. package/dist/native-policy-parent-windows.js +200 -0
  94. package/dist/native-rename-outcome.d.ts +4 -0
  95. package/dist/native-rename-outcome.d.ts.map +1 -0
  96. package/dist/native-rename-outcome.js +8 -0
  97. package/dist/native-staged-file.d.ts +2 -2
  98. package/dist/native-staged-file.d.ts.map +1 -1
  99. package/dist/native-staged-file.js +42 -40
  100. package/dist/output.d.ts.map +1 -1
  101. package/dist/output.js +12 -8
  102. package/dist/path-prefix.d.ts.map +1 -1
  103. package/dist/path-prefix.js +30 -8
  104. package/dist/path-suffix-aliases.d.ts +2 -0
  105. package/dist/path-suffix-aliases.d.ts.map +1 -1
  106. package/dist/path-suffix-aliases.js +25 -17
  107. package/dist/permission-exec.d.ts +2 -0
  108. package/dist/permission-exec.d.ts.map +1 -1
  109. package/dist/permission-exec.js +150 -21
  110. package/dist/permissions-windows.js +1 -1
  111. package/dist/pinned-mutation-admission.d.ts.map +1 -1
  112. package/dist/pinned-mutation-admission.js +10 -5
  113. package/dist/pinned-mutation-observation.d.ts +0 -1
  114. package/dist/pinned-mutation-observation.d.ts.map +1 -1
  115. package/dist/pinned-mutation-observation.js +0 -19
  116. package/dist/pinned-mutation-shared-route.d.ts +1 -0
  117. package/dist/pinned-mutation-shared-route.d.ts.map +1 -1
  118. package/dist/pinned-mutation-shared-route.js +1 -1
  119. package/dist/pinned-write-types.d.ts +2 -0
  120. package/dist/pinned-write-types.d.ts.map +1 -1
  121. package/dist/private-temp-workspace.d.ts.map +1 -1
  122. package/dist/private-temp-workspace.js +75 -121
  123. package/dist/regular-file.d.ts.map +1 -1
  124. package/dist/regular-file.js +1 -15
  125. package/dist/replace-directory.d.ts.map +1 -1
  126. package/dist/replace-directory.js +256 -18
  127. package/dist/replace-file-copy-fallback.d.ts.map +1 -1
  128. package/dist/replace-file-copy-fallback.js +62 -70
  129. package/dist/replace-file-copy-source.d.ts.map +1 -1
  130. package/dist/replace-file-copy-source.js +10 -12
  131. package/dist/replace-file-temp-owner.d.ts +5 -2
  132. package/dist/replace-file-temp-owner.d.ts.map +1 -1
  133. package/dist/replace-file-temp-owner.js +65 -30
  134. package/dist/replace-file.js +6 -6
  135. package/dist/retained-directory-replacement.d.ts +26 -0
  136. package/dist/retained-directory-replacement.d.ts.map +1 -0
  137. package/dist/retained-directory-replacement.js +193 -0
  138. package/dist/root-boundary.d.ts +1 -0
  139. package/dist/root-boundary.d.ts.map +1 -1
  140. package/dist/root-boundary.js +4 -0
  141. package/dist/root-context.d.ts +0 -8
  142. package/dist/root-context.d.ts.map +1 -1
  143. package/dist/root-context.js +0 -3
  144. package/dist/root-create-input.d.ts +6 -0
  145. package/dist/root-create-input.d.ts.map +1 -1
  146. package/dist/root-create-input.js +5 -1
  147. package/dist/root-directory-list.d.ts +1 -0
  148. package/dist/root-directory-list.d.ts.map +1 -1
  149. package/dist/root-directory-list.js +1 -0
  150. package/dist/root-impl.d.ts.map +1 -1
  151. package/dist/root-impl.js +18 -10
  152. package/dist/root-move-noreplace.d.ts.map +1 -1
  153. package/dist/root-move-noreplace.js +2 -2
  154. package/dist/root-path-errors.d.ts +1 -0
  155. package/dist/root-path-errors.d.ts.map +1 -1
  156. package/dist/root-path-errors.js +11 -2
  157. package/dist/root-path-existing.d.ts.map +1 -1
  158. package/dist/root-path-existing.js +11 -35
  159. package/dist/root-path.js +1 -13
  160. package/dist/root-remove.d.ts +1 -0
  161. package/dist/root-remove.d.ts.map +1 -1
  162. package/dist/root-remove.js +4 -0
  163. package/dist/root-walk.d.ts +1 -1
  164. package/dist/root-walk.d.ts.map +1 -1
  165. package/dist/root-walk.js +17 -2
  166. package/dist/root-write-admission.d.ts +0 -2
  167. package/dist/root-write-admission.d.ts.map +1 -1
  168. package/dist/root-write-admission.js +1 -15
  169. package/dist/root-write-complete-parent.d.ts.map +1 -1
  170. package/dist/root-write-complete-parent.js +7 -23
  171. package/dist/root-write-verification.d.ts.map +1 -1
  172. package/dist/root-write-verification.js +29 -42
  173. package/dist/secret-file.d.ts.map +1 -1
  174. package/dist/secret-file.js +2 -24
  175. package/dist/secret-read-async.d.ts.map +1 -1
  176. package/dist/secret-read-async.js +3 -24
  177. package/dist/secret-read-policy.d.ts +6 -2
  178. package/dist/secret-read-policy.d.ts.map +1 -1
  179. package/dist/secret-read-policy.js +26 -2
  180. package/dist/sibling-temp.d.ts.map +1 -1
  181. package/dist/sibling-temp.js +23 -12
  182. package/dist/sidecar-lock-acquire.d.ts +2 -28
  183. package/dist/sidecar-lock-acquire.d.ts.map +1 -1
  184. package/dist/sidecar-lock-acquire.js +288 -199
  185. package/dist/sidecar-lock-admission-context.d.ts +19 -0
  186. package/dist/sidecar-lock-admission-context.d.ts.map +1 -0
  187. package/dist/sidecar-lock-admission-context.js +60 -0
  188. package/dist/sidecar-lock-admission-parser.d.ts +43 -0
  189. package/dist/sidecar-lock-admission-parser.d.ts.map +1 -0
  190. package/dist/sidecar-lock-admission-parser.js +113 -0
  191. package/dist/sidecar-lock-admission.d.ts +35 -0
  192. package/dist/sidecar-lock-admission.d.ts.map +1 -0
  193. package/dist/sidecar-lock-admission.js +7 -0
  194. package/dist/sidecar-lock-reclaim.d.ts +9 -4
  195. package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
  196. package/dist/sidecar-lock-reclaim.js +80 -25
  197. package/dist/sidecar-lock-stale-admission.d.ts +39 -0
  198. package/dist/sidecar-lock-stale-admission.d.ts.map +1 -0
  199. package/dist/sidecar-lock-stale-admission.js +232 -0
  200. package/dist/sidecar-lock-target.d.ts +8 -0
  201. package/dist/sidecar-lock-target.d.ts.map +1 -0
  202. package/dist/sidecar-lock-target.js +55 -0
  203. package/dist/sidecar-lock.d.ts.map +1 -1
  204. package/dist/sidecar-lock.js +100 -16
  205. package/dist/temp-workspace-descriptor.d.ts.map +1 -1
  206. package/dist/temp-workspace-descriptor.js +9 -27
  207. package/dist/temp-workspace-owner.d.ts.map +1 -1
  208. package/dist/temp-workspace-owner.js +8 -8
  209. package/dist/walk.d.ts +5 -1
  210. package/dist/walk.d.ts.map +1 -1
  211. package/dist/walk.js +19 -6
  212. package/dist/windows-owner.d.ts.map +1 -1
  213. package/dist/windows-owner.js +2 -2
  214. package/docs/advanced.md +1 -1
  215. package/docs/archive.md +36 -9
  216. package/docs/atomic.md +85 -8
  217. package/docs/copy.md +35 -0
  218. package/docs/file-store.md +19 -0
  219. package/docs/json-store.md +5 -0
  220. package/docs/native-helper.md +10 -3
  221. package/docs/output.md +6 -0
  222. package/docs/path-prefix.md +10 -0
  223. package/docs/path-suffix-aliases.md +51 -6
  224. package/docs/permissions.md +13 -0
  225. package/docs/public-api.md +3 -2
  226. package/docs/root.md +22 -3
  227. package/docs/sidecar-lock.md +109 -4
  228. package/docs/staged-file.md +7 -3
  229. package/docs/temp.md +20 -3
  230. package/docs/walk.md +67 -1
  231. package/docs/writing.md +5 -1
  232. package/package.json +10 -10
  233. package/dist/darwin-acl.d.ts +0 -4
  234. package/dist/darwin-acl.d.ts.map +0 -1
  235. package/dist/darwin-acl.js +0 -24
@@ -0,0 +1,209 @@
1
+ import fs, {} from "node:fs";
2
+ import path from "node:path";
3
+ import { readFileDescriptorBoundedSync } from "./bounded-read.js";
4
+ import { inspectDirectoryIdentitySync } from "./directory-guard.js";
5
+ import { FsSafeError } from "./errors.js";
6
+ import { isNotFoundPathError } from "./path.js";
7
+ import { assertRootIdentityCurrentSync } from "./root-context.js";
8
+ import { hardlinkedPathNotAllowedError } from "./root-errors.js";
9
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
10
+ import { realpathSync } from "./realpath.js";
11
+ import { sidecarLockSnapshotMatches, } from "./sidecar-lock-reclaim.js";
12
+ import { inspectFileIdentitySync } from "./strict-file-identity.js";
13
+ import { createSuppressedError } from "./suppressed-error.js";
14
+ import { assertFileLockSyncRootResolvedPathCurrent, } from "./file-lock-sync-root.js";
15
+ import { assertNoWindowsPathAlias, pathForWindowsFilesystem } from "./windows-path-alias.js";
16
+ const MAX_SIDECAR_LOCK_PAYLOAD_BYTES = 1024 * 1024;
17
+ const samePath = (left, right) => path.relative(path.resolve(left), path.resolve(right)) === "";
18
+ export function observeDirectory(pathname, initial) {
19
+ const stat = inspectDirectoryIdentitySync(pathname, undefined, initial);
20
+ const realPath = realpathSync.native(pathForWindowsFilesystem(pathname));
21
+ assertNoWindowsPathAlias(realPath, "filesystem", "sidecar lock parent uses a Windows filesystem namespace alias");
22
+ if (!samePath(realPath, pathname)) {
23
+ throw new FsSafeError("path-mismatch", "sidecar lock parent changed during operation");
24
+ }
25
+ return Object.freeze({
26
+ identity: Object.freeze({ dev: stat.dev, ino: stat.ino }),
27
+ path: pathname,
28
+ realPath,
29
+ });
30
+ }
31
+ export function assertDirectoryCurrent(receipt, initial) {
32
+ inspectDirectoryIdentitySync(receipt.path, receipt.identity, initial);
33
+ const currentReal = realpathSync.native(pathForWindowsFilesystem(receipt.path));
34
+ assertNoWindowsPathAlias(currentReal, "filesystem", "sidecar lock parent uses a Windows filesystem namespace alias");
35
+ if (currentReal !== receipt.realPath) {
36
+ throw new FsSafeError("path-mismatch", "sidecar lock parent changed during operation");
37
+ }
38
+ }
39
+ export function assertRetainedParentCurrent(pathAuthority, parent) {
40
+ const context = pathAuthority.authority.context;
41
+ const sharedIdentity = parent.path === context.rootReal &&
42
+ parent.identity.dev === context.rootIdentity.dev && parent.identity.ino === context.rootIdentity.ino;
43
+ let rootStat;
44
+ assertRootIdentityCurrentSync(context, sharedIdentity ? stat => { rootStat = stat; } : undefined);
45
+ assertDirectoryCurrent(parent, rootStat);
46
+ assertRootIdentityCurrentSync(context);
47
+ }
48
+ export function exactFileIdentity(stat) {
49
+ return Object.freeze({ dev: stat.dev, ino: stat.ino });
50
+ }
51
+ export function assertRegularFile(stat, hardlinks) {
52
+ if (stat.isSymbolicLink() || !stat.isFile()) {
53
+ throw new FsSafeError("not-file", "sidecar lock is not a regular file");
54
+ }
55
+ if (hardlinks !== "allow" && stat.nlink > 1n)
56
+ throw hardlinkedPathNotAllowedError();
57
+ }
58
+ export function sameExactIdentity(left, right) {
59
+ return left.dev === right.dev && left.ino === right.ino;
60
+ }
61
+ function assertFreshPathCurrent(pathAuthority) {
62
+ // The exact Root observation is deliberately last: this helper is used both
63
+ // immediately before fresh pathname I/O and immediately before returning it.
64
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
65
+ assertRootIdentityCurrentSync(pathAuthority.authority.context);
66
+ }
67
+ function missingAfterCurrentRead(pathAuthority, expectedReceipt) {
68
+ if (expectedReceipt) {
69
+ assertRetainedParentCurrent(pathAuthority, expectedReceipt.parent);
70
+ }
71
+ else {
72
+ assertFreshPathCurrent(pathAuthority);
73
+ }
74
+ return null;
75
+ }
76
+ export function readFileLockSyncRootSnapshot(pathAuthority, options = {}) {
77
+ const expectedReceipt = options.expectedReceipt;
78
+ if (expectedReceipt) {
79
+ assertRetainedParentCurrent(pathAuthority, expectedReceipt.parent);
80
+ }
81
+ else {
82
+ assertFreshPathCurrent(pathAuthority);
83
+ }
84
+ let before;
85
+ try {
86
+ before = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }), expectedReceipt?.identity);
87
+ }
88
+ catch (error) {
89
+ if (isNotFoundPathError(error) || (expectedReceipt && error instanceof FsSafeError && error.code === "path-mismatch"))
90
+ return missingAfterCurrentRead(pathAuthority, expectedReceipt);
91
+ throw error;
92
+ }
93
+ assertRegularFile(before, pathAuthority.authority.hardlinks);
94
+ const parent = expectedReceipt?.parent ?? observeDirectory(path.dirname(pathAuthority.path));
95
+ let fd;
96
+ let operationError;
97
+ let operationFailed = false;
98
+ try {
99
+ try {
100
+ fd = fs.openSync(pathForWindowsFilesystem(pathAuthority.path), resolveReadOpenFlags());
101
+ }
102
+ catch (error) {
103
+ if (isNotFoundPathError(error))
104
+ return missingAfterCurrentRead(pathAuthority, expectedReceipt);
105
+ options.onOpenFailure?.(error);
106
+ throw error;
107
+ }
108
+ let opened;
109
+ try {
110
+ opened = inspectFileIdentitySync(() => fs.fstatSync(fd, { bigint: true }), exactFileIdentity(before));
111
+ }
112
+ catch (error) {
113
+ if (error instanceof FsSafeError && error.code === "path-mismatch") {
114
+ if (expectedReceipt) {
115
+ assertRetainedParentCurrent(pathAuthority, parent);
116
+ }
117
+ else {
118
+ assertDirectoryCurrent(parent);
119
+ assertFreshPathCurrent(pathAuthority);
120
+ }
121
+ return null;
122
+ }
123
+ throw error;
124
+ }
125
+ assertRegularFile(opened, pathAuthority.authority.hardlinks);
126
+ const raw = readFileDescriptorBoundedSync(fd, MAX_SIDECAR_LOCK_PAYLOAD_BYTES).toString("utf8");
127
+ let after;
128
+ try {
129
+ after = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }), exactFileIdentity(opened));
130
+ }
131
+ catch (error) {
132
+ if (isNotFoundPathError(error) ||
133
+ (error instanceof FsSafeError && error.code === "path-mismatch")) {
134
+ if (expectedReceipt) {
135
+ assertRetainedParentCurrent(pathAuthority, parent);
136
+ }
137
+ else {
138
+ assertDirectoryCurrent(parent);
139
+ assertFreshPathCurrent(pathAuthority);
140
+ }
141
+ return null;
142
+ }
143
+ throw error;
144
+ }
145
+ assertRegularFile(after, pathAuthority.authority.hardlinks);
146
+ const stat = fs.fstatSync(fd);
147
+ if (expectedReceipt) {
148
+ assertRetainedParentCurrent(pathAuthority, parent);
149
+ }
150
+ else {
151
+ assertDirectoryCurrent(parent);
152
+ assertFreshPathCurrent(pathAuthority);
153
+ }
154
+ const snapshot = {
155
+ raw,
156
+ payload: null,
157
+ stat,
158
+ };
159
+ return Object.freeze({
160
+ receipt: Object.freeze({ identity: exactFileIdentity(opened), parent }),
161
+ snapshot,
162
+ });
163
+ }
164
+ catch (error) {
165
+ operationFailed = true;
166
+ operationError = error;
167
+ throw error;
168
+ }
169
+ finally {
170
+ if (fd !== undefined) {
171
+ try {
172
+ fs.closeSync(fd);
173
+ }
174
+ catch (closeError) {
175
+ if (operationFailed) {
176
+ throw createSuppressedError(closeError, operationError, "sidecar snapshot admission and descriptor close both failed");
177
+ }
178
+ throw closeError;
179
+ }
180
+ }
181
+ }
182
+ }
183
+ export function fileLockSyncRootSnapshotStillCurrent(pathAuthority, observed) {
184
+ const current = readFileLockSyncRootSnapshot(pathAuthority, {
185
+ expectedReceipt: observed.receipt,
186
+ });
187
+ return !!current &&
188
+ sameExactIdentity(current.receipt.identity, observed.receipt.identity) &&
189
+ sidecarLockSnapshotMatches(current.snapshot, observed.snapshot);
190
+ }
191
+ export function fileReceiptCurrentAfterParentCheck(pathAuthority, receipt) {
192
+ let current;
193
+ try {
194
+ current = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }), receipt.identity);
195
+ }
196
+ catch (error) {
197
+ if (isNotFoundPathError(error) ||
198
+ (error instanceof FsSafeError && error.code === "path-mismatch"))
199
+ return false;
200
+ throw error;
201
+ }
202
+ assertRegularFile(current, pathAuthority.authority.hardlinks);
203
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
204
+ return true;
205
+ }
206
+ export function fileLockSyncRootReceiptStillCurrent(pathAuthority, receipt) {
207
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
208
+ return fileReceiptCurrentAfterParentCheck(pathAuthority, receipt);
209
+ }
@@ -0,0 +1,17 @@
1
+ import { type SidecarLockSnapshot } from "./sidecar-lock-reclaim.js";
2
+ import { type FileLockSyncRootPath } from "./file-lock-sync-root.js";
3
+ import { type FileLockSyncRootDirectoryReceipt, type FileLockSyncRootFileReceipt } from "./file-lock-sync-root-io.js";
4
+ export declare function createFileLockSyncRootFile(pathAuthority: FileLockSyncRootPath, mode: number, options?: {
5
+ assertBeforeOpen?: () => void;
6
+ onOpenFailure?: (error: unknown) => void;
7
+ }): {
8
+ fd: number;
9
+ receipt: FileLockSyncRootFileReceipt;
10
+ };
11
+ export declare function refreshFileLockSyncRootFileReceipt(pathAuthority: FileLockSyncRootPath, receipt: FileLockSyncRootFileReceipt): FileLockSyncRootFileReceipt;
12
+ export declare function removeFileLockSyncRootFile(pathAuthority: FileLockSyncRootPath, receipt: FileLockSyncRootFileReceipt, expected?: SidecarLockSnapshot, assertBeforeRemove?: () => boolean | void): boolean;
13
+ export declare function fileLockSyncRootGuardExists(pathAuthority: FileLockSyncRootPath, pathAlreadyCurrent?: boolean): boolean;
14
+ export declare function createFileLockSyncRootDirectory(pathAuthority: FileLockSyncRootPath): FileLockSyncRootDirectoryReceipt | null;
15
+ export declare function removeFileLockSyncRootDirectory(pathAuthority: FileLockSyncRootPath, receipt: FileLockSyncRootDirectoryReceipt): boolean;
16
+ export declare function fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority: FileLockSyncRootPath, receipt: FileLockSyncRootDirectoryReceipt): boolean;
17
+ //# sourceMappingURL=file-lock-sync-root-mutation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock-sync-root-mutation.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-root-mutation.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAWL,KAAK,gCAAgC,EACrC,KAAK,2BAA2B,EACjC,MAAM,6BAA6B,CAAC;AA+DrC,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,oBAAoB,EACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC,GACL;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,2BAA2B,CAAA;CAAE,CA4CtD;AAED,wBAAgB,kCAAkC,CAChD,aAAa,EAAE,oBAAoB,EACnC,OAAO,EAAE,2BAA2B,GACnC,2BAA2B,CAK7B;AAED,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,oBAAoB,EACnC,OAAO,EAAE,2BAA2B,EACpC,QAAQ,CAAC,EAAE,mBAAmB,EAC9B,kBAAkB,CAAC,EAAE,MAAM,OAAO,GAAG,IAAI,GACxC,OAAO,CA0DT;AAED,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,oBAAoB,EACnC,kBAAkB,UAAQ,GACzB,OAAO,CAkCT;AAED,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,oBAAoB,GAClC,gCAAgC,GAAG,IAAI,CAiBzC;AAED,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,oBAAoB,EACnC,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAST;AAED,wBAAgB,4CAA4C,CAC1D,aAAa,EAAE,oBAAoB,EACnC,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAWT"}
@@ -0,0 +1,277 @@
1
+ import fs, {} from "node:fs";
2
+ import path from "node:path";
3
+ import { inspectDirectoryIdentitySync } from "./directory-guard.js";
4
+ import { FsSafeError } from "./errors.js";
5
+ import { isNotFoundPathError } from "./path.js";
6
+ import { admitPathInsideRoot } from "./root-boundary.js";
7
+ import { assertRootIdentityCurrentSync } from "./root-context.js";
8
+ import { directoryComponentNotDirectoryError, outsideWorkspaceError, } from "./root-errors.js";
9
+ import { sidecarLockSnapshotMatches, } from "./sidecar-lock-reclaim.js";
10
+ import { inspectFileIdentitySync } from "./strict-file-identity.js";
11
+ import { createSuppressedError } from "./suppressed-error.js";
12
+ import { assertFileLockSyncRootMutationAllowed, assertFileLockSyncRootResolvedPathCurrent, invokeFileLockSyncRootMutationAuthority, } from "./file-lock-sync-root.js";
13
+ import { assertDirectoryCurrent, assertRegularFile, assertRetainedParentCurrent, exactFileIdentity, fileLockSyncRootReceiptStillCurrent, fileReceiptCurrentAfterParentCheck, observeDirectory, readFileLockSyncRootSnapshot, sameExactIdentity, } from "./file-lock-sync-root-io.js";
14
+ import { pathForWindowsFilesystem } from "./windows-path-alias.js";
15
+ function ensureParent(pathAuthority) {
16
+ const authority = pathAuthority.authority;
17
+ const context = authority.context;
18
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
19
+ const targetParent = path.dirname(pathAuthority.path);
20
+ const admitted = admitPathInsideRoot({
21
+ rootPath: context.rootReal,
22
+ candidatePath: targetParent,
23
+ rootIdentity: context.rootIdentity,
24
+ });
25
+ if (!admitted)
26
+ throw outsideWorkspaceError();
27
+ const relative = admitted.relativePath;
28
+ let current = context.rootReal;
29
+ let currentReceipt = observeDirectory(current);
30
+ for (const segment of relative.split(path.sep).filter(Boolean)) {
31
+ const next = path.join(current, segment);
32
+ assertRootIdentityCurrentSync(context);
33
+ assertDirectoryCurrent(currentReceipt);
34
+ let missing = false;
35
+ let existing;
36
+ try {
37
+ existing = fs.lstatSync(pathForWindowsFilesystem(next), { bigint: true });
38
+ if (existing.isSymbolicLink() || !existing.isDirectory()) {
39
+ throw directoryComponentNotDirectoryError();
40
+ }
41
+ }
42
+ catch (error) {
43
+ if (!isNotFoundPathError(error))
44
+ throw error;
45
+ missing = true;
46
+ }
47
+ if (missing) {
48
+ assertFileLockSyncRootMutationAllowed(next, authority.denyMutations);
49
+ const mutationAuthorityInvoked = invokeFileLockSyncRootMutationAuthority(authority);
50
+ if (mutationAuthorityInvoked) {
51
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
52
+ }
53
+ assertDirectoryCurrent(currentReceipt);
54
+ assertRootIdentityCurrentSync(context);
55
+ // The callback may retarget a deny-policy alias at this particular
56
+ // intermediate component without changing the admitted final sidecar.
57
+ // Refresh the actual mkdir target after the callback and immediately
58
+ // before mutation.
59
+ if (mutationAuthorityInvoked) {
60
+ assertFileLockSyncRootMutationAllowed(next, authority.denyMutations);
61
+ }
62
+ try {
63
+ fs.mkdirSync(pathForWindowsFilesystem(next));
64
+ }
65
+ catch (error) {
66
+ if (error.code !== "EEXIST")
67
+ throw error;
68
+ }
69
+ }
70
+ const nextReceipt = observeDirectory(next, existing);
71
+ assertDirectoryCurrent(currentReceipt);
72
+ current = nextReceipt.realPath;
73
+ currentReceipt = nextReceipt;
74
+ }
75
+ assertRootIdentityCurrentSync(context);
76
+ assertDirectoryCurrent(currentReceipt);
77
+ return currentReceipt;
78
+ }
79
+ export function createFileLockSyncRootFile(pathAuthority, mode, options = {}) {
80
+ const parent = ensureParent(pathAuthority);
81
+ if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority)) {
82
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
83
+ assertRetainedParentCurrent(pathAuthority, parent);
84
+ }
85
+ const noFollow = process.platform !== "win32" && typeof fs.constants.O_NOFOLLOW === "number"
86
+ ? fs.constants.O_NOFOLLOW
87
+ : 0;
88
+ let fd;
89
+ let receipt;
90
+ try {
91
+ options.assertBeforeOpen?.();
92
+ try {
93
+ fd = fs.openSync(pathForWindowsFilesystem(pathAuthority.path), fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | noFollow, mode);
94
+ }
95
+ catch (error) {
96
+ options.onOpenFailure?.(error);
97
+ throw error;
98
+ }
99
+ const opened = inspectFileIdentitySync(() => fs.fstatSync(fd, { bigint: true }));
100
+ assertRegularFile(opened, pathAuthority.authority.hardlinks);
101
+ receipt = Object.freeze({ identity: exactFileIdentity(opened), parent });
102
+ if (!fileReceiptCurrentAfterParentCheck(pathAuthority, receipt)) {
103
+ throw new FsSafeError("path-mismatch", "created sidecar lock changed before admission");
104
+ }
105
+ return { fd, receipt };
106
+ }
107
+ catch (error) {
108
+ if (fd === undefined)
109
+ throw error;
110
+ const failedFd = fd;
111
+ fd = undefined;
112
+ try {
113
+ fs.closeSync(failedFd);
114
+ if (receipt && !removeFileLockSyncRootFile(pathAuthority, receipt)) {
115
+ throw new FsSafeError("path-mismatch", "created sidecar lock changed before cleanup");
116
+ }
117
+ }
118
+ catch (cleanupError) {
119
+ throw createSuppressedError(error, cleanupError, "file lock create admission and cleanup both failed");
120
+ }
121
+ throw error;
122
+ }
123
+ }
124
+ export function refreshFileLockSyncRootFileReceipt(pathAuthority, receipt) {
125
+ if (!fileReceiptCurrentAfterParentCheck(pathAuthority, receipt)) {
126
+ throw new FsSafeError("path-mismatch", "created sidecar lock changed before admission");
127
+ }
128
+ return receipt;
129
+ }
130
+ export function removeFileLockSyncRootFile(pathAuthority, receipt, expected, assertBeforeRemove) {
131
+ assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations);
132
+ const matches = () => {
133
+ if (!expected)
134
+ return fileLockSyncRootReceiptStillCurrent(pathAuthority, receipt);
135
+ const current = readFileLockSyncRootSnapshot(pathAuthority, {
136
+ expectedReceipt: receipt,
137
+ });
138
+ const matched = !!current &&
139
+ sameExactIdentity(current.receipt.identity, receipt.identity) &&
140
+ sidecarLockSnapshotMatches(current.snapshot, expected);
141
+ return matched;
142
+ };
143
+ if (!matches())
144
+ return false;
145
+ if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority) && !matches())
146
+ return false;
147
+ if (assertBeforeRemove?.() === false)
148
+ return false;
149
+ assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations);
150
+ fs.unlinkSync(pathForWindowsFilesystem(pathAuthority.path));
151
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
152
+ let successorStat;
153
+ try {
154
+ successorStat = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }));
155
+ }
156
+ catch (error) {
157
+ if (isNotFoundPathError(error))
158
+ return true;
159
+ throw error;
160
+ }
161
+ assertRegularFile(successorStat, pathAuthority.authority.hardlinks);
162
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
163
+ if (!sameExactIdentity(exactFileIdentity(successorStat), receipt.identity))
164
+ return true;
165
+ if (expected) {
166
+ const successor = readFileLockSyncRootSnapshot(pathAuthority);
167
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
168
+ if (successor) {
169
+ if (!sameExactIdentity(successor.receipt.identity, receipt.identity) ||
170
+ !sidecarLockSnapshotMatches(successor.snapshot, expected))
171
+ return true;
172
+ }
173
+ else {
174
+ // A null descriptor-bound snapshot can mean confirmed absence, a distinct
175
+ // replacement, or unverifiable identity. Re-observe once and accept only
176
+ // the first two states; ambiguity about the removed generation fails closed.
177
+ let current;
178
+ try {
179
+ current = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }));
180
+ }
181
+ catch (error) {
182
+ if (isNotFoundPathError(error)) {
183
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
184
+ return true;
185
+ }
186
+ throw error;
187
+ }
188
+ assertRegularFile(current, pathAuthority.authority.hardlinks);
189
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
190
+ if (!sameExactIdentity(exactFileIdentity(current), receipt.identity))
191
+ return true;
192
+ }
193
+ }
194
+ throw new FsSafeError("path-mismatch", "sidecar lock was replaced during removal");
195
+ }
196
+ export function fileLockSyncRootGuardExists(pathAuthority, pathAlreadyCurrent = false) {
197
+ if (!pathAlreadyCurrent)
198
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
199
+ // A shared path admission may skip only duplicate resolution, never this
200
+ // operation-local Root identity fence before fresh directory inspection.
201
+ assertRootIdentityCurrentSync(pathAuthority.authority.context);
202
+ let stat;
203
+ try {
204
+ stat = fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true });
205
+ }
206
+ catch (error) {
207
+ if (isNotFoundPathError(error)) {
208
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
209
+ assertRootIdentityCurrentSync(pathAuthority.authority.context);
210
+ return false;
211
+ }
212
+ throw error;
213
+ }
214
+ if (stat.isSymbolicLink() || (!stat.isDirectory() && !stat.isFile())) {
215
+ throw directoryComponentNotDirectoryError();
216
+ }
217
+ if (stat.isFile())
218
+ assertRegularFile(stat, pathAuthority.authority.hardlinks);
219
+ const parent = observeDirectory(path.dirname(pathAuthority.path));
220
+ if (stat.isFile()) {
221
+ const current = inspectFileIdentitySync(() => fs.lstatSync(pathForWindowsFilesystem(pathAuthority.path), { bigint: true }), exactFileIdentity(stat));
222
+ assertRegularFile(current, pathAuthority.authority.hardlinks);
223
+ }
224
+ else {
225
+ inspectDirectoryIdentitySync(pathAuthority.path, exactFileIdentity(stat));
226
+ }
227
+ assertDirectoryCurrent(parent);
228
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
229
+ assertRootIdentityCurrentSync(pathAuthority.authority.context);
230
+ return true;
231
+ }
232
+ export function createFileLockSyncRootDirectory(pathAuthority) {
233
+ const parent = ensureParent(pathAuthority);
234
+ if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority)) {
235
+ assertFileLockSyncRootResolvedPathCurrent(pathAuthority);
236
+ assertRetainedParentCurrent(pathAuthority, parent);
237
+ }
238
+ try {
239
+ fs.mkdirSync(pathForWindowsFilesystem(pathAuthority.path));
240
+ }
241
+ catch (error) {
242
+ if (error.code === "EEXIST")
243
+ return null;
244
+ throw error;
245
+ }
246
+ const stat = inspectDirectoryIdentitySync(pathAuthority.path);
247
+ const receipt = Object.freeze({ identity: exactFileIdentity(stat), parent });
248
+ assertRetainedParentCurrent(pathAuthority, parent);
249
+ inspectDirectoryIdentitySync(pathAuthority.path, receipt.identity);
250
+ return receipt;
251
+ }
252
+ export function removeFileLockSyncRootDirectory(pathAuthority, receipt) {
253
+ if (!fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority, receipt))
254
+ return false;
255
+ assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations, true);
256
+ if (invokeFileLockSyncRootMutationAuthority(pathAuthority.authority) &&
257
+ !fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority, receipt))
258
+ return false;
259
+ assertFileLockSyncRootMutationAllowed(pathAuthority.path, pathAuthority.authority.denyMutations, true);
260
+ fs.rmdirSync(pathForWindowsFilesystem(pathAuthority.path));
261
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
262
+ return true;
263
+ }
264
+ export function fileLockSyncRootDirectoryReceiptStillCurrent(pathAuthority, receipt) {
265
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
266
+ try {
267
+ inspectDirectoryIdentitySync(pathAuthority.path, receipt.identity);
268
+ }
269
+ catch (error) {
270
+ if (isNotFoundPathError(error) ||
271
+ (error instanceof FsSafeError && error.code === "path-mismatch"))
272
+ return false;
273
+ throw error;
274
+ }
275
+ assertRetainedParentCurrent(pathAuthority, receipt.parent);
276
+ return true;
277
+ }
@@ -0,0 +1,20 @@
1
+ import type { FileLockSyncAcquireOptions } from "./file-lock-sync.js";
2
+ import type { SidecarLockCompromisedInfo, SidecarLockRetryOptions, SidecarLockStaleRecovery } from "./sidecar-lock-types.js";
3
+ type CapturedRootSyncAcquireOptions<TPayload extends Record<string, unknown>> = Readonly<{
4
+ compromiseCheckIntervalMs?: number;
5
+ lockPath?: string;
6
+ onCompromised?: (info: SidecarLockCompromisedInfo) => void;
7
+ optionsReceiver: FileLockSyncAcquireOptions<TPayload>;
8
+ parsePayload?: (raw: string) => unknown;
9
+ payload: () => TPayload;
10
+ reentrantOwner?: string;
11
+ retry: Readonly<SidecarLockRetryOptions>;
12
+ shouldReclaim?: FileLockSyncAcquireOptions<TPayload>["shouldReclaim"];
13
+ shouldRemoveStaleLock?: FileLockSyncAcquireOptions<TPayload>["shouldRemoveStaleLock"];
14
+ staleMs: number;
15
+ staleRecovery?: SidecarLockStaleRecovery;
16
+ timeoutMs?: number;
17
+ }>;
18
+ export declare function captureRootSyncAcquireOptions<TPayload extends Record<string, unknown>>(options: FileLockSyncAcquireOptions<TPayload>): CapturedRootSyncAcquireOptions<TPayload>;
19
+ export {};
20
+ //# sourceMappingURL=file-lock-sync-root-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock-sync-root-options.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-root-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAItE,OAAO,KAAK,EAAE,0BAA0B,EAAE,uBAAuB,EAC/D,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,KAAK,8BAA8B,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC;IACvF,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC3D,eAAe,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACtD,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,OAAO,EAAE,MAAM,QAAQ,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,CAAC;IACtE,qBAAqB,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC,uBAAuB,CAAC,CAAC;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,6BAA6B,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpF,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,GAC5C,8BAA8B,CAAC,QAAQ,CAAC,CAuD1C"}
@@ -0,0 +1,58 @@
1
+ import { getFsSafeLockConfig } from "./lock-config.js";
2
+ import { validateSidecarLockCompromiseCheckIntervalMs, validateSidecarLockRetryOptions, validateSidecarLockStaleMs, validateSidecarLockTimeoutMs } from "./sidecar-lock-policy.js";
3
+ export function captureRootSyncAcquireOptions(options) {
4
+ // Root authority is already validated and snapshotted before entering this
5
+ // helper. Snapshot every remaining caller-owned property before validating
6
+ // options; nested retry accessors must not be revisited by backoff or a
7
+ // callback that mutates the original options object.
8
+ const lockPath = options.lockPath;
9
+ const staleMsInput = options.staleMs;
10
+ const timeoutMsInput = options.timeoutMs;
11
+ const retryInput = options.retry;
12
+ const staleRecoveryInput = options.staleRecovery;
13
+ const reentrantOwner = options.reentrantOwner;
14
+ const payload = options.payload;
15
+ const shouldReclaim = options.shouldReclaim;
16
+ const shouldRemoveStaleLock = options.shouldRemoveStaleLock;
17
+ const parsePayload = options.parsePayload;
18
+ const onCompromised = options.onCompromised;
19
+ const compromiseCheckIntervalMs = options.compromiseCheckIntervalMs;
20
+ const retrySnapshot = retryInput === undefined ? undefined : Object.freeze({
21
+ retries: retryInput.retries,
22
+ factor: retryInput.factor,
23
+ minTimeout: retryInput.minTimeout,
24
+ maxTimeout: retryInput.maxTimeout,
25
+ randomize: retryInput.randomize,
26
+ });
27
+ const defaults = getFsSafeLockConfig();
28
+ const defaultRetry = defaults.retry;
29
+ const retry = retrySnapshot ?? Object.freeze({
30
+ retries: defaultRetry?.retries,
31
+ factor: defaultRetry?.factor,
32
+ minTimeout: defaultRetry?.minTimeout,
33
+ maxTimeout: defaultRetry?.maxTimeout,
34
+ randomize: defaultRetry?.randomize,
35
+ });
36
+ const timeoutMs = timeoutMsInput ?? defaults.timeoutMs;
37
+ const staleMs = staleMsInput ?? defaults.staleMs ?? 30_000;
38
+ const staleRecovery = staleRecoveryInput ?? defaults.staleRecovery;
39
+ validateSidecarLockRetryOptions(retry);
40
+ validateSidecarLockTimeoutMs(timeoutMs);
41
+ validateSidecarLockStaleMs(staleMs);
42
+ validateSidecarLockCompromiseCheckIntervalMs(compromiseCheckIntervalMs);
43
+ return Object.freeze({
44
+ compromiseCheckIntervalMs,
45
+ lockPath,
46
+ onCompromised,
47
+ optionsReceiver: options,
48
+ parsePayload,
49
+ payload,
50
+ reentrantOwner,
51
+ retry,
52
+ shouldReclaim,
53
+ shouldRemoveStaleLock,
54
+ staleMs,
55
+ staleRecovery,
56
+ timeoutMs,
57
+ });
58
+ }
@@ -0,0 +1,2 @@
1
+ export declare function ensureFileLockSyncRootExitCleanupRegistered(cleanupHandler: () => void): void;
2
+ //# sourceMappingURL=file-lock-sync-root-registration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock-sync-root-registration.d.ts","sourceRoot":"","sources":["../src/file-lock-sync-root-registration.ts"],"names":[],"mappings":"AA+BA,wBAAgB,2CAA2C,CACzD,cAAc,EAAE,MAAM,IAAI,GACzB,IAAI,CAgFN"}