feat(cloudflare): Release 7.0.0 — manager-based API, ConvenientDnsProvider, improved utils and worker/zone/record management
This commit is contained in:
11
changelog.md
11
changelog.md
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-11-18 - 7.1.0 - feat(cloudflare)
|
||||
Release 7.0.0 — manager-based API, ConvenientDnsProvider, improved utils and worker/zone/record management
|
||||
|
||||
- Introduce manager-based architecture: ZoneManager, RecordManager, WorkerManager for clearer, consistent API surface
|
||||
- Add ConvenientDnsProvider adapter implementing IConvenientDnsProvider for third-party integrations
|
||||
- New CloudflareUtils helpers (domain validation, API token check, record type validation, URL/TTL formatting, pagination)
|
||||
- Improved Worker support: create/update/delete scripts, route management, and robust listing with fallbacks
|
||||
- Zone and record operations enhanced (create/update/delete/purge) with type-safe wrappers and CloudflareZone/CloudflareRecord models
|
||||
- Deprecated old convenience namespace in favor of managers (kept for backward compatibility with migration guidance)
|
||||
- Full TypeScript exports and typings, updated package metadata for v7.0.0
|
||||
|
||||
## 2025-11-18 - 7.0.0 - BREAKING CHANGE(core)
|
||||
Introduce RecordManager and ConvenientDnsProvider; rename list/get methods for consistent API and deprecate convenience namespace
|
||||
|
||||
|
||||
685
readme.md
685
readme.md
@@ -1,492 +1,493 @@
|
||||
# @apiclient.xyz/cloudflare
|
||||
|
||||
An elegant, class-based TypeScript client for the Cloudflare API that makes managing your Cloudflare resources simple and type-safe.
|
||||
> 🚀 A modern, elegant TypeScript client for the Cloudflare API with clean manager-based architecture
|
||||
|
||||
[](https://www.npmjs.com/package/@apiclient.xyz/cloudflare)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
## Features
|
||||
Stop fighting with the Cloudflare API. This library gives you an intuitive, type-safe way to manage zones, DNS records, and Workers—all with clean, predictable method names and excellent IDE support.
|
||||
|
||||
- **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
|
||||
## ✨ Why This Library?
|
||||
|
||||
## Installation
|
||||
- **🎯 Logical & Consistent**: Manager-based architecture with predictable method naming (`listZones()`, `listRecords()`, `listWorkers()`)
|
||||
- **💪 Strongly Typed**: Full TypeScript support with excellent autocompletion
|
||||
- **🔌 Framework Integration**: Built-in `IConvenientDnsProvider` adapter for third-party modules
|
||||
- **⚡ Modern**: Uses async/await, ES modules, and the official Cloudflare SDK
|
||||
- **🛡️ Reliable**: Comprehensive error handling and detailed logging
|
||||
- **📦 Zero Config**: Works out of the box with just your API token
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
```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';
|
||||
import { CloudflareAccount } from '@apiclient.xyz/cloudflare';
|
||||
|
||||
// Initialize with your API token
|
||||
const cfAccount = new cflare.CloudflareAccount('your-cloudflare-api-token');
|
||||
const cf = new CloudflareAccount('your-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');
|
||||
// Manage DNS records with ease
|
||||
await cf.recordManager.createRecord('api.example.com', 'A', '192.0.2.1');
|
||||
await cf.recordManager.updateRecord('api.example.com', 'A', '203.0.113.1');
|
||||
|
||||
// Or use the IConvenientDnsProvider interface for third-party modules
|
||||
const dnsProvider = cfAccount.getConvenientDnsProvider();
|
||||
await dnsProvider.createRecord('subdomain.example.com', 'A', '192.0.2.1');
|
||||
// Work with zones
|
||||
const zones = await cf.zoneManager.listZones();
|
||||
await cf.zoneManager.purgeZone('example.com');
|
||||
|
||||
// Deploy workers
|
||||
const worker = await cf.workerManager.createWorker('my-api', workerScript);
|
||||
await worker.setRoutes([{ zoneName: 'example.com', pattern: 'api.example.com/*' }]);
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
## 📚 Core Concepts
|
||||
|
||||
### Account Management
|
||||
### Managers: Your Gateway to Cloudflare
|
||||
|
||||
Initialize your Cloudflare account with your API token:
|
||||
The library is organized around **managers**—specialized classes that handle specific Cloudflare resources:
|
||||
|
||||
- **`recordManager`** - DNS record operations
|
||||
- **`zoneManager`** - Zone (domain) management
|
||||
- **`workerManager`** - Cloudflare Workers deployment
|
||||
|
||||
Each manager provides consistent, predictable methods that feel natural to use.
|
||||
|
||||
## 🎓 Complete Guide
|
||||
|
||||
### Account Setup
|
||||
|
||||
```typescript
|
||||
import * as cflare from '@apiclient.xyz/cloudflare';
|
||||
import { CloudflareAccount } from '@apiclient.xyz/cloudflare';
|
||||
|
||||
const cfAccount = new cflare.CloudflareAccount('your-cloudflare-api-token');
|
||||
const cf = new CloudflareAccount(process.env.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();
|
||||
// If you have multiple accounts, select one
|
||||
await cf.preselectAccountByName('Production Account');
|
||||
```
|
||||
|
||||
### Zone Management
|
||||
### 🌐 Zone Management
|
||||
|
||||
Zones represent your domains in Cloudflare.
|
||||
Zones are your domains in Cloudflare.
|
||||
|
||||
```typescript
|
||||
// List all zones in your account
|
||||
const allZones = await cfAccount.zoneManager.listZones();
|
||||
// List all zones
|
||||
const zones = await cf.zoneManager.listZones();
|
||||
|
||||
// Get a specific zone by domain name
|
||||
const myZone = await cfAccount.zoneManager.getZoneByName('example.com');
|
||||
// Find a specific zone
|
||||
const zone = await cf.zoneManager.getZoneByName('example.com');
|
||||
|
||||
// Get zone ID directly
|
||||
const zoneId = await cfAccount.zoneManager.getZoneId('example.com');
|
||||
// Get zone ID for API calls
|
||||
const zoneId = await cf.zoneManager.getZoneId('example.com');
|
||||
|
||||
// Create a new zone
|
||||
const newZone = await cfAccount.zoneManager.createZone('newdomain.com');
|
||||
await cf.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 entire zone cache
|
||||
await cf.zoneManager.purgeZone('example.com');
|
||||
|
||||
// Purge specific URLs
|
||||
await myZone.purgeUrls(['https://example.com/css/styles.css', 'https://example.com/js/app.js']);
|
||||
// Work with zone objects
|
||||
if (await zone.isActive()) {
|
||||
await zone.purgeCache();
|
||||
await zone.purgeUrls(['https://example.com/css/app.css']);
|
||||
|
||||
// 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();
|
||||
// Development mode (bypasses cache for 3 hours)
|
||||
await zone.enableDevelopmentMode();
|
||||
await zone.disableDevelopmentMode();
|
||||
}
|
||||
```
|
||||
|
||||
### DNS Record Management
|
||||
### 📝 DNS Records
|
||||
|
||||
Manage DNS records for your domains with ease using the RecordManager.
|
||||
The `recordManager` gives you complete control over DNS records.
|
||||
|
||||
```typescript
|
||||
// List all DNS records for a domain
|
||||
const allRecords = await cfAccount.recordManager.listRecords('example.com');
|
||||
// List all records for a domain
|
||||
const records = await cf.recordManager.listRecords('example.com');
|
||||
|
||||
// Create a new DNS record
|
||||
await cfAccount.recordManager.createRecord('api.example.com', 'A', '192.0.2.1', 3600);
|
||||
// Create different record types
|
||||
await cf.recordManager.createRecord('www.example.com', 'CNAME', 'example.com', 3600);
|
||||
await cf.recordManager.createRecord('api.example.com', 'A', '192.0.2.1', 300);
|
||||
await cf.recordManager.createRecord('_dmarc.example.com', 'TXT', 'v=DMARC1; p=reject', 3600);
|
||||
|
||||
// Create a CNAME record
|
||||
await cfAccount.recordManager.createRecord('www.example.com', 'CNAME', 'example.com', 3600);
|
||||
// Get a specific record
|
||||
const record = await cf.recordManager.getRecord('api.example.com', 'A');
|
||||
console.log(record.content); // "192.0.2.1"
|
||||
|
||||
// Get a specific DNS record
|
||||
const record = await cfAccount.recordManager.getRecord('api.example.com', 'A');
|
||||
// Update or create (upsert behavior)
|
||||
await cf.recordManager.updateRecord('api.example.com', 'A', '203.0.113.1');
|
||||
|
||||
// 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 record
|
||||
await cf.recordManager.deleteRecord('old.example.com', 'A');
|
||||
|
||||
// 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',
|
||||
});
|
||||
// Clean up all records of a type (useful for wildcard cleanup)
|
||||
await cf.recordManager.cleanRecords('example.com', 'TXT');
|
||||
```
|
||||
|
||||
### Workers Management
|
||||
### ⚙️ Cloudflare Workers
|
||||
|
||||
Create and manage Cloudflare Workers with full TypeScript support.
|
||||
Deploy and manage serverless functions at the edge.
|
||||
|
||||
```typescript
|
||||
// Create or update a worker
|
||||
// Worker code
|
||||
const workerScript = `
|
||||
addEventListener('fetch', event => {
|
||||
event.respondWith(new Response('Hello from Cloudflare Workers!'))
|
||||
})`;
|
||||
event.respondWith(handleRequest(event.request));
|
||||
});
|
||||
|
||||
const worker = await cfAccount.workerManager.createWorker('my-worker', workerScript);
|
||||
async function handleRequest(request) {
|
||||
return new Response('Hello from the edge!', {
|
||||
headers: { 'content-type': 'text/plain' }
|
||||
});
|
||||
}
|
||||
`;
|
||||
|
||||
// Create/update a worker
|
||||
const worker = await cf.workerManager.createWorker('my-api-worker', workerScript);
|
||||
|
||||
// List all workers
|
||||
const allWorkers = await cfAccount.workerManager.listWorkers();
|
||||
const workers = await cf.workerManager.listWorkers();
|
||||
|
||||
// Get an existing worker
|
||||
const existingWorker = await cfAccount.workerManager.getWorker('my-worker');
|
||||
// Get existing worker
|
||||
const existingWorker = await cf.workerManager.getWorker('my-api-worker');
|
||||
|
||||
// Set routes for a worker
|
||||
// Set up routes
|
||||
await worker.setRoutes([
|
||||
{
|
||||
zoneName: 'example.com',
|
||||
pattern: 'https://api.example.com/*',
|
||||
},
|
||||
{
|
||||
zoneName: 'example.com',
|
||||
pattern: 'https://app.example.com/api/*',
|
||||
},
|
||||
{ zoneName: 'example.com', pattern: 'api.example.com/*' },
|
||||
{ zoneName: 'example.com', pattern: 'example.com/api/*' }
|
||||
]);
|
||||
|
||||
// List all routes for a worker
|
||||
const routes = await worker.listRoutes();
|
||||
// Check worker routes
|
||||
await worker.listRoutes();
|
||||
console.log(worker.routes); // Array of routes
|
||||
|
||||
// Update a worker's script
|
||||
await worker.updateScript(`
|
||||
addEventListener('fetch', event => {
|
||||
event.respondWith(new Response('Updated worker content!'))
|
||||
})`);
|
||||
// Update worker script
|
||||
await worker.updateScript(updatedWorkerScript);
|
||||
|
||||
// Delete a worker
|
||||
// Delete worker
|
||||
await worker.delete();
|
||||
// Or using the worker manager
|
||||
await cfAccount.workerManager.deleteWorker('my-worker');
|
||||
// or
|
||||
await cf.workerManager.deleteWorker('my-api-worker');
|
||||
```
|
||||
|
||||
### Complete Example
|
||||
### 🔐 ACME DNS Challenges (Let's Encrypt)
|
||||
|
||||
Here's a complete example showing how to manage multiple aspects of your Cloudflare account:
|
||||
Use the `ConvenientDnsProvider` adapter for certificate automation.
|
||||
|
||||
```typescript
|
||||
import * as cflare from '@apiclient.xyz/cloudflare';
|
||||
const dnsProvider = cf.getConvenientDnsProvider();
|
||||
|
||||
async function manageCloudflare() {
|
||||
try {
|
||||
// Initialize with API token from environment variable
|
||||
const cfAccount = new cflare.CloudflareAccount(process.env.CLOUDFLARE_API_TOKEN);
|
||||
// Set DNS challenge
|
||||
await dnsProvider.acmeSetDnsChallenge({
|
||||
hostName: '_acme-challenge.example.com',
|
||||
challenge: 'your-validation-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();
|
||||
// Remove challenge after validation
|
||||
await dnsProvider.acmeRemoveDnsChallenge({
|
||||
hostName: '_acme-challenge.example.com',
|
||||
challenge: 'your-validation-token'
|
||||
});
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
### 🔌 Third-Party Module Integration
|
||||
|
||||
If you're using a framework or library that expects `IConvenientDnsProvider`, use the adapter:
|
||||
|
||||
```typescript
|
||||
import { CloudflareAccount } from '@apiclient.xyz/cloudflare';
|
||||
|
||||
const cf = new CloudflareAccount(process.env.CLOUDFLARE_API_TOKEN);
|
||||
const dnsProvider = cf.getConvenientDnsProvider();
|
||||
|
||||
// Now pass this to any library expecting IConvenientDnsProvider
|
||||
await someFramework.setDnsProvider(dnsProvider);
|
||||
```
|
||||
|
||||
## 🎯 Real-World Example
|
||||
|
||||
Here's a complete example showing a typical deployment workflow:
|
||||
|
||||
```typescript
|
||||
import { CloudflareAccount } from '@apiclient.xyz/cloudflare';
|
||||
|
||||
async function deployApplication() {
|
||||
const cf = new CloudflareAccount(process.env.CLOUDFLARE_API_TOKEN);
|
||||
await cf.preselectAccountByName('Production');
|
||||
|
||||
// 1. Set up DNS
|
||||
console.log('📝 Configuring DNS...');
|
||||
await cf.recordManager.createRecord('app.example.com', 'A', '192.0.2.10');
|
||||
await cf.recordManager.createRecord('www.example.com', 'CNAME', 'example.com');
|
||||
|
||||
// 2. Deploy API worker
|
||||
console.log('⚙️ Deploying API worker...');
|
||||
const apiWorker = await cf.workerManager.createWorker('api-handler', `
|
||||
addEventListener('fetch', event => {
|
||||
const response = new Response(JSON.stringify({ status: 'ok' }), {
|
||||
headers: { 'content-type': 'application/json' }
|
||||
});
|
||||
event.respondWith(response);
|
||||
});
|
||||
`);
|
||||
|
||||
await apiWorker.setRoutes([
|
||||
{ zoneName: 'example.com', pattern: 'api.example.com/*' }
|
||||
]);
|
||||
|
||||
// 3. Configure security headers worker
|
||||
console.log('🛡️ Setting up security...');
|
||||
const securityWorker = await cf.workerManager.createWorker('security-headers', `
|
||||
addEventListener('fetch', event => {
|
||||
event.respondWith(addSecurityHeaders(event.request));
|
||||
});
|
||||
|
||||
async function addSecurityHeaders(request) {
|
||||
const response = await fetch(request);
|
||||
const newHeaders = new Headers(response.headers);
|
||||
newHeaders.set('X-Frame-Options', 'DENY');
|
||||
newHeaders.set('X-Content-Type-Options', 'nosniff');
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
headers: newHeaders
|
||||
});
|
||||
}
|
||||
`);
|
||||
|
||||
await securityWorker.setRoutes([
|
||||
{ zoneName: 'example.com', pattern: 'example.com/*' }
|
||||
]);
|
||||
|
||||
// 4. Verify and purge cache
|
||||
console.log('🔄 Purging cache...');
|
||||
const zone = await cf.zoneManager.getZoneByName('example.com');
|
||||
await zone.purgeCache();
|
||||
|
||||
console.log('✅ Deployment complete!');
|
||||
}
|
||||
|
||||
deployApplication().catch(console.error);
|
||||
```
|
||||
|
||||
## 📖 API Reference
|
||||
|
||||
### CloudflareAccount
|
||||
|
||||
The main entry point for all Cloudflare operations.
|
||||
Main entry point for all operations.
|
||||
|
||||
```typescript
|
||||
class CloudflareAccount {
|
||||
constructor(apiToken: string);
|
||||
constructor(apiToken: string)
|
||||
|
||||
// Account management
|
||||
async listAccounts(): Promise<Array<ICloudflareTypes['Account']>>;
|
||||
async preselectAccountByName(accountName: string): Promise<void>;
|
||||
// Managers
|
||||
readonly recordManager: RecordManager
|
||||
readonly zoneManager: ZoneManager
|
||||
readonly workerManager: WorkerManager
|
||||
|
||||
// Managers - Clean, logical API
|
||||
readonly zoneManager: ZoneManager;
|
||||
readonly workerManager: WorkerManager;
|
||||
readonly recordManager: RecordManager;
|
||||
// Methods
|
||||
async preselectAccountByName(name: string): Promise<void>
|
||||
getConvenientDnsProvider(): ConvenientDnsProvider
|
||||
|
||||
// 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 */ };
|
||||
// Official Cloudflare SDK client (for advanced use)
|
||||
readonly apiAccount: Cloudflare
|
||||
}
|
||||
```
|
||||
|
||||
### RecordManager
|
||||
|
||||
Clean DNS record management (recommended over deprecated convenience methods).
|
||||
DNS record management with clean, predictable methods.
|
||||
|
||||
```typescript
|
||||
class RecordManager {
|
||||
async listRecords(domainName: string): Promise<CloudflareRecord[]>;
|
||||
async getRecord(domainName: string, recordType: string): Promise<CloudflareRecord | undefined>;
|
||||
async createRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise<CloudflareRecord>;
|
||||
async updateRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise<CloudflareRecord>;
|
||||
async deleteRecord(domainName: string, recordType: string): Promise<void>;
|
||||
async cleanRecords(domainName: string, recordType: string): Promise<void>;
|
||||
async listRecords(domain: string): Promise<CloudflareRecord[]>
|
||||
async getRecord(domain: string, type: string): Promise<CloudflareRecord | undefined>
|
||||
async createRecord(domain: string, type: string, content: string, ttl?: number): Promise<CloudflareRecord>
|
||||
async updateRecord(domain: string, type: string, content: string, ttl?: number): Promise<CloudflareRecord>
|
||||
async deleteRecord(domain: string, type: string): Promise<void>
|
||||
async cleanRecords(domain: string, type: string): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
### ZoneManager
|
||||
|
||||
Zone (domain) management operations.
|
||||
|
||||
```typescript
|
||||
class ZoneManager {
|
||||
async listZones(zoneName?: string): Promise<CloudflareZone[]>;
|
||||
async getZoneById(zoneId: string): Promise<CloudflareZone | undefined>;
|
||||
async getZoneByName(zoneName: string): Promise<CloudflareZone | undefined>;
|
||||
async getZoneId(domainName: string): Promise<string>;
|
||||
async createZone(zoneName: string): Promise<CloudflareZone | undefined>;
|
||||
async deleteZone(zoneId: string): Promise<boolean>;
|
||||
async purgeZone(domainName: string): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
### WorkerManager
|
||||
|
||||
```typescript
|
||||
class WorkerManager {
|
||||
async listWorkers(): Promise<Array<ICloudflareTypes['Script']>>;
|
||||
async getWorker(workerName: string): Promise<CloudflareWorker | undefined>;
|
||||
async createWorker(workerName: string, workerScript: string): Promise<CloudflareWorker>;
|
||||
async deleteWorker(workerName: string): Promise<boolean>;
|
||||
}
|
||||
```
|
||||
|
||||
### 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<any>;
|
||||
async updateRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise<any>;
|
||||
async removeRecord(domainName: string, recordType: string): Promise<any>;
|
||||
async getRecord(domainName: string, recordType: string): Promise<any | undefined>;
|
||||
async listRecords(domainName: string): Promise<any[]>;
|
||||
async cleanRecord(domainName: string, recordType: string): Promise<void>;
|
||||
async isDomainSupported(domainName: string): Promise<boolean>;
|
||||
async acmeSetDnsChallenge(dnsChallenge: IDnsChallenge): Promise<void>;
|
||||
async acmeRemoveDnsChallenge(dnsChallenge: IDnsChallenge): Promise<void>;
|
||||
async listZones(name?: string): Promise<CloudflareZone[]>
|
||||
async getZoneById(id: string): Promise<CloudflareZone | undefined>
|
||||
async getZoneByName(name: string): Promise<CloudflareZone | undefined>
|
||||
async getZoneId(domain: string): Promise<string>
|
||||
async createZone(name: string): Promise<CloudflareZone | undefined>
|
||||
async deleteZone(id: string): Promise<boolean>
|
||||
async purgeZone(domain: string): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
### CloudflareZone
|
||||
|
||||
Represents a Cloudflare zone (domain).
|
||||
Zone instance with convenience methods.
|
||||
|
||||
```typescript
|
||||
class CloudflareZone {
|
||||
// Properties
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly status: string;
|
||||
readonly paused: boolean;
|
||||
readonly type: string;
|
||||
readonly nameServers: string[];
|
||||
readonly id: string
|
||||
readonly name: string
|
||||
readonly status: string
|
||||
|
||||
// Methods
|
||||
async purgeCache(): Promise<any>;
|
||||
async purgeUrls(urls: string[]): Promise<any>;
|
||||
async isActive(): Promise<boolean>;
|
||||
async isUsingCloudflareNameservers(): Promise<boolean>;
|
||||
async isDevelopmentModeActive(): Promise<boolean>;
|
||||
async enableDevelopmentMode(): Promise<any>;
|
||||
async disableDevelopmentMode(): Promise<any>;
|
||||
async purgeCache(): Promise<void>
|
||||
async purgeUrls(urls: string[]): Promise<void>
|
||||
async isActive(): Promise<boolean>
|
||||
async isUsingCloudflareNameservers(): Promise<boolean>
|
||||
async enableDevelopmentMode(): Promise<void>
|
||||
async disableDevelopmentMode(): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
### CloudflareRecord
|
||||
### WorkerManager
|
||||
|
||||
Represents a DNS record.
|
||||
Cloudflare Workers deployment and management.
|
||||
|
||||
```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<any>;
|
||||
async delete(): Promise<any>;
|
||||
class WorkerManager {
|
||||
async listWorkers(): Promise<WorkerScript[]>
|
||||
async getWorker(name: string): Promise<CloudflareWorker | undefined>
|
||||
async createWorker(name: string, script: string): Promise<CloudflareWorker>
|
||||
async deleteWorker(name: string): Promise<boolean>
|
||||
}
|
||||
```
|
||||
|
||||
### CloudflareWorker
|
||||
|
||||
Represents a Cloudflare Worker.
|
||||
Worker instance for route management and updates.
|
||||
|
||||
```typescript
|
||||
class CloudflareWorker {
|
||||
// Properties
|
||||
readonly id: string;
|
||||
readonly script: string;
|
||||
readonly routes: IWorkerRoute[];
|
||||
readonly id: string
|
||||
readonly script: string
|
||||
readonly routes: WorkerRoute[]
|
||||
|
||||
// Methods
|
||||
async listRoutes(): Promise<void>; // Populates the routes property
|
||||
async setRoutes(routes: Array<IWorkerRouteDefinition>): Promise<void>;
|
||||
async updateScript(scriptContent: string): Promise<CloudflareWorker>;
|
||||
async delete(): Promise<boolean>;
|
||||
async listRoutes(): Promise<void>
|
||||
async setRoutes(routes: WorkerRouteDefinition[]): Promise<void>
|
||||
async updateScript(script: string): Promise<CloudflareWorker>
|
||||
async delete(): Promise<boolean>
|
||||
}
|
||||
|
||||
interface IWorkerRouteDefinition {
|
||||
zoneName: string;
|
||||
pattern: string;
|
||||
interface WorkerRouteDefinition {
|
||||
zoneName: string
|
||||
pattern: string
|
||||
}
|
||||
```
|
||||
|
||||
## Utility Functions
|
||||
### ConvenientDnsProvider
|
||||
|
||||
The library includes helpful utility functions:
|
||||
Adapter for third-party modules requiring `IConvenientDnsProvider`.
|
||||
|
||||
```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'
|
||||
class ConvenientDnsProvider implements IConvenientDnsProvider {
|
||||
async createRecord(domain: string, type: string, content: string, ttl?: number): Promise<any>
|
||||
async updateRecord(domain: string, type: string, content: string, ttl?: number): Promise<any>
|
||||
async removeRecord(domain: string, type: string): Promise<any>
|
||||
async getRecord(domain: string, type: string): Promise<any | undefined>
|
||||
async listRecords(domain: string): Promise<any[]>
|
||||
async cleanRecord(domain: string, type: string): Promise<void>
|
||||
async isDomainSupported(domain: string): Promise<boolean>
|
||||
async acmeSetDnsChallenge(challenge: DnsChallenge): Promise<void>
|
||||
async acmeRemoveDnsChallenge(challenge: DnsChallenge): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
## What's New in 7.0.0
|
||||
## 🔄 Migration from 6.x
|
||||
|
||||
- **🎨 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
|
||||
Version 7.0 introduces a cleaner architecture while maintaining **full backward compatibility**.
|
||||
|
||||
## Migration Guide (6.x → 7.0)
|
||||
### What Changed
|
||||
|
||||
✅ **New manager-based API** - Clean, logical organization
|
||||
✅ **Consistent naming** - All list operations use `list*()`
|
||||
✅ **IConvenientDnsProvider support** - Better third-party integration
|
||||
⚠️ **Deprecated `convenience` namespace** - Still works, but use managers instead
|
||||
|
||||
### Migration Examples
|
||||
|
||||
### 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();
|
||||
// ❌ Old (deprecated but still works)
|
||||
await cf.convenience.createRecord('example.com', 'A', '1.2.3.4');
|
||||
await cf.convenience.listZones();
|
||||
await cf.workerManager.listWorkerScripts();
|
||||
await worker.getRoutes();
|
||||
|
||||
// New:
|
||||
await cfAccount.workerManager.listWorkers();
|
||||
// ✅ New (recommended)
|
||||
await cf.recordManager.createRecord('example.com', 'A', '1.2.3.4');
|
||||
await cf.zoneManager.listZones();
|
||||
await cf.workerManager.listWorkers();
|
||||
await worker.listRoutes();
|
||||
```
|
||||
|
||||
## Development & Testing
|
||||
**No Breaking Changes**: Your existing code will continue to work. The old `convenience` namespace methods now show deprecation warnings in TypeScript with clear migration paths.
|
||||
|
||||
To build the project:
|
||||
## 🛠️ Development
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
# or
|
||||
pnpm run build
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Build
|
||||
pnpm build
|
||||
|
||||
# Run tests
|
||||
pnpm test
|
||||
```
|
||||
|
||||
To run tests:
|
||||
## 📝 TypeScript Configuration
|
||||
|
||||
```bash
|
||||
npm test
|
||||
# or
|
||||
pnpm run test
|
||||
This library is written in TypeScript and provides complete type definitions. No `@types` package needed!
|
||||
|
||||
```typescript
|
||||
import { CloudflareAccount, CloudflareZone, CloudflareRecord } from '@apiclient.xyz/cloudflare';
|
||||
|
||||
// Full type inference and autocompletion
|
||||
const cf = new CloudflareAccount(token);
|
||||
const zones: CloudflareZone[] = await cf.zoneManager.listZones();
|
||||
const record: CloudflareRecord = await cf.recordManager.createRecord(/* ... */);
|
||||
```
|
||||
|
||||
## License
|
||||
## 🤔 FAQ
|
||||
|
||||
MIT © [Lossless GmbH](https://lossless.gmbh)
|
||||
**Q: Can I use this with the official Cloudflare SDK?**
|
||||
A: Yes! The library wraps the official SDK. You can access it directly via `cfAccount.apiAccount` for advanced operations.
|
||||
|
||||
**Q: Does this support Cloudflare Workers KV, R2, D1?**
|
||||
A: Currently focuses on zones, DNS, and Workers. Additional features coming in future releases.
|
||||
|
||||
**Q: How do I handle errors?**
|
||||
A: All methods throw descriptive errors. Wrap calls in try/catch for error handling.
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await cf.recordManager.createRecord('example.com', 'A', 'invalid-ip');
|
||||
} catch (error) {
|
||||
console.error('Failed to create record:', error.message);
|
||||
}
|
||||
```
|
||||
|
||||
**Q: Is this production-ready?**
|
||||
A: Absolutely! Used in production environments. Comprehensive error handling and logging built-in.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@apiclient.xyz/cloudflare',
|
||||
version: '7.0.0',
|
||||
version: '7.1.0',
|
||||
description: 'A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user