@apexops/kernel 0.10.0-next.5 → 0.11.0-next.1

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 (65) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/directory-lock.d.ts +118 -0
  3. package/dist/directory-lock.d.ts.map +1 -0
  4. package/dist/directory-lock.js +587 -0
  5. package/dist/directory-lock.js.map +1 -0
  6. package/dist/files.d.ts +63 -0
  7. package/dist/files.d.ts.map +1 -1
  8. package/dist/files.js +158 -2
  9. package/dist/files.js.map +1 -1
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/object-store.js +2 -2
  15. package/dist/object-store.js.map +1 -1
  16. package/dist/project-store.d.ts +2 -1
  17. package/dist/project-store.d.ts.map +1 -1
  18. package/dist/project-store.js +1 -0
  19. package/dist/project-store.js.map +1 -1
  20. package/dist/repeat-files.d.ts +66 -0
  21. package/dist/repeat-files.d.ts.map +1 -0
  22. package/dist/repeat-files.js +214 -0
  23. package/dist/repeat-files.js.map +1 -0
  24. package/dist/repeat-guard.d.ts +197 -0
  25. package/dist/repeat-guard.d.ts.map +1 -0
  26. package/dist/repeat-guard.js +462 -0
  27. package/dist/repeat-guard.js.map +1 -0
  28. package/dist/review-capture.d.ts +170 -0
  29. package/dist/review-capture.d.ts.map +1 -0
  30. package/dist/review-capture.js +570 -0
  31. package/dist/review-capture.js.map +1 -0
  32. package/dist/run-repository.d.ts +52 -2
  33. package/dist/run-repository.d.ts.map +1 -1
  34. package/dist/run-repository.js +198 -52
  35. package/dist/run-repository.js.map +1 -1
  36. package/dist/tasks.d.ts.map +1 -1
  37. package/dist/tasks.js +16 -2
  38. package/dist/tasks.js.map +1 -1
  39. package/dist/test/files.test.d.ts +2 -0
  40. package/dist/test/files.test.d.ts.map +1 -0
  41. package/dist/test/files.test.js +140 -0
  42. package/dist/test/files.test.js.map +1 -0
  43. package/dist/test/policies.test.js +1 -1
  44. package/dist/test/policies.test.js.map +1 -1
  45. package/dist/test/repeat-guard.test.d.ts +2 -0
  46. package/dist/test/repeat-guard.test.d.ts.map +1 -0
  47. package/dist/test/repeat-guard.test.js +1106 -0
  48. package/dist/test/repeat-guard.test.js.map +1 -0
  49. package/dist/test/review-capture.test.d.ts +2 -0
  50. package/dist/test/review-capture.test.d.ts.map +1 -0
  51. package/dist/test/review-capture.test.js +291 -0
  52. package/dist/test/review-capture.test.js.map +1 -0
  53. package/dist/test/run-repository.test.js +451 -7
  54. package/dist/test/run-repository.test.js.map +1 -1
  55. package/dist/test/workflow.test.js +30 -1
  56. package/dist/test/workflow.test.js.map +1 -1
  57. package/dist/test/writer-transfer.test.js +6 -1
  58. package/dist/test/writer-transfer.test.js.map +1 -1
  59. package/dist/validator-registry.d.ts.map +1 -1
  60. package/dist/validator-registry.js +10 -1
  61. package/dist/validator-registry.js.map +1 -1
  62. package/dist/workflow-validator-ownership.d.ts.map +1 -1
  63. package/dist/workflow-validator-ownership.js +2 -1
  64. package/dist/workflow-validator-ownership.js.map +1 -1
  65. package/package.json +3 -3
@@ -0,0 +1,587 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { constants } from "node:fs";
3
+ import { lstat, mkdir, mkdtemp, open, readdir, rm } from "node:fs/promises";
4
+ import { hostname } from "node:os";
5
+ import { basename, dirname, join } from "node:path";
6
+ import { canonicalJsonBytes, sha256Bytes, sha256Json } from "./canonical.js";
7
+ import { renameWithRetry } from "./files.js";
8
+ const LOCK_METADATA_FILE = "metadata.json";
9
+ const MAX_LOCK_METADATA_BYTES = 64 * 1024;
10
+ const LOCK_RETRY_MS = 10;
11
+ const TRANSIENT_LOCK_RENAME_CODES = new Set(["EPERM", "EACCES", "EBUSY"]);
12
+ // Released generations are parked under the retired-lock root with this prefix and deleted; every other entry there
13
+ // is a permanent takeover tombstone named by its recovery id.
14
+ const RELEASED_LOCK_PREFIX = "released-";
15
+ const RELEASED_LOCK_REMOVE_ATTEMPTS = 5;
16
+ const TRANSIENT_LOCK_REMOVE_CODES = new Set(["EPERM", "EACCES", "EBUSY", "ENOTEMPTY"]);
17
+ // Marker inside a held generation that opens it to snapshot readers; see `DirectoryLockHold.share`.
18
+ const SHARE_MARKER_FILE = "shared.json";
19
+ const MAX_SHARE_MARKER_BYTES = 4 * 1024;
20
+ // Holds whose share window the current async context runs inside, so a nested share joins it instead of waiting for it.
21
+ const enclosingShares = new AsyncLocalStorage();
22
+ const SHARE_MARKER_REMOVE_ATTEMPTS = 8;
23
+ /**
24
+ * A share window could not be closed, so snapshot readers may still trust it. The hold refuses to share again; its
25
+ * holder must write nothing more before it releases the lock, which takes the window with it.
26
+ */
27
+ export class DirectoryLockShareCloseError extends Error {
28
+ constructor(label, cause) {
29
+ super(`${label} share window could not be closed`, { cause });
30
+ this.name = "DirectoryLockShareCloseError";
31
+ }
32
+ }
33
+ function lockExpiry(value) {
34
+ if (value === null || typeof value !== "object" || Array.isArray(value))
35
+ return undefined;
36
+ const lock = value;
37
+ const createdAt = Date.parse(lock.createdAt ?? "");
38
+ const expiresAt = Date.parse(lock.expiresAt ?? "");
39
+ return typeof lock.token === "string" &&
40
+ lock.token.length > 0 &&
41
+ Number.isInteger(lock.pid) &&
42
+ Number(lock.pid) > 0 &&
43
+ typeof lock.host === "string" &&
44
+ lock.host.length > 0 &&
45
+ Number.isFinite(createdAt) &&
46
+ Number.isFinite(expiresAt) &&
47
+ expiresAt >= createdAt
48
+ ? expiresAt
49
+ : undefined;
50
+ }
51
+ async function sleep(milliseconds) {
52
+ await new Promise((done) => setTimeout(done, milliseconds));
53
+ }
54
+ /**
55
+ * Cross-process exclusive lock published as a directory `<name>.lock` holding owner metadata. A generation is staged
56
+ * in `<name>.pending-*` and published by rename, so the lock path never holds partial metadata. A live owner is waited
57
+ * for; an expired generation whose local owner process is gone is taken over into a permanent tombstone under
58
+ * `<name>.retired/`, which makes takeover compare-and-swap; released generations are parked there and deleted.
59
+ */
60
+ export class DirectoryLock {
61
+ lockPath;
62
+ retiredLockPath;
63
+ stagingPrefix;
64
+ label;
65
+ clock;
66
+ idSource;
67
+ ttlMs;
68
+ platform;
69
+ busyError;
70
+ constructor(lockPath, options) {
71
+ if (!lockPath.endsWith(".lock"))
72
+ throw new TypeError("Directory lock path must end with .lock");
73
+ const stem = basename(lockPath).slice(0, -".lock".length);
74
+ this.lockPath = lockPath;
75
+ this.retiredLockPath = join(dirname(lockPath), `${stem}.retired`);
76
+ this.stagingPrefix = `${stem}.pending-`;
77
+ this.label = options.label;
78
+ this.clock = options.clock;
79
+ this.idSource = options.idSource;
80
+ this.ttlMs = options.ttlMs;
81
+ this.platform = options.platform;
82
+ this.busyError = options.busyError;
83
+ }
84
+ /** Runs `operation` while holding the lock; throws the configured busy error when it cannot be acquired in time. */
85
+ async run(operation, options = {}) {
86
+ const held = await this.acquire(options);
87
+ try {
88
+ return await operation();
89
+ }
90
+ finally {
91
+ await held.release();
92
+ }
93
+ }
94
+ /**
95
+ * Acquires the lock and returns its release, for holders that give the lock up and take it again while they run.
96
+ * Throws the configured busy error when it cannot be acquired in time. Release is idempotent.
97
+ */
98
+ async acquire(options = {}) {
99
+ await mkdir(dirname(this.lockPath), { recursive: true });
100
+ const token = this.idSource();
101
+ const createdAt = this.clock();
102
+ const metadata = {
103
+ token,
104
+ pid: process.pid,
105
+ host: hostname(),
106
+ createdAt: createdAt.toISOString(),
107
+ expiresAt: new Date(createdAt.getTime() + this.ttlMs).toISOString(),
108
+ };
109
+ for (;;) {
110
+ if (await this.acquireLock(metadata))
111
+ break;
112
+ const existing = await this.readLock();
113
+ if (existing === undefined)
114
+ continue;
115
+ if (existing.expiresAt > this.clock().getTime() || this.ownerMayBeAlive(existing.metadata)) {
116
+ const deadline = Date.now() + (options.waitMs ?? 0);
117
+ for (;;) {
118
+ const contention = await options.onContention?.();
119
+ if (contention !== undefined)
120
+ throw contention;
121
+ if (Date.now() >= deadline)
122
+ break;
123
+ await sleep(LOCK_RETRY_MS);
124
+ if (await this.acquireLock(metadata))
125
+ break;
126
+ const current = await this.readLock();
127
+ if (current === undefined)
128
+ continue;
129
+ if (current.expiresAt <= this.clock().getTime() && !this.ownerMayBeAlive(current.metadata)) {
130
+ if (await this.retireStaleLock(current))
131
+ continue;
132
+ }
133
+ }
134
+ if (await this.readLock().then((current) => current?.metadata.token === token))
135
+ break;
136
+ throw this.busyError();
137
+ }
138
+ if (!(await this.retireStaleLock(existing)))
139
+ throw this.busyError();
140
+ }
141
+ let released = false;
142
+ let unclosed;
143
+ const key = {};
144
+ // The open (or opening) window that concurrent calls join, and the close of the previous one, which a new window
145
+ // waits for so it never publishes its marker before the old one is removed.
146
+ let window;
147
+ let closing = Promise.resolve();
148
+ return {
149
+ share: async (operation) => {
150
+ if (unclosed !== undefined)
151
+ throw unclosed;
152
+ if (released)
153
+ throw new Error(`${this.label} is no longer held`);
154
+ const enclosing = enclosingShares.getStore();
155
+ if (enclosing?.has(key) === true)
156
+ return operation();
157
+ if (window === undefined) {
158
+ let resolveClosed;
159
+ let rejectClosed;
160
+ const closed = new Promise((resolve, reject) => {
161
+ resolveClosed = resolve;
162
+ rejectClosed = reject;
163
+ });
164
+ const previous = closing;
165
+ closing = closed.catch(() => undefined);
166
+ window = {
167
+ members: 0,
168
+ opened: previous.then(() => {
169
+ if (unclosed !== undefined)
170
+ throw unclosed;
171
+ return this.openShare(token);
172
+ }),
173
+ closed,
174
+ settle: (error) => (error === undefined ? resolveClosed() : rejectClosed(error)),
175
+ };
176
+ }
177
+ const current = window;
178
+ current.members += 1;
179
+ let outcome;
180
+ try {
181
+ await current.opened;
182
+ const members = new Set(enclosing ?? []).add(key);
183
+ outcome = { value: await enclosingShares.run(members, operation) };
184
+ }
185
+ catch (error) {
186
+ outcome = { error };
187
+ }
188
+ current.members -= 1;
189
+ if (current.members === 0) {
190
+ if (window === current)
191
+ window = undefined;
192
+ try {
193
+ // A released generation took its marker with it; the lock path may now hold another generation.
194
+ if (!released)
195
+ await this.closeShare();
196
+ current.settle();
197
+ }
198
+ catch (error) {
199
+ unclosed = new DirectoryLockShareCloseError(this.label, error);
200
+ current.settle(unclosed);
201
+ }
202
+ }
203
+ // No member returns while the window may still be open; a close failure replaces every member's outcome, so
204
+ // the holder never continues as if the window had closed.
205
+ await current.closed;
206
+ if ("error" in outcome)
207
+ throw outcome.error;
208
+ return outcome.value;
209
+ },
210
+ release: async () => {
211
+ if (released)
212
+ return;
213
+ released = true;
214
+ try {
215
+ const current = await this.readLock();
216
+ if (current?.metadata.token === token)
217
+ await this.releaseLock();
218
+ }
219
+ catch (error) {
220
+ if (error.code !== "ENOENT")
221
+ throw error;
222
+ }
223
+ await this.sweepReleasedLocks();
224
+ },
225
+ };
226
+ }
227
+ /**
228
+ * Runs `read` without the lock while a holder shares its generation (see {@link DirectoryLockHold.share}) and returns
229
+ * its outcome only when the same window was still open after `read` settled, so the holder wrote nothing meanwhile.
230
+ * Returns undefined, discarding the outcome, when no window was open or it closed during the read; the caller then
231
+ * retries or waits for the lock. `read` must not write the state the lock protects.
232
+ */
233
+ async readShared(read) {
234
+ const before = await this.shareWindow();
235
+ if (before === undefined)
236
+ return undefined;
237
+ let outcome;
238
+ try {
239
+ outcome = { value: await read() };
240
+ }
241
+ catch (error) {
242
+ outcome = { error };
243
+ }
244
+ if ((await this.shareWindow()) !== before)
245
+ return undefined;
246
+ if ("error" in outcome)
247
+ throw outcome.error;
248
+ return outcome;
249
+ }
250
+ async openShare(token) {
251
+ const current = await this.readLock();
252
+ if (current?.metadata.token !== token)
253
+ throw new Error(`${this.label} is no longer held`);
254
+ const staging = join(this.lockPath, `${SHARE_MARKER_FILE}.${crypto.randomUUID()}.pending`);
255
+ try {
256
+ const handle = await open(staging, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
257
+ try {
258
+ await handle.writeFile(canonicalJsonBytes({ token, window: crypto.randomUUID() }));
259
+ await handle.sync();
260
+ }
261
+ finally {
262
+ await handle.close();
263
+ }
264
+ // Published by rename, so a reader never parses a partial marker.
265
+ await renameWithRetry(staging, join(this.lockPath, SHARE_MARKER_FILE));
266
+ }
267
+ finally {
268
+ await rm(staging, { force: true });
269
+ }
270
+ }
271
+ async closeShare() {
272
+ const attempts = this.platform === "win32" ? SHARE_MARKER_REMOVE_ATTEMPTS : 1;
273
+ for (let attempt = 1;; attempt += 1) {
274
+ try {
275
+ await rm(join(this.lockPath, SHARE_MARKER_FILE), { force: true });
276
+ return;
277
+ }
278
+ catch (error) {
279
+ const code = error.code ?? "";
280
+ if (attempt >= attempts || !TRANSIENT_LOCK_REMOVE_CODES.has(code))
281
+ throw error;
282
+ await sleep(10 * 2 ** (attempt - 1));
283
+ }
284
+ }
285
+ }
286
+ /**
287
+ * Identity of the open share window: the holding generation's token and the window id, or undefined when there is no
288
+ * readable window. Any failure to read it counts as no window, so a reader falls back to the lock.
289
+ */
290
+ async shareWindow() {
291
+ try {
292
+ const lock = await this.readLock();
293
+ if (lock === undefined)
294
+ return undefined;
295
+ const markerPath = join(this.lockPath, SHARE_MARKER_FILE);
296
+ const marker = await lstat(markerPath);
297
+ if (!marker.isFile() || marker.size > MAX_SHARE_MARKER_BYTES)
298
+ return undefined;
299
+ // Read through one handle that is still the file checked above, so a replacement cannot redirect or enlarge it.
300
+ const handle = await open(markerPath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
301
+ let bytes;
302
+ try {
303
+ const opened = await handle.stat();
304
+ if (!opened.isFile() ||
305
+ opened.dev !== marker.dev ||
306
+ opened.ino !== marker.ino ||
307
+ opened.size > MAX_SHARE_MARKER_BYTES)
308
+ return undefined;
309
+ const buffer = Buffer.alloc(MAX_SHARE_MARKER_BYTES + 1);
310
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
311
+ if (bytesRead > MAX_SHARE_MARKER_BYTES)
312
+ return undefined;
313
+ bytes = buffer.subarray(0, bytesRead);
314
+ }
315
+ finally {
316
+ await handle.close();
317
+ }
318
+ const value = JSON.parse(bytes.toString("utf8"));
319
+ // The token binds the marker to the generation read above; a later generation carries a different token.
320
+ if (value?.token !== lock.metadata.token || typeof value.window !== "string" || value.window.length === 0)
321
+ return undefined;
322
+ return `${lock.metadata.token}\n${value.window}`;
323
+ }
324
+ catch {
325
+ return undefined;
326
+ }
327
+ }
328
+ async acquireLock(metadata) {
329
+ const parent = dirname(this.lockPath);
330
+ await mkdir(parent, { recursive: true });
331
+ if (await this.lockPublished())
332
+ return false;
333
+ const staging = await mkdtemp(join(parent, this.stagingPrefix));
334
+ let published = false;
335
+ try {
336
+ const handle = await open(join(staging, LOCK_METADATA_FILE), constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
337
+ try {
338
+ await handle.writeFile(canonicalJsonBytes(metadata));
339
+ await handle.sync();
340
+ }
341
+ finally {
342
+ await handle.close();
343
+ }
344
+ if (await this.lockPublished())
345
+ return false;
346
+ try {
347
+ await renameWithRetry(staging, this.lockPath);
348
+ published = true;
349
+ return true;
350
+ }
351
+ catch (error) {
352
+ const code = error.code ?? "";
353
+ if (["EEXIST", "ENOTEMPTY"].includes(code) || TRANSIENT_LOCK_RENAME_CODES.has(code))
354
+ return false;
355
+ try {
356
+ await lstat(this.lockPath);
357
+ return false;
358
+ }
359
+ catch (lockError) {
360
+ if (lockError.code === "ENOENT")
361
+ throw error;
362
+ throw lockError;
363
+ }
364
+ }
365
+ }
366
+ finally {
367
+ if (!published)
368
+ await rm(staging, { recursive: true, force: true });
369
+ }
370
+ }
371
+ /** Cheap pre-check so contended waiters do not stage and fsync lock metadata on every poll. */
372
+ async lockPublished() {
373
+ try {
374
+ await lstat(this.lockPath);
375
+ return true;
376
+ }
377
+ catch (error) {
378
+ if (error.code === "ENOENT")
379
+ return false;
380
+ throw error;
381
+ }
382
+ }
383
+ async readLock() {
384
+ let directoryStat;
385
+ try {
386
+ directoryStat = await lstat(this.lockPath);
387
+ }
388
+ catch (error) {
389
+ if (error.code === "ENOENT")
390
+ return undefined;
391
+ throw error;
392
+ }
393
+ if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
394
+ throw new Error(`${this.label} metadata is unsafe`);
395
+ }
396
+ const metadataPath = join(this.lockPath, LOCK_METADATA_FILE);
397
+ let metadataStat;
398
+ try {
399
+ metadataStat = await lstat(metadataPath);
400
+ }
401
+ catch (error) {
402
+ if (error.code === "ENOENT") {
403
+ let currentDirectory;
404
+ try {
405
+ currentDirectory = await lstat(this.lockPath);
406
+ }
407
+ catch (lockError) {
408
+ if (lockError.code === "ENOENT")
409
+ return undefined;
410
+ throw lockError;
411
+ }
412
+ if (currentDirectory.dev !== directoryStat.dev || currentDirectory.ino !== directoryStat.ino)
413
+ return undefined;
414
+ throw new Error(`${this.label} metadata is unreadable`, { cause: error });
415
+ }
416
+ throw error;
417
+ }
418
+ if (!metadataStat.isFile() || metadataStat.isSymbolicLink() || metadataStat.size > MAX_LOCK_METADATA_BYTES) {
419
+ throw new Error(`${this.label} metadata is unsafe`);
420
+ }
421
+ let handle;
422
+ try {
423
+ handle = await open(metadataPath, constants.O_RDONLY);
424
+ }
425
+ catch (error) {
426
+ if (error.code === "ENOENT")
427
+ return undefined;
428
+ throw error;
429
+ }
430
+ let bytes;
431
+ try {
432
+ const opened = await handle.stat();
433
+ if (!opened.isFile() ||
434
+ opened.dev !== metadataStat.dev ||
435
+ opened.ino !== metadataStat.ino ||
436
+ opened.size > MAX_LOCK_METADATA_BYTES) {
437
+ return undefined;
438
+ }
439
+ bytes = await handle.readFile();
440
+ }
441
+ finally {
442
+ await handle.close();
443
+ }
444
+ const [after, metadataAfter] = await Promise.all([
445
+ lstat(this.lockPath).catch((error) => {
446
+ if (error.code === "ENOENT")
447
+ return undefined;
448
+ throw error;
449
+ }),
450
+ lstat(metadataPath).catch((error) => {
451
+ if (error.code === "ENOENT")
452
+ return undefined;
453
+ throw error;
454
+ }),
455
+ ]);
456
+ if (after === undefined ||
457
+ metadataAfter === undefined ||
458
+ after.dev !== directoryStat.dev ||
459
+ after.ino !== directoryStat.ino ||
460
+ metadataAfter.isSymbolicLink() ||
461
+ metadataAfter.dev !== metadataStat.dev ||
462
+ metadataAfter.ino !== metadataStat.ino ||
463
+ bytes.byteLength > MAX_LOCK_METADATA_BYTES) {
464
+ return undefined;
465
+ }
466
+ let metadata;
467
+ try {
468
+ metadata = JSON.parse(bytes.toString("utf8"));
469
+ }
470
+ catch (error) {
471
+ throw new Error(`${this.label} metadata is unreadable`, { cause: error });
472
+ }
473
+ const expiresAt = lockExpiry(metadata);
474
+ if (expiresAt === undefined)
475
+ throw new Error(`${this.label} metadata is unreadable`);
476
+ return {
477
+ metadata: metadata,
478
+ expiresAt,
479
+ recoveryId: sha256Json({
480
+ metadataHash: sha256Bytes(bytes),
481
+ device: String(directoryStat.dev),
482
+ inode: String(directoryStat.ino),
483
+ changedAt: directoryStat.ctimeMs,
484
+ }),
485
+ };
486
+ }
487
+ ownerMayBeAlive(metadata) {
488
+ if (metadata.host !== hostname())
489
+ return true;
490
+ try {
491
+ process.kill(metadata.pid, 0);
492
+ return true;
493
+ }
494
+ catch (error) {
495
+ return error.code !== "ESRCH";
496
+ }
497
+ }
498
+ /**
499
+ * Take over an expired generation whose local owner was confirmed dead after `snapshot` was read. Re-reading the lock
500
+ * after that liveness check is what lets released generations skip tombstones: a generation still present after its
501
+ * owner died can no longer be released by that owner, so it can only leave the lock path through another takeover,
502
+ * which leaves the permanent tombstone that makes this rename fail instead of retiring a replacement generation.
503
+ */
504
+ async retireStaleLock(snapshot) {
505
+ const confirmed = await this.readLock();
506
+ if (confirmed?.recoveryId !== snapshot.recoveryId)
507
+ return false;
508
+ return this.retireLock(snapshot.recoveryId);
509
+ }
510
+ /**
511
+ * Retire a taken-over generation into a permanent tombstone named by its recovery id. Rename is not compare-and-swap,
512
+ * so the tombstone is the guard: a delayed contender that confirmed the same generation renames onto the existing
513
+ * non-empty tombstone and fails rather than moving a replacement lock. Tombstones are therefore never swept; they
514
+ * accumulate only once per crashed lock owner, not per mutation.
515
+ */
516
+ async retireLock(recoveryId) {
517
+ await this.ensureRetiredRoot();
518
+ try {
519
+ await renameWithRetry(this.lockPath, join(this.retiredLockPath, recoveryId));
520
+ return true;
521
+ }
522
+ catch (error) {
523
+ if (error.code === "ENOENT")
524
+ return false;
525
+ if (["EEXIST", "ENOTEMPTY"].includes(error.code ?? ""))
526
+ return false;
527
+ throw error;
528
+ }
529
+ }
530
+ /**
531
+ * Release a generation this process owns. While the owner is alive no contender can take its generation over (see
532
+ * `retireStaleLock`), so the rename moves exactly this generation and needs no tombstone: it is parked under a fresh
533
+ * unique name and deleted by `sweepReleasedLocks`.
534
+ */
535
+ async releaseLock() {
536
+ await this.ensureRetiredRoot();
537
+ await renameWithRetry(this.lockPath, join(this.retiredLockPath, `${RELEASED_LOCK_PREFIX}${crypto.randomUUID()}`));
538
+ }
539
+ async ensureRetiredRoot() {
540
+ await mkdir(this.retiredLockPath, { recursive: true, mode: 0o700 });
541
+ const retiredRoot = await lstat(this.retiredLockPath);
542
+ if (!retiredRoot.isDirectory() || retiredRoot.isSymbolicLink()) {
543
+ throw new Error(`${this.label} retired directory is unsafe`);
544
+ }
545
+ }
546
+ /**
547
+ * Best-effort deletion of every released generation, including ones left by earlier cleanup failures or crashes
548
+ * between release and deletion. Any process may delete any released entry at any time: each has a unique name that
549
+ * only its releasing owner ever renames to, and nothing reads, renames, or locks through it afterwards. Takeover
550
+ * tombstones, the live lock, and other processes' `.pending-` staging directories are never touched. Failures never
551
+ * fail the caller; Windows sharing violations (for example a contender's metadata handle still open) are retried
552
+ * briefly and otherwise left for the next sweep.
553
+ */
554
+ async sweepReleasedLocks() {
555
+ let entries;
556
+ try {
557
+ const retiredRoot = await lstat(this.retiredLockPath);
558
+ if (!retiredRoot.isDirectory() || retiredRoot.isSymbolicLink())
559
+ return;
560
+ entries = await readdir(this.retiredLockPath, { withFileTypes: true });
561
+ }
562
+ catch {
563
+ return;
564
+ }
565
+ for (const entry of entries) {
566
+ if (entry.isDirectory() && entry.name.startsWith(RELEASED_LOCK_PREFIX)) {
567
+ await this.removeReleasedLock(join(this.retiredLockPath, entry.name));
568
+ }
569
+ }
570
+ }
571
+ async removeReleasedLock(path) {
572
+ const attempts = this.platform === "win32" ? RELEASED_LOCK_REMOVE_ATTEMPTS : 1;
573
+ for (let attempt = 1;; attempt += 1) {
574
+ try {
575
+ await rm(path, { recursive: true, force: true });
576
+ return;
577
+ }
578
+ catch (error) {
579
+ const code = error.code ?? "";
580
+ if (attempt >= attempts || !TRANSIENT_LOCK_REMOVE_CODES.has(code))
581
+ return;
582
+ await sleep(10 * 2 ** (attempt - 1));
583
+ }
584
+ }
585
+ }
586
+ }
587
+ //# sourceMappingURL=directory-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-lock.js","sourceRoot":"","sources":["../src/directory-lock.ts"],"names":[],"mappings":"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"}