e-bon
e-bon.ro
SDK TypeScript

Erori

Clasele de excepție FiscalError și EBonApiError, enumerarea ErrorCode și mulțimea RETRYABLE_ERRORS re-exportate din @e-bon/sdk și un model recomandat de reîncercare.

Erori

Fiecare eșec care iese din @e-bon/sdk este o instanță a uneia din două clase concrete — EBonApiError pentru eșecurile la nivel HTTP, FiscalError pentru eșecurile fiscale de la imprimantă. Nu există nicio aruncare simplă de Error și nicio respingere netipată de tip unknown din SDK însuși.

Pentru catalogul complet al codurilor HTTP și FiscalError cu pași de recuperare per cod, vezi /ro/api/errors.

EBonApiError

EBonApiError împachetează orice răspuns HTTP non-2xx de la https://api.e-bon.ro. Este aruncată și pentru eșecurile la nivel de transport — timeout-uri de cerere (SDK-ul anulează prin AbortController după timeout milisecunde, implicit 30000) și erori fetch — cu status: 0 și un code sintetic TIMEOUT sau NETWORK_ERROR.

class EBonApiError extends Error {
  status: number              // statusul HTTP, sau 0 pentru erori de transport
  code: string                // se potrivește cu catalogul de erori HTTP (UNAUTHORIZED, VALIDATION_ERROR, …)
  message: string
  details: ApiErrorDetails[]  // populat la VALIDATION_ERROR și la câteva alte coduri
  retryAfter?: number         // secunde — populat pe 429 din antetul Retry-After
}

Ramifică pe status și code în loc să parsezi mesajul:

import { EBonApiError } from '@e-bon/sdk';

try {
  await client.receipts.create(body);
} catch (err) {
  if (err instanceof EBonApiError) {
    if (err.code === 'VALIDATION_ERROR') {
      for (const detail of err.details) {
        console.warn(`${detail.field ?? '<root>'}: ${detail.message}`);
      }
      return;
    }
    if (err.status === 429 && err.retryAfter) {
      await sleep(err.retryAfter * 1000);
      return;
    }
  }
  throw err;
}

Catalogul complet al valorilor code la nivel HTTP se află la Prezentare generală API › Catalogul codurilor de eroare HTTP.

FiscalError

FiscalError reprezintă un eșec care a pornit de la imprimantă sau de la driver-ul fiscal. SDK-ul construiește și atașează o astfel de instanță fiecărui payload command.failed, iar metodele de resursă care rezolvă o comandă fiscală sincron (de exemplu un wrapper care face polling până la finalizare) o aruncă direct.

Clasa are exact patru câmpuri tipate dincolo de message-ul moștenit:

class FiscalError extends Error {
  code: ErrorCode             // unul din codurile fiscale E100…E901
  message: string
  retryable: boolean          // precalculat prin isRetryable(code)
  commandId?: string          // comanda care a eșuat, când se cunoaște
  deviceId?: string           // aparatul care a emis eșecul, când se cunoaște
}

Constructorul acceptă { code, message, commandId?, deviceId? }; retryable este derivat în interiorul constructorului din isRetryable(code), deci nu e nevoie să-l calculezi tu.

Enumerarea completă ErrorCode și maparea de retryable per cod sunt documentate la Prezentare generală API › Coduri de eroare fiscale / de aparat.

Importă utilitarele de erori din @e-bon/sdk

@e-bon/sdk re-exportă cele trei piese de care ai nevoie ca să lucrezi cu erorile fiscale fără să tragi @e-bon/types direct:

import { ErrorCode, RETRYABLE_ERRORS, isRetryable } from '@e-bon/sdk';
  • ErrorCode — enumerarea codurilor de eroare fiscale (E100E901). Folosește-o pentru switch-uri și pentru comparații tipate cu FiscalError.code.
  • RETRYABLE_ERRORS — mulțimea canonică de valori ErrorCode care pot fi retrimise în siguranță. Reflectă coloana retryable din tabelul de prezentare API.
  • isRetryable(code) — helper-ul care stă la baza câmpului FiscalError.retryable. Util când primești un cod printr-un canal exterior (un webhook, o coloană de bază de date) și vrei același răspuns.

Reîncearcă în siguranță eșecurile tranzitorii

Combină FiscalError.retryable cu antetul Idempotency-Key pe cererea HTTP subiacentă pentru a relua eșecurile fiscale tranzitorii fără riscul de a tipări de două ori:

import { EBonApiError, FiscalError } from '@e-bon/sdk';

async function sendWithRetry(
  client: EBonClient,
  body: SendCommandBody,
  idempotencyKey: string,
  maxAttempts = 3,
) {
  let attempt = 0;
  let delay = 1_000;

  while (true) {
    attempt += 1;
    try {
      return await client.commands.send(body);
    } catch (err) {
      // Eșec fiscal la imprimantă.
      if (err instanceof FiscalError && err.retryable && attempt < maxAttempts) {
        await sleep(delay);
        delay *= 2;
        continue;
      }

      // Limită de rată la nivel HTTP. Respectă Retry-After.
      if (err instanceof EBonApiError && err.status === 429 && err.retryAfter) {
        await sleep(err.retryAfter * 1000);
        continue;
      }

      throw err;
    }
  }
}

Pasarea aceleiași idempotencyKey la reîncercări este ce face acest model sigur — serverul returnează răspunsul cache-uit din încercarea originală, în loc să execute comanda de două ori. Vezi Prezentare generală API › Idempotență pentru regulile complete.

Reîncearcă doar când err.retryable este true. Coduri precum FiscalMemoryFull (E300), FiscalDailyLimitReached (E303) și FiscalHardwareError (E304) cer un operator pe loc, nu încă un tur prin rețea.

Unde mergi mai departe