@kentcdodds/cloudflare
Cloudflare helpers: API v4, static site publishing to Pages, analytics, WAF rules, logs, and docs.
README.md
93 lines · 4.6 KB · Markdown@kentcdodds/cloudflare
Intent
Account-aware Cloudflare helpers for Kody workflows: API v4 (JSON, multipart,
and raw bodies), public static-site publishing to Cloudflare Pages, GraphQL
analytics, Rulesets/WAF, Log Explorer, and developer docs. Token aliases
(default, kody, pages) pick the right secret and — when known — the right
Cloudflare account id, so agents do not hardcode credentials.
What it does
- Publish a static site to Cloudflare Pages in one call (
publish-static) - Call Cloudflare API v4 for zones, Workers, D1, R2, KV, Pages, and related
resources (
api-v4, withform/rawBodywhen JSON is not enough) - Auto-paginate list endpoints (
api-v4-list; Pages projects max out atper_page=10) - Discover which token alias and account id to use (
accounts,verify) - Summarize zone HTTP traffic; search Log Explorer; preview or apply WAF rules
- Fetch allowlisted Cloudflare developer documentation
- PUT binary objects into R2 (
r2-put-object)
Publishing a static site
publish-static is the general path for public HTML/CSS/JS hosting. It runs
Cloudflare Pages Direct Upload (the same flow as wrangler pages deploy):
- Resolve the Cloudflare account id (from the alias, or
accountId). - Get or optionally create the Pages project (Direct Upload only — never Git).
- Scan text files for forbidden content (built-in credential patterns + your
scan.forbid) and refuse when something matches. - Fetch a short-lived upload JWT, upload only missing files, and upsert hashes.
- Create a multipart deployment (
manifest+_headers/_redirects). - Wait until the deployment is live (opt out with
wait: false).
Pass the site as a files map (text or base64) and/or a public sourceUrl to a
.zip / .tar / .tar.gz. Prefer the pages account alias for Kent's
personal (KCD) Pages projects.
Custom domains and Cloudflare Access are out of scope for this helper: the
Pages token usually cannot edit DNS. Point DNS at the returned *.pages.dev
hostname yourself (or with a token that has Zone DNS edit). Deployment list /
rollback / prune and project delete are also deferred.
Prerequisites / setup
Three saved Cloudflare API token secrets (user scope), one per account alias:
| Account | Secret | Account id | Use when |
|---|---|---|---|
default | cloudflareApiToken | (none — spans accounts) | Routine API, analytics, logs, and WAF on accounts the primary token covers |
kody | cloudflareApiTokenKodyAccount | Kody production (baked in) | Kody Cloudflare account resources when the default token is unauthorized |
pages | cloudflarePagesApiToken | KCD / personal (baked in) | Cloudflare Pages Direct Upload and Pages project management |
- Save each token you need in Kody (never paste values in chat).
- Approve host
api.cloudflare.comfor each secret you use. - Grant firewall/ruleset edit permission only if you will call
rulesetswithapply: true. - Agents: see
AGENTS.mdfor import paths, dry-run snippets, and account-id discovery notes.
Authenticated exports accept optional account (default 'default'). For a
token outside the table, pass apiTokenSecret with the Kody secret name
(never a raw token). Do not pass both account and apiTokenSecret.
Finding the Cloudflare account id
accounts()returns each alias's knownaccountId(pages→ KCD,kody→ Kody;default→nullbecause that token covers multiple accounts).verify({ account })returnsaccountIdwhen it is unambiguous, plusaccessibleAccountsfromGET /accounts.- The
pagestoken cannot list accounts (GET /accountsis empty even when valid) — that is why its account id is baked into the alias metadata. - Otherwise copy the id from the Cloudflare dashboard URL
(
dash.cloudflare.com/<accountId>/…) and passaccountId.
Verifying tokens
Cloudflare has two verify endpoints. /user/tokens/verify alone often returns
401 Invalid API Token for a valid account-scoped token. Prefer this
package's verify export (tries user, then account when an account id is
known). After verify succeeds: 403 = lacks permission; 400/404 on a
mutating call against a bad/missing target = authorized for that operation.
Done when
- Needed token secrets are saved and
api.cloudflare.comis approved verifyfor the intended account returnsok: true(and anaccountIdwhen you need one)publish-staticwithdryRun: trueshows the plan; a real run returnslive: trueand a*.pages.devURL- Rulesets stay dry-run until an explicit
apply: trueafter review r2-put-objectwithconfirm: truereturnsok: truefor a test object