Expand description
Cloudflare management API client — accounts, tunnels, R2 buckets, DNS.
Shared by the desktop Tauri commands, the CLI, and the reconciler.
Callers resolve the API token themselves (keychain, env, vault) and pass
it to CloudflareClient::new; this module never reads credentials.
Two distinct API surfaces:
- Management API (this module) — accounts, R2-bucket CRUD, tunnels, DNS, cache purge.
- R2 object publish — S3 SigV4, lives in
reconciler::r2_publishand reuses the existings3_signhelper. Not part of this module.
@yah:ticket(R320-F12, “yah cloud: mint scoped Cloudflare API token from a policy template (one-command onboarding for a new CF account)”)
@yah:assignee(agent:claude)
@yah:at(2026-05-26T14:57:46Z)
@yah:status(review)
@yah:parent(R320)
@arch:see(.yah/docs/working/W074-cloudflare-infra-provider.md)
@yah:next(“Resolve permission-group UUIDs at runtime from GET /accounts/{id}/tokens/permission_groups — CF references groups by ID not name; the policy template stores names and resolves to IDs at create time”)
@yah:next(“Build the minimal mesofact-static policy: account-scoped block (Account Settings:Read + Workers R2 Storage:Edit) + zone-scoped block (Zone:Read + Transform Rules:Edit + Cache Purge). Keep scope blocks separate — mixing account- and zone-scoped groups in one block fails token-create validation”)
@yah:next(“POST /accounts/{id}/tokens to create an ACCOUNT-OWNED token (DECIDED by user: survives the creating user, correct for a shared tool credential). Print the secret once and offer to store it in the cloudflare-api-token keystore slot”)
@yah:next(“Expose as ‘yah cloud cf token create –account
@yah:ticket(R324-F5, “Tunnel connection status + uptime in the Tunnels table”)
@yah:assignee(agent:claude)
@yah:at(2026-05-26T15:33:48Z)
@yah:status(review)
@yah:phase(P2)
@yah:parent(R324)
@yah:handoff(“Tunnel connection state fully wired end-to-end. Rust: TunnelConnState enum (Active/Inactive/Degraded/Unknown) added to cloud crate; CfTunnel wire struct extended with status + conns_active_at; TunnelMeta private struct carries enriched data; list_tunnels_meta() fetches status in one pass; TunnelDriftRow gained conn_state + conn_since (RFC3339 optional); tunnel_dns_drift() refactored to walk accounts→tunnels_meta→configs in a single list_accounts pass instead of calling tunnel_dns_records() separately (avoids duplicate API round-trip). Re-exported TunnelConnState through provider/mod.rs + cloud/src/lib.rs + desktop cloudflare.rs. TS: TunnelConnState type + connState/connSince on TunnelDriftRow in types.ts. UI: DriftPill now shows ‘connected ·
@yah:ticket(R324-F6, “R2 bucket size + object count + region in Accounts section”) @yah:assignee(agent:claude) @yah:at(2026-05-26T15:33:49Z) @yah:status(review) @yah:phase(P2) @yah:parent(R324) @yah:next(“Extend R2BucketInfo + list_r2_buckets with size/object-count/region; design AccountBlock shows ‘412 MB · 142 obj’. Needs extra R2 (or S3 list) calls per bucket.”) @yah:next(“Render the new fields in CloudflarePanel AccountBlock bucket rows.”) @yah:handoff(“Added location + creation_date to R2BucketInfo (Rust struct + TS interface). Both fields come from the existing GET /accounts/{id}/r2/buckets list call — no extra round-trips. fmtR2Location() maps CF location codes (WEUR/EEUR/WNAM/ENAM/APAC) to short labels. AccountBlock bucket cards now show the region badge on the right when present. Note: bucket size + object count are not available from the CF management API without per-bucket S3 calls (paginated ListObjectsV2 + S3 credentials); deferred to a future ticket.”) @yah:verify(“cargo check -p cloud -p desktop — clean (R2BucketInfo extended, deserialized from BucketEntry, re-exported unchanged)”) @yah:verify(“cd packages/yah/ui && bun run typecheck — no new errors in infra/ or env/”)
@yah:ticket(R419-F1, “Extend deploy_worker_script for r2_bucket bindings”)
@yah:assignee(agent:claude)
@yah:at(2026-06-03T08:02:38Z)
@yah:status(review)
@yah:parent(R419)
@yah:handoff(“Widened deploy_worker_script + build_worker_multipart to typed bindings. New pub enum WorkerBinding<’a> { PlainText { name, text }, R2Bucket { name, bucket_name } } encodes both shapes; multipart metadata.bindings now emits the matching CF wire JSON. Single existing caller (mesofact_static.rs:505) maps its (String,String) plain_text vec into WorkerBinding::PlainText refs — runtime behavior unchanged. F2’s CloudflareWorkerReconciler now has the surface it needs: pass [WorkerBinding::R2Bucket { name: binding_name_from_workload_toml, bucket_name: from_mirror_providers_cache }, …].”)
@yah:verify(“cargo check -p cloud –lib — clean”)
@yah:verify(“cargo test -p cloud –lib provider::cloudflare — 12 passed, incl. multipart_includes_r2_bucket_binding_metadata + multipart_mixes_plain_text_and_r2_bindings”)
@yah:next(“F2 pickup: bind via WorkerBinding::R2Bucket { name: <workload.toml [[bindings]].name>, bucket_name:
Structs§
- CfAccount
Info - A Cloudflare account the API token can access.
- Cloudflare
Client - Cloudflare management API client.
- Create
R2Bucket Result - Result of creating a Cloudflare R2 bucket.
- Create
Token Result - Result of minting an account-owned API token.
valueis the secret and is returned by Cloudflare exactly once — store it immediately. - Create
Tunnel Result - Result of creating a Cloudflare Named Tunnel.
- R2Bucket
Info - R2 bucket information from the list endpoint.
- R2Custom
Domain - One R2 custom-domain binding from
GET /accounts/{id}/r2/buckets/{bucket}/domains/custom. - Token
Grant - One permission to bake into a minted token: a Cloudflare permission-group display name, the scope it applies at, and a validated fallback ID.
- Tunnel
DnsRecord - One CNAME record a user needs to create in their external DNS registrar to route a hostname through a Cloudflare Tunnel.
- Tunnel
Drift Row - One row of the tunnel DNS-drift report: a tunnel ingress hostname paired with whether live Cloudflare DNS routes it to the tunnel, plus the live connector connection state.
- Worker
Deploy Result - Result of deploying a Cloudflare Worker script.
Enums§
- Grant
Scope - Resource scope a permission group applies at when building a token policy.
- Tunnel
Conn State - Live connection state of a Cloudflare Tunnel connector.
- Tunnel
Drift State - Drift verdict for one tunnel ingress hostname: does live Cloudflare DNS route it to the tunnel’s CNAME target?
- Worker
Binding - One binding to inject into a Worker’s
envat deploy time.
Constants§
- MESOFACT_
STATIC_ GRANTS - Minimal permission set for a mesofact-static publish token: see the account, list/create R2 buckets, deploy Worker scripts, resolve the zone, manage Worker routes + the index-rewrite Transform Rule, and purge the CDN cache.