switch to official cloudflare api client while keeping class based approach

This commit is contained in:
Philipp Kunz 2024-06-15 19:47:09 +02:00
parent 1d2e0974b2
commit f39f8cd33c
9 changed files with 160 additions and 264 deletions

View File

@ -32,7 +32,8 @@
"@push.rocks/smartpromise": "^4.0.2", "@push.rocks/smartpromise": "^4.0.2",
"@push.rocks/smartrequest": "^2.0.15", "@push.rocks/smartrequest": "^2.0.15",
"@push.rocks/smartstring": "^4.0.5", "@push.rocks/smartstring": "^4.0.5",
"@tsclass/tsclass": "^4.0.42" "@tsclass/tsclass": "^4.0.58",
"cloudflare": "^3.2.0"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.1.66", "@git.zone/tsbuild": "^2.1.66",

View File

@ -24,8 +24,11 @@ importers:
specifier: ^4.0.5 specifier: ^4.0.5
version: 4.0.15 version: 4.0.15
'@tsclass/tsclass': '@tsclass/tsclass':
specifier: ^4.0.42 specifier: ^4.0.58
version: 4.0.55 version: 4.0.58
cloudflare:
specifier: ^3.2.0
version: 3.2.0
devDependencies: devDependencies:
'@git.zone/tsbuild': '@git.zone/tsbuild':
specifier: ^2.1.66 specifier: ^2.1.66
@ -629,8 +632,8 @@ packages:
'@tsclass/tsclass@3.0.48': '@tsclass/tsclass@3.0.48':
resolution: {integrity: sha512-hC65UvDlp9qvsl6OcIZXz0JNiWZ0gyzsTzbXpg215sGxopgbkOLCr6E0s4qCTnweYm95gt2AdY95uP7M7kExaQ==} resolution: {integrity: sha512-hC65UvDlp9qvsl6OcIZXz0JNiWZ0gyzsTzbXpg215sGxopgbkOLCr6E0s4qCTnweYm95gt2AdY95uP7M7kExaQ==}
'@tsclass/tsclass@4.0.55': '@tsclass/tsclass@4.0.58':
resolution: {integrity: sha512-zg774JF90/3/rJ7xk4LyGgxcUzxdKIQcwtBVxez4LhvegESxvHiFmX42WL105iBpE53ISJ8sctLWlwG1JQZdlA==} resolution: {integrity: sha512-H9b9m83TXMEF+xrW4IdGO0vGgIdC6t/Cv55bHHzUbbFxR+AgcPxMxMKtEYjkwrwtl4QNYez3Q5VuomF3WqaiIA==}
'@tsconfig/node10@1.0.11': '@tsconfig/node10@1.0.11':
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
@ -770,6 +773,12 @@ packages:
'@types/ms@0.7.34': '@types/ms@0.7.34':
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
'@types/node-fetch@2.6.11':
resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
'@types/node@18.19.34':
resolution: {integrity: sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==}
'@types/node@20.14.2': '@types/node@20.14.2':
resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==} resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==}
@ -865,6 +874,10 @@ packages:
resolution: {integrity: sha512-G0D3mv9jvR+5xILENchPP9v1ZjBf3QVlzarMLR5jedCNbgntzcayF0LeW5wh5uyafGZJH28cYm9jGrJvGipoPQ==} resolution: {integrity: sha512-G0D3mv9jvR+5xILENchPP9v1ZjBf3QVlzarMLR5jedCNbgntzcayF0LeW5wh5uyafGZJH28cYm9jGrJvGipoPQ==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
accepts@1.3.8: accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -1085,6 +1098,9 @@ packages:
resolution: {integrity: sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=} resolution: {integrity: sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=}
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
cloudflare@3.2.0:
resolution: {integrity: sha512-L6X3ky8rj+vFv6wf+/MxVVkwzMcxm+rjHtPAznHejYp3UC3ESovv+z8a6SZv6uXIXkAXHbCMCsbegiM4NNvXsg==}
co-body@6.2.0: co-body@6.2.0:
resolution: {integrity: sha512-Kbpv2Yd1NdL1V/V4cwLVxraHDV6K8ayohr2rmH0J87Er8+zJjcTa6dAn9QMPC9CRgU8+aNajKbSf1TzDB1yKPA==} resolution: {integrity: sha512-Kbpv2Yd1NdL1V/V4cwLVxraHDV6K8ayohr2rmH0J87Er8+zJjcTa6dAn9QMPC9CRgU8+aNajKbSf1TzDB1yKPA==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
@ -1385,6 +1401,10 @@ packages:
resolution: {integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=} resolution: {integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
event-target-shim@5.0.1:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
eventemitter3@4.0.7: eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
@ -1466,6 +1486,9 @@ packages:
resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==}
engines: {node: '>=14'} engines: {node: '>=14'}
form-data-encoder@1.7.2:
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
form-data-encoder@2.1.4: form-data-encoder@2.1.4:
resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
engines: {node: '>= 14.17'} engines: {node: '>= 14.17'}
@ -1478,6 +1501,10 @@ packages:
resolution: {integrity: sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=} resolution: {integrity: sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=}
engines: {node: '>=0.4.x'} engines: {node: '>=0.4.x'}
formdata-node@4.4.1:
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
engines: {node: '>= 12.20'}
forwarded@0.2.0: forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -2183,6 +2210,10 @@ packages:
no-case@2.3.2: no-case@2.3.2:
resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
node-fetch@2.6.7: node-fetch@2.6.7:
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
engines: {node: 4.x || >=6.0.0} engines: {node: 4.x || >=6.0.0}
@ -2887,6 +2918,14 @@ packages:
web-namespaces@2.0.1: web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
web-streams-polyfill@4.0.0-beta.3:
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
engines: {node: '>= 14'}
webidl-conversions@3.0.1: webidl-conversions@3.0.1:
resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=} resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=}
@ -3080,7 +3119,7 @@ snapshots:
'@push.rocks/taskbuffer': 3.1.7 '@push.rocks/taskbuffer': 3.1.7
'@push.rocks/webrequest': 3.0.37 '@push.rocks/webrequest': 3.0.37
'@push.rocks/webstore': 2.0.20 '@push.rocks/webstore': 2.0.20
'@tsclass/tsclass': 4.0.55 '@tsclass/tsclass': 4.0.58
'@types/express': 4.17.21 '@types/express': 4.17.21
body-parser: 1.20.2 body-parser: 1.20.2
cors: 2.8.5 cors: 2.8.5
@ -3587,7 +3626,7 @@ snapshots:
'@push.rocks/smartlog-interfaces@3.0.2': '@push.rocks/smartlog-interfaces@3.0.2':
dependencies: dependencies:
'@api.global/typedrequest-interfaces': 2.0.2 '@api.global/typedrequest-interfaces': 2.0.2
'@tsclass/tsclass': 4.0.55 '@tsclass/tsclass': 4.0.58
'@push.rocks/smartlog@3.0.7': '@push.rocks/smartlog@3.0.7':
dependencies: dependencies:
@ -3667,7 +3706,7 @@ snapshots:
'@push.rocks/smartpromise': 4.0.3 '@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartpuppeteer': 2.0.2 '@push.rocks/smartpuppeteer': 2.0.2
'@push.rocks/smartunique': 3.0.9 '@push.rocks/smartunique': 3.0.9
'@tsclass/tsclass': 4.0.55 '@tsclass/tsclass': 4.0.58
'@types/express': 4.17.21 '@types/express': 4.17.21
express: 4.19.2 express: 4.19.2
pdf-lib: 1.17.1 pdf-lib: 1.17.1
@ -3725,7 +3764,7 @@ snapshots:
'@push.rocks/smartxml': 1.0.8 '@push.rocks/smartxml': 1.0.8
'@push.rocks/smartyaml': 2.0.5 '@push.rocks/smartyaml': 2.0.5
'@push.rocks/webrequest': 3.0.37 '@push.rocks/webrequest': 3.0.37
'@tsclass/tsclass': 4.0.55 '@tsclass/tsclass': 4.0.58
'@push.rocks/smartsocket@2.0.27': '@push.rocks/smartsocket@2.0.27':
dependencies: dependencies:
@ -3859,7 +3898,7 @@ snapshots:
dependencies: dependencies:
'@pushrocks/smartdelay': 3.0.1 '@pushrocks/smartdelay': 3.0.1
'@pushrocks/smartpromise': 4.0.2 '@pushrocks/smartpromise': 4.0.2
'@tsclass/tsclass': 4.0.55 '@tsclass/tsclass': 4.0.58
'@push.rocks/webstore@2.0.20': '@push.rocks/webstore@2.0.20':
dependencies: dependencies:
@ -4035,7 +4074,7 @@ snapshots:
dependencies: dependencies:
type-fest: 2.19.0 type-fest: 2.19.0
'@tsclass/tsclass@4.0.55': '@tsclass/tsclass@4.0.58':
dependencies: dependencies:
type-fest: 4.20.0 type-fest: 4.20.0
@ -4198,6 +4237,15 @@ snapshots:
'@types/ms@0.7.34': {} '@types/ms@0.7.34': {}
'@types/node-fetch@2.6.11':
dependencies:
'@types/node': 20.14.2
form-data: 4.0.0
'@types/node@18.19.34':
dependencies:
undici-types: 5.26.5
'@types/node@20.14.2': '@types/node@20.14.2':
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
@ -4349,6 +4397,10 @@ snapshots:
- supports-color - supports-color
- utf-8-validate - utf-8-validate
abort-controller@3.0.0:
dependencies:
event-target-shim: 5.0.1
accepts@1.3.8: accepts@1.3.8:
dependencies: dependencies:
mime-types: 2.1.35 mime-types: 2.1.35
@ -4575,6 +4627,21 @@ snapshots:
clone@2.1.2: {} clone@2.1.2: {}
cloudflare@3.2.0:
dependencies:
'@types/node': 18.19.34
'@types/node-fetch': 2.6.11
'@types/qs': 6.9.15
abort-controller: 3.0.0
agentkeepalive: 4.5.0
form-data-encoder: 1.7.2
formdata-node: 4.4.1
node-fetch: 2.7.0
qs: 6.12.1
web-streams-polyfill: 3.3.3
transitivePeerDependencies:
- encoding
co-body@6.2.0: co-body@6.2.0:
dependencies: dependencies:
'@hapi/bourne': 3.0.0 '@hapi/bourne': 3.0.0
@ -4847,6 +4914,8 @@ snapshots:
etag@1.8.1: {} etag@1.8.1: {}
event-target-shim@5.0.1: {}
eventemitter3@4.0.7: {} eventemitter3@4.0.7: {}
express-force-ssl@0.3.2: express-force-ssl@0.3.2:
@ -4980,6 +5049,8 @@ snapshots:
cross-spawn: 7.0.3 cross-spawn: 7.0.3
signal-exit: 4.1.0 signal-exit: 4.1.0
form-data-encoder@1.7.2: {}
form-data-encoder@2.1.4: {} form-data-encoder@2.1.4: {}
form-data@4.0.0: form-data@4.0.0:
@ -4990,6 +5061,11 @@ snapshots:
format@0.2.2: {} format@0.2.2: {}
formdata-node@4.4.1:
dependencies:
node-domexception: 1.0.0
web-streams-polyfill: 4.0.0-beta.3
forwarded@0.2.0: {} forwarded@0.2.0: {}
fresh@0.5.2: {} fresh@0.5.2: {}
@ -5955,6 +6031,8 @@ snapshots:
dependencies: dependencies:
lower-case: 1.1.4 lower-case: 1.1.4
node-domexception@1.0.0: {}
node-fetch@2.6.7: node-fetch@2.6.7:
dependencies: dependencies:
whatwg-url: 5.0.0 whatwg-url: 5.0.0
@ -6701,6 +6779,10 @@ snapshots:
web-namespaces@2.0.1: {} web-namespaces@2.0.1: {}
web-streams-polyfill@3.3.3: {}
web-streams-polyfill@4.0.0-beta.3: {}
webidl-conversions@3.0.1: {} webidl-conversions@3.0.1: {}
webidl-conversions@4.0.2: {} webidl-conversions@4.0.2: {}

View File

@ -18,6 +18,7 @@ tap.test('.listZones() -> should display an entire account', async (tools) => {
tools.timeout(600000); tools.timeout(600000);
const result = await testCloudflareAccount.convenience.listZones(); const result = await testCloudflareAccount.convenience.listZones();
console.log(result); console.log(result);
await tools.delayFor(10000);
}); });
tap.test( tap.test(

View File

@ -13,24 +13,17 @@ export class CloudflareAccount {
public workerManager = new WorkerManager(this); public workerManager = new WorkerManager(this);
public zoneManager = new ZoneManager(this); public zoneManager = new ZoneManager(this);
public apiAccount: plugins.cloudflare.Cloudflare;
/** /**
* constructor sets auth information on the CloudflareAccountInstance * constructor sets auth information on the CloudflareAccountInstance
* @param optionsArg * @param optionsArg
*/ */
constructor(authTokenArg: string) { constructor(authTokenArg: string) {
this.authToken = authTokenArg; this.authToken = authTokenArg;
} this.apiAccount = new plugins.cloudflare.Cloudflare({
apiToken: this.authToken,
/** });
* gets you the account identifier
*/
public async getAccountIdentifier() {
if (!this.accountIdentifier) {
const route = `/accounts?page=1&per_page=20&direction=desc`;
const response: any = await this.request('GET', route);
this.accountIdentifier = response.result[0].id;
}
return this.accountIdentifier;
} }
public convenience = { public convenience = {
@ -59,7 +52,7 @@ export class CloudflareAccount {
getRecord: async ( getRecord: async (
domainNameArg: string, domainNameArg: string,
typeArg: plugins.tsclass.network.TDnsRecordType typeArg: plugins.tsclass.network.TDnsRecordType
): Promise<interfaces.ICflareRecord> => { ): Promise<plugins.ICloudflareTypes['Record']> => {
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);
const filteredResponse = recordArrayArg.filter((recordArg) => { const filteredResponse = recordArrayArg.filter((recordArg) => {
@ -77,18 +70,14 @@ export class CloudflareAccount {
ttlArg = 1 ttlArg = 1
): Promise<any> => { ): Promise<any> => {
const domain = new plugins.smartstring.Domain(domainNameArg); const domain = new plugins.smartstring.Domain(domainNameArg);
const domainIdArg = await this.convenience.getZoneId(domain.zoneName); const zoneId = await this.convenience.getZoneId(domain.zoneName);
const dataObject = { const response = await this.apiAccount.dns.records.create({
zone_id: zoneId,
type: typeArg as any,
name: domain.fullName, name: domain.fullName,
type: typeArg,
content: contentArg, content: contentArg,
ttl: ttlArg, ttl: ttlArg,
}; })
const response = await this.request(
'POST',
'/zones/' + domainIdArg + '/dns_records',
dataObject
);
return response; return response;
}, },
/** /**
@ -101,20 +90,36 @@ export class CloudflareAccount {
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 cflareRecord = await this.convenience.getRecord(domain.fullName, typeArg); const zoneId = await this.convenience.getZoneId(domain.zoneName);
if (cflareRecord) { const records = await this.convenience.listRecords(domain.zoneName);
const requestRoute: string = `/zones/${cflareRecord.zone_id}/dns_records/${cflareRecord.id}`; const recordToDelete = records.find((recordArg) => {
return await this.request('DELETE', requestRoute); return recordArg.name === domainNameArg && recordArg.type === typeArg;
});
if (recordToDelete) {
await this.apiAccount.dns.records.delete(recordToDelete.id, {
zone_id: zoneId,
});
} else { } else {
throw new Error(`could not remove record for ${domainNameArg} with type ${typeArg}`); logger.log('warn', `record ${domainNameArg} of type ${typeArg} not found`);
} }
}, },
/** /**
* cleanrecord allows the cleaning of any previous records to avoid unwanted sideeffects * cleanrecord allows the cleaning of any previous records to avoid unwanted sideeffects
*/ */
cleanRecord: async (domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType) => { cleanRecord: async (domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType) => {
console.log(`cleaning record for ${domainNameArg}`); console.log(`cleaning record for ${domainNameArg}`);
const records = await this.convenience.listRecords(domainNameArg);
const recordsToDelete = records.filter((recordArg) => {
return recordArg.type === typeArg;
});
for (const recordToDelete of recordsToDelete) {
await this.apiAccount.dns.records.delete(recordToDelete.id, {
zone_id: recordToDelete.zone_id,
});
}
}, },
/** /**
* updates a record * updates a record
* @param domainNameArg * @param domainNameArg
@ -133,45 +138,40 @@ export class CloudflareAccount {
* list all records of a specified domain name * list all records of a specified domain name
* @param domainNameArg - the domain name that you want to get the records from * @param domainNameArg - the domain name that you want to get the records from
*/ */
listRecords: async (domainNameArg: string): Promise<interfaces.ICflareRecord[]> => { listRecords: async (domainNameArg: string) => {
const domain = new plugins.smartstring.Domain(domainNameArg); const domain = new plugins.smartstring.Domain(domainNameArg);
const domainId = await this.convenience.getZoneId(domain.zoneName); const zoneId = await this.convenience.getZoneId(domain.zoneName);
const responseArg: any = await this.request( const records: plugins.ICloudflareTypes['Record'][] = [];
'GET', for await (const record of this.apiAccount.dns.records.list({
'/zones/' + domainId + '/dns_records?per_page=100' zone_id: zoneId,
); })) {
const result: interfaces.ICflareRecord[] = responseArg.result; records.push(record);
return result; }
return records;
}, },
/** /**
* list all zones in the associated authenticated account * list all zones in the associated authenticated account
* @param domainName * @param domainName
*/ */
listZones: async (domainName?: string): Promise<interfaces.ICflareZone[]> => { listZones: async (domainName?: string) => {
// TODO: handle pagination const zones: plugins.ICloudflareTypes['Zone'][] = [];
let requestRoute = `/zones?per_page=50`; for await (const zone of this.apiAccount.zones.list()) {
zones.push(zone);
// may be optionally filtered by domain name
if (domainName) {
requestRoute = `${requestRoute}&name=${domainName}`;
} }
return zones;
const response: any = await this.request('GET', requestRoute);
const result = response.result;
return result;
}, },
/** /**
* purges a zone * purges a zone
*/ */
purgeZone: async (domainName: string): Promise<void> => { purgeZone: async (domainName: string): Promise<void> => {
const domain = new plugins.smartstring.Domain(domainName); const domain = new plugins.smartstring.Domain(domainName);
const domainId = await this.convenience.getZoneId(domain.zoneName); const zoneId = await this.convenience.getZoneId(domain.zoneName);
const requestUrl = `/zones/${domainId}/purge_cache`; await this.apiAccount.cache.purge({
const payload = { zone_id: zoneId,
purge_everything: true, purge_everything: true,
}; });
const respone = await this.request('DELETE', requestUrl, payload);
}, },
// acme convenience functions // acme convenience functions
acmeSetDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => { acmeSetDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => {
await this.convenience.cleanRecord(dnsChallenge.hostName, 'TXT'); await this.convenience.cleanRecord(dnsChallenge.hostName, 'TXT');
@ -186,105 +186,4 @@ export class CloudflareAccount {
await this.convenience.removeRecord(dnsChallenge.hostName, 'TXT'); await this.convenience.removeRecord(dnsChallenge.hostName, 'TXT');
}, },
}; };
public async request(
methodArg: string,
routeArg: string,
dataArg: any = {},
requestHeadersArg = {}
): Promise<any> {
const options: plugins.smartrequest.ISmartRequestOptions = {
method: methodArg,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.authToken}`,
'Content-Length': Buffer.byteLength(JSON.stringify(dataArg)),
...requestHeadersArg,
},
requestBody: dataArg,
};
// route analysis
const routeWithoutQuery = routeArg.split('?')[0];
let queryParams: string[] = [];
if (routeArg.split('?').length > 1) {
queryParams = routeArg.split('?')[1].split('&');
}
// console.log(options);
let retryCount = 0; // count the amount of retries
let pageCount = 1;
const getQueryParams = () => {
let result = '';
if (queryParams.length > 0) {
result += '?';
} else {
return result;
}
let isFirst = true;
for (const queryParam of queryParams) {
if (!isFirst) {
result += '&';
}
isFirst = false;
const queryParamSerialized = queryParam.split('=');
if (queryParam === 'page') {
result += `page=${pageCount}`;
} else {
result += queryParam;
}
}
return result;
};
const makeRequest = async (): Promise<plugins.smartrequest.IExtendedIncomingMessage> => {
const requestUrl = `https://api.cloudflare.com/client/v4${routeWithoutQuery}${getQueryParams()}`;
const response = await plugins.smartrequest.request(requestUrl, options);
if (response.statusCode === 200) {
if (response.body.result_info) {
const rI = response.body.result_info;
if (rI.total_count / rI.per_page > pageCount) {
pageCount++;
const subresponse = await makeRequest();
response.body.result = response.body.result.concat(subresponse.body.result);
return response;
} else {
return response;
}
} else {
return response;
}
} else if (response.statusCode === 429) {
console.log('rate limited! Waiting for retry!');
return await retryRequest();
} else if (response.statusCode === 400) {
console.log(`bad request for route ${requestUrl}!`);
console.log(response.body);
throw new Error(`request failed for ${requestUrl}`);
} else {
console.log(response.body);
throw new Error(`request failed for ${requestUrl} with status${response.statusCode}}`);
}
};
const retryRequest = async (
delayTimeArg = Math.floor(Math.random() * (60000 - 8000) + 8000)
) => {
console.log(`retry started and waiting for ${delayTimeArg} ms`);
await plugins.smartdelay.delayFor(delayTimeArg);
if (retryCount < 10) {
retryCount++;
return await makeRequest();
}
};
const response = await makeRequest();
return response.body;
}
private authCheck() {
return !!this.authToken; // check if auth is available
}
} }

View File

@ -1,50 +1,9 @@
import * as plugins from './cloudflare.plugins.js'; import * as plugins from './cloudflare.plugins.js';
import * as interfaces from './interfaces/index.js';
export class CloudflareZone implements interfaces.ICflareZone { export class CloudflareZone {
public static createFromApiObject(apiObject: interfaces.ICflareZone) { public static createFromApiObject(apiObject: plugins.ICloudflareTypes['Zone']) {
const cloudflareZone = new CloudflareZone(); const cloudflareZone = new CloudflareZone();
Object.assign(cloudflareZone, apiObject); Object.assign(cloudflareZone, apiObject);
return cloudflareZone; return cloudflareZone;
} }
id: string;
name: string;
development_mode: number;
original_name_servers: string[];
original_registrar: string;
original_dnshost: string;
created_on: string;
modified_on: string;
name_servers: string[];
owner: {
id: string;
email: string;
owner_type: string;
};
permissions: string[];
plan: {
id: string;
name: string;
price: number;
currency: string;
frequency: string;
legacy_id: string;
is_subscribed: boolean;
can_subscribe: boolean;
};
plan_pending: {
id: string;
name: string;
price: number;
currency: string;
frequency: string;
legacy_id: string;
is_subscribed: string;
can_subscribe: string;
};
status: string;
paused: boolean;
type: string;
checked_on: string;
} }

View File

@ -6,3 +6,15 @@ import * as smartstring from '@push.rocks/smartstring';
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';
export { smartlog, smartpromise, smartdelay, smartrequest, smartstring, tsclass }; export { smartlog, smartpromise, smartdelay, smartrequest, smartstring, tsclass };
// third party
import * as cloudflare from 'cloudflare';
import type { Zone } from 'cloudflare/resources/zones/zones.js';
import type { Record } from 'cloudflare/resources/dns/records.js';
export interface ICloudflareTypes {
Zone: Zone;
Record: Record;
}
export { cloudflare };

View File

@ -1,15 +0,0 @@
export interface ICflareRecord {
id: string;
type: string;
name: string;
content: string;
proxiable: boolean;
proxied: boolean;
ttl: number;
locked: boolean;
zone_id: string;
zone_name: string;
created_on: string;
modified_on: string;
data: any;
}

View File

@ -1,41 +0,0 @@
export interface ICflareZone {
id: string;
name: string;
development_mode: number;
original_name_servers: string[];
original_registrar: string;
original_dnshost: string;
created_on: string;
modified_on: string;
name_servers: string[];
owner: {
id: string;
email: string;
owner_type: string;
};
permissions: string[];
plan: {
id: string;
name: string;
price: number;
currency: string;
frequency: string;
legacy_id: string;
is_subscribed: boolean;
can_subscribe: boolean;
};
plan_pending: {
id: string;
name: string;
price: number;
currency: string;
frequency: string;
legacy_id: string;
is_subscribed: string;
can_subscribe: string;
};
status: string;
paused: boolean;
type: string;
checked_on: string;
}

View File

@ -1,3 +1 @@
export * from './cloudflare.api.record.js';
export * from './cloudflare.api.zone.js';
export * from './cloudflare.api.workerroute.js'; export * from './cloudflare.api.workerroute.js';