/** * @fileoverview Error types for AFD commands * * Errors should be actionable - they tell the user what went wrong * AND what they can do about it. */ /** * Standard error structure for command failures. * * All errors should be actionable - users should know what to do next. * * @example * ```typescript * const error: CommandError = { * code: 'RATE_LIMITED', * message: 'API rate limit exceeded', * suggestion: 'Wait 60 seconds and try again, or upgrade to a higher tier', * retryable: true, * details: { retryAfterSeconds: 60 } * }; * ``` */ export interface CommandError { /** * Machine-readable error code. * * Use SCREAMING_SNAKE_CASE for consistency. * Should be unique within your application. * * @example 'DOCUMENT_NOT_FOUND', 'VALIDATION_ERROR', 'RATE_LIMITED' */ code: string; /** * Human-readable error message. * * Should be clear and concise, describing what went wrong. */ message: string; /** * What the user can do about this error. * * This is the most important field for UX - it turns an error * from a dead-end into a recoverable situation. * * @example "Check the document ID and try again" * @example "Wait 60 seconds and retry" * @example "Contact support if this persists" */ suggestion?: string; /** * Whether retrying the same request might succeed. * * - `true`: Transient error, retry may work (rate limits, timeouts) * - `false`: Permanent error, retry won't help (not found, validation) * - `undefined`: Unknown, treat as non-retryable */ retryable?: boolean; /** * Additional technical details for debugging. * * Request IDs, timestamps, resource identifiers, etc. Details are sent to * the caller, so avoid sensitive information: stack traces belong here only * in development (`devMode`). */ details?: Record; /** * The `CommandError` that caused this error, if any. * * Serialized causes are always `CommandError`s. The core helpers never put a * native `Error` here as an enumerable property: `wrapError()` keeps only a * `CommandError` cause, and `internalError()` attaches its `Error` cause * non-enumerably, so it is available to in-process logging but never * serialized. The `Error` type is kept for compatibility. */ cause?: CommandError | Error; } /** * Standard error codes for common scenarios. * * Use these for consistency across AFD applications. This is the shared * catalog from `spec/error-codes.md`: Python, Rust and C++ define the same * codes. Transport-specific codes, such as `HTTP_` and the client's * `OUTCOME_UNKNOWN`, are listed in the spec but not here. */ export declare const ErrorCodes: { readonly VALIDATION_ERROR: "VALIDATION_ERROR"; readonly INVALID_INPUT: "INVALID_INPUT"; readonly MISSING_REQUIRED_FIELD: "MISSING_REQUIRED_FIELD"; readonly INVALID_FORMAT: "INVALID_FORMAT"; readonly NOT_FOUND: "NOT_FOUND"; readonly ALREADY_EXISTS: "ALREADY_EXISTS"; readonly CONFLICT: "CONFLICT"; readonly UNAUTHORIZED: "UNAUTHORIZED"; readonly FORBIDDEN: "FORBIDDEN"; readonly TOKEN_EXPIRED: "TOKEN_EXPIRED"; readonly RATE_LIMITED: "RATE_LIMITED"; readonly QUOTA_EXCEEDED: "QUOTA_EXCEEDED"; readonly SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE"; readonly TIMEOUT: "TIMEOUT"; readonly CONNECTION_ERROR: "CONNECTION_ERROR"; readonly INTERNAL_ERROR: "INTERNAL_ERROR"; readonly NOT_IMPLEMENTED: "NOT_IMPLEMENTED"; readonly UNKNOWN_ERROR: "UNKNOWN_ERROR"; readonly COMMAND_NOT_FOUND: "COMMAND_NOT_FOUND"; readonly INVALID_COMMAND_ARGS: "INVALID_COMMAND_ARGS"; readonly COMMAND_CANCELLED: "COMMAND_CANCELLED"; readonly COMMAND_EXECUTION_ERROR: "COMMAND_EXECUTION_ERROR"; readonly COMMAND_NOT_EXPOSED: "COMMAND_NOT_EXPOSED"; readonly COMMAND_NOT_IN_CONTEXT: "COMMAND_NOT_IN_CONTEXT"; readonly COMMAND_NOT_ALLOWED: "COMMAND_NOT_ALLOWED"; readonly UNKNOWN_TOOL: "UNKNOWN_TOOL"; readonly AMBIGUOUS_ACTION: "AMBIGUOUS_ACTION"; readonly INVALID_GROUPED_CALL: "INVALID_GROUPED_CALL"; readonly SESSION_REQUIRED: "SESSION_REQUIRED"; readonly CONTEXT_NOT_FOUND: "CONTEXT_NOT_FOUND"; readonly CONTEXT_DEPTH_EXCEEDED: "CONTEXT_DEPTH_EXCEEDED"; readonly INVALID_BATCH_REQUEST: "INVALID_BATCH_REQUEST"; readonly BATCH_TIMEOUT: "BATCH_TIMEOUT"; readonly COMMAND_SKIPPED: "COMMAND_SKIPPED"; readonly INVALID_PIPELINE_REQUEST: "INVALID_PIPELINE_REQUEST"; readonly PIPELINE_TIMEOUT: "PIPELINE_TIMEOUT"; readonly UNSUPPORTED_OPTION: "UNSUPPORTED_OPTION"; readonly STREAM_ABORTED: "STREAM_ABORTED"; readonly STREAM_TIMEOUT: "STREAM_TIMEOUT"; readonly STREAM_ERROR: "STREAM_ERROR"; readonly STREAM_ENDED_UNEXPECTEDLY: "STREAM_ENDED_UNEXPECTEDLY"; readonly COMMAND_FAILED: "COMMAND_FAILED"; }; export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes]; /** * Create a CommandError with standard fields. */ export declare function createError(code: string, message: string, options?: Omit): CommandError; /** * Create a validation error. */ export declare function validationError(message: string, details?: Record): CommandError; /** * Create a not found error. */ export declare function notFoundError(resourceType: string, resourceId: string): CommandError; /** * Create a rate limit error. */ export declare function rateLimitError(retryAfterSeconds?: number): CommandError; /** * Create a timeout error. */ export declare function timeoutError(operationName: string, timeoutMs: number): CommandError; /** * Create an internal error (use sparingly - prefer specific errors). * * The `cause` is attached as a non-enumerable property: `error.cause` still * returns it for in-process logging, but it is never serialized, so a native * error's own fields (such as a Node system error's `path`) cannot reach the * caller. */ export declare function internalError(message: string, cause?: Error): CommandError; /** * Wrap an unknown error in a CommandError. * * - A `CommandError` is returned unchanged. * - A native `Error` becomes a new plain `CommandError` built only from its * `message` and, when present and correctly typed, its own `code`, * `suggestion` and `retryable` fields, so structured errors such as * `AuthAdapterError` keep their code. Every other field, such as a Node * system error's `errno`, `syscall` and `path`, is dropped. A Node system * error (an `E`-prefixed `code` such as `ENOENT` or `EACCES`, with `errno` * or `syscall`, or a common POSIX code) also gets a generic message naming * its code, such as `A system error occurred: ENOENT (no such file or * directory)`, because its own message contains the path. `cause` is set * only when the error's cause is itself a `CommandError`. The stack is never * put in `details`: it is kept on a non-enumerable `stack` property for * logging, and is not serialized. * - Any other value becomes `UNKNOWN_ERROR` with its string form as the message. */ export declare function wrapError(error: unknown): CommandError; /** * Type guard to check if a value is a CommandError. * * A CommandError is a plain object with a string `code` and `message`. Native * `Error` instances are rejected even when they carry a string `code`, as Node * system errors (`ENOENT`, ...) do: they do not serialize as CommandErrors and * their own fields can expose file paths. Convert them with `wrapError()`. */ export declare function isCommandError(value: unknown): value is CommandError; //# sourceMappingURL=errors.d.ts.map