UNPKG

@dudousxd/nestjs-telescope

Version:

Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.

99 lines 5.1 kB
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