import * as plugins from './cloudflare.plugins.js'; import { logger } from './cloudflare.logger.js'; /** * Adapter class that implements IConvenientDnsProvider interface * Delegates to RecordManager and ZoneManager internally for clean architecture * This allows third-party modules to use the standard DNS provider interface */ export class ConvenientDnsProvider implements plugins.tsclass.network.IConvenientDnsProvider { /** * The convenience property is required by IConvenientDnsProvider interface * It returns this instance to maintain interface compatibility */ public convenience = this; constructor(private cfAccount: any) {} /** * Creates a new DNS record * @param domainNameArg - The domain name for the record * @param typeArg - The DNS record type * @param contentArg - The record content (IP address, CNAME target, etc.) * @param ttlArg - Time to live in seconds (default: 1 = automatic) * @returns Created record as raw API object */ public async createRecord( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, contentArg: string, ttlArg: number = 1, ): Promise { const record = await this.cfAccount.recordManager.createRecord( domainNameArg, typeArg, contentArg, ttlArg, ); // Return raw API object format for interface compatibility return this.recordToApiObject(record); } /** * Updates an existing DNS record, or creates it if it doesn't exist * @param domainNameArg - The domain name * @param typeArg - The DNS record type * @param contentArg - The new record content * @param ttlArg - Time to live in seconds (default: 1 = automatic) * @returns Updated record as raw API object */ public async updateRecord( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, contentArg: string, ttlArg: number = 1, ): Promise { const record = await this.cfAccount.recordManager.updateRecord( domainNameArg, typeArg, contentArg, ttlArg, ); return this.recordToApiObject(record); } /** * Removes a DNS record * @param domainNameArg - The domain name * @param typeArg - The DNS record type */ public async removeRecord( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, ): Promise { await this.cfAccount.recordManager.deleteRecord(domainNameArg, typeArg); } /** * Gets a specific DNS record by domain and type * @param domainNameArg - The domain name * @param typeArg - The DNS record type * @returns Record as raw API object or undefined if not found */ public async getRecord( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, ): Promise { const record = await this.cfAccount.recordManager.getRecord(domainNameArg, typeArg); return record ? this.recordToApiObject(record) : undefined; } /** * Lists all DNS records for a domain * @param domainNameArg - The domain name to list records for * @returns Array of records as raw API objects */ public async listRecords(domainNameArg: string): Promise { const records = await this.cfAccount.recordManager.listRecords(domainNameArg); return records.map((record: any) => this.recordToApiObject(record)); } /** * Removes all DNS records of a specific type for a domain * @param domainNameArg - The domain name * @param typeArg - The DNS record type to clean */ public async cleanRecord( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, ): Promise { await this.cfAccount.recordManager.cleanRecords(domainNameArg, typeArg); } /** * Determines whether the given domain can be managed by this account * @param domainName - Full domain name to check (e.g., "sub.example.com") * @returns True if the zone for the domain exists in the account, false otherwise */ public async isDomainSupported(domainName: string): Promise { try { // Parse out the apex/zone name from the full domain const domain = new plugins.smartstring.Domain(domainName); // List zones filtered by the zone name const zones = await this.cfAccount.zoneManager.listZones(domain.zoneName); // If any zone matches, we can manage this domain return Array.isArray(zones) && zones.length > 0; } catch (error) { logger.log('error', `Error checking domain support for ${domainName}: ${error.message}`); return false; } } /** * Sets an ACME DNS challenge for domain verification * @param dnsChallenge - The DNS challenge object */ public async acmeSetDnsChallenge( dnsChallenge: plugins.tsclass.network.IDnsChallenge, ): Promise { await this.cfAccount.recordManager.cleanRecords(dnsChallenge.hostName, 'TXT'); await this.cfAccount.recordManager.createRecord( dnsChallenge.hostName, 'TXT', dnsChallenge.challenge, 120, ); } /** * Removes an ACME DNS challenge * @param dnsChallenge - The DNS challenge object */ public async acmeRemoveDnsChallenge( dnsChallenge: plugins.tsclass.network.IDnsChallenge, ): Promise { await this.cfAccount.recordManager.deleteRecord(dnsChallenge.hostName, 'TXT'); } /** * Helper method to convert CloudflareRecord instance to raw API object format * This ensures compatibility with the IConvenientDnsProvider interface */ private recordToApiObject(record: any): any { return { id: record.id, type: record.type, name: record.name, content: record.content, proxiable: record.proxiable, proxied: record.proxied, ttl: record.ttl, locked: record.locked, zone_id: record.zone_id, zone_name: record.zone_name, created_on: record.created_on, modified_on: record.modified_on, }; } }