X402.Extensions.PaymentIdentifier.ETSCache (X402 v0.6.0)

Copy Markdown View Source

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

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

server()

@type server() :: GenServer.server()

Server identifier accepted by GenServer.call/3.

Functions

child_spec(init_arg)

(since 0.1.0)
@spec child_spec(keyword()) :: Supervisor.child_spec()

Returns a child specification for X402.Extensions.PaymentIdentifier.ETSCache.

delete(cache, payment_id)

(since 0.1.0)

Deletes a payment identifier entry from the cache.

get(cache, payment_id)

(since 0.1.0)

Looks up a payment identifier in the cache.

put(cache, payment_id, value)

(since 0.1.0)

Stores a payment identifier result in the cache.

put_new(cache, payment_id, value)

(since 0.4.0)
@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.

start_link(opts \\ [])

(since 0.1.0)
@spec start_link(keyword()) ::
  GenServer.on_start() | {:error, NimbleOptions.ValidationError.t()}

Starts an ETS-backed idempotency cache process.

Options