mirror of
https://github.com/rajnandan1/kener.git
synced 2026-05-24 21:28:32 -05:00
feat: implement dynamic versioning in headers and documentation as reported in #346
This commit is contained in:
@@ -3,6 +3,7 @@ import Mustache from "mustache";
|
||||
import { DiscordJSONTemplate } from "../../anywhere.js";
|
||||
import variables from "./variables.js";
|
||||
import { GetRequiredSecrets, ReplaceAllOccurrences } from "../tool.js";
|
||||
import version from "../../version.js";
|
||||
|
||||
class Discord {
|
||||
url;
|
||||
@@ -15,7 +16,7 @@ class Discord {
|
||||
constructor(url, siteData, monitorData, trigger_meta) {
|
||||
const kenerHeader = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Kener",
|
||||
"User-Agent": `Kener/${version()}`,
|
||||
};
|
||||
|
||||
this.url = url;
|
||||
|
||||
@@ -3,56 +3,57 @@ import { Resend } from "resend";
|
||||
import nodemailer from "nodemailer";
|
||||
import getSMTPTransport from "./smtps.js";
|
||||
import { GetRequiredSecrets, ReplaceAllOccurrences } from "../tool.js";
|
||||
import version from "../../version.js";
|
||||
|
||||
class Email {
|
||||
to;
|
||||
from;
|
||||
method;
|
||||
siteData;
|
||||
monitorData;
|
||||
meta;
|
||||
to;
|
||||
from;
|
||||
method;
|
||||
siteData;
|
||||
monitorData;
|
||||
meta;
|
||||
|
||||
constructor(meta, siteData, monitorData) {
|
||||
this.to = meta.to;
|
||||
this.from = meta.from;
|
||||
this.siteData = siteData;
|
||||
this.monitorData = monitorData;
|
||||
constructor(meta, siteData, monitorData) {
|
||||
this.to = meta.to;
|
||||
this.from = meta.from;
|
||||
this.siteData = siteData;
|
||||
this.monitorData = monitorData;
|
||||
|
||||
let metaString = JSON.stringify(meta);
|
||||
let metaString = JSON.stringify(meta);
|
||||
|
||||
let envSecrets = GetRequiredSecrets(`${JSON.stringify(meta)}`);
|
||||
let envSecrets = GetRequiredSecrets(`${JSON.stringify(meta)}`);
|
||||
|
||||
for (let i = 0; i < envSecrets.length; i++) {
|
||||
const secret = envSecrets[i];
|
||||
metaString = ReplaceAllOccurrences(metaString, secret.find, secret.replace);
|
||||
}
|
||||
for (let i = 0; i < envSecrets.length; i++) {
|
||||
const secret = envSecrets[i];
|
||||
metaString = ReplaceAllOccurrences(metaString, secret.find, secret.replace);
|
||||
}
|
||||
|
||||
this.meta = JSON.parse(metaString);
|
||||
}
|
||||
this.meta = JSON.parse(metaString);
|
||||
}
|
||||
|
||||
transformData(data) {
|
||||
let ctaLink = data.actions[0].url;
|
||||
let ctaText = data.actions[0].text;
|
||||
let emailApiRequest = {
|
||||
from: this.from,
|
||||
to: this.to.split(",").map((email) => email.trim()),
|
||||
subject: `[${data.status}] ${data.alert_name} at ${data.timestamp}`,
|
||||
text: `Alert ${data.alert_name} has been ${data.status} at ${data.timestamp}. Click here to view the alert: ${ctaLink}`,
|
||||
html: ""
|
||||
};
|
||||
transformData(data) {
|
||||
let ctaLink = data.actions[0].url;
|
||||
let ctaText = data.actions[0].text;
|
||||
let emailApiRequest = {
|
||||
from: this.from,
|
||||
to: this.to.split(",").map((email) => email.trim()),
|
||||
subject: `[${data.status}] ${data.alert_name} at ${data.timestamp}`,
|
||||
text: `Alert ${data.alert_name} has been ${data.status} at ${data.timestamp}. Click here to view the alert: ${ctaLink}`,
|
||||
html: "",
|
||||
};
|
||||
|
||||
let bgColor = "#f4f4f4";
|
||||
if (data.severity == "critical") {
|
||||
bgColor = this.siteData.colors.DOWN;
|
||||
} else if (data.severity == "warning") {
|
||||
bgColor = this.siteData.colors.DEGRADED;
|
||||
}
|
||||
let bgColor = "#f4f4f4";
|
||||
if (data.severity == "critical") {
|
||||
bgColor = this.siteData.colors.DOWN;
|
||||
} else if (data.severity == "warning") {
|
||||
bgColor = this.siteData.colors.DEGRADED;
|
||||
}
|
||||
|
||||
if (data.status === "RESOLVED") {
|
||||
bgColor = this.siteData.colors.UP;
|
||||
}
|
||||
if (data.status === "RESOLVED") {
|
||||
bgColor = this.siteData.colors.UP;
|
||||
}
|
||||
|
||||
let html = `
|
||||
let html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -177,53 +178,53 @@ class Email {
|
||||
</table>
|
||||
|
||||
<div class="footer">
|
||||
This is an automated alert notification from ${this.siteData.siteName} monitoring system.
|
||||
This is an automated alert notification from ${this.siteData.siteName} monitoring system. It is being powered by <a href='https://kener.ing'>Kener</a> v${version()}.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
emailApiRequest.html = html;
|
||||
emailApiRequest.html = html;
|
||||
|
||||
return emailApiRequest;
|
||||
}
|
||||
return emailApiRequest;
|
||||
}
|
||||
|
||||
type() {
|
||||
return "email";
|
||||
}
|
||||
type() {
|
||||
return "email";
|
||||
}
|
||||
|
||||
async send(data) {
|
||||
let emailBody = this.transformData(data); // object containing email data (to, subject, text, html, etc)
|
||||
if (!this.meta.email_type || this.meta.email_type === "resend") {
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
try {
|
||||
return await resend.emails.send(emailBody);
|
||||
} catch (error) {
|
||||
console.error("Error sending webhook", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if (this.meta.email_type === "smtp") {
|
||||
// Configure the SMTP transporter using environment variables
|
||||
const transporter = getSMTPTransport(this.meta);
|
||||
async send(data) {
|
||||
let emailBody = this.transformData(data); // object containing email data (to, subject, text, html, etc)
|
||||
if (!this.meta.email_type || this.meta.email_type === "resend") {
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
try {
|
||||
return await resend.emails.send(emailBody);
|
||||
} catch (error) {
|
||||
console.error("Error sending webhook", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if (this.meta.email_type === "smtp") {
|
||||
// Configure the SMTP transporter using environment variables
|
||||
const transporter = getSMTPTransport(this.meta);
|
||||
|
||||
const mailOptions = {
|
||||
from: emailBody.from, // sender address
|
||||
to: Array.isArray(emailBody.to) ? emailBody.to.join(",") : emailBody.to, // recipient address(es)
|
||||
subject: emailBody.subject, // email subject
|
||||
text: emailBody.text, // plain text body
|
||||
html: emailBody.html // HTML body (if any)
|
||||
};
|
||||
const mailOptions = {
|
||||
from: emailBody.from, // sender address
|
||||
to: Array.isArray(emailBody.to) ? emailBody.to.join(",") : emailBody.to, // recipient address(es)
|
||||
subject: emailBody.subject, // email subject
|
||||
text: emailBody.text, // plain text body
|
||||
html: emailBody.html, // HTML body (if any)
|
||||
};
|
||||
|
||||
try {
|
||||
return await transporter.sendMail(mailOptions);
|
||||
} catch (error) {
|
||||
console.error("Error sending email via SMTP", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await transporter.sendMail(mailOptions);
|
||||
} catch (error) {
|
||||
console.error("Error sending email via SMTP", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Email;
|
||||
|
||||
@@ -3,6 +3,7 @@ import variables from "./variables.js";
|
||||
import { SlackJSONTemplate } from "../../anywhere.js";
|
||||
import Mustache from "mustache";
|
||||
import { GetRequiredSecrets, ReplaceAllOccurrences } from "../tool.js";
|
||||
import version from "../../version.js";
|
||||
|
||||
class Slack {
|
||||
url;
|
||||
@@ -15,7 +16,7 @@ class Slack {
|
||||
constructor(url, siteData, monitorData, trigger_meta) {
|
||||
const kenerHeader = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Kener",
|
||||
"User-Agent": `Kener/${version()}`,
|
||||
};
|
||||
|
||||
this.url = url;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { GetRequiredSecrets, ReplaceAllOccurrences } from "../tool.js";
|
||||
import Mustache from "mustache";
|
||||
import { WebhookJSONTemplate } from "../../anywhere.js";
|
||||
import variables from "./variables.js";
|
||||
import version from "../../version.js";
|
||||
|
||||
class Webhook {
|
||||
url;
|
||||
@@ -16,7 +17,7 @@ class Webhook {
|
||||
constructor(trigger_meta, method, siteData, monitorData) {
|
||||
const kenerHeader = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Kener/3.2.5",
|
||||
"User-Agent": `Kener/${version()}`,
|
||||
};
|
||||
let headers = trigger_meta.headers;
|
||||
this.trigger_meta = trigger_meta;
|
||||
|
||||
@@ -9,25 +9,12 @@ import { HashString } from "./tool.js";
|
||||
import { fileURLToPath } from "url";
|
||||
import { dirname, resolve } from "path";
|
||||
import fs from "fs";
|
||||
import version from "../version.js";
|
||||
|
||||
const jobs = [];
|
||||
process.env.TZ = "UTC";
|
||||
let isStartUP = true;
|
||||
|
||||
// Get the version from package.json
|
||||
const getVersion = () => {
|
||||
try {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const packagePath = resolve(__dirname, "../../../package.json");
|
||||
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
||||
return packageJson.version;
|
||||
} catch (error) {
|
||||
console.error("Error reading version:", error);
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
const scheduleCronJobs = async () => {
|
||||
// Fetch and map all active monitors, creating a unique hash for each
|
||||
const activeMonitors = (await GetMonitorsParsed({ status: "ACTIVE" })).map((monitor) => ({
|
||||
@@ -86,15 +73,13 @@ async function Startup() {
|
||||
|
||||
mainJob.trigger();
|
||||
|
||||
const version = getVersion();
|
||||
|
||||
figlet("Kener v" + version, function (err, data) {
|
||||
figlet("Kener v" + version(), function (err, data) {
|
||||
if (err) {
|
||||
console.log("Something went wrong...");
|
||||
return;
|
||||
}
|
||||
console.log(data);
|
||||
console.log(`Kener version ${version} is running!`);
|
||||
console.log(`Kener version ${version()} is running!`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { fileURLToPath } from "url";
|
||||
import { dirname, resolve } from "path";
|
||||
import fs from "fs";
|
||||
|
||||
function getVersionUsingVite() {
|
||||
try {
|
||||
if (!!import.meta.env.PACKAGE_VERSION) {
|
||||
return import.meta.env.PACKAGE_VERSION;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default function version() {
|
||||
let v = getVersionUsingVite();
|
||||
if (!!v) {
|
||||
return v;
|
||||
} else {
|
||||
try {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const packagePath = resolve(__dirname, "../../package.json");
|
||||
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
||||
return packageJson.version;
|
||||
} catch (e) {
|
||||
return "0.0.0";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import { marked } from "marked";
|
||||
import version from "$lib/version.js";
|
||||
|
||||
function extractMetadataAndContent(fileContent) {
|
||||
// Regular expression to match metadata section
|
||||
@@ -15,9 +16,7 @@ function extractMetadataAndContent(fileContent) {
|
||||
|
||||
if (match) {
|
||||
// Extract metadata section and remaining content
|
||||
const metadataLines = match[1]
|
||||
.split("\n")
|
||||
.filter((line) => line.trim() !== "");
|
||||
const metadataLines = match[1].split("\n").filter((line) => line.trim() !== "");
|
||||
result.content = fileContent.slice(match[0].length).trim(); // Remaining content after metadata
|
||||
|
||||
metadataLines.forEach((line) => {
|
||||
@@ -40,10 +39,7 @@ export async function load({ params, route, url, cookies, request }) {
|
||||
docFilePath = docFolderPath + `/${docFile}.md`;
|
||||
}
|
||||
const fileContents = await fs.readFileSync(docFilePath, "utf-8");
|
||||
const siteStructure = await fs.readFileSync(
|
||||
docFolderPath + "/structure.json",
|
||||
"utf-8",
|
||||
);
|
||||
const siteStructure = await fs.readFileSync(docFolderPath + "/structure.json", "utf-8");
|
||||
const { metadata, content } = extractMetadataAndContent(fileContents);
|
||||
|
||||
const selectedDoc = docFilePath.replace(docFolderPath, "");
|
||||
@@ -54,5 +50,6 @@ export async function load({ params, route, url, cookies, request }) {
|
||||
title: metadata.title || "Kener Docs",
|
||||
description: metadata.description || "Kener Docs",
|
||||
siteStructure: siteStructureJSON,
|
||||
kenerVersion: version(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import Moon from "lucide-svelte/icons/moon";
|
||||
import { onMount } from "svelte";
|
||||
import { base } from "$app/paths";
|
||||
import { page } from "$app/stores";
|
||||
let defaultTheme = "light";
|
||||
export let data;
|
||||
let siteStructure = data.siteStructure;
|
||||
@@ -111,7 +112,7 @@
|
||||
<img src="https://kener.ing/logo.png" class="h-8 w-8" alt="" />
|
||||
<span class="text-xl font-medium">Kener Documentation</span>
|
||||
<span class="me-2 rounded border px-2.5 py-0.5 text-xs font-medium">
|
||||
{import.meta.env.PACKAGE_VERSION}
|
||||
{$page.data.kenerVersion}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { redirect } from "@sveltejs/kit";
|
||||
import { base } from "$app/paths";
|
||||
import { MaskString } from "$lib/server/tool.js";
|
||||
import db from "$lib/server/db/db.js";
|
||||
import version from "$lib/version.js";
|
||||
//write a function to mask a string, just have last 4 characters visible
|
||||
|
||||
export async function load({ params, route, url, cookies, request }) {
|
||||
@@ -25,5 +26,6 @@ export async function load({ params, route, url, cookies, request }) {
|
||||
siteData,
|
||||
KENER_SECRET_KEY: !!process.env.KENER_SECRET_KEY ? MaskString(process.env.KENER_SECRET_KEY) : "",
|
||||
user: userDB,
|
||||
kenerVersion: version(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
import Github from "lucide-svelte/icons/github";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { afterNavigate } from "$app/navigation";
|
||||
|
||||
const version = import.meta.env.PACKAGE_VERSION;
|
||||
|
||||
import { page } from "$app/stores";
|
||||
import { Play, User } from "lucide-svelte";
|
||||
import { setMode, mode, ModeWatcher } from "mode-watcher";
|
||||
|
||||
@@ -23,7 +21,6 @@
|
||||
setMode("light");
|
||||
}
|
||||
}
|
||||
|
||||
// setMode("dark");
|
||||
|
||||
let nav = [
|
||||
@@ -168,8 +165,10 @@
|
||||
<a
|
||||
target="_blank"
|
||||
class="text-xs font-semibold text-muted-foreground hover:underline"
|
||||
href="https://kener.ing/docs/changelogs#v{version.replaceAll('.', '-')}">v{version}</a
|
||||
href="https://kener.ing/docs/changelogs#v{$page.data.kenerVersion.replaceAll('.', '-')}"
|
||||
>
|
||||
v{$page.data.kenerVersion}
|
||||
</a>
|
||||
by
|
||||
<a
|
||||
target="_blank"
|
||||
|
||||
Reference in New Issue
Block a user