/** * The durable lock record and the pure reducers that mutate it. These are the * deterministic core of the {@link DurableSemaphore}/{@link DurableMutex} * primitives in `./concurrency.ts`: every acquire, release, and renew is one * pure function over a {@link LockRecord}, so the algorithm is trivially * replay-safe and unit-testable in isolation from any storage flavour. * * @module core/concurrency-lock-record */ /** * One permit currently held against a {@link DurableSemaphore}. `leaseExpiresAt` * is the deterministic timestamp (milliseconds since epoch) after which the * permit may be reclaimed by another contender, preventing a crashed holder * from deadlocking the lock. * * @example * ```ts * import type { LockHolder } from '@lostgradient/weft'; * * const holder: LockHolder = { holderId: 'workflow-a', leaseExpiresAt: 1_717_000_030_000 }; * void holder; * ``` */ export interface LockHolder { /** Caller-chosen identifier for the holder (typically `ctx.workflowId`). */ holderId: string; /** Timestamp (ms since epoch) after which this lease may be reclaimed. */ leaseExpiresAt: number; } /** * The durable record persisted in a single CAS state slot. `holders` are the * permits currently granted (length never exceeds the semaphore's permit * count); `waiters` is the FIFO queue of holder ids waiting for a permit. * * @example * ```ts * import type { LockRecord } from '@lostgradient/weft'; * * const record: LockRecord = { * holders: [{ holderId: 'workflow-a', leaseExpiresAt: 1_717_000_030_000 }], * waiters: ['workflow-b'], * }; * void record; * ``` */ export interface LockRecord { holders: LockHolder[]; waiters: string[]; } /** * Outcome of a single non-blocking acquire attempt. * * @example * ```ts * import type { AcquireAttempt } from '@lostgradient/weft'; * * const attempt: AcquireAttempt = { acquired: false, position: 0 }; * if (!attempt.acquired) { * // attempt.position is the caller's place in the FIFO queue. * } * ``` */ export interface AcquireAttempt { /** Whether the caller now holds a permit. */ acquired: boolean; /** * Zero-based position in the FIFO waiter queue when `acquired` is `false`. * `0` means the caller is next in line. `-1` when `acquired` is `true`. */ position: number; } /** * A fresh empty {@link LockRecord}. Pass this as the `initial` option when * constructing the CAS state handle so the first reader sees an empty lock * rather than `undefined`. * * @example * ```ts * import { initialLockRecord, AtomicState } from '@lostgradient/weft'; * import { MemoryStorage } from '@lostgradient/weft/storage/memory'; * * const slot = new AtomicState(new MemoryStorage(), 'state:workflow-scope:default:lock', { * initial: initialLockRecord(), * }); * void slot; * ``` */ export declare function initialLockRecord(): LockRecord; /** * Pure reducer for one acquire attempt. Returns the next record alongside * whether the caller acquired a permit and its queue position. Deterministic * in its inputs so it replays identically. */ export declare function reduceAcquire(current: LockRecord | undefined, options: { holderId: string; now: number; leaseMs: number; permits: number; }): { record: LockRecord; attempt: AcquireAttempt; }; /** * Pure reducer for releasing a permit. Removes the holder (and any stale waiter * entry) and reclaims expired leases so the record stays clean. */ export declare function reduceRelease(current: LockRecord | undefined, options: { holderId: string; now: number; }): LockRecord; /** * Pure reducer for renewing a held lease. Extends the holder's * `leaseExpiresAt`; a no-op if the caller is not currently a holder. */ export declare function reduceRenew(current: LockRecord | undefined, options: { holderId: string; now: number; leaseMs: number; }): { record: LockRecord; renewed: boolean; };