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
impl CloudflareClient
Sourcepub async fn list_accounts(&self) -> Result<Vec<CfAccountInfo>>
pub async fn list_accounts(&self) -> Result<Vec<CfAccountInfo>>
List accounts the token can access.
Requires: Account: Read.
Sourcepub async fn list_tunnels(
&self,
account_id: &str,
) -> Result<Vec<(String, String)>>
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.
Sourcepub async fn tunnel_dns_records(&self) -> Result<Vec<TunnelDnsRecord>>
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.
Sourcepub async fn tunnel_dns_drift(&self) -> Result<Vec<TunnelDriftRow>>
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.
Sourcepub async fn list_zones(&self) -> Result<Vec<(String, String)>>
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.
Sourcepub async fn create_tunnel(
&self,
account_id: &str,
name: &str,
) -> Result<CreateTunnelResult>
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.
Sourcepub async fn tunnel_configuration(
&self,
account_id: &str,
tunnel_id: &str,
) -> Result<Value>
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.
Sourcepub async fn put_tunnel_configuration(
&self,
account_id: &str,
tunnel_id: &str,
config: &Value,
) -> Result<()>
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.
Sourcepub async fn create_r2_bucket(
&self,
account_id: &str,
bucket_name: &str,
) -> Result<CreateR2BucketResult>
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.
Sourcepub async fn zone_id_for_name(&self, zone_name: &str) -> Result<String>
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.
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.
Sourcepub async fn upsert_index_rewrite(&self, zone_id: &str) -> Result<()>
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.
Sourcepub async fn deploy_worker_script(
&self,
account_id: &str,
script_name: &str,
script_js: &str,
bindings: &[WorkerBinding<'_>],
) -> Result<WorkerDeployResult>
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).
Sourcepub async fn upsert_worker_route(
&self,
zone_id: &str,
pattern: &str,
script_name: &str,
) -> Result<()>
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).
Sourcepub async fn upsert_worker_custom_domain(
&self,
account_id: &str,
zone_id: &str,
hostname: &str,
script_name: &str,
) -> Result<()>
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).
Sourcepub async fn delete_r2_bucket(
&self,
account_id: &str,
bucket_name: &str,
) -> Result<()>
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.
Sourcepub async fn upsert_dns_record(
&self,
zone_id: &str,
name: &str,
record_type: &str,
content: &str,
ttl: u32,
proxied: bool,
) -> Result<String>
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).
Sourcepub async fn upsert_dns_record_matching(
&self,
zone_id: &str,
name: &str,
record_type: &str,
content: &str,
ttl: u32,
proxied: bool,
match_content: bool,
) -> Result<String>
pub async fn upsert_dns_record_matching( &self, zone_id: &str, name: &str, record_type: &str, content: &str, ttl: u32, proxied: bool, match_content: bool, ) -> Result<String>
upsert_dns_record with control over what
counts as “the existing record” — R859-F1.
match_content = false reproduces the original behaviour: the first
record sharing name + record_type is updated in place. That is right
for a single-valued name (one CNAME at cdn.yah.dev) and wrong for a
multi-valued RRset: adding the second A record of a round-robin apex
would rewrite the first one’s content, silently halving the origin set
to one box.
match_content = true keys the lookup on (name, type, content), so
the call means “ensure exactly this record exists” — a no-op update when
it already does, a create when it does not, and never a mutation of a
sibling record at the same name.
Sourcepub async fn list_dns_records(
&self,
zone_id: &str,
name: Option<&str>,
record_type: Option<&str>,
) -> Result<Vec<DnsRecordDetail>>
pub async fn list_dns_records( &self, zone_id: &str, name: Option<&str>, record_type: Option<&str>, ) -> Result<Vec<DnsRecordDetail>>
Read the DNS records in zone_id, optionally narrowed to one name
and/or one record_type — R859-F1, the read half the dns.* catalog
was missing.
Unlike dns_records_named (drift-detection
only, name + content) this returns the record id, type, ttl and
proxy flag, which is what a reconciler needs to decide what to change.
Requires: DNS: Read (zone-scoped).
Sourcepub async fn delete_dns_records(
&self,
zone_id: &str,
name: &str,
record_type: Option<&str>,
) -> Result<u32>
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).
Sourcepub async fn delete_dns_records_matching(
&self,
zone_id: &str,
name: &str,
record_type: Option<&str>,
content: Option<&str>,
) -> Result<u32>
pub async fn delete_dns_records_matching( &self, zone_id: &str, name: &str, record_type: Option<&str>, content: Option<&str>, ) -> Result<u32>
delete_dns_records narrowed to records
carrying one exact value — R859-F1.
A round-robin apex holds several A records under one name, so
“delete the A records at yah.dev” is not a way to withdraw one
origin: it takes the live ones with it. content = Some(ip) deletes
only the withdrawn member.
Requires: DNS: Edit (zone-scoped).
Sourcepub async fn list_r2_buckets(
&self,
account_id: &str,
) -> Result<Vec<R2BucketInfo>>
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>.
Sourcepub async fn list_r2_custom_domains(
&self,
account_id: &str,
bucket_name: &str,
) -> Result<Vec<R2CustomDomain>>
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.
Sourcepub async fn add_r2_custom_domain(
&self,
account_id: &str,
bucket_name: &str,
domain: &str,
zone_id: &str,
) -> Result<()>
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.
Sourcepub async fn list_permission_group_ids(
&self,
account_id: &str,
) -> Result<BTreeMap<String, String>>
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).
Sourcepub async fn create_account_token(
&self,
account_id: &str,
zone_id: &str,
token_name: &str,
grants: &[TokenGrant],
) -> Result<CreateTokenResult>
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§
impl !RefUnwindSafe for CloudflareClient
impl !UnwindSafe for CloudflareClient
impl Freeze for CloudflareClient
impl Send for CloudflareClient
impl Sync for CloudflareClient
impl Unpin for CloudflareClient
impl UnsafeUnpin for CloudflareClient
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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 Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<T> ErasedDestructor for Twhere
T: 'static,
impl<T> Fruit for T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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