import type { ExceptionContent } from '../entry/content.js';
import { type RecordInput } from '../entry/entry.js';
import type { ExceptionsOptions } from './telescope.options.js';
/**
 * Where a throw happened, for the doors that know something the stack doesn't.
 *
 * The Nest interceptor passes nothing (the request entry in the same batch
 * already says which route it was). A queue or schedule watcher DOES have
 * context worth keeping — which queue, which job id, which cron task — because
 * off the request path there is no sibling `request` entry to read it from.
 */
export interface ExceptionCaptureDetails {
    /** Merged into the entry's `content.context` (queue + job name, task name, …). */
    context?: Record<string, unknown>;
    /** Extra tags appended to the exception entry. */
    tags?: string[];
}
/**
 * Decides whether a thrown error is expected 4xx control flow that should NOT
 * become an exception entry. True only for a NestJS `HttpException` whose
 * `getStatus()` is a 4xx (>= 400 and < 500), and only while the
 * `captureHttp4xx` escape hatch is off (the default).
 *
 * WHY the default-skip: expected 4xx control flow is NOT an incident. A
 * `ForbiddenException` (403), `NotFoundException` (404) or a validation 400 is
 * the framework doing its job — permission denied, resource missing, bad input.
 * Recording those as exception entries means every permission denial in
 * production opens a NEW exception family (the family hash keys on
 * name+message+top-frame, so each call site is its own family), which fires the
 * `new-exception` Slack alert and, in AI auto-mode, spends model tokens on a
 * "diagnosis" of intended behaviour. We hit exactly this: Telescope's own
 * client-errors `authorize` gate threw a 403, it was captured as a brand-new
 * family, paged Slack, and burned an AI diagnosis.
 *
 * This applies to EVERY door, not just HTTP. An `HttpException` thrown inside a
 * job body is the same expected control flow (hosts routinely reuse
 * `NotFoundException` in services that both a controller and a worker call), so
 * a queue retry storm must not be able to page on-call through the back door
 * that the front door was hardened against.
 *
 * Detected via `instanceof HttpException` from `@nestjs/common` (a peer dep),
 * which also covers all the built-in subclasses (`ForbiddenException`,
 * `NotFoundException`, `BadRequestException`, the validation-pipe 400, …).
 */
export declare function isExpectedHttpControlFlow(error: unknown, options: ExceptionsOptions | undefined): boolean;
/**
 * Build the `exception` entry for a thrown value. A non-`Error` throw (a string,
 * a rejected object) is normalised into an `Error` so `class`/`message` are
 * always populated and the family hash is always computable.
 */
export declare function toExceptionRecordInput(error: unknown, details?: ExceptionCaptureDetails): RecordInput<ExceptionContent>;
/**
 * Apply the 4xx policy and, when the error survives it, hand the exception
 * entry to `record`. Returns whether an entry was recorded (the watchers ignore
 * it; it exists so tests and future doors can assert the decision).
 *
 * This function NEVER throws. Every caller is on the host's own failure path —
 * an rxjs `catchError`, a `catch` block that is about to re-throw a job's error
 * — and a throw from here would REPLACE the host's original error with a
 * Telescope error, turning an observability bug into a data-loss bug. Building
 * the entry (`String(error)` on a hostile `toString`, a getter on `err.stack`)
 * runs on the host's thread, so the guard has to be here and not only inside
 * the Recorder.
 */
export declare function captureException(record: (input: RecordInput) => void, error: unknown, options: ExceptionsOptions | undefined, details?: ExceptionCaptureDetails): boolean;
//# sourceMappingURL=exception-capture.d.ts.map