Skip to main content

CloudflareClient

Struct CloudflareClient 

Source
pub struct CloudflareClient { /* private fields */ }
Expand description

Cloudflare management API client.

Construct with CloudflareClient::new passing a pre-resolved API token. The token scope required per method is noted on each method.

Implementations§

Source§

impl CloudflareClient

Source

pub fn new(token: String) -> Self

Create a client for the given API token.

Source

pub async fn list_accounts(&self) -> Result<Vec<CfAccountInfo>>

List accounts the token can access. Requires: Account: Read.

Source

pub async fn list_tunnels( &self, account_id: &str, ) -> Result<Vec<(String, String)>>

List non-deleted Cloudflare Tunnels in account_id as (id, name) pairs. Requires: Cloudflare Tunnel: Read.

Source

pub async fn tunnel_dns_records(&self) -> Result<Vec<TunnelDnsRecord>>

Collect CNAME records for all tunnels across all accessible accounts.

Walks accounts → tunnels → ingress configurations. Returns an empty vec when the token has no tunnels or no configured ingress hostnames.

Source

pub async fn tunnel_dns_drift(&self) -> Result<Vec<TunnelDriftRow>>

Compute DNS drift for every tunnel ingress hostname, enriched with live connector connection state.

The declared side is the tunnel ingress config; the live side is the zone’s DNS records. Each ingress hostname is classified: TunnelDriftState::Synced when a record points at the tunnel’s CNAME target, Missing when none exists, Mismatch when one points elsewhere.

Connection state (conn_state / conn_since) comes from the status and conns_active_at fields on the tunnel list response — fetched in the same pass as the ingress configs to avoid an extra list_accounts round-trip.

Degrades gracefully — a hostname whose zone can’t be resolved or read is reported ZoneUnknown rather than failing the whole report. Returns an empty vec when the token has no tunnels or no ingress hostnames.

Requires: Cloudflare Tunnel: Read, Zone: Read, DNS: Read.

Source

pub async fn list_zones(&self) -> Result<Vec<(String, String)>>

List zones the token can read, as (zone_id, zone_name) pairs. Requires: Zone: Read.

Source

pub async fn create_tunnel( &self, account_id: &str, name: &str, ) -> Result<CreateTunnelResult>

Create a new Named Tunnel under account_id and return the connector token. Requires: Cloudflare Tunnel: Edit.

Source

pub async fn tunnel_configuration( &self, account_id: &str, tunnel_id: &str, ) -> Result<Value>

Read a tunnel’s remotely-managed configuration body as raw JSON (R594-F11).

Returns the result.config object — the thing a PUT round-trips — or an empty object when the tunnel has never been configured. Deliberately untyped: the ingress list is the only key this crate owns, and every sibling (warp-routing, originRequest, …) must survive a read-modify-write untouched.

Requires: Cloudflare Tunnel: Read.

Source

pub async fn put_tunnel_configuration( &self, account_id: &str, tunnel_id: &str, config: &Value, ) -> Result<()>

Replace a tunnel’s remotely-managed configuration (R594-F11).

config is the whole config body, not a patch — Cloudflare replaces it wholesale, which is why callers must GET-merge-PUT rather than PUT a freshly-built list. See reconciler::ingress::ensure_tunnel_ingress.

Requires: Cloudflare Tunnel: Edit.

Source

pub async fn create_r2_bucket( &self, account_id: &str, bucket_name: &str, ) -> Result<CreateR2BucketResult>

Create a new R2 bucket under account_id. Requires: Account: Cloudflare R2: Edit.

Source

pub async fn zone_id_for_name(&self, zone_name: &str) -> Result<String>

Resolve a zone name (e.g. "yah.dev") to its Cloudflare zone ID. Requires: Zone: Read.

Source

pub async fn purge_cache_tags( &self, zone_id: &str, tags: &[String], ) -> Result<()>

Purge content by cache tags from a zone.

Cache tags must be applied to responses via the Cache-Tag header or Cloudflare page rules. Returns Ok(()) when all tags are queued for purge. Requires: Zone: Cache Purge.

Source

pub async fn upsert_index_rewrite(&self, zone_id: &str) -> Result<()>

Upsert the Transform Rule that rewrites GET / → /index.html on the zone, identified by the stable description tag "yah:static-index".

Idempotent: fetches the existing http_request_transform entrypoint, drops any prior "yah:static-index" rule, appends the current one, and PUTs the merged list back. Treats a missing entrypoint (no rules yet) as an empty list.

Requires: Zone: Transform Rules: Edit.

Source

pub async fn deploy_worker_script( &self, account_id: &str, script_name: &str, script_js: &str, bindings: &[WorkerBinding<'_>], ) -> Result<WorkerDeployResult>

Deploy an ES-module Worker script with typed bindings for runtime config.

Each entry in bindings becomes one metadata.bindings[…] declaration in the upload payload — see WorkerBinding for the supported variants (plain_text config, R2 bucket references).

Uses a manual multipart/form-data upload (CF Workers API requires multipart when metadata/bindings are attached). Idempotent: re-uploading the same script is safe but costs one CF API round-trip — callers should hash-guard this.

Requires: Workers Scripts: Edit (account-scoped).

Source

pub async fn upsert_worker_route( &self, zone_id: &str, pattern: &str, script_name: &str, ) -> Result<()>

Upsert a Worker route for pattern on zone_id, pointing at script_name.

Idempotent: fetches existing routes, skips PUT/POST when the pattern already points at the right script, updates an existing pattern pointing elsewhere, or creates a new route entry.

Requires: Zone: Workers Routes: Edit (zone-scoped).

Source

pub async fn upsert_worker_custom_domain( &self, account_id: &str, zone_id: &str, hostname: &str, script_name: &str, ) -> Result<()>

Idempotently attach hostname (e.g. cr.yah.dev) as a Workers Custom Domain on script_name. Custom Domains route every request for the hostname into the Worker — distinct from a Worker Route, which only matches a URL pattern within an already-proxied zone.

Walks the existing Custom Domains list first; if hostname is already bound to script_name on zone_id, returns Ok without an extra PUT. Otherwise PUTs /accounts/{account_id}/workers/domains, which CF treats as an upsert keyed on (hostname, environment).

Requires: Workers Scripts: Edit (account-scoped).

Source

pub async fn delete_r2_bucket( &self, account_id: &str, bucket_name: &str, ) -> Result<()>

Delete an R2 bucket under account_id.

Cloudflare’s management API handles non-empty buckets — objects do not need to be drained first. Returns Ok(()) on success, Err if the API returns a failure (including “bucket not found” — callers that need idempotency should probe Self::list_r2_buckets first).

Requires: Account: Cloudflare R2: Edit.

Source

pub async fn upsert_dns_record( &self, zone_id: &str, name: &str, record_type: &str, content: &str, ttl: u32, proxied: bool, ) -> Result<String>

Idempotently upsert a DNS record in zone_id. Fetches existing records with the same name and type: updates the first match if found, creates a new record otherwise. Returns the provider-issued record ID.

Requires: DNS: Edit (zone-scoped).

Source

pub async fn delete_dns_records( &self, zone_id: &str, name: &str, record_type: Option<&str>, ) -> Result<u32>

Delete all DNS records in zone_id whose name matches name (and optionally record_type). Returns the count of records deleted. A count of 0 is not an error — the records may already have been absent.

Requires: DNS: Edit (zone-scoped).

Source

pub async fn list_r2_buckets( &self, account_id: &str, ) -> Result<Vec<R2BucketInfo>>

List R2 buckets in account_id. Requires: Account: Cloudflare R2: Read.

Unlike /accounts and /zones, the R2 list endpoint nests the array under result.buckets rather than returning result as a bare array, so it needs CfSingle<R2ListResult> and not CfPage<BucketEntry>.

Source

pub async fn list_r2_custom_domains( &self, account_id: &str, bucket_name: &str, ) -> Result<Vec<R2CustomDomain>>

List R2 custom-domain bindings on bucket_name.

Requires: Workers R2 Storage: Read (or Write, which implies Read). The response nests the array under result.domains, mirroring list_r2_buckets’s result.buckets shape.

Source

pub async fn add_r2_custom_domain( &self, account_id: &str, bucket_name: &str, domain: &str, zone_id: &str, ) -> Result<()>

Bind a custom domain to an R2 bucket.

zone_id names the zone that owns domain (resolve via Self::zone_id_for_name). CF requires it so the CNAME write into that zone is authorized — even though the caller is the bucket-side API. CF creates the CNAME automatically; no separate DNS-side call. Requires: Workers R2 Storage: Edit (account-scoped).

enabled: true activates the binding immediately. CF still has to validate ownership + provision TLS in the background — the binding returns success the moment the record is queued, not when the hostname is fully resolvable. First-time DNS propagation is on the order of seconds to a minute.

Source

pub async fn list_permission_group_ids( &self, account_id: &str, ) -> Result<BTreeMap<String, String>>

Fetch the account’s permission-group catalog as a name → id map, used to resolve TokenGrant names before minting a token. Requires the calling token to carry API Tokens: Read (implied by Write).

Source

pub async fn create_account_token( &self, account_id: &str, zone_id: &str, token_name: &str, grants: &[TokenGrant], ) -> Result<CreateTokenResult>

Mint an account-owned API token under account_id from grants scoped to account_id + zone_id.

Resolves each grant’s permission-group name against the live catalog (falling back to its baked-in ID), groups the IDs into account- and zone-scoped policy blocks, and POSTs to /accounts/{id}/tokens. Requires the calling token to carry API Tokens: Write — but the minted token is bounded by the account’s access, not the calling token’s, so the caller may hold only API Tokens: Write.

The returned CreateTokenResult::value is the secret — Cloudflare reveals it only here.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Send + Sync>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Fruit for T
where T: Send + Downcast,

Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more