feat: complete i18n support, telegram webhook, and security improvements

This commit is contained in:
AyrisAI
2026-05-14 13:46:17 +03:00
parent 4c9a07e3ef
commit cc65a2bd72
23 changed files with 798 additions and 205 deletions

View File

@@ -4,22 +4,38 @@
* Uses the single super-admin API key from .env.
*/
const BASE = process.env.MAILCOW_API_URL?.replace(/\/$/, "") ?? "";
let BASE = process.env.MAILCOW_API_URL?.replace(/\/$/, "") ?? "";
if (BASE && !BASE.startsWith("http")) {
BASE = `https://${BASE}`;
}
const KEY = process.env.MAILCOW_API_KEY ?? "";
async function mfetch(path: string, options: RequestInit = {}) {
if (!BASE || !KEY) {
console.error("[Mailcow API] MAILCOW_API_URL or MAILCOW_API_KEY is not set in .env");
return new Response(JSON.stringify({ error: "Server configuration error" }), { status: 500 });
}
const url = `${BASE}/api/v1${path}`;
const res = await fetch(url, {
...options,
headers: {
"Content-Type": "application/json",
"X-API-Key": KEY,
...options.headers,
},
// Don't cache — always fresh
cache: "no-store",
});
return res;
console.log(`[Mailcow API] ${options.method || "GET"} ${url}`);
try {
const res = await fetch(url, {
...options,
headers: {
"Content-Type": "application/json",
"X-API-Key": KEY,
...options.headers,
},
cache: "no-store",
});
if (!res.ok) {
const text = await res.text();
console.error(`[Mailcow API] Error ${res.status}: ${text}`);
}
return res;
} catch (err: any) {
console.error(`[Mailcow API] Fetch failed: ${err.message}`);
return new Response(JSON.stringify({ error: "Connection to Mailcow failed" }), { status: 503 });
}
}
// ─── Types ─────────────────────────────────────────────────
@@ -88,11 +104,14 @@ export async function createDomain(payload: {
active: 1,
aliases: 400,
mailboxes: 10,
defquota: 3072,
maxquota: 10240,
defquota: Math.min(payload.quota || 10240, 3072),
maxquota: payload.quota || 10240,
quota: 10240,
...payload,
};
// Double check constraints
if (body.maxquota > body.quota) body.maxquota = body.quota;
if (body.defquota > body.maxquota) body.defquota = body.maxquota;
const res = await mfetch("/add/domain", { method: "POST", body: JSON.stringify(body) });
const data = await res.json();
return { ok: res.ok, data };