The Uploads Protocol: images for callers that can only reach a Game Master through MoM.
An AI assistant connected through MoM's MCP server can send game events but cannot put a file in one: the tool carries small JSON, and the assistant holds no repo access or MoM credential of its own. This namespace gives a GM two ways in, both ending in MoM's file store (R2, game-scoped), so no GM needs a disk volume:
uploads/prepare-image-upload returns
a signed, ten-minute PUT URL bound to one membership and one exact file
(size, SHA-256, type). The caller PUTs the raw bytes to the GM, which
verifies them, stores them in MoM and answers with a receipt. The caller
then sends uploads/complete-image-upload through MoM, where its verified
membership must match the ticket's, and gets the image URL.uploads/import-image has the GM fetch an https image the
caller can already link to. For clients that cannot make a raw PUT.Tickets and receipts are self-contained HMAC-signed claims: there is no ticket database. A retried PUT stores a second copy rather than failing, which is harmless and bounded by the ticket's size and lifetime.
Images are PNG, JPEG or WebP, identified by their bytes, never by a header. SVG is refused: it carries script, and files are served from the GM's origin.
Wiring, in a GM: (uploads/manifest {:roles #{:strategist :creator}}) ; merge into the registry (uploads/routes {}) ; mount before catch-alls and add "uploads" to the game spec's :protocols.
Ticket URLs and receipts are credentials. Nothing here logs a URL, header, ticket or body, and every upload response is no-store.
The Uploads Protocol: images for callers that can only reach a Game Master
through MoM.
An AI assistant connected through MoM's MCP server can send game events but
cannot put a file in one: the tool carries small JSON, and the assistant holds
no repo access or MoM credential of its own. This namespace gives a GM two
ways in, both ending in MoM's file store (R2, game-scoped), so no GM needs a
disk volume:
1. Upload tickets (after OVERHEAD's). `uploads/prepare-image-upload` returns
a signed, ten-minute PUT URL bound to one membership and one exact file
(size, SHA-256, type). The caller PUTs the raw bytes to the GM, which
verifies them, stores them in MoM and answers with a receipt. The caller
then sends `uploads/complete-image-upload` through MoM, where its verified
membership must match the ticket's, and gets the image URL.
2. Import by URL. `uploads/import-image` has the GM fetch an https image the
caller can already link to. For clients that cannot make a raw PUT.
Tickets and receipts are self-contained HMAC-signed claims: there is no
ticket database. A retried PUT stores a second copy rather than failing,
which is harmless and bounded by the ticket's size and lifetime.
Images are PNG, JPEG or WebP, identified by their bytes, never by a header.
SVG is refused: it carries script, and files are served from the GM's origin.
Wiring, in a GM:
(uploads/manifest {:roles #{:strategist :creator}}) ; merge into the registry
(uploads/routes {}) ; mount before catch-alls
and add "uploads" to the game spec's :protocols.
Ticket URLs and receipts are credentials. Nothing here logs a URL, header,
ticket or body, and every upload response is no-store.(blocked-address? addr)Addresses a fetch must never reach: this machine, private networks, cloud metadata, multicast and reserved ranges.
Addresses a fetch must never reach: this machine, private networks, cloud metadata, multicast and reserved ranges.
(complete-upload opts payload)Confirm an upload through MoM: the receipt must be this membership's.
Confirm an upload through MoM: the receipt must be this membership's.
(file-response opts file-id)Stream a stored image from MoM. Public, so an <img> needs no token, and scoped to this game: the GM's service credential could read any game's file.
Stream a stored image from MoM. Public, so an <img> needs no token, and scoped to this game: the GM's service credential could read any game's file.
(identify b)The image's type and dimensions read from its bytes, or nil when it is not a PNG, JPEG or WebP we can size. Headers only: nothing is decoded.
The image's type and dimensions read from its bytes, or nil when it is not a PNG, JPEG or WebP we can size. Headers only: nothing is decoded.
(import-image opts payload)Fetch an https image the caller can link to, verify it and store it in MoM.
Fetch an https image the caller can link to, verify it and store it in MoM.
(manifest {:keys [roles] :as opts})The uploads protocol. roles are the seat roles allowed to add images.
The `uploads` protocol. `roles` are the seat roles allowed to add images.
(prepare-upload opts payload)Issue a ticket for one exact file, bound to the calling membership.
Issue a ticket for one exact file, bound to the calling membership.
(put-response opts upload-id request)(routes opts)The HTTP side: the ticketed PUT and the public image route.
The HTTP side: the ticketed PUT and the public image route.
(sha256-hex b)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 |