{"version":3,"file":"exceptions-DRYLe-J4.mjs","names":[],"sources":["../src/lib/classes/base_exception.ts","../src/lib/utils/validation.ts","../src/lib/utils/exceptions.ts"],"sourcesContent":["/**\n * Base class for all structured exceptions in the ADK.\n *\n * @remarks\n * Subclasses should declare static `code`, `status`, `fatal`, and optionally `help` to avoid\n * repeating those values on every instance. Instance-level options always take precedence over\n * static defaults, so a single exception class can still be thrown with per-site overrides when\n * needed.\n *\n * The runtime cross-realm guard is inlined here rather than imported from `../utils/guards`\n * to break a circular-import chain: `guards` depends on `validation`, which extends\n * `BaseException`. Importing the shared `isInstanceOf` helper into this file would create a\n * load-order cycle that leaves `BaseException` undefined when `ValidationException extends\n * BaseException` evaluates.\n */\nexport class BaseException extends Error {\n  /**\n   * Returns `true` if `value` is a {@link BaseException} instance.\n   *\n   * @remarks\n   * Performs cross-realm-safe detection: tries `instanceof`, then `Symbol.hasInstance`, then\n   * constructor-name comparison. The ADK does not export the `BaseException` class itself\n   * as a constructable value — use this guard plus the {@link BaseException} type for runtime\n   * detection and TypeScript narrowing.\n   *\n   * @param value - The value to test.\n   * @returns `true` when `value` is a {@link BaseException} instance.\n   */\n  public static isBaseException(value: unknown): value is BaseException {\n    // eslint-disable-next-line adk/use-is-instance-of -- module cycle (guards ↔ validation ↔ BaseException); the cross-realm fallback is inlined below\n    if (value instanceof BaseException) return true\n    if (\n      typeof BaseException[Symbol.hasInstance] === 'function' &&\n      BaseException[Symbol.hasInstance](value)\n    )\n      return true\n    // eslint-disable-next-line adk/prefer-is-object -- module cycle (guards ↔ validation ↔ BaseException); isObject would create a load-order cycle\n    if (typeof value === 'object' && value !== null) {\n      const ctorName = (value as { constructor?: { name?: string } }).constructor?.name\n      if (ctorName === 'BaseException') return true\n    }\n    return false\n  }\n  /**\n   * Default help text inherited by all instances unless overridden at the throw site.\n   */\n  declare static help?: string\n  /**\n   * Default machine-readable error code inherited by all instances.\n   */\n  declare static code?: string\n  /**\n   * Default HTTP status code inherited by all instances.\n   */\n  declare static status?: number\n  /**\n   * Whether exceptions of this class are fatal by default.\n   */\n  declare static fatal?: boolean\n  /**\n   * Default message used when no message is supplied to the constructor.\n   */\n  declare static message?: string\n\n  /**\n   * Name of the class that raised the exception.\n   */\n  name: string\n\n  /**\n   * Human-readable guidance for resolving or reporting this error.\n   */\n  declare help?: string\n\n  /**\n   * Machine-readable error code for narrowing exception-handling logic.\n   */\n  declare code?: string\n\n  /**\n   * HTTP status code associated with this error.\n   */\n  declare status?: number\n\n  /**\n   * When `true`, the ADK treats this error as unrecoverable and should halt the agent loop.\n   */\n  declare fatal?: boolean\n\n  /**\n   * @param message - Human-readable error message. Falls back to the static `message` on the\n   *   subclass if omitted.\n   * @param options - Standard `ErrorOptions` extended with `code`, `status`, and `fatal`\n   *   overrides. Static defaults on the subclass are used when these are absent.\n   */\n  constructor(\n    message?: string,\n    options?: ErrorOptions & { code?: string; status?: number; fatal?: boolean }\n  ) {\n    super(message, options)\n\n    const ErrorConstructor = this.constructor as typeof BaseException\n\n    this.name = ErrorConstructor.name\n    this.message = message || ErrorConstructor.message || ''\n\n    const code = options?.code || ErrorConstructor.code\n    if (code !== undefined) {\n      this.code = code\n    }\n\n    const status = options?.status || ErrorConstructor.status\n    if (status !== undefined) {\n      this.status = status\n    }\n\n    const fatal = options?.fatal ?? ErrorConstructor.fatal\n    if (fatal !== undefined) {\n      this.fatal = fatal\n    }\n\n    const help = ErrorConstructor.help\n    if (help !== undefined) {\n      this.help = help\n    }\n\n    Error.captureStackTrace(this, ErrorConstructor)\n  }\n\n  /** Tag used by `Object.prototype.toString` — reports the concrete exception class name. */\n  get [Symbol.toStringTag]() {\n    return this.constructor.name\n  }\n\n  toString() {\n    if (this.code) {\n      return `${this.name} [${this.code}]: ${this.message}`\n    }\n    return `${this.name}: ${this.message}`\n  }\n}\n","import { BaseException } from '../classes/base_exception'\nimport { validator, ValidationError } from '@nhtio/validation'\nimport type { Schema } from '@nhtio/validation'\n\n/**\n * Returns `true` if `value` satisfies `schema` without throwing.\n *\n * @remarks\n * Aborts on the first validation error. Use {@link validateOrThrow} or\n * {@link asyncValidateOrThrow} when you need the full set of field errors.\n *\n * @param schema - The schema to validate against.\n * @param value - The value to test.\n * @returns `true` when `value` passes the schema; `false` otherwise.\n */\nexport const passesSchema = (schema: Schema, value: unknown): boolean => {\n  const { error } = schema.validate(value, { abortEarly: true })\n  return !error\n}\n\n/**\n * Returns `true` if `value` is a `ValidationError` or satisfies its minimum duck-type shape.\n *\n * @remarks\n * The duck-typing path handles `ValidationError` objects that cross module or realm boundaries\n * where `instanceof` would return `false`.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the `ValidationError` shape.\n */\nexport const isValidationError = (value: unknown): value is ValidationError => {\n  const schema = validator.alternatives(\n    validator.object().instance(ValidationError as any),\n    validator.function().instance(ValidationError as any),\n    validator\n      .object({\n        message: validator.string().required(),\n        details: validator\n          .array()\n          .items(\n            validator.object({\n              message: validator.string().required(),\n              path: validator\n                .array()\n                .items(validator.alternatives(validator.string(), validator.number()))\n                .required(),\n              type: validator.string().required(),\n              context: validator.object().unknown(true).required(),\n            })\n          )\n          .required(),\n      })\n      .unknown(true)\n  )\n  return passesSchema(schema, value)\n}\n\nconst messageFromValidationError = (reason: ValidationError | undefined, fallback: string) => {\n  return reason ? reason.details.map((d) => d.message).join(' and ') : fallback\n}\n\n/**\n * Thrown when input fails schema validation.\n *\n * @remarks\n * Carries the full `details` array from the underlying `ValidationError` so callers can surface\n * field-level messages without unwrapping the `cause` manually.\n */\nexport class ValidationException extends BaseException {\n  static status = 422\n  static code = 'VALIDATION_EXCEPTION'\n  static fatal = false\n\n  /** The raw field-level error details from the underlying `ValidationError`. */\n  declare readonly details?: ValidationError['details']\n\n  /**\n   * @param reason - The `ValidationError` thrown by the schema; its `details` are surfaced\n   *   directly on this exception and its messages are joined to form the human-readable message.\n   */\n  constructor(reason: ValidationError) {\n    const message = messageFromValidationError(reason, 'Validation failed')\n    super(message, {\n      code: ValidationException.code,\n      status: ValidationException.status,\n      fatal: ValidationException.fatal,\n      cause: reason,\n    })\n    Object.defineProperty(this, 'details', {\n      value: reason.details,\n      enumerable: true,\n      configurable: false,\n      writable: false,\n    })\n  }\n}\n\n/**\n * Validates `value` against `schema` synchronously and returns the coerced result typed as `T`.\n *\n * @remarks\n * Collects all field errors before throwing. Use {@link asyncValidateOrThrow} for schemas that\n * include async custom validators.\n *\n * @typeParam T - The expected type of `value` after successful validation.\n * @param schema - The schema to validate against.\n * @param value - The value to validate.\n * @param convert - When `true`, the validator coerces values to their target types (e.g. string\n *   `\"1\"` → number `1`). Defaults to `false` to prevent silent type coercion.\n * @returns The validated (and optionally coerced) value typed as `T`.\n * @throws {@link ValidationException} when `value` does not satisfy `schema`.\n */\nexport const validateOrThrow = <T>(schema: Schema, value: unknown, convert: boolean = false): T => {\n  const { value: returnable, error } = schema.validate(value, { abortEarly: false, convert })\n  if (error) {\n    throw new ValidationException(error)\n  }\n  return returnable as T\n}\n\n/**\n * Validates `value` against `schema` asynchronously and returns the coerced result typed as `T`.\n *\n * @remarks\n * Collects all field errors before throwing. Prefer this over {@link validateOrThrow} when the\n * schema includes async custom validators.\n *\n * @typeParam T - The expected type of the validated and coerced return value.\n * @param schema - The schema to validate against.\n * @param value - The value to validate.\n * @param convert - When `true`, the validator coerces values to their target types (e.g. string\n *   `\"1\"` → number `1`). Defaults to `false` to prevent silent type coercion.\n * @returns The validated (and optionally coerced) value typed as `T`.\n * @throws {@link ValidationException} when `value` does not satisfy `schema`.\n */\nexport const asyncValidateOrThrow = async <T>(\n  schema: Schema,\n  value: unknown,\n  convert: boolean = false\n): Promise<T> => {\n  try {\n    return await schema.validateAsync(value, { abortEarly: false, convert })\n  } catch (error) {\n    if (isValidationError(error)) {\n      throw new ValidationException(error)\n    }\n    throw error\n  }\n}\n","import { passesSchema } from './validation'\nimport { validator } from '@nhtio/validation'\nimport { printf as format } from 'fast-printf'\nimport { BaseException } from '../classes/base_exception'\n\n/**\n * Options accepted by {@link @nhtio/adk!BaseException} (and factory-created exceptions) beyond the\n * standard `ErrorOptions`.\n *\n * @remarks\n * These mirror the static defaults on {@link @nhtio/adk!BaseException} but allow per-throw overrides so a\n * single exception class can carry different metadata at different throw sites.\n */\nexport type ExceptionOptions = ErrorOptions & {\n  code?: string\n  status?: number\n  fatal?: boolean\n}\n\n/**\n * Constructor signature of an exception class produced by {@link createException}.\n *\n * @typeParam T - Tuple of printf-style format argument types. When `T` is an empty tuple the\n *   constructor takes no positional message arguments; when non-empty the first argument must be\n *   an array of values matching `T`.\n */\nexport type CreatedException<T extends any[] = []> = typeof BaseException &\n  (T extends []\n    ? {\n        new (options?: ExceptionOptions): BaseException\n      }\n    : { new (args: T, options?: ExceptionOptions): BaseException })\n\n/**\n * Factory that produces a named {@link @nhtio/adk!BaseException} subclass with a fixed printf-style message\n * template, error code, HTTP status, and fatality flag.\n *\n * @remarks\n * Prefer this over hand-writing subclasses for simple, static exception definitions.\n *\n * @typeParam T - Tuple of printf format argument types. Pass a non-empty tuple to require\n *   callers to supply interpolation values at the throw site.\n *\n * @param name - The `name` property set on thrown instances (used by `isNamedException`).\n * @param message - Printf-style template string for the error message.\n * @param code - Machine-readable error code stored on the static and instance `code` property.\n * @param status - HTTP status code associated with this exception class.\n * @param fatal - When `true`, signals that the error is unrecoverable.\n * @returns A constructor for a {@link @nhtio/adk!BaseException} subclass with the given metadata baked in.\n *\n * @example\n * ```ts\n * export const E_NOT_FOUND = createException<[string]>(\n *   'E_NOT_FOUND', 'Resource %s not found', 'E_NOT_FOUND', 404, false\n * )\n * throw new E_NOT_FOUND(['my-id'])\n * ```\n */\nexport const createException = <T extends any[] = []>(\n  name: string,\n  message: string,\n  code: string,\n  status?: number,\n  fatal?: boolean\n): CreatedException<T> => {\n  const Ctor = class extends BaseException {\n    static message = message\n    static code = code\n    static status = status\n    static fatal = fatal\n    constructor(args?: T | ExceptionOptions, options?: ExceptionOptions) {\n      const hasMessageArgs = Array.isArray(args)\n      const messageArgs = hasMessageArgs ? args : []\n      const errorOptions = hasMessageArgs ? options : args\n\n      super(format(message, ...messageArgs), errorOptions)\n      this.name = name\n    }\n  }\n  // Without this, the factory returns an anonymous class — constructor.name is \"\" and\n  // cross-realm `isInstanceOf(err, 'E_FOO')` (which falls back to constructor-name comparison)\n  // never matches. Setting the name on the class itself makes the identity carry through.\n  Object.defineProperty(Ctor, 'name', { value: name, configurable: true })\n  return Ctor as unknown as CreatedException<T>\n}\n\n/**\n * Returns `true` if `value` is a {@link @nhtio/adk!BaseException} or satisfies its minimum duck-type shape.\n *\n * @remarks\n * The duck-typing path handles exceptions that cross module or realm boundaries where\n * `instanceof` would return `false` for structurally identical objects.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link @nhtio/adk!BaseException} shape.\n */\nexport const isException = (value: unknown): value is BaseException => {\n  const schema = validator.alternatives(\n    validator.object().instance(BaseException as any),\n    validator.function().instance(BaseException as any),\n    validator\n      .object({\n        name: validator.string().required(),\n        message: validator.string().required(),\n        help: validator.string().optional(),\n        code: validator.string().optional(),\n        status: validator.number().optional(),\n        fatal: validator.boolean().optional(),\n      })\n      .unknown(true)\n  )\n  return passesSchema(schema, value)\n}\n\n/**\n * Narrows `value` to a {@link @nhtio/adk!BaseException} whose `name` property matches `name` exactly.\n *\n * @remarks\n * Useful for catching a specific factory-created exception by its string identifier when\n * `instanceof` checks are not available (e.g. across module boundaries).\n *\n * @param value - The value to test.\n * @param name - The exact string to compare against `value.name`.\n * @returns `true` when `value` is a {@link @nhtio/adk!BaseException} with the given `name`.\n */\nexport const isNamedException = (value: unknown, name: string): value is BaseException => {\n  return isException(value) && value.name === name\n}\n"],"mappings":"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"}