@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
99 lines • 5.1 kB
TypeScript
import { Logger } from '@nestjs/common';
import { type Entry } from '../entry/entry.js';
import type { StorageProvider } from '../storage/storage-provider.js';
import type { TelescopeAiOptions } from './diagnoser.js';
import { DiagnosisCache } from './diagnosis-cache.js';
/**
* Default grace an alert waits for an in-flight auto-mode diagnosis before
* dispatching WITHOUT it. Kept short: the alert is the time-critical artifact, so
* we'd rather page promptly with no AI note than hold the page waiting on a model.
*/
declare const DEFAULT_ALERT_GRACE_MS = 10000;
/** Outcome of a diagnose request: the markdown plus whether it was a cache hit. */
export interface DiagnoseResult {
markdown: string;
cached: boolean;
}
/**
* Central AI-diagnosis coordinator. Owns the diagnoser, the per-family cache, and
* the auto-mode wiring. Constructed only when the host configures `ai`; the
* service injects nothing AI-related otherwise, so the feature is zero-cost off.
*
* Two entry points:
* - {@link diagnose}: on-demand, behind the dashboard endpoint. Cache-first
* (unless `force`), and a diagnoser rejection PROPAGATES so the controller can
* map it to a safe 5xx.
* - {@link onNewFamily}: auto-mode. Called from the alerter's first-seen signal.
* Fire-and-forget — it NEVER throws into the flush path; a failure is swallowed
* and logged. The in-flight promise is tracked so an alert firing for the same
* family can briefly await it ({@link awaitForAlert}) and attach the result.
*/
export declare class DiagnosisCoordinator {
private readonly storage;
private readonly logger;
private readonly diagnoser;
readonly mode: 'auto' | 'on-demand';
private readonly cache;
/** In-flight auto-mode diagnoses keyed by familyHash (so alerts can await). */
private readonly inFlight;
private readonly alertGraceMs;
/** First-seen tracker backing auto-mode (independent of the alerter's). */
private readonly newFamilyTracker;
private readonly newFamilyWindowMs;
private readonly now;
constructor(options: TelescopeAiOptions, storage: StorageProvider, deps?: {
cache?: DiagnosisCache;
logger?: Logger;
alertGraceMs?: number;
now?: () => number;
});
/**
* Auto-mode flush hook, wired into the Recorder's `onFlushStored` path (the
* SAME path the new-exception alert evaluates on). For each just-stored
* exception, do a cheap first-seen check; on a genuinely NEW family kick off a
* fire-and-forget diagnosis. Independent of whether a `new-exception` ALERT
* rule is configured — auto-diagnosis is its own feature. No-op in on-demand
* mode. NEVER throws into the flush path.
*/
observeFlush(storedEntries: Entry[]): void;
/**
* On-demand diagnosis for an exception entry. Serves from cache unless `force`.
* A diagnoser rejection propagates to the caller (the endpoint turns it into a
* safe 502). On success the result is cached by family for the next reader.
*
* @throws whatever the diagnoser rejects with (timeout/model error).
*/
diagnose(entry: Entry, occurrenceCount: number, force?: boolean): Promise<DiagnoseResult>;
/**
* Read-only, cache-ONLY lookup for an entry's diagnosis. Returns the cached
* markdown for the entry's family, or `null` on a miss / when the entry has no
* family hash. NEVER builds context and NEVER calls the diagnoser — so it costs
* nothing and can be safely fetched on every detail-page open. This is what
* makes an auto-mode (or previously on-demand) diagnosis visible immediately:
* the cache was populated by `observeFlush`/`onNewFamily` (auto) or a prior
* `diagnose` (on-demand), and this just surfaces it without re-running.
*/
peekCached(entry: Entry): string | null;
/**
* Auto-mode hook: a NEW exception family was just seen. Kick off diagnosis
* fire-and-forget and cache the result. NEVER throws — this runs inside the
* flush/alert path. If a diagnosis for this family is already in flight or
* already cached, do nothing (at most once per family per cache window).
*
* Returns the tracked promise (resolving to the markdown, or `null` on
* failure) so the alert path can await it; callers on the flush path ignore it.
*/
onNewFamily(entry: Entry, occurrenceCount: number): Promise<string | null>;
/**
* Briefly await an in-flight (or cached) diagnosis for `familyHash`, for the
* alert path to attach it. Returns the markdown if ready within the grace cap,
* else `null` (the alert dispatches without it). Never throws.
*/
awaitForAlert(familyHash: string, graceMs?: number): Promise<string | null>;
/** True when running in `'auto'` mode (the alerter wires the first-seen hook). */
get isAuto(): boolean;
/** Run + cache one diagnosis, swallowing every failure. Clears the in-flight slot. */
private runDiagnosis;
}
export { DEFAULT_ALERT_GRACE_MS };
//# sourceMappingURL=diagnosis-coordinator.d.ts.map