fix(ci): Update CI workflows, repository URL, and apply minor code formatting fixes
This commit is contained in:
		
							
								
								
									
										66
									
								
								.gitea/workflows/default_nottags.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								.gitea/workflows/default_nottags.yaml
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										124
									
								
								.gitea/workflows/default_tags.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								.gitea/workflows/default_tags.yaml
									
									
									
									
									
										Normal 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
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -3,7 +3,6 @@
 | 
			
		||||
# artifacts
 | 
			
		||||
coverage/
 | 
			
		||||
public/
 | 
			
		||||
pages/
 | 
			
		||||
 | 
			
		||||
# installs
 | 
			
		||||
node_modules/
 | 
			
		||||
@@ -17,4 +16,4 @@ node_modules/
 | 
			
		||||
dist/
 | 
			
		||||
dist_*/
 | 
			
		||||
 | 
			
		||||
# custom
 | 
			
		||||
#------# custom
 | 
			
		||||
@@ -1,5 +1,13 @@
 | 
			
		||||
# 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)
 | 
			
		||||
Bump dependency versions and add domain support check in CloudflareAccount
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								package.json
									
									
									
									
									
								
							@@ -14,7 +14,7 @@
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://gitlab.com/pushrocks/cflare.git"
 | 
			
		||||
    "url": "https://gitlab.com/mojoio/cloudflare.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "Cloudflare",
 | 
			
		||||
@@ -31,9 +31,9 @@
 | 
			
		||||
  "author": "Lossless GmbH",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "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": {
 | 
			
		||||
    "@push.rocks/smartdelay": "^3.0.1",
 | 
			
		||||
    "@push.rocks/smartlog": "^3.0.2",
 | 
			
		||||
@@ -67,5 +67,8 @@
 | 
			
		||||
  "browserslist": [
 | 
			
		||||
    "last 1 chrome versions"
 | 
			
		||||
  ],
 | 
			
		||||
  "packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
 | 
			
		||||
}
 | 
			
		||||
  "packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6",
 | 
			
		||||
  "pnpm": {
 | 
			
		||||
    "overrides": {}
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								readme.md
									
									
									
									
									
								
							@@ -89,7 +89,7 @@ await myZone.purgeCache();
 | 
			
		||||
await myZone.purgeUrls(['https://example.com/css/styles.css', 'https://example.com/js/app.js']);
 | 
			
		||||
 | 
			
		||||
// Enable/disable development mode
 | 
			
		||||
await myZone.enableDevelopmentMode();  // Enables dev mode for 3 hours
 | 
			
		||||
await myZone.enableDevelopmentMode(); // Enables dev mode for 3 hours
 | 
			
		||||
await myZone.disableDevelopmentMode();
 | 
			
		||||
 | 
			
		||||
// Check zone status
 | 
			
		||||
@@ -126,11 +126,11 @@ await cfAccount.convenience.cleanRecord('example.com', 'TXT');
 | 
			
		||||
// Support for ACME DNS challenges (for certificate issuance)
 | 
			
		||||
await cfAccount.convenience.acmeSetDnsChallenge({
 | 
			
		||||
  hostName: '_acme-challenge.example.com',
 | 
			
		||||
  challenge: 'token-validation-string'
 | 
			
		||||
  challenge: 'token-validation-string',
 | 
			
		||||
});
 | 
			
		||||
await cfAccount.convenience.acmeRemoveDnsChallenge({
 | 
			
		||||
  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([
 | 
			
		||||
  {
 | 
			
		||||
    zoneName: 'example.com',
 | 
			
		||||
    pattern: 'https://api.example.com/*'
 | 
			
		||||
    pattern: 'https://api.example.com/*',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    zoneName: 'example.com',
 | 
			
		||||
    pattern: 'https://app.example.com/api/*'
 | 
			
		||||
  }
 | 
			
		||||
    pattern: 'https://app.example.com/api/*',
 | 
			
		||||
  },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
// Get all routes for a worker
 | 
			
		||||
@@ -191,19 +191,19 @@ async function manageCloudflare() {
 | 
			
		||||
  try {
 | 
			
		||||
    // Initialize with API token from environment variable
 | 
			
		||||
    const cfAccount = new cflare.CloudflareAccount(process.env.CLOUDFLARE_API_TOKEN);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Preselect account if needed
 | 
			
		||||
    await cfAccount.preselectAccountByName('My Company');
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Get zone and check status
 | 
			
		||||
    const myZone = await cfAccount.zoneManager.getZoneByName('example.com');
 | 
			
		||||
    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');
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Create a worker and set up routes
 | 
			
		||||
    const workerCode = `
 | 
			
		||||
    addEventListener('fetch', event => {
 | 
			
		||||
@@ -217,15 +217,13 @@ async function manageCloudflare() {
 | 
			
		||||
        event.respondWith(fetch(event.request));
 | 
			
		||||
      }
 | 
			
		||||
    })`;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    const worker = await cfAccount.workerManager.createWorker('api-handler', workerCode);
 | 
			
		||||
    await worker.setRoutes([
 | 
			
		||||
      { zoneName: 'example.com', pattern: 'https://api.example.com/*' }
 | 
			
		||||
    ]);
 | 
			
		||||
    
 | 
			
		||||
    await worker.setRoutes([{ zoneName: 'example.com', pattern: 'https://api.example.com/*' }]);
 | 
			
		||||
 | 
			
		||||
    // Purge cache for specific URLs
 | 
			
		||||
    await myZone.purgeUrls(['https://example.com/css/styles.css']);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    console.log('Configuration completed successfully');
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('Error managing Cloudflare:', error);
 | 
			
		||||
@@ -244,33 +242,43 @@ The main entry point for all Cloudflare operations.
 | 
			
		||||
```typescript
 | 
			
		||||
class CloudflareAccount {
 | 
			
		||||
  constructor(apiToken: string);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // Account management
 | 
			
		||||
  async listAccounts(): Promise<Array<ICloudflareTypes['Account']>>;
 | 
			
		||||
  async preselectAccountByName(accountName: string): Promise<void>;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // Managers
 | 
			
		||||
  readonly zoneManager: ZoneManager;
 | 
			
		||||
  readonly workerManager: WorkerManager;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // 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>;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // 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>;
 | 
			
		||||
    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>;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // ACME operations
 | 
			
		||||
    acmeSetDnsChallenge(dnsChallenge: IDnsChallenge): Promise<any>;
 | 
			
		||||
    acmeRemoveDnsChallenge(dnsChallenge: IDnsChallenge): Promise<any>;
 | 
			
		||||
@@ -291,7 +299,7 @@ class CloudflareZone {
 | 
			
		||||
  readonly paused: boolean;
 | 
			
		||||
  readonly type: string;
 | 
			
		||||
  readonly nameServers: string[];
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // Methods
 | 
			
		||||
  async purgeCache(): Promise<any>;
 | 
			
		||||
  async purgeUrls(urls: string[]): Promise<any>;
 | 
			
		||||
@@ -316,7 +324,7 @@ class CloudflareRecord {
 | 
			
		||||
  readonly content: string;
 | 
			
		||||
  readonly ttl: number;
 | 
			
		||||
  readonly proxied: boolean;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // Methods
 | 
			
		||||
  async update(content: string, ttl?: number): Promise<any>;
 | 
			
		||||
  async delete(): Promise<any>;
 | 
			
		||||
@@ -333,7 +341,7 @@ class CloudflareWorker {
 | 
			
		||||
  readonly id: string;
 | 
			
		||||
  readonly script: string;
 | 
			
		||||
  readonly routes: IWorkerRoute[];
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // Methods
 | 
			
		||||
  async getRoutes(): Promise<IWorkerRoute[]>;
 | 
			
		||||
  async setRoutes(routes: Array<IWorkerRouteDefinition>): Promise<void>;
 | 
			
		||||
@@ -396,4 +404,4 @@ pnpm run test
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
MIT © [Lossless GmbH](https://lossless.gmbh)
 | 
			
		||||
MIT © [Lossless GmbH](https://lossless.gmbh)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								test/test.ts
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								test/test.ts
									
									
									
									
									
								
							@@ -14,7 +14,9 @@ let testZoneName = `test-zone-${randomPrefix}.com`;
 | 
			
		||||
 | 
			
		||||
// Basic initialization tests
 | 
			
		||||
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.apiAccount).toBeTypeOf('object');
 | 
			
		||||
});
 | 
			
		||||
@@ -22,12 +24,12 @@ tap.test('should create a valid instance of CloudflareAccount', async () => {
 | 
			
		||||
tap.test('should preselect an account', async () => {
 | 
			
		||||
  await testCloudflareAccount.preselectAccountByName('Sandbox Account');
 | 
			
		||||
  expect(testCloudflareAccount.preselectedAccountId).toBeTypeOf('string');
 | 
			
		||||
})
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Zone management tests
 | 
			
		||||
tap.test('.listZones() -> should list zones in account', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const result = await testCloudflareAccount.convenience.listZones();
 | 
			
		||||
    // The test expects an array, but the current API might return an object with a result property
 | 
			
		||||
@@ -66,7 +68,7 @@ tap.test('ZoneManager: should get zone by name', async (tools) => {
 | 
			
		||||
// DNS record tests
 | 
			
		||||
tap.test('.listRecords(domainName) -> should list records for domain', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const records = await testCloudflareAccount.convenience.listRecords('bleu.de');
 | 
			
		||||
    // The test expects an array, but the current API might return an object with a result property
 | 
			
		||||
@@ -94,7 +96,7 @@ tap.test('should create A record for subdomain', async (tools) => {
 | 
			
		||||
    subdomain,
 | 
			
		||||
    'A',
 | 
			
		||||
    '127.0.0.1',
 | 
			
		||||
    120
 | 
			
		||||
    120,
 | 
			
		||||
  );
 | 
			
		||||
  expect(result).toBeTypeOf('object');
 | 
			
		||||
  console.log(`Created A record for ${subdomain}`);
 | 
			
		||||
@@ -107,7 +109,7 @@ tap.test('should create CNAME record for subdomain', async (tools) => {
 | 
			
		||||
    subdomain,
 | 
			
		||||
    'CNAME',
 | 
			
		||||
    'example.com',
 | 
			
		||||
    120
 | 
			
		||||
    120,
 | 
			
		||||
  );
 | 
			
		||||
  expect(result).toBeTypeOf('object');
 | 
			
		||||
  console.log(`Created CNAME record for ${subdomain}`);
 | 
			
		||||
@@ -120,7 +122,7 @@ tap.test('should create TXT record for subdomain', async (tools) => {
 | 
			
		||||
    subdomain,
 | 
			
		||||
    'TXT',
 | 
			
		||||
    'v=spf1 include:_spf.example.com ~all',
 | 
			
		||||
    120
 | 
			
		||||
    120,
 | 
			
		||||
  );
 | 
			
		||||
  expect(result).toBeTypeOf('object');
 | 
			
		||||
  console.log(`Created TXT record for ${subdomain}`);
 | 
			
		||||
@@ -142,7 +144,7 @@ tap.test('should update A record content', async (tools) => {
 | 
			
		||||
    subdomain,
 | 
			
		||||
    'A',
 | 
			
		||||
    '192.168.1.1',
 | 
			
		||||
    120
 | 
			
		||||
    120,
 | 
			
		||||
  );
 | 
			
		||||
  expect(result).toBeTypeOf('object');
 | 
			
		||||
  expect(result.content).toEqual('192.168.1.1');
 | 
			
		||||
@@ -157,7 +159,7 @@ tap.test('should create A record for nested subdomain', async (tools) => {
 | 
			
		||||
    nestedSubdomain,
 | 
			
		||||
    'A',
 | 
			
		||||
    '127.0.0.5',
 | 
			
		||||
    120
 | 
			
		||||
    120,
 | 
			
		||||
  );
 | 
			
		||||
  expect(result).toBeTypeOf('object');
 | 
			
		||||
  console.log(`Created nested A record for ${nestedSubdomain}`);
 | 
			
		||||
@@ -179,7 +181,7 @@ tap.test('should update A record for nested subdomain', async (tools) => {
 | 
			
		||||
    nestedSubdomain,
 | 
			
		||||
    'A',
 | 
			
		||||
    '127.0.0.6',
 | 
			
		||||
    120
 | 
			
		||||
    120,
 | 
			
		||||
  );
 | 
			
		||||
  expect(result).toBeTypeOf('object');
 | 
			
		||||
  expect(result.content).toEqual('127.0.0.6');
 | 
			
		||||
@@ -209,14 +211,14 @@ tap.test('should remove A and CNAME records', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  const aSubdomain = `${randomPrefix}-a-test.bleu.de`;
 | 
			
		||||
  const cnameSubdomain = `${randomPrefix}-cname-test.bleu.de`;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  await testCloudflareAccount.convenience.removeRecord(aSubdomain, 'A');
 | 
			
		||||
  await testCloudflareAccount.convenience.removeRecord(cnameSubdomain, 'CNAME');
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  // Verify records are removed
 | 
			
		||||
  const aRecord = await testCloudflareAccount.convenience.getRecord(aSubdomain, 'A');
 | 
			
		||||
  const cnameRecord = await testCloudflareAccount.convenience.getRecord(cnameSubdomain, 'CNAME');
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  expect(aRecord).toBeUndefined();
 | 
			
		||||
  expect(cnameRecord).toBeUndefined();
 | 
			
		||||
  console.log(`Successfully removed A and CNAME records`);
 | 
			
		||||
@@ -232,7 +234,7 @@ tap.test('.purgeZone() -> should purge zone cache', async (tools) => {
 | 
			
		||||
// Worker tests
 | 
			
		||||
tap.test('should list workers', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const workerArray = await testCloudflareAccount.workerManager.listWorkerScripts();
 | 
			
		||||
    expect(workerArray).toBeTypeOf('array');
 | 
			
		||||
@@ -246,7 +248,7 @@ tap.test('should list workers', async (tools) => {
 | 
			
		||||
 | 
			
		||||
tap.test('should create a worker', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const worker = await testCloudflareAccount.workerManager.createWorker(
 | 
			
		||||
      testWorkerName,
 | 
			
		||||
@@ -254,13 +256,13 @@ tap.test('should create a worker', async (tools) => {
 | 
			
		||||
        event.respondWith(new Response('Hello from Cloudflare Workers!', {
 | 
			
		||||
          headers: { 'content-type': 'text/plain' }
 | 
			
		||||
        }))
 | 
			
		||||
      })`
 | 
			
		||||
      })`,
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    expect(worker).toBeTypeOf('object');
 | 
			
		||||
    expect(worker.id).toEqual(testWorkerName);
 | 
			
		||||
    console.log(`Created worker: ${testWorkerName}`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // Set routes for the worker
 | 
			
		||||
      await worker.setRoutes([
 | 
			
		||||
@@ -269,7 +271,7 @@ tap.test('should create a worker', async (tools) => {
 | 
			
		||||
          pattern: `https://${testWorkerName}.bleu.de/*`,
 | 
			
		||||
        },
 | 
			
		||||
      ]);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      console.log(`Set routes for worker ${testWorkerName}`);
 | 
			
		||||
    } catch (routeError) {
 | 
			
		||||
      console.error(`Error setting routes: ${routeError.message}`);
 | 
			
		||||
@@ -284,7 +286,7 @@ tap.test('should create a worker', async (tools) => {
 | 
			
		||||
 | 
			
		||||
tap.test('should get a specific worker by name', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    // First create a worker to ensure it exists
 | 
			
		||||
    await testCloudflareAccount.workerManager.createWorker(
 | 
			
		||||
@@ -293,12 +295,12 @@ tap.test('should get a specific worker by name', async (tools) => {
 | 
			
		||||
        event.respondWith(new Response('Hello from Cloudflare Workers!', {
 | 
			
		||||
          headers: { 'content-type': 'text/plain' }
 | 
			
		||||
        }))
 | 
			
		||||
      })`
 | 
			
		||||
      })`,
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Now get the worker
 | 
			
		||||
    const worker = await testCloudflareAccount.workerManager.getWorker(testWorkerName);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    expect(worker).toBeTypeOf('object');
 | 
			
		||||
    expect(worker?.id).toEqual(testWorkerName);
 | 
			
		||||
    console.log(`Successfully retrieved worker: ${testWorkerName}`);
 | 
			
		||||
@@ -311,17 +313,17 @@ tap.test('should get a specific worker by name', async (tools) => {
 | 
			
		||||
 | 
			
		||||
tap.test('should update worker script', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const worker = await testCloudflareAccount.workerManager.getWorker(testWorkerName);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if (worker) {
 | 
			
		||||
      await worker.updateScript(`addEventListener('fetch', event => {
 | 
			
		||||
        event.respondWith(new Response('Updated Worker Script!', {
 | 
			
		||||
          headers: { 'content-type': 'text/plain' }
 | 
			
		||||
        }))
 | 
			
		||||
      })`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      console.log(`Updated script for worker ${testWorkerName}`);
 | 
			
		||||
      expect(true).toBeTrue();
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -338,10 +340,10 @@ tap.test('should update worker script', async (tools) => {
 | 
			
		||||
 | 
			
		||||
tap.test('should delete the test worker', async (tools) => {
 | 
			
		||||
  tools.timeout(600000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const worker = await testCloudflareAccount.workerManager.getWorker(testWorkerName);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if (worker) {
 | 
			
		||||
      const result = await worker.delete();
 | 
			
		||||
      console.log(`Deleted worker: ${testWorkerName}`);
 | 
			
		||||
@@ -381,4 +383,4 @@ tap.test('should format TTL values', async () => {
 | 
			
		||||
  expect(cloudflare.CloudflareUtils.formatTtl(999)).toEqual('999 seconds');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
tap.start();
 | 
			
		||||
tap.start();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@
 | 
			
		||||
 */
 | 
			
		||||
export const commitinfo = {
 | 
			
		||||
  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.'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,13 +39,13 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
    method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
 | 
			
		||||
    endpoint: string,
 | 
			
		||||
    data?: any,
 | 
			
		||||
    customHeaders?: Record<string, string>
 | 
			
		||||
    customHeaders?: Record<string, string>,
 | 
			
		||||
  ): Promise<T> {
 | 
			
		||||
    try {
 | 
			
		||||
      const options: plugins.smartrequest.ISmartRequestOptions = {
 | 
			
		||||
        method,
 | 
			
		||||
        headers: {
 | 
			
		||||
          'Authorization': `Bearer ${this.authToken}`,
 | 
			
		||||
          Authorization: `Bearer ${this.authToken}`,
 | 
			
		||||
          'Content-Type': 'application/json',
 | 
			
		||||
          ...customHeaders,
 | 
			
		||||
        },
 | 
			
		||||
@@ -62,13 +62,16 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      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)
 | 
			
		||||
      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()) {
 | 
			
		||||
@@ -80,13 +83,15 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        }
 | 
			
		||||
      } 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}...`]
 | 
			
		||||
          messages: [
 | 
			
		||||
            `Failed to parse: ${typeof response.body === 'string' ? response.body?.substring(0, 50) : typeof response.body}...`,
 | 
			
		||||
          ],
 | 
			
		||||
        } as T;
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -115,12 +120,12 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
    listAccounts: async () => {
 | 
			
		||||
      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) {
 | 
			
		||||
@@ -152,21 +157,24 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
     */
 | 
			
		||||
    getRecord: async (
 | 
			
		||||
      domainNameArg: string,
 | 
			
		||||
      typeArg: plugins.tsclass.network.TDnsRecordType
 | 
			
		||||
      typeArg: plugins.tsclass.network.TDnsRecordType,
 | 
			
		||||
    ): Promise<plugins.ICloudflareTypes['Record'] | undefined> => {
 | 
			
		||||
      try {
 | 
			
		||||
        const domain = new plugins.smartstring.Domain(domainNameArg);
 | 
			
		||||
        const recordArrayArg = await this.convenience.listRecords(domain.zoneName);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        const filteredResponse = recordArrayArg.filter((recordArg) => {
 | 
			
		||||
          return recordArg.type === typeArg && recordArg.name === domainNameArg;
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        return filteredResponse.length > 0 ? filteredResponse[0] : undefined;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        logger.log('error', `Error getting record for ${domainNameArg}: ${error.message}`);
 | 
			
		||||
@@ -180,7 +188,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
      domainNameArg: string,
 | 
			
		||||
      typeArg: plugins.tsclass.network.TDnsRecordType,
 | 
			
		||||
      contentArg: string,
 | 
			
		||||
      ttlArg = 1
 | 
			
		||||
      ttlArg = 1,
 | 
			
		||||
    ): Promise<any> => {
 | 
			
		||||
      const domain = new plugins.smartstring.Domain(domainNameArg);
 | 
			
		||||
      const zoneId = await this.convenience.getZoneId(domain.zoneName);
 | 
			
		||||
@@ -190,7 +198,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        name: domain.fullName,
 | 
			
		||||
        content: contentArg,
 | 
			
		||||
        ttl: ttlArg,
 | 
			
		||||
      })
 | 
			
		||||
      });
 | 
			
		||||
      return response;
 | 
			
		||||
    },
 | 
			
		||||
    /**
 | 
			
		||||
@@ -200,7 +208,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
     */
 | 
			
		||||
    removeRecord: async (
 | 
			
		||||
      domainNameArg: string,
 | 
			
		||||
      typeArg: plugins.tsclass.network.TDnsRecordType
 | 
			
		||||
      typeArg: plugins.tsclass.network.TDnsRecordType,
 | 
			
		||||
    ): Promise<any> => {
 | 
			
		||||
      const domain = new plugins.smartstring.Domain(domainNameArg);
 | 
			
		||||
      const zoneId = await this.convenience.getZoneId(domain.zoneName);
 | 
			
		||||
@@ -228,22 +236,28 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        logger.log('info', `Cleaning ${typeArg} records for ${domainNameArg}`);
 | 
			
		||||
        const domain = new plugins.smartstring.Domain(domainNameArg);
 | 
			
		||||
        const zoneId = await this.convenience.getZoneId(domain.zoneName);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // 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}`);
 | 
			
		||||
          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 && 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) {
 | 
			
		||||
          try {
 | 
			
		||||
            // The official client might have different property locations
 | 
			
		||||
@@ -253,7 +267,7 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
              logger.log('warn', `Record ID not found for ${domainNameArg} record`);
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            await this.apiAccount.dns.records.delete(recordId, {
 | 
			
		||||
              zone_id: zoneId,
 | 
			
		||||
            });
 | 
			
		||||
@@ -263,7 +277,10 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      } 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,19 +296,22 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
      domainNameArg: string,
 | 
			
		||||
      typeArg: plugins.tsclass.network.TDnsRecordType,
 | 
			
		||||
      contentArg: string,
 | 
			
		||||
      ttlArg: number = 1
 | 
			
		||||
      ttlArg: number = 1,
 | 
			
		||||
    ): Promise<plugins.ICloudflareTypes['Record']> => {
 | 
			
		||||
      const domain = new plugins.smartstring.Domain(domainNameArg);
 | 
			
		||||
      const zoneId = await this.convenience.getZoneId(domain.zoneName);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Find existing record
 | 
			
		||||
      const record = await this.convenience.getRecord(domainNameArg, typeArg);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      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);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Update the record - cast to any to access the id property
 | 
			
		||||
      const recordId = (record as any).id;
 | 
			
		||||
      const updatedRecord = await this.apiAccount.dns.records.edit(recordId, {
 | 
			
		||||
@@ -299,9 +319,9 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        type: typeArg as any,
 | 
			
		||||
        name: domain.fullName,
 | 
			
		||||
        content: contentArg,
 | 
			
		||||
        ttl: ttlArg
 | 
			
		||||
        ttl: ttlArg,
 | 
			
		||||
      });
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return updatedRecord;
 | 
			
		||||
    },
 | 
			
		||||
    /**
 | 
			
		||||
@@ -313,14 +333,14 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        const domain = new plugins.smartstring.Domain(domainNameArg);
 | 
			
		||||
        const zoneId = await this.convenience.getZoneId(domain.zoneName);
 | 
			
		||||
        const records: plugins.ICloudflareTypes['Record'][] = [];
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // 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) {
 | 
			
		||||
@@ -338,15 +358,18 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        if (domainName) {
 | 
			
		||||
          options.name = domainName;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        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}` : ''}`);
 | 
			
		||||
 | 
			
		||||
        logger.log(
 | 
			
		||||
          'info',
 | 
			
		||||
          `Found ${zones.length} zones${domainName ? ` matching ${domainName}` : ''}`,
 | 
			
		||||
        );
 | 
			
		||||
        return zones;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        logger.log('error', `Failed to list zones: ${error.message}`);
 | 
			
		||||
@@ -390,11 +413,11 @@ export class CloudflareAccount implements plugins.tsclass.network.IConvenientDns
 | 
			
		||||
        dnsChallenge.hostName,
 | 
			
		||||
        'TXT',
 | 
			
		||||
        dnsChallenge.challenge,
 | 
			
		||||
        120
 | 
			
		||||
        120,
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    acmeRemoveDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => {
 | 
			
		||||
      await this.convenience.removeRecord(dnsChallenge.hostName, 'TXT');
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,9 @@ export class CloudflareRecord {
 | 
			
		||||
   * @param apiObject Cloudflare DNS record API object
 | 
			
		||||
   * @returns CloudflareRecord instance
 | 
			
		||||
   */
 | 
			
		||||
  public static createFromApiObject(apiObject: plugins.ICloudflareTypes['Record']): CloudflareRecord {
 | 
			
		||||
  public static createFromApiObject(
 | 
			
		||||
    apiObject: plugins.ICloudflareTypes['Record'],
 | 
			
		||||
  ): CloudflareRecord {
 | 
			
		||||
    const record = new CloudflareRecord();
 | 
			
		||||
    Object.assign(record, apiObject);
 | 
			
		||||
    return record;
 | 
			
		||||
@@ -52,28 +54,28 @@ export class CloudflareRecord {
 | 
			
		||||
  public async update(
 | 
			
		||||
    cloudflareAccount: any,
 | 
			
		||||
    newContent: string,
 | 
			
		||||
    ttl?: number
 | 
			
		||||
    ttl?: number,
 | 
			
		||||
  ): Promise<CloudflareRecord> {
 | 
			
		||||
    logger.log('info', `Updating record ${this.name} (${this.type}) with new content`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    const updatedRecord = await cloudflareAccount.apiAccount.dns.records.edit(this.id, {
 | 
			
		||||
      zone_id: this.zone_id,
 | 
			
		||||
      type: this.type as any,
 | 
			
		||||
      name: this.name,
 | 
			
		||||
      content: newContent,
 | 
			
		||||
      ttl: ttl || this.ttl,
 | 
			
		||||
      proxied: this.proxied
 | 
			
		||||
      proxied: this.proxied,
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Update this instance
 | 
			
		||||
    this.content = newContent;
 | 
			
		||||
    if (ttl) {
 | 
			
		||||
      this.ttl = ttl;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Delete this record
 | 
			
		||||
   * @param cloudflareAccount The Cloudflare account to use
 | 
			
		||||
@@ -82,15 +84,15 @@ export class CloudflareRecord {
 | 
			
		||||
  public async delete(cloudflareAccount: any): Promise<boolean> {
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Deleting record ${this.name} (${this.type})`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      await cloudflareAccount.apiAccount.dns.records.delete(this.id, {
 | 
			
		||||
        zone_id: this.zone_id
 | 
			
		||||
        zone_id: this.zone_id,
 | 
			
		||||
      });
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to delete record: ${error.message}`);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ export class CloudflareWorker {
 | 
			
		||||
  // STATIC
 | 
			
		||||
  public static async fromApiObject(
 | 
			
		||||
    workerManager: WorkerManager,
 | 
			
		||||
    apiObject
 | 
			
		||||
    apiObject,
 | 
			
		||||
  ): Promise<CloudflareWorker> {
 | 
			
		||||
    const newWorker = new CloudflareWorker(workerManager);
 | 
			
		||||
    Object.assign(newWorker, apiObject);
 | 
			
		||||
@@ -46,33 +46,33 @@ export class CloudflareWorker {
 | 
			
		||||
  public async getRoutes() {
 | 
			
		||||
    try {
 | 
			
		||||
      this.routes = []; // Reset routes before fetching
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Get all zones using the async iterator
 | 
			
		||||
      const zones: plugins.ICloudflareTypes['Zone'][] = [];
 | 
			
		||||
      for await (const zone of this.workerManager.cfAccount.apiAccount.zones.list()) {
 | 
			
		||||
        zones.push(zone);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      if (zones.length === 0) {
 | 
			
		||||
        logger.log('warn', 'No zones found for the account');
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      for (const zone of zones) {
 | 
			
		||||
        try {
 | 
			
		||||
          if (!zone || !zone.id) {
 | 
			
		||||
            logger.log('warn', 'Zone is missing ID property');
 | 
			
		||||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          // Get worker routes for this zone
 | 
			
		||||
          const apiRoutes = [];
 | 
			
		||||
          for await (const route of this.workerManager.cfAccount.apiAccount.workers.routes.list({
 | 
			
		||||
            zone_id: zone.id
 | 
			
		||||
            zone_id: zone.id,
 | 
			
		||||
          })) {
 | 
			
		||||
            apiRoutes.push(route);
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          // Filter for routes that match this worker's ID
 | 
			
		||||
          for (const route of apiRoutes) {
 | 
			
		||||
            if (route.script === this.id) {
 | 
			
		||||
@@ -81,10 +81,13 @@ export class CloudflareWorker {
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } 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}`,
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      logger.log('info', `Found ${this.routes.length} routes for worker ${this.id}`);
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to get routes for worker ${this.id}: ${error.message}`);
 | 
			
		||||
@@ -100,60 +103,62 @@ export class CloudflareWorker {
 | 
			
		||||
  public async setRoutes(routeArray: IWorkerRouteDefinition[]) {
 | 
			
		||||
    // First get all existing routes to determine what we need to create/update
 | 
			
		||||
    await this.getRoutes();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    for (const newRoute of routeArray) {
 | 
			
		||||
      // Determine whether a route is new, needs an update, or is already up to date
 | 
			
		||||
      let routeStatus: 'new' | 'needsUpdate' | 'alreadyUpToDate' = 'new';
 | 
			
		||||
      let existingRouteId: string;
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      for (const existingRoute of this.routes) {
 | 
			
		||||
        if (existingRoute.pattern === newRoute.pattern) {
 | 
			
		||||
          routeStatus = 'needsUpdate';
 | 
			
		||||
          existingRouteId = existingRoute.id;
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          if (existingRoute.script === this.id) {
 | 
			
		||||
            routeStatus = 'alreadyUpToDate';
 | 
			
		||||
            logger.log('info', `Route ${newRoute.pattern} already exists, no update needed`);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        // 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) {
 | 
			
		||||
          logger.log('error', `Zone ${newRoute.zoneName} not found`);
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Handle route creation, update, or skip if already up to date
 | 
			
		||||
        if (routeStatus === 'new') {
 | 
			
		||||
          await this.workerManager.cfAccount.apiAccount.workers.routes.create({
 | 
			
		||||
            zone_id: zone.id,
 | 
			
		||||
            pattern: newRoute.pattern,
 | 
			
		||||
            script: this.id
 | 
			
		||||
            script: this.id,
 | 
			
		||||
          });
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          logger.log('info', `Created new route ${newRoute.pattern} for worker ${this.id}`);
 | 
			
		||||
        } else if (routeStatus === 'needsUpdate') {
 | 
			
		||||
          await this.workerManager.cfAccount.apiAccount.workers.routes.update(existingRouteId, {
 | 
			
		||||
            zone_id: zone.id,
 | 
			
		||||
            pattern: newRoute.pattern,
 | 
			
		||||
            script: this.id
 | 
			
		||||
            script: this.id,
 | 
			
		||||
          });
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          logger.log('info', `Updated route ${newRoute.pattern} for worker ${this.id}`);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        logger.log('error', `Failed to set route ${newRoute.pattern}: ${error.message}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Refresh routes after all changes
 | 
			
		||||
    await this.getRoutes();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Upload or update worker script content
 | 
			
		||||
   * @param scriptContent The worker script content
 | 
			
		||||
@@ -163,10 +168,10 @@ export class CloudflareWorker {
 | 
			
		||||
    if (!this.workerManager.cfAccount.preselectedAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Updating script for worker ${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 = {
 | 
			
		||||
@@ -175,23 +180,27 @@ export class CloudflareWorker {
 | 
			
		||||
      };
 | 
			
		||||
      updateParams['CF-WORKER-BODY-PART'] = 'script';
 | 
			
		||||
      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
 | 
			
		||||
      if (updatedWorker && typeof updatedWorker === 'object') {
 | 
			
		||||
        Object.assign(this, updatedWorker);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Always ensure the script property is updated
 | 
			
		||||
      this.script = scriptContent;
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return this;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to update worker script: ${error.message}`);
 | 
			
		||||
      throw error;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Delete this worker script
 | 
			
		||||
   * @returns True if deletion was successful
 | 
			
		||||
@@ -200,19 +209,19 @@ export class CloudflareWorker {
 | 
			
		||||
    if (!this.workerManager.cfAccount.preselectedAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Deleting worker ${this.id}`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Use the official client to delete the worker
 | 
			
		||||
      await this.workerManager.cfAccount.apiAccount.workers.scripts.delete(this.id, {
 | 
			
		||||
        account_id: this.workerManager.cfAccount.preselectedAccountId
 | 
			
		||||
        account_id: this.workerManager.cfAccount.preselectedAccountId,
 | 
			
		||||
      });
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to delete worker: ${error.message}`);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ export class WorkerManager {
 | 
			
		||||
    if (!this.cfAccount.preselectedAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // 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
 | 
			
		||||
@@ -31,12 +31,12 @@ export class WorkerManager {
 | 
			
		||||
      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);
 | 
			
		||||
      worker.id = workerName;
 | 
			
		||||
      worker.script = workerScript;
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Initialize the worker and get its routes
 | 
			
		||||
      try {
 | 
			
		||||
        await worker.getRoutes();
 | 
			
		||||
@@ -44,7 +44,7 @@ export class WorkerManager {
 | 
			
		||||
        logger.log('warn', `Failed to get routes for worker ${workerName}: ${routeError.message}`);
 | 
			
		||||
        // Continue anyway since the worker was created
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return worker;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to create worker ${workerName}: ${error.message}`);
 | 
			
		||||
@@ -61,22 +61,22 @@ export class WorkerManager {
 | 
			
		||||
    if (!this.cfAccount.preselectedAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // Get the worker script using the official client
 | 
			
		||||
      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
 | 
			
		||||
      const worker = new CloudflareWorker(this);
 | 
			
		||||
      worker.id = workerName;
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Save script content if available
 | 
			
		||||
      if (workerScript && typeof workerScript === 'object') {
 | 
			
		||||
        Object.assign(worker, workerScript);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Initialize the worker and get its routes
 | 
			
		||||
      try {
 | 
			
		||||
        await worker.getRoutes();
 | 
			
		||||
@@ -84,7 +84,7 @@ export class WorkerManager {
 | 
			
		||||
        logger.log('warn', `Failed to get routes for worker ${workerName}: ${routeError.message}`);
 | 
			
		||||
        // Continue anyway since we found the worker
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return worker;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('warn', `Worker '${workerName}' not found: ${error.message}`);
 | 
			
		||||
@@ -100,35 +100,35 @@ export class WorkerManager {
 | 
			
		||||
    if (!this.cfAccount.preselectedAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // Collect all scripts using the new client's async iterator
 | 
			
		||||
      const workerScripts: plugins.ICloudflareTypes['Script'][] = [];
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        for await (const script of this.cfAccount.apiAccount.workers.scripts.list({
 | 
			
		||||
          account_id: this.cfAccount.preselectedAccountId,
 | 
			
		||||
        })) {
 | 
			
		||||
          workerScripts.push(script);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        logger.log('info', `Found ${workerScripts.length} worker scripts`);
 | 
			
		||||
        return workerScripts;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        logger.log('warn', `Error while listing workers with async iterator: ${error.message}`);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // 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,
 | 
			
		||||
        }) as any;
 | 
			
		||||
        
 | 
			
		||||
        })) as any;
 | 
			
		||||
 | 
			
		||||
        // Check if the result has a 'result' property (older API response format)
 | 
			
		||||
        if (result && result.result && Array.isArray(result.result)) {
 | 
			
		||||
          logger.log('info', `Found ${result.result.length} worker scripts using direct result`);
 | 
			
		||||
          return result.result;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      logger.log('warn', 'Could not retrieve worker scripts');
 | 
			
		||||
      return [];
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -136,7 +136,7 @@ export class WorkerManager {
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Deletes a worker script
 | 
			
		||||
   * @param workerName Name of the worker to delete
 | 
			
		||||
@@ -146,10 +146,10 @@ export class WorkerManager {
 | 
			
		||||
    if (!this.cfAccount.preselectedAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      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`);
 | 
			
		||||
      return true;
 | 
			
		||||
@@ -158,4 +158,4 @@ export class WorkerManager {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ export class CloudflareZone {
 | 
			
		||||
  public account: interfaces.ICflareZone['account'];
 | 
			
		||||
  public permissions: string[];
 | 
			
		||||
  public plan: interfaces.ICflareZone['plan'];
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  private cfAccount?: CloudflareAccount; // Will be set when created through a manager
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -33,19 +33,19 @@ export class CloudflareZone {
 | 
			
		||||
   * @returns CloudflareZone instance
 | 
			
		||||
   */
 | 
			
		||||
  public static createFromApiObject(
 | 
			
		||||
    apiObject: plugins.ICloudflareTypes['Zone'], 
 | 
			
		||||
    cfAccount?: CloudflareAccount
 | 
			
		||||
    apiObject: plugins.ICloudflareTypes['Zone'],
 | 
			
		||||
    cfAccount?: CloudflareAccount,
 | 
			
		||||
  ): CloudflareZone {
 | 
			
		||||
    const cloudflareZone = new CloudflareZone();
 | 
			
		||||
    Object.assign(cloudflareZone, apiObject);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if (cfAccount) {
 | 
			
		||||
      cloudflareZone.cfAccount = cfAccount;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return cloudflareZone;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Check if development mode is currently active
 | 
			
		||||
   * @returns True if development mode is active
 | 
			
		||||
@@ -53,7 +53,7 @@ export class CloudflareZone {
 | 
			
		||||
  public isDevelopmentModeActive(): boolean {
 | 
			
		||||
    return this.development_mode > 0;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Enable development mode for the zone
 | 
			
		||||
   * @param cfAccount Cloudflare account to use if not already set
 | 
			
		||||
@@ -62,23 +62,23 @@ export class CloudflareZone {
 | 
			
		||||
   */
 | 
			
		||||
  public async enableDevelopmentMode(
 | 
			
		||||
    cfAccount?: CloudflareAccount,
 | 
			
		||||
    duration: number = 10800
 | 
			
		||||
    duration: number = 10800,
 | 
			
		||||
  ): Promise<CloudflareZone> {
 | 
			
		||||
    const account = cfAccount || this.cfAccount;
 | 
			
		||||
    if (!account) {
 | 
			
		||||
      throw new Error('CloudflareAccount is required to enable development mode');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    logger.log('info', `Enabling development mode for zone ${this.name}`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // The official client doesn't have a direct method for development mode
 | 
			
		||||
      // We'll use the request method for this specific case
 | 
			
		||||
      await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, {
 | 
			
		||||
        value: 'on',
 | 
			
		||||
        time: duration
 | 
			
		||||
        time: duration,
 | 
			
		||||
      });
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      this.development_mode = duration;
 | 
			
		||||
      return this;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -86,7 +86,7 @@ export class CloudflareZone {
 | 
			
		||||
      throw error;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Disable development mode for the zone
 | 
			
		||||
   * @param cfAccount Cloudflare account to use if not already set
 | 
			
		||||
@@ -97,16 +97,16 @@ export class CloudflareZone {
 | 
			
		||||
    if (!account) {
 | 
			
		||||
      throw new Error('CloudflareAccount is required to disable development mode');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    logger.log('info', `Disabling development mode for zone ${this.name}`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // The official client doesn't have a direct method for development mode
 | 
			
		||||
      // We'll use the request method for this specific case
 | 
			
		||||
      await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, {
 | 
			
		||||
        value: 'off'
 | 
			
		||||
        value: 'off',
 | 
			
		||||
      });
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      this.development_mode = 0;
 | 
			
		||||
      return this;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -114,7 +114,7 @@ export class CloudflareZone {
 | 
			
		||||
      throw error;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Purge all cached content for this zone
 | 
			
		||||
   * @param cfAccount Cloudflare account to use if not already set
 | 
			
		||||
@@ -125,13 +125,13 @@ export class CloudflareZone {
 | 
			
		||||
    if (!account) {
 | 
			
		||||
      throw new Error('CloudflareAccount is required to purge cache');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    logger.log('info', `Purging all cache for zone ${this.name}`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await account.apiAccount.cache.purge({
 | 
			
		||||
        zone_id: this.id,
 | 
			
		||||
        purge_everything: true
 | 
			
		||||
        purge_everything: true,
 | 
			
		||||
      });
 | 
			
		||||
      return true;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -139,7 +139,7 @@ export class CloudflareZone {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Purge specific URLs from the cache
 | 
			
		||||
   * @param urls Array of URLs to purge
 | 
			
		||||
@@ -151,17 +151,17 @@ export class CloudflareZone {
 | 
			
		||||
    if (!account) {
 | 
			
		||||
      throw new Error('CloudflareAccount is required to purge URLs');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if (!urls.length) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    logger.log('info', `Purging ${urls.length} URLs from cache for zone ${this.name}`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await account.apiAccount.cache.purge({
 | 
			
		||||
        zone_id: this.id,
 | 
			
		||||
        files: urls
 | 
			
		||||
        files: urls,
 | 
			
		||||
      });
 | 
			
		||||
      return true;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -169,7 +169,7 @@ export class CloudflareZone {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Check if the zone is active
 | 
			
		||||
   * @returns True if the zone is active
 | 
			
		||||
@@ -177,7 +177,7 @@ export class CloudflareZone {
 | 
			
		||||
  public isActive(): boolean {
 | 
			
		||||
    return this.status === 'active' && !this.paused;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Check if the zone is using Cloudflare nameservers
 | 
			
		||||
   * @returns True if using Cloudflare nameservers
 | 
			
		||||
@@ -187,11 +187,11 @@ export class CloudflareZone {
 | 
			
		||||
    if (!this.original_name_servers || !this.name_servers) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // 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'));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Update zone settings
 | 
			
		||||
   * @param settings Settings to update
 | 
			
		||||
@@ -205,23 +205,23 @@ export class CloudflareZone {
 | 
			
		||||
      vanity_name_servers: string[];
 | 
			
		||||
      type: 'full' | 'partial' | 'secondary';
 | 
			
		||||
    }>,
 | 
			
		||||
    cfAccount?: CloudflareAccount
 | 
			
		||||
    cfAccount?: CloudflareAccount,
 | 
			
		||||
  ): Promise<CloudflareZone> {
 | 
			
		||||
    const account = cfAccount || this.cfAccount;
 | 
			
		||||
    if (!account) {
 | 
			
		||||
      throw new Error('CloudflareAccount is required to update zone settings');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    logger.log('info', `Updating settings for zone ${this.name}`);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // Use the request method instead of zones.edit to avoid type issues
 | 
			
		||||
      const response: { result: interfaces.ICflareZone } = await account.request(
 | 
			
		||||
        'PATCH',
 | 
			
		||||
        `/zones/${this.id}`,
 | 
			
		||||
        settings
 | 
			
		||||
        settings,
 | 
			
		||||
      );
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      Object.assign(this, response.result);
 | 
			
		||||
      return this;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -229,4 +229,4 @@ export class CloudflareZone {
 | 
			
		||||
      throw error;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ export class ZoneManager {
 | 
			
		||||
  public async getZones(zoneName?: string): Promise<CloudflareZone[]> {
 | 
			
		||||
    try {
 | 
			
		||||
      const options: any = { per_page: 50 };
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // May be optionally filtered by domain name
 | 
			
		||||
      if (zoneName) {
 | 
			
		||||
        options.name = zoneName;
 | 
			
		||||
@@ -29,14 +29,14 @@ export class ZoneManager {
 | 
			
		||||
      for await (const zone of this.cfAccount.apiAccount.zones.list(options)) {
 | 
			
		||||
        zones.push(zone);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      return zones.map(zone => CloudflareZone.createFromApiObject(zone, this.cfAccount));
 | 
			
		||||
 | 
			
		||||
      return zones.map((zone) => CloudflareZone.createFromApiObject(zone, this.cfAccount));
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to fetch zones: ${error.message}`);
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get a single zone by name
 | 
			
		||||
   * @param zoneName Zone name to find
 | 
			
		||||
@@ -44,9 +44,9 @@ export class ZoneManager {
 | 
			
		||||
   */
 | 
			
		||||
  public async getZoneByName(zoneName: string): Promise<CloudflareZone | undefined> {
 | 
			
		||||
    const zones = await this.getZones(zoneName);
 | 
			
		||||
    return zones.find(zone => zone.name === zoneName);
 | 
			
		||||
    return zones.find((zone) => zone.name === zoneName);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get a zone by its ID
 | 
			
		||||
   * @param zoneId Zone ID to find
 | 
			
		||||
@@ -56,17 +56,17 @@ export class ZoneManager {
 | 
			
		||||
    try {
 | 
			
		||||
      // Use the request method instead of the zones.get method to avoid type issues
 | 
			
		||||
      const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
 | 
			
		||||
        'GET', 
 | 
			
		||||
        `/zones/${zoneId}`
 | 
			
		||||
        'GET',
 | 
			
		||||
        `/zones/${zoneId}`,
 | 
			
		||||
      );
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to fetch zone with ID ${zoneId}: ${error.message}`);
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new zone
 | 
			
		||||
   * @param zoneName Name of the zone to create
 | 
			
		||||
@@ -75,37 +75,37 @@ export class ZoneManager {
 | 
			
		||||
   * @returns The created zone
 | 
			
		||||
   */
 | 
			
		||||
  public async createZone(
 | 
			
		||||
    zoneName: string, 
 | 
			
		||||
    zoneName: string,
 | 
			
		||||
    jumpStart: boolean = false,
 | 
			
		||||
    accountId?: string
 | 
			
		||||
    accountId?: string,
 | 
			
		||||
  ): Promise<CloudflareZone | undefined> {
 | 
			
		||||
    const useAccountId = accountId || this.cfAccount.preselectedAccountId;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if (!useAccountId) {
 | 
			
		||||
      throw new Error('No account selected. Please select it first on the account.');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Creating zone ${zoneName}`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Use the request method for more direct control over the parameters
 | 
			
		||||
      const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
 | 
			
		||||
        'POST', 
 | 
			
		||||
        '/zones', 
 | 
			
		||||
        'POST',
 | 
			
		||||
        '/zones',
 | 
			
		||||
        {
 | 
			
		||||
          name: zoneName,
 | 
			
		||||
          jump_start: jumpStart,
 | 
			
		||||
          account: { id: useAccountId }
 | 
			
		||||
        }
 | 
			
		||||
          account: { id: useAccountId },
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to create zone ${zoneName}: ${error.message}`);
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Delete a zone
 | 
			
		||||
   * @param zoneId ID of the zone to delete
 | 
			
		||||
@@ -114,7 +114,7 @@ export class ZoneManager {
 | 
			
		||||
  public async deleteZone(zoneId: string): Promise<boolean> {
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Deleting zone with ID ${zoneId}`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Use the request method to avoid type issues
 | 
			
		||||
      await this.cfAccount.request('DELETE', `/zones/${zoneId}`);
 | 
			
		||||
      return true;
 | 
			
		||||
@@ -123,7 +123,7 @@ export class ZoneManager {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Check if a zone exists
 | 
			
		||||
   * @param zoneName Name of the zone to check
 | 
			
		||||
@@ -131,9 +131,9 @@ export class ZoneManager {
 | 
			
		||||
   */
 | 
			
		||||
  public async zoneExists(zoneName: string): Promise<boolean> {
 | 
			
		||||
    const zones = await this.getZones(zoneName);
 | 
			
		||||
    return zones.some(zone => zone.name === zoneName);
 | 
			
		||||
    return zones.some((zone) => zone.name === zoneName);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Activate a zone (if it's in pending status)
 | 
			
		||||
   * @param zoneId ID of the zone to activate
 | 
			
		||||
@@ -142,23 +142,23 @@ export class ZoneManager {
 | 
			
		||||
  public async activateZone(zoneId: string): Promise<CloudflareZone | undefined> {
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Activating zone with ID ${zoneId}`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // Use the request method for better control
 | 
			
		||||
      const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
 | 
			
		||||
        'PATCH', 
 | 
			
		||||
        'PATCH',
 | 
			
		||||
        `/zones/${zoneId}`,
 | 
			
		||||
        {
 | 
			
		||||
          status: 'active'
 | 
			
		||||
        }
 | 
			
		||||
          status: 'active',
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to activate zone with ID ${zoneId}: ${error.message}`);
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Check the activation status of a zone
 | 
			
		||||
   * @param zoneId ID of the zone to check
 | 
			
		||||
@@ -167,17 +167,17 @@ export class ZoneManager {
 | 
			
		||||
  public async checkZoneActivation(zoneId: string): Promise<CloudflareZone | undefined> {
 | 
			
		||||
    try {
 | 
			
		||||
      logger.log('info', `Checking activation for zone with ID ${zoneId}`);
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      // For this specific endpoint, we'll use the request method
 | 
			
		||||
      const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
 | 
			
		||||
        'PUT',
 | 
			
		||||
        `/zones/${zoneId}/activation_check`
 | 
			
		||||
        `/zones/${zoneId}/activation_check`,
 | 
			
		||||
      );
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      logger.log('error', `Failed to check zone activation with ID ${zoneId}: ${error.message}`);
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ export class CloudflareUtils {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Extracts the zone name (apex domain) from a full domain
 | 
			
		||||
   * @param domainName Domain name to process
 | 
			
		||||
@@ -31,7 +31,7 @@ export class CloudflareUtils {
 | 
			
		||||
      throw new Error(`Invalid domain name: ${domainName}`);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Checks if a string is a valid Cloudflare API token
 | 
			
		||||
   * @param token API token to validate
 | 
			
		||||
@@ -41,7 +41,7 @@ export class CloudflareUtils {
 | 
			
		||||
    // Cloudflare API tokens are typically 40+ characters long and start with specific patterns
 | 
			
		||||
    return /^[A-Za-z0-9_-]{40,}$/.test(token);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Validates a DNS record type
 | 
			
		||||
   * @param type DNS record type to validate
 | 
			
		||||
@@ -49,14 +49,28 @@ export class CloudflareUtils {
 | 
			
		||||
   */
 | 
			
		||||
  public static isValidRecordType(type: string): boolean {
 | 
			
		||||
    const validTypes: plugins.tsclass.network.TDnsRecordType[] = [
 | 
			
		||||
      'A', 'AAAA', 'CNAME', 'TXT', 'SRV', 'LOC', 'MX',
 | 
			
		||||
      'NS', 'CAA', 'CERT', 'DNSKEY', 'DS', 'NAPTR', 'SMIMEA',
 | 
			
		||||
      'SSHFP', 'TLSA', 'URI'
 | 
			
		||||
      'A',
 | 
			
		||||
      'AAAA',
 | 
			
		||||
      '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
 | 
			
		||||
    ];
 | 
			
		||||
    return validTypes.includes(type as any);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Formats a URL for cache purging (ensures it starts with http/https)
 | 
			
		||||
   * @param url URL to format
 | 
			
		||||
@@ -68,7 +82,7 @@ export class CloudflareUtils {
 | 
			
		||||
    }
 | 
			
		||||
    return url;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Converts a TTL value in seconds to a human-readable string
 | 
			
		||||
   * @param ttl TTL in seconds
 | 
			
		||||
@@ -101,20 +115,23 @@ export class CloudflareUtils {
 | 
			
		||||
      return `${ttl} seconds`;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Safely handles API pagination for Cloudflare requests
 | 
			
		||||
   * @param makeRequest Function that makes the API request with page parameters
 | 
			
		||||
   * @returns Combined results from all pages
 | 
			
		||||
   */
 | 
			
		||||
  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[]> {
 | 
			
		||||
    const perPage = 50; // Cloudflare's maximum
 | 
			
		||||
    let page = 1;
 | 
			
		||||
    let totalPages = 1;
 | 
			
		||||
    const allResults: T[] = [];
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
      try {
 | 
			
		||||
        const response = await makeRequest(page, perPage);
 | 
			
		||||
@@ -126,7 +143,7 @@ export class CloudflareUtils {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    } while (page <= totalPages);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return allResults;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
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 { CloudflareRecord, type ICloudflareRecordInfo } from './cloudflare.classes.record.js';
 | 
			
		||||
export { CloudflareZone } from './cloudflare.classes.zone.js';
 | 
			
		||||
@@ -8,4 +12,4 @@ export { CloudflareUtils } from './cloudflare.utils.js';
 | 
			
		||||
export { commitinfo } from './00_commitinfo_data.js';
 | 
			
		||||
 | 
			
		||||
// Re-export interfaces
 | 
			
		||||
export * from './interfaces/index.js';
 | 
			
		||||
export * from './interfaces/index.js';
 | 
			
		||||
 
 | 
			
		||||
@@ -17,4 +17,4 @@ export interface ICloudflareApiAccountObject {
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
  created_on: string; // Assuming ISO date string
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,4 +42,4 @@ export interface ICflareZone {
 | 
			
		||||
    legacy_discount: boolean;
 | 
			
		||||
    externally_managed: boolean;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,11 @@
 | 
			
		||||
    "module": "NodeNext",
 | 
			
		||||
    "moduleResolution": "NodeNext",
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "verbatimModuleSyntax": true
 | 
			
		||||
    "verbatimModuleSyntax": true,
 | 
			
		||||
    "baseUrl": ".",
 | 
			
		||||
    "paths": {}
 | 
			
		||||
  },
 | 
			
		||||
  "exclude": [
 | 
			
		||||
    "dist_*/**/*.d.ts"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user