@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
194 lines • 8.95 kB
TypeScript
import { type OnApplicationShutdown, type OnModuleInit } from '@nestjs/common';
import { DiagnosisCoordinator } from '../ai/diagnosis-coordinator.js';
import type { AuthMode, ResolvedDashboardAuth } from '../auth/dashboard-auth-config.js';
import type { ResolvedCoreConfig } from '../config/options.js';
import { type ContextAccessor } from '../context/context-accessor.js';
import { TelescopeContext } from '../context/telescope-context.js';
import { type BatchOrigin, type RecordInput } from '../entry/entry.js';
import { ExtensionRegistry } from '../extension/registry.js';
import type { DashboardSection, Panel } from '../extension/types.js';
import { type RecorderSelfMetrics } from '../recorder/recorder.js';
import { EntryEvents } from '../sse/entry-events.js';
import type { StorageProvider } from '../storage/storage-provider.js';
import { type ExceptionCaptureDetails } from './exception-capture.js';
import { type TelescopeModuleOptions } from './telescope.options.js';
import type { BatchHandle } from './watcher.js';
export interface TelescopeMeta {
enabled: boolean;
droppedCount: number;
watchers: string[];
traceLink: string | null;
/**
* Whether the host wired a `traceContext` provider. When `false`, every entry's
* `trace_id` is null, so the dashboard's Traces page is permanently empty — the
* UI hides that nav item, mirroring how unregistered watchers hide their types.
*/
tracesEnabled: boolean;
/** Resolved retention window from `prune`, or `null` when unbounded. */
retention: {
afterMs: number;
keepLast: number | null;
} | null;
/**
* Whether on-demand pruning is available from the dashboard: requires both a
* configured retention window (`prune`) AND mutations enabled (`authorizeAction`
* present, the same default-deny gate the queue mutations use). When `false`,
* the dashboard hides/disables the "Prune now" control.
*/
pruneEnabled: boolean;
/**
* Whether the query EXPLAIN feature is available (the host configured an
* `explainQuery` hook). When `false`, the dashboard hides the "Explain" button.
*/
explainEnabled: boolean;
/** Resolved per-type sample rates (0..1). Empty when no sampling configured. */
sampling: Record<string, number>;
/**
* Dashboard cookie-auth state for the AUTHENTICATED UI (e.g. showing a logout
* button + the active modes). The UNauthenticated SPA learns the modes from
* the 401 body of `GET /api/auth/me` instead — meta stays behind the gate.
*/
auth: {
enabled: boolean;
modes: AuthMode[];
};
/**
* Webhook alerting state: whether `alerts` is configured and how many rules
* are armed. The dashboard surfaces this as a read-only "Alerts: N rules" badge.
*/
alerts: {
enabled: boolean;
ruleCount: number;
};
/**
* AI exception-diagnosis state. `enabled` is true when the host configured a
* `diagnoser`; the dashboard renders the "Diagnose with AI" button on exception
* detail pages only then. `mode` mirrors the configured mode (`'on-demand'` by
* default), purely informational for the UI.
*/
ai: {
enabled: boolean;
mode: 'auto' | 'on-demand' | null;
};
/**
* CPU flamegraph profiling state. `enabled` gates the dashboard's Profiles tab;
* `sampleRate` is surfaced as a read-only badge. Both come straight from the
* resolved config (off by default).
*/
profiling: {
enabled: boolean;
sampleRate: number;
};
/** Entry types contributed by extensions (id/label/dot) — feeds the UI nav. */
entryTypes: {
id: string;
label: string;
dot: string;
}[];
/** Dashboards contributed by extensions — feeds the UI nav + routes + panel rendering. */
dashboards: {
id: string;
label: string;
navGroup?: string;
panels: Panel[];
sections?: DashboardSection[];
}[];
}
/**
* Self-observability snapshot for surfacing Telescope's OWN overhead. Combines
* the Recorder's cheap self-metrics with whether capture is enabled and an
* on-demand micro-benchmark of the per-capture cost (never measured on the live
* `record()` path).
*/
export interface TelescopeHealth extends RecorderSelfMetrics {
/** Whether capture is currently enabled (from config). */
enabled: boolean;
/** Mean nanoseconds per capture, from an on-demand micro-benchmark. */
captureCostNanos: number;
}
export declare class TelescopeService implements OnModuleInit, OnApplicationShutdown {
private readonly config;
private readonly storage;
private readonly options;
private readonly dashboardAuth;
private readonly extensions;
private readonly contextAccessor;
private readonly entryEvents;
readonly context: TelescopeContext;
private readonly recorder;
private readonly logger;
private flushTimer;
private watcherTypes;
/** Resolved (boot-validated) alerting config, or `null` when unconfigured. */
private readonly alerts;
private alerter;
/** AI exception-diagnosis coordinator, or `null` when `ai` is unconfigured. */
private readonly diagnosis;
constructor(config: ResolvedCoreConfig, storage: StorageProvider, options: TelescopeModuleOptions, dashboardAuth?: ResolvedDashboardAuth | null, extensions?: ExtensionRegistry, contextAccessor?: ContextAccessor | undefined, entryEvents?: EntryEvents);
/**
* Record a developer debug dump into the Dumps tab. The value is redacted by
* the Recorder and correlated to the active batch automatically. Prefer the
* free `telescopeDump()` at call sites that don't already inject this service.
*/
dump(value: unknown, label?: string): void;
/** Normalized mount segment (no leading/trailing slash). Default `'telescope'`. */
get path(): string;
/**
* Host-supplied hook to resolve the authenticated user from a raw request
* (used by the request middleware). `undefined` when the host didn't supply
* one — the middleware then falls back to reading `request.user`.
*/
get resolveUser(): ((request: unknown) => unknown) | undefined;
onModuleInit(): Promise<void>;
onApplicationShutdown(): Promise<void>;
/** Register the set of active watcher type names (for meta). */
/** @internal Used by TelescopeWatcherRegistrar; not part of the public API. */
setWatchers(types: string[]): void;
record(input: RecordInput): void;
/**
* Turn a thrown error into the same `exception` entry the Nest interceptor
* produces — same family hash, same 4xx control-flow policy, same content
* shape — for code that runs OFF the Nest execution pipeline: a queue job
* body, a scheduled callback, a durable workflow step, an event listener.
*
* Records into whatever batch is active on the current async context, so an
* exception thrown inside a watcher's `runInBatch` scope correlates to that
* job/run instead of standing alone. Never throws (see `captureException`),
* so a caller on its own failure path can call this immediately before
* re-throwing the host's error without any risk of replacing it.
*/
recordException(error: unknown, details?: ExceptionCaptureDetails): void;
runInBatch<T>(origin: BatchOrigin, fn: () => Promise<T>): Promise<T>;
/**
* Open a batch and make it active for the current async execution (no
* callback scope). Returns a handle; `end()` is a no-op today (the async
* scope ends naturally) but is part of the contract for future cleanup.
*/
beginBatch(origin: BatchOrigin): BatchHandle;
flush(): Promise<void>;
/**
* Pause capture (overload protection). While paused the Recorder drops new
* `record()` calls; flushing continues so the buffer drains. Driven by the
* OverloadGuard when event-loop lag crosses its threshold.
*/
pause(): void;
/** Resume capture after a {@link pause}. */
resume(): void;
/** Whether capture is currently paused by overload protection. */
get isPaused(): boolean;
getMeta(): Promise<TelescopeMeta>;
/**
* AI exception-diagnosis coordinator, or `null` when `ai` is unconfigured. The
* gated controller reads this to run the on-demand `diagnose` endpoint (and to
* 404 when AI is off).
*/
get diagnosisCoordinator(): DiagnosisCoordinator | null;
/**
* Self-observability snapshot: the Recorder's cheap self-metrics plus an
* on-demand micro-benchmark of the per-capture cost. The benchmark runs the
* synchronous enrich path on a representative input WITHOUT enqueuing, so it
* never pollutes the live buffer or taxes real records.
*/
getHealth(): TelescopeHealth;
}
//# sourceMappingURL=telescope.service.d.ts.map