@eleva-io/erp-sdk
Version:
SDK oficial para el ERP de Eleva
224 lines • 10.1 kB
TypeScript
import { z } from 'zod';
import { ErrorCode, type ErrorDetails } from './catalog';
import { ErrorKind } from './catalog_types';
import { BASE_ERROR_CODES } from './catalog_base';
import { API_ERROR_CODES } from './catalog_api';
/** Plain-object representation of an `ElevaError`, suitable for serialisation. */
export interface ElevaErrorJSON<C extends ErrorCode = ErrorCode> {
code: C | string;
kind: ErrorKind;
status: number;
message: string;
details: ErrorDetails<C>;
}
/**
* Slim response payload for API consumers.
* `SYSTEM` errors omit `details`; `DOMAIN` errors include it.
*/
export interface ElevaErrorResponse<C extends ErrorCode = ErrorCode> {
code: ElevaErrorJSON<C>['code'];
message: ElevaErrorJSON<C>['message'];
details?: ElevaErrorJSON<C>['details'];
}
/** Constructor arguments for `ElevaError`. Adds optional `cause` for error chaining. */
export type ElevaErrorArgs<C extends ErrorCode> = ElevaErrorJSON<C> & {
/** The original error forwarded to `Error.cause`. */
cause?: unknown;
};
/**
* Central error class for the Eleva ERP SDK.
*
* Extends `Error` with structured metadata: `code`, `kind`, `status`, and typed `details`.
*
* ```ts
* // Create
* throw ElevaError.notFound({ entity: 'Invoice' })
* throw ElevaError.conflict({ details: [{ key: 'email', value: 'a@b.com', cause: 'duplicate' }] })
*
* // Narrow
* if (err instanceof ElevaError && err.is(ERROR_CODES.NOT_FOUND)) {
* console.log(err.details.entity) // string
* }
* ```
*
* Serialisation: `toJSON()` for logging, `toResponse()` for sanitised API output.
*/
export declare class ElevaError<C extends ErrorCode = ErrorCode> extends Error {
/** Error code constant identifying the failure condition. */
readonly code: C | string;
/** `DOMAIN` (safe to expose) or `SYSTEM` (sanitised before sending to clients). */
readonly kind: ErrorKind;
/** HTTP status code for this error. */
readonly status: number;
/** Structured, code-specific failure context. */
readonly details: ErrorDetails<C>;
constructor(args: ElevaErrorArgs<C>);
/**
* Type-guard: narrows to `ElevaError<K>` when `this.code === code`.
* After a positive check `this.details` is fully typed for `K`.
* @example
* if (err.is(ERROR_CODES.NOT_FOUND)) console.log(err.details.entity)
*/
is<K extends ErrorCode>(code: K | string): this is ElevaError<K>;
/** Full serialised representation for logging / diagnostics. */
toJSON(): ElevaErrorJSON<C>;
toString(): string;
/**
* Sanitised payload safe for API responses.
* `SYSTEM` errors replace the message with a generic string; `DOMAIN` errors include `details`.
*/
toResponse(): ElevaErrorResponse<C>;
/**
* Parses an unknown value into `ElevaErrorArgs`. Shared by `parse()` and `RemoteElevaError.from()`.
*
* Strategy: validate against `errorSchema` → look up known codes in the catalog →
* fall back to `INTERNAL_SERVER_ERROR` for unrecognised codes or malformed payloads →
* accept legacy `errors` field as a fallback for `details`.
*/
protected static _parsePayload(value: unknown): ElevaErrorArgs<ErrorCode>;
/** Deserialises an unknown value into an `ElevaError`. Unrecognised payloads become `INTERNAL_SERVER_ERROR`. */
static parse(value: unknown): ElevaError<ErrorCode>;
/** Converts a `ZodError` into a `VALIDATION` error, preserving field paths and rule codes. */
static fromZodError<T>(error: z.ZodError<T>): ElevaError<BASE_ERROR_CODES.VALIDATION>;
/** Creates a `VALIDATION` error from a pre-built array of issue descriptors. */
static validation(args: {
errors: ErrorDetails<BASE_ERROR_CODES.VALIDATION>['errors'];
message?: string;
}): ElevaError<BASE_ERROR_CODES.VALIDATION>;
/** Creates a `VALIDATION` error for a single invalid field. Convenience wrapper around `validation()`. */
static invalidField(args: {
error: ErrorDetails<BASE_ERROR_CODES.VALIDATION>['errors'][number];
message?: string;
}): ElevaError<BASE_ERROR_CODES.VALIDATION>;
/** HTTP 400 — request is malformed or has invalid parameters outside of validation. */
static readonly badRequest: (args?: {
message?: string;
details?: {
field?: string | undefined;
reason?: string | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.BAD_REQUEST>;
/** HTTP 401 — credentials are missing, expired, or invalid. Caller must re-authenticate. */
static readonly authentication: (args?: {
message?: string;
details?: {
reason?: string | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.AUTHENTICATION>;
/** HTTP 403 — authenticated but lacks the required scope or permission. */
static readonly unauthorized: (args?: {
message?: string;
details?: {
requiredScope?: string | undefined;
resource?: string | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.UNAUTHORIZED>;
/**
* HTTP 404 — no resource found for the given identifier.
* @param args.entity - Entity type that was not found (e.g. `"Invoice"`).
*/
static readonly notFound: (args: Record<"entity", string> & {
message?: string;
}) => ElevaError<BASE_ERROR_CODES.NOT_FOUND>;
/** HTTP 406 — server cannot produce a response matching the `Accept` header. */
static readonly notAcceptable: (args?: {
message?: string;
details?: {
acceptedTypes?: string[] | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.NOT_ACCEPTABLE>;
/** HTTP 409 — operation violates a uniqueness or integrity constraint. */
static readonly conflict: (args: {
details: {
value: string;
key: string;
cause: string;
}[];
message?: string;
}) => ElevaError<BASE_ERROR_CODES.CONFLICT>;
/** HTTP 410 — resource permanently removed; retrying will never succeed. */
static readonly gone: (args?: {
message?: string;
details?: {
since?: string | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.GONE>;
/** HTTP 422 — request is syntactically valid but semantically unprocessable. */
static readonly unprocessableEntity: (args?: {
message?: string;
details?: {
field?: string | undefined;
reason?: string | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.UNPROCESSABLE_ENTITY>;
/**
* HTTP 502 — upstream service returned an invalid response (`SYSTEM`).
* @param args.details.upstream - Name of the misbehaving upstream service.
*/
static readonly badGateway: (args?: {
message?: string;
details?: {
upstream?: string | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.BAD_GATEWAY>;
/** HTTP 503 — service temporarily unavailable (`SYSTEM`). Pass `retryAfter` (seconds) if known. */
static readonly serviceUnavailable: (args?: {
message?: string;
details?: {
retryAfter?: number | undefined;
} | undefined;
} | undefined) => ElevaError<BASE_ERROR_CODES.SERVICE_UNAVAILABLE>;
/**
* HTTP 400 — a required field was missing from the request.
* @param args.field - Name of the missing field.
*/
static readonly mandatoryField: (args: Record<"field", string> & {
message?: string;
}) => ElevaError<BASE_ERROR_CODES.MANDATORY_FIELD>;
/**
* HTTP 500 — unexpected server error (`SYSTEM`).
* Pass the original exception as `cause` to preserve the full stack chain for logging.
*/
static internal(args?: {
message?: string;
cause?: unknown;
details?: ErrorDetails<BASE_ERROR_CODES.INTERNAL_SERVER_ERROR>;
}): ElevaError<BASE_ERROR_CODES.INTERNAL_SERVER_ERROR>;
static forbiddenContact(args: {
message?: string;
details: ErrorDetails<API_ERROR_CODES.FORBIDDEN_CONTACT>;
}): ElevaError<API_ERROR_CODES.FORBIDDEN_CONTACT>;
/**
* HTTP 413 — bulk messaging attachments exceed the maximum allowed total size.
* @param args.details.maxBytes - Maximum total size allowed, in bytes.
* @param args.details.totalBytes - Total size of the submitted attachments, in bytes.
*/
static readonly horizontalBulkMessagingAttachmentsTooLarge: (args: {
details: {
maxBytes: number;
totalBytes: number;
};
message?: string;
}) => ElevaError<API_ERROR_CODES.HORIZONTAL_BULK_MESSAGING_ATTACHMENTS_TOO_LARGE>;
static horizontalClaimPolicyCommunityMismatch(args: {
message?: string;
details: ErrorDetails<API_ERROR_CODES.HORIZONTAL_CLAIM_POLICY_COMMUNITY_MISMATCH>;
}): ElevaError<API_ERROR_CODES.HORIZONTAL_CLAIM_POLICY_COMMUNITY_MISMATCH>;
static horizontalClaimContactAlreadyLinked(args: {
message?: string;
details: ErrorDetails<API_ERROR_CODES.HORIZONTAL_CLAIM_CONTACT_ALREADY_LINKED>;
}): ElevaError<API_ERROR_CODES.HORIZONTAL_CLAIM_CONTACT_ALREADY_LINKED>;
static horizontalClaimClosedBeforeOpened(args: {
message?: string;
details: ErrorDetails<API_ERROR_CODES.HORIZONTAL_CLAIM_CLOSED_BEFORE_OPENED>;
}): ElevaError<API_ERROR_CODES.HORIZONTAL_CLAIM_CLOSED_BEFORE_OPENED>;
static ticketingTaskClaimSubRefNotAllowed(args: {
message?: string;
details: ErrorDetails<API_ERROR_CODES.TICKETING_TASK_CLAIM_SUBREF_NOT_ALLOWED>;
}): ElevaError<API_ERROR_CODES.TICKETING_TASK_CLAIM_SUBREF_NOT_ALLOWED>;
static ticketingTaskClaimAlreadyAssociated(args: {
message?: string;
details: ErrorDetails<API_ERROR_CODES.TICKETING_TASK_CLAIM_ALREADY_ASSOCIATED>;
}): ElevaError<API_ERROR_CODES.TICKETING_TASK_CLAIM_ALREADY_ASSOCIATED>;
}
//# sourceMappingURL=errors.d.ts.map