forked from c-fu/arah2
- Deploy walkthrough revealed a bare workers.dev origin setWebhook answers ok but drops updates at / (404) - Normalize WEBHOOK_URL: no path -> append /telegram/webhook; invalid URL -> fail fast, never echo values (T-02-04) - .dev.vars.example documents the path expectation
94 lines
3.5 KiB
JavaScript
94 lines
3.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/*
|
|
* set-webhook.mjs — one-time setWebhook registration (D-16, D-17).
|
|
* -----------------------------------------------------------------
|
|
* Points Telegram at the Worker's /telegram/webhook route and arms the
|
|
* secret-token channel: the `secret_token` value sent here is the one
|
|
* Telegram echoes back in X-Telegram-Bot-Api-Secret-Token on every update,
|
|
* which the Worker's webhook adapter constant-time-compares against
|
|
* env.WEBHOOK_SECRET (T-02-03).
|
|
*
|
|
* Inputs come from bot/.dev.vars (gitignored, D-15): BOT_TOKEN,
|
|
* WEBHOOK_URL, WEBHOOK_SECRET. The bot token is never echoed — on failure
|
|
* only the API's error_code/description are printed (T-02-04).
|
|
* WEBHOOK_URL is normalized: if the configured origin points at the
|
|
* workers.dev root (no path), /telegram/webhook is appended automatically —
|
|
* a bare origin passed the 2026-10-22 deploy walkthrough caused Telegram to
|
|
* answer ok but deliver nothing (updates routed to "/" → 404).
|
|
* Exit 0 only when Telegram answers ok:true.
|
|
*/
|
|
import { readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
function readDevVars() {
|
|
const devVarsPath = path.join(fileURLToPath(new URL(import.meta.url)), "..", "..", ".dev.vars");
|
|
let raw = "";
|
|
try {
|
|
raw = readFileSync(devVarsPath, "utf8");
|
|
} catch {
|
|
return {};
|
|
}
|
|
const vars = {};
|
|
for (const line of raw.split("\n")) {
|
|
const trimmed = line.trim();
|
|
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
const eq = trimmed.indexOf("=");
|
|
if (eq === -1) continue;
|
|
vars[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
|
|
}
|
|
return vars;
|
|
}
|
|
|
|
const devVars = readDevVars();
|
|
const token = process.env.BOT_TOKEN ?? devVars.BOT_TOKEN;
|
|
const webhookUrl = process.env.WEBHOOK_URL ?? devVars.WEBHOOK_URL;
|
|
const secret = process.env.WEBHOOK_SECRET ?? devVars.WEBHOOK_SECRET;
|
|
|
|
const missing = ["BOT_TOKEN", "WEBHOOK_URL", "WEBHOOK_SECRET"].filter(
|
|
(name) => !{ BOT_TOKEN: token, WEBHOOK_URL: webhookUrl, WEBHOOK_SECRET: secret }[name],
|
|
);
|
|
if (missing.length > 0) {
|
|
console.error(`Missing ${missing.join(", ")} — set them in bot/.dev.vars (see .dev.vars.example; never commit).`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Auto-append the route path when the URL has none — prevents the recurring
|
|
// misconfiguration where a bare workers.dev origin is registered and the
|
|
// Worker answers ok:true but Telegram updates land on "/" (404, silent drop).
|
|
const WEBHOOK_ROUTE = "/telegram/webhook";
|
|
let normalizedUrl;
|
|
try {
|
|
const parsed = new URL(webhookUrl);
|
|
if (parsed.pathname === "/" || parsed.pathname === "") {
|
|
parsed.pathname = WEBHOOK_ROUTE;
|
|
normalizedUrl = parsed.toString();
|
|
console.log(`WEBHOOK_URL had no path — normalized to ...${WEBHOOK_ROUTE}`);
|
|
} else {
|
|
normalizedUrl = webhookUrl;
|
|
}
|
|
} catch {
|
|
console.error(`WEBHOOK_URL is not a valid URL — check bot/.dev.vars (value never echoed).`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const payload = {
|
|
url: normalizedUrl,
|
|
secret_token: secret,
|
|
allowed_updates: ["message"],
|
|
};
|
|
|
|
const res = await fetch(`https://api.telegram.org/bot${token}/setWebhook`, {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
const body = await res.json();
|
|
|
|
if (!body.ok) {
|
|
console.error(`setWebhook failed: ${body.error_code ?? "?"} ${body.description ?? "unknown error"}`);
|
|
process.exit(1);
|
|
}
|
|
console.log(`setWebhook ok:true — updates will be delivered to the configured URL with the secret-token header.`);
|
|
process.exit(0);
|