Liking cljdoc? Tell your friends :D

wagoe.platform.core.circuit-breaker

When to stop calling a service that keeps failing.

Retries bound the damage of one call; this bounds the damage of many. A service that is down still receives every request until each one times out, and every caller pays that timeout. Declining to call is the only thing that stops both.

FC/IS: pure. The state lives elsewhere — see …shell.rpc.breaker, which keeps it in the cache so replicas share one breaker rather than each discovering the outage separately.

When to stop calling a service that keeps failing.

Retries bound the damage of one call; this bounds the damage of many. A
service that is down still receives every request until each one times out,
and every caller pays that timeout. Declining to call is the only thing that
stops both.

FC/IS: pure. The state lives elsewhere — see `…shell.rpc.breaker`, which
keeps it in the cache so replicas share one breaker rather than each
discovering the outage separately.
raw docstring

wagoe.platform.core.csrf

Pure CSRF token functions — synchronizer token bound to a session.

The token is a signed double-submit value:

token = base64url(nonce) "." base64url(HMAC-SHA256(secret, nonce || binding))

The binding is the value the token is tied to: the user's session token for authenticated requests, or a per-request pre-session cookie value for the login form (which has no session yet). A token is only valid when presented together with the same binding it was signed against, which is what defeats CSRF: an attacker can forge a cross-site request but cannot read the victim's binding to produce a matching token.

Functional Core: these functions are pure and deterministic. The CSPRNG nonce and the secret are produced in the shell and passed in as arguments — nothing here performs I/O or reads ambient state.

Safety parity with ring-anti-forgery: validation uses buddy's mac/verify, which performs a constant-time comparison of the recomputed HMAC, so token checks do not leak timing information.

Enforcement is opt-in at the interceptor level (default off); see wagoe.platform.shell.http.interceptors/http-csrf-protection. Emit the token with hidden-field (server forms) or hx-headers (HTMX elements), or via the

<meta name="csrf-token"> tag + the ui-style init.js htmx:configRequest listener.

Pure CSRF token functions — synchronizer token bound to a session.

The token is a signed double-submit value:

    token = base64url(nonce) "." base64url(HMAC-SHA256(secret, nonce || binding))

The `binding` is the value the token is tied to: the user's session token for
authenticated requests, or a per-request pre-session cookie value for the login
form (which has no session yet). A token is only valid when presented together
with the same binding it was signed against, which is what defeats CSRF: an
attacker can forge a cross-site request but cannot read the victim's binding to
produce a matching token.

Functional Core: these functions are pure and deterministic. The CSPRNG nonce
and the secret are produced in the shell and passed in as arguments — nothing
here performs I/O or reads ambient state.

Safety parity with ring-anti-forgery: validation uses buddy's `mac/verify`,
which performs a constant-time comparison of the recomputed HMAC, so token
checks do not leak timing information.

Enforcement is opt-in at the interceptor level (default off); see
`wagoe.platform.shell.http.interceptors/http-csrf-protection`. Emit the token
with `hidden-field` (server forms) or `hx-headers` (HTMX elements), or via the
<meta name="csrf-token"> tag + the ui-style init.js htmx:configRequest listener.
raw docstring

wagoe.platform.core.database.query

Pure functions for SQL query building and transformation.

All functions in this namespace are pure - they take data and return data without side effects. No I/O, logging, or state mutation.

Pure functions for SQL query building and transformation.

All functions in this namespace are pure - they take data and return data
without side effects. No I/O, logging, or state mutation.
raw docstring

wagoe.platform.core.database.seed

Pure logic for database seeding.

A seed file is EDN, in either of two shapes.

A map of table -> rows, for the simple case:

{:tasks [{:title "Try the admin UI" :done false} {:title "Read AGENTS.md" :done true}]}

Or a vector of [table rows] pairs, which is ordered:

[[:users [{:email "admin@example.com"}]] [:tasks [{:title "Owned by that user" :user-id 1}]]]

Insert order matters as soon as one table references another, and EDN maps only preserve their written order up to 8 entries — a 9th turns the literal into a PersistentHashMap and the order becomes hash order. Rather than let a seed file quietly start inserting children before parents once it grows, a map larger than that is rejected with a pointer to the vector form.

Table and column names are written in kebab-case, like the rest of the codebase; the conversion to snake_case happens here, at the point where the data becomes a persistence concern.

Everything in this namespace is pure. Validation returns typed error values rather than throwing — the shell decides how to present them.

Pure logic for database seeding.

A seed file is EDN, in either of two shapes.

A map of table -> rows, for the simple case:

  {:tasks [{:title "Try the admin UI" :done false}
           {:title "Read AGENTS.md"   :done true}]}

Or a vector of [table rows] pairs, which is ordered:

  [[:users [{:email "admin@example.com"}]]
   [:tasks [{:title "Owned by that user" :user-id 1}]]]

Insert order matters as soon as one table references another, and EDN maps
only preserve their written order up to 8 entries — a 9th turns the literal
into a PersistentHashMap and the order becomes hash order. Rather than let a
seed file quietly start inserting children before parents once it grows, a
map larger than that is rejected with a pointer to the vector form.

Table and column names are written in kebab-case, like the rest of the
codebase; the conversion to snake_case happens here, at the point where the
data becomes a persistence concern.

Everything in this namespace is pure. Validation returns typed error values
rather than throwing — the shell decides how to present them.
raw docstring

wagoe.platform.core.http.problem-details

Pure functions for RFC 7807 Problem Details transformations.

All functions are pure data transformations from exceptions to standardized error response structures.

Pure functions for RFC 7807 Problem Details transformations.

All functions are pure data transformations from exceptions to
standardized error response structures.
raw docstring

wagoe.platform.core.pagination.pagination

Pure functions for pagination logic.

This namespace provides pure functional implementations for pagination calculations, following the Functional Core pattern. All functions are deterministic and side-effect free.

Supports:

  • Offset-based pagination (simple, familiar)
  • Cursor-based pagination (high performance, stable results)
  • Parameter validation
  • Metadata calculation

Pure: All functions return data, no side effects.

Pure functions for pagination logic.

This namespace provides pure functional implementations for pagination calculations,
following the Functional Core pattern. All functions are deterministic and side-effect free.

Supports:
- Offset-based pagination (simple, familiar)
- Cursor-based pagination (high performance, stable results)
- Parameter validation
- Metadata calculation

Pure: All functions return data, no side effects.
raw docstring

wagoe.platform.core.pagination.versioning

Pure functions for API versioning logic.

This namespace provides pure functional implementations for API version management, following the Functional Core pattern. All functions are deterministic and side-effect free.

Supports:

  • Version parsing and comparison
  • Version lifecycle management (experimental → stable → deprecated → sunset)
  • Version validation
  • Migration path tracking

Pure: All functions return data, no side effects.

Pure functions for API versioning logic.

This namespace provides pure functional implementations for API version
management, following the Functional Core pattern. All functions are
deterministic and side-effect free.

Supports:
- Version parsing and comparison
- Version lifecycle management (experimental → stable → deprecated → sunset)
- Version validation
- Migration path tracking

Pure: All functions return data, no side effects.
raw docstring

wagoe.platform.core.rpc

Pure RPC envelope handling for the remote-port adapter.

A cross-module call goes through a protocol (ports.clj). Slicing a module into its own process means implementing that same protocol with something that makes a network call instead — the seam is already there, only the adapter is missing (BOU-90, scaling.adoc → Functional decomposition).

This namespace is the wire contract and nothing else: building an envelope, reading one, and turning a remote failure into the error shape callers already handle. No I/O — see wagoe.platform.shell.rpc.client and …rpc.server for that.

FC/IS: pure. Everything here is data in, data out.

Pure RPC envelope handling for the remote-port adapter.

A cross-module call goes through a protocol (`ports.clj`). Slicing a module
into its own process means implementing that same protocol with something
that makes a network call instead — the seam is already there, only the
adapter is missing (BOU-90, scaling.adoc → Functional decomposition).

This namespace is the wire contract and nothing else: building an envelope,
reading one, and turning a remote failure into the error shape callers
already handle. No I/O — see `wagoe.platform.shell.rpc.client` and
`…rpc.server` for that.

FC/IS: pure. Everything here is data in, data out.
raw docstring

wagoe.platform.core.system-selection

Cut an Integrant config down to the modules one service runs.

Modules are already gated by :enabled?, and the router mounts only the routes it is handed, so a process can run a subset — there was just no way to say which subset (BOU-91). This is that, as a pure transformation: config in, smaller config out.

The whole difficulty is refs. Dropping :wagoe/tenant-service leaves :wagoe/http-handler pointing at a key that no longer exists, and Integrant refuses to build a config with a dangling ref — so the refs have to go with the keys, and they have to go first, or the closure that works out what is still needed follows them straight back to everything.

FC/IS: pure. Nothing here starts, stops or reads anything.

Cut an Integrant config down to the modules one service runs.

Modules are already gated by `:enabled?`, and the router mounts only the
routes it is handed, so a process *can* run a subset — there was just no way
to say which subset (BOU-91). This is that, as a pure transformation:
config in, smaller config out.

The whole difficulty is refs. Dropping `:wagoe/tenant-service` leaves
`:wagoe/http-handler` pointing at a key that no longer exists, and Integrant
refuses to build a config with a dangling ref — so the refs have to go with
the keys, and they have to go *first*, or the closure that works out what is
still needed follows them straight back to everything.

FC/IS: pure. Nothing here starts, stops or reads anything.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close