BREAKING CHANGE(core): Introduce RecordManager and ConvenientDnsProvider; rename list/get methods for consistent API and deprecate convenience namespace

This commit is contained in:
2025-11-18 20:39:08 +00:00
parent 39d53da4e6
commit 5ce1520e2b
12 changed files with 617 additions and 79 deletions

213
readme.md
View File

@@ -8,10 +8,10 @@ An elegant, class-based TypeScript client for the Cloudflare API that makes mana
## Features
- **Comprehensive coverage** of the Cloudflare API including zones, DNS records, and Workers
- **Class-based design** with intuitive methods for all Cloudflare operations
- **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
- **Convenience methods** for common operations to reduce boilerplate code
- **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
@@ -37,12 +37,13 @@ import * as cflare from '@apiclient.xyz/cloudflare';
// Initialize with your API token
const cfAccount = new cflare.CloudflareAccount('your-cloudflare-api-token');
// Use convenience methods for quick operations
await cfAccount.convenience.createRecord('subdomain.example.com', 'A', '192.0.2.1', 3600);
// 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 work with the powerful class-based API
const zone = await cfAccount.zoneManager.getZoneByName('example.com');
await zone.purgeCache();
// 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
@@ -68,20 +69,20 @@ const myAccounts = await cfAccount.listAccounts();
Zones represent your domains in Cloudflare.
```typescript
// Get all zones in your account
const allZones = await cfAccount.convenience.listZones();
// 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.convenience.getZoneId('example.com');
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.convenience.purgeZone('example.com');
await cfAccount.zoneManager.purgeZone('example.com');
// Or using the zone object
await myZone.purgeCache();
@@ -99,36 +100,40 @@ const usingCfNameservers = await myZone.isUsingCloudflareNameservers();
### DNS Record Management
Manage DNS records for your domains with ease.
Manage DNS records for your domains with ease using the RecordManager.
```typescript
// List all DNS records for a domain
const allRecords = await cfAccount.convenience.listRecords('example.com');
const allRecords = await cfAccount.recordManager.listRecords('example.com');
// Create a new DNS record
await cfAccount.convenience.createRecord('api.example.com', 'A', '192.0.2.1', 3600);
await cfAccount.recordManager.createRecord('api.example.com', 'A', '192.0.2.1', 3600);
// Create a CNAME record
await cfAccount.convenience.createRecord('www.example.com', 'CNAME', 'example.com', 3600);
await cfAccount.recordManager.createRecord('www.example.com', 'CNAME', 'example.com', 3600);
// Get a specific DNS record
const record = await cfAccount.convenience.getRecord('api.example.com', 'A');
const record = await cfAccount.recordManager.getRecord('api.example.com', 'A');
// Update a DNS record (automatically creates it if it doesn't exist)
await cfAccount.convenience.updateRecord('api.example.com', 'A', '192.0.2.2', 3600);
await cfAccount.recordManager.updateRecord('api.example.com', 'A', '192.0.2.2', 3600);
// Remove a specific DNS record
await cfAccount.convenience.removeRecord('api.example.com', 'A');
// Delete a specific DNS record
await cfAccount.recordManager.deleteRecord('api.example.com', 'A');
// Clean (remove) all records of a specific type
await cfAccount.convenience.cleanRecord('example.com', 'TXT');
// 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 cfAccount.convenience.acmeSetDnsChallenge({
await dnsProvider.acmeSetDnsChallenge({
hostName: '_acme-challenge.example.com',
challenge: 'token-validation-string',
});
await cfAccount.convenience.acmeRemoveDnsChallenge({
await dnsProvider.acmeRemoveDnsChallenge({
hostName: '_acme-challenge.example.com',
challenge: 'token-validation-string',
});
@@ -148,7 +153,7 @@ addEventListener('fetch', event => {
const worker = await cfAccount.workerManager.createWorker('my-worker', workerScript);
// List all workers
const allWorkers = await cfAccount.workerManager.listWorkerScripts();
const allWorkers = await cfAccount.workerManager.listWorkers();
// Get an existing worker
const existingWorker = await cfAccount.workerManager.getWorker('my-worker');
@@ -165,8 +170,8 @@ await worker.setRoutes([
},
]);
// Get all routes for a worker
const routes = await worker.getRoutes();
// List all routes for a worker
const routes = await worker.listRoutes();
// Update a worker's script
await worker.updateScript(`
@@ -200,9 +205,9 @@ async function manageCloudflare() {
console.log(`Zone active: ${await myZone.isActive()}`);
console.log(`Using CF nameservers: ${await myZone.isUsingCloudflareNameservers()}`);
// Configure DNS
await cfAccount.convenience.createRecord('api.example.com', 'A', '192.0.2.1');
await cfAccount.convenience.createRecord('www.example.com', 'CNAME', 'example.com');
// 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 = `
@@ -247,42 +252,78 @@ class CloudflareAccount {
async listAccounts(): Promise<Array<ICloudflareTypes['Account']>>;
async preselectAccountByName(accountName: string): Promise<void>;
// Managers
// 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;
// Convenience namespace with helper methods
readonly convenience: {
// Zone operations
listZones(domainName?: string): Promise<CloudflareZone[]>;
getZoneId(domainName: string): Promise<string>;
purgeZone(domainName: string): Promise<void>;
// ⚠️ Deprecated: convenience namespace (kept for backward compatibility)
// Use the managers instead: recordManager, zoneManager, workerManager
readonly convenience: { /* deprecated methods */ };
}
```
// DNS operations
listRecords(domainName: string): Promise<CloudflareRecord[]>;
getRecord(domainName: string, recordType: string): Promise<CloudflareRecord | undefined>;
createRecord(
domainName: string,
recordType: string,
content: string,
ttl?: number,
): Promise<any>;
updateRecord(
domainName: string,
recordType: string,
content: string,
ttl?: number,
): Promise<any>;
removeRecord(domainName: string, recordType: string): Promise<any>;
cleanRecord(domainName: string, recordType: string): Promise<void>;
### RecordManager
// ACME operations
acmeSetDnsChallenge(dnsChallenge: IDnsChallenge): Promise<any>;
acmeRemoveDnsChallenge(dnsChallenge: IDnsChallenge): Promise<any>;
};
Clean DNS record management (recommended over deprecated convenience 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>;
}
```
### ZoneManager
```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>;
}
```
@@ -343,7 +384,7 @@ class CloudflareWorker {
readonly routes: IWorkerRoute[];
// Methods
async getRoutes(): Promise<IWorkerRoute[]>;
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>;
@@ -376,13 +417,57 @@ CloudflareUtils.formatUrlForPurge('example.com/page'); // 'https://example.com/p
CloudflareUtils.formatTtl(3600); // '1 hour'
```
## What's New in 6.2.0
## What's New in 7.0.0
- **Improved async iterator support**: Fully leverages the official Cloudflare client's async iterator pattern
- **Enhanced error handling**: Better error detection and recovery
- **Simplified API**: More consistent method signatures and return types
- **Better type safety**: Improved TypeScript typing throughout the library
- **Detailed logging**: More informative logging for easier debugging
- **🎨 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