🎨 style: add Prettier formatting

This commit is contained in:
2026-07-01 12:36:15 +07:00
parent 3cf1571070
commit eb242ce953
12 changed files with 627 additions and 570 deletions
+5
View File
@@ -0,0 +1,5 @@
node_modules
dist
configs
coverage
bun.lock
+5
View File
@@ -0,0 +1,5 @@
{
"printWidth": 100,
"singleQuote": false,
"trailingComma": "all"
}
+10 -7
View File
@@ -5,15 +5,16 @@
"": { "": {
"name": "cloudflare-ddns-updater", "name": "cloudflare-ddns-updater",
"dependencies": { "dependencies": {
"axios": "latest", "axios": "^1.18.1",
"dotenv": "latest", "dotenv": "^17.4.2",
"validator": "latest", "validator": "^13.15.35",
"winston": "latest", "winston": "3.19.0",
}, },
"devDependencies": { "devDependencies": {
"@types/node": "latest", "@types/node": "^26.0.1",
"@types/validator": "latest", "@types/validator": "^13.15.10",
"typescript": "latest", "prettier": "^3.9.4",
"typescript": "^6.0.3",
}, },
}, },
}, },
@@ -110,6 +111,8 @@
"one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="],
"prettier": ["prettier@3.9.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg=="],
"proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="], "proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="],
"readable-stream": ["readable-stream@3.6.0", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="], "readable-stream": ["readable-stream@3.6.0", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="],
+3
View File
@@ -15,10 +15,13 @@
"devDependencies": { "devDependencies": {
"@types/node": "^26.0.1", "@types/node": "^26.0.1",
"@types/validator": "^13.15.10", "@types/validator": "^13.15.10",
"prettier": "^3.9.4",
"typescript": "^6.0.3" "typescript": "^6.0.3"
}, },
"scripts": { "scripts": {
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"format": "prettier --write .",
"format:check": "prettier --check .",
"dev": "bun --watch src/index.ts", "dev": "bun --watch src/index.ts",
"start": "bun src/index.ts", "start": "bun src/index.ts",
"build": "bun run typecheck", "build": "bun run typecheck",
+1 -1
View File
@@ -1,4 +1,4 @@
import App from './providers/App'; import App from "./providers/App";
App.loadConfig(); App.loadConfig();
App.loadENV(); App.loadENV();
+20 -22
View File
@@ -1,4 +1,4 @@
import winston from 'winston'; import winston from "winston";
const levels = { const levels = {
critical: 0, critical: 0,
@@ -11,47 +11,45 @@ const levels = {
}; };
const level = () => { const level = () => {
const env = process.env.NODE_ENV || 'development'; const env = process.env.NODE_ENV || "development";
const isDevelopment = env === 'development'; const isDevelopment = env === "development";
return isDevelopment ? 'debug' : 'info'; return isDevelopment ? "debug" : "info";
}; };
const colors = { const colors = {
critical: 'red', critical: "red",
error: 'red', error: "red",
alert: 'red', alert: "red",
warn: 'yellow', warn: "yellow",
info: 'green', info: "green",
http: 'magenta', http: "magenta",
debug: 'white', debug: "white",
}; };
winston.addColors(colors); winston.addColors(colors);
const consoleFormat = winston.format.combine( const consoleFormat = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }), winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }),
winston.format.colorize({ all: true }), winston.format.colorize({ all: true }),
winston.format.printf( winston.format.printf((info) => `[${info.timestamp}] [${info.level}] ${info.message}`),
(info) => `[${info.timestamp}] [${info.level}] ${info.message}`
)
); );
const format = winston.format.combine( const format = winston.format.combine(
winston.format.timestamp({ winston.format.timestamp({
format: new Date().toISOString() format: new Date().toISOString(),
}), }),
winston.format.json() winston.format.json(),
) );
const transports = [ const transports = [
new winston.transports.Console({ new winston.transports.Console({
format: consoleFormat format: consoleFormat,
}), }),
new winston.transports.File({ new winston.transports.File({
filename: 'logs/error.log', filename: "logs/error.log",
level: 'error', level: "error",
}), }),
new winston.transports.File({ filename: 'logs/all.log' }), new winston.transports.File({ filename: "logs/all.log" }),
]; ];
const Logger = winston.createLogger({ const Logger = winston.createLogger({
+9 -9
View File
@@ -1,23 +1,23 @@
import Logger from '../libs/Logger'; import Logger from "../libs/Logger";
import Environment from './Environment'; import Environment from "./Environment";
import Configuration from './Configuration'; import Configuration from "./Configuration";
import Daemon from './Daemon'; import Daemon from "./Daemon";
class App { class App {
public loadConfig(): void { public loadConfig(): void {
Logger.log('info', 'Loading configuration'); Logger.log("info", "Loading configuration");
Configuration.init(); Configuration.init();
} }
public loadENV(): void { public loadENV(): void {
Logger.log('info', 'Loading environment'); Logger.log("info", "Loading environment");
Environment.init(); Environment.init();
} }
public loadDaemon() : void { public loadDaemon(): void {
Logger.log('info', 'Loading daemon'); Logger.log("info", "Loading daemon");
Daemon.init(); Daemon.init();
} }
} }
export default new App; export default new App();
+10 -12
View File
@@ -3,9 +3,8 @@ import path from "path";
const ConfigurationData: any = []; const ConfigurationData: any = [];
class Configuration { class Configuration {
public init(): void { public init(): void {
const dir = path.join(process.cwd(), 'configs/'); const dir = path.join(process.cwd(), "configs/");
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
fs.mkdirSync(dir); fs.mkdirSync(dir);
} }
@@ -15,7 +14,7 @@ class Configuration {
} }
public loadConfig(configFileName: string): void { public loadConfig(configFileName: string): void {
const dir = path.join(process.cwd(), 'configs/'); const dir = path.join(process.cwd(), "configs/");
if (!fs.existsSync(path.join(dir, configFileName))) if (!fs.existsSync(path.join(dir, configFileName)))
throw new Error(`Config file ${configFileName} does not exist`); throw new Error(`Config file ${configFileName} does not exist`);
@@ -24,23 +23,22 @@ class Configuration {
} }
public getConfig(key?: string) { public getConfig(key?: string) {
if(!key) if (!key) return ConfigurationData;
return ConfigurationData;
else { else {
if(ConfigurationData[key]) if (ConfigurationData[key]) return ConfigurationData[key];
return ConfigurationData[key]; else throw new Error(`No configuration found for ${key}`);
else
throw new Error(`No configuration found for ${key}`);
} }
} }
private copyExampleIfNotExists(file: string): void { private copyExampleIfNotExists(file: string): void {
const dir = path.join(process.cwd(), 'configs/'); const dir = path.join(process.cwd(), "configs/");
if (!fs.existsSync(path.join(dir, file))) { if (!fs.existsSync(path.join(dir, file))) {
fs.copyFileSync(path.join(process.cwd(), 'configs_example/', `${file.replace('.json', '.example.json')}`), path.join(dir, file)); fs.copyFileSync(
path.join(process.cwd(), "configs_example/", `${file.replace(".json", ".example.json")}`),
path.join(dir, file),
);
} }
} }
} }
export default new Configuration(); export default new Configuration();
+178 -125
View File
@@ -3,39 +3,37 @@ import Environment from "./Environment";
import Configuration from "./Configuration"; import Configuration from "./Configuration";
import axios from "axios"; import axios from "axios";
import validator from 'validator'; import validator from "validator";
interface CloudflareConfig { interface CloudflareConfig {
token: string, token: string;
updateInterval: number, updateInterval: number;
zone: Array<ZoneConfig> zone: Array<ZoneConfig>;
} }
interface ZoneConfig { interface ZoneConfig {
id: string, id: string;
type: string, type: string;
name: string, name: string;
content: string, content: string;
ttl: number, ttl: number;
proxied: boolean proxied: boolean;
} }
class Deamon { class Deamon {
private config: Array<CloudflareConfig> = []; private config: Array<CloudflareConfig> = [];
constructor () { constructor() {}
}
public init(): void { public init(): void {
const _config = Configuration.getConfig("UpdaterConfig"); const _config = Configuration.getConfig("UpdaterConfig");
if(!_config) { if (!_config) {
Logger.error('No configuration found') Logger.error("No configuration found");
return; return;
} }
for(let cloudflareConfig of _config) { for (let cloudflareConfig of _config) {
if(!this.isCloudflareConfig(cloudflareConfig)) { if (!this.isCloudflareConfig(cloudflareConfig)) {
Logger.error(`Invalid configuration for cloudflare: ${JSON.stringify(cloudflareConfig)}`); Logger.error(`Invalid configuration for cloudflare: ${JSON.stringify(cloudflareConfig)}`);
continue; continue;
} }
@@ -48,24 +46,22 @@ class Deamon {
} }
public start(): void { public start(): void {
Logger.info('Starting deamon'); Logger.info("Starting deamon");
for(const cloudflareConfig of this.config) { for (const cloudflareConfig of this.config) {
this.update(cloudflareConfig); this.update(cloudflareConfig);
setInterval(() => this.update(cloudflareConfig), cloudflareConfig.updateInterval * 1000); setInterval(() => this.update(cloudflareConfig), cloudflareConfig.updateInterval * 1000);
} }
} }
private async update(cloudflareConfig: CloudflareConfig) { private async update(cloudflareConfig: CloudflareConfig) {
let token = cloudflareConfig.token; let token = cloudflareConfig.token;
// Replace placeholders env with value // Replace placeholders env with value
if(this.isEnviromentTokenPlaceholder(token)) { if (this.isEnviromentTokenPlaceholder(token)) {
const envTokenName = this.parseEnvironmentTokenPlaceholderName(token)!; const envTokenName = this.parseEnvironmentTokenPlaceholderName(token)!;
if(process.env[envTokenName]) { if (process.env[envTokenName]) {
token = process.env[envTokenName]!; token = process.env[envTokenName]!;
} } else {
else {
Logger.error(`Environment variable ${envTokenName} not found`); Logger.error(`Environment variable ${envTokenName} not found`);
return; return;
} }
@@ -75,7 +71,7 @@ class Deamon {
try { try {
IPv4 = await this.getCurrentIPv4(); IPv4 = await this.getCurrentIPv4();
IPv6 = await this.getCurrentIPv6(); IPv6 = await this.getCurrentIPv6();
} catch(err) { } catch (err) {
Logger.error(`Unable to fetch ip address: ${err}`); Logger.error(`Unable to fetch ip address: ${err}`);
return; return;
} }
@@ -83,130 +79,139 @@ class Deamon {
IPv4 && Logger.info(`Current IPv4 address: ${IPv4}`); IPv4 && Logger.info(`Current IPv4 address: ${IPv4}`);
IPv6 && Logger.info(`Current IPv6 address: ${IPv6}`); IPv6 && Logger.info(`Current IPv6 address: ${IPv6}`);
for(const zone of cloudflareConfig.zone) { for (const zone of cloudflareConfig.zone) {
const api = new CloudflareAPI(token, zone.id); const api = new CloudflareAPI(token, zone.id);
const records = await api.getRecord({ const records = await api
.getRecord({
type: zone.type, type: zone.type,
name: zone.name name: zone.name,
}).catch(err => { })
.catch((err) => {
Logger.error(`Unable to get records for zone ${zone.id}`); Logger.error(`Unable to get records for zone ${zone.id}`);
return err; return err;
}); });
if(records instanceof Error) { if (records instanceof Error) {
continue; continue;
} }
// No records found, create it // No records found, create it
if(!records || records.length === 0) { if (!records || records.length === 0) {
const newContent = zone.content.replaceAll("{CURRENT_IPv4}", IPv4).replaceAll("{CURRENT_IPv6}", IPv6); const newContent = zone.content
.replaceAll("{CURRENT_IPv4}", IPv4)
.replaceAll("{CURRENT_IPv6}", IPv6);
const result = await api.createRecord({ const result = await api
.createRecord({
type: zone.type, type: zone.type,
name: zone.name, name: zone.name,
content: IPv4, content: IPv4,
ttl: zone.ttl, ttl: zone.ttl,
proxied: zone.proxied proxied: zone.proxied,
}).catch(err => { })
.catch((err) => {
Logger.error(`Unable to create record: ${err.message}`); Logger.error(`Unable to create record: ${err.message}`);
return err; return err;
}); });
if(records instanceof Error) { if (records instanceof Error) {
continue; continue;
} }
if(result) if (result) Logger.info(`Created [${zone.type}] (${zone.name} -> ${newContent})`);
Logger.info(`Created [${zone.type}] (${zone.name} -> ${newContent})`);
} }
// Only 1 matching records found // Only 1 matching records found
else if(records.length === 1) { else if (records.length === 1) {
const record = records[0]; const record = records[0];
const newContent = zone.content.replaceAll("{CURRENT_IPv4}", IPv4).replaceAll("{CURRENT_IPv6}", IPv6); const newContent = zone.content
.replaceAll("{CURRENT_IPv4}", IPv4)
.replaceAll("{CURRENT_IPv6}", IPv6);
// Check if the ip is the same // Check if the ip is the same
if(record.content !== IPv4 && record.content !== IPv6) { if (record.content !== IPv4 && record.content !== IPv6) {
const updateResult = await api.updateRecord({ const updateResult = await api
.updateRecord({
record_id: record.id, record_id: record.id,
type: zone.type, type: zone.type,
name: zone.name, name: zone.name,
ttl: zone.ttl, ttl: zone.ttl,
content: newContent, content: newContent,
proxied: zone.proxied proxied: zone.proxied,
}).catch(err => { })
.catch((err) => {
Logger.error(`Unable to update record: ${err.message}`); Logger.error(`Unable to update record: ${err.message}`);
return err; return err;
}); });
if(records instanceof Error) { if (records instanceof Error) {
continue; continue;
} }
if(updateResult) if (updateResult)
Logger.info(`[${zone.type}] (${zone.name} -> ${record.content}) updated to (${zone.name} -> ${newContent})`); Logger.info(
} `[${zone.type}] (${zone.name} -> ${record.content}) updated to (${zone.name} -> ${newContent})`,
else if( );
record.ttl !== zone.ttl || } else if (record.ttl !== zone.ttl || record.proxied !== zone.proxied) {
record.proxied !== zone.proxied const updateResult = await api
) { .updateRecord({
const updateResult = await api.updateRecord({
record_id: record.id, record_id: record.id,
type: zone.type, type: zone.type,
name: zone.name, name: zone.name,
ttl: zone.ttl, ttl: zone.ttl,
content: newContent, content: newContent,
proxied: zone.proxied proxied: zone.proxied,
}).catch(err => { })
.catch((err) => {
Logger.error(`Unable to update record: ${err.message}`); Logger.error(`Unable to update record: ${err.message}`);
console.log(err); console.log(err);
return; return;
}); });
if(updateResult) if (updateResult)
Logger.info(`[${zone.type}] (${zone.name} -> ${record.content}) updated proxy status/ttl (TTL: ${record.ttl} -> ${zone.ttl}) (Proxy status: ${record.proxied} -> ${zone.proxied})`); Logger.info(
} `[${zone.type}] (${zone.name} -> ${record.content}) updated proxy status/ttl (TTL: ${record.ttl} -> ${zone.ttl}) (Proxy status: ${record.proxied} -> ${zone.proxied})`,
);
else { } else {
Logger.info(`[${zone.type}] (${zone.name} -> ${record.content}) already up to date`); Logger.info(`[${zone.type}] (${zone.name} -> ${record.content}) already up to date`);
continue; continue;
} }
} }
// Many records found // Many records found
else if(records.length > 1) { else if (records.length > 1) {
Logger.error(`Multiple records found for ${zone.type} (${zone.name}) (Multiple records are not supported right now)`); Logger.error(
`Multiple records found for ${zone.type} (${zone.name}) (Multiple records are not supported right now)`,
);
continue; continue;
} }
} }
} }
private isCloudflareConfig(object: any): object is CloudflareConfig { private isCloudflareConfig(object: any): object is CloudflareConfig {
if (!this.arraysEqual(Object.keys(object), ["token", "updateInterval", "zone"])) return false;
if(!this.arraysEqual(Object.keys(object), ['token', 'updateInterval', 'zone'])) const res =
return false; object &&
object.token &&
typeof object.token == "string" &&
object.updateInterval &&
typeof object.updateInterval == "number";
const res = object && for (let zone of object.zone) {
object.token && typeof(object.token) == 'string' && if (!this.isZoneConfig(zone)) return false;
object.updateInterval && typeof(object.updateInterval) == 'number';
for(let zone of object.zone) {
if(!this.isZoneConfig(zone))
return false;
} }
if(!res) return false; if (!res) return false;
const token = object.token as string; const token = object.token as string;
// Process the env token // Process the env token
if(this.isEnviromentTokenPlaceholder(token)) { if (this.isEnviromentTokenPlaceholder(token)) {
const envTokenName = this.parseEnvironmentTokenPlaceholderName(token)!; const envTokenName = this.parseEnvironmentTokenPlaceholderName(token)!;
const envValue = process.env[envTokenName]; const envValue = process.env[envTokenName];
if(!envValue) { if (!envValue) {
Logger.error(`Environment variable ${envTokenName} not found`); Logger.error(`Environment variable ${envTokenName} not found`);
return false; return false;
} }
@@ -216,41 +221,43 @@ class Deamon {
} }
private isZoneConfig(object: any): object is ZoneConfig { private isZoneConfig(object: any): object is ZoneConfig {
if (!this.arraysEqual(Object.keys(object), ["id", "type", "name", "content", "ttl", "proxied"]))
if(!this.arraysEqual(Object.keys(object), ['id', 'type', 'name', 'content', 'ttl', 'proxied']))
return false; return false;
const res =
object &&
object.id &&
typeof object.id == "string" &&
object.type &&
typeof object.type == "string" &&
object.name &&
typeof object.name == "string" &&
object.content &&
typeof object.content == "string" &&
object.ttl &&
typeof object.ttl == "number" &&
typeof object.proxied == "boolean";
const res = object && if (!res) return false;
object.id && typeof(object.id) == 'string' &&
object.type && typeof(object.type) == 'string' &&
object.name && typeof(object.name) == 'string' &&
object.content && typeof(object.content) == 'string' &&
object.ttl && typeof(object.ttl) == 'number' &&
typeof(object.proxied) == 'boolean';
if(!res) return false;
return true; return true;
} }
private isEnviromentTokenPlaceholder(token: string) { private isEnviromentTokenPlaceholder(token: string) {
return token.startsWith('{ENV_TOKEN:') && token.endsWith('}'); return token.startsWith("{ENV_TOKEN:") && token.endsWith("}");
} }
private parseEnvironmentTokenPlaceholderName(token: string) { private parseEnvironmentTokenPlaceholderName(token: string) {
if(!this.isEnviromentTokenPlaceholder(token)) return null; if (!this.isEnviromentTokenPlaceholder(token)) return null;
return token.split('{ENV_TOKEN:')[1].slice(0, -1); return token.split("{ENV_TOKEN:")[1].slice(0, -1);
} }
private async getCurrentIPv4() { private async getCurrentIPv4() {
const response = await axios.get("https://api.ipify.org?format=json"); const response = await axios.get("https://api.ipify.org?format=json");
if(!response.data.ip) if (!response.data.ip) throw new Error("Unable to fetch ip address");
throw new Error("Unable to fetch ip address");
if(!validator.isIP(response.data.ip, 4)) if (!validator.isIP(response.data.ip, 4)) throw new Error("Invalid IP");
throw new Error("Invalid IP");
return response.data.ip; return response.data.ip;
} }
@@ -258,11 +265,9 @@ class Deamon {
private async getCurrentIPv6() { private async getCurrentIPv6() {
const response = await axios.get("https://api64.ipify.org/?format=json"); const response = await axios.get("https://api64.ipify.org/?format=json");
if(!response.data.ip) if (!response.data.ip) throw new Error("Unable to fetch ip address");
throw new Error("Unable to fetch ip address");
if(!validator.isIP(response.data.ip, 6)) if (!validator.isIP(response.data.ip, 6)) return null;
return null;
return response.data.ip; return response.data.ip;
} }
@@ -277,7 +282,6 @@ class Deamon {
} }
return true; return true;
} }
} }
class CloudflareAPI { class CloudflareAPI {
@@ -289,63 +293,112 @@ class CloudflareAPI {
this.zoneId = zoneId; this.zoneId = zoneId;
} }
public async getRecord({ name, type, content, proxied, page }: { name?: string, type?: string, content?: string, proxied?: boolean, page?: number }) { public async getRecord({
const response = await axios.get(`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records`, { name,
type,
content,
proxied,
page,
}: {
name?: string;
type?: string;
content?: string;
proxied?: boolean;
page?: number;
}) {
const response = await axios.get(
`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records`,
{
params: { params: {
name, name,
type, type,
perPage: 5000, perPage: 5000,
content, content,
proxied, proxied,
page page,
}, },
headers: { headers: {
'Authorization': `Bearer ${this.token}`, Authorization: `Bearer ${this.token}`,
'Content-Type': 'application/json' "Content-Type": "application/json",
} },
}); },
);
if(response.data.success !== true) if (response.data.success !== true)
throw new Error(`Unable to fetch record: ${response.data.errors[0].message}`); throw new Error(`Unable to fetch record: ${response.data.errors[0].message}`);
return response.data.result; return response.data.result;
} }
public async createRecord ({ name, type, content, ttl, proxied }: { name?: string, type?: string, content?: string, ttl: number, proxied?: boolean }) { public async createRecord({
const response = await axios.post(`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records`, { name,
type,
content,
ttl,
proxied,
}: {
name?: string;
type?: string;
content?: string;
ttl: number;
proxied?: boolean;
}) {
const response = await axios.post(
`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records`,
{
type, type,
name, name,
content, content,
ttl, ttl,
proxied proxied,
}, { },
{
headers: { headers: {
'Authorization': `Bearer ${this.token}`, Authorization: `Bearer ${this.token}`,
'Content-Type': 'application/json' "Content-Type": "application/json",
} },
}); },
);
if(response.data.success !== true) if (response.data.success !== true)
throw new Error(`Unable to create record: ${response.data.errors[0].message}`); throw new Error(`Unable to create record: ${response.data.errors[0].message}`);
return response.data.result; return response.data.result;
} }
public async updateRecord({ record_id, name, type, content, ttl, proxied }: { record_id: string, name?: string, type?: string, content?: string, ttl: number, proxied?: boolean }) { public async updateRecord({
const response = await axios.put(`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records/${record_id}`, { record_id,
name,
type,
content,
ttl,
proxied,
}: {
record_id: string;
name?: string;
type?: string;
content?: string;
ttl: number;
proxied?: boolean;
}) {
const response = await axios.put(
`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records/${record_id}`,
{
type, type,
name, name,
content, content,
ttl, ttl,
proxied proxied,
}, { },
{
headers: { headers: {
'Authorization': `Bearer ${this.token}`, Authorization: `Bearer ${this.token}`,
'Content-Type': 'application/json' "Content-Type": "application/json",
} },
}); },
);
if(response.data.success !== true) if (response.data.success !== true)
throw new Error(`Unable to update record: ${response.data.errors[0].message}`); throw new Error(`Unable to update record: ${response.data.errors[0].message}`);
return response.data.result; return response.data.result;
+6 -14
View File
@@ -3,12 +3,9 @@ import * as dotenv from "dotenv";
import Logger from "../libs/Logger"; import Logger from "../libs/Logger";
const requiredENV = [ const requiredENV = ["NODE_ENV"];
'NODE_ENV',
];
class Environment { class Environment {
public init(): void { public init(): void {
dotenv.config({ path: path.resolve(__dirname, "../../.env") }); dotenv.config({ path: path.resolve(__dirname, "../../.env") });
@@ -21,31 +18,26 @@ class Environment {
if (this.get().NODE_ENV != "production" && this.get().NODE_ENV != "development") if (this.get().NODE_ENV != "production" && this.get().NODE_ENV != "development")
throw new Error('.env NODE_ENV must be either "production" or "development"'); throw new Error('.env NODE_ENV must be either "production" or "development"');
Logger.log('info', `Running in ${process.env.NODE_ENV} environment`); Logger.log("info", `Running in ${process.env.NODE_ENV} environment`);
} }
public get(): any { public get(): any {
const NODE_ENV = process.env.NODE_ENV; const NODE_ENV = process.env.NODE_ENV;
return { return {
NODE_ENV NODE_ENV,
}; };
} }
private isUndefinedOrEmpty(value: String | undefined): boolean { private isUndefinedOrEmpty(value: String | undefined): boolean {
if(typeof value === 'undefined') if (typeof value === "undefined") return true;
return true;
if(value === undefined) if (value === undefined) return true;
return true;
if(value === '') if (value === "") return true;
return true;
return false; return false;
} }
} }
export default new Environment(); export default new Environment();
+1 -1
View File
@@ -89,7 +89,7 @@
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
"alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ "alwaysStrict": true /* Ensure 'use strict' is always emitted. */,
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */