feat(core): Release 6.2.0: Improved async iterator support, enhanced error handling and refined API interfaces for better type safety and consistent behavior.
This commit is contained in:
@@ -32,12 +32,14 @@ export class CloudflareAccount {
|
||||
* @param method HTTP method (GET, POST, PUT, DELETE)
|
||||
* @param endpoint API endpoint path
|
||||
* @param data Optional request body data
|
||||
* @param customHeaders Optional custom headers to override defaults
|
||||
* @returns API response
|
||||
*/
|
||||
public async request<T = any>(
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
|
||||
endpoint: string,
|
||||
data?: any
|
||||
data?: any,
|
||||
customHeaders?: Record<string, string>
|
||||
): Promise<T> {
|
||||
try {
|
||||
const options: plugins.smartrequest.ISmartRequestOptions = {
|
||||
@@ -45,15 +47,48 @@ export class CloudflareAccount {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.authToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
...customHeaders,
|
||||
},
|
||||
};
|
||||
|
||||
if (data) {
|
||||
options.requestBody = JSON.stringify(data);
|
||||
if (customHeaders && customHeaders['Content-Type']?.includes('multipart/form-data')) {
|
||||
// For multipart form data, use the data directly as the request body
|
||||
options.requestBody = data;
|
||||
} else {
|
||||
// For JSON requests, stringify the data
|
||||
options.requestBody = JSON.stringify(data);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log('debug', `Making ${method} request to ${endpoint}`);
|
||||
const response = await plugins.smartrequest.request(`https://api.cloudflare.com/client/v4${endpoint}`, options);
|
||||
return JSON.parse(response.body);
|
||||
|
||||
// Check if response is already an object (might happen with newer smartrequest versions)
|
||||
if (typeof response.body === 'object' && response.body !== null) {
|
||||
return response.body;
|
||||
}
|
||||
|
||||
// Otherwise try to parse as JSON
|
||||
try {
|
||||
if (typeof response.body === 'string' && response.body.trim()) {
|
||||
return JSON.parse(response.body);
|
||||
} else {
|
||||
// If body is empty or not a string, return an empty result
|
||||
logger.log('warn', `Empty or invalid response body: ${typeof response.body}`);
|
||||
return { result: [] } as T;
|
||||
}
|
||||
} catch (parseError) {
|
||||
logger.log('warn', `Failed to parse response as JSON: ${parseError.message}`);
|
||||
|
||||
// Create a fake response object to maintain expected structure
|
||||
return {
|
||||
result: [],
|
||||
success: true,
|
||||
errors: [],
|
||||
messages: [`Failed to parse: ${typeof response.body === 'string' ? response.body?.substring(0, 50) : typeof response.body}...`]
|
||||
} as T;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log('error', `Cloudflare API request failed: ${error.message}`);
|
||||
throw error;
|
||||
@@ -74,14 +109,24 @@ export class CloudflareAccount {
|
||||
|
||||
public convenience = {
|
||||
/**
|
||||
* listAccounts
|
||||
* Lists all accounts accessible with the current API token
|
||||
* @returns Array of Cloudflare account objects
|
||||
*/
|
||||
listAccounts: async () => {
|
||||
const accounts: plugins.ICloudflareTypes['Account'][] = [];
|
||||
for await (const account of this.apiAccount.accounts.list()) {
|
||||
accounts.push(account as interfaces.ICloudflareApiAccountObject);
|
||||
try {
|
||||
const accounts: plugins.ICloudflareTypes['Account'][] = [];
|
||||
|
||||
// Collect all accounts using async iterator
|
||||
for await (const account of this.apiAccount.accounts.list()) {
|
||||
accounts.push(account as interfaces.ICloudflareApiAccountObject);
|
||||
}
|
||||
|
||||
logger.log('info', `Found ${accounts.length} accounts`);
|
||||
return accounts;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to list accounts: ${error.message}`);
|
||||
return [];
|
||||
}
|
||||
return accounts;
|
||||
},
|
||||
/**
|
||||
* gets a zone id of a domain from cloudflare
|
||||
@@ -262,27 +307,19 @@ export class CloudflareAccount {
|
||||
* @param domainNameArg - the domain name that you want to get the records from
|
||||
*/
|
||||
listRecords: async (domainNameArg: string) => {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
const records: plugins.ICloudflareTypes['Record'][] = [];
|
||||
|
||||
try {
|
||||
const result = await this.apiAccount.dns.records.list({
|
||||
zone_id: zoneId,
|
||||
});
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
const records: plugins.ICloudflareTypes['Record'][] = [];
|
||||
|
||||
// Check if the result has a 'result' property (API response format)
|
||||
if (result && result.result && Array.isArray(result.result)) {
|
||||
return result.result;
|
||||
}
|
||||
|
||||
// Otherwise iterate through async iterator (new client format)
|
||||
// Collect all records using async iterator
|
||||
for await (const record of this.apiAccount.dns.records.list({
|
||||
zone_id: zoneId,
|
||||
})) {
|
||||
records.push(record);
|
||||
}
|
||||
|
||||
logger.log('info', `Found ${records.length} DNS records for ${domainNameArg}`);
|
||||
return records;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to list records for ${domainNameArg}: ${error.message}`);
|
||||
@@ -291,29 +328,23 @@ export class CloudflareAccount {
|
||||
},
|
||||
/**
|
||||
* list all zones in the associated authenticated account
|
||||
* @param domainName
|
||||
* @param domainName optional filter by domain name
|
||||
*/
|
||||
listZones: async (domainName?: string) => {
|
||||
const options: any = {};
|
||||
if (domainName) {
|
||||
options.name = domainName;
|
||||
}
|
||||
|
||||
const zones: plugins.ICloudflareTypes['Zone'][] = [];
|
||||
|
||||
try {
|
||||
const result = await this.apiAccount.zones.list(options);
|
||||
|
||||
// Check if the result has a 'result' property (API response format)
|
||||
if (result && result.result && Array.isArray(result.result)) {
|
||||
return result.result;
|
||||
const options: any = {};
|
||||
if (domainName) {
|
||||
options.name = domainName;
|
||||
}
|
||||
|
||||
// Otherwise iterate through async iterator (new client format)
|
||||
const zones: plugins.ICloudflareTypes['Zone'][] = [];
|
||||
|
||||
// Collect all zones using async iterator
|
||||
for await (const zone of this.apiAccount.zones.list(options)) {
|
||||
zones.push(zone);
|
||||
}
|
||||
|
||||
logger.log('info', `Found ${zones.length} zones${domainName ? ` matching ${domainName}` : ''}`);
|
||||
return zones;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to list zones: ${error.message}`);
|
||||
|
||||
Reference in New Issue
Block a user