Canonical caller and manifest-level authorization helpers.
New protocols opt into enforcement with
:authorization {:caller :member} on a capability definition. Legacy
capabilities without that key retain their current behavior while they are
migrated deliberately. Actor identity always comes from MoM's top-level
:caller envelope, never from :event/data.
Canonical caller and manifest-level authorization helpers.
New protocols opt into enforcement with
`:authorization {:caller :member}` on a capability definition. Legacy
capabilities without that key retain their current behavior while they are
migrated deliberately. Actor identity always comes from MoM's top-level
`:caller` envelope, never from `:event/data`.Reusable Seller Commerce v2 payment HTTP boundary extracted from AoM. Protocol state stays in MoM.
Reusable Seller Commerce v2 payment HTTP boundary extracted from AoM. Protocol state stays in MoM.
Market checkout payment-provider adapters.
This is intentionally scoped to native Market checkout collection. It is not the general Payments Protocol; a future protocol can replace this namespace as the thing Market calls to collect a checkout.
Market checkout payment-provider adapters. This is intentionally scoped to native Market checkout collection. It is not the general Payments Protocol; a future protocol can replace this namespace as the thing Market calls to collect a checkout.
Runtime registry and HTTP client for Seller Commerce API v2.
Market stores public adapter capabilities. This namespace owns private routing and credentials. Adding a seller must not add a new code branch.
Runtime registry and HTTP client for Seller Commerce API v2. Market stores public adapter capabilities. This namespace owns private routing and credentials. Adding a seller must not add a new code branch.
OAuth authorization for seller-owned Standard accounts; legacy Yvatar remains pinned.
OAuth authorization for seller-owned Standard accounts; legacy Yvatar remains pinned.
Thin wrapper around Stripe REST API + webhook signature verification. v1 supports Hosted Checkout only; all funds land in our account. Connect migration is additive — see docs/stripe.md.
Thin wrapper around Stripe REST API + webhook signature verification. v1 supports Hosted Checkout only; all funds land in our account. Connect migration is additive — see docs/stripe.md.
Payload-bound command idempotency for pure Game Master transitions.
Payload-bound command idempotency for pure Game Master transitions.
Identity: sign-in, session and seat resolution for a Game Master.
Deliberately NOT under game.protocols. Everything in that package is a
pure event handler with a manifest, dispatched from MoM through
/v1/gm/handle and returning :updated-state. This is the opposite shape: HTTP
routes served to a browser, proxying MoM, holding no game state and
advertising no handlers. It belongs with the runtime concerns (config,
dispatch, heartbeat) rather than the game protocols.
The flow, end to end:
A seat is a game membership owned by the signed-in human, matched by
owner-id or owner-email. Most authenticated reads are seat-scoped, so
require-selected-seat is the usual entry point for a route.
Game-specific behaviour is injected through an options map rather than
baked in — see session-context.
Identity: sign-in, session and seat resolution for a Game Master.
Deliberately NOT under `game.protocols`. Everything in that package is a
pure event handler with a manifest, dispatched from MoM through
/v1/gm/handle and returning :updated-state. This is the opposite shape: HTTP
routes served to a *browser*, proxying MoM, holding no game state and
advertising no handlers. It belongs with the runtime concerns (config,
dispatch, heartbeat) rather than the game protocols.
The flow, end to end:
1. the browser GETs /auth.json from the GM it is talking to
2. it redirects to the hosted auth app with ?config=<that url>
3. the auth app signs the user in and redirects to :redirect_uri
(/auth/callback on this GM)
4. the GM bounces to the app with the token on the query string
5. the browser stores the token and sends it as a Bearer header
A *seat* is a game membership owned by the signed-in human, matched by
owner-id or owner-email. Most authenticated reads are seat-scoped, so
`require-selected-seat` is the usual entry point for a route.
Game-specific behaviour is injected through an options map rather than
baked in — see `session-context`.Idempotent startup seed for the Market taxonomy. Posts register-category and register-hashtag events to MoM as the Game Master so the marketplace UI has a non-empty set of categories and hashtags to render on day one.
Once a real curator process exists this seeder can go away.
Idempotent startup seed for the Market taxonomy. Posts register-category and register-hashtag events to MoM as the Game Master so the marketplace UI has a non-empty set of categories and hashtags to render on day one. Once a real curator process exists this seeder can go away.
Framework-neutral HTTP gateway. MoM re-verifies every forwarded credential; no caller identity or roles are accepted from Shoptype's request body.
Framework-neutral HTTP gateway. MoM re-verifies every forwarded credential; no caller identity or roles are accepted from Shoptype's request body.
Anonymous visitors: the web layer of coseller attribution for readers who have no seat yet.
A reader arriving through a ?ref= link cannot use /events — that route is
seat-gated, and event-payload rewrites the actor to the seat. The GM mints
them a visitor:<uuid> instead and records real touches against it; when
they later sign in, coseller/claim-visitor re-keys those touches onto their
player-name. See game.protocols.coseller for why the prefix is load-bearing.
Deliberately NOT under game.protocols, for the same reason as
game.gm.identity: everything there is a pure event handler with a manifest,
dispatched from MoM through /v1/gm/handle. This is the opposite shape — HTTP
routes served to a browser, proxying MoM, holding no game state and
advertising no handlers. The protocol half of anonymous visitors is already
in game.protocols.coseller and stays there.
A consuming GM supplies three things:
the routes themselves — gm-lib carries no compojure dependency, so each game keeps its own route definitions and delegates here:
(POST "/public/touch" [:as request] (gm-visitor/record-visitor-touch request)) (POST "/coseller/claim-visitor" [:as request] (let [{:keys [context seat response]} (require-selected-seat request)] (or response (gm-visitor/claim-visitor-touches request (:game-name context) seat {:submit-ui-event-fn submit-ui-event}))))
ring.middleware.cookies/wrap-cookies in the app's middleware stack.
Without it :cookies is absent on the request and unserialised on the
response, so every visit mints a new id and nothing is ever claimable
— a silent failure with a 200 on every call. This is the one wiring
mistake that looks like it works.
the dispatch fn for the claim (:submit-ui-event-fn), because the claim
must run as the signed-in caller, and building that payload is
game-specific. The public touch needs no injection: it runs on service
credentials via game.gm.identity/submit-service-event, and the game
name comes from the runtime.
Anonymous visitors: the web layer of coseller attribution for readers who
have no seat yet.
A reader arriving through a `?ref=` link cannot use /events — that route is
seat-gated, and event-payload rewrites the actor to the seat. The GM mints
them a `visitor:<uuid>` instead and records real touches against it; when
they later sign in, `coseller/claim-visitor` re-keys those touches onto their
player-name. See `game.protocols.coseller` for why the prefix is load-bearing.
Deliberately NOT under `game.protocols`, for the same reason as
`game.gm.identity`: everything there is a pure event handler with a manifest,
dispatched from MoM through /v1/gm/handle. This is the opposite shape — HTTP
routes served to a *browser*, proxying MoM, holding no game state and
advertising no handlers. The *protocol* half of anonymous visitors is already
in `game.protocols.coseller` and stays there.
A consuming GM supplies three things:
1. the routes themselves — gm-lib carries no compojure dependency, so each
game keeps its own route definitions and delegates here:
(POST "/public/touch" [:as request]
(gm-visitor/record-visitor-touch request))
(POST "/coseller/claim-visitor" [:as request]
(let [{:keys [context seat response]} (require-selected-seat request)]
(or response
(gm-visitor/claim-visitor-touches
request (:game-name context) seat
{:submit-ui-event-fn submit-ui-event}))))
2. `ring.middleware.cookies/wrap-cookies` in the app's middleware stack.
Without it `:cookies` is absent on the request and unserialised on the
response, so every visit mints a *new* id and nothing is ever claimable
— a silent failure with a 200 on every call. This is the one wiring
mistake that looks like it works.
3. the dispatch fn for the claim (`:submit-ui-event-fn`), because the claim
must run as the signed-in caller, and building that payload is
game-specific. The public touch needs no injection: it runs on service
credentials via `game.gm.identity/submit-service-event`, and the game
name comes from the runtime.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 |