@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
79 lines • 3.22 kB
JavaScript
import { formatSlackMessage } from './slack-format.js';
/**
* POST timeout for the built-in HTTP channels. A hung endpoint must never stall
* the alerter's fan-out, so every request is raced against an abort timer.
*/
const HTTP_CHANNEL_TIMEOUT_MS = 5_000;
/**
* POST a JSON body to `url` with a hard abort timeout. Shared by the webhook and
* Slack channels — the ONLY difference between them is the body shape, so the
* transport lives here once. Rejects on network error / non-2xx-driven throw /
* timeout; the alerter turns that rejection into a rate-limited warn.
*/
async function postJson(fetchImpl, url, body) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), HTTP_CHANNEL_TIMEOUT_MS);
timeout.unref?.();
try {
await fetchImpl(url, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(body),
signal: controller.signal,
});
}
finally {
clearTimeout(timeout);
}
}
/**
* Raw-JSON webhook channel — today's v1 behavior, preserved verbatim: it POSTs
* the {@link AlertPayload} as-is so existing relays that parse the raw body keep
* working. The legacy top-level `webhookUrl` option is internally rewritten into
* one of these, which is why the payload shape stayed additive/backward-compatible.
*
* @param url Destination that receives `POST <AlertPayload as JSON>`.
* @param fetchImpl Test seam; defaults to global `fetch`.
*/
export function webhookChannel(url, fetchImpl) {
const send = fetchImpl ?? ((u, init) => fetch(u, init));
return {
name: 'webhook',
send(alert) {
return postJson(send, url, alert);
},
};
}
/**
* Slack-formatted channel — POSTs Block Kit JSON to a Slack incoming webhook so
* the message renders as a rich, human-readable card (severity header, fielded
* context, a truncated stack snippet, and a deep link to the dashboard entry when
* `dashboardUrl` is configured) instead of a raw JSON blob. See
* {@link formatSlackMessage} for the exact block structure and Slack's limits.
*
* @param url Slack incoming webhook URL.
* @param options Formatting knobs (currently `username`/`iconEmoji` overrides).
* @param fetchImpl Test seam; defaults to global `fetch`.
*/
export function slackChannel(url, options, fetchImpl) {
const send = fetchImpl ?? ((u, init) => fetch(u, init));
return {
name: 'slack',
send(alert) {
return postJson(send, url, formatSlackMessage(alert, options));
},
};
}
/**
* Custom channel — the escape hatch. The host supplies an arbitrary async sink
* (send an email, publish to SNS, page someone, write a row, …) and Telescope
* calls it with the rich {@link AlertPayload}. As with every channel, a rejection
* is isolated and logged by the alerter, so the host's `fn` may freely throw.
*
* @param fn Async sink invoked with the fired alert payload.
* @param name Identifier for failure logging. Defaults to `"custom"`.
*/
export function customChannel(fn, name = 'custom') {
return { name, send: fn };
}
//# sourceMappingURL=alert-channel.js.map