atabey-shared 0.0.22 → 0.0.25

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # [GOV] Atabey Shared — Core Utility Library for AI Governance Platform
2
2
 
3
- [![Version](https://img.shields.io/badge/Version-v0.0.22-blue.svg)](https://github.com/ysf-bkr/atabey)
3
+ [![Version](https://img.shields.io/badge/Version-v0.0.23-blue.svg)](https://github.com/ysf-bkr/atabey)
4
4
  [![npm](https://img.shields.io/npm/v/atabey-shared)](https://www.npmjs.com/package/atabey-shared)
5
5
  [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
6
6
 
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Tamper-evident audit hash chain helpers (Phase 1.4).
3
+ *
4
+ * Chain: each entry stores prev_hash (previous entry hash or GENESIS) and hash = SHA-256(payload).
5
+ * Any mutation of historical rows fails verification.
6
+ */
7
+ export declare const AUDIT_CHAIN_GENESIS = "GENESIS";
8
+ export declare function sha256Hex(payload: string): string;
9
+ /**
10
+ * Canonical payload for agent execution logs (Storage.saveLog).
11
+ * MUST stay stable — changing it breaks verification of existing DBs.
12
+ */
13
+ export declare function buildAgentLogChainPayload(fields: {
14
+ prevHash: string;
15
+ agent: string;
16
+ action: string;
17
+ traceId: string;
18
+ status: string;
19
+ summary: string;
20
+ timestamp: string;
21
+ }): string;
22
+ /**
23
+ * Canonical payload for structured Audit.log entries.
24
+ */
25
+ export declare function buildStructuredAuditChainPayload(fields: {
26
+ prevHash: string;
27
+ agent: string;
28
+ action: string;
29
+ status: string;
30
+ traceId: string;
31
+ timestamp: string;
32
+ detailsJson: string;
33
+ errorMessage: string;
34
+ }): string;
35
+ export interface ChainRow {
36
+ id: number;
37
+ prev_hash: string | null;
38
+ hash: string | null;
39
+ }
40
+ export interface ChainVerifyResult {
41
+ valid: boolean;
42
+ checked: number;
43
+ failedLogId?: number;
44
+ reason?: string;
45
+ tip?: string;
46
+ }
47
+ /**
48
+ * Verify a sequence of rows already ordered by id ASC.
49
+ * `computePayload(row, prevHash)` must rebuild the exact string used at insert time.
50
+ */
51
+ export declare function verifyHashChain<T extends ChainRow>(rows: T[], computePayload: (row: T, prevHash: string) => string): ChainVerifyResult;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Tamper-evident audit hash chain helpers (Phase 1.4).
3
+ *
4
+ * Chain: each entry stores prev_hash (previous entry hash or GENESIS) and hash = SHA-256(payload).
5
+ * Any mutation of historical rows fails verification.
6
+ */
7
+ import crypto from "crypto";
8
+ export const AUDIT_CHAIN_GENESIS = "GENESIS";
9
+ export function sha256Hex(payload) {
10
+ return crypto.createHash("sha256").update(payload, "utf8").digest("hex");
11
+ }
12
+ /**
13
+ * Canonical payload for agent execution logs (Storage.saveLog).
14
+ * MUST stay stable — changing it breaks verification of existing DBs.
15
+ */
16
+ export function buildAgentLogChainPayload(fields) {
17
+ return [
18
+ fields.prevHash,
19
+ fields.agent,
20
+ fields.action,
21
+ fields.traceId,
22
+ fields.status,
23
+ fields.summary,
24
+ fields.timestamp,
25
+ ].join("|");
26
+ }
27
+ /**
28
+ * Canonical payload for structured Audit.log entries.
29
+ */
30
+ export function buildStructuredAuditChainPayload(fields) {
31
+ return [
32
+ fields.prevHash,
33
+ fields.agent,
34
+ fields.action,
35
+ fields.status,
36
+ fields.traceId,
37
+ fields.timestamp,
38
+ fields.detailsJson,
39
+ fields.errorMessage,
40
+ ].join("|");
41
+ }
42
+ /**
43
+ * Verify a sequence of rows already ordered by id ASC.
44
+ * `computePayload(row, prevHash)` must rebuild the exact string used at insert time.
45
+ */
46
+ export function verifyHashChain(rows, computePayload) {
47
+ let expectedPrev = AUDIT_CHAIN_GENESIS;
48
+ let checked = 0;
49
+ for (const row of rows) {
50
+ checked++;
51
+ const prev = row.prev_hash || "";
52
+ if (prev !== expectedPrev) {
53
+ return {
54
+ valid: false,
55
+ checked,
56
+ failedLogId: row.id,
57
+ reason: `prev_hash mismatch at row ${row.id}`,
58
+ tip: "A log was deleted, reordered, or inserted out of chain order.",
59
+ };
60
+ }
61
+ if (!row.hash) {
62
+ return {
63
+ valid: false,
64
+ checked,
65
+ failedLogId: row.id,
66
+ reason: `Missing hash at row ${row.id}`,
67
+ tip: "Legacy row without hash; re-seed or accept and re-hash from tip.",
68
+ };
69
+ }
70
+ const payload = computePayload(row, prev);
71
+ const calculated = sha256Hex(payload);
72
+ if (calculated !== row.hash) {
73
+ return {
74
+ valid: false,
75
+ checked,
76
+ failedLogId: row.id,
77
+ reason: `Hash corruption at row ${row.id}`,
78
+ tip: "Row content was modified after append.",
79
+ };
80
+ }
81
+ expectedPrev = row.hash;
82
+ }
83
+ return { valid: true, checked };
84
+ }
85
+ //# sourceMappingURL=audit-chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-chain.js","sourceRoot":"","sources":["../src/audit-chain.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,MAAM,UAAU,SAAS,CAAC,OAAe;IACrC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAQzC;IACG,OAAO;QACH,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,KAAK;QACZ,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,SAAS;KACnB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gCAAgC,CAAC,MAShD;IACG,OAAO;QACH,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,KAAK;QACZ,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,SAAS;QAChB,MAAM,CAAC,WAAW;QAClB,MAAM,CAAC,YAAY;KACtB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChB,CAAC;AAgBD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC3B,IAAS,EACT,cAAoD;IAEpD,IAAI,YAAY,GAAG,mBAAmB,CAAC;IACvC,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;QACV,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC;QACjC,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YACxB,OAAO;gBACH,KAAK,EAAE,KAAK;gBACZ,OAAO;gBACP,WAAW,EAAE,GAAG,CAAC,EAAE;gBACnB,MAAM,EAAE,6BAA6B,GAAG,CAAC,EAAE,EAAE;gBAC7C,GAAG,EAAE,+DAA+D;aACvE,CAAC;QACN,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO;gBACH,KAAK,EAAE,KAAK;gBACZ,OAAO;gBACP,WAAW,EAAE,GAAG,CAAC,EAAE;gBACnB,MAAM,EAAE,uBAAuB,GAAG,CAAC,EAAE,EAAE;gBACvC,GAAG,EAAE,kEAAkE;aAC1E,CAAC;QACN,CAAC;QACD,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,UAAU,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;YAC1B,OAAO;gBACH,KAAK,EAAE,KAAK;gBACZ,OAAO;gBACP,WAAW,EAAE,GAAG,CAAC,EAAE;gBACnB,MAAM,EAAE,0BAA0B,GAAG,CAAC,EAAE,EAAE;gBAC1C,GAAG,EAAE,wCAAwC;aAChD,CAAC;QACN,CAAC;QACD,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC"}
package/dist/audit.d.ts CHANGED
@@ -13,6 +13,7 @@
13
13
  * Audit.log("user.create", "SUCCESS", { userId: "usr_123" });
14
14
  * Audit.query({ action: "user.create", status: "FAILED" });
15
15
  */
16
+ import { type ChainVerifyResult } from "./audit-chain.js";
16
17
  export type AuditStatus = "SUCCESS" | "FAILED" | "BLOCKED" | "APPROVED" | "REJECTED";
17
18
  export type DataCategory = "OPERATIONAL" | "USER_DATA" | "API_CALL" | "SECURITY" | "COMPLIANCE";
18
19
  export interface AuditEntry {
@@ -28,6 +29,9 @@ export interface AuditEntry {
28
29
  dataCategory?: DataCategory;
29
30
  /** [KVKK] Data retention period (days). null = unlimited (not recommended) */
30
31
  retentionDays?: number;
32
+ /** Tamper-evident chain (Phase 1.4) */
33
+ prev_hash?: string;
34
+ hash?: string;
31
35
  }
32
36
  export declare class Audit {
33
37
  private static TABLE;
@@ -50,6 +54,10 @@ export declare class Audit {
50
54
  /** [KVKK] Custom retention period (days). Default: 30 */
51
55
  retentionDays?: number;
52
56
  }): void;
57
+ /**
58
+ * Verify tamper-evident chain for structured audit_log table.
59
+ */
60
+ static verifyIntegrity(): ChainVerifyResult;
53
61
  /**
54
62
  * Queries audit logs with filters.
55
63
  */
package/dist/audit.js CHANGED
@@ -13,6 +13,7 @@
13
13
  * Audit.log("user.create", "SUCCESS", { userId: "usr_123" });
14
14
  * Audit.query({ action: "user.create", status: "FAILED" });
15
15
  */
16
+ import { AUDIT_CHAIN_GENESIS, buildStructuredAuditChainPayload, sha256Hex, verifyHashChain, } from "./audit-chain.js";
16
17
  import { maskObject, maskText } from "./pii.js";
17
18
  import { databaseHolder } from "./database.js";
18
19
  import { logger } from "./logger.js";
@@ -36,9 +37,22 @@ export class Audit {
36
37
  errorMessage TEXT,
37
38
  durationMs INTEGER,
38
39
  dataCategory TEXT DEFAULT 'OPERATIONAL',
39
- retentionDays INTEGER DEFAULT ${this.DEFAULT_RETENTION_DAYS}
40
+ retentionDays INTEGER DEFAULT ${this.DEFAULT_RETENTION_DAYS},
41
+ prev_hash TEXT,
42
+ hash TEXT
40
43
  )
41
44
  `);
45
+ // Migrate older DBs
46
+ try {
47
+ const cols = db.prepare(`PRAGMA table_info(${this.TABLE})`).all().map((c) => c.name);
48
+ if (!cols.includes("prev_hash"))
49
+ db.exec(`ALTER TABLE ${this.TABLE} ADD COLUMN prev_hash TEXT`);
50
+ if (!cols.includes("hash"))
51
+ db.exec(`ALTER TABLE ${this.TABLE} ADD COLUMN hash TEXT`);
52
+ }
53
+ catch {
54
+ /* ignore */
55
+ }
42
56
  // Indexes for performance
43
57
  db.exec(`
44
58
  CREATE INDEX IF NOT EXISTS idx_audit_action ON ${this.TABLE}(action);
@@ -62,23 +76,73 @@ export class Audit {
62
76
  const maskedError = options.errorMessage
63
77
  ? maskText(options.errorMessage)
64
78
  : undefined;
65
- const entry = {
66
- timestamp: new Date().toISOString(),
67
- action,
68
- status,
69
- agent: options.agent || "@manager",
70
- traceId: options.traceId,
71
- details: maskedDetails,
72
- errorMessage: maskedError,
73
- durationMs: options.durationMs,
74
- dataCategory: options.dataCategory || "OPERATIONAL",
75
- retentionDays,
76
- };
77
- db.prepare(`
78
- INSERT INTO ${this.TABLE}
79
- (timestamp, action, status, agent, traceId, details, errorMessage, durationMs, dataCategory, retentionDays)
80
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
81
- `).run(entry.timestamp, entry.action, entry.status, entry.agent, entry.traceId || null, entry.details ? JSON.stringify(entry.details) : null, entry.errorMessage || null, entry.durationMs || null, entry.dataCategory, entry.retentionDays);
79
+ const timestamp = new Date().toISOString();
80
+ const agent = options.agent || "@manager";
81
+ const detailsJson = maskedDetails ? JSON.stringify(maskedDetails) : "";
82
+ const errorMessage = maskedError || "";
83
+ const traceId = options.traceId || "";
84
+ const dataCategory = options.dataCategory || "OPERATIONAL";
85
+ // Append-only hash chain inside a transaction (Phase 1.4)
86
+ const insert = db.transaction(() => {
87
+ let prevHash = AUDIT_CHAIN_GENESIS;
88
+ try {
89
+ const last = db.prepare(`SELECT hash FROM ${this.TABLE} WHERE hash IS NOT NULL ORDER BY id DESC LIMIT 1`).get();
90
+ if (last?.hash)
91
+ prevHash = last.hash;
92
+ }
93
+ catch {
94
+ /* genesis */
95
+ }
96
+ const payload = buildStructuredAuditChainPayload({
97
+ prevHash,
98
+ agent,
99
+ action,
100
+ status,
101
+ traceId,
102
+ timestamp,
103
+ detailsJson,
104
+ errorMessage,
105
+ });
106
+ const hash = sha256Hex(payload);
107
+ db.prepare(`
108
+ INSERT INTO ${this.TABLE}
109
+ (timestamp, action, status, agent, traceId, details, errorMessage, durationMs, dataCategory, retentionDays, prev_hash, hash)
110
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
111
+ `).run(timestamp, action, status, agent, options.traceId || null, detailsJson || null, errorMessage || null, options.durationMs || null, dataCategory, retentionDays, prevHash, hash);
112
+ });
113
+ insert();
114
+ }
115
+ /**
116
+ * Verify tamper-evident chain for structured audit_log table.
117
+ */
118
+ static verifyIntegrity() {
119
+ const db = databaseHolder.getDB();
120
+ try {
121
+ const rows = db.prepare(`SELECT id, prev_hash, hash, agent, action, status, traceId, timestamp, details, errorMessage
122
+ FROM ${this.TABLE} ORDER BY id ASC`).all();
123
+ // Skip unhashed legacy rows at the head; start chain at first hashed row
124
+ const hashed = rows.filter((r) => r.hash);
125
+ if (hashed.length === 0) {
126
+ return { valid: true, checked: 0, reason: "No hashed audit rows yet" };
127
+ }
128
+ return verifyHashChain(hashed, (row, prevHash) => buildStructuredAuditChainPayload({
129
+ prevHash,
130
+ agent: row.agent,
131
+ action: row.action,
132
+ status: row.status,
133
+ traceId: row.traceId || "",
134
+ timestamp: row.timestamp,
135
+ detailsJson: row.details || "",
136
+ errorMessage: row.errorMessage || "",
137
+ }));
138
+ }
139
+ catch (err) {
140
+ return {
141
+ valid: false,
142
+ checked: 0,
143
+ reason: `Verification error: ${err.message}`,
144
+ };
145
+ }
82
146
  }
83
147
  /**
84
148
  * Queries audit logs with filters.
package/dist/audit.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Atomic File-Based Locking — OS-level exclusive create via open('wx').
3
+ *
4
+ * Replaces check-then-act lock races. No Redis/Redlock required.
5
+ *
6
+ * Pattern:
7
+ * resource → .atabey/locks/<relative>.lock (created with O_EXCL / 'wx')
8
+ * holder writes JSON metadata after exclusive create
9
+ * release unlinks the lock file
10
+ *
11
+ * Stale locks (TTL exceeded) are reclaimed atomically when possible.
12
+ */
13
+ export interface FileLockOptions {
14
+ /** Base directory for lock files. Default: `.atabey/locks` under cwd or projectRoot. */
15
+ locksDir?: string;
16
+ /** Project root used to relativize resource paths. Default: process.cwd(). */
17
+ projectRoot?: string;
18
+ /** Lock TTL in ms. Stale locks may be stolen after this. Default: 5 minutes. */
19
+ ttlMs?: number;
20
+ /** Retry interval when waiting for a lock. Default: 50ms. */
21
+ retryMs?: number;
22
+ /** Max wait when using acquireAsync. Default: 10s. */
23
+ timeoutMs?: number;
24
+ }
25
+ export interface FileLockMeta {
26
+ ownerId: string;
27
+ resource: string;
28
+ acquiredAt: string;
29
+ expiresAt: string;
30
+ reason?: string;
31
+ pid: number;
32
+ hostname: string;
33
+ }
34
+ export declare class AtomicFileLock {
35
+ private readonly locksDir;
36
+ private readonly projectRoot;
37
+ private readonly ttlMs;
38
+ private readonly retryMs;
39
+ private readonly timeoutMs;
40
+ constructor(options?: FileLockOptions);
41
+ /** Absolute path of the lock file for a resource. */
42
+ getLockPath(resource: string): string;
43
+ /**
44
+ * Try to acquire a lock once (non-blocking).
45
+ * Uses atomic exclusive file create (`wx` = O_CREAT | O_EXCL | O_WRONLY).
46
+ */
47
+ tryAcquire(resource: string, ownerId: string, reason?: string, _reclaimDepth?: number): {
48
+ acquired: boolean;
49
+ meta?: FileLockMeta;
50
+ heldBy?: FileLockMeta;
51
+ };
52
+ /**
53
+ * Acquire with async retry until timeout.
54
+ */
55
+ acquireAsync(resource: string, ownerId: string, options?: {
56
+ reason?: string;
57
+ timeoutMs?: number;
58
+ retryMs?: number;
59
+ }): Promise<FileLockMeta>;
60
+ /**
61
+ * Release lock only if owned by ownerId (or force=true).
62
+ */
63
+ release(resource: string, ownerId: string, force?: boolean): boolean;
64
+ isLocked(resource: string): FileLockMeta | null;
65
+ /**
66
+ * Run `fn` while holding the lock.
67
+ * ALWAYS releases in `finally` even if `fn` throws (disk full, parse errors, etc.).
68
+ */
69
+ withLock<T>(resource: string, ownerId: string, fn: () => Promise<T> | T, options?: {
70
+ reason?: string;
71
+ timeoutMs?: number;
72
+ }): Promise<T>;
73
+ /**
74
+ * Synchronous withLock — same try/finally release guarantee.
75
+ */
76
+ withLockSync<T>(resource: string, ownerId: string, fn: () => T, options?: {
77
+ reason?: string;
78
+ }): T;
79
+ private reclaimIfStale;
80
+ private isExpired;
81
+ private readMeta;
82
+ private forceRemove;
83
+ }
84
+ /** Convenience: lock under project `.atabey/locks`. */
85
+ export declare function createProjectFileLock(projectRoot: string, options?: Omit<FileLockOptions, "projectRoot">): AtomicFileLock;
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Atomic File-Based Locking — OS-level exclusive create via open('wx').
3
+ *
4
+ * Replaces check-then-act lock races. No Redis/Redlock required.
5
+ *
6
+ * Pattern:
7
+ * resource → .atabey/locks/<relative>.lock (created with O_EXCL / 'wx')
8
+ * holder writes JSON metadata after exclusive create
9
+ * release unlinks the lock file
10
+ *
11
+ * Stale locks (TTL exceeded) are reclaimed atomically when possible.
12
+ */
13
+ import fs from "fs";
14
+ import path from "path";
15
+ import os from "os";
16
+ export class AtomicFileLock {
17
+ locksDir;
18
+ projectRoot;
19
+ ttlMs;
20
+ retryMs;
21
+ timeoutMs;
22
+ constructor(options = {}) {
23
+ this.projectRoot = options.projectRoot ?? process.cwd();
24
+ this.locksDir = options.locksDir
25
+ ? path.resolve(options.locksDir)
26
+ : path.join(this.projectRoot, ".atabey", "locks");
27
+ this.ttlMs = options.ttlMs ?? 5 * 60 * 1000;
28
+ this.retryMs = options.retryMs ?? 50;
29
+ this.timeoutMs = options.timeoutMs ?? 10_000;
30
+ }
31
+ /** Absolute path of the lock file for a resource. */
32
+ getLockPath(resource) {
33
+ const abs = path.isAbsolute(resource)
34
+ ? resource
35
+ : path.resolve(this.projectRoot, resource);
36
+ let relative = path.relative(this.projectRoot, abs);
37
+ if (relative.startsWith("..")) {
38
+ // Outside project root — hash path to avoid escaping locks dir
39
+ relative = `_ext/${Buffer.from(abs).toString("base64url")}`;
40
+ }
41
+ // Normalize separators for cross-platform lock paths
42
+ relative = relative.split(path.sep).join("/");
43
+ return path.join(this.locksDir, `${relative}.lock`);
44
+ }
45
+ /**
46
+ * Try to acquire a lock once (non-blocking).
47
+ * Uses atomic exclusive file create (`wx` = O_CREAT | O_EXCL | O_WRONLY).
48
+ */
49
+ tryAcquire(resource, ownerId, reason, _reclaimDepth = 0) {
50
+ const lockPath = this.getLockPath(resource);
51
+ fs.mkdirSync(path.dirname(lockPath), { recursive: true });
52
+ // Reclaim stale lock first (best-effort, still atomic on create)
53
+ this.reclaimIfStale(lockPath);
54
+ const now = Date.now();
55
+ const meta = {
56
+ ownerId,
57
+ resource,
58
+ acquiredAt: new Date(now).toISOString(),
59
+ expiresAt: new Date(now + this.ttlMs).toISOString(),
60
+ reason,
61
+ pid: process.pid,
62
+ hostname: os.hostname(),
63
+ };
64
+ let fd;
65
+ try {
66
+ // Atomic exclusive create — fails if file already exists
67
+ fd = fs.openSync(lockPath, "wx");
68
+ try {
69
+ fs.writeFileSync(fd, JSON.stringify(meta, null, 2), "utf8");
70
+ }
71
+ catch (writeErr) {
72
+ // CRITICAL: meta write failed after wx create (e.g. ENOSPC) — remove orphan lock
73
+ try {
74
+ if (fd !== undefined)
75
+ fs.closeSync(fd);
76
+ }
77
+ catch { /* ignore */ }
78
+ fd = undefined;
79
+ this.forceRemove(lockPath, null);
80
+ throw writeErr;
81
+ }
82
+ fs.closeSync(fd);
83
+ fd = undefined;
84
+ return { acquired: true, meta };
85
+ }
86
+ catch (err) {
87
+ if (fd !== undefined) {
88
+ try {
89
+ fs.closeSync(fd);
90
+ }
91
+ catch { /* ignore */ }
92
+ }
93
+ const code = err.code;
94
+ if (code === "EEXIST") {
95
+ // Race: another process created the lock between reclaim and open
96
+ const heldBy = this.readMeta(lockPath) ?? undefined;
97
+ // Corrupt lock (unreadable JSON) or expired → reclaim and retry once
98
+ if ((!heldBy || this.isExpired(heldBy)) && _reclaimDepth < 1) {
99
+ this.forceRemove(lockPath, heldBy ?? null);
100
+ return this.tryAcquire(resource, ownerId, reason, _reclaimDepth + 1);
101
+ }
102
+ return { acquired: false, heldBy };
103
+ }
104
+ throw err;
105
+ }
106
+ }
107
+ /**
108
+ * Acquire with async retry until timeout.
109
+ */
110
+ async acquireAsync(resource, ownerId, options) {
111
+ const timeoutMs = options?.timeoutMs ?? this.timeoutMs;
112
+ const retryMs = options?.retryMs ?? this.retryMs;
113
+ const start = Date.now();
114
+ while (true) {
115
+ const result = this.tryAcquire(resource, ownerId, options?.reason);
116
+ if (result.acquired && result.meta) {
117
+ return result.meta;
118
+ }
119
+ if (Date.now() - start >= timeoutMs) {
120
+ const holder = result.heldBy?.ownerId ?? "unknown";
121
+ throw new Error(`[AtomicFileLock] Timeout acquiring lock for "${resource}" after ${timeoutMs}ms (held by ${holder})`);
122
+ }
123
+ await sleep(retryMs);
124
+ }
125
+ }
126
+ /**
127
+ * Release lock only if owned by ownerId (or force=true).
128
+ */
129
+ release(resource, ownerId, force = false) {
130
+ const lockPath = this.getLockPath(resource);
131
+ if (!fs.existsSync(lockPath))
132
+ return true;
133
+ const meta = this.readMeta(lockPath);
134
+ if (!meta) {
135
+ this.forceRemove(lockPath, null);
136
+ return true;
137
+ }
138
+ if (!force && meta.ownerId !== ownerId) {
139
+ return false;
140
+ }
141
+ this.forceRemove(lockPath, meta);
142
+ return true;
143
+ }
144
+ isLocked(resource) {
145
+ const lockPath = this.getLockPath(resource);
146
+ if (!fs.existsSync(lockPath))
147
+ return null;
148
+ const meta = this.readMeta(lockPath);
149
+ if (!meta)
150
+ return null;
151
+ if (this.isExpired(meta)) {
152
+ this.forceRemove(lockPath, meta);
153
+ return null;
154
+ }
155
+ return meta;
156
+ }
157
+ /**
158
+ * Run `fn` while holding the lock.
159
+ * ALWAYS releases in `finally` even if `fn` throws (disk full, parse errors, etc.).
160
+ */
161
+ async withLock(resource, ownerId, fn, options) {
162
+ await this.acquireAsync(resource, ownerId, options);
163
+ try {
164
+ return await fn();
165
+ }
166
+ finally {
167
+ try {
168
+ this.release(resource, ownerId);
169
+ }
170
+ catch {
171
+ this.forceRemove(this.getLockPath(resource), null);
172
+ }
173
+ const stillHeld = this.isLocked(resource);
174
+ if (stillHeld && stillHeld.ownerId === ownerId) {
175
+ this.forceRemove(this.getLockPath(resource), stillHeld);
176
+ }
177
+ }
178
+ }
179
+ /**
180
+ * Synchronous withLock — same try/finally release guarantee.
181
+ */
182
+ withLockSync(resource, ownerId, fn, options) {
183
+ const result = this.tryAcquire(resource, ownerId, options?.reason);
184
+ if (!result.acquired) {
185
+ const holder = result.heldBy?.ownerId ?? "unknown";
186
+ throw new Error(`[AtomicFileLock] Could not acquire lock for "${resource}" (held by ${holder})`);
187
+ }
188
+ try {
189
+ return fn();
190
+ }
191
+ finally {
192
+ try {
193
+ this.release(resource, ownerId);
194
+ }
195
+ catch {
196
+ this.forceRemove(this.getLockPath(resource), null);
197
+ }
198
+ const stillHeld = this.isLocked(resource);
199
+ if (stillHeld && stillHeld.ownerId === ownerId) {
200
+ this.forceRemove(this.getLockPath(resource), stillHeld);
201
+ }
202
+ }
203
+ }
204
+ reclaimIfStale(lockPath) {
205
+ if (!fs.existsSync(lockPath))
206
+ return;
207
+ const meta = this.readMeta(lockPath);
208
+ if (!meta || this.isExpired(meta)) {
209
+ this.forceRemove(lockPath, meta);
210
+ }
211
+ }
212
+ isExpired(meta) {
213
+ const exp = Date.parse(meta.expiresAt);
214
+ if (Number.isNaN(exp)) {
215
+ // Fallback: acquiredAt + ttl
216
+ const acq = Date.parse(meta.acquiredAt);
217
+ return Number.isNaN(acq) ? true : Date.now() - acq > this.ttlMs;
218
+ }
219
+ return Date.now() > exp;
220
+ }
221
+ readMeta(lockPath) {
222
+ try {
223
+ const raw = fs.readFileSync(lockPath, "utf8");
224
+ return JSON.parse(raw);
225
+ }
226
+ catch {
227
+ return null;
228
+ }
229
+ }
230
+ forceRemove(lockPath, _meta) {
231
+ try {
232
+ fs.unlinkSync(lockPath);
233
+ }
234
+ catch {
235
+ // ignore ENOENT races
236
+ }
237
+ }
238
+ }
239
+ function sleep(ms) {
240
+ return new Promise((r) => setTimeout(r, ms));
241
+ }
242
+ /** Convenience: lock under project `.atabey/locks`. */
243
+ export function createProjectFileLock(projectRoot, options) {
244
+ return new AtomicFileLock({ ...options, projectRoot });
245
+ }
246
+ //# sourceMappingURL=file-lock.js.map