Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
5d77214222 | |||
f27eaa0e82 | |||
4c16e0263a | |||
d8ca3dc115 | |||
6cd5aa2913 | |||
4b82cfbaae |
19
changelog.md
19
changelog.md
@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-04-30 - 6.4.0 - feat(CloudflareAccount)
|
||||
Bump dependency versions and add domain support check in CloudflareAccount
|
||||
|
||||
- Upgrade dependencies: @push.rocks/smartrequest, @tsclass/tsclass, @git.zone/tsbuild, @push.rocks/tapbundle, and @types/node
|
||||
- Implement the isDomainSupported convenience method in CloudflareAccount for validating domain management
|
||||
|
||||
## 2025-04-26 - 6.3.2 - fix(worker)
|
||||
Refactor worker script update and creation to use intermediate parameter objects
|
||||
|
||||
- Build updateParams in CloudflareWorker for proper multipart form handling when updating scripts
|
||||
- Use contentParams in WorkerManager to improve clarity and consistency in worker creation
|
||||
|
||||
## 2025-04-26 - 6.3.1 - fix(core)
|
||||
Improve nested DNS record management and worker script multipart handling
|
||||
|
||||
- Add tests for creating, updating, and removing nested subdomain A records
|
||||
- Refine TXT record cleaning by filtering records with matching name and type
|
||||
- Clarify multipart form data handling for worker script updates and creation
|
||||
|
||||
## 2025-04-26 - 6.3.0 - feat(core)
|
||||
Release 6.2.0: Improved async iterator support, enhanced error handling and refined API interfaces for better type safety and consistent behavior.
|
||||
|
||||
|
12
package.json
12
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@apiclient.xyz/cloudflare",
|
||||
"version": "6.3.0",
|
||||
"version": "6.4.0",
|
||||
"private": false,
|
||||
"description": "A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.",
|
||||
"main": "dist_ts/index.js",
|
||||
@ -38,18 +38,18 @@
|
||||
"@push.rocks/smartdelay": "^3.0.1",
|
||||
"@push.rocks/smartlog": "^3.0.2",
|
||||
"@push.rocks/smartpromise": "^4.2.3",
|
||||
"@push.rocks/smartrequest": "^2.0.23",
|
||||
"@push.rocks/smartrequest": "^2.1.0",
|
||||
"@push.rocks/smartstring": "^4.0.5",
|
||||
"@tsclass/tsclass": "^5.0.0",
|
||||
"@tsclass/tsclass": "^9.1.0",
|
||||
"cloudflare": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.2.7",
|
||||
"@git.zone/tsbuild": "^2.3.2",
|
||||
"@git.zone/tsrun": "^1.3.3",
|
||||
"@git.zone/tstest": "^1.0.96",
|
||||
"@push.rocks/qenv": "^6.1.0",
|
||||
"@push.rocks/tapbundle": "^5.6.0",
|
||||
"@types/node": "^22.13.10",
|
||||
"@push.rocks/tapbundle": "^6.0.0",
|
||||
"@types/node": "^22.15.3",
|
||||
"openapi-typescript": "^7.6.1"
|
||||
},
|
||||
"files": [
|
||||
|
1282
pnpm-lock.yaml
generated
1282
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
46
test/test.ts
46
test/test.ts
@ -149,6 +149,52 @@ tap.test('should update A record content', async (tools) => {
|
||||
console.log(`Updated A record for ${subdomain} to 192.168.1.1`);
|
||||
});
|
||||
|
||||
// Nested subdomain DNS record tests
|
||||
tap.test('should create A record for nested subdomain', async (tools) => {
|
||||
tools.timeout(600000);
|
||||
const nestedSubdomain = `${randomPrefix}-nested.sub.bleu.de`;
|
||||
const result = await testCloudflareAccount.convenience.createRecord(
|
||||
nestedSubdomain,
|
||||
'A',
|
||||
'127.0.0.5',
|
||||
120
|
||||
);
|
||||
expect(result).toBeTypeOf('object');
|
||||
console.log(`Created nested A record for ${nestedSubdomain}`);
|
||||
});
|
||||
|
||||
tap.test('should get A record for nested subdomain', async (tools) => {
|
||||
tools.timeout(600000);
|
||||
const nestedSubdomain = `${randomPrefix}-nested.sub.bleu.de`;
|
||||
const record = await testCloudflareAccount.convenience.getRecord(nestedSubdomain, 'A');
|
||||
expect(record).toBeTypeOf('object');
|
||||
expect(record.content).toEqual('127.0.0.5');
|
||||
console.log(`Successfully retrieved nested A record for ${nestedSubdomain}`);
|
||||
});
|
||||
|
||||
tap.test('should update A record for nested subdomain', async (tools) => {
|
||||
tools.timeout(600000);
|
||||
const nestedSubdomain = `${randomPrefix}-nested.sub.bleu.de`;
|
||||
const result = await testCloudflareAccount.convenience.updateRecord(
|
||||
nestedSubdomain,
|
||||
'A',
|
||||
'127.0.0.6',
|
||||
120
|
||||
);
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(result.content).toEqual('127.0.0.6');
|
||||
console.log(`Updated nested A record for ${nestedSubdomain}`);
|
||||
});
|
||||
|
||||
tap.test('should remove nested subdomain A record', async (tools) => {
|
||||
tools.timeout(600000);
|
||||
const nestedSubdomain = `${randomPrefix}-nested.sub.bleu.de`;
|
||||
await testCloudflareAccount.convenience.removeRecord(nestedSubdomain, 'A');
|
||||
const record = await testCloudflareAccount.convenience.getRecord(nestedSubdomain, 'A');
|
||||
expect(record).toBeUndefined();
|
||||
console.log(`Successfully removed nested A record for ${nestedSubdomain}`);
|
||||
});
|
||||
|
||||
tap.test('should clean TXT records', async (tools) => {
|
||||
tools.timeout(600000);
|
||||
const subdomain = `${randomPrefix}-txt-test.bleu.de`;
|
||||
|
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@apiclient.xyz/cloudflare',
|
||||
version: '6.3.0',
|
||||
version: '6.4.0',
|
||||
description: 'A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.'
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import * as interfaces from './interfaces/index.js';
|
||||
import { WorkerManager } from './cloudflare.classes.workermanager.js';
|
||||
import { ZoneManager } from './cloudflare.classes.zonemanager.js';
|
||||
|
||||
export class CloudflareAccount {
|
||||
export class CloudflareAccount implements plugins.tsclass.network.IConvenientDnsProvider {
|
||||
private authToken: string;
|
||||
public preselectedAccountId: string;
|
||||
|
||||
@ -229,15 +229,17 @@ export class CloudflareAccount {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
|
||||
const records = await this.convenience.listRecords(domainNameArg);
|
||||
// List all records in the zone for this domain
|
||||
const records = await this.convenience.listRecords(domain.zoneName);
|
||||
|
||||
if (!Array.isArray(records)) {
|
||||
logger.log('warn', `Expected records array for ${domainNameArg} but got ${typeof records}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only delete records matching the specified name and type
|
||||
const recordsToDelete = records.filter((recordArg) => {
|
||||
return recordArg.type === typeArg;
|
||||
return recordArg.type === typeArg && recordArg.name === domainNameArg;
|
||||
});
|
||||
|
||||
logger.log('info', `Found ${recordsToDelete.length} ${typeArg} records to delete for ${domainNameArg}`);
|
||||
@ -351,6 +353,24 @@ export class CloudflareAccount {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
isDomainSupported: async (domainName: string): Promise<boolean> => {
|
||||
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.convenience.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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* purges a zone
|
||||
*/
|
||||
|
@ -167,12 +167,15 @@ export class CloudflareWorker {
|
||||
try {
|
||||
logger.log('info', `Updating script for worker ${this.id}`);
|
||||
|
||||
// Use the official client to update the script
|
||||
const updatedWorker = await this.workerManager.cfAccount.apiAccount.workers.scripts.content.update(this.id, {
|
||||
// Use the official client to update the script (upload new content)
|
||||
// Build params as any to include the script form part without TS errors
|
||||
const updateParams: any = {
|
||||
account_id: this.workerManager.cfAccount.preselectedAccountId,
|
||||
"CF-WORKER-BODY-PART": scriptContent,
|
||||
metadata: {}
|
||||
});
|
||||
metadata: { body_part: 'script' },
|
||||
};
|
||||
updateParams['CF-WORKER-BODY-PART'] = 'script';
|
||||
updateParams['script'] = scriptContent;
|
||||
const updatedWorker = await this.workerManager.cfAccount.apiAccount.workers.scripts.content.update(this.id, updateParams);
|
||||
|
||||
// Update this instance with new data
|
||||
if (updatedWorker && typeof updatedWorker === 'object') {
|
||||
|
@ -22,12 +22,15 @@ export class WorkerManager {
|
||||
}
|
||||
|
||||
try {
|
||||
// Use the official client to create/update the worker
|
||||
await this.cfAccount.apiAccount.workers.scripts.content.update(workerName, {
|
||||
// Use the official client to create/update the worker (upload script content)
|
||||
// Build params as any to include the script form part without TS errors
|
||||
const contentParams: any = {
|
||||
account_id: this.cfAccount.preselectedAccountId,
|
||||
"CF-WORKER-BODY-PART": workerScript,
|
||||
metadata: {}
|
||||
});
|
||||
metadata: { body_part: 'script' },
|
||||
};
|
||||
contentParams['CF-WORKER-BODY-PART'] = 'script';
|
||||
contentParams['script'] = workerScript;
|
||||
await this.cfAccount.apiAccount.workers.scripts.content.update(workerName, contentParams);
|
||||
|
||||
// Create a new worker instance
|
||||
const worker = new CloudflareWorker(this);
|
||||
|
Reference in New Issue
Block a user