@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
48 lines • 2.4 kB
TypeScript
import { type TelescopeModuleOptions } from './telescope.options.js';
import { TelescopeService } from './telescope.service.js';
/**
* Public front-end error ingestion. Mounted on a SEPARATE controller from the
* gated dashboard API (like {@link TelescopeAuthController}) so it carries NO
* `@UseGuards(TelescopeGuard)` — ordinary users' browsers hit it, they have no
* dashboard session. Security is instead the per-endpoint knobs in
* {@link ClientErrorsOptions}: an opt-in `enabled` flag (404 while off), a body
* byte cap, a per-IP token bucket, and an optional `authorize` hook.
*
* Records every accepted error as a `client_exception` entry through the normal
* pipeline so it composes with new-exception alerts, per-type prune/archive, and
* the dashboard — with a family-hash mirroring server exceptions and the
* `failed` / `client` / `user:<id>` tags.
*/
export declare class ClientErrorController {
private readonly options;
private readonly service;
private readonly logger;
/** Per-pod, bounded token bucket (lazily built so a disabled endpoint is free). */
private rateLimiter;
/** One warn for an authorize-hook throw, so a flaky hook can't spam logs. */
private warnedAuthorize;
constructor(options: TelescopeModuleOptions, service: TelescopeService);
ingest(body: unknown, request: unknown): Promise<void>;
/** Build (once) the per-pod token bucket from the resolved rate-limit config. */
private limiter;
/**
* Run the host's authorize hook defensively: a throw is a DENIAL (fail closed)
* and warn-logged once, so a buggy hook never 500s the public endpoint nor
* floods the logs.
*/
private runAuthorize;
/**
* Best-effort serialized byte size of the parsed body. The framework already
* parsed JSON by the time we get here, so we re-serialize to measure bytes
* (UTF-8) — a tight enough proxy for the wire size to reject oversized
* payloads. A non-serializable body counts as 0 (it'll fail validation anyway).
*/
private bodyByteSize;
/**
* Extract the reporting client's IP: the first hop of `x-forwarded-for` when
* present (the original client behind a proxy), else `request.ip` /
* `socket.remoteAddress`. Returns `null` when nothing usable is found.
*/
private clientIp;
}
//# sourceMappingURL=client-error.controller.d.ts.map