mirror of
https://github.com/tiennm99/claude-status-webhook.git
synced 2026-04-17 17:21:05 +00:00
feat: implement Telegram bot for Claude status webhooks
Cloudflare Workers bot that forwards status.claude.com (Atlassian Statuspage) incident and component updates to subscribed Telegram users via CF Queues fan-out. - Hono.js routing with grammY webhook handler - Bot commands: /start, /stop, /status, /subscribe - Supergroup topic support (message_thread_id) - KV store with claude-status: prefix and composite keys - Queue consumer with batch send, 403 auto-removal, 429 retry - Timing-safe webhook secret validation - HTML escaping for Telegram messages
This commit is contained in:
53
src/status-fetcher.js
Normal file
53
src/status-fetcher.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const STATUS_API = "https://status.claude.com/api/v2/summary.json";
|
||||
|
||||
/**
|
||||
* Fetch all components from status.claude.com (excludes group-level entries)
|
||||
*/
|
||||
export async function fetchAllComponents() {
|
||||
const res = await fetch(STATUS_API);
|
||||
if (!res.ok) throw new Error(`Status API returned ${res.status}`);
|
||||
const data = await res.json();
|
||||
return data.components.filter((c) => !c.group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuzzy match a component by name (case-insensitive includes)
|
||||
*/
|
||||
export async function fetchComponentByName(name) {
|
||||
const components = await fetchAllComponents();
|
||||
return components.find((c) =>
|
||||
c.name.toLowerCase().includes(name.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable status label
|
||||
*/
|
||||
export function humanizeStatus(status) {
|
||||
const map = {
|
||||
operational: "Operational",
|
||||
degraded_performance: "Degraded Performance",
|
||||
partial_outage: "Partial Outage",
|
||||
major_outage: "Major Outage",
|
||||
under_maintenance: "Under Maintenance",
|
||||
investigating: "Investigating",
|
||||
identified: "Identified",
|
||||
monitoring: "Monitoring",
|
||||
resolved: "Resolved",
|
||||
};
|
||||
return map[status] || status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTML special chars for Telegram's HTML parse mode
|
||||
*/
|
||||
export function escapeHtml(s) {
|
||||
return s?.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a single component as HTML line
|
||||
*/
|
||||
export function formatComponentLine(component) {
|
||||
return `<b>${escapeHtml(component.name)}</b>: <code>${humanizeStatus(component.status)}</code>`;
|
||||
}
|
||||
Reference in New Issue
Block a user