cloudflare-ddns-sync 3.0.2 → 4.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,19 +1,18 @@
1
- import { ScheduledTask } from 'node-cron';
2
- import { Auth, DomainRecordList, MultiSyncCallback, Record, RecordData } from './types/index.js';
1
+ import { Auth, MultiSyncCallback, Record } from './types/index.js';
3
2
  export default class CloudflareDDNSSync {
4
3
  private cloudflareClient;
5
4
  constructor(auth: Auth);
6
5
  getIp(): Promise<string>;
7
6
  getIpv6(): Promise<string>;
8
- getRecordDataForDomain(domain: string): Promise<Array<RecordData>>;
9
- getRecordDataForDomains(domains: Array<string>): Promise<DomainRecordList>;
10
- getRecordDataForRecord(record: Record): Promise<RecordData>;
11
- getRecordDataForRecords(records: Array<Record>): Promise<Array<RecordData>>;
7
+ getRecordDataForDomain(domain: string): Promise<import("cloudflare/resources/dns/records.mjs").DNSRecord[]>;
8
+ getRecordDataForDomains(domains: Array<string>): Promise<{}>;
9
+ getRecordDataForRecord(record: Record): Promise<import("cloudflare/resources/dns/records.mjs").DNSRecord>;
10
+ getRecordDataForRecords(records: Array<Record>): Promise<any[]>;
12
11
  removeRecord(recordName: string, recordType?: string): Promise<void>;
13
12
  stopSyncOnIpChange(changeListenerId: string): void;
14
- syncByCronTime(cronExpression: string, records: Array<Record>, callback: MultiSyncCallback, ip?: string): ScheduledTask;
13
+ syncByCronTime(cronExpression: string, records: Array<Record>, callback: MultiSyncCallback, ip?: string): import("node-cron").ScheduledTask;
15
14
  syncOnIpChange(records: Array<Record>, callback: MultiSyncCallback): Promise<string>;
16
- syncRecord(record: Record, ip?: string): Promise<RecordData>;
17
- syncRecords(records: Array<Record>, ip?: string): Promise<Array<RecordData>>;
15
+ syncRecord(record: Record, ip?: string): any;
16
+ syncRecords(records: Array<Record>, ip?: string): Promise<import("cloudflare/resources/dns/records.mjs").DNSRecord[]>;
18
17
  }
19
18
  export * from './types/index.js';
package/dist/index.js CHANGED
@@ -13,10 +13,10 @@ export default class CloudflareDDNSSync {
13
13
  return ipUtils.getIpv6();
14
14
  }
15
15
  getRecordDataForDomain(domain) {
16
- return this.cloudflareClient.getRecordDataForDomain(domain);
16
+ return this.cloudflareClient.getRecordsByDomain(domain);
17
17
  }
18
18
  getRecordDataForDomains(domains) {
19
- return this.cloudflareClient.getRecordDataForDomains(domains);
19
+ return this.cloudflareClient.getRecordsByDomains(domains);
20
20
  }
21
21
  getRecordDataForRecord(record) {
22
22
  return this.cloudflareClient.getRecordDataForRecord(record);
@@ -1,16 +1,16 @@
1
- import Cloudflare from 'cloudflare';
2
- import { DomainRecordList, Record, RecordData } from '../types/index.js';
1
+ import Cloudflare, { ClientOptions as CloudflareOptions } from 'cloudflare';
2
+ import { Record } from '../types/index.js';
3
3
  export default class CloudflareClient {
4
4
  private cloudflare;
5
5
  private zoneMap;
6
- constructor(auth: Cloudflare.AuthObject);
7
- syncRecord(record: Record, ip?: string): Promise<RecordData>;
8
- syncRecords(records: Array<Record>, ip?: string): Promise<Array<RecordData>>;
6
+ constructor(cloudflareOptions: CloudflareOptions);
7
+ syncRecord(record: Record, ip?: string): Promise<Cloudflare.DNS.Records.DNSRecord>;
8
+ syncRecords(records: Array<Record>, ip?: string): Promise<Cloudflare.DNS.Records.DNSRecord[]>;
9
9
  removeRecordByNameAndType(recordName: string, recordType?: string): Promise<void>;
10
- getRecordDataForRecord(record: Record): Promise<RecordData>;
11
- getRecordDataForRecords(records: Array<Record>): Promise<Array<RecordData>>;
12
- getRecordDataForDomains(domains: Array<string>): Promise<DomainRecordList>;
13
- getRecordDataForDomain(domain: string): Promise<Array<RecordData>>;
10
+ getRecordDataForRecord(record: Record): Promise<Cloudflare.DNS.Records.DNSRecord>;
11
+ getRecordDataForRecords(records: Array<Record>): Promise<any[]>;
12
+ getRecordsByDomains(domains: Array<string>): Promise<{}>;
13
+ getRecordsByDomain(domain: string): Promise<Cloudflare.DNS.Records.DNSRecord[]>;
14
14
  private createRecord;
15
15
  private updateRecord;
16
16
  private updateZoneMap;
@@ -19,7 +19,6 @@ export default class CloudflareClient {
19
19
  private getRecordByNameAndType;
20
20
  private getRecordIdsForRecords;
21
21
  private getRecordIdMapKey;
22
- private getRecordsByDomain;
23
22
  private getZoneIdByDomain;
24
23
  private getDomainsFromRecords;
25
24
  private getDomainByRecordName;
@@ -6,8 +6,8 @@ const ipv6Regex = /^(?:(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){6})(?:(?:(?:(?:(?:
6
6
  export default class CloudflareClient {
7
7
  cloudflare;
8
8
  zoneMap = new Map();
9
- constructor(auth) {
10
- this.cloudflare = new Cloudflare(auth);
9
+ constructor(cloudflareOptions) {
10
+ this.cloudflare = new Cloudflare(cloudflareOptions);
11
11
  this.updateZoneMap();
12
12
  }
13
13
  async syncRecord(record, ip) {
@@ -44,7 +44,7 @@ export default class CloudflareClient {
44
44
  const recordTypeToUse = recordType ? recordType : 'A';
45
45
  const zoneId = await this.getZoneIdByRecordName(recordName);
46
46
  const recordId = await this.getRecordIdByNameAndType(recordName, recordTypeToUse);
47
- await this.cloudflare.dnsRecords.del(zoneId, recordId);
47
+ await this.cloudflare.dns.records.delete(recordId, { zone_id: zoneId });
48
48
  }
49
49
  async getRecordDataForRecord(record) {
50
50
  const domain = this.getDomainByRecordName(record.name);
@@ -63,8 +63,8 @@ export default class CloudflareClient {
63
63
  const recordData = [].concat(...recordDataForDomains);
64
64
  return recordData;
65
65
  }
66
- async getRecordDataForDomains(domains) {
67
- const recordDataPromises = domains.map((domain) => this.getRecordDataForDomain(domain));
66
+ async getRecordsByDomains(domains) {
67
+ const recordDataPromises = domains.map((domain) => this.getRecordsByDomain(domain));
68
68
  const recordDataForDomains = await Promise.all(recordDataPromises);
69
69
  const recordData = {};
70
70
  recordDataForDomains.forEach((recordDataForDomain, index) => {
@@ -72,73 +72,83 @@ export default class CloudflareClient {
72
72
  });
73
73
  return recordData;
74
74
  }
75
- async getRecordDataForDomain(domain) {
76
- const recordData = await this.getRecordsByDomain(domain);
77
- return recordData;
78
- }
79
- async createRecord(zoneId, record, ip) {
80
- const dnsRecord = {
81
- ...record,
82
- name: record.name.toLowerCase(),
83
- content: record.content ? record.content : ip,
84
- type: record.type ? record.type : 'A',
85
- ttl: record.ttl ? record.ttl : 1,
75
+ async getRecordsByDomain(domain) {
76
+ const zoneId = await this.getZoneIdByDomain(domain);
77
+ const allRecords = [];
78
+ for await (const recordListResponse of this.cloudflare.dns.records.list({ zone_id: zoneId })) {
79
+ allRecords.push(recordListResponse);
80
+ }
81
+ return allRecords;
82
+ }
83
+ async createRecord(zoneId, recordData, ip) {
84
+ const dnsRecordToCreate = {
85
+ ...recordData,
86
+ name: recordData.name.toLowerCase(),
87
+ content: (recordData.content ? recordData.content : ip),
88
+ type: (recordData.type ? recordData.type : 'A'),
89
+ ttl: recordData.ttl ? recordData.ttl : 1,
90
+ zone_id: zoneId,
86
91
  };
87
- if (!dnsRecord.content) {
88
- throw Error(`Could not create Record "${dnsRecord.name}": Content is missing!`);
92
+ if (!dnsRecordToCreate.content) {
93
+ throw Error(`Could not create Record "${dnsRecordToCreate.name}": Content is missing!`);
89
94
  }
90
- if (dnsRecord.type === 'A') {
91
- if (!dnsRecord.content.match(ipv4Regex)) {
92
- throw Error(`Could not create Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv4!`);
95
+ if (dnsRecordToCreate.type === 'A') {
96
+ if (!dnsRecordToCreate.content.match(ipv4Regex)) {
97
+ throw Error(`Could not create Record "${dnsRecordToCreate.name}": '${dnsRecordToCreate.content}' is not a valid ipv4!`);
93
98
  }
94
99
  }
95
- else if (dnsRecord.type === 'AAAA') {
96
- if (!dnsRecord.content.match(ipv6Regex)) {
97
- throw Error(`Could not create Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv6!`);
100
+ else if (dnsRecordToCreate.type === 'AAAA') {
101
+ if (!dnsRecordToCreate.content.match(ipv6Regex)) {
102
+ throw Error(`Could not create Record "${dnsRecordToCreate.name}": '${dnsRecordToCreate.content}' is not a valid ipv6!`);
98
103
  }
99
104
  }
100
- else if (dnsRecord.type === 'CNAME') {
101
- const parsedDomain = parseDomain(fromUrl(dnsRecord.content));
105
+ else if (dnsRecordToCreate.type === 'CNAME') {
106
+ const parsedDomain = parseDomain(fromUrl(dnsRecordToCreate.content));
102
107
  if (parsedDomain.type !== ParseResultType.Listed || !parsedDomain.domain) {
103
- throw Error(`Could not create Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid domain name!`);
108
+ throw Error(`Could not create Record "${dnsRecordToCreate.name}": '${dnsRecordToCreate.content}' is not a valid domain name!`);
104
109
  }
105
110
  }
106
- const response = (await this.cloudflare.dnsRecords.add(zoneId, dnsRecord));
107
- return response.result;
111
+ return this.cloudflare.dns.records.create(dnsRecordToCreate);
108
112
  }
109
- async updateRecord(zoneId, recordId, record, ip) {
110
- const dnsRecord = {
111
- ...record,
112
- name: record.name.toLowerCase(),
113
- content: record.content ? record.content : ip,
114
- type: record.type ? record.type : 'A',
115
- ttl: record.ttl ? record.ttl : 1,
113
+ async updateRecord(zoneId, recordId, recordData, ip) {
114
+ const updatedDnsRecord = {
115
+ ...recordData,
116
+ name: recordData.name.toLowerCase(),
117
+ content: (recordData.content ? recordData.content : ip),
118
+ type: (recordData.type ? recordData.type : 'A'),
119
+ ttl: recordData.ttl ? recordData.ttl : 1,
120
+ zone_id: zoneId,
116
121
  };
117
- if (!dnsRecord.content) {
118
- throw Error(`Could not update Record "${dnsRecord.name}": Content is missing!`);
122
+ if (!updatedDnsRecord.content) {
123
+ throw Error(`Could not update Record "${updatedDnsRecord.name}": Content is missing!`);
119
124
  }
120
- if (dnsRecord.type === 'A') {
121
- if (!dnsRecord.content.match(ipv4Regex)) {
122
- throw Error(`Could not update Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv4!`);
125
+ if (updatedDnsRecord.type === 'A') {
126
+ if (!updatedDnsRecord.content.match(ipv4Regex)) {
127
+ throw Error(`Could not update Record "${updatedDnsRecord.name}": '${updatedDnsRecord.content}' is not a valid ipv4!`);
123
128
  }
124
129
  }
125
- else if (dnsRecord.type === 'AAAA') {
126
- if (!dnsRecord.content.match(ipv6Regex)) {
127
- throw Error(`Could not update Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid ipv6!`);
130
+ else if (updatedDnsRecord.type === 'AAAA') {
131
+ if (!updatedDnsRecord.content.match(ipv6Regex)) {
132
+ throw Error(`Could not update Record "${updatedDnsRecord.name}": '${updatedDnsRecord.content}' is not a valid ipv6!`);
128
133
  }
129
134
  }
130
- else if (dnsRecord.type === 'CNAME') {
131
- const parsedDomain = parseDomain(fromUrl(dnsRecord.content));
135
+ else if (updatedDnsRecord.type === 'CNAME') {
136
+ const parsedDomain = parseDomain(fromUrl(updatedDnsRecord.content));
132
137
  if (parsedDomain.type !== ParseResultType.Listed || !parsedDomain.domain) {
133
- throw Error(`Could not update Record "${dnsRecord.name}": '${dnsRecord.content}' is not a valid domain name!`);
138
+ throw Error(`Could not update Record "${updatedDnsRecord.name}": '${updatedDnsRecord.content}' is not a valid domain name!`);
134
139
  }
135
140
  }
136
- const response = (await this.cloudflare.dnsRecords.edit(zoneId, recordId, dnsRecord));
137
- return response.result;
141
+ return await this.cloudflare.dns.records.edit(recordId, updatedDnsRecord);
138
142
  }
139
143
  async updateZoneMap() {
140
- const response = (await this.cloudflare.zones.browse());
141
- const zones = response.result;
144
+ const response = await this.cloudflare.zones.list();
145
+ let zones = response.result;
146
+ let nextPageExists = response.hasNextPage();
147
+ while (nextPageExists) {
148
+ const nextPageResponse = await response.getNextPage();
149
+ zones = zones.concat(nextPageResponse.result);
150
+ nextPageExists = nextPageResponse.hasNextPage();
151
+ }
142
152
  this.zoneMap = new Map();
143
153
  for (const zone of zones) {
144
154
  this.zoneMap.set(zone.name, zone.id);
@@ -175,23 +185,6 @@ export default class CloudflareClient {
175
185
  const recordType = record.type ? record.type.toLowerCase() : 'a';
176
186
  return `"${recordName}"_"${recordType}"`;
177
187
  }
178
- async getRecordsByDomain(domain) {
179
- const zoneId = await this.getZoneIdByDomain(domain);
180
- const records = [];
181
- let pageIndex = 1;
182
- let allRecordsFound = false;
183
- const recordsPerPage = 5000;
184
- while (!allRecordsFound) {
185
- const response = (await this.cloudflare.dnsRecords.browse(zoneId, {
186
- page: pageIndex,
187
- per_page: recordsPerPage,
188
- }));
189
- records.push(...response.result);
190
- allRecordsFound = response.result.length < recordsPerPage;
191
- pageIndex++;
192
- }
193
- return records;
194
- }
195
188
  async getZoneIdByDomain(domain) {
196
189
  if (this.zoneMap.has(domain)) {
197
190
  const zoneId = this.zoneMap.get(domain.toLowerCase());
@@ -1,3 +1,2 @@
1
- import { RecordData } from './index.js';
2
- export type SingleSyncCallback = (syncResult: RecordData) => void;
3
- export type MultiSyncCallback = (syncResult: Array<RecordData>) => void;
1
+ import Cloudflare from 'cloudflare';
2
+ export type MultiSyncCallback = (syncResult: Cloudflare.DNS.DNSRecord[]) => void;
@@ -0,0 +1,2 @@
1
+ import { ClientOptions } from 'cloudflare';
2
+ export type Auth = ClientOptions;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,2 @@
1
- import { RecordTypes as CloudflareRecordTypes } from 'cloudflare';
2
- export type RecordTypes = Exclude<CloudflareRecordTypes, 'MX' | 'SRV' | 'URI'>;
3
- export type Record = {
4
- name: string;
5
- type?: RecordTypes;
6
- proxied?: boolean;
7
- ttl?: number;
8
- priority?: number;
9
- content?: string;
10
- };
1
+ import { Cloudflare } from 'cloudflare';
2
+ export type Record = Cloudflare.DNS.DNSRecord;
@@ -1,6 +1,4 @@
1
- export * from './cloudflare/index.js';
2
- export * from './Auth.js';
1
+ export * from './CloudflareOptions.js';
3
2
  export * from './Callbacks.js';
4
- export * from './DomainRecordList.js';
5
3
  export * from './Record.js';
6
4
  export * from './ZoneMap.js';
@@ -1,6 +1,4 @@
1
- export * from './cloudflare/index.js';
2
- export * from './Auth.js';
1
+ export * from './CloudflareOptions.js';
3
2
  export * from './Callbacks.js';
4
- export * from './DomainRecordList.js';
5
3
  export * from './Record.js';
6
4
  export * from './ZoneMap.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-ddns-sync",
3
- "version": "3.0.2",
3
+ "version": "4.0.0-beta.2",
4
4
  "description": "A simple module to update DNS records on Cloudflare whenever you want",
5
5
  "main": "dist/index.js",
6
6
  "author": "Steffen Knaup <SteffenKnaup@hotmail.de>",
@@ -29,7 +29,7 @@
29
29
  "test:coverage-report": "c8 report"
30
30
  },
31
31
  "dependencies": {
32
- "cloudflare": "2.9.1",
32
+ "cloudflare": "3.0.0",
33
33
  "node-cron": "3.0.3",
34
34
  "parse-domain": "8.0.2",
35
35
  "public-ip": "6.0.2"
@@ -39,13 +39,13 @@
39
39
  "@types/cloudflare": "^2.7.14",
40
40
  "@types/minimist": "1.2.5",
41
41
  "@types/mocha": "10.0.6",
42
- "@types/node": "20.11.30",
42
+ "@types/node": "20.12.7",
43
43
  "@types/node-cron": "3.0.11",
44
44
  "c8": "9.1.0",
45
45
  "chai": "5.1.0",
46
46
  "minimist": "1.2.8",
47
- "mocha": "10.3.0",
47
+ "mocha": "10.4.0",
48
48
  "prettier": "^3.2.5",
49
- "typescript": "5.4.3"
49
+ "typescript": "5.4.5"
50
50
  }
51
51
  }