crypto-aio / crypto-aio / OperationStore
Interface: OperationStore ​
Defined in: src/core/store/types.ts:264
Durable Operation storage. Required guarantees (verified by the contract suite), binding on every implementation (memory, Redis, Postgres, ...):
createis create-if-absent on(namespace, idempotencyKey): a secondcreatefor an existing key returns the stored record unchanged, regardless ofintentHash— this store never performs the idempotency-conflict check itself; the calling engine does.update/appendAttemptare version-checked (compare-and-set onexpectedVersion) and optionally fenced by a claim token. Both are restricted to the same runtime patch whitelist (OPERATION_PATCH_KEYS), andclearmay only nameCLEARABLE_FIELDS; any other key anywhere in the patch rejects the whole call withINVALID_TRANSITIONbefore any mutation. An explicitundefinedvalue for a writable field is a no-op (the stored value survives); onlyclearremoves a field.appendAttemptis atomic with its accompanying patch, never rewrites a previously storedAttemptRecord, and rejects a duplicate attempt id. Attempt ids are globally unique across every Operation and namespace: the core makes each one random, and observations are keyed by attempt id alone, so a store may also refuse (INVALID_TRANSITION) an id that another Operation holds.- Time:
createdAt,updatedAtand claim expiry are stamped with the store's clock, which the core compares with its own (claimDuegets the worker'snow). Give a durable store the container's clock, or a wall clock the processes share, as the memory stores take theirs. claimDueandlistare scoped by namespace: they never return a record of another namespace, even one with the same id.claimDuereturns only non-terminal operations withnextCheckAtset and<= now, ordered by(nextCheckAt, createdAt)with a stable tie-break for equal values, and returns[]forlimit <= 0. A claimed Operation is excluded until itsclaim.until <= now; then another worker may take it over. Claim tokens are strictly increasing per store; fenced writes are rejected after a takeover.listreturns matches in creation order.ClearableFieldis restricted on purpose:clearcan never remove store-owned or identity fields (attempts,claim,version,id, ...) orstate. An implementation reads the caller'sclearlist once, so the list it validates is the list it applies.- A key set to
undefined, in an observation or a patch, is never persisted as a value such asnull. In a patch, the stored field keeps its value. In an observation, which replaces the whole record, the field reads backundefined(nevernull).
Methods ​
appendAttempt() ​
appendAttempt(
namespace,id,attempt,patch,expectedVersion,fence?):Promise<OperationRecord>
Defined in: src/core/store/types.ts:289
Parameters ​
namespace ​
string
id ​
string
attempt ​
patch ​
expectedVersion ​
number
fence? ​
Returns ​
Promise<OperationRecord>
claimDue() ​
claimDue(
namespace,workerId,now,leaseMs,limit):Promise<OperationRecord[]>
Defined in: src/core/store/types.ts:309
Claims non-terminal operations whose nextCheckAt is set and <= now (unscheduled ones are never due).
Parameters ​
namespace ​
string
workerId ​
string
now ​
number
leaseMs ​
number
limit ​
number
Returns ​
Promise<OperationRecord[]>
create() ​
create(
operation):Promise<CreateResult>
Defined in: src/core/store/types.ts:265
Parameters ​
operation ​
Returns ​
Promise<CreateResult>
findByRef() ​
findByRef(
namespace,refOrTxHash):Promise<OperationRecord|null>
Defined in: src/core/store/types.ts:276
Finds by an Attempt ref id or by an observed canonical tx hash. The engine's AttemptRef guard, which refuses an Attempt whose ref another Operation of the namespace holds, relies on this read being read-your-writes consistent across every process that shares the store: it must see any appendAttempt that another store instance committed before it was called (no read replica, no eventually consistent index).
Parameters ​
namespace ​
string
refOrTxHash ​
string
Returns ​
Promise<OperationRecord | null>
get() ​
get(
namespace,id):Promise<OperationRecord|null>
Defined in: src/core/store/types.ts:266
Parameters ​
namespace ​
string
id ​
string
Returns ​
Promise<OperationRecord | null>
getByKey() ​
getByKey(
namespace,idempotencyKey):Promise<OperationRecord|null>
Defined in: src/core/store/types.ts:267
Parameters ​
namespace ​
string
idempotencyKey ​
string
Returns ​
Promise<OperationRecord | null>
getObservation() ​
getObservation(
attemptId):Promise<AttemptObservation|null>
Defined in: src/core/store/types.ts:297
Parameters ​
attemptId ​
string
Returns ​
Promise<AttemptObservation | null>
list() ​
list(
filter):Promise<OperationRecord[]>
Defined in: src/core/store/types.ts:317
Parameters ​
filter ​
Returns ​
Promise<OperationRecord[]>
purge()? ​
optionalpurge(filter):Promise<number>
Defined in: src/core/store/types.ts:318
Parameters ​
filter ​
Returns ​
Promise<number>
putObservation() ​
putObservation(
observation,expectedVersion):Promise<AttemptObservation>
Defined in: src/core/store/types.ts:304
Stores observation as the whole new record, version-checked. An optional field left out of it or set to undefined (a cleared reason, blockHash or blockHeight) reads back undefined (never null) afterwards. A store must replace the record, never merge fields into the old one. The monitor relies on this to clear stale values.
Parameters ​
observation ​
Omit<AttemptObservation, "version">
expectedVersion ​
number | null
Returns ​
Promise<AttemptObservation>
releaseClaim() ​
releaseClaim(
namespace,id,fence):Promise<void>
Defined in: src/core/store/types.ts:316
Parameters ​
namespace ​
string
id ​
string
fence ​
Returns ​
Promise<void>
update() ​
update(
namespace,id,patch,expectedVersion,fence?):Promise<OperationRecord>
Defined in: src/core/store/types.ts:282
Compare-and-set on expectedVersion, optionally fenced. Every successful update bumps version, even when the patch changes no field (the engine fences stale writers with such a no-effect update).
Parameters ​
namespace ​
string
id ​
string
patch ​
expectedVersion ​
number
fence? ​
Returns ​
Promise<OperationRecord>