ETS-backed cache adapter for payment identifier idempotency.
Entries expire after :ttl_ms (default: 1 hour). Expired entries are removed
by an internal periodic cleanup loop.
Per-node only
The ETS table lives on the local node. In a clustered BEAM deployment each
node keeps its own independent table, so this adapter cannot prevent the
same payment proof from being served once per node. See the
"Clustered deployments" section in
X402.Extensions.PaymentIdentifier.Cache for a shared-store adapter
sketch.
Summary
Types
Server identifier accepted by GenServer.call/3.
Functions
Returns a child specification for X402.Extensions.PaymentIdentifier.ETSCache.
Deletes a payment identifier entry from the cache.
Looks up a payment identifier in the cache.
Stores a payment identifier result in the cache.
Atomically inserts a payment identifier only if it does not already exist.
Starts an ETS-backed idempotency cache process.
Types
@type server() :: GenServer.server()
Server identifier accepted by GenServer.call/3.
Functions
@spec child_spec(keyword()) :: Supervisor.child_spec()
Returns a child specification for X402.Extensions.PaymentIdentifier.ETSCache.
@spec delete(server(), X402.Extensions.PaymentIdentifier.Cache.key()) :: X402.Extensions.PaymentIdentifier.Cache.write_result()
Deletes a payment identifier entry from the cache.
@spec get(server(), X402.Extensions.PaymentIdentifier.Cache.key()) :: X402.Extensions.PaymentIdentifier.Cache.get_result()
Looks up a payment identifier in the cache.
@spec put( server(), X402.Extensions.PaymentIdentifier.Cache.key(), X402.Extensions.PaymentIdentifier.Cache.value() ) :: X402.Extensions.PaymentIdentifier.Cache.write_result()
Stores a payment identifier result in the cache.
@spec put_new( server(), X402.Extensions.PaymentIdentifier.Cache.key(), X402.Extensions.PaymentIdentifier.Cache.value() ) :: :ok | {:error, :already_exists | :cache_full | :invalid_cache_value}
Atomically inserts a payment identifier only if it does not already exist.
Returns :ok if the entry was inserted, or {:error, :already_exists} if
a non-expired entry for payment_id is already present. This is used to
prevent concurrent requests from double-settling the same payment proof.
When the table is at :max_size and purging expired entries does not free a
slot, returns {:error, :cache_full} instead of evicting a live claim —
evicting live claims would let cheap junk claims drop legitimate replay
locks. Size :max_size for your expected claim TTL × request rate.
@spec start_link(keyword()) :: GenServer.on_start() | {:error, NimbleOptions.ValidationError.t()}
Starts an ETS-backed idempotency cache process.
Options
:name(term/0) - Registered name for the ETS cache process. The default value isX402.Extensions.PaymentIdentifier.ETSCache.:ttl_ms(non_neg_integer/0) - Time-to-live for entries in milliseconds. The default value is3600000.:cleanup_interval_ms(pos_integer/0) - How often expired entries are cleaned up, in milliseconds. The default value is60000.:max_size(pos_integer/0) - Maximum number of entries in the cache. The default value is10000.