UNPKG

@dudousxd/nestjs-telescope

Version:

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

201 lines 9.13 kB
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