Heavy Computation's Cloudflare toolkit for Clojure.
A thin, batteries-included wrapper over the Cloudflare products we reach for in every webapp. Features are added incrementally:
This namespace re-exports R2's high-level API for convenience. Images is not
flattened in here: its CRUD verbs (get/list/update/delete/exists?/
get-bytes/request …) would collide with R2's, and a bare upload/delete
at the top level couldn't tell which product you meant. So Images is used
through its own namespace — (require '[…cloudflare.images :as images]) — and
so is R2's raw escape hatch. For the full surface, use the per-product
namespaces directly.
get/list shadow clojure.core names and are excluded here; refer to them
qualified (e.g. cloudflare/get).
Heavy Computation's Cloudflare toolkit for Clojure. A thin, batteries-included wrapper over the Cloudflare products we reach for in every webapp. Features are added incrementally: - R2 object storage (S3-compatible) -> com.heavycomputation.cloudflare.r2 - Images upload/manage/serve -> com.heavycomputation.cloudflare.images This namespace re-exports R2's high-level API for convenience. Images is *not* flattened in here: its CRUD verbs (`get`/`list`/`update`/`delete`/`exists?`/ `get-bytes`/`request` …) would collide with R2's, and a bare `upload`/`delete` at the top level couldn't tell which product you meant. So Images is used through its own namespace — `(require '[…cloudflare.images :as images])` — and so is R2's raw escape hatch. For the full surface, use the per-product namespaces directly. `get`/`list` shadow `clojure.core` names and are excluded here; refer to them qualified (e.g. `cloudflare/get`).
Cloudflare Images: store, manage, and serve images.
Unlike R2 (which speaks S3 and is signed with SigV4), Images has two distinct surfaces, and this namespace covers both:
internal.api) — for uploading, listing, updating and
deleting images; andimagedelivery.net/<hash>/<id>/ <variant>, a URL this namespace builds (and, for private images, signs)
with no network round-trip.The public API:
(client m) ; build a client handle (upload client body) ; upload a File/byte[]/InputStream (upload-url client url) ; ingest a remote image by URL (direct-upload-url client) ; a one-time URL the browser uploads to (get client id) ; fetch details; also head-less exists? (list client) / (list-seq …) ; enumerate images (v2 cursor pagination) (update client id m) ; edit metadata / requireSignedURLs (delete client id) ; remove an image (idempotent) (get-bytes client id) ; original bytes; also get-stream (stats client) ; usage counts (signing-keys client) ; the URL-signing keys (delivery-url client id v) ; build (optionally signed) a delivery URL (request client req) ; escape hatch to the raw v4 API
get/list/update shadow clojure.core names, so this namespace excludes
them; refer to them qualified (e.g. images/get).
Cloudflare Images: store, manage, and serve images.
Unlike R2 (which speaks S3 and is signed with SigV4), Images has two distinct
surfaces, and this namespace covers both:
- the **management API** — Cloudflare's REST API v4, authenticated with a
Bearer token (see `internal.api`) — for uploading, listing, updating and
deleting images; and
- **delivery** — images are *served* from `imagedelivery.net/<hash>/<id>/
<variant>`, a URL this namespace builds (and, for private images, signs)
with no network round-trip.
The public API:
(client m) ; build a client handle
(upload client body) ; upload a File/byte[]/InputStream
(upload-url client url) ; ingest a remote image by URL
(direct-upload-url client) ; a one-time URL the browser uploads to
(get client id) ; fetch details; also head-less exists?
(list client) / (list-seq …) ; enumerate images (v2 cursor pagination)
(update client id m) ; edit metadata / requireSignedURLs
(delete client id) ; remove an image (idempotent)
(get-bytes client id) ; original bytes; also get-stream
(stats client) ; usage counts
(signing-keys client) ; the URL-signing keys
(delivery-url client id v) ; build (optionally signed) a delivery URL
(request client req) ; escape hatch to the raw v4 API
`get`/`list`/`update` shadow `clojure.core` names, so this namespace excludes
them; refer to them qualified (e.g. `images/get`).A tiny, zero-dependency client for the Cloudflare REST API v4: attaches a
Bearer token and sends requests over the JDK's java.net.http client. It is
the transport the Images product needs — the counterpart to internal.s3,
but for Cloudflare's own JSON API rather than S3.
It handles two request-body shapes, both hand-rolled so nothing is pulled in:
a JSON body (:json <clj-data>) and a multipart/form-data upload
(:multipart [part …]). It is stateless and carries no per-product knowledge;
callers build paths and interpret responses.
A tiny, zero-dependency client for the Cloudflare REST API v4: attaches a Bearer token and sends requests over the JDK's `java.net.http` client. It is the transport the Images product needs — the counterpart to `internal.s3`, but for Cloudflare's own JSON API rather than S3. It handles two request-body shapes, both hand-rolled so nothing is pulled in: a JSON body (`:json <clj-data>`) and a `multipart/form-data` upload (`:multipart [part …]`). It is stateless and carries no per-product knowledge; callers build paths and interpret responses.
Just enough JSON to talk to the Cloudflare REST API v4: read the small
{success, errors, messages, result} envelopes it returns and write the
compact request bodies (and x-amz-free metadata blobs) we send.
This is deliberately not a general JSON library — but it is a correct one
for the subset it covers: objects, arrays, strings (with \uXXXX and the
usual escapes), numbers (long or double), true/false/null. Keeping it
in-house preserves the library's zero-dependency promise, the same way
internal.xml does for S3.
read returns objects as maps with string keys (Cloudflare's are camelCase,
so callers destructure with :strs); write accepts maps with string or
keyword keys.
Just enough JSON to talk to the Cloudflare REST API v4: read the small
`{success, errors, messages, result}` envelopes it returns and write the
compact request bodies (and `x-amz`-free metadata blobs) we send.
This is deliberately *not* a general JSON library — but it is a correct one
for the subset it covers: objects, arrays, strings (with `\uXXXX` and the
usual escapes), numbers (long or double), `true`/`false`/`null`. Keeping it
in-house preserves the library's zero-dependency promise, the same way
`internal.xml` does for S3.
`read` returns objects as maps with *string* keys (Cloudflare's are camelCase,
so callers destructure with `:strs`); `write` accepts maps with string or
keyword keys.A tiny, zero-dependency S3 client: signs each request with SigV4 and sends it
over the JDK's java.net.http client. It is path-style and stateless — just
the transport R2 needs, with no per-operation knowledge baked in.
A tiny, zero-dependency S3 client: signs each request with SigV4 and sends it over the JDK's `java.net.http` client. It is path-style and stateless — just the transport R2 needs, with no per-operation knowledge baked in.
AWS Signature Version 4 signing, pared down to what R2 needs.
Header-based authorization (not presigned query strings), SHA-256 payload
hashing, path-style URLs. No chunked/streaming signature. The crypto is all
JDK-native (java.security, javax.crypto), so this carries no dependency.
sign is pure — timestamps are passed in rather than read from the clock —
which lets it be checked against AWS's published test vectors.
AWS Signature Version 4 signing, pared down to what R2 needs. Header-based authorization (not presigned query strings), SHA-256 payload hashing, path-style URLs. No chunked/streaming signature. The crypto is all JDK-native (`java.security`, `javax.crypto`), so this carries no dependency. `sign` is pure — timestamps are passed in rather than read from the clock — which lets it be checked against AWS's published test vectors.
Just enough XML to talk to S3: pull a tag's text out of a small response document and build the CompleteMultipartUpload request body.
This is deliberately not a general XML library. The documents S3 returns for the handful of operations we use are small, flat, and machine-generated, so a tag scan is enough and avoids a parser dependency.
Just enough XML to talk to S3: pull a tag's text out of a small response document and build the CompleteMultipartUpload request body. This is deliberately *not* a general XML library. The documents S3 returns for the handful of operations we use are small, flat, and machine-generated, so a tag scan is enough and avoids a parser dependency.
Cloudflare R2 object storage.
R2 speaks the S3 API, so this namespace signs requests with AWS Signature V4
and sends them over the JDK's http client (see the internal namespaces) —
no AWS SDK, no dependencies. The public API:
(bucket m) ; build a bucket handle (put bucket key body) ; upload an object, multipart automatically (get-bytes bucket key) ; download; also head/exists?/get/get-stream (delete bucket key) ; remove; also delete-many for batches (list bucket opts) ; enumerate by prefix; also list-seq (lazy) (presigned-url bucket k) ; time-limited download/upload URL (create-multipart-upload bucket k) ; broker a browser-direct multipart upload (request bucket req) ; escape hatch to the raw signed-S3 surface
put hides the single-PUT vs. multipart decision: small objects go up in one
request, large objects (and unknown-length streams) are split into parts that
upload concurrently and retry individually, so a network blip only costs the
part that failed rather than the whole transfer.
get/head/list shadow clojure.core names, so this namespace excludes
them; refer to it qualified (e.g. r2/get).
Cloudflare R2 object storage. R2 speaks the S3 API, so this namespace signs requests with AWS Signature V4 and sends them over the JDK's http client (see the `internal` namespaces) — no AWS SDK, no dependencies. The public API: (bucket m) ; build a bucket handle (put bucket key body) ; upload an object, multipart automatically (get-bytes bucket key) ; download; also head/exists?/get/get-stream (delete bucket key) ; remove; also delete-many for batches (list bucket opts) ; enumerate by prefix; also list-seq (lazy) (presigned-url bucket k) ; time-limited download/upload URL (create-multipart-upload bucket k) ; broker a browser-direct multipart upload (request bucket req) ; escape hatch to the raw signed-S3 surface `put` hides the single-PUT vs. multipart decision: small objects go up in one request, large objects (and unknown-length streams) are split into parts that upload concurrently and retry individually, so a network blip only costs the part that failed rather than the whole transfer. `get`/`head`/`list` shadow `clojure.core` names, so this namespace excludes them; refer to it qualified (e.g. `r2/get`).
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 |