@oh-my-pi/pi-utils 18.2.8 → 18.2.10

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.
@@ -5,6 +5,8 @@ export interface FileLockOptions {
5
5
  retries?: number;
6
6
  /** Delay between acquisition attempts. */
7
7
  retryDelayMs?: number;
8
+ /** Cancel acquisition while waiting for another process to release the resource. */
9
+ signal?: AbortSignal;
8
10
  }
9
11
  /** An exclusive OS-backed lease. Releasing an already released handle is safe. */
10
12
  export interface FileLockHandle {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-utils",
3
- "version": "18.2.8",
3
+ "version": "18.2.10",
4
4
  "description": "Shared utilities for pi packages",
5
5
  "keywords": [
6
6
  "cli",
@@ -54,7 +54,7 @@
54
54
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
55
55
  },
56
56
  "dependencies": {
57
- "@oh-my-pi/pi-natives": "18.2.8"
57
+ "@oh-my-pi/pi-natives": "18.2.10"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/bun": "^1.3.14"
package/src/file-lock.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * mutexes, and other Unix platforms use `flock(2)` on `${filePath}.lock`.
6
6
  */
7
7
  import * as path from "node:path";
8
+ import { scheduler } from "node:timers/promises";
8
9
  import { FileLock as NativeFileLock } from "@oh-my-pi/pi-natives";
9
10
 
10
11
  /** Controls bounded waiting when an advisory file lock is contended. */
@@ -13,6 +14,8 @@ export interface FileLockOptions {
13
14
  retries?: number;
14
15
  /** Delay between acquisition attempts. */
15
16
  retryDelayMs?: number;
17
+ /** Cancel acquisition while waiting for another process to release the resource. */
18
+ signal?: AbortSignal;
16
19
  }
17
20
 
18
21
  /** An exclusive OS-backed lease. Releasing an already released handle is safe. */
@@ -20,7 +23,7 @@ export interface FileLockHandle {
20
23
  release(): void;
21
24
  }
22
25
 
23
- const DEFAULT_OPTIONS: Required<FileLockOptions> = {
26
+ const DEFAULT_OPTIONS = {
24
27
  retries: 50,
25
28
  retryDelayMs: 100,
26
29
  };
@@ -40,9 +43,10 @@ export async function acquireFileLock(filePath: string, options: FileLockOptions
40
43
  const lockPath = getLockPath(filePath);
41
44
 
42
45
  for (let attempt = 0; attempt < opts.retries; attempt++) {
46
+ opts.signal?.throwIfAborted();
43
47
  const lock = tryAcquireLock(lockPath);
44
48
  if (lock) return lock;
45
- if (attempt + 1 < opts.retries) await Bun.sleep(opts.retryDelayMs);
49
+ if (attempt + 1 < opts.retries) await scheduler.wait(opts.retryDelayMs, { signal: opts.signal });
46
50
  }
47
51
 
48
52
  throw new Error(`Failed to acquire lock for ${filePath} after ${opts.retries} attempts`);
@@ -53,6 +57,7 @@ function acquireLockSync(filePath: string, options: FileLockOptions = {}): Nativ
53
57
  const lockPath = getLockPath(filePath);
54
58
 
55
59
  for (let attempt = 0; attempt < opts.retries; attempt++) {
60
+ opts.signal?.throwIfAborted();
56
61
  const lock = tryAcquireLock(lockPath);
57
62
  if (lock) return lock;
58
63
  if (attempt + 1 < opts.retries && opts.retryDelayMs > 0) Bun.sleepSync(opts.retryDelayMs);