cloudflare-ddns-sync 2.0.1 → 2.0.5

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/.eslintrc.json ADDED
@@ -0,0 +1,229 @@
1
+ {
2
+ "env": {
3
+ "es2021": true,
4
+ "node": true
5
+ },
6
+ "extends": [
7
+ "eslint:recommended",
8
+ "plugin:@typescript-eslint/recommended"
9
+ ],
10
+ "parser": "@typescript-eslint/parser",
11
+ "parserOptions": {
12
+ "ecmaVersion": "latest",
13
+ "sourceType": "module"
14
+ },
15
+ "plugins": [
16
+ "@typescript-eslint"
17
+ ],
18
+ "rules": {
19
+ "@typescript-eslint/ban-types": "off",
20
+ "@typescript-eslint/indent": ["error", 2],
21
+ "@typescript-eslint/no-shadow": "error",
22
+ "accessor-pairs": "error",
23
+ "array-bracket-newline": "error",
24
+ "array-bracket-spacing": "error",
25
+ "array-callback-return": "error",
26
+ "array-element-newline": "error",
27
+ "arrow-body-style": "error",
28
+ "arrow-parens": "error",
29
+ "arrow-spacing": "error",
30
+ "block-scoped-var": "error",
31
+ "block-spacing": "error",
32
+ "brace-style": "error",
33
+ "camelcase": "warn",
34
+ "capitalized-comments": "off",
35
+ "class-methods-use-this": "off",
36
+ "comma-dangle": ["error", "always-multiline"],
37
+ "comma-spacing": "error",
38
+ "comma-style": "error",
39
+ "complexity": "error",
40
+ "computed-property-spacing": "error",
41
+ "consistent-return": "error",
42
+ "consistent-this": "error",
43
+ "curly": "error",
44
+ "default-case": "error",
45
+ "default-case-last": "error",
46
+ "default-param-last": "error",
47
+ "dot-location": ["error", "property"],
48
+ "dot-notation": "error",
49
+ "eol-last": "error",
50
+ "eqeqeq": "error",
51
+ "func-call-spacing": "error",
52
+ "func-name-matching": "error",
53
+ "func-names": "error",
54
+ "func-style": ["error", "declaration", {
55
+ "allowArrowFunctions": true
56
+ }],
57
+ "function-call-argument-newline": ["error", "consistent"],
58
+ "function-paren-newline": "error",
59
+ "generator-star-spacing": "error",
60
+ "grouped-accessor-pairs": "error",
61
+ "guard-for-in": "error",
62
+ "id-denylist": "error",
63
+ "id-length": "off",
64
+ "id-match": "error",
65
+ "implicit-arrow-linebreak": "error",
66
+ "indent": "off",
67
+ "init-declarations": "off",
68
+ "key-spacing": "error",
69
+ "keyword-spacing": "error",
70
+ "line-comment-position": "error",
71
+ "linebreak-style": "error",
72
+ "lines-around-comment": "off",
73
+ "lines-between-class-members": "off",
74
+ "max-classes-per-file": "error",
75
+ "max-depth": "error",
76
+ "max-len": ["error", 150],
77
+ "max-lines": ["error", 1000],
78
+ "max-lines-per-function": "off",
79
+ "max-nested-callbacks": "error",
80
+ "max-params": ["warn", {"max": 4}],
81
+ "max-statements": "off",
82
+ "max-statements-per-line": "off",
83
+ "multiline-comment-style": "off",
84
+ "multiline-ternary": "off",
85
+ "new-cap": "error",
86
+ "new-parens": "error",
87
+ "newline-per-chained-call": "error",
88
+ "no-alert": "error",
89
+ "no-array-constructor": "error",
90
+ "no-await-in-loop": "off",
91
+ "no-bitwise": "error",
92
+ "no-caller": "error",
93
+ "no-confusing-arrow": "error",
94
+ "no-console": "error",
95
+ "no-constructor-return": "error",
96
+ "no-continue": "error",
97
+ "no-div-regex": "error",
98
+ "no-duplicate-imports": "error",
99
+ "no-else-return": "error",
100
+ "no-empty-function": "error",
101
+ "no-eq-null": "error",
102
+ "no-eval": "error",
103
+ "no-extend-native": "error",
104
+ "no-extra-bind": "error",
105
+ "no-extra-label": "error",
106
+ "no-extra-parens": "off",
107
+ "no-floating-decimal": "error",
108
+ "no-implicit-coercion": "error",
109
+ "no-implicit-globals": "error",
110
+ "no-implied-eval": "error",
111
+ "no-inline-comments": "error",
112
+ "no-invalid-this": "error",
113
+ "no-iterator": "error",
114
+ "no-label-var": "error",
115
+ "no-labels": "error",
116
+ "no-lone-blocks": "error",
117
+ "no-lonely-if": "error",
118
+ "no-loop-func": "error",
119
+ "no-magic-numbers": "off",
120
+ "no-mixed-operators": "error",
121
+ "no-multi-assign": "error",
122
+ "no-multi-spaces": "error",
123
+ "no-multi-str": "error",
124
+ "no-multiple-empty-lines": "error",
125
+ "no-negated-condition": "error",
126
+ "no-nested-ternary": "error",
127
+ "no-new": "error",
128
+ "no-new-func": "error",
129
+ "no-new-object": "error",
130
+ "no-new-wrappers": "error",
131
+ "no-octal-escape": "error",
132
+ "no-param-reassign": "error",
133
+ "no-plusplus": "off",
134
+ "no-promise-executor-return": "error",
135
+ "no-proto": "error",
136
+ "no-restricted-exports": "error",
137
+ "no-restricted-globals": "error",
138
+ "no-restricted-imports": "error",
139
+ "no-restricted-properties": "error",
140
+ "no-restricted-syntax": "error",
141
+ "no-return-assign": "error",
142
+ "no-return-await": "error",
143
+ "no-script-url": "error",
144
+ "no-self-compare": "error",
145
+ "no-sequences": "error",
146
+ "no-shadow": "off",
147
+ "no-tabs": "error",
148
+ "no-template-curly-in-string": "error",
149
+ "no-ternary": "off",
150
+ "no-throw-literal": "error",
151
+ "no-trailing-spaces": "error",
152
+ "no-undef-init": "error",
153
+ "no-undefined": "off",
154
+ "no-underscore-dangle": "error",
155
+ "no-unmodified-loop-condition": "error",
156
+ "no-unneeded-ternary": "error",
157
+ "no-unreachable-loop": "error",
158
+ "no-unused-expressions": "error",
159
+ "no-unused-private-class-members": "error",
160
+ "no-use-before-define": "off",
161
+ "no-useless-call": "error",
162
+ "no-useless-computed-key": "error",
163
+ "no-useless-concat": "error",
164
+ "no-useless-constructor": "error",
165
+ "no-useless-rename": "error",
166
+ "no-useless-return": "error",
167
+ "no-var": "error",
168
+ "no-void": "error",
169
+ "no-warning-comments": "error",
170
+ "no-whitespace-before-property": "error",
171
+ "nonblock-statement-body-position": "error",
172
+ "object-curly-newline": "error",
173
+ "object-curly-spacing": "error",
174
+ "object-property-newline": "error",
175
+ "object-shorthand": ["error", "never"],
176
+ "one-var": ["error", "never"],
177
+ "operator-assignment": "error",
178
+ "operator-linebreak": ["error", "before"],
179
+ "padded-blocks": ["error", "never"],
180
+ "padding-line-between-statements": "error",
181
+ "prefer-arrow-callback": "error",
182
+ "prefer-const": "error",
183
+ "prefer-destructuring": "error",
184
+ "prefer-exponentiation-operator": "error",
185
+ "prefer-named-capture-group": "off",
186
+ "prefer-numeric-literals": "error",
187
+ "prefer-object-spread": "error",
188
+ "prefer-promise-reject-errors": "error",
189
+ "prefer-regex-literals": "error",
190
+ "prefer-rest-params": "error",
191
+ "prefer-spread": "error",
192
+ "prefer-template": "error",
193
+ "quote-props": ["error", "as-needed"],
194
+ "quotes": ["error", "single"],
195
+ "radix": "error",
196
+ "require-atomic-updates": "error",
197
+ "require-await": "error",
198
+ "require-unicode-regexp": "error",
199
+ "rest-spread-spacing": "error",
200
+ "semi": "error",
201
+ "semi-spacing": "error",
202
+ "semi-style": "error",
203
+ "sort-imports": ["error", {
204
+ "ignoreCase": false,
205
+ "ignoreDeclarationSort": false,
206
+ "ignoreMemberSort": false,
207
+ "allowSeparatedGroups": true
208
+ }],
209
+ "sort-keys": "off",
210
+ "sort-vars": "error",
211
+ "space-before-blocks": "error",
212
+ "space-before-function-paren": ["error", "never"],
213
+ "space-in-parens": "error",
214
+ "space-infix-ops": "error",
215
+ "space-unary-ops": "error",
216
+ "spaced-comment": "error",
217
+ "strict": "error",
218
+ "switch-colon-spacing": "error",
219
+ "symbol-description": "error",
220
+ "template-curly-spacing": "error",
221
+ "template-tag-spacing": "error",
222
+ "unicode-bom": "error",
223
+ "vars-on-top": "error",
224
+ "wrap-iife": "error",
225
+ "wrap-regex": "error",
226
+ "yield-star-spacing": "error",
227
+ "yoda": "error"
228
+ }
229
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,135 @@
1
+ # Changelog
2
+
3
+ ## v2
4
+
5
+ ### v2.0.5
6
+
7
+ - 🚨 Replace tslint with eslint
8
+ - ⬆️ Update dependencies
9
+
10
+ ### v2.0.4
11
+
12
+ - 📝 Update links in README
13
+ - ⬆️ Update dependencies
14
+
15
+ ### v2.0.3
16
+
17
+ - ✨ **Add function to get ipv6 address**
18
+ - 🐛 **Fix syncing two records with the same name**
19
+ - 🐛 **Fix removing records if two records have the same name**
20
+ - ✏️ Fix typo in error messages
21
+ - 🐛 Make cloudflareClient private
22
+ - 📝 Update links in README
23
+
24
+ ### v2.0.2
25
+
26
+ - 🐛 **Fix Publishing**
27
+
28
+ ### v2.0.1
29
+
30
+ - ⬆️ Update Dependencies
31
+
32
+ ### v2.0.0
33
+
34
+ - ♻️ **Rewrite Cloudflare-DDNS-Sync in Typescript**
35
+
36
+ ## v1
37
+
38
+ ### v1.5.4
39
+
40
+ - 📝 Update README
41
+
42
+ ### v1.5.3
43
+
44
+ - 🐛 **Fix Stopping Sync On IP Change**
45
+ - 🐛 **Fix Crontime Converter For Hour**
46
+ - 🐛 **Fix Syncing With Crontime Without Setting an IP**
47
+ - ⚡️ **Small Performance Improvements**
48
+ - 💄 Improve Code Quality
49
+ - 💄 Extract Business Rules
50
+
51
+ ### v1.5.2
52
+
53
+ - 🐛 Fix Wrong Using of Const
54
+
55
+ ### v1.5.1
56
+
57
+ - 🐛 **Fix Bug When 'public-ip' Throws An Error**
58
+ - 💄 Improve Code Quality
59
+
60
+ ### v1.5.0
61
+
62
+ - ✨ **Add Create Not Existing Records Functionality**
63
+ - ✨ **Add Fallback getIp Function**
64
+
65
+ ### v1.4.0
66
+
67
+ - ✨ **Add Stop SyncOnIpChange Function**
68
+
69
+ ### v1.3.4
70
+
71
+ - 🐛 **Fix ipChange Interval**
72
+
73
+ ### v1.3.3
74
+
75
+ - 📝 **Add Changelog**
76
+
77
+ ### v1.3.2
78
+
79
+ - ✨ **Add getRecordIps Function**
80
+ - ♻️ **Refactor syncOnIpChange**
81
+ - ✅ **Add Tests for Sync Functionality**
82
+ - 📝 **Improve README**
83
+ - 📝 **Add NPM Badge**
84
+ - 🔥 Remove Unnecessary Code
85
+ - 🚸 Update Description
86
+ - 🎨 Order Dependencies
87
+ - 🎨 Lint files
88
+
89
+ ### v1.3.1
90
+
91
+ - 📝 **Fix README**
92
+
93
+ ### v1.3.0
94
+
95
+ - ✨ **Add syncAtDate Function**
96
+ - 📝 **Improve README**
97
+
98
+ ### v1.2.1
99
+
100
+ - 🚑 **Fix README**
101
+
102
+ ### v1.2.0
103
+
104
+ - ✨ **Add onIpChange Function**
105
+ - 📝 **Adjust README**
106
+ - 🚚 Move Utils to Lib
107
+ - 🚚 Move IP Functions to Lib
108
+ - 🚚 Move Dependencies to devDependencies
109
+ - 🔧 Update Eslint Config
110
+ - 🎨 Fix Eslit Error
111
+
112
+ ### v1.1.0
113
+
114
+ - ⚡️ **Improve Performance of First Sync**
115
+ - ✨ **Add Schedule Functionality**
116
+ - 🚸 **Improve Success Message of Sync Function**
117
+ - 📝 **Fix Typos in README**
118
+ - 📝 **Add Schedule Functions to README**
119
+ - ✅ Add Unittests
120
+ - ✨ Add Eslint
121
+
122
+ ### v1.0.3
123
+
124
+ - 📝 **Fix Typo in README**
125
+ - 📄 Add LICENSE
126
+
127
+ ### v1.0.2
128
+
129
+ - 📝 **Add "Get Your Cloudflare Api Key"-Section to README**
130
+
131
+ ### v1.0.1
132
+
133
+ - ✨ **Add sync Function -> changes the IP of the configured DNS records on Cloudflare**
134
+ - ✨ **Add getIp Function -> returns the external IP**
135
+ - 📝 **Add README**
package/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  Cloudflare-DDNS-Sync is a simple module that updates Cloudflare DNS records.
12
12
 
13
+ For a more detailed overview, have a look at the [Documentation](https://cddnss.knaup.dev/)
13
14
 
14
15
  You may also have a look at the **official** [CLI version](https://www.npmjs.com/package/cloudflare-ddns-sync-cli) of Cloudflare-DDNS-Sync.
15
16
 
@@ -106,18 +107,19 @@ Cron expressions have the following syntax:
106
107
  ## Methods
107
108
 
108
109
  - getIp(): Promise\<string\>
109
- - getRecordDataForDomain(domain: string): Promise\<Array\<[RecordData](https://docu.cddnss.pw/types/recorddata)\>\>
110
- - getRecordDataForDomains(domains: Array\<string\>): Promise\<[DomainRecordList](https://docu.cddnss.pw/types/domainrecordlist)\>
111
- - getRecordDataForRecord(record: [Record](https://docu.cddnss.pw/types/record)): Promise\<[RecordData](https://docu.cddnss.pw/types/recorddata)\>
112
- - getRecordDataForRecords(records: Array\<[Record](https://docu.cddnss.pw/types/record)\>): Promise\<Array\<[RecordData](https://docu.cddnss.pw/types/recorddata)\>\>
113
- - removeRecord(recordName: string): Promise\<void\>
110
+ - getIpv6(): Promise\<string\>
111
+ - getRecordDataForDomain(domain: string): Promise\<Array\<[RecordData](https://cddnss.knaup.dev/types/recorddata)\>\>
112
+ - getRecordDataForDomains(domains: Array\<string\>): Promise\<[DomainRecordList](https://cddnss.knaup.dev/types/domainrecordlist)\>
113
+ - getRecordDataForRecord(record: [Record](https://cddnss.knaup.dev/types/record)): Promise\<[RecordData](https://cddnss.knaup.dev/types/recorddata)\>
114
+ - getRecordDataForRecords(records: Array\<[Record](https://cddnss.knaup.dev/types/record)\>): Promise\<Array\<[RecordData](https://cddnss.knaup.dev/types/recorddata)\>\>
115
+ - removeRecord(recordName: string, recordType?: string): Promise\<void\>
114
116
  - stopSyncOnIpChange(changeListenerId: string): void
115
- - syncByCronTime(cronExpression: string, records: Array\<[Record](https://docu.cddnss.pw/types/recorddata)\>, callback: [MultiSyncCallback](https://docu.cddnss.pw/types/multisynccallback), ip?: string): [ScheduledTask](https://www.npmjs.com/package/node-cron#scheduledtask-methods)
116
- - syncOnIpChange(records: Array\<[Record](https://docu.cddnss.pw/types/record)\>, callback: multisynccallback): Promise\<string\>
117
- - syncRecord(record: [Record](https://docu.cddnss.pw/types/record), ip?: string): Promise\<[RecordData](https://docu.cddnss.pw/types/recorddata)\>
118
- - syncRecords(records: Array\<[Record](https://docu.cddnss.pw/types/record)\>, ip?: string): Promise\<Array\<[RecordData](https://docu.cddnss.pw/types/recorddata)\>\>
117
+ - syncByCronTime(cronExpression: string, records: Array\<[Record](https://cddnss.knaup.dev/types/recorddata)\>, callback: [MultiSyncCallback](https://cddnss.knaup.dev/types/multisynccallback), ip?: string): [ScheduledTask](https://www.npmjs.com/package/node-cron#scheduledtask-methods)
118
+ - syncOnIpChange(records: Array\<[Record](https://cddnss.knaup.dev/types/record)\>, callback: multisynccallback): Promise\<string\>
119
+ - syncRecord(record: [Record](https://cddnss.knaup.dev/types/record), ip?: string): Promise\<[RecordData](https://cddnss.knaup.dev/types/recorddata)\>
120
+ - syncRecords(records: Array\<[Record](https://cddnss.knaup.dev/types/record)\>, ip?: string): Promise\<Array\<[RecordData](https://cddnss.knaup.dev/types/recorddata)\>\>
119
121
 
120
- For a more detailed view, have a look at the [Documentation](https://docu.cddnss.pw/)
122
+ For a more detailed view, have a look at the [Documentation](https://cddnss.knaup.dev/)
121
123
 
122
124
  ## Get Your Cloudflare API Key
123
125
 
@@ -142,112 +144,3 @@ In order to run the tests there are two ways to do so
142
144
  ### Use `npm test` Only
143
145
 
144
146
  - Run `npm test -- --email="your@email.com" --key="your_cloudflare_api_key" --domain="yourdomain.com"`
145
-
146
- ## Changelog
147
-
148
- ### v2.0.1
149
-
150
- - ⬆️ Update Dependencies
151
-
152
- ### v2.0.0
153
-
154
- - ♻️ **Rewrite Cloudflare-DDNS-Sync in Typescript**
155
-
156
- ### v1.5.4
157
-
158
- - 📝 Update README
159
-
160
- ### v1.5.3
161
-
162
- - 🐛 **Fix Stopping Sync On IP Change**
163
- - 🐛 **Fix Crontime Converter For Hour**
164
- - 🐛 **Fix Syncing With Crontime Without Setting an IP**
165
- - ⚡️ **Small Performance Improvements**
166
- - 💄 Improve Code Quality
167
- - 💄 Extract Business Rules
168
-
169
- ### v1.5.2
170
-
171
- - 🐛 Fix Wrong Using of Const
172
-
173
- ### v1.5.1
174
-
175
- - 🐛 **Fix Bug When 'public-ip' Throws An Error**
176
- - 💄 Improve Code Quality
177
-
178
- ### v1.5.0
179
-
180
- - ✨ **Add Create Not Existing Records Functionality**
181
- - ✨ **Add Fallback getIp Function**
182
-
183
- ### v1.4.0
184
-
185
- - ✨ **Add Stop SyncOnIpChange Function**
186
-
187
- ### v1.3.4
188
-
189
- - 🐛 **Fix ipChange Interval**
190
-
191
- ### v1.3.3
192
-
193
- - 📝 **Add Changelog**
194
-
195
- ### v1.3.2
196
-
197
- - ✨ **Add getRecordIps Function**
198
- - ♻️ **Refactor syncOnIpChange**
199
- - ✅ **Add Tests for Sync Functionality**
200
- - 📝 **Improve README**
201
- - 📝 **Add NPM Badge**
202
- - 🔥 Remove Unnecessary Code
203
- - 🚸 Update Description
204
- - 🎨 Order Dependencies
205
- - 🎨 Lint files
206
-
207
- ### v1.3.1
208
-
209
- - 📝 **Fix README**
210
-
211
- ### v1.3.0
212
-
213
- - ✨ **Add syncAtDate Function**
214
- - 📝 **Improve README**
215
-
216
- ### v1.2.1
217
-
218
- - 🚑 **Fix README**
219
-
220
- ### v1.2.0
221
-
222
- - ✨ **Add onIpChange Function**
223
- - 📝 **Adjust README**
224
- - 🚚 Move Utils to Lib
225
- - 🚚 Move IP Functions to Lib
226
- - 🚚 Move Dependencies to devDependencies
227
- - 🔧 Update Eslint Config
228
- - 🎨 Fix Eslit Error
229
-
230
- ### v1.1.0
231
-
232
- - ⚡️ **Improve Performance of First Sync**
233
- - ✨ **Add Schedule Functionality**
234
- - 🚸 **Improve Success Message of Sync Function**
235
- - 📝 **Fix Typos in README**
236
- - 📝 **Add Schedule Functions to README**
237
- - ✅ Add Unittests
238
- - ✨ Add Eslint
239
-
240
- ### v1.0.3
241
-
242
- - 📝 **Fix Typo in README**
243
- - 📄 Add LICENSE
244
-
245
- ### v1.0.2
246
-
247
- - 📝 **Add "Get Your Cloudflare Api Key"-Section to README**
248
-
249
- ### v1.0.1
250
-
251
- - ✨ **Add sync Function -> changes the IP of the configured DNS records on Cloudflare**
252
- - ✨ **Add getIp Function -> returns the external IP**
253
- - 📝 **Add README**
@@ -0,0 +1,3 @@
1
+ import { RecordData } from './index';
2
+ export declare type SingleSyncCallback = (syncResult: RecordData) => void;
3
+ export declare type MultiSyncCallback = (syncResult: Array<RecordData>) => void;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ import { RecordData } from './index';
2
+ export declare type DomainRecordList = {
3
+ [domain: string]: Array<RecordData>;
4
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ export declare type Record = {
2
+ name: string;
3
+ type?: string;
4
+ proxied?: boolean;
5
+ ttl?: number;
6
+ priority?: number;
7
+ content?: string;
8
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare type ZoneMap = Map<string, string>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,20 @@
1
+ export declare type RecordData = {
2
+ id: string;
3
+ type: string;
4
+ name: string;
5
+ content: string;
6
+ proxiable: boolean;
7
+ proxied: boolean;
8
+ ttl: number;
9
+ locked: boolean;
10
+ zone_id: string;
11
+ zone_name: string;
12
+ modified_on: string;
13
+ created_on: string;
14
+ meta: RecordMetaData;
15
+ };
16
+ export declare type RecordMetaData = {
17
+ auto_added: boolean;
18
+ managed_by_apps: boolean;
19
+ managed_by_argo_tunnel: boolean;
20
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,43 @@
1
+ export declare type ZoneData = {
2
+ id: string;
3
+ name: string;
4
+ status: string;
5
+ paused: boolean;
6
+ type: string;
7
+ development_mode: number;
8
+ name_servers: Array<string>;
9
+ original_name_servers: Array<string>;
10
+ modified_on: Date;
11
+ created_on: Date;
12
+ activated_on: Date;
13
+ meta: {
14
+ step: number;
15
+ wildcard_proxiable: boolean;
16
+ custom_certificate_quota: number;
17
+ page_rule_quota: number;
18
+ phishing_detected: boolean;
19
+ multiple_railguns_allowed: boolean;
20
+ };
21
+ owner: {
22
+ id: string;
23
+ type: string;
24
+ email: string;
25
+ };
26
+ account: {
27
+ id: string;
28
+ name: string;
29
+ };
30
+ permissions: Array<string>;
31
+ plan: {
32
+ id: string;
33
+ name: string;
34
+ price: number;
35
+ currency: string;
36
+ frequency: string;
37
+ is_subscribed: boolean;
38
+ can_subscribe: boolean;
39
+ legacy_id: string;
40
+ legacy_discount: boolean;
41
+ externally_managed: boolean;
42
+ };
43
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export * from './RecordData';
2
+ export * from './ZoneData';
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./RecordData"), exports);
14
+ __exportStar(require("./ZoneData"), exports);
@@ -0,0 +1,5 @@
1
+ export * from './cloudflare/index';
2
+ export * from './Callbacks';
3
+ export * from './DomainRecordList';
4
+ export * from './Record';
5
+ export * from './ZoneMap';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./cloudflare/index"), exports);
14
+ __exportStar(require("./Callbacks"), exports);
15
+ __exportStar(require("./DomainRecordList"), exports);
16
+ __exportStar(require("./Record"), exports);
17
+ __exportStar(require("./ZoneMap"), exports);
@@ -0,0 +1,19 @@
1
+ import { ScheduledTask } from 'node-cron';
2
+ import { DomainRecordList, MultiSyncCallback, Record, RecordData } from './contracts/index';
3
+ export default class CloudflareDDNSSync {
4
+ private cloudflareClient;
5
+ constructor(email: string, authKey: string);
6
+ getIp(): Promise<string>;
7
+ 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>>;
12
+ removeRecord(recordName: string, recordType?: string): Promise<void>;
13
+ stopSyncOnIpChange(changeListenerId: string): void;
14
+ syncByCronTime(cronExpression: string, records: Array<Record>, callback: MultiSyncCallback, ip?: string): ScheduledTask;
15
+ 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>>;
18
+ }
19
+ export * from './contracts/index';
package/dist/index.js ADDED
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ const cloudflare_client_1 = __importDefault(require("./lib/cloudflare-client"));
17
+ const cron_1 = __importDefault(require("./lib/cron"));
18
+ const ip_utils_1 = __importDefault(require("./lib/ip-utils"));
19
+ class CloudflareDDNSSync {
20
+ cloudflareClient;
21
+ constructor(email, authKey) {
22
+ this.cloudflareClient = new cloudflare_client_1.default(email, authKey);
23
+ }
24
+ getIp() {
25
+ return ip_utils_1.default.getIpv4();
26
+ }
27
+ getIpv6() {
28
+ return ip_utils_1.default.getIpv6();
29
+ }
30
+ getRecordDataForDomain(domain) {
31
+ return this.cloudflareClient.getRecordDataForDomain(domain);
32
+ }
33
+ getRecordDataForDomains(domains) {
34
+ return this.cloudflareClient.getRecordDataForDomains(domains);
35
+ }
36
+ getRecordDataForRecord(record) {
37
+ return this.cloudflareClient.getRecordDataForRecord(record);
38
+ }
39
+ getRecordDataForRecords(records) {
40
+ return this.cloudflareClient.getRecordDataForRecords(records);
41
+ }
42
+ removeRecord(recordName, recordType) {
43
+ return this.cloudflareClient.removeRecordByNameAndType(recordName, recordType);
44
+ }
45
+ stopSyncOnIpChange(changeListenerId) {
46
+ ip_utils_1.default.removeIpChangeListener(changeListenerId);
47
+ }
48
+ syncByCronTime(cronExpression, records, callback, ip) {
49
+ return cron_1.default.createCronJob(cronExpression, async () => {
50
+ const result = await this.syncRecords(records, ip);
51
+ callback(result);
52
+ });
53
+ }
54
+ async syncOnIpChange(records, callback) {
55
+ const changeListenerId = await ip_utils_1.default.addIpChangeListener(async (ip) => {
56
+ const result = await this.syncRecords(records, ip);
57
+ callback(result);
58
+ });
59
+ // Sync records to make sure the current ip is already set.
60
+ const currentIp = await ip_utils_1.default.getIpv4();
61
+ this.syncRecords(records, currentIp).then((syncedRecords) => {
62
+ callback(syncedRecords);
63
+ });
64
+ return changeListenerId;
65
+ }
66
+ syncRecord(record, ip) {
67
+ return this.cloudflareClient.syncRecord(record, ip);
68
+ }
69
+ syncRecords(records, ip) {
70
+ return this.cloudflareClient.syncRecords(records, ip);
71
+ }
72
+ }
73
+ exports.default = CloudflareDDNSSync;
74
+ __exportStar(require("./contracts/index"), exports);
@@ -0,0 +1,25 @@
1
+ import { DomainRecordList, Record, RecordData } from '../contracts';
2
+ export default class CloudflareClient {
3
+ private cloudflare;
4
+ private zoneMap;
5
+ constructor(email: string, authKey: string);
6
+ syncRecord(record: Record, ip?: string): Promise<RecordData>;
7
+ syncRecords(records: Array<Record>, ip?: string): Promise<Array<RecordData>>;
8
+ removeRecordByNameAndType(recordName: string, recordType?: string): Promise<void>;
9
+ getRecordDataForRecord(record: Record): Promise<RecordData>;
10
+ getRecordDataForRecords(records: Array<Record>): Promise<Array<RecordData>>;
11
+ getRecordDataForDomains(domains: Array<string>): Promise<DomainRecordList>;
12
+ getRecordDataForDomain(domain: string): Promise<Array<RecordData>>;
13
+ private createRecord;
14
+ private updateRecord;
15
+ private updateZoneMap;
16
+ private getRecordIdByNameAndType;
17
+ private getZoneIdByRecordName;
18
+ private getRecordByNameAndType;
19
+ private getRecordIdsForRecords;
20
+ private getRecordIdMapKey;
21
+ private getRecordsByDomain;
22
+ private getZoneIdByDomain;
23
+ private getDomainsFromRecords;
24
+ private getDomainByRecordName;
25
+ }
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const parse_domain_1 = require("parse-domain");
7
+ const cloudflare_1 = __importDefault(require("cloudflare"));
8
+ const ip_utils_1 = __importDefault(require("./ip-utils"));
9
+ const ipv4Regex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/u;
10
+ // eslint-disable-next-line max-len
11
+ const ipv6Regex = /^(?:(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-fA-F]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,1}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,2}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,3}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:[0-9a-fA-F]{1,4})):)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,4}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,5}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,6}(?:(?:[0-9a-fA-F]{1,4})))?::))))$/u;
12
+ class CloudflareClient {
13
+ cloudflare;
14
+ zoneMap = new Map();
15
+ constructor(email, authKey) {
16
+ this.cloudflare = new cloudflare_1.default({
17
+ email: email,
18
+ key: authKey,
19
+ });
20
+ this.updateZoneMap();
21
+ }
22
+ async syncRecord(record, ip) {
23
+ const recordIds = await this.getRecordIdsForRecords([record]);
24
+ const ipToUse = ip ? ip : await ip_utils_1.default.getIpv4();
25
+ const zoneId = await this.getZoneIdByRecordName(record.name);
26
+ const recordId = recordIds.get(this.getRecordIdMapKey(record));
27
+ const recordExists = recordId !== undefined;
28
+ if (recordExists) {
29
+ const result = await this.updateRecord(zoneId, recordId, record, ipToUse);
30
+ return result;
31
+ }
32
+ const result = await this.createRecord(zoneId, record, ipToUse);
33
+ return result;
34
+ }
35
+ async syncRecords(records, ip) {
36
+ const recordIds = await this.getRecordIdsForRecords(records);
37
+ const ipToUse = ip ? ip : await ip_utils_1.default.getIpv4();
38
+ const resultPromises = records.map(async (record) => {
39
+ const zoneId = await this.getZoneIdByRecordName(record.name);
40
+ const recordId = recordIds.get(this.getRecordIdMapKey(record));
41
+ const recordExists = recordId !== undefined;
42
+ if (recordExists) {
43
+ const currentResult = await this.updateRecord(zoneId, recordId, record, ipToUse);
44
+ return currentResult;
45
+ }
46
+ const currentResult = await this.createRecord(zoneId, record, ipToUse);
47
+ return currentResult;
48
+ });
49
+ const results = await Promise.all(resultPromises);
50
+ return results;
51
+ }
52
+ async removeRecordByNameAndType(recordName, recordType) {
53
+ const recordTypeToUse = recordType ? recordType : 'A';
54
+ const zoneId = await this.getZoneIdByRecordName(recordName);
55
+ const recordId = await this.getRecordIdByNameAndType(recordName, recordTypeToUse);
56
+ return this.cloudflare.dnsRecords.del(zoneId, recordId);
57
+ }
58
+ async getRecordDataForRecord(record) {
59
+ const domain = this.getDomainByRecordName(record.name);
60
+ const recordDataForDomain = await this.getRecordsByDomain(domain);
61
+ const recordData = recordDataForDomain.find((singleRecordData) => record.name.toLowerCase() === singleRecordData.name.toLowerCase());
62
+ return recordData;
63
+ }
64
+ async getRecordDataForRecords(records) {
65
+ const domains = this.getDomainsFromRecords(records);
66
+ const recordDataPromises = domains.map(async (domain) => {
67
+ const recordDataForDomain = await this.getRecordsByDomain(domain);
68
+ const recordDataForDomainFilteredByRecords = recordDataForDomain
69
+ .filter((singleRecordData) => records
70
+ .some((record) => record.name.toLowerCase() === singleRecordData.name.toLowerCase()));
71
+ return recordDataForDomainFilteredByRecords;
72
+ });
73
+ const recordDataForDomains = await Promise.all(recordDataPromises);
74
+ const recordData = [].concat(...recordDataForDomains);
75
+ return recordData;
76
+ }
77
+ async getRecordDataForDomains(domains) {
78
+ const recordDataPromises = domains.map((domain) => this.getRecordDataForDomain(domain));
79
+ const recordDataForDomains = await Promise.all(recordDataPromises);
80
+ const recordData = {};
81
+ recordDataForDomains.forEach((recordDataForDomain, index) => {
82
+ recordData[domains[index]] = recordDataForDomain;
83
+ });
84
+ return recordData;
85
+ }
86
+ async getRecordDataForDomain(domain) {
87
+ const recordData = await this.getRecordsByDomain(domain);
88
+ return recordData;
89
+ }
90
+ async createRecord(zoneId, record, ip) {
91
+ const copyOfRecord = { ...record };
92
+ copyOfRecord.name = record.name.toLowerCase();
93
+ copyOfRecord.content = copyOfRecord.content ? copyOfRecord.content : ip;
94
+ copyOfRecord.type = copyOfRecord.type ? copyOfRecord.type : 'A';
95
+ if (!copyOfRecord.content) {
96
+ throw Error(`Could not create Record "${copyOfRecord.name}": Content is missing!`);
97
+ }
98
+ if (copyOfRecord.type === 'A') {
99
+ if (!copyOfRecord.content.match(ipv4Regex)) {
100
+ throw Error(`Could not create Record "${copyOfRecord.name}": '${copyOfRecord.content}' is not a valid ipv4!`);
101
+ }
102
+ }
103
+ else if (copyOfRecord.type === 'AAAA') {
104
+ if (!copyOfRecord.content.match(ipv6Regex)) {
105
+ throw Error(`Could not create Record "${copyOfRecord.name}": '${copyOfRecord.content}' is not a valid ipv6!`);
106
+ }
107
+ }
108
+ else if (copyOfRecord.type === 'CNAME') {
109
+ const parsedDomain = (0, parse_domain_1.parseDomain)((0, parse_domain_1.fromUrl)(copyOfRecord.content));
110
+ if (parsedDomain.type !== parse_domain_1.ParseResultType.Listed || !parsedDomain.domain) {
111
+ throw Error(`Could not create Record "${copyOfRecord.name}": '${copyOfRecord.content}' is not a valid domain name!`);
112
+ }
113
+ }
114
+ const response = await this.cloudflare.dnsRecords.add(zoneId, copyOfRecord);
115
+ return response.result;
116
+ }
117
+ async updateRecord(zoneId, recordId, record, ip) {
118
+ const copyOfRecord = { ...record };
119
+ copyOfRecord.name = record.name.toLowerCase();
120
+ copyOfRecord.content = copyOfRecord.content ? copyOfRecord.content : ip;
121
+ copyOfRecord.type = copyOfRecord.type ? copyOfRecord.type : 'A';
122
+ if (!copyOfRecord.content) {
123
+ throw Error(`Could not update Record "${copyOfRecord.name}": Content is missing!`);
124
+ }
125
+ if (copyOfRecord.type === 'A') {
126
+ if (!copyOfRecord.content.match(ipv4Regex)) {
127
+ throw Error(`Could not update Record "${copyOfRecord.name}": '${copyOfRecord.content}' is not a valid ipv4!`);
128
+ }
129
+ }
130
+ else if (copyOfRecord.type === 'AAAA') {
131
+ if (!copyOfRecord.content.match(ipv6Regex)) {
132
+ throw Error(`Could not update Record "${copyOfRecord.name}": '${copyOfRecord.content}' is not a valid ipv6!`);
133
+ }
134
+ }
135
+ else if (copyOfRecord.type === 'CNAME') {
136
+ const parsedDomain = (0, parse_domain_1.parseDomain)((0, parse_domain_1.fromUrl)(copyOfRecord.content));
137
+ if (parsedDomain.type !== parse_domain_1.ParseResultType.Listed || !parsedDomain.domain) {
138
+ throw Error(`Could not update Record "${copyOfRecord.name}": '${copyOfRecord.content}' is not a valid domain name!`);
139
+ }
140
+ }
141
+ const response = await this.cloudflare.dnsRecords.edit(zoneId, recordId, copyOfRecord);
142
+ return response.result;
143
+ }
144
+ async updateZoneMap() {
145
+ const response = await this.cloudflare.zones.browse();
146
+ const zones = response.result;
147
+ this.zoneMap = new Map();
148
+ for (const zone of zones) {
149
+ this.zoneMap.set(zone.name, zone.id);
150
+ }
151
+ }
152
+ async getRecordIdByNameAndType(recordName, recordType) {
153
+ const record = await this.getRecordByNameAndType(recordName, recordType);
154
+ return record.id;
155
+ }
156
+ getZoneIdByRecordName(recordName) {
157
+ const domain = this.getDomainByRecordName(recordName);
158
+ return this.getZoneIdByDomain(domain);
159
+ }
160
+ async getRecordByNameAndType(recordName, recordType) {
161
+ const domain = this.getDomainByRecordName(recordName);
162
+ const records = await this.getRecordsByDomain(domain);
163
+ const record = records.find((currentRecord) => currentRecord.name.toLowerCase() === recordName.toLowerCase()
164
+ && currentRecord.type.toLowerCase() === recordType.toLowerCase());
165
+ const recordNotFound = record === undefined;
166
+ if (recordNotFound) {
167
+ throw new Error(`Record '${recordName}' not found.`);
168
+ }
169
+ return record;
170
+ }
171
+ async getRecordIdsForRecords(records) {
172
+ const recordIdMap = new Map();
173
+ const recordData = await this.getRecordDataForRecords(records);
174
+ for (const record of recordData) {
175
+ recordIdMap.set(this.getRecordIdMapKey(record), record.id);
176
+ }
177
+ return recordIdMap;
178
+ }
179
+ getRecordIdMapKey(record) {
180
+ const recordName = record.name.toLowerCase();
181
+ const recordType = record.type ? record.type.toLowerCase() : 'a';
182
+ return `"${recordName}"_"${recordType}"`;
183
+ }
184
+ async getRecordsByDomain(domain) {
185
+ const zoneId = await this.getZoneIdByDomain(domain);
186
+ const records = [];
187
+ let pageIndex = 1;
188
+ let allRecordsFound = false;
189
+ while (!allRecordsFound) {
190
+ const response = await this.cloudflare.dnsRecords.browse(zoneId, {
191
+ page: pageIndex,
192
+ per_page: 100,
193
+ });
194
+ records.push(...response.result);
195
+ allRecordsFound = response.result.length < 100;
196
+ pageIndex++;
197
+ }
198
+ return records;
199
+ }
200
+ async getZoneIdByDomain(domain) {
201
+ if (this.zoneMap.has(domain)) {
202
+ const zoneId = this.zoneMap.get(domain.toLowerCase());
203
+ return zoneId;
204
+ }
205
+ await this.updateZoneMap();
206
+ if (!this.zoneMap.has(domain)) {
207
+ throw new Error(`Could not find domain '${domain}'. Make sure the domain is set up for your cloudflare account.`);
208
+ }
209
+ const zoneId = this.zoneMap.get(domain.toLowerCase());
210
+ return zoneId;
211
+ }
212
+ getDomainsFromRecords(records) {
213
+ const domains = records
214
+ .map((record) => this.getDomainByRecordName(record.name))
215
+ .filter((domain, index, domainList) => domainList.indexOf(domain.toLowerCase()) === index);
216
+ return domains;
217
+ }
218
+ getDomainByRecordName(recordName) {
219
+ const parsedDomain = (0, parse_domain_1.parseDomain)((0, parse_domain_1.fromUrl)(recordName));
220
+ if (parsedDomain.type !== parse_domain_1.ParseResultType.Listed || !parsedDomain.domain) {
221
+ throw new Error(`Could not parse domain. '${JSON.stringify(recordName)}' is not a valid record name.`);
222
+ }
223
+ let domain = '';
224
+ domain += parsedDomain.domain;
225
+ for (const tld of parsedDomain.topLevelDomains) {
226
+ domain += `.${tld}`;
227
+ }
228
+ return domain.toLowerCase();
229
+ }
230
+ }
231
+ exports.default = CloudflareClient;
@@ -0,0 +1,5 @@
1
+ import { ScheduledTask } from 'node-cron';
2
+ export default class Cron {
3
+ static createCronJob(cronExpression: string, callback: Function): ScheduledTask;
4
+ static isValid(cronExpression: string): boolean;
5
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_cron_1 = __importDefault(require("node-cron"));
7
+ class Cron {
8
+ static createCronJob(cronExpression, callback) {
9
+ const cronExpressionIsInvalid = !this.isValid(cronExpression);
10
+ if (cronExpressionIsInvalid) {
11
+ // eslint-disable-next-line max-len
12
+ throw new Error(`'${cronExpression}' is not a valid cron expression.\nHere you can see how cron expressions work: https://cddnss.knaup.dev/cron-expression-syntax`);
13
+ }
14
+ return node_cron_1.default.schedule(cronExpression, () => {
15
+ callback();
16
+ }, undefined);
17
+ }
18
+ static isValid(cronExpression) {
19
+ return node_cron_1.default.validate(cronExpression);
20
+ }
21
+ }
22
+ exports.default = Cron;
@@ -0,0 +1,9 @@
1
+ export default class IPUtils {
2
+ private static readonly ipPollingDelay;
3
+ private static ipChangeEventListeners;
4
+ static getIpv4(): Promise<string>;
5
+ static getIpv6(): Promise<string>;
6
+ static addIpChangeListener(callback: Function): Promise<string>;
7
+ static removeIpChangeListener(eventListenerId: string): void;
8
+ private static getRandomId;
9
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ const wimIp = __importStar(require("what-is-my-ip-address"));
26
+ const public_ip_1 = __importDefault(require("public-ip"));
27
+ class IPUtils {
28
+ static ipPollingDelay = 10 * 1000;
29
+ static ipChangeEventListeners = new Map();
30
+ static async getIpv4() {
31
+ /* c8 ignore start*/
32
+ try {
33
+ return await public_ip_1.default.v4();
34
+ }
35
+ catch (error) {
36
+ return wimIp.v4();
37
+ }
38
+ /* c8 ignore stop*/
39
+ }
40
+ static async getIpv6() {
41
+ /* c8 ignore start */
42
+ try {
43
+ return await public_ip_1.default.v6();
44
+ }
45
+ catch (error) {
46
+ return wimIp.v6();
47
+ }
48
+ /* c8 ignore stop*/
49
+ }
50
+ static async addIpChangeListener(callback) {
51
+ const eventListenerId = this.getRandomId();
52
+ let previousIp = await this.getIpv4();
53
+ /* c8 ignore start */
54
+ const intervalId = setInterval(async () => {
55
+ const currentIp = await this.getIpv4();
56
+ const ipMustBeUpdated = currentIp !== previousIp;
57
+ if (ipMustBeUpdated) {
58
+ previousIp = currentIp;
59
+ callback(currentIp);
60
+ }
61
+ }, this.ipPollingDelay);
62
+ /* c8 ignore stop*/
63
+ this.ipChangeEventListeners.set(eventListenerId, intervalId);
64
+ return eventListenerId;
65
+ }
66
+ static removeIpChangeListener(eventListenerId) {
67
+ const eventListenerIntervalId = this.ipChangeEventListeners.get(eventListenerId);
68
+ clearInterval(eventListenerIntervalId);
69
+ IPUtils.ipChangeEventListeners.delete(eventListenerId);
70
+ }
71
+ static getRandomId() {
72
+ const beginningRandomString = Math.random().toString(36)
73
+ .substr(2);
74
+ const currentDateAsString = new Date().valueOf()
75
+ .toString(36);
76
+ const endingRandomString = Math.random().toString(36)
77
+ .substr(2);
78
+ const randomString = beginningRandomString + currentDateAsString + endingRandomString;
79
+ return randomString;
80
+ }
81
+ }
82
+ exports.default = IPUtils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-ddns-sync",
3
- "version": "2.0.1",
3
+ "version": "2.0.5",
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>",
@@ -13,37 +13,41 @@
13
13
  "dyndns",
14
14
  "sync"
15
15
  ],
16
+ "homepage": "https://cddnss.knaup.dev/",
16
17
  "repository": {
17
18
  "type": "git",
18
19
  "url": "git://github.com:Steffen982/cloudflare-ddns-sync.git"
19
20
  },
20
21
  "scripts": {
21
22
  "build": "tsc",
22
- "lint": "tslint --project .",
23
+ "lint": "eslint \"src/**/*.ts\"",
24
+ "lint:fix": "eslint --fix \"src/**/*.ts\"",
23
25
  "test": "c8 mocha dist/tests/*.js --timeout 15000 --exit",
24
- "test-jenkins": "JUNIT_REPORT_PATH=report.xml npm test -- --reporter mocha-jenkins-reporter",
25
- "test-coverage-check": "c8 check-coverage --lines 70 --functions 70 --branches 70",
26
- "test-coverage-report": "c8 report"
26
+ "test:coverage": "npm run test:coverage-check && npm run test:coverage-report",
27
+ "test:coverage-check": "c8 check-coverage --lines 70 --functions 70 --branches 70",
28
+ "test:coverage-report": "c8 report"
27
29
  },
28
30
  "dependencies": {
29
- "cloudflare": "2.7.0",
30
- "node-cron": "2.0.3",
31
- "parse-domain": "3.0.2",
32
- "public-ip": "4.0.1",
31
+ "cloudflare": "2.9.1",
32
+ "node-cron": "3.0.0",
33
+ "parse-domain": "4.1.0",
34
+ "public-ip": "4.0.4",
33
35
  "what-is-my-ip-address": "1.0.3"
34
36
  },
35
37
  "devDependencies": {
36
- "@types/chai": "4.2.11",
37
- "@types/minimist": "1.2.0",
38
- "@types/mocha": "7.0.2",
39
- "@types/node": "10.14.17",
40
- "@types/node-cron": "2.0.3",
41
- "c8": "7.2.0",
42
- "chai": "4.2.0",
38
+ "@types/chai": "4.3.0",
39
+ "@types/minimist": "1.2.2",
40
+ "@types/mocha": "9.0.0",
41
+ "@types/node": "16.11.20",
42
+ "@types/node-cron": "3.0.1",
43
+ "@typescript-eslint/eslint-plugin": "5.10.0",
44
+ "@typescript-eslint/parser": "5.10.0",
45
+ "c8": "7.11.0",
46
+ "chai": "4.3.4",
47
+ "eslint": "8.7.0",
43
48
  "minimist": "1.2.5",
44
- "mocha": "8.0.1",
45
- "mocha-jenkins-reporter": "0.4.3",
46
- "tslint": "6.1.2",
47
- "typescript": "3.9.5"
49
+ "mocha": "9.1.4",
50
+ "tslint": "6.1.3",
51
+ "typescript": "4.5.4"
48
52
  }
49
53
  }