Where the store says what happened — as a port.
A store that cannot see its own funnel cannot be improved, and a store that ships its customers' payment details to an analytics vendor should not exist. Both facts are handled by the same seam: the pipeline emits DOMAIN events with named fields, and an adapter decides what leaves the building.
Ships with a no-op, a logger, an in-memory recorder for tests, and an Umami adapter — Umami because it is self-hostable, so the funnel of a Monero store need not be posted to an advertising network to be measured.
Where the store says what happened — as a port. A store that cannot see its own funnel cannot be improved, and a store that ships its customers' payment details to an analytics vendor should not exist. Both facts are handled by the same seam: the pipeline emits DOMAIN events with named fields, and an adapter decides what leaves the building. Ships with a no-op, a logger, an in-memory recorder for tests, and an Umami adapter — Umami because it is self-hostable, so the funnel of a Monero store need not be posted to an advertising network to be measured.
The hosted-checkout processor as a port, plus a fake.
Callers above this namespace see schema/CheckoutSession values. The Stripe
adapter needs an SDK and lives behind its own alias in adapters/stripe; any
processor with the same two operations drops in beside it.
The hosted-checkout processor as a port, plus a fake. Callers above this namespace see `schema/CheckoutSession` values. The Stripe adapter needs an SDK and lives behind its own alias in `adapters/stripe`; any processor with the same two operations drops in beside it.
What the store does once money is confirmed — as a port.
This is the seam the host application implements: grant a licence, flip a feature, ship a key, extend a subscription. The store decides WHETHER; the host decides WHAT.
A fulfilment MUST be idempotent. The store gates on the invoice's
pending -> paid transition, so it calls fulfil! once per invoice under
normal operation — but a process that dies between the claim and the call is
retried by the next sweep, and at-least-once is the only delivery a store
and a foreign system can honestly agree on.
What the store does once money is confirmed — as a port. This is the seam the host application implements: grant a licence, flip a feature, ship a key, extend a subscription. The store decides WHETHER; the host decides WHAT. A fulfilment MUST be idempotent. The store gates on the invoice's pending -> paid transition, so it calls `fulfil!` once per invoice under normal operation — but a process that dies between the claim and the call is retried by the next sweep, and at-least-once is the only delivery a store and a foreign system can honestly agree on.
Outbound HTTP as a port, so every adapter above it is testable with a map.
One shape in — {:http/method :http/url :http/headers :http/body} — and one shape out: {:http/status :http/body}, the body already parsed when it was JSON. Only this namespace knows which client library is on the classpath.
Outbound HTTP as a port, so every adapter above it is testable with a map.
One shape in — {:http/method :http/url :http/headers :http/body} — and one
shape out: {:http/status :http/body}, the body already parsed when it was
JSON. Only this namespace knows which client library is on the classpath.Public price tickers behind one port, described as data.
Adding an exchange — or a whole new pair — is a map entry in sources;
nothing here branches on which exchange it is. A source that fails is simply
absent from the round, and the quote layer above decides whether what came
back is enough to price a sale.
Public price tickers behind one port, described as data. Adding an exchange — or a whole new pair — is a map entry in `sources`; nothing here branches on which exchange it is. A source that fails is simply absent from the round, and the quote layer above decides whether what came back is enough to price a sale.
Can the store reach the services it settles through?
A telnet by hand answers this once, for one person, and leaves nothing
behind. probe answers it as a value: which endpoint, which outcome, how
long it took.
Can the store reach the services it settles through? A telnet by hand answers this once, for one person, and leaves nothing behind. `probe` answers it as a value: which endpoint, which outcome, how long it took.
Persistence as a port, plus the in-memory adapter the template runs on.
Two operations carry the invariants; everything else is storage.
record-payment! is idempotent per (invoice, reference): a rail that reports
the same transaction forever must move the books exactly once.
claim-paid! is a compare-and-set on the invoice's status. Only the caller
that performs the pending -> paid transition is told it did, and that caller
is the one — the only one — that may hand anything over.
Persistence as a port, plus the in-memory adapter the template runs on. Two operations carry the invariants; everything else is storage. `record-payment!` is idempotent per (invoice, reference): a rail that reports the same transaction forever must move the books exactly once. `claim-paid!` is a compare-and-set on the invoice's status. Only the caller that performs the pending -> paid transition is told it did, and that caller is the one — the only one — that may hand anything over.
The chain wallet as a port, plus the adapters that need no SDK.
Callers above this namespace see schema/Subaddress and
schema/WalletObservation — never a gateway's JSON, never a wallet library's
types. Two concrete adapters live here (MoneroPay over HTTP, and a fake); the
monero-wallet-rpc adapter needs a Java SDK and lives behind its own alias in
adapters/monero-rpc.
The chain wallet as a port, plus the adapters that need no SDK. Callers above this namespace see `schema/Subaddress` and `schema/WalletObservation` — never a gateway's JSON, never a wallet library's types. Two concrete adapters live here (MoneroPay over HTTP, and a fake); the monero-wallet-rpc adapter needs a Java SDK and lives behind its own alias in `adapters/monero-rpc`.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |