← Public packages
@kentcdodds/cloudflare
Cloudflare helpers: API v4, static site publishing to Pages, analytics, WAF rules, logs, and docs.
src/index.ts
138 lines · 5.2 KB · TypeScript/**
* Return Cloudflare package discovery metadata: exports, secrets, and usage notes.
*/
export default async function describeCloudflareToolkit() {
return {
packageId: 'cloudflare',
exports: [
'overview',
'accounts',
'api-v4',
'api-v4-list',
'analytics',
'docs',
'observability-logs',
'publish-static',
'rulesets',
'r2-put-object',
'verify',
],
helpers: [
{
export: 'accounts',
purpose:
'List Cloudflare API token aliases (default, kody, pages) with secret name, known accountId, and what each can/cannot do.',
mutating: false,
requiredSecrets: [],
},
{
export: 'verify',
purpose:
'Verify a Cloudflare API token using the correct endpoint for user-scoped vs account-scoped tokens, and return the accountId to use when unambiguous. Never treat /user/tokens/verify 401 alone as “token invalid.”',
mutating: false,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'api-v4',
purpose:
'Call Cloudflare API v4 endpoints under /client/v4/ with JSON, multipart form, or raw body, using an optional account alias or apiTokenSecret.',
mutating: true,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'api-v4-list',
purpose:
'Auto-paginate Cloudflare API v4 list endpoints (page or cursor). Pages project lists reject per_page above 10 — omit perPage for the endpoint default.',
mutating: false,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'publish-static',
purpose:
'Publish a static site to Cloudflare Pages (Direct Upload): create-if-missing, upload JWT refresh, scan for forbidden content, wait until live.',
mutating: true,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'analytics',
purpose:
'Query Cloudflare GraphQL analytics for zone traffic summaries, request paths, statuses, user agents, and outage forensics.',
mutating: false,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'docs',
purpose: 'Fetch allowlisted Cloudflare developer docs pages as markdown-oriented text.',
mutating: false,
requiredSecrets: [],
},
{
export: 'observability-logs',
purpose:
'Search Cloudflare Log Explorer datasets with structured filters or custom SQL, with an analytics fallback for missing entitlement.',
mutating: false,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'r2-put-object',
purpose:
'PUT binary objects into an R2 bucket (sourceUrl preferred for large files; bytesBase64 for small). Use instead of api-v4 for R2 file uploads from a URL.',
mutating: true,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
{
export: 'rulesets',
purpose:
'Preview or apply Cloudflare Rulesets/WAF custom rules, including cheap bogus-route blocks before traffic reaches origin.',
mutating: true,
requiredSecrets: [
'cloudflareApiToken',
'cloudflareApiTokenKodyAccount',
'cloudflarePagesApiToken',
],
},
],
notes: [
'Authenticate with account: "default" | "kody" | "pages" (default token: cloudflareApiToken), or apiTokenSecret for an unlisted secret name.',
'Never pass a raw API token string; always reference a Kody secret by alias or name.',
'Approve api.cloudflare.com for each Cloudflare token secret before using authenticated exports.',
'Token verification: use export verify (or /accounts/{account_id}/tokens/verify for account-scoped tokens). /user/tokens/verify often 401s for valid account tokens — that is not proof the secret is broken.',
'Permission checks after verify: 403 means lacks permission; 400/404 on a mutating call against a bad/missing target means the token is authorized for that operation.',
'Account ids: call accounts() for alias metadata (pages → KCD, kody → Kody). default spans multiple accounts — verify().accessibleAccounts lists them, or pass accountId.',
'Publish public static sites with publish-static (Pages Direct Upload). Workers Assets and public R2 hosting are not implemented yet.',
'api-v4 accepts body (JSON), form (multipart), or rawBody. Prefer publish-static for Pages deploys and r2-put-object for R2 PUTs from a URL.',
'Use analytics for zone HTTP request aggregates, especially when Log Explorer SQL is unavailable or returns missing entitlement.',
'Use rulesets in dry-run mode first to preview WAF/custom-rule changes; pass apply: true only after review.',
'Use observability-logs for Workers trace events, HTTP request forensics, Access requests, Ray IDs, errors, and slow-request investigations.',
'Use docs for current Cloudflare documentation under allowlisted product prefixes.',
],
}
}