# @apiclient.xyz/cloudflare An elegant, class-based TypeScript client for the Cloudflare API that makes managing your Cloudflare resources simple and type-safe. [![npm version](https://badge.fury.io/js/%40apiclient.xyz%2Fcloudflare.svg)](https://www.npmjs.com/package/@apiclient.xyz/cloudflare) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) ## Features - **Comprehensive coverage** of the Cloudflare API including zones, DNS records, and Workers - **Clean manager-based architecture** with intuitive methods for all Cloudflare operations - **Strong TypeScript typing** for excellent IDE autocompletion and type safety - **Fully integrated with the official Cloudflare client** using modern async iterators - **IConvenientDnsProvider compatibility** for seamless integration with third-party modules - **Promise-based API** for easy async/await usage - **ESM compatible** for modern JavaScript projects - **Comprehensive error handling** for robust applications ## Installation ```bash # Using npm npm install @apiclient.xyz/cloudflare # Using yarn yarn add @apiclient.xyz/cloudflare # Using pnpm pnpm add @apiclient.xyz/cloudflare ``` ## Quick Start ```typescript import * as cflare from '@apiclient.xyz/cloudflare'; // Initialize with your API token const cfAccount = new cflare.CloudflareAccount('your-cloudflare-api-token'); // Use the clean manager-based API await cfAccount.recordManager.createRecord('subdomain.example.com', 'A', '192.0.2.1', 3600); await cfAccount.zoneManager.purgeZone('example.com'); // Or use the IConvenientDnsProvider interface for third-party modules const dnsProvider = cfAccount.getConvenientDnsProvider(); await dnsProvider.createRecord('subdomain.example.com', 'A', '192.0.2.1'); ``` ## Usage Guide ### Account Management Initialize your Cloudflare account with your API token: ```typescript import * as cflare from '@apiclient.xyz/cloudflare'; const cfAccount = new cflare.CloudflareAccount('your-cloudflare-api-token'); // If you have multiple accounts, you can preselect one await cfAccount.preselectAccountByName('My Company Account'); // List all accounts you have access to const myAccounts = await cfAccount.listAccounts(); ``` ### Zone Management Zones represent your domains in Cloudflare. ```typescript // List all zones in your account const allZones = await cfAccount.zoneManager.listZones(); // Get a specific zone by domain name const myZone = await cfAccount.zoneManager.getZoneByName('example.com'); // Get zone ID directly const zoneId = await cfAccount.zoneManager.getZoneId('example.com'); // Create a new zone const newZone = await cfAccount.zoneManager.createZone('newdomain.com'); // Purge cache for an entire zone await cfAccount.zoneManager.purgeZone('example.com'); // Or using the zone object await myZone.purgeCache(); // Purge specific URLs await myZone.purgeUrls(['https://example.com/css/styles.css', 'https://example.com/js/app.js']); // Enable/disable development mode await myZone.enableDevelopmentMode(); // Enables dev mode for 3 hours await myZone.disableDevelopmentMode(); // Check zone status const isActive = await myZone.isActive(); const usingCfNameservers = await myZone.isUsingCloudflareNameservers(); ``` ### DNS Record Management Manage DNS records for your domains with ease using the RecordManager. ```typescript // List all DNS records for a domain const allRecords = await cfAccount.recordManager.listRecords('example.com'); // Create a new DNS record await cfAccount.recordManager.createRecord('api.example.com', 'A', '192.0.2.1', 3600); // Create a CNAME record await cfAccount.recordManager.createRecord('www.example.com', 'CNAME', 'example.com', 3600); // Get a specific DNS record const record = await cfAccount.recordManager.getRecord('api.example.com', 'A'); // Update a DNS record (automatically creates it if it doesn't exist) await cfAccount.recordManager.updateRecord('api.example.com', 'A', '192.0.2.2', 3600); // Delete a specific DNS record await cfAccount.recordManager.deleteRecord('api.example.com', 'A'); // Clean (remove) all records of a specific type for a domain await cfAccount.recordManager.cleanRecords('example.com', 'TXT'); // For third-party modules requiring IConvenientDnsProvider interface const dnsProvider = cfAccount.getConvenientDnsProvider(); await dnsProvider.createRecord('api.example.com', 'A', '192.0.2.1'); // Support for ACME DNS challenges (for certificate issuance) await dnsProvider.acmeSetDnsChallenge({ hostName: '_acme-challenge.example.com', challenge: 'token-validation-string', }); await dnsProvider.acmeRemoveDnsChallenge({ hostName: '_acme-challenge.example.com', challenge: 'token-validation-string', }); ``` ### Workers Management Create and manage Cloudflare Workers with full TypeScript support. ```typescript // Create or update a worker const workerScript = ` addEventListener('fetch', event => { event.respondWith(new Response('Hello from Cloudflare Workers!')) })`; const worker = await cfAccount.workerManager.createWorker('my-worker', workerScript); // List all workers const allWorkers = await cfAccount.workerManager.listWorkers(); // Get an existing worker const existingWorker = await cfAccount.workerManager.getWorker('my-worker'); // Set routes for a worker await worker.setRoutes([ { zoneName: 'example.com', pattern: 'https://api.example.com/*', }, { zoneName: 'example.com', pattern: 'https://app.example.com/api/*', }, ]); // List all routes for a worker const routes = await worker.listRoutes(); // Update a worker's script await worker.updateScript(` addEventListener('fetch', event => { event.respondWith(new Response('Updated worker content!')) })`); // Delete a worker await worker.delete(); // Or using the worker manager await cfAccount.workerManager.deleteWorker('my-worker'); ``` ### Complete Example Here's a complete example showing how to manage multiple aspects of your Cloudflare account: ```typescript import * as cflare from '@apiclient.xyz/cloudflare'; async function manageCloudflare() { try { // Initialize with API token from environment variable const cfAccount = new cflare.CloudflareAccount(process.env.CLOUDFLARE_API_TOKEN); // Preselect account if needed await cfAccount.preselectAccountByName('My Company'); // Get zone and check status const myZone = await cfAccount.zoneManager.getZoneByName('example.com'); console.log(`Zone active: ${await myZone.isActive()}`); console.log(`Using CF nameservers: ${await myZone.isUsingCloudflareNameservers()}`); // Configure DNS using RecordManager await cfAccount.recordManager.createRecord('api.example.com', 'A', '192.0.2.1'); await cfAccount.recordManager.createRecord('www.example.com', 'CNAME', 'example.com'); // Create a worker and set up routes const workerCode = ` addEventListener('fetch', event => { const url = new URL(event.request.url); if (url.pathname.startsWith('/api/')) { event.respondWith(new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } })); } else { event.respondWith(fetch(event.request)); } })`; const worker = await cfAccount.workerManager.createWorker('api-handler', workerCode); await worker.setRoutes([{ zoneName: 'example.com', pattern: 'https://api.example.com/*' }]); // Purge cache for specific URLs await myZone.purgeUrls(['https://example.com/css/styles.css']); console.log('Configuration completed successfully'); } catch (error) { console.error('Error managing Cloudflare:', error); } } manageCloudflare(); ``` ## API Documentation ### CloudflareAccount The main entry point for all Cloudflare operations. ```typescript class CloudflareAccount { constructor(apiToken: string); // Account management async listAccounts(): Promise>; async preselectAccountByName(accountName: string): Promise; // Managers - Clean, logical API readonly zoneManager: ZoneManager; readonly workerManager: WorkerManager; readonly recordManager: RecordManager; // Get IConvenientDnsProvider adapter for third-party modules getConvenientDnsProvider(): ConvenientDnsProvider; // Official Cloudflare client readonly apiAccount: cloudflare.Cloudflare; // ⚠️ Deprecated: convenience namespace (kept for backward compatibility) // Use the managers instead: recordManager, zoneManager, workerManager readonly convenience: { /* deprecated methods */ }; } ``` ### RecordManager Clean DNS record management (recommended over deprecated convenience methods). ```typescript class RecordManager { async listRecords(domainName: string): Promise; async getRecord(domainName: string, recordType: string): Promise; async createRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise; async updateRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise; async deleteRecord(domainName: string, recordType: string): Promise; async cleanRecords(domainName: string, recordType: string): Promise; } ``` ### ZoneManager ```typescript class ZoneManager { async listZones(zoneName?: string): Promise; async getZoneById(zoneId: string): Promise; async getZoneByName(zoneName: string): Promise; async getZoneId(domainName: string): Promise; async createZone(zoneName: string): Promise; async deleteZone(zoneId: string): Promise; async purgeZone(domainName: string): Promise; } ``` ### WorkerManager ```typescript class WorkerManager { async listWorkers(): Promise>; async getWorker(workerName: string): Promise; async createWorker(workerName: string, workerScript: string): Promise; async deleteWorker(workerName: string): Promise; } ``` ### ConvenientDnsProvider Adapter for third-party modules requiring `IConvenientDnsProvider` interface. ```typescript class ConvenientDnsProvider implements IConvenientDnsProvider { async createRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise; async updateRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise; async removeRecord(domainName: string, recordType: string): Promise; async getRecord(domainName: string, recordType: string): Promise; async listRecords(domainName: string): Promise; async cleanRecord(domainName: string, recordType: string): Promise; async isDomainSupported(domainName: string): Promise; async acmeSetDnsChallenge(dnsChallenge: IDnsChallenge): Promise; async acmeRemoveDnsChallenge(dnsChallenge: IDnsChallenge): Promise; } ``` ### CloudflareZone Represents a Cloudflare zone (domain). ```typescript class CloudflareZone { // Properties readonly id: string; readonly name: string; readonly status: string; readonly paused: boolean; readonly type: string; readonly nameServers: string[]; // Methods async purgeCache(): Promise; async purgeUrls(urls: string[]): Promise; async isActive(): Promise; async isUsingCloudflareNameservers(): Promise; async isDevelopmentModeActive(): Promise; async enableDevelopmentMode(): Promise; async disableDevelopmentMode(): Promise; } ``` ### CloudflareRecord Represents a DNS record. ```typescript class CloudflareRecord { // Properties readonly id: string; readonly type: string; readonly name: string; readonly content: string; readonly ttl: number; readonly proxied: boolean; // Methods async update(content: string, ttl?: number): Promise; async delete(): Promise; } ``` ### CloudflareWorker Represents a Cloudflare Worker. ```typescript class CloudflareWorker { // Properties readonly id: string; readonly script: string; readonly routes: IWorkerRoute[]; // Methods async listRoutes(): Promise; // Populates the routes property async setRoutes(routes: Array): Promise; async updateScript(scriptContent: string): Promise; async delete(): Promise; } interface IWorkerRouteDefinition { zoneName: string; pattern: string; } ``` ## Utility Functions The library includes helpful utility functions: ```typescript // Validate a domain name CloudflareUtils.isValidDomain('example.com'); // true // Extract zone name from a domain CloudflareUtils.getZoneName('subdomain.example.com'); // 'example.com' // Validate a record type CloudflareUtils.isValidRecordType('A'); // true // Format URL for cache purging CloudflareUtils.formatUrlForPurge('example.com/page'); // 'https://example.com/page' // Format TTL value CloudflareUtils.formatTtl(3600); // '1 hour' ``` ## What's New in 7.0.0 - **🎨 Clean Manager-Based Architecture**: New RecordManager, improved ZoneManager and WorkerManager with consistent naming - **🔌 IConvenientDnsProvider Compatibility**: New ConvenientDnsProvider adapter for seamless third-party module integration - **📝 Consistent Method Naming**: - `listZones()`, `listWorkers()`, `listRecords()` - consistent list* pattern - `deleteRecord()` instead of `removeRecord()` - clearer semantics - `listRoutes()` instead of `getRoutes()` - consistent with other list methods - **⚠️ Deprecated convenience Namespace**: Old methods still work but are deprecated - use managers instead - **✅ Backward Compatible**: All existing code continues to work with deprecation warnings ## Migration Guide (6.x → 7.0) ### DNS Record Operations ```typescript // Old (deprecated): await cfAccount.convenience.createRecord('example.com', 'A', '1.2.3.4'); await cfAccount.convenience.listRecords('example.com'); await cfAccount.convenience.removeRecord('example.com', 'A'); // New (recommended): await cfAccount.recordManager.createRecord('example.com', 'A', '1.2.3.4'); await cfAccount.recordManager.listRecords('example.com'); await cfAccount.recordManager.deleteRecord('example.com', 'A'); // For third-party modules: const dnsProvider = cfAccount.getConvenientDnsProvider(); await dnsProvider.createRecord('example.com', 'A', '1.2.3.4'); ``` ### Zone Operations ```typescript // Old (deprecated): await cfAccount.convenience.listZones(); await cfAccount.convenience.purgeZone('example.com'); // New (recommended): await cfAccount.zoneManager.listZones(); await cfAccount.zoneManager.purgeZone('example.com'); ``` ### Worker Operations ```typescript // Old: await cfAccount.workerManager.listWorkerScripts(); await worker.getRoutes(); // New: await cfAccount.workerManager.listWorkers(); await worker.listRoutes(); ``` ## Development & Testing To build the project: ```bash npm run build # or pnpm run build ``` To run tests: ```bash npm test # or pnpm run test ``` ## License MIT © [Lossless GmbH](https://lossless.gmbh)