fix(ci): Update CI workflows, repository URL, and apply minor code formatting fixes

This commit is contained in:
Philipp Kunz 2025-04-30 12:09:13 +00:00
parent 5d77214222
commit 36d9db4332
19 changed files with 531 additions and 264 deletions

View File

@ -0,0 +1,66 @@
name: Default (not tags)
on:
push:
tags-ignore:
- '**'
env:
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Install pnpm and npmci
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
- name: Run npm prepare
run: npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build

View File

@ -0,0 +1,124 @@
name: Default (tags)
on:
push:
tags:
- '*'
env:
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build
release:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Release
run: |
npmci node install stable
npmci npm publish
metadata:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
continue-on-error: true
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Code quality
run: |
npmci command npm install -g typescript
npmci npm install
- name: Trigger
run: npmci trigger
- name: Build docs and upload artifacts
run: |
npmci node install stable
npmci npm install
pnpm install -g @git.zone/tsdoc
npmci command tsdoc
continue-on-error: true

3
.gitignore vendored
View File

@ -3,7 +3,6 @@
# artifacts # artifacts
coverage/ coverage/
public/ public/
pages/
# installs # installs
node_modules/ node_modules/
@ -17,4 +16,4 @@ node_modules/
dist/ dist/
dist_*/ dist_*/
# custom #------# custom

View File

@ -1,5 +1,13 @@
# Changelog # Changelog
## 2025-04-30 - 6.4.1 - fix(ci)
Update CI workflows, repository URL, and apply minor code formatting fixes
- Add new Gitea workflows for both tagged and non-tagged push events with security, test, release, and metadata jobs
- Update repository URL in package.json from pushrocks/cflare to mojoio/cloudflare
- Refine .gitignore custom comments
- Apply minor formatting improvements in source code and documentation
## 2025-04-30 - 6.4.0 - feat(CloudflareAccount) ## 2025-04-30 - 6.4.0 - feat(CloudflareAccount)
Bump dependency versions and add domain support check in CloudflareAccount Bump dependency versions and add domain support check in CloudflareAccount

View File

@ -14,7 +14,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://gitlab.com/pushrocks/cflare.git" "url": "https://gitlab.com/mojoio/cloudflare.git"
}, },
"keywords": [ "keywords": [
"Cloudflare", "Cloudflare",
@ -31,9 +31,9 @@
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://gitlab.com/pushrocks/cflare/issues" "url": "https://gitlab.com/mojoio/cloudflare/issues"
}, },
"homepage": "https://gitlab.com/pushrocks/cflare#readme", "homepage": "https://gitlab.com/mojoio/cloudflare#readme",
"dependencies": { "dependencies": {
"@push.rocks/smartdelay": "^3.0.1", "@push.rocks/smartdelay": "^3.0.1",
"@push.rocks/smartlog": "^3.0.2", "@push.rocks/smartlog": "^3.0.2",
@ -67,5 +67,8 @@
"browserslist": [ "browserslist": [
"last 1 chrome versions" "last 1 chrome versions"
], ],
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6" "packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6",
"pnpm": {
"overrides": {}
}
} }

View File

@ -126,11 +126,11 @@ await cfAccount.convenience.cleanRecord('example.com', 'TXT');
// Support for ACME DNS challenges (for certificate issuance) // Support for ACME DNS challenges (for certificate issuance)
await cfAccount.convenience.acmeSetDnsChallenge({ await cfAccount.convenience.acmeSetDnsChallenge({
hostName: '_acme-challenge.example.com', hostName: '_acme-challenge.example.com',
challenge: 'token-validation-string' challenge: 'token-validation-string',
}); });
await cfAccount.convenience.acmeRemoveDnsChallenge({ await cfAccount.convenience.acmeRemoveDnsChallenge({
hostName: '_acme-challenge.example.com', hostName: '_acme-challenge.example.com',
challenge: 'token-validation-string' challenge: 'token-validation-string',
}); });
``` ```
@ -157,12 +157,12 @@ const existingWorker = await cfAccount.workerManager.getWorker('my-worker');
await worker.setRoutes([ await worker.setRoutes([
{ {
zoneName: 'example.com', zoneName: 'example.com',
pattern: 'https://api.example.com/*' pattern: 'https://api.example.com/*',
}, },
{ {
zoneName: 'example.com', zoneName: 'example.com',
pattern: 'https://app.example.com/api/*' pattern: 'https://app.example.com/api/*',
} },
]); ]);
// Get all routes for a worker // Get all routes for a worker
@ -219,9 +219,7 @@ async function manageCloudflare() {
})`; })`;
const worker = await cfAccount.workerManager.createWorker('api-handler', workerCode); const worker = await cfAccount.workerManager.createWorker('api-handler', workerCode);
await worker.setRoutes([ await worker.setRoutes([{ zoneName: 'example.com', pattern: 'https://api.example.com/*' }]);
{ zoneName: 'example.com', pattern: 'https://api.example.com/*' }
]);
// Purge cache for specific URLs // Purge cache for specific URLs
await myZone.purgeUrls(['https://example.com/css/styles.css']); await myZone.purgeUrls(['https://example.com/css/styles.css']);
@ -266,8 +264,18 @@ class CloudflareAccount {
// DNS operations // DNS operations
listRecords(domainName: string): Promise<CloudflareRecord[]>; listRecords(domainName: string): Promise<CloudflareRecord[]>;
getRecord(domainName: string, recordType: string): Promise<CloudflareRecord | undefined>; getRecord(domainName: string, recordType: string): Promise<CloudflareRecord | undefined>;
createRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise<any>; createRecord(
updateRecord(domainName: string, recordType: string, content: string, ttl?: number): Promise<any>; 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>; removeRecord(domainName: string, recordType: string): Promise<any>;
cleanRecord(domainName: string, recordType: string): Promise<void>; cleanRecord(domainName: string, recordType: string): Promise<void>;

View File

@ -14,7 +14,9 @@ let testZoneName = `test-zone-${randomPrefix}.com`;
// Basic initialization tests // Basic initialization tests
tap.test('should create a valid instance of CloudflareAccount', async () => { tap.test('should create a valid instance of CloudflareAccount', async () => {
testCloudflareAccount = new cloudflare.CloudflareAccount(await testQenv.getEnvVarOnDemand('CF_KEY')); testCloudflareAccount = new cloudflare.CloudflareAccount(
await testQenv.getEnvVarOnDemand('CF_KEY'),
);
expect(testCloudflareAccount).toBeTypeOf('object'); expect(testCloudflareAccount).toBeTypeOf('object');
expect(testCloudflareAccount.apiAccount).toBeTypeOf('object'); expect(testCloudflareAccount.apiAccount).toBeTypeOf('object');
}); });
@ -22,7 +24,7 @@ tap.test('should create a valid instance of CloudflareAccount', async () => {
tap.test('should preselect an account', async () => { tap.test('should preselect an account', async () => {
await testCloudflareAccount.preselectAccountByName('Sandbox Account'); await testCloudflareAccount.preselectAccountByName('Sandbox Account');
expect(testCloudflareAccount.preselectedAccountId).toBeTypeOf('string'); expect(testCloudflareAccount.preselectedAccountId).toBeTypeOf('string');
}) });
// Zone management tests // Zone management tests
tap.test('.listZones() -> should list zones in account', async (tools) => { tap.test('.listZones() -> should list zones in account', async (tools) => {
@ -94,7 +96,7 @@ tap.test('should create A record for subdomain', async (tools) => {
subdomain, subdomain,
'A', 'A',
'127.0.0.1', '127.0.0.1',
120 120,
); );
expect(result).toBeTypeOf('object'); expect(result).toBeTypeOf('object');
console.log(`Created A record for ${subdomain}`); console.log(`Created A record for ${subdomain}`);
@ -107,7 +109,7 @@ tap.test('should create CNAME record for subdomain', async (tools) => {
subdomain, subdomain,
'CNAME', 'CNAME',
'example.com', 'example.com',
120 120,
); );
expect(result).toBeTypeOf('object'); expect(result).toBeTypeOf('object');
console.log(`Created CNAME record for ${subdomain}`); console.log(`Created CNAME record for ${subdomain}`);
@ -120,7 +122,7 @@ tap.test('should create TXT record for subdomain', async (tools) => {
subdomain, subdomain,
'TXT', 'TXT',
'v=spf1 include:_spf.example.com ~all', 'v=spf1 include:_spf.example.com ~all',
120 120,
); );
expect(result).toBeTypeOf('object'); expect(result).toBeTypeOf('object');
console.log(`Created TXT record for ${subdomain}`); console.log(`Created TXT record for ${subdomain}`);
@ -142,7 +144,7 @@ tap.test('should update A record content', async (tools) => {
subdomain, subdomain,
'A', 'A',
'192.168.1.1', '192.168.1.1',
120 120,
); );
expect(result).toBeTypeOf('object'); expect(result).toBeTypeOf('object');
expect(result.content).toEqual('192.168.1.1'); expect(result.content).toEqual('192.168.1.1');
@ -157,7 +159,7 @@ tap.test('should create A record for nested subdomain', async (tools) => {
nestedSubdomain, nestedSubdomain,
'A', 'A',
'127.0.0.5', '127.0.0.5',
120 120,
); );
expect(result).toBeTypeOf('object'); expect(result).toBeTypeOf('object');
console.log(`Created nested A record for ${nestedSubdomain}`); console.log(`Created nested A record for ${nestedSubdomain}`);
@ -179,7 +181,7 @@ tap.test('should update A record for nested subdomain', async (tools) => {
nestedSubdomain, nestedSubdomain,
'A', 'A',
'127.0.0.6', '127.0.0.6',
120 120,
); );
expect(result).toBeTypeOf('object'); expect(result).toBeTypeOf('object');
expect(result.content).toEqual('127.0.0.6'); expect(result.content).toEqual('127.0.0.6');
@ -254,7 +256,7 @@ tap.test('should create a worker', async (tools) => {
event.respondWith(new Response('Hello from Cloudflare Workers!', { event.respondWith(new Response('Hello from Cloudflare Workers!', {
headers: { 'content-type': 'text/plain' } headers: { 'content-type': 'text/plain' }
})) }))
})` })`,
); );
expect(worker).toBeTypeOf('object'); expect(worker).toBeTypeOf('object');
@ -293,7 +295,7 @@ tap.test('should get a specific worker by name', async (tools) => {
event.respondWith(new Response('Hello from Cloudflare Workers!', { event.respondWith(new Response('Hello from Cloudflare Workers!', {
headers: { 'content-type': 'text/plain' } headers: { 'content-type': 'text/plain' }
})) }))
})` })`,
); );
// Now get the worker // Now get the worker

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@apiclient.xyz/cloudflare', name: '@apiclient.xyz/cloudflare',
version: '6.4.0', version: '6.4.1',
description: 'A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.' description: 'A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.'
} }

View File

@ -39,13 +39,13 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
endpoint: string, endpoint: string,
data?: any, data?: any,
customHeaders?: Record<string, string> customHeaders?: Record<string, string>,
): Promise<T> { ): Promise<T> {
try { try {
const options: plugins.smartrequest.ISmartRequestOptions = { const options: plugins.smartrequest.ISmartRequestOptions = {
method, method,
headers: { headers: {
'Authorization': `Bearer ${this.authToken}`, Authorization: `Bearer ${this.authToken}`,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...customHeaders, ...customHeaders,
}, },
@ -62,7 +62,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
} }
logger.log('debug', `Making ${method} request to ${endpoint}`); logger.log('debug', `Making ${method} request to ${endpoint}`);
const response = await plugins.smartrequest.request(`https://api.cloudflare.com/client/v4${endpoint}`, options); const response = await plugins.smartrequest.request(
`https://api.cloudflare.com/client/v4${endpoint}`,
options,
);
// Check if response is already an object (might happen with newer smartrequest versions) // Check if response is already an object (might happen with newer smartrequest versions)
if (typeof response.body === 'object' && response.body !== null) { if (typeof response.body === 'object' && response.body !== null) {
@ -86,7 +89,9 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
result: [], result: [],
success: true, success: true,
errors: [], errors: [],
messages: [`Failed to parse: ${typeof response.body === 'string' ? response.body?.substring(0, 50) : typeof response.body}...`] messages: [
`Failed to parse: ${typeof response.body === 'string' ? response.body?.substring(0, 50) : typeof response.body}...`,
],
} as T; } as T;
} }
} catch (error) { } catch (error) {
@ -152,14 +157,17 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
*/ */
getRecord: async ( getRecord: async (
domainNameArg: string, domainNameArg: string,
typeArg: plugins.tsclass.network.TDnsRecordType typeArg: plugins.tsclass.network.TDnsRecordType,
): Promise<plugins.ICloudflareTypes['Record'] | undefined> => { ): Promise<plugins.ICloudflareTypes['Record'] | undefined> => {
try { try {
const domain = new plugins.smartstring.Domain(domainNameArg); const domain = new plugins.smartstring.Domain(domainNameArg);
const recordArrayArg = await this.convenience.listRecords(domain.zoneName); const recordArrayArg = await this.convenience.listRecords(domain.zoneName);
if (!Array.isArray(recordArrayArg)) { if (!Array.isArray(recordArrayArg)) {
logger.log('warn', `Expected records array for ${domainNameArg} but got ${typeof recordArrayArg}`); logger.log(
'warn',
`Expected records array for ${domainNameArg} but got ${typeof recordArrayArg}`,
);
return undefined; return undefined;
} }
@ -180,7 +188,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
domainNameArg: string, domainNameArg: string,
typeArg: plugins.tsclass.network.TDnsRecordType, typeArg: plugins.tsclass.network.TDnsRecordType,
contentArg: string, contentArg: string,
ttlArg = 1 ttlArg = 1,
): Promise<any> => { ): Promise<any> => {
const domain = new plugins.smartstring.Domain(domainNameArg); const domain = new plugins.smartstring.Domain(domainNameArg);
const zoneId = await this.convenience.getZoneId(domain.zoneName); const zoneId = await this.convenience.getZoneId(domain.zoneName);
@ -190,7 +198,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
name: domain.fullName, name: domain.fullName,
content: contentArg, content: contentArg,
ttl: ttlArg, ttl: ttlArg,
}) });
return response; return response;
}, },
/** /**
@ -200,7 +208,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
*/ */
removeRecord: async ( removeRecord: async (
domainNameArg: string, domainNameArg: string,
typeArg: plugins.tsclass.network.TDnsRecordType typeArg: plugins.tsclass.network.TDnsRecordType,
): Promise<any> => { ): Promise<any> => {
const domain = new plugins.smartstring.Domain(domainNameArg); const domain = new plugins.smartstring.Domain(domainNameArg);
const zoneId = await this.convenience.getZoneId(domain.zoneName); const zoneId = await this.convenience.getZoneId(domain.zoneName);
@ -233,7 +241,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
const records = await this.convenience.listRecords(domain.zoneName); const records = await this.convenience.listRecords(domain.zoneName);
if (!Array.isArray(records)) { if (!Array.isArray(records)) {
logger.log('warn', `Expected records array for ${domainNameArg} but got ${typeof records}`); logger.log(
'warn',
`Expected records array for ${domainNameArg} but got ${typeof records}`,
);
return; return;
} }
@ -242,7 +253,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
return recordArg.type === typeArg && recordArg.name === domainNameArg; return recordArg.type === typeArg && recordArg.name === domainNameArg;
}); });
logger.log('info', `Found ${recordsToDelete.length} ${typeArg} records to delete for ${domainNameArg}`); logger.log(
'info',
`Found ${recordsToDelete.length} ${typeArg} records to delete for ${domainNameArg}`,
);
for (const recordToDelete of recordsToDelete) { for (const recordToDelete of recordsToDelete) {
try { try {
@ -263,7 +277,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
} }
} }
} catch (error) { } catch (error) {
logger.log('error', `Error cleaning ${typeArg} records for ${domainNameArg}: ${error.message}`); logger.log(
'error',
`Error cleaning ${typeArg} records for ${domainNameArg}: ${error.message}`,
);
} }
}, },
@ -279,7 +296,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
domainNameArg: string, domainNameArg: string,
typeArg: plugins.tsclass.network.TDnsRecordType, typeArg: plugins.tsclass.network.TDnsRecordType,
contentArg: string, contentArg: string,
ttlArg: number = 1 ttlArg: number = 1,
): Promise<plugins.ICloudflareTypes['Record']> => { ): Promise<plugins.ICloudflareTypes['Record']> => {
const domain = new plugins.smartstring.Domain(domainNameArg); const domain = new plugins.smartstring.Domain(domainNameArg);
const zoneId = await this.convenience.getZoneId(domain.zoneName); const zoneId = await this.convenience.getZoneId(domain.zoneName);
@ -288,7 +305,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
const record = await this.convenience.getRecord(domainNameArg, typeArg); const record = await this.convenience.getRecord(domainNameArg, typeArg);
if (!record) { if (!record) {
logger.log('warn', `Record ${domainNameArg} of type ${typeArg} not found for update, creating instead`); logger.log(
'warn',
`Record ${domainNameArg} of type ${typeArg} not found for update, creating instead`,
);
return this.convenience.createRecord(domainNameArg, typeArg, contentArg, ttlArg); return this.convenience.createRecord(domainNameArg, typeArg, contentArg, ttlArg);
} }
@ -299,7 +319,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
type: typeArg as any, type: typeArg as any,
name: domain.fullName, name: domain.fullName,
content: contentArg, content: contentArg,
ttl: ttlArg ttl: ttlArg,
}); });
return updatedRecord; return updatedRecord;
@ -346,7 +366,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
zones.push(zone); zones.push(zone);
} }
logger.log('info', `Found ${zones.length} zones${domainName ? ` matching ${domainName}` : ''}`); logger.log(
'info',
`Found ${zones.length} zones${domainName ? ` matching ${domainName}` : ''}`,
);
return zones; return zones;
} catch (error) { } catch (error) {
logger.log('error', `Failed to list zones: ${error.message}`); logger.log('error', `Failed to list zones: ${error.message}`);
@ -390,7 +413,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
dnsChallenge.hostName, dnsChallenge.hostName,
'TXT', 'TXT',
dnsChallenge.challenge, dnsChallenge.challenge,
120 120,
); );
}, },
acmeRemoveDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => { acmeRemoveDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => {

View File

@ -22,7 +22,9 @@ export class CloudflareRecord {
* @param apiObject Cloudflare DNS record API object * @param apiObject Cloudflare DNS record API object
* @returns CloudflareRecord instance * @returns CloudflareRecord instance
*/ */
public static createFromApiObject(apiObject: plugins.ICloudflareTypes['Record']): CloudflareRecord { public static createFromApiObject(
apiObject: plugins.ICloudflareTypes['Record'],
): CloudflareRecord {
const record = new CloudflareRecord(); const record = new CloudflareRecord();
Object.assign(record, apiObject); Object.assign(record, apiObject);
return record; return record;
@ -52,7 +54,7 @@ export class CloudflareRecord {
public async update( public async update(
cloudflareAccount: any, cloudflareAccount: any,
newContent: string, newContent: string,
ttl?: number ttl?: number,
): Promise<CloudflareRecord> { ): Promise<CloudflareRecord> {
logger.log('info', `Updating record ${this.name} (${this.type}) with new content`); logger.log('info', `Updating record ${this.name} (${this.type}) with new content`);
@ -62,7 +64,7 @@ export class CloudflareRecord {
name: this.name, name: this.name,
content: newContent, content: newContent,
ttl: ttl || this.ttl, ttl: ttl || this.ttl,
proxied: this.proxied proxied: this.proxied,
}); });
// Update this instance // Update this instance
@ -84,7 +86,7 @@ export class CloudflareRecord {
logger.log('info', `Deleting record ${this.name} (${this.type})`); logger.log('info', `Deleting record ${this.name} (${this.type})`);
await cloudflareAccount.apiAccount.dns.records.delete(this.id, { await cloudflareAccount.apiAccount.dns.records.delete(this.id, {
zone_id: this.zone_id zone_id: this.zone_id,
}); });
return true; return true;

View File

@ -16,7 +16,7 @@ export class CloudflareWorker {
// STATIC // STATIC
public static async fromApiObject( public static async fromApiObject(
workerManager: WorkerManager, workerManager: WorkerManager,
apiObject apiObject,
): Promise<CloudflareWorker> { ): Promise<CloudflareWorker> {
const newWorker = new CloudflareWorker(workerManager); const newWorker = new CloudflareWorker(workerManager);
Object.assign(newWorker, apiObject); Object.assign(newWorker, apiObject);
@ -68,7 +68,7 @@ export class CloudflareWorker {
// Get worker routes for this zone // Get worker routes for this zone
const apiRoutes = []; const apiRoutes = [];
for await (const route of this.workerManager.cfAccount.apiAccount.workers.routes.list({ for await (const route of this.workerManager.cfAccount.apiAccount.workers.routes.list({
zone_id: zone.id zone_id: zone.id,
})) { })) {
apiRoutes.push(route); apiRoutes.push(route);
} }
@ -81,7 +81,10 @@ export class CloudflareWorker {
} }
} }
} catch (error) { } catch (error) {
logger.log('error', `Failed to get worker routes for zone ${zone.name || zone.id}: ${error.message}`); logger.log(
'error',
`Failed to get worker routes for zone ${zone.name || zone.id}: ${error.message}`,
);
} }
} }
@ -120,7 +123,9 @@ export class CloudflareWorker {
try { try {
// Get the zone ID // Get the zone ID
const zone = await this.workerManager.cfAccount.zoneManager.getZoneByName(newRoute.zoneName); const zone = await this.workerManager.cfAccount.zoneManager.getZoneByName(
newRoute.zoneName,
);
if (!zone) { if (!zone) {
logger.log('error', `Zone ${newRoute.zoneName} not found`); logger.log('error', `Zone ${newRoute.zoneName} not found`);
@ -132,7 +137,7 @@ export class CloudflareWorker {
await this.workerManager.cfAccount.apiAccount.workers.routes.create({ await this.workerManager.cfAccount.apiAccount.workers.routes.create({
zone_id: zone.id, zone_id: zone.id,
pattern: newRoute.pattern, pattern: newRoute.pattern,
script: this.id script: this.id,
}); });
logger.log('info', `Created new route ${newRoute.pattern} for worker ${this.id}`); logger.log('info', `Created new route ${newRoute.pattern} for worker ${this.id}`);
@ -140,7 +145,7 @@ export class CloudflareWorker {
await this.workerManager.cfAccount.apiAccount.workers.routes.update(existingRouteId, { await this.workerManager.cfAccount.apiAccount.workers.routes.update(existingRouteId, {
zone_id: zone.id, zone_id: zone.id,
pattern: newRoute.pattern, pattern: newRoute.pattern,
script: this.id script: this.id,
}); });
logger.log('info', `Updated route ${newRoute.pattern} for worker ${this.id}`); logger.log('info', `Updated route ${newRoute.pattern} for worker ${this.id}`);
@ -175,7 +180,11 @@ export class CloudflareWorker {
}; };
updateParams['CF-WORKER-BODY-PART'] = 'script'; updateParams['CF-WORKER-BODY-PART'] = 'script';
updateParams['script'] = scriptContent; updateParams['script'] = scriptContent;
const updatedWorker = await this.workerManager.cfAccount.apiAccount.workers.scripts.content.update(this.id, updateParams); const updatedWorker =
await this.workerManager.cfAccount.apiAccount.workers.scripts.content.update(
this.id,
updateParams,
);
// Update this instance with new data // Update this instance with new data
if (updatedWorker && typeof updatedWorker === 'object') { if (updatedWorker && typeof updatedWorker === 'object') {
@ -206,7 +215,7 @@ export class CloudflareWorker {
// Use the official client to delete the worker // Use the official client to delete the worker
await this.workerManager.cfAccount.apiAccount.workers.scripts.delete(this.id, { await this.workerManager.cfAccount.apiAccount.workers.scripts.delete(this.id, {
account_id: this.workerManager.cfAccount.preselectedAccountId account_id: this.workerManager.cfAccount.preselectedAccountId,
}); });
return true; return true;

View File

@ -65,7 +65,7 @@ export class WorkerManager {
try { try {
// Get the worker script using the official client // Get the worker script using the official client
const workerScript = await this.cfAccount.apiAccount.workers.scripts.get(workerName, { const workerScript = await this.cfAccount.apiAccount.workers.scripts.get(workerName, {
account_id: this.cfAccount.preselectedAccountId account_id: this.cfAccount.preselectedAccountId,
}); });
// Create a new worker instance // Create a new worker instance
@ -118,9 +118,9 @@ export class WorkerManager {
logger.log('warn', `Error while listing workers with async iterator: ${error.message}`); logger.log('warn', `Error while listing workers with async iterator: ${error.message}`);
// Try alternative approach if the async iterator fails // Try alternative approach if the async iterator fails
const result = await this.cfAccount.apiAccount.workers.scripts.list({ const result = (await this.cfAccount.apiAccount.workers.scripts.list({
account_id: this.cfAccount.preselectedAccountId, account_id: this.cfAccount.preselectedAccountId,
}) as any; })) as any;
// Check if the result has a 'result' property (older API response format) // Check if the result has a 'result' property (older API response format)
if (result && result.result && Array.isArray(result.result)) { if (result && result.result && Array.isArray(result.result)) {
@ -149,7 +149,7 @@ export class WorkerManager {
try { try {
await this.cfAccount.apiAccount.workers.scripts.delete(workerName, { await this.cfAccount.apiAccount.workers.scripts.delete(workerName, {
account_id: this.cfAccount.preselectedAccountId account_id: this.cfAccount.preselectedAccountId,
}); });
logger.log('info', `Worker '${workerName}' deleted successfully`); logger.log('info', `Worker '${workerName}' deleted successfully`);
return true; return true;

View File

@ -34,7 +34,7 @@ export class CloudflareZone {
*/ */
public static createFromApiObject( public static createFromApiObject(
apiObject: plugins.ICloudflareTypes['Zone'], apiObject: plugins.ICloudflareTypes['Zone'],
cfAccount?: CloudflareAccount cfAccount?: CloudflareAccount,
): CloudflareZone { ): CloudflareZone {
const cloudflareZone = new CloudflareZone(); const cloudflareZone = new CloudflareZone();
Object.assign(cloudflareZone, apiObject); Object.assign(cloudflareZone, apiObject);
@ -62,7 +62,7 @@ export class CloudflareZone {
*/ */
public async enableDevelopmentMode( public async enableDevelopmentMode(
cfAccount?: CloudflareAccount, cfAccount?: CloudflareAccount,
duration: number = 10800 duration: number = 10800,
): Promise<CloudflareZone> { ): Promise<CloudflareZone> {
const account = cfAccount || this.cfAccount; const account = cfAccount || this.cfAccount;
if (!account) { if (!account) {
@ -76,7 +76,7 @@ export class CloudflareZone {
// We'll use the request method for this specific case // We'll use the request method for this specific case
await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, { await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, {
value: 'on', value: 'on',
time: duration time: duration,
}); });
this.development_mode = duration; this.development_mode = duration;
@ -104,7 +104,7 @@ export class CloudflareZone {
// The official client doesn't have a direct method for development mode // The official client doesn't have a direct method for development mode
// We'll use the request method for this specific case // We'll use the request method for this specific case
await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, { await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, {
value: 'off' value: 'off',
}); });
this.development_mode = 0; this.development_mode = 0;
@ -131,7 +131,7 @@ export class CloudflareZone {
try { try {
await account.apiAccount.cache.purge({ await account.apiAccount.cache.purge({
zone_id: this.id, zone_id: this.id,
purge_everything: true purge_everything: true,
}); });
return true; return true;
} catch (error) { } catch (error) {
@ -161,7 +161,7 @@ export class CloudflareZone {
try { try {
await account.apiAccount.cache.purge({ await account.apiAccount.cache.purge({
zone_id: this.id, zone_id: this.id,
files: urls files: urls,
}); });
return true; return true;
} catch (error) { } catch (error) {
@ -189,7 +189,7 @@ export class CloudflareZone {
} }
// If they're different, and current nameservers are Cloudflare's // If they're different, and current nameservers are Cloudflare's
return this.name_servers.some(ns => ns.includes('cloudflare')); return this.name_servers.some((ns) => ns.includes('cloudflare'));
} }
/** /**
@ -205,7 +205,7 @@ export class CloudflareZone {
vanity_name_servers: string[]; vanity_name_servers: string[];
type: 'full' | 'partial' | 'secondary'; type: 'full' | 'partial' | 'secondary';
}>, }>,
cfAccount?: CloudflareAccount cfAccount?: CloudflareAccount,
): Promise<CloudflareZone> { ): Promise<CloudflareZone> {
const account = cfAccount || this.cfAccount; const account = cfAccount || this.cfAccount;
if (!account) { if (!account) {
@ -219,7 +219,7 @@ export class CloudflareZone {
const response: { result: interfaces.ICflareZone } = await account.request( const response: { result: interfaces.ICflareZone } = await account.request(
'PATCH', 'PATCH',
`/zones/${this.id}`, `/zones/${this.id}`,
settings settings,
); );
Object.assign(this, response.result); Object.assign(this, response.result);

View File

@ -30,7 +30,7 @@ export class ZoneManager {
zones.push(zone); zones.push(zone);
} }
return zones.map(zone => CloudflareZone.createFromApiObject(zone, this.cfAccount)); return zones.map((zone) => CloudflareZone.createFromApiObject(zone, this.cfAccount));
} catch (error) { } catch (error) {
logger.log('error', `Failed to fetch zones: ${error.message}`); logger.log('error', `Failed to fetch zones: ${error.message}`);
return []; return [];
@ -44,7 +44,7 @@ export class ZoneManager {
*/ */
public async getZoneByName(zoneName: string): Promise<CloudflareZone | undefined> { public async getZoneByName(zoneName: string): Promise<CloudflareZone | undefined> {
const zones = await this.getZones(zoneName); const zones = await this.getZones(zoneName);
return zones.find(zone => zone.name === zoneName); return zones.find((zone) => zone.name === zoneName);
} }
/** /**
@ -57,7 +57,7 @@ export class ZoneManager {
// Use the request method instead of the zones.get method to avoid type issues // Use the request method instead of the zones.get method to avoid type issues
const response: { result: interfaces.ICflareZone } = await this.cfAccount.request( const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
'GET', 'GET',
`/zones/${zoneId}` `/zones/${zoneId}`,
); );
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount); return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
@ -77,7 +77,7 @@ export class ZoneManager {
public async createZone( public async createZone(
zoneName: string, zoneName: string,
jumpStart: boolean = false, jumpStart: boolean = false,
accountId?: string accountId?: string,
): Promise<CloudflareZone | undefined> { ): Promise<CloudflareZone | undefined> {
const useAccountId = accountId || this.cfAccount.preselectedAccountId; const useAccountId = accountId || this.cfAccount.preselectedAccountId;
@ -95,8 +95,8 @@ export class ZoneManager {
{ {
name: zoneName, name: zoneName,
jump_start: jumpStart, jump_start: jumpStart,
account: { id: useAccountId } account: { id: useAccountId },
} },
); );
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount); return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
@ -131,7 +131,7 @@ export class ZoneManager {
*/ */
public async zoneExists(zoneName: string): Promise<boolean> { public async zoneExists(zoneName: string): Promise<boolean> {
const zones = await this.getZones(zoneName); const zones = await this.getZones(zoneName);
return zones.some(zone => zone.name === zoneName); return zones.some((zone) => zone.name === zoneName);
} }
/** /**
@ -148,8 +148,8 @@ export class ZoneManager {
'PATCH', 'PATCH',
`/zones/${zoneId}`, `/zones/${zoneId}`,
{ {
status: 'active' status: 'active',
} },
); );
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount); return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
@ -171,7 +171,7 @@ export class ZoneManager {
// For this specific endpoint, we'll use the request method // For this specific endpoint, we'll use the request method
const response: { result: interfaces.ICflareZone } = await this.cfAccount.request( const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
'PUT', 'PUT',
`/zones/${zoneId}/activation_check` `/zones/${zoneId}/activation_check`,
); );
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount); return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);

View File

@ -49,9 +49,23 @@ export class CloudflareUtils {
*/ */
public static isValidRecordType(type: string): boolean { public static isValidRecordType(type: string): boolean {
const validTypes: plugins.tsclass.network.TDnsRecordType[] = [ const validTypes: plugins.tsclass.network.TDnsRecordType[] = [
'A', 'AAAA', 'CNAME', 'TXT', 'SRV', 'LOC', 'MX', 'A',
'NS', 'CAA', 'CERT', 'DNSKEY', 'DS', 'NAPTR', 'SMIMEA', 'AAAA',
'SSHFP', 'TLSA', 'URI' 'CNAME',
'TXT',
'SRV',
'LOC',
'MX',
'NS',
'CAA',
'CERT',
'DNSKEY',
'DS',
'NAPTR',
'SMIMEA',
'SSHFP',
'TLSA',
'URI',
// Note: SPF has been removed as it's not in TDnsRecordType // Note: SPF has been removed as it's not in TDnsRecordType
]; ];
return validTypes.includes(type as any); return validTypes.includes(type as any);
@ -108,7 +122,10 @@ export class CloudflareUtils {
* @returns Combined results from all pages * @returns Combined results from all pages
*/ */
public static async paginateResults<T>( public static async paginateResults<T>(
makeRequest: (page: number, perPage: number) => Promise<{ result: T[], result_info: { total_pages: number } }> makeRequest: (
page: number,
perPage: number,
) => Promise<{ result: T[]; result_info: { total_pages: number } }>,
): Promise<T[]> { ): Promise<T[]> {
const perPage = 50; // Cloudflare's maximum const perPage = 50; // Cloudflare's maximum
let page = 1; let page = 1;

View File

@ -1,5 +1,9 @@
export { CloudflareAccount } from './cloudflare.classes.account.js'; export { CloudflareAccount } from './cloudflare.classes.account.js';
export { CloudflareWorker, type IWorkerRoute, type IWorkerRouteDefinition } from './cloudflare.classes.worker.js'; export {
CloudflareWorker,
type IWorkerRoute,
type IWorkerRouteDefinition,
} from './cloudflare.classes.worker.js';
export { WorkerManager } from './cloudflare.classes.workermanager.js'; export { WorkerManager } from './cloudflare.classes.workermanager.js';
export { CloudflareRecord, type ICloudflareRecordInfo } from './cloudflare.classes.record.js'; export { CloudflareRecord, type ICloudflareRecordInfo } from './cloudflare.classes.record.js';
export { CloudflareZone } from './cloudflare.classes.zone.js'; export { CloudflareZone } from './cloudflare.classes.zone.js';

View File

@ -6,7 +6,9 @@
"module": "NodeNext", "module": "NodeNext",
"moduleResolution": "NodeNext", "moduleResolution": "NodeNext",
"esModuleInterop": true, "esModuleInterop": true,
"verbatimModuleSyntax": true "verbatimModuleSyntax": true,
"baseUrl": ".",
"paths": {}
}, },
"exclude": [ "exclude": [
"dist_*/**/*.d.ts" "dist_*/**/*.d.ts"