import type { DaemonErrorCategory, DaemonErrorSource, StructuredDaemonErrorBody } from './daemon-error-contract.js'; import { SDKErrorCodes, isErrorCode, isKnownErrorCode, type SDKErrorCode } from './error-codes.js'; export type { DaemonErrorSource, StructuredDaemonErrorBody, } from './daemon-error-contract.js'; export { DaemonErrorCategory, MEMORY_RECORD_NOT_FOUND_CODE } from './daemon-error-contract.js'; export { SDKErrorCodes, isErrorCode, isKnownErrorCode, type SDKErrorCode }; /** * `'contract'` is an SDK-internal category used when the daemon returns * a response that violates the expected contract schema. It is NOT part of the * daemon wire schema (`DaemonErrorCategory`) and MUST NOT be marshalled over * the wire, doing so will cause the daemon to schema-reject the error envelope. * Treat `'contract'` as a local SDK sentinel only. */ export type ErrorCategory = DaemonErrorCategory | 'contract'; export type ErrorSource = DaemonErrorSource | 'contract'; /** * Tagged union discriminant for all SDK errors. Use this for exhaustive * switch/if-else handling instead of `instanceof` chains. * * @example * if (error instanceof GoodVibesSdkError) { * if (error.kind === 'rate-limit') { * await delay(error.retryAfterMs ?? 1000); * } else if (error.kind === 'auth') { * // refresh credentials * } * } */ export type SDKErrorKind = 'auth' | 'config' | 'contract' | 'network' | 'not-found' | 'protocol' | 'rate-limit' | 'service' | 'internal' | 'tool' | 'validation' | 'unknown'; export interface GoodVibesSdkErrorOptions { /** * A typed error code for programmatic matching. May be an {@link SDKErrorCode} * literal or any custom string for caller-supplied codes. * When omitted, the SDK infers a code from `category` or `status`. */ readonly code?: SDKErrorCode | (string & {}) | undefined; readonly category?: ErrorCategory | undefined; readonly source?: ErrorSource | undefined; readonly recoverable?: boolean | undefined; readonly status?: number | undefined; readonly url?: string | undefined; readonly method?: string | undefined; readonly body?: unknown | undefined; readonly hint?: string | undefined; readonly provider?: string | undefined; readonly operation?: string | undefined; readonly phase?: string | undefined; readonly requestId?: string | undefined; readonly providerCode?: string | undefined; readonly providerType?: string | undefined; readonly retryAfterMs?: number | undefined; readonly cause?: unknown | undefined; } export declare const RETRYABLE_STATUS_CODES: readonly number[]; /** * Base error class for all errors thrown by the GoodVibes SDK. * * Every error carries a structured `category`, `source`, and `code` that allow * callers to handle specific failure modes without string-matching messages. * * The `code` field is typed as `SDKErrorCode | (string & {})`, SDK-produced * errors always carry a known {@link SDKErrorCode}, while caller-supplied codes * remain valid arbitrary strings. * * ### Narrowing by code * ```ts * import { GoodVibesSdkError, isErrorCode, SDKErrorCodes } from '@pellux/goodvibes-errors'; * * catch (err) { * if (err instanceof GoodVibesSdkError) { * if (isErrorCode(err, SDKErrorCodes.RATE_LIMITED)) { * await delay(err.retryAfterMs ?? 1000); * } else if (isErrorCode(err, SDKErrorCodes.TOKEN_EXPIRED)) { * await refreshToken(); * } * } * } * ``` * * ### Narrowing by kind * ```ts * import { GoodVibesSdkError, HttpStatusError, ConfigurationError } from '@pellux/goodvibes-errors'; * * try { * await sdk.operator.agents.list(); * } catch (err) { * if (err instanceof HttpStatusError && err.category === 'rate_limit') { * // Back off and retry after err.retryAfterMs * } else if (err instanceof ConfigurationError) { * // Invalid SDK setup, not recoverable * } else if (err instanceof GoodVibesSdkError) { * console.error(err.category, err.hint); * } * } * ``` */ export declare class GoodVibesSdkError extends Error { readonly kind: SDKErrorKind; /** * Typed error code for programmatic matching. SDK-produced errors always set * a {@link SDKErrorCode}; caller-supplied codes may be any string. * * **Note:** `code` and `category` are inferred independently and can diverge. * For example, `new GoodVibesSdkError('…', { status: 409 })` yields * `code === 'CONFLICT'` (from `inferCodeFromStatus`) while * `category === 'unknown'` (because `inferCategory` intentionally returns * `'unknown'` for 409, the caller must supply `category` explicitly to get * a meaningful category for conflict-style errors). */ readonly code: SDKErrorCode | (string & {}); readonly category: ErrorCategory; readonly source: ErrorSource; readonly recoverable: boolean; readonly status?: number | undefined; readonly url?: string | undefined; readonly method?: string | undefined; readonly body?: unknown | undefined; readonly hint?: string | undefined; readonly provider?: string | undefined; readonly operation?: string | undefined; readonly phase?: string | undefined; readonly requestId?: string | undefined; readonly providerCode?: string | undefined; readonly providerType?: string | undefined; readonly retryAfterMs?: number | undefined; readonly cause?: unknown | undefined; static [Symbol.hasInstance](value: unknown): boolean; constructor(message: string, options?: GoodVibesSdkErrorOptions); toJSON(): Record; } /** * Thrown when the SDK is misconfigured (e.g. missing `baseUrl`, no fetch * implementation available, or calling a mutation on a read-only auth resolver). * * Always non-recoverable (`recoverable: false`). * Category: `'config'`. Kind: `'config'`. Code: `'SDK_CONFIGURATION_ERROR'`. * * @example * import { ConfigurationError } from '@pellux/goodvibes-errors'; * * try { * await sdk.auth.setToken('x'); * } catch (err) { * if (err instanceof ConfigurationError) { * // SDK was constructed with getAuthToken, token mutation not supported * } * } */ export declare class ConfigurationError extends GoodVibesSdkError { /** * Brand contract, `code` is the source of truth, not the prototype chain. * A `GoodVibesSdkError` constructed directly with `code: 'SDK_CONFIGURATION_ERROR'` * will pass `instanceof ConfigurationError` even if its prototype is only * `GoodVibesSdkError`. Callers that need strict prototype checking should use * `Object.getPrototypeOf(err) === ConfigurationError.prototype` instead. */ static [Symbol.hasInstance](value: unknown): boolean; constructor(message: string, options?: GoodVibesSdkErrorOptions); } /** * Thrown when a response from the daemon violates the expected contract * (unexpected shape, missing required fields, etc.). * * Always non-recoverable (`recoverable: false`). * Category: `'contract'`. Kind: `'contract'`. Code: `'SDK_CONTRACT_ERROR'`. * * @example * import { ContractError } from '@pellux/goodvibes-errors'; * * try { * const result = await sdk.operator.agents.get({ id: agentId }); * } catch (err) { * if (err instanceof ContractError) { * // Daemon returned an unexpected shape, SDK version mismatch? * console.error('Contract violation:', err.message); * } * } */ export declare class ContractError extends GoodVibesSdkError { /** * Brand contract, `code` is the source of truth, not the prototype chain. * A `GoodVibesSdkError` constructed directly with `code: 'SDK_CONTRACT_ERROR'` * will pass `instanceof ContractError` even if its prototype is only * `GoodVibesSdkError`. Callers that need strict prototype checking should use * `Object.getPrototypeOf(err) === ContractError.prototype` instead. */ static [Symbol.hasInstance](value: unknown): boolean; constructor(message: string, options?: GoodVibesSdkErrorOptions); } /** * Thrown when the daemon returns a non-2xx HTTP status code. * * The `category` field is inferred from the status code: * - `401` → `'authentication'` `402` → `'billing'` `403` → `'authorization'` * - `404` → `'not_found'` `408` → `'timeout'` `429` → `'rate_limit'` * - `5xx` → `'service'` * - Any other status (or when constructed without a `status`) → `'unknown'` * * The `code` field is inferred from `status` automatically: * - `400` → `'VALIDATION_FAILED'` * - `401` → `'AUTH_REQUIRED'` * - `402` → `'PAYMENT_REQUIRED'` * - `403` → `'PERMISSION_DENIED'` * - `404` → `'NOT_FOUND'` * - `408` → `'TIMEOUT'` * - `409` → `'CONFLICT'` * - `429` → `'RATE_LIMITED'` * - `5xx` → `'SERVICE_UNAVAILABLE'` * * When constructed without a `status` argument (e.g. as a typed * wrapper around a structured daemon error that provides its own `category`), * the category defaults to `'unknown'`. Callers relying on category-based * routing should always prefer the structured-body factory * (`createHttpStatusError`) or check `err.category` directly rather than * assuming a specific category from constructor arguments alone. * * Use `recoverable` to decide whether to retry, and `retryAfterMs` for * the backoff hint on rate-limit responses. * * @example * import { HttpStatusError } from '@pellux/goodvibes-errors'; * * try { * await sdk.operator.agents.list(); * } catch (err) { * if (err instanceof HttpStatusError) { * if (err.category === 'rate_limit') { * await delay(err.retryAfterMs ?? 1000); * } else if (!err.recoverable) { * throw err; // Surface non-retryable errors immediately * } * } * } */ export declare class HttpStatusError extends GoodVibesSdkError { /** * Brand contract: `instanceof HttpStatusError` relies on a dedicated Symbol * brand stamped in the constructor, enabling cross-realm identity checks that * are independent of the `code` field. * * A `GoodVibesSdkError` constructed directly with `code: 'SDK_HTTP_STATUS_ERROR'` * will also pass `instanceof HttpStatusError` for backward compatibility with * callers that serialise/deserialise errors by code. Callers that need strict * prototype checking should use * `Object.getPrototypeOf(err) === HttpStatusError.prototype` instead. */ static [Symbol.hasInstance](value: unknown): boolean; constructor(message: string, options?: GoodVibesSdkErrorOptions); } export declare function isStructuredDaemonErrorBody(value: unknown): value is StructuredDaemonErrorBody; /** * Creates an {@link HttpStatusError} from an HTTP response. * * When `body` is a {@link StructuredDaemonErrorBody}, its fields are used * directly (including any explicit `code`). When the body is unstructured, * the `code` is inferred from `status` via status-based inference (`inferCodeFromStatus`). * * The structured body path respects the body-supplied `code` over status * inference, preserving full backward compatibility for callers that supply * custom codes in the daemon response. * * @param status - HTTP status code. * @param url - Request URL. * @param method - HTTP method. * @param body - Parsed response body (may be structured or unstructured). * @param fallbackHint - Human-readable hint when the body provides none. */ export declare function createHttpStatusError(status: number, url: string, method: string, body: unknown, fallbackHint?: string): HttpStatusError; //# sourceMappingURL=index.d.ts.map