const pageConfig = { // Title for your status page title: "lyc8503's Status Page", // Links shown at the header of your status page, could set `highlight` to `true` links: [ { link: 'https://github.com/lyc8503', label: 'GitHub' }, { link: 'https://blog.lyc8503.site/', label: 'Blog' }, { link: 'mailto:me@lyc8503.site', label: 'Email Me', highlight: true }, ], } const workerConfig = { // Write KV at most every 10 minutes unless the status changed. kvWriteCooldownMinutes: 10, // Define all your monitors here monitors: [ // Example HTTP Monitor { // `id` should be unique, history will be kept if the `id` remains constant id: 'foo_monitor', // `name` is used at status page and callback message name: 'My API Monitor', // `url` for clickable link at status page url: 'https://example.com', // `method` should be a valid HTTP Method method: 'POST', // `target` is a valid URL target: 'https://example.com', // [OPTIONAL] `tooltip` is only used at status page to show a tooltip tooltip: 'This is a tooltip for this monitor', // [OPTIONAL] `expectedCodes` is an array of acceptable HTTP response codes, if not specified, default to 2xx expectedCodes: [200], // [OPTIONAL] `timeout` in millisecond, if not specified, default to 10000 timeout: 10000, // [OPTIONAL] headers to be sent headers: { 'User-Agent': 'Uptimeflare', Authorization: 'Bearer YOUR_TOKEN_HERE', }, // [OPTIONAL] body to be sent body: 'Hello, world!', // [OPTIONAL] if specified, the response must contains the keyword to be considered as operational. responseKeyword: 'success', // [OPTIONAL] if specified, the check will run in your specified region, // refer to docs https://github.com/lyc8503/UptimeFlare/wiki/Geo-specific-checks-setup before setting this value checkLocationWorkerRoute: 'https://xxx.example.com', }, // Example TCP Monitor { id: 'test_tcp_monitor', name: 'Example TCP Monitor', // `method` should be `TCP_PING` for tcp monitors method: 'TCP_PING', // `target` should be `host:port` for tcp monitors target: '1.2.3.4:22', tooltip: 'My production server SSH', timeout: 5000, }, ], callbacks: { onStatusChange: async ( env: Env, monitor: any, isUp: boolean, timeIncidentStart: number, timeNow: number, reason: string ) => { await notify(env, monitor, isUp, timeIncidentStart, timeNow, reason) }, onIncident: async ( env: Env, monitor: any, isUp: boolean, timeIncidentStart: number, timeNow: number, reason: string ) => { // This callback will be called EVERY 2 MINTUES if there's an on-going incident for any monitor // Write any Typescript code here }, }, } const escapeMarkdown = (text: string) => { return text.replace(/[_*[\](){}~`>#+\-=|.!\\]/g, '\\$&'); }; async function notify( env: Env, monitor: any, isUp: boolean, timeIncidentStart: number, timeNow: number, reason: string, ) { const dateFormatter = new Intl.DateTimeFormat('en-US', { month: 'numeric', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false, timeZone: 'Asia/Shanghai', }); let downtimeDuration = Math.round((timeNow - timeIncidentStart) / 60); const timeIncidentStartFormatted = dateFormatter.format(new Date(timeIncidentStart * 1000)); let statusText = isUp ? `The service is up again after being down for ${downtimeDuration} minutes.` : `Service became unavailable at ${timeIncidentStartFormatted}. Issue: ${reason || 'unspecified'}`; console.log('Notifying: ', monitor.name, statusText); if (env.BARK_SERVER && env.BARK_DEVICE_KEY) { try { let title = isUp ? `✅ ${monitor.name} is up again!` : `🔴 ${monitor.name} is currently down.`; await sendBarkNotification(env, monitor, title, statusText); } catch (error) { console.error('Error sending Bark notification:', error); } } if (env.SECRET_TELEGRAM_CHAT_ID && env.SECRET_TELEGRAM_API_TOKEN) { try { let operationalLabel = isUp ? 'Up' : 'Down'; let statusEmoji = isUp ? '✅' : '🔴'; let telegramText = `*${escapeMarkdown( monitor.name, )}* is currently *${operationalLabel}*\n${statusEmoji} ${escapeMarkdown(statusText)}`; await notifyTelegram(env, monitor, isUp, telegramText); } catch (error) { console.error('Error sending Telegram notification:', error); } } } export async function notifyTelegram(env: Env, monitor: any, operational: boolean, text: string) { const chatId = env.SECRET_TELEGRAM_CHAT_ID; const apiToken = env.SECRET_TELEGRAM_API_TOKEN; const payload = new URLSearchParams({ chat_id: chatId, parse_mode: 'MarkdownV2', text: text, }); try { const response = await fetch(`https://api.telegram.org/bot${apiToken}/sendMessage`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: payload.toString(), }); if (!response.ok) { console.error( `Failed to send Telegram notification "${text}", ${response.status} ${ response.statusText } ${await response.text()}`, ); } } catch (error) { console.error('Error sending Telegram notification:', error); } } async function sendBarkNotification(env: Env, monitor: any, title: string, body: string, group: string = '') { const barkServer = env.BARK_SERVER; const barkDeviceKey = env.BARK_DEVICE_KEY; const barkUrl = `${barkServer}/push`; const data = { title: title, body: body, group: group, url: monitor.url, device_key: barkDeviceKey, }; const response = await fetch(barkUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); if (response.ok) { console.log('Bark notification sent successfully.'); } else { const respText = await response.text(); console.error('Failed to send Bark notification:', response.status, response.statusText, respText); } } // Don't forget this, otherwise compilation fails. export { pageConfig, workerConfig }