type BaseErrorOptions = {
    /** Override the runtime error name. Intended for framework errors with stable codes. */
    name?: string;
};
/**
 * Replacement used by {@link BaseError.redact}/{@link BaseError.redactAllow}.
 * Either a fixed value, or a function of the original `(value, key)`: useful
 * for partial masking (`****6789`) or preserving the value's type.
 */
type RedactMask = string | ((value: unknown, key: string) => unknown);
/**
 * Application-specific base error that works across full Node.js, isolate "edge"
 * runtimes (Cloudflare Workers, Deno Deploy, Vercel Edge Functions) and modern
 * browsers. It preserves the native `cause` field where available, falls back
 * gracefully where it is not, and produces the richest stack trace the host
 * can provide.
 *
 * @example
 * ```ts
 * // Using automatic name inference
 * class UserNotFoundError extends BaseError<'UserNotFoundError'> {
 * constructor(userId: string) {
 * super(`User with id ${userId} not found in database lookup`); // Technical message
 * }
 * }
 * ```
 */
declare class BaseError<T extends string> extends Error {
    #private;
    /**
     * Nominal type brand - makes each subclass structurally distinct at compile time.
     * Using 'this' ensures every subclass gets its own unique type identity.
     * @internal - This property is for type-checking only, never use it directly.
     */
    protected readonly __brand: this;
    /**
     * Discriminant tag for type narrowing. Derived from the resolved error name
     * (an explicit `name` option, otherwise the constructor name), so it never
     * diverges from {@link name}.
     *
     * Because the fallback is `constructor.name`, a build that minifies class
     * names will mangle it. For a stable discriminant either pass an explicit
     * `name`, or override `_tag` with a literal, which also narrows the
     * type:
     *
     * @example
     * ```ts
     * class MyError extends BaseError<'MyError'> {
     *   readonly _tag = 'MyError' as const; // stable + strictly typed
     * }
     * ```
     */
    readonly _tag: string;
    readonly name: T;
    /** Epoch-ms timestamp (numeric) */
    readonly timestamp: number;
    /**
     * ISO-8601 timestamp (string) for log aggregators that prefer text. Derived
     * from {@link timestamp} (one clock read), so the two can never disagree
     * across a millisecond boundary.
     */
    readonly timestampIso: string;
    /** Rich, filtered stack where the host supports it. */
    readonly stack?: string;
    /**
     * Creates a new BaseError instance with automatic name inference.
     *
     * @param message – Human-readable explanation (name will be inferred from constructor)
     * @param cause   – Optional underlying error or extra context
     * @param options – Optional runtime name settings
     */
    constructor(message: string, cause?: unknown, options?: BaseErrorOptions);
    /**
     * Redacts the given keys (deep, at any depth) from the **log** output
     * (`toLogObject`/`toJSON`). Sticky on the instance, so it also applies when a
     * logger auto-serializes the error via `JSON.stringify`.
     *
     * ⚠️ Scope: redaction rewrites the **log object**, not every string render.
     * When `keys` includes `"message"`, {@link toString} masks the technical
     * message too; everything else (`err.stack`, whose header carries the raw
     * message, and Node's `console.log(err)` inspection, which prints the stack)
     * stays unredacted. When redaction matters, log errors only through a
     * structured serializer that hits `toJSON`, never via string interpolation.
     *
     * @param keys - Property names to mask wherever they appear in the log object.
     * @param options - `mask` defaults to `"[REDACTED]"`.
     */
    redact(keys: string[], options?: {
        mask?: RedactMask;
    }): this;
    /**
     * Allow-list redaction (higher assurance than {@link redact}): within any
     * **data** region (a `details` subtree at any depth, the data-bearing
     * fields of a `cause`, and any subclass-added top-level field): masks every
     * leaf whose key is **not** listed, so a newly-added field leaks nothing by
     * default. Container objects are recursed so nested allowed leaves survive.
     * Only the library's own structural envelope is kept: the fixed top-level
     * fields ({@link BaseError.#ROOT_ENVELOPE_KEYS}: `name`/`message`/`stack`/
     * `code`/`category`/`retryable`/`timestamp`/`timestampIso`/`cause`/`details`)
     * and a cause's top-level structural envelope keys (`name`/`message`/`stack`/
     * `code`/`category`/`retryable`). Any other top-level field (e.g. one a
     * subclass adds via `buildLogObject`) is data: its leaves are masked unless
     * allow-listed. A cause's foreign fields (anything outside that fixed set,
     * and everything nested beneath them) are treated as data, so a plain object
     * that merely *looks* like a structured error cannot smuggle siblings (or
     * envelope-named keys buried in foreign subtrees) through. Sticky; last
     * redactor wins.
     *
     * ⚠️ Scope: rewrites the **log object** only. The technical `message` is part
     * of the kept structural envelope, so `toString`, `err.stack`, and Node's
     * `console.log(err)` inspection carry it unchanged; see {@link redact} for
     * masking the message itself.
     *
     * @param keys - Data leaf keys allowed to survive in the log.
     * @param options - `mask` defaults to `"[REDACTED]"`.
     */
    redactAllow(keys: string[], options?: {
        mask?: RedactMask;
    }): this;
    /**
     * Sets a custom redactor applied to the full log object. Use for allow-lists
     * or scrubbing the technical `message`. Sticky; the last redactor wins.
     *
     * ⚠️ Scope: applies to the **log object** only. A custom redactor cannot be
     * mapped onto the one-line {@link toString} render, so `toString`,
     * `err.stack`, and `console.log(err)` inspection keep the raw technical
     * message even when the redactor scrubs it from the log.
     */
    redactWith(redactor: (log: Record<string, unknown>) => Record<string, unknown>): this;
    /**
     * Assembles the raw log object (no redaction). Subclasses override this to
     * add their own fields; the public {@link toLogObject} applies redaction to
     * the complete assembled object.
     */
    protected buildLogObject(): Record<string, unknown>;
    /**
     * Serialises the error for logs. Includes technical message, stack and cause,
     * with the instance redactor applied (see {@link redact} / {@link redactWith}).
     *
     * ⚠️ This is a **log** serialization: it carries the technical message, stack,
     * cause chain and raw `details`. **Never return it to a client.** Anything that
     * auto-serializes the error (`JSON.stringify`, `res.json(err)`, `Response.json`,
     * `return err`) reaches {@link toJSON}, which is an alias of this method, and
     * leaks the same payload. For client-safe output use the `public-error`
     * subpath (`@shirudo/base-error/public-error`, `project`), which projects only
     * an allow-listed, message-free public view.
     */
    toLogObject(): Record<string, unknown>;
    /**
     * JSON serialization for logging-oriented consumers. Alias of
     * {@link toLogObject}, so it returns the same **log** shape: technical message,
     * stack, cause chain and raw `details`.
     *
     * ⚠️ Because `JSON.stringify(err)`, `res.json(err)`, `Response.json(err)` and
     * `return err` all route through `toJSON`, sending an error down any of those
     * paths leaks the full technical payload to the client. **Never serialize an
     * error straight into a response.** Produce a client payload through the
     * `public-error` subpath (`project` / `toProblem`) instead. This shape is also
     * the input that {@link StructuredError.fromJSON} reconstructs, which is why it
     * intentionally retains the stack and cause chain.
     */
    toJSON(): Record<string, unknown>;
    /**
     * Readable one-liner plus full nested cause chain. Honors a deny-listed
     * `"message"` (see {@link redact}) per BaseError in the chain; other
     * redaction shapes rewrite only the log object.
     */
    toString(): string;
}

/**
 * Configuration options for creating a StructuredError with typed metadata.
 *
 * ErrorOptions provides a standardized structure for error configuration with:
 * - Type-safe error codes and categories
 * - Retryability flags for automatic retry logic
 * - Structured details for additional context
 * - Error cause chains for nested errors
 *
 * @template TCode - Union type of error codes (e.g., "USER_NOT_FOUND" | "VALIDATION_FAILED")
 * @template TCategory - Union type of error categories (e.g., "AUTH" | "VALIDATION")
 * @template TDetails - Type of structured details object, defaults to Record<string, unknown>
 *
 * @example
 * ```ts
 * // Basic usage with type inference
 * const options: ErrorOptions<string, string> = {
 *   code: "VALIDATION_FAILED",
 *   category: "CLIENT_ERROR",
 *   retryable: false,
 *   message: "Email format is invalid",
 *   details: { field: "email", value: "not-an-email" }
 * };
 * ```
 *
 * @example
 * ```ts
 * // With typed error codes and categories
 * type ApiErrorCode = "UNAUTHORIZED" | "NOT_FOUND" | "RATE_LIMIT";
 * type ApiCategory = "AUTH" | "RESOURCE" | "RATE_LIMIT";
 *
 * interface ApiErrorDetails {
 *   statusCode: number;
 *   endpoint?: string;
 * }
 *
 * const options: ErrorOptions<ApiErrorCode, ApiCategory, ApiErrorDetails> = {
 *   code: "UNAUTHORIZED",
 *   category: "AUTH",
 *   retryable: false,
 *   message: "Authentication token is invalid",
 *   details: { statusCode: 401, endpoint: "/api/users" }
 * };
 * ```
 */
type ErrorOptions<TCode extends string, TCategory extends string, TDetails extends Record<string, unknown> = Record<string, {}>> = {
    /**
     * Unique identifier for the error type.
     * Used for programmatic error handling and switching.
     *
     * @example "USER_NOT_FOUND", "DATABASE_TIMEOUT", "VALIDATION_FAILED"
     */
    code: TCode;
    /**
     * Category grouping for related errors.
     * Used for broader error classification and handling.
     *
     * @example "AUTH", "VALIDATION", "INFRASTRUCTURE"
     */
    category: TCategory;
    /**
     * Flag indicating whether the failed operation can be retried.
     * Used by retry mechanisms to determine if automatic retry should be attempted.
     *
     * @example
     * - `true` for transient errors (network timeouts, rate limits)
     * - `false` for permanent errors (validation failures, unauthorized access)
     */
    retryable: boolean;
    /**
     * Human-readable technical error message.
     * Typically contains detailed information for developers and logs.
     *
     * @example "Failed to connect to PostgreSQL database at localhost:5432"
     */
    message: string;
    /**
     * Optional structured data providing additional error context.
     * Can include any relevant metadata specific to the error.
     *
     * @example
     * ```ts
     * {
     *   userId: "123",
     *   field: "email",
     *   constraint: "format",
     *   attemptCount: 3
     * }
     * ```
     */
    details?: TDetails;
    /**
     * Optional underlying error that caused this error.
     * Used to preserve error chains and root cause information.
     *
     * @example
     * ```ts
     * try {
     *   await database.connect();
     * } catch (err) {
     *   throw new StructuredError({
     *     code: "DB_CONNECTION_FAILED",
     *     category: "INFRASTRUCTURE",
     *     retryable: true,
     *     message: "Failed to connect to database",
     *     cause: err // Preserve the original error
     *   });
     * }
     * ```
     */
    cause?: unknown;
};

/**
 * A structured error class that extends BaseError with enhanced error metadata.
 *
 * StructuredError provides a standardized way to create errors with:
 * - Error codes for programmatic error handling
 * - Categories for grouping related errors
 * - Retryability flags for automatic retry logic
 * - Structured details for additional context
 *
 * All BaseError features are preserved, including timestamps, cause chains, and
 * log serialization.
 *
 * @example
 * ```ts
 * // Basic usage with type inference
 * const error = new StructuredError({
 *   code: "USER_NOT_FOUND",
 *   category: "NOT_FOUND",
 *   retryable: false,
 *   message: "User with id 123 not found",
 *   details: { userId: "123" }
 * });
 *
 * // Error handling
 * if (error.code === "USER_NOT_FOUND") {
 *   console.log("User does not exist");
 * }
 * ```
 *
 * @example
 * ```ts
 * // Creating a domain-specific error class
 * type DatabaseErrorCode = "CONNECTION_FAILED" | "QUERY_TIMEOUT" | "DEADLOCK";
 * type DatabaseErrorCategory = "CONNECTION" | "EXECUTION" | "CONCURRENCY";
 *
 * interface DatabaseErrorDetails {
 *   query?: string;
 *   duration?: number;
 *   connectionId?: string;
 * }
 *
 * class DatabaseError extends StructuredError<
 *   DatabaseErrorCode,
 *   DatabaseErrorCategory,
 *   DatabaseErrorDetails
 * > {
 *   constructor(
 *     code: DatabaseErrorCode,
 *     message: string,
 *     details?: DatabaseErrorDetails,
 *     cause?: unknown
 *   ) {
 *     super({
 *       code,
 *       category: code === "CONNECTION_FAILED" ? "CONNECTION" :
 *                code === "QUERY_TIMEOUT" ? "EXECUTION" : "CONCURRENCY",
 *       retryable: code !== "DEADLOCK",
 *       message,
 *       details,
 *       cause,
 *     });
 *   }
 * }
 * ```
 */
declare class StructuredError<TCode extends string, TCategory extends string, TDetails extends Record<string, unknown> = Record<string, {}>> extends BaseError<`${TCode}`> {
    #private;
    /**
     * Stable discriminant for the StructuredError family. Fixed as a literal so it
     * survives class-name minification. Narrow on {@link code} to distinguish
     * individual structured errors; subclasses that need their own tag override
     * this with their own literal.
     */
    readonly _tag: string;
    /** Error code for programmatic error handling */
    readonly code: TCode;
    /** Error category for grouping related errors */
    readonly category: TCategory;
    /** Whether this error is retryable */
    readonly retryable: boolean;
    /** Optional structured details providing additional context */
    readonly details?: TDetails;
    /**
     * Creates a new StructuredError with typed metadata.
     *
     * @param options - Configuration object containing all error metadata
     */
    constructor(options: ErrorOptions<TCode, TCategory, TDetails>);
    /**
     * Reconstruct a StructuredError from its serialized (`toJSON`/`toLogObject`)
     * shape. This is the inverse of {@link toJSON}.
     *
     * Intended for reconstruction **within a single trust/bounded-context
     * boundary**: Web Worker / `postMessage` (where `instanceof` is lost across
     * `structuredClone`), job queues / durable storage, and log replay. Across
     * services, reconstruct then translate through an Anti-Corruption Layer; do
     * not treat an upstream's `code` as your own.
     *
     * Lenient and safe: missing fields fall back to safe defaults
     * (`UNKNOWN_ERROR`/`INTERNAL`/non-retryable); malformed input yields that
     * envelope instead of throwing; only whitelisted fields are read (no
     * prototype pollution). `details` is copied shallowly (the top level is
     * decoupled from the payload; nested values stay shared). The original
     * `stack`/`timestamp` and the cause chain are restored. Reconstructed
     * fields are **not** an authority on trust: whoever produced the payload
     * can forge them.
     *
     * Always returns a base `StructuredError`: subclass identity and behavior are
     * **not** restored (a `ValidationError` round-trips to a `StructuredError`,
     * losing `publicIssues()`/`addIssue()`; its raw `details.issues` survive as
     * data). Narrow on `code`, not on `_tag`/instanceof.
     */
    static fromJSON(json: unknown): StructuredError<string, string>;
    /**
     * Extends BaseError's raw log object with code, category, retryable, and
     * details. Redaction (if configured) is applied by the inherited
     * {@link toLogObject} to the complete assembled object.
     */
    protected buildLogObject(): Record<string, unknown>;
}

/**
 * Narrows a member of an error union to a single `code`.
 *
 * When `E` is a real union of structured error types (e.g. produced by a
 * catalog), this resolves to the precise member, so `details` is the per-code
 * type. When `E` is a single `StructuredError<"A" | "B">` there is nothing to
 * narrow, so it falls back to `E` instead of `never`.
 */
type CaseArg<E extends StructuredError<string, string>, K extends string> = [
    Extract<E, {
        code: K;
    }>
] extends [never] ? E : Extract<E, {
    code: K;
}>;
/**
 * All handlers, each optional, plus an optional `_` catch-all. Return types are
 * left open so the concrete handler object can drive the result type.
 */
type Cases<E extends StructuredError<string, string>> = {
    [K in E["code"]]?: (error: CaseArg<E, K>) => unknown;
} & {
    _?: (error: E) => unknown;
};
/** The union of every handler's return type. This is the result of `matchError`. */
type Result<C> = {
    [K in keyof C]: C[K] extends (...args: never[]) => infer R ? R : never;
}[keyof C];
/**
 * Exhaustiveness constraint: if no `_` catch-all is given, every `code` must
 * have a handler. Missing codes are added as required, so an incomplete object
 * fails to type-check.
 */
type Exhaustive<E extends StructuredError<string, string>, C> = "_" extends keyof C ? C : [Exclude<E["code"], keyof C>] extends [never] ? C : C & {
    [K in Exclude<E["code"], keyof C>]: (error: CaseArg<E, K>) => unknown;
};
/**
 * Exhaustively dispatch on a structured error's `code`, with type narrowing.
 *
 * Pass a handler per `code`. If `error`'s type is a closed union of structured
 * error types and you omit a handler, it is a **compile error** (unless you
 * provide a `_` catch-all). Each handler receives the error narrowed to its
 * case, so `details` is the precise per-code type, and the return type is the
 * union of the handler return types.
 *
 * Errors caught as `unknown` must be narrowed first (e.g. with
 * `isStructuredError`) and annotated as the expected union; exhaustiveness
 * cannot be derived from `unknown`.
 *
 * @param error - The structured error to match on
 * @param cases - A handler per `code`, optionally with a `_` catch-all
 * @returns The value returned by the matching handler
 * @throws Error - When no case matches and no `_` catch-all is provided
 *   (only reachable if the static exhaustiveness check is bypassed)
 *
 * @example
 * ```ts
 * const status = matchError(err, {
 *   USER_NOT_FOUND: () => 404,
 *   EMAIL_TAKEN: () => 409,
 *   RATE_LIMITED: (e) => (e.retryable ? 429 : 503),
 * });
 * ```
 *
 * @example
 * ```ts
 * // Partial handling with a catch-all
 * matchError(err, {
 *   USER_NOT_FOUND: () => render404(),
 *   _: (e) => renderGeneric(e.code),
 * });
 * ```
 */
declare function matchError<E extends StructuredError<string, string>, const C extends Cases<E>>(error: E, cases: Exhaustive<E, C>): Result<C>;

/**
 * Type guard functions for error type narrowing.
 */

/** Portable fields shared by native and structurally recognized errors. */
type ErrorLike = {
    readonly name: string;
    readonly message: string;
    readonly stack?: string;
};
/** A reusable predicate that narrows an unknown value to `T`. */
type TypeGuard<T> = (value: unknown) => value is T;
/** Constructor for an Error subclass with any concrete argument list. */
type ErrorClass<T extends Error = Error> = abstract new (...args: never[]) => T;
type GuardTarget<G> = G extends TypeGuard<infer T> ? T : never;
type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void ? I : never;
type GuardIntersection<G extends readonly TypeGuard<unknown>[]> = UnionToIntersection<GuardTarget<G[number]>>;
/**
 * Checks for a native Error or a structurally equivalent cross-realm value.
 * Structural matches establish shape only, not trusted domain identity.
 */
declare function isError(value: unknown): value is ErrorLike;
/** Creates a guard for an error-like value with an exact string or numeric code. */
declare function hasErrorCode<const C extends string | number>(code: C): TypeGuard<ErrorLike & {
    readonly code: C;
}>;
/** Creates an instanceof guard with an optional additional runtime predicate. */
declare function isErrorOf<T extends Error>(constructor: ErrorClass<T>, predicate?: (error: T) => boolean): TypeGuard<T>;
/** Checks whether a value is an instance of any listed Error constructor. */
declare function isAnyErrorOf<const C extends readonly ErrorClass[]>(value: unknown, constructors: C): value is InstanceType<C[number]>;
/** Checks that a value satisfies every guard and narrows to their intersection. */
declare function isAllOf<const G extends readonly [TypeGuard<unknown>, ...TypeGuard<unknown>[]]>(value: unknown, guards: G): value is GuardIntersection<G>;
/**
 * Type guard to check if a value is a BaseError instance.
 *
 * @param value - The value to check
 * @returns True if the value is a BaseError instance
 *
 * @example
 * ```ts
 * try {
 *   await someOperation();
 * } catch (error) {
 *   if (isBaseError(error)) {
 *     console.log(error.timestamp);    // TypeScript knows this exists
 *     console.log(error.timestampIso);
 *   }
 * }
 * ```
 */
declare function isBaseError(value: unknown): value is BaseError<string>;
/**
 * Type guard to check if a value is a StructuredError.
 *
 * Uses a two-phase check:
 * 1. Fast path: `instanceof` check for real StructuredError instances
 * 2. Fallback: Duck-typing for cross-realm objects, serialized errors, or plain objects
 *
 * @param value - The value to check
 * @returns True if the value is a StructuredError or has the StructuredError shape
 *
 * @example
 * ```ts
 * try {
 *   await someOperation();
 * } catch (error) {
 *   if (isStructuredError(error)) {
 *     console.log(error.code);      // TypeScript knows this exists
 *     console.log(error.category);
 *     console.log(error.retryable);
 *
 *     if (error.retryable) {
 *       // Retry logic
 *     }
 *   }
 * }
 * ```
 */
declare function isStructuredError(value: unknown): value is StructuredError<string, string>;
/**
 * Type guard to check if an error is retryable.
 * Works with any error that has a `retryable` property (duck-typing).
 *
 * @param value - The value to check
 * @returns True if the value has retryable === true
 *
 * @example
 * ```ts
 * try {
 *   await someOperation();
 * } catch (error) {
 *   if (isRetryable(error)) {
 *     // Safe to retry
 *     await retry(someOperation);
 *   } else {
 *     // Don't retry, handle error
 *     throw error;
 *   }
 * }
 * ```
 */
declare function isRetryable(value: unknown): value is {
    retryable: true;
} & Record<string, unknown>;

/** Non-exhaustive matcher for arbitrary thrown values. */
interface ThrownMatcher<TResult> {
    /** Register a local Error-constructor case. */
    with<T extends Error, const R>(constructor: ErrorClass<T>, handler: (error: T) => R): ThrownMatcher<TResult | R>;
    /** Register a case for a non-empty group of local Error constructors. */
    withAny<const C extends readonly [ErrorClass, ...ErrorClass[]], const R>(constructors: C, handler: (error: InstanceType<C[number]>) => R): ThrownMatcher<TResult | R>;
    /** Register a narrowing type guard. */
    when<T, const R>(guard: TypeGuard<T>, handler: (value: T) => R): ThrownMatcher<TResult | R>;
    /** Register a boolean predicate without static narrowing. */
    when<const R>(predicate: (value: unknown) => boolean, handler: (value: unknown) => R): ThrownMatcher<TResult | R>;
    /** Evaluate the registered cases and handle an unmatched value. */
    otherwise<const R>(handler: (value: unknown) => R): TResult | R;
}
/** Start an immutable, first-match-wins matcher for an arbitrary thrown value. */
declare function matchThrown(value: unknown): ThrownMatcher<never>;

/** A keyed set of local Error constructors. */
type ErrorClassMap = Readonly<Record<string, ErrorClass>>;
type ErrorClassHandlers<TClasses extends ErrorClassMap> = {
    readonly [K in keyof TClasses]: (error: InstanceType<TClasses[K]>) => unknown;
};
type MatchResult<THandlers> = THandlers[keyof THandlers] extends (...args: never[]) => infer R ? R : never;
type ValidClassDefinition<TClasses extends ErrorClassMap> = [
    keyof TClasses
] extends [never] ? never : string extends keyof TClasses ? never : Exclude<keyof TClasses, string> extends never ? Extract<keyof TClasses, `${number}`> extends never ? TClasses : never : never;
/** A reusable, exhaustive matcher for a closed set of Error classes. */
interface ErrorClassSet<TClasses extends ErrorClassMap> {
    /** Match a value using exactly one handler for every declared class key. */
    match<const THandlers extends ErrorClassHandlers<TClasses>>(value: unknown, handlers: THandlers & Record<Exclude<keyof THandlers, keyof TClasses>, never>): MatchResult<THandlers>;
}
/** Define a reusable, exhaustive set of local Error classes. */
declare function defineErrorClassSet<const TClasses extends ErrorClassMap>(classes: ValidClassDefinition<TClasses>): ErrorClassSet<TClasses>;

/** JSON-safe static metadata supported by catalog definitions. */
type CatalogJsonValue = null | boolean | number | string | readonly CatalogJsonValue[] | {
    readonly [key: string]: CatalogJsonValue;
};
/** Static boundary metadata attached to one catalog definition. */
type CatalogMetadata = Readonly<Record<string, CatalogJsonValue>>;
declare const DETAILS_TYPE: unique symbol;
/** Compile-time-only marker for one error code's details shape. */
type DetailsType<T extends Record<string, unknown>> = {
    readonly [DETAILS_TYPE]: T;
};
/** Declare an error code's details type without a consumer-side cast. */
declare function detailsType<T extends Record<string, unknown>>(): DetailsType<T>;
/** Declarative log-redaction policy applied by every generated factory. */
type CatalogRedactionPolicy = {
    readonly mode: "deny";
    readonly keys: readonly string[];
    readonly mask?: RedactMask;
} | {
    readonly mode: "allow";
    readonly keys: readonly string[];
    readonly mask?: RedactMask;
};
/**
 * Declarative spec for a single error code in a catalog.
 *
 * `details` is a compile-time marker created by {@link detailsType}.
 */
type ErrorSpec = {
    /** Internal category for this code. */
    category: string;
    /** Whether the failed operation can be retried. */
    retryable: boolean;
    /** JSON-safe static metadata for transport and boundary adapters. */
    metadata?: CatalogMetadata;
    /** Type marker for this code's structured details. */
    details?: DetailsType<Record<string, unknown>>;
    /** Sticky log-redaction policy applied to generated instances. */
    redaction?: CatalogRedactionPolicy;
};
/** A reusable finite catalog definition. Prefer `satisfies` over annotation. */
type ErrorCatalogDefinition = Readonly<Record<string, ErrorSpec>>;
type InvalidCatalogSpec<T extends ErrorCatalogDefinition> = {
    [K in keyof T]: Exclude<keyof T[K], keyof ErrorSpec> extends never ? T[K] extends {
        redaction: infer R;
    } ? Exclude<keyof R, keyof CatalogRedactionPolicy> extends never ? never : K : never : K;
}[keyof T];
type ValidCatalogDefinition<T extends ErrorCatalogDefinition> = [
    keyof T
] extends [never] ? never : string extends keyof T ? never : Exclude<keyof T, string> extends never ? InvalidCatalogSpec<T> extends never ? unknown : never : never;
type CatalogValidationArgs<T extends ErrorCatalogDefinition> = [
    ValidCatalogDefinition<T>
] extends [never] ? [invalidCatalog: never] : "" extends keyof T ? [invalidCatalog: never] : [];
type CategoryOf<S> = S extends {
    category: infer C extends string;
} ? C : string;
type RetryableOf<S> = S extends {
    retryable: infer R extends boolean;
} ? R : boolean;
/** Immutable static metadata returned by `Catalog.meta()`. */
type CatalogMeta<S extends ErrorSpec> = {
    readonly category: CategoryOf<S>;
    readonly retryable: RetryableOf<S>;
} & (S extends {
    metadata: infer M extends CatalogMetadata;
} ? {
    readonly metadata: M;
} : Record<never, never>);
/** Options accepted by a generated factory (shared, non-details part). */
type FactoryBaseOptions = {
    /** Underlying cause to preserve in the chain. */
    cause?: unknown;
};
/**
 * The factory signature for one code. `details` is required when the spec
 * declares a details shape, and the whole options argument is optional when it
 * does not.
 */
type FactoryFor<K extends string, S> = S extends {
    details: DetailsType<infer D extends Record<string, unknown>>;
} ? (message: string, options: FactoryBaseOptions & {
    details: D;
}) => StructuredError<K, CategoryOf<S>, D> : (message: string, options?: FactoryBaseOptions) => StructuredError<K, CategoryOf<S>, Record<string, never>>;
/** Typed factory namespace produced by {@link defineErrors}. */
type CatalogFactories<T extends Record<string, ErrorSpec>> = {
    [K in keyof T]: FactoryFor<K & string, T[K]>;
};
/** The object returned by {@link defineErrors}. */
type Catalog<T extends ErrorCatalogDefinition> = {
    /** Factory namespace with one precisely typed constructor per error code. */
    readonly create: CatalogFactories<T>;
    /** Finite runtime list of the catalog's error codes. */
    readonly codes: readonly (keyof T & string)[];
    /** Returns immutable core fields and static boundary metadata for a code. */
    meta<K extends keyof T>(code: K): CatalogMeta<T[K]>;
    /** Recognize any error created by this exact catalog. */
    is(value: unknown): value is CatalogError<Catalog<T>>;
    /** Recognize one code created by this exact catalog. */
    is<K extends keyof T & string>(value: unknown, code: K): value is CatalogErrorOf<Catalog<T>, K>;
};
/**
 * The union of every error type a catalog can produce. Pass this closed set to
 * {@link matchError}. `meta` is excluded automatically.
 *
 * @example
 * ```ts
 * const AppErrors = defineErrors({ ... });
 * type AppError = CatalogError<typeof AppErrors>;
 * ```
 */
type CatalogError<C extends {
    create: Record<string, unknown>;
}> = {
    [K in keyof C["create"]]: C["create"][K] extends (...args: never[]) => infer R ? R extends StructuredError<string, string> ? R : never : never;
}[keyof C["create"]];
/** Extract one generated error type from a catalog by its code. */
type CatalogErrorOf<C extends {
    create: Record<string, unknown>;
}, K extends keyof C["create"]> = C["create"][K] extends (...args: never[]) => infer R ? R extends StructuredError<string, string> ? R : never : never;
/**
 * Define a catalog of structured errors from a declarative spec.
 *
 * Returns an immutable catalog with namespaced factories, static metadata,
 * local provenance guards, and optional catalog-level redaction. Errors are
 * tagged instances of `StructuredError` discriminated by `code`.
 *
 * @example
 * ```ts
 * const AppErrors = defineErrors({
 *   USER_NOT_FOUND: {
 *     category: "NOT_FOUND",
 *     retryable: false,
 *     metadata: { httpStatus: 404 },
 *     details: detailsType<{ userId: string }>(),
 *   },
 *   RATE_LIMITED: {
 *     category: "RATE_LIMIT",
 *     retryable: true,
 *     metadata: { httpStatus: 429 },
 *   },
 * });
 *
 * throw AppErrors.create.USER_NOT_FOUND("user 123 missing", {
 *   details: { userId: "123" },
 * });
 *
 * const status = AppErrors.meta(err.code).metadata.httpStatus;
 * ```
 */
declare function defineErrors<const T extends ErrorCatalogDefinition>(catalog: T, ..._validation: CatalogValidationArgs<T>): Catalog<T>;

/** Fallback configuration for {@link toStructuredError}. */
type CoerceOptions = {
    /** Internal code for the fallback. Default: `"UNKNOWN_ERROR"`. */
    code?: string;
    /** Internal category for the fallback. Default: `"INTERNAL"`. */
    category?: string;
    /** Retryable flag for the fallback. Default: `false`. */
    retryable?: boolean;
    /** Override the technical message (otherwise derived from the value). */
    message?: string;
};
declare function toStructuredError(value: unknown, options?: CoerceOptions): StructuredError<string, string>;

/**
 * A single validation issue. Structurally identical to Standard Schema's
 * `Issue` (standardschema.dev), so Zod / Valibot / ArkType / TanStack Form
 * output pipes in unchanged, with no dependency. Extra fields a validator
 * attaches are kept for logs but never cross to a client.
 */
type ValidationIssue = {
    /** Human-readable message. Keep it client-safe if you choose to expose it. */
    readonly message: string;
    /** Path to the offending value (Standard Schema form). */
    readonly path?: ReadonlyArray<PropertyKey | {
        readonly key: PropertyKey;
    }>;
};
/** The fixed, client-safe shape an issue takes on the wire. */
type PublicIssue = {
    message: string;
    path?: ReadonlyArray<PropertyKey | {
        readonly key: PropertyKey;
    }>;
    /** Included only when the source issue carried one. */
    code?: string;
    /** Derived string path (e.g. "address.zip") for HTTP clients. */
    pointer?: string;
};
/** Options for {@link ValidationError}. */
type ValidationErrorOptions<TCode extends string, TCategory extends string> = {
    issues?: ValidationIssue[];
    cause?: unknown;
    /** Override the code (default `"VALIDATION_FAILED"`). */
    code?: TCode;
    /** Override the category (default `"VALIDATION"`). */
    category?: TCategory;
};
/** Options for {@link ValidationError.publicIssues}. */
type PublicIssuesOptions = {
    /**
     * Fully customize the wire shape (e.g. RFC-7807 `{ name, reason }`).
     * Replaces the default whitelist entirely: a custom mapper receives the raw
     * issue (validator extras included) and must apply its own whitelist,
     * including copying `path` and narrowing object segments to `{ key }` if it
     * forwards them.
     */
    mapIssue?: (issue: ValidationIssue) => PublicIssue;
};
/**
 * Aggregate error for validation: collects N field-level issues into one
 * `StructuredError`. Issues are stored in full for logs, but only ever cross to
 * a client through the safe `publicIssues()` whitelist, on explicit opt-in.
 *
 * @example
 * ```ts
 * const v = new ValidationError("Registration is invalid");
 * if (!isEmail(email)) v.addIssue({ message: "Enter a valid email.", path: ["email"] });
 * if (v.hasIssues()) throw v;
 *
 * // or ingest a Standard Schema validator's output directly:
 * const result = schema["~standard"].validate(input);
 * if (result.issues) throw new ValidationError("Invalid input", { issues: result.issues });
 * ```
 */
declare class ValidationError<TCode extends string = "VALIDATION_FAILED", TCategory extends string = "VALIDATION"> extends StructuredError<TCode, TCategory, {
    issues: ValidationIssue[];
}> {
    #private;
    readonly _tag: string;
    constructor(message: string, options?: ValidationErrorOptions<TCode, TCategory>);
    addIssue(issue: ValidationIssue): this;
    addIssues(issues: ValidationIssue[]): this;
    hasIssues(): boolean;
    get issues(): readonly ValidationIssue[];
    /**
     * Client-safe projection of the issues. Returns only the fixed whitelist
     * (`message`, `path`, `code?`, `pointer?`); raw validator extras are never included.
     * Provide `mapIssue` to emit a fully custom wire shape (e.g. RFC-7807
     * `{ name, reason }`).
     */
    publicIssues(options?: PublicIssuesOptions): PublicIssue[];
}

/**
 * Asserts that a condition is truthy, throwing the provided error if it's falsy.
 * This function provides TypeScript type narrowing through assertion signatures.
 *
 * @template T - The error name type extending string
 * @param condition - The value to check for truthiness
 * @param error - The BaseError instance to throw if condition is falsy
 * @throws {BaseError<T>} The provided error when condition is falsy
 *
 * @example
 * ```ts
 * const user = getUser();
 * guard(user, new UserNotFoundError("User not found"));
 * // TypeScript now knows user is not null/undefined
 * console.log(user.name);
 * ```
 *
 * @example
 * ```ts
 * guard(isValidEmail(email), new ValidationError("Invalid email format"));
 * // Continues execution only if email is valid
 * ```
 *
 * @example
 * ```ts
 * // Pass a factory to avoid constructing the error on the happy path.
 * guard(user, () => new UserNotFoundError(id));
 * ```
 */
declare function guard<T extends string>(condition: unknown, error: BaseError<T> | (() => BaseError<T>)): asserts condition;

/**
 * Builds a {@link RedactMask} that reveals a prefix and/or suffix of a string
 * value and masks the middle (e.g. to show *which* API key it was without
 * exposing it, as in `sk_live…AbCd`).
 *
 * Safe by construction:
 * - a value too short to safely reveal (`length <= keepStart + keepEnd`) is
 *   masked **entirely**, never partially exposed;
 * - non-string values are masked entirely.
 *
 * @param options - `keepStart` (default 0), `keepEnd` (default 4), `fill`
 *   (default `"…"`, also used as the full mask for short/non-string values).
 *
 * @example
 * ```ts
 * err.redact(["apiKey"], { mask: partialMask({ keepStart: 7, keepEnd: 4 }) });
 * // "sk_live_51HxYz...AbCd" -> "sk_live…AbCd"
 * ```
 */
declare function partialMask(options?: {
    keepStart?: number;
    keepEnd?: number;
    fill?: string;
}): RedactMask;

/**
 * Traverses the cause chain to find the root cause (the last error in the chain).
 *
 * @param error - The error to traverse
 * @param maxDepth - Maximum number of cause hops to follow (default: 100)
 * @returns The root cause, or the last valid error if maxDepth is exceeded.
 *   On a circular chain, the deepest error before the repeat (never throws).
 *
 * @example
 * ```typescript
 * const root = getRootCause(nestedError);
 * if (isRetryableStructuredError(root)) {
 *   // Handle retryable root cause
 * }
 * ```
 */
declare function getRootCause(error: unknown, maxDepth?: number): unknown;
/**
 * Finds the first error in the cause chain that matches the predicate.
 *
 * @param error - The error to start traversing from
 * @param predicate - Function that returns true for matching errors
 * @param maxDepth - Maximum number of cause hops to follow (default: 100)
 * @returns The first matching error, or undefined if no match found
 *
 * @example
 * ```typescript
 * const dbError = findInCauseChain(
 *   error,
 *   (e): e is StructuredError => e.code?.startsWith("DB_")
 * );
 * ```
 */
declare function findInCauseChain<T>(error: unknown, predicate: (e: unknown) => e is T, maxDepth?: number): T | undefined;
declare function findInCauseChain(error: unknown, predicate: (e: unknown) => boolean, maxDepth?: number): unknown;
/**
 * Collects all errors in the cause chain that match the predicate.
 *
 * @param error - The error to start traversing from
 * @param predicate - Function that returns true for errors to collect
 * @param maxDepth - Maximum number of cause hops to follow (default: 100)
 * @returns Array of matching errors, ordered from outermost to innermost
 *
 * @example
 * ```typescript
 * const allRetryable = filterCauseChain(
 *   error,
 *   (e): e is StructuredError & { retryable: true } =>
 *     isRetryableStructuredError(e)
 * );
 * ```
 */
declare function filterCauseChain<T>(error: unknown, predicate: (e: unknown) => e is T, maxDepth?: number): T[];
declare function filterCauseChain(error: unknown, predicate: (e: unknown) => boolean, maxDepth?: number): unknown[];
/**
 * Checks if any error in the cause chain matches the predicate.
 *
 * @param error - The error to start traversing from
 * @param predicate - Function that returns true for matching errors
 * @param maxDepth - Maximum number of cause hops to follow (default: 100)
 * @returns True if at least one error matches the predicate. A circular
 *   chain is evaluated over each distinct node (never throws).
 *
 * @example
 * ```typescript
 * const hasRetryable = someCauseChain(
 *   error,
 *   (e) => isRetryableStructuredError(e)
 * );
 * ```
 */
declare function someCauseChain(error: unknown, predicate: (e: unknown) => boolean, maxDepth?: number): boolean;
/**
 * Checks if all errors in the cause chain match the predicate.
 *
 * @param error - The error to start traversing from
 * @param predicate - Function that returns true for matching errors
 * @param maxDepth - Maximum number of cause hops to follow (default: 100)
 * @returns True if all errors match the predicate, or if the chain is empty.
 *   A circular chain is evaluated over each distinct node (never throws).
 *
 * @example
 * ```typescript
 * const allAreRetryable = everyCauseChain(
 *   error,
 *   (e) => isRetryableStructuredError(e)
 * );
 * ```
 */
declare function everyCauseChain(error: unknown, predicate: (e: unknown) => boolean, maxDepth?: number): boolean;

type RetryableError = {
    retryable: true;
} & Record<string, unknown>;
/**
 * Checks if any error in the cause chain is a retryable StructuredError.
 *
 * Uses the strict {@link isRetryableStructuredError} predicate: each error
 * must have the full StructuredError shape (`code`, `category`, `retryable`)
 * in addition to `retryable === true`. Errors that extend `BaseError`
 * directly and only set `retryable: true` will NOT match. For those, use
 * {@link someChainRetryable} instead.
 *
 * @param error - The error to check
 * @returns True if any error in the chain is a retryable StructuredError
 *
 * @example
 * ```typescript
 * if (isChainRetryable(error)) {
 *   // Retry the operation
 * }
 * ```
 */
declare function isChainRetryable(error: unknown): boolean;
/**
 * Checks if any error in the cause chain is retryable, using the loose
 * `retryable === true` predicate.
 *
 * Unlike {@link isChainRetryable}, this does NOT require the full
 * StructuredError shape (`code`/`category`/`retryable`). Use this when your
 * error hierarchy extends `BaseError` directly and signals retryability via
 * a plain `retryable: true` field, common in DDD-style error hierarchies
 * that discriminate by class rather than `code`/`category` strings.
 *
 * @param error - The error to check
 * @param maxDepth - Maximum chain depth to traverse (default: 100)
 * @returns True if any error in the chain has `retryable === true`
 *
 * @example
 * ```typescript
 * class ConcurrencyConflictError extends BaseError<"ConcurrencyConflictError"> {
 *   readonly retryable = true as const;
 * }
 *
 * if (someChainRetryable(error)) {
 *   // Retry (works even though ConcurrencyConflictError has no code/category)
 * }
 * ```
 */
declare function someChainRetryable(error: unknown, maxDepth?: number): boolean;
/**
 * Checks if the root cause of an error is retryable.
 * This provides the most specific retry decision by examining only the deepest error.
 *
 * @param error - The error to check
 * @returns True if the root cause is a retryable StructuredError
 *
 * @example
 * ```typescript
 * // Only retry for root cause issues (e.g., network timeout)
 * if (getRootCauseRetryable(error)) {
 *   await retryOperation();
 * }
 * ```
 */
declare function getRootCauseRetryable(error: unknown): boolean;
/**
 * Finds the first retryable error in the cause chain.
 *
 * @param error - The error to start traversing from
 * @returns The first retryable StructuredError, or undefined if none found
 *
 * @example
 * ```typescript
 * const retryable = getFirstRetryableCause(error);
 * if (retryable) {
 *   console.log(`Retryable error: ${retryable.code}`);
 * }
 * ```
 */
declare function getFirstRetryableCause(error: unknown): RetryableError | undefined;

/**
 * Checks if a value has a non-empty `cause` (duck-typing).
 *
 * An explicit `cause: undefined` (as produced by `new Error(msg, { cause:
 * undefined })`) counts as no cause, so chain traversal stops there instead of
 * stepping onto a spurious `undefined`.
 *
 * @param value - The value to check
 * @returns True if the value has a `cause` property whose value is not `undefined`
 */
declare function isErrorWithCause(value: unknown): value is {
    cause: unknown;
};
/**
 * Checks if a value is a retryable StructuredError.
 *
 * @param value - The value to check
 * @returns True if the value is a StructuredError with retryable === true
 */
declare function isRetryableStructuredError(value: unknown): value is {
    retryable: true;
} & Record<string, unknown>;

export { BaseError, type BaseErrorOptions, type Catalog, type CatalogError, type CatalogErrorOf, type CatalogJsonValue, type CatalogMeta, type CatalogMetadata, type CatalogRedactionPolicy, type CoerceOptions, type DetailsType, type ErrorCatalogDefinition, type ErrorClass, type ErrorClassMap, type ErrorClassSet, type ErrorLike, type ErrorOptions, type ErrorSpec, type PublicIssue, type PublicIssuesOptions, type RedactMask, StructuredError, type ThrownMatcher, type TypeGuard, ValidationError, type ValidationErrorOptions, type ValidationIssue, defineErrorClassSet, defineErrors, detailsType, everyCauseChain, filterCauseChain, findInCauseChain, getFirstRetryableCause, getRootCause, getRootCauseRetryable, guard, hasErrorCode, isAllOf, isAnyErrorOf, isBaseError, isChainRetryable, isError, isErrorOf, isErrorWithCause, isRetryable, isRetryableStructuredError, isStructuredError, matchError, matchThrown, partialMask, someCauseChain, someChainRetryable, toStructuredError };
