@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
201 lines • 9.13 kB
TypeScript
import { ModuleRef } from '@nestjs/core';
import type { ResolvedCoreConfig } from '../config/options.js';
import { type Entry } from '../entry/entry.js';
import { ExtensionRegistry } from '../extension/registry.js';
import { type QueueMetricsResult, QueueMetricsService } from '../metrics/queue-metrics.service.js';
import { type ServerStats, type ServerStatsHistory, ServerStatsService } from '../metrics/server-stats.service.js';
import type { StatsResult } from '../metrics/stats.js';
import { StatsService } from '../metrics/stats.service.js';
import { type TimeseriesResult, TimeseriesService } from '../metrics/timeseries.service.js';
import { type TracesResult, TracesService } from '../metrics/traces.service.js';
import type { Waterfall } from '../metrics/waterfall.js';
import { ProfilerService } from '../profiling/profiler.service.js';
import type { CpuProfileContent } from '../profiling/types.js';
import { type PulseResult, PulseService } from '../pulse/pulse.service.js';
import { type JobPage, type QueueActionName, type QueueCounts, type QueueJobDetail, type QueueSummary } from '../queue/queue-manager.js';
import { QueueManagerRegistry } from '../queue/queue-manager.registry.js';
import type { ScheduledTask } from '../schedule/schedule-manager.js';
import { ScheduleManagerRegistry } from '../schedule/schedule-manager.registry.js';
import type { EntryWithBatch, Page, StorageProvider, TagCount } from '../storage/storage-provider.js';
import { type ReplayResult } from './request-replay.js';
import { type PruneRun, TelescopePruner } from './telescope-pruner.service.js';
import type { TelescopeModuleOptions } from './telescope.options.js';
import { type TelescopeHealth, type TelescopeMeta, TelescopeService } from './telescope.service.js';
interface ListQuery {
type?: string;
tag?: string;
familyHash?: string;
batchId?: string;
traceId?: string;
search?: string;
cursor?: string;
limit?: string;
}
export interface QueueCapabilities {
mutationsEnabled: boolean;
actionsByDriver: Record<string, QueueActionName[]>;
}
interface EnqueueBody {
name?: string;
payload?: unknown;
}
interface ExplainBody {
entryId?: string;
}
/**
* Retention/prune status surfaced to the dashboard. `retention` mirrors meta's
* shape (the configured window) or `null` when unbounded. `entryCount`/
* `oldestCreatedAt` are `null` unless the storage SPI can expose them cheaply
* (it currently can't — newest-first `get` has no count/oldest), so we never
* scan to derive them. `pruneSupported` advertises that the on-demand prune
* endpoint exists (separate from whether it's authorized/configured).
*/
export interface RetentionInfo {
retention: {
afterMs: number;
keepLast: number | null;
} | null;
entryCount: number | null;
oldestCreatedAt: string | null;
pruneSupported: true;
}
/** Resolved retention config surfaced to the Prunes screen. `null` when unset. */
export interface PrunesConfig {
afterMs: number;
intervalMs: number;
keepLast: number | null;
/** Per-type retention overrides (ms), omitted when none are configured. */
perType?: Record<string, number>;
}
/**
* Prune-run activity for the dashboard's Prunes screen: the in-memory ring of
* recent cycles (newest-first, PER-POD), the resolved retention config, and the
* predicted next scheduled run (`null` when no `prune` window is configured).
*/
export interface PrunesInfo {
runs: PruneRun[];
config: PrunesConfig | null;
nextRunAt: string | null;
}
export declare class TelescopeController {
private readonly storage;
private readonly service;
private readonly queueMetrics;
private readonly timeseriesService;
private readonly tracesService;
private readonly statsService;
private readonly serverStats;
private readonly pulse;
private readonly profiler;
private readonly queueManagers;
private readonly scheduleManagers;
private readonly options;
private readonly extensions;
private readonly extConfig;
private readonly pruner;
private readonly moduleRef;
constructor(storage: StorageProvider, service: TelescopeService, queueMetrics: QueueMetricsService, timeseriesService: TimeseriesService, tracesService: TracesService, statsService: StatsService, serverStats: ServerStatsService, pulse: PulseService, profiler: ProfilerService, queueManagers: QueueManagerRegistry, scheduleManagers: ScheduleManagerRegistry, options: TelescopeModuleOptions, extensions: ExtensionRegistry, extConfig: ResolvedCoreConfig, pruner: TelescopePruner, moduleRef: ModuleRef);
list(query: ListQuery): Promise<Page<Entry>>;
show(id: string): Promise<EntryWithBatch | null>;
replay(id: string, request: unknown): Promise<ReplayResult>;
batch(id: string): Promise<Entry[]>;
/**
* Tag counts for a picker: most-used first, ties alphabetical, narrowed by `search` and cut to one
* page.
*
* The page is re-applied HERE even though the provider was asked for it, because a provider is
* allowed to ignore the query — the contract says as much, so an older or third-party one simply
* returns everything. Without this line such a provider hands a picker more rows than it asked
* for, the picker reads that as "there is another page", and the next request returns the same
* rows again.
*/
tags(prefix?: string, search?: string, limit?: string, offset?: string): Promise<TagCount[]>;
queues(window?: string): Promise<QueueMetricsResult>;
pulseHealth(window?: string): Promise<PulseResult>;
timeseries(window?: string, buckets?: string, type?: string, tag?: string): Promise<TimeseriesResult>;
traces(window?: string, limit?: string): Promise<TracesResult>;
waterfall(traceId: string): Promise<Waterfall>;
stats(type?: string, window?: string, buckets?: string): Promise<StatsResult>;
liveQueues(): Promise<{
queues: QueueSummary[];
capabilities: QueueCapabilities;
}>;
liveSchedules(): Promise<{
tasks: ScheduledTask[];
}>;
liveCounts(driver: string, queue: string): Promise<QueueCounts>;
liveJobs(driver: string, queue: string, state?: string, cursor?: string, limit?: string): Promise<JobPage>;
liveJob(driver: string, queue: string, id: string): Promise<QueueJobDetail | null>;
jobAction(driver: string, queue: string, id: string, action: string): Promise<{
ok: true;
}>;
queueAction(driver: string, queue: string, action: string, state?: string): Promise<{
ok: true;
count?: number;
}>;
enqueue(driver: string, queue: string, body: EnqueueBody): Promise<{
id: string | null;
}>;
private callAction;
private requireManager;
meta(): Promise<TelescopeMeta>;
serverStatsSnapshot(): ServerStats;
serverStatsHistory(): ServerStatsHistory;
health(): TelescopeHealth;
extData(ext: string, provider: string, query: Record<string, unknown>): Promise<unknown>;
retention(): RetentionInfo;
prunes(): PrunesInfo;
prune(): Promise<{
pruned: number;
}>;
explain(body: ExplainBody): Promise<{
plan: unknown;
}>;
diagnose(id: string, force?: string): Promise<{
markdown: string;
cached: boolean;
}>;
cachedDiagnosis(id: string, res: unknown): Promise<{
markdown: string;
cached: true;
} | undefined>;
/** Count entries of this exception family in the trailing 24h (>= 1). */
private countExceptionFamily;
/**
* Profiler status for the dashboard's Profiles tab: whether the feature is
* enabled, the sample rate, and current capture activity. Read-shaped — sits
* behind the normal read guard. When profiling is disabled the tab shows an
* "enable `profiling`" empty state from this payload.
*/
profilesStatus(): ReturnType<ProfilerService['status']>;
/**
* List captured CPU profiles, newest-first, WITHOUT their (potentially large)
* frame trees — `omitContent` keeps the list cheap; the tree is fetched per
* profile via {@link profile}. Read-shaped.
*/
profiles(limit?: string): Promise<Page<Entry>>;
/**
* Fetch ONE profile's full frame tree (the flamegraph payload). 404 when the
* id is unknown or not a cpu_profile entry. Read-shaped.
*/
profile(id: string): Promise<Entry<CpuProfileContent>>;
/**
* Arm an on-demand capture of the next N requests (optionally only those whose
* normalized route matches `label`, e.g. "GET /users/:id"). A MUTATION-shaped
* trigger — it incurs real profiling overhead — so it stays behind the same
* default-deny `authorizeAction` gate as prune/replay. 400 when profiling is
* disabled (so the dashboard can explain why nothing happens).
*/
arm(body: ArmBody): {
pendingManual: number;
};
clear(): Promise<{
cleared: true;
}>;
}
interface ArmBody {
count?: number;
label?: string;
}
export type { ReplayResult };
//# sourceMappingURL=telescope.controller.d.ts.map