@taxora/sdk 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -46,6 +46,7 @@ __export(index_exports, {
46
46
  LoginIdentifier: () => LoginIdentifier,
47
47
  ProviderDocument: () => ProviderDocument,
48
48
  ProviderDocumentLine: () => ProviderDocumentLine,
49
+ RetryPolicy: () => RetryPolicy,
49
50
  RevenueStatistics: () => RevenueStatistics,
50
51
  ScoreBreakdown: () => ScoreBreakdown,
51
52
  SireneLookupResult: () => SireneLookupResult,
@@ -53,6 +54,7 @@ __export(index_exports, {
53
54
  SmartEnrichmentHistoryPage: () => SmartEnrichmentHistoryPage,
54
55
  SmartEnrichmentHistoryRow: () => SmartEnrichmentHistoryRow,
55
56
  SmartEnrichmentJob: () => SmartEnrichmentJob,
57
+ SmartEnrichmentMode: () => SmartEnrichmentMode,
56
58
  SmartEnrichmentResource: () => SmartEnrichmentResource,
57
59
  SmartEnrichmentStatistics: () => SmartEnrichmentStatistics,
58
60
  SmartEnrichmentStatus: () => SmartEnrichmentStatus,
@@ -68,10 +70,12 @@ __export(index_exports, {
68
70
  VatResource: () => VatResource,
69
71
  VatState: () => VatState,
70
72
  VatValidationAddressInput: () => VatValidationAddressInput,
73
+ describeApiError: () => describeApiError,
71
74
  describeComplianceEnrollmentStatus: () => describeComplianceEnrollmentStatus,
72
75
  describeComplianceTaxReportState: () => describeComplianceTaxReportState,
73
76
  describeComplianceTransactionState: () => describeComplianceTransactionState,
74
77
  describeComplianceTransactionType: () => describeComplianceTransactionType,
78
+ describeSmartEnrichmentMode: () => describeSmartEnrichmentMode,
75
79
  describeSmartEnrichmentStatus: () => describeSmartEnrichmentStatus,
76
80
  describeVatState: () => describeVatState,
77
81
  getBaseUrl: () => getBaseUrl,
@@ -80,6 +84,7 @@ __export(index_exports, {
80
84
  toComplianceTaxReportState: () => toComplianceTaxReportState,
81
85
  toComplianceTransactionState: () => toComplianceTransactionState,
82
86
  toComplianceTransactionType: () => toComplianceTransactionType,
87
+ toSmartEnrichmentMode: () => toSmartEnrichmentMode,
83
88
  toSmartEnrichmentStatus: () => toSmartEnrichmentStatus
84
89
  });
85
90
  module.exports = __toCommonJS(index_exports);
@@ -146,37 +151,299 @@ var AuthenticationException = class extends TaxoraException {
146
151
  }
147
152
  };
148
153
 
154
+ // src/exceptions/apiErrorMessage.ts
155
+ var MAX_LENGTH = 500;
156
+ var MAX_PLAIN_LENGTH = 200;
157
+ var REASON_PHRASES = {
158
+ 400: "Bad Request",
159
+ 401: "Unauthorized",
160
+ 403: "Forbidden",
161
+ 404: "Not Found",
162
+ 405: "Method Not Allowed",
163
+ 408: "Request Timeout",
164
+ 409: "Conflict",
165
+ 413: "Payload Too Large",
166
+ 422: "Unprocessable Entity",
167
+ 429: "Too Many Requests",
168
+ 500: "Internal Server Error",
169
+ 502: "Bad Gateway",
170
+ 503: "Service Unavailable",
171
+ 504: "Gateway Timeout"
172
+ };
173
+ function describeApiError(body, statusCode) {
174
+ return jsonErrorMessage(body) ?? plainErrorMessage(body) ?? statusErrorMessage(statusCode);
175
+ }
176
+ function detailApiError(body, statusCode) {
177
+ return jsonErrorMessage(body) ?? plainErrorMessage(body) ?? statusPhrase(statusCode);
178
+ }
179
+ function jsonErrorMessage(body) {
180
+ if (body === null || body === void 0 || body.trim() === "") return null;
181
+ let parsed;
182
+ try {
183
+ parsed = JSON.parse(body);
184
+ } catch {
185
+ return null;
186
+ }
187
+ if (typeof parsed !== "object" || parsed === null) return null;
188
+ const payload = parsed;
189
+ for (const key of ["message", "error"]) {
190
+ const value = payload[key];
191
+ if (typeof value === "string") {
192
+ const message = sanitize(value);
193
+ if (message !== null) return message;
194
+ }
195
+ }
196
+ const errors = payload["errors"];
197
+ if (typeof errors === "object" && errors !== null) {
198
+ return fromErrorBag(errors);
199
+ }
200
+ return null;
201
+ }
202
+ function statusErrorMessage(statusCode) {
203
+ return `Taxora API request failed (${statusPhrase(statusCode)}).`;
204
+ }
205
+ function statusPhrase(statusCode) {
206
+ const phrase = REASON_PHRASES[statusCode];
207
+ return `HTTP ${statusCode}${phrase ? ` ${phrase}` : ""}`;
208
+ }
209
+ function plainErrorMessage(body) {
210
+ if (body === null || body === void 0) return null;
211
+ const value = body.replace(/\s+/g, " ").trim();
212
+ if (value === "" || value.length > MAX_PLAIN_LENGTH) return null;
213
+ if (value.includes("<") || value.includes("{")) return null;
214
+ return value;
215
+ }
216
+ function fromErrorBag(errors) {
217
+ for (const [field, messages] of Object.entries(errors)) {
218
+ for (const message of Array.isArray(messages) ? messages : [messages]) {
219
+ if (typeof message !== "string") continue;
220
+ const sanitized = sanitize(message);
221
+ if (sanitized === null) continue;
222
+ return field !== "" ? `${field}: ${sanitized}` : sanitized;
223
+ }
224
+ }
225
+ return null;
226
+ }
227
+ function sanitize(value) {
228
+ const collapsed = value.replace(/\s+/g, " ").trim();
229
+ if (collapsed === "") return null;
230
+ if (/<!doctype\s+html|<html[\s>]/i.test(collapsed)) return null;
231
+ return collapsed.length > MAX_LENGTH ? `${collapsed.slice(0, MAX_LENGTH - 1)}\u2026` : collapsed;
232
+ }
233
+
149
234
  // src/exceptions/HttpException.ts
150
- var HttpException = class extends TaxoraException {
235
+ var HttpException = class _HttpException extends TaxoraException {
151
236
  statusCode;
152
237
  responseBody;
153
- constructor(message, statusCode, responseBody, context = {}) {
238
+ /** Raw `Retry-After` header of the failed response, when it carried one. */
239
+ retryAfter;
240
+ constructor(message, statusCode, responseBody, context = {}, retryAfter = null) {
154
241
  super(message, context);
155
242
  this.name = "HttpException";
156
243
  this.statusCode = statusCode;
157
244
  this.responseBody = responseBody;
245
+ this.retryAfter = retryAfter;
158
246
  Object.setPrototypeOf(this, new.target.prototype);
159
247
  }
248
+ /**
249
+ * The final failure after the SDK retried a transient gateway error, e.g.
250
+ * "Taxora VAT validation failed after 3 attempts (HTTP 504 Gateway Timeout)."
251
+ */
252
+ static afterAttempts(operation, attempts, last) {
253
+ const detail = detailApiError(last.getResponseBody(), last.getStatusCode());
254
+ return new _HttpException(
255
+ `Taxora ${operation} failed after ${attempts} attempts (${detail}).`,
256
+ last.getStatusCode(),
257
+ last.getResponseBody(),
258
+ { ...last.context, attempts, cause: last },
259
+ last.getRetryAfter()
260
+ );
261
+ }
160
262
  getStatusCode() {
161
263
  return this.statusCode;
162
264
  }
163
265
  getResponseBody() {
164
266
  return this.responseBody;
165
267
  }
268
+ getRetryAfter() {
269
+ return this.retryAfter;
270
+ }
166
271
  };
167
272
 
273
+ // src/http/RetryPolicy.ts
274
+ var DEFAULT_RETRYABLE_STATUS_CODES = [502, 503, 504];
275
+ var RETRY_AFTER_ONLY_STATUS_CODES = [429];
276
+ var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
277
+ "ECONNRESET",
278
+ "ECONNREFUSED",
279
+ "ECONNABORTED",
280
+ "EPIPE",
281
+ "ETIMEDOUT",
282
+ "EAI_AGAIN",
283
+ "EHOSTUNREACH",
284
+ "ENETUNREACH",
285
+ "ENETDOWN",
286
+ "UND_ERR_CONNECT_TIMEOUT",
287
+ "UND_ERR_HEADERS_TIMEOUT",
288
+ "UND_ERR_BODY_TIMEOUT",
289
+ "UND_ERR_SOCKET"
290
+ ]);
291
+ var RetryPolicy = class _RetryPolicy {
292
+ maxAttempts;
293
+ initialDelayMs;
294
+ backoffMultiplier;
295
+ maxDelayMs;
296
+ retryableStatusCodes;
297
+ respectRetryAfter;
298
+ maxRetryAfterMs;
299
+ retryOnNetworkErrors;
300
+ sleeper;
301
+ constructor(options = {}) {
302
+ this.maxAttempts = options.maxAttempts ?? 3;
303
+ this.initialDelayMs = options.initialDelayMs ?? 500;
304
+ this.backoffMultiplier = options.backoffMultiplier ?? 2;
305
+ this.maxDelayMs = options.maxDelayMs ?? 5e3;
306
+ this.retryableStatusCodes = options.retryableStatusCodes ?? DEFAULT_RETRYABLE_STATUS_CODES;
307
+ this.respectRetryAfter = options.respectRetryAfter ?? true;
308
+ this.maxRetryAfterMs = options.maxRetryAfterMs ?? 1e4;
309
+ this.retryOnNetworkErrors = options.retryOnNetworkErrors ?? true;
310
+ this.sleeper = options.sleeper;
311
+ if (this.maxAttempts < 1) throw new Error("maxAttempts must be at least 1.");
312
+ if (this.initialDelayMs < 0 || this.maxDelayMs < 0) throw new Error("Delays must not be negative.");
313
+ if (this.backoffMultiplier < 1) throw new Error("backoffMultiplier must be at least 1.");
314
+ }
315
+ /** No retrying at all — every failure is surfaced on the first attempt. */
316
+ static disabled() {
317
+ return new _RetryPolicy({ maxAttempts: 1 });
318
+ }
319
+ /** Retry immediately, without waiting (mainly useful in tests). */
320
+ static withoutDelay(maxAttempts = 3) {
321
+ return new _RetryPolicy({ maxAttempts, initialDelayMs: 0, maxDelayMs: 0 });
322
+ }
323
+ isRetryable(statusCode, retryAfterHeader) {
324
+ const retryAfterMs = this.retryAfterMs(retryAfterHeader);
325
+ if (retryAfterMs !== null && retryAfterMs > this.maxRetryAfterMs) return false;
326
+ if (this.retryableStatusCodes.includes(statusCode)) return true;
327
+ return retryAfterMs !== null && RETRY_AFTER_ONLY_STATUS_CODES.includes(statusCode);
328
+ }
329
+ /** @param attempt Number of attempts made so far (1 = the first one just failed). */
330
+ shouldRetry(statusCode, attempt, retryAfterHeader) {
331
+ return attempt < this.maxAttempts && this.isRetryable(statusCode, retryAfterHeader);
332
+ }
333
+ /**
334
+ * A connection-level failure: the request never got an answer, so repeating it
335
+ * is as safe as repeating a gateway timeout.
336
+ */
337
+ isRetryableError(error) {
338
+ if (!this.retryOnNetworkErrors || !(error instanceof Error)) return false;
339
+ if (error.name === "AbortError" || error.name === "TimeoutError") return true;
340
+ const code = error.code ?? error.cause?.code;
341
+ if (typeof code === "string" && NETWORK_ERROR_CODES.has(code)) return true;
342
+ return error instanceof TypeError && /fetch failed|network|failed to fetch/i.test(error.message);
343
+ }
344
+ shouldRetryError(error, attempt) {
345
+ return attempt < this.maxAttempts && this.isRetryableError(error);
346
+ }
347
+ /**
348
+ * The wait the API asked for, in milliseconds — seconds or HTTP-date form — or
349
+ * null when there is none, it cannot be parsed, or the header is ignored.
350
+ */
351
+ retryAfterMs(header, now = /* @__PURE__ */ new Date()) {
352
+ if (!this.respectRetryAfter || header === null || header === void 0) return null;
353
+ const value = header.trim();
354
+ if (value === "") return null;
355
+ if (/^\d+$/.test(value)) return Number(value) * 1e3;
356
+ const date = Date.parse(value);
357
+ if (Number.isNaN(date)) return null;
358
+ return Math.max(0, date - now.getTime());
359
+ }
360
+ /** The wait before the next attempt: what the API asked for, else exponential backoff. */
361
+ delayMsForAttempt(attempt, retryAfterHeader) {
362
+ const retryAfterMs = this.retryAfterMs(retryAfterHeader);
363
+ if (retryAfterMs !== null) return Math.min(retryAfterMs, this.maxRetryAfterMs);
364
+ if (this.initialDelayMs === 0) return 0;
365
+ const delay = Math.round(this.initialDelayMs * this.backoffMultiplier ** Math.max(0, attempt - 1));
366
+ return Math.max(0, Math.min(delay, this.maxDelayMs));
367
+ }
368
+ async sleepBeforeRetry(attempt, retryAfterHeader) {
369
+ const delayMs = this.delayMsForAttempt(attempt, retryAfterHeader);
370
+ if (delayMs <= 0) return;
371
+ if (this.sleeper) {
372
+ await this.sleeper(delayMs);
373
+ return;
374
+ }
375
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
376
+ }
377
+ };
378
+
379
+ // src/http/withRetries.ts
380
+ async function withRetries(policy, operation, request) {
381
+ let attempt = 1;
382
+ for (; ; ) {
383
+ try {
384
+ return await request();
385
+ } catch (error) {
386
+ if (!(error instanceof HttpException)) {
387
+ if (!policy.shouldRetryError(error, attempt)) throw error;
388
+ await policy.sleepBeforeRetry(attempt);
389
+ attempt++;
390
+ continue;
391
+ }
392
+ const retryAfter = error.getRetryAfter();
393
+ if (!policy.shouldRetry(error.getStatusCode(), attempt, retryAfter)) {
394
+ throw attempt > 1 && policy.isRetryable(error.getStatusCode(), retryAfter) ? HttpException.afterAttempts(operation, attempt, error) : error;
395
+ }
396
+ await policy.sleepBeforeRetry(attempt, retryAfter);
397
+ attempt++;
398
+ }
399
+ }
400
+ }
401
+ async function withResponseRetries(policy, operation, send) {
402
+ let attempt = 1;
403
+ for (; ; ) {
404
+ let response;
405
+ try {
406
+ response = await send();
407
+ } catch (error) {
408
+ if (!policy.shouldRetryError(error, attempt)) throw error;
409
+ await policy.sleepBeforeRetry(attempt);
410
+ attempt++;
411
+ continue;
412
+ }
413
+ const retryAfter = response.headers.get("retry-after");
414
+ if (!policy.shouldRetry(response.status, attempt, retryAfter)) {
415
+ if (attempt > 1 && policy.isRetryable(response.status, retryAfter)) {
416
+ const body = await response.text();
417
+ const last = new HttpException(
418
+ describeApiError(body, response.status),
419
+ response.status,
420
+ body,
421
+ {},
422
+ retryAfter
423
+ );
424
+ throw HttpException.afterAttempts(operation, attempt, last);
425
+ }
426
+ return response;
427
+ }
428
+ await policy.sleepBeforeRetry(attempt, retryAfter);
429
+ attempt++;
430
+ }
431
+ }
432
+
168
433
  // src/endpoints/AuthEndpoint.ts
169
434
  var AuthEndpoint = class {
170
- constructor(baseUrl, apiKey, tokenStorage, httpClient) {
435
+ constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
171
436
  this.baseUrl = baseUrl;
172
437
  this.apiKey = apiKey;
173
438
  this.tokenStorage = tokenStorage;
174
439
  this.httpClient = httpClient;
440
+ this.retryPolicy = retryPolicy;
175
441
  }
176
442
  baseUrl;
177
443
  apiKey;
178
444
  tokenStorage;
179
445
  httpClient;
446
+ retryPolicy;
180
447
  async login(identifier, password, device, loginIdentifier = LoginIdentifier.EMAIL) {
181
448
  const deviceName = device ?? (0, import_os.hostname)();
182
449
  const body = {
@@ -189,24 +456,32 @@ var AuthEndpoint = class {
189
456
  } else {
190
457
  body["email"] = identifier;
191
458
  }
192
- const response = await this.httpClient.request("POST", `${this.baseUrl}/auth/login`, {
193
- headers: {
194
- "Content-Type": "application/json",
195
- "x-api-key": this.apiKey
196
- },
197
- body: JSON.stringify(body)
198
- });
199
- const responseText = await response.text();
200
- if (response.status === 401) {
201
- throw new AuthenticationException("Authentication failed: invalid credentials", {
202
- status: 401,
203
- body: responseText
459
+ const data = await withRetries(this.retryPolicy, "login", async () => {
460
+ const response = await this.httpClient.request("POST", `${this.baseUrl}/auth/login`, {
461
+ headers: {
462
+ "Content-Type": "application/json",
463
+ "x-api-key": this.apiKey
464
+ },
465
+ body: JSON.stringify(body)
204
466
  });
205
- }
206
- if (!response.ok) {
207
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
208
- }
209
- const data = this.parseResponse(responseText);
467
+ const responseText = await response.text();
468
+ if (response.status === 401) {
469
+ throw new AuthenticationException("Authentication failed: invalid credentials", {
470
+ status: 401,
471
+ body: responseText
472
+ });
473
+ }
474
+ if (!response.ok) {
475
+ throw new HttpException(
476
+ describeApiError(responseText, response.status),
477
+ response.status,
478
+ responseText,
479
+ {},
480
+ response.headers.get("retry-after")
481
+ );
482
+ }
483
+ return this.parseResponse(responseText, response.status);
484
+ });
210
485
  const token = Token.fromArray(data);
211
486
  this.tokenStorage.set(token);
212
487
  return token;
@@ -223,28 +498,36 @@ var AuthEndpoint = class {
223
498
  if (storedToken) {
224
499
  headers["Authorization"] = `Bearer ${storedToken.accessToken}`;
225
500
  }
226
- const response = await this.httpClient.request("POST", `${this.baseUrl}/auth/refresh`, { headers });
227
- const responseText = await response.text();
228
- if (response.status === 401) {
229
- throw new AuthenticationException("Token refresh failed: unauthorized", { status: 401, body: responseText });
230
- }
231
- if (!response.ok) {
232
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
233
- }
234
- const data = this.parseResponse(responseText);
501
+ const data = await withRetries(this.retryPolicy, "token refresh", async () => {
502
+ const response = await this.httpClient.request("POST", `${this.baseUrl}/auth/refresh`, { headers });
503
+ const responseText = await response.text();
504
+ if (response.status === 401) {
505
+ throw new AuthenticationException("Token refresh failed: unauthorized", { status: 401, body: responseText });
506
+ }
507
+ if (!response.ok) {
508
+ throw new HttpException(
509
+ describeApiError(responseText, response.status),
510
+ response.status,
511
+ responseText,
512
+ {},
513
+ response.headers.get("retry-after")
514
+ );
515
+ }
516
+ return this.parseResponse(responseText, response.status);
517
+ });
235
518
  const token = Token.fromArray(data);
236
519
  this.tokenStorage.set(token);
237
520
  return token;
238
521
  }
239
- parseResponse(responseText) {
522
+ parseResponse(responseText, statusCode) {
240
523
  let parsed;
241
524
  try {
242
525
  parsed = JSON.parse(responseText);
243
526
  } catch {
244
- throw new HttpException("Invalid JSON response", 0, responseText);
527
+ throw new HttpException("Invalid JSON response", statusCode, responseText);
245
528
  }
246
529
  if (typeof parsed !== "object" || parsed === null) {
247
- throw new HttpException("Unexpected response format", 0, responseText);
530
+ throw new HttpException("Unexpected response format", statusCode, responseText);
248
531
  }
249
532
  const obj = parsed;
250
533
  if (obj["data"] !== void 0 && typeof obj["data"] === "object" && obj["data"] !== null) {
@@ -268,16 +551,18 @@ function normalizeCompanyResource(data) {
268
551
 
269
552
  // src/endpoints/CompanyEndpoint.ts
270
553
  var CompanyEndpoint = class {
271
- constructor(baseUrl, apiKey, tokenStorage, httpClient) {
554
+ constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
272
555
  this.baseUrl = baseUrl;
273
556
  this.apiKey = apiKey;
274
557
  this.tokenStorage = tokenStorage;
275
558
  this.httpClient = httpClient;
559
+ this.retryPolicy = retryPolicy;
276
560
  }
277
561
  baseUrl;
278
562
  apiKey;
279
563
  tokenStorage;
280
564
  httpClient;
565
+ retryPolicy;
281
566
  async get() {
282
567
  const headers = {
283
568
  "Content-Type": "application/json",
@@ -287,25 +572,33 @@ var CompanyEndpoint = class {
287
572
  if (token) {
288
573
  headers["Authorization"] = `Bearer ${token.accessToken}`;
289
574
  }
290
- const response = await this.httpClient.request("GET", `${this.baseUrl}/company`, { headers });
291
- const responseText = await response.text();
292
- if (!response.ok) {
293
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
294
- }
295
- let parsed;
296
- try {
297
- parsed = JSON.parse(responseText);
298
- } catch {
299
- throw new HttpException("Invalid JSON response", 0, responseText);
300
- }
301
- if (typeof parsed !== "object" || parsed === null) {
302
- throw new HttpException("Unexpected response format", 0, responseText);
303
- }
304
- const obj = parsed;
305
- if (obj["data"] !== void 0 && typeof obj["data"] === "object" && obj["data"] !== null) {
306
- return normalizeCompanyResource(obj["data"]);
307
- }
308
- return normalizeCompanyResource(obj);
575
+ return withRetries(this.retryPolicy, "company request", async () => {
576
+ const response = await this.httpClient.request("GET", `${this.baseUrl}/company`, { headers });
577
+ const responseText = await response.text();
578
+ if (!response.ok) {
579
+ throw new HttpException(
580
+ describeApiError(responseText, response.status),
581
+ response.status,
582
+ responseText,
583
+ {},
584
+ response.headers.get("retry-after")
585
+ );
586
+ }
587
+ let parsed;
588
+ try {
589
+ parsed = JSON.parse(responseText);
590
+ } catch {
591
+ throw new HttpException("Invalid JSON response", response.status, responseText);
592
+ }
593
+ if (typeof parsed !== "object" || parsed === null) {
594
+ throw new HttpException("Unexpected response format", response.status, responseText);
595
+ }
596
+ const obj = parsed;
597
+ if (obj["data"] !== void 0 && typeof obj["data"] === "object" && obj["data"] !== null) {
598
+ return normalizeCompanyResource(obj["data"]);
599
+ }
600
+ return normalizeCompanyResource(obj);
601
+ });
309
602
  }
310
603
  };
311
604
 
@@ -1018,16 +1311,18 @@ var TRANSACTION_TYPES = [
1018
1311
  "crossborder_inbound"
1019
1312
  ];
1020
1313
  var EReportingEndpoint = class {
1021
- constructor(baseUrl, apiKey, tokenStorage, httpClient) {
1314
+ constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
1022
1315
  this.baseUrl = baseUrl;
1023
1316
  this.apiKey = apiKey;
1024
1317
  this.tokenStorage = tokenStorage;
1025
1318
  this.httpClient = httpClient;
1319
+ this.retryPolicy = retryPolicy;
1026
1320
  }
1027
1321
  baseUrl;
1028
1322
  apiKey;
1029
1323
  tokenStorage;
1030
1324
  httpClient;
1325
+ retryPolicy;
1031
1326
  // ---------------------------------------------------------------------
1032
1327
  // Enrollments
1033
1328
  // ---------------------------------------------------------------------
@@ -1421,7 +1716,8 @@ var EReportingEndpoint = class {
1421
1716
  async sendRequest(method, url, body) {
1422
1717
  const options = { headers: this.buildHeaders() };
1423
1718
  if (body) options.body = JSON.stringify(body);
1424
- return this.httpClient.request(method, url, options);
1719
+ const send = () => this.httpClient.request(method, url, options);
1720
+ return method === "GET" ? withResponseRetries(this.retryPolicy, "e-reporting request", send) : send();
1425
1721
  }
1426
1722
  /** Multipart upload: Content-Type is left to fetch so the boundary is set correctly. */
1427
1723
  async sendMultipartRequest(method, url, form) {
@@ -1434,16 +1730,22 @@ var EReportingEndpoint = class {
1434
1730
  throw this.buildValidationException(responseText);
1435
1731
  }
1436
1732
  if (!response.ok) {
1437
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
1733
+ throw new HttpException(
1734
+ describeApiError(responseText, response.status),
1735
+ response.status,
1736
+ responseText,
1737
+ {},
1738
+ response.headers.get("retry-after")
1739
+ );
1438
1740
  }
1439
1741
  let parsed;
1440
1742
  try {
1441
1743
  parsed = JSON.parse(responseText);
1442
1744
  } catch {
1443
- throw new HttpException("Invalid JSON response", 0, responseText);
1745
+ throw new HttpException("Invalid JSON response", response.status, responseText);
1444
1746
  }
1445
1747
  if (typeof parsed !== "object" || parsed === null) {
1446
- throw new HttpException("Unexpected response format", 0, responseText);
1748
+ throw new HttpException("Unexpected response format", response.status, responseText);
1447
1749
  }
1448
1750
  const obj = parsed;
1449
1751
  if (obj["data"] !== void 0 && typeof obj["data"] === "object" && obj["data"] !== null) {
@@ -1461,7 +1763,13 @@ var EReportingEndpoint = class {
1461
1763
  throw this.buildValidationException(responseText);
1462
1764
  }
1463
1765
  if (!response.ok) {
1464
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
1766
+ throw new HttpException(
1767
+ describeApiError(responseText, response.status),
1768
+ response.status,
1769
+ responseText,
1770
+ {},
1771
+ response.headers.get("retry-after")
1772
+ );
1465
1773
  }
1466
1774
  }
1467
1775
  /**
@@ -1505,6 +1813,29 @@ var EReportingEndpoint = class {
1505
1813
  }
1506
1814
  };
1507
1815
 
1816
+ // src/enums/SmartEnrichmentMode.ts
1817
+ var SmartEnrichmentMode = {
1818
+ DEFAULT: "default",
1819
+ COMPLEX: "complex"
1820
+ };
1821
+ var VALUES5 = Object.values(SmartEnrichmentMode);
1822
+ function toSmartEnrichmentMode(value) {
1823
+ if (typeof value === "string") {
1824
+ const normalized = value.trim().toLowerCase();
1825
+ if (VALUES5.includes(normalized)) {
1826
+ return normalized;
1827
+ }
1828
+ }
1829
+ return void 0;
1830
+ }
1831
+ var DESCRIPTIONS5 = {
1832
+ [SmartEnrichmentMode.DEFAULT]: "One provider searches; a second is consulted only if it finds nothing.",
1833
+ [SmartEnrichmentMode.COMPLEX]: "Two providers search independently and are cross-checked against the tax authority. Costs more."
1834
+ };
1835
+ function describeSmartEnrichmentMode(mode) {
1836
+ return DESCRIPTIONS5[mode];
1837
+ }
1838
+
1508
1839
  // src/enums/SmartEnrichmentStatus.ts
1509
1840
  var SmartEnrichmentStatus = {
1510
1841
  FOUND: "found",
@@ -1516,17 +1847,17 @@ var SmartEnrichmentStatus = {
1516
1847
  FAILED: "failed",
1517
1848
  UNKNOWN: "unknown"
1518
1849
  };
1519
- var VALUES5 = Object.values(SmartEnrichmentStatus);
1850
+ var VALUES6 = Object.values(SmartEnrichmentStatus);
1520
1851
  function toSmartEnrichmentStatus(value) {
1521
1852
  if (typeof value === "string") {
1522
1853
  const normalized = value.trim().toLowerCase();
1523
- if (VALUES5.includes(normalized)) {
1854
+ if (VALUES6.includes(normalized)) {
1524
1855
  return normalized;
1525
1856
  }
1526
1857
  }
1527
1858
  return SmartEnrichmentStatus.UNKNOWN;
1528
1859
  }
1529
- var DESCRIPTIONS5 = {
1860
+ var DESCRIPTIONS6 = {
1530
1861
  [SmartEnrichmentStatus.FOUND]: "A VAT number was resolved and confirmed.",
1531
1862
  [SmartEnrichmentStatus.NO_VAT_EXISTS]: "The company was identified but has no VAT number.",
1532
1863
  [SmartEnrichmentStatus.NOT_FOUND]: "No sufficiently-confident match could be resolved.",
@@ -1537,12 +1868,12 @@ var DESCRIPTIONS5 = {
1537
1868
  [SmartEnrichmentStatus.UNKNOWN]: "Unknown status."
1538
1869
  };
1539
1870
  function describeSmartEnrichmentStatus(status) {
1540
- return DESCRIPTIONS5[status];
1871
+ return DESCRIPTIONS6[status];
1541
1872
  }
1542
1873
 
1543
1874
  // src/dto/SmartEnrichmentResource.ts
1544
1875
  var SmartEnrichmentResource = class _SmartEnrichmentResource {
1545
- constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source) {
1876
+ constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source, mode = void 0, providerVerdicts = [], addressQuality = void 0) {
1546
1877
  this.status = status;
1547
1878
  this.vatNumber = vatNumber;
1548
1879
  this.vatType = vatType;
@@ -1551,6 +1882,9 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
1551
1882
  this.matchedAddress = matchedAddress;
1552
1883
  this.country = country;
1553
1884
  this.source = source;
1885
+ this.mode = mode;
1886
+ this.providerVerdicts = providerVerdicts;
1887
+ this.addressQuality = addressQuality;
1554
1888
  }
1555
1889
  status;
1556
1890
  vatNumber;
@@ -1560,6 +1894,9 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
1560
1894
  matchedAddress;
1561
1895
  country;
1562
1896
  source;
1897
+ mode;
1898
+ providerVerdicts;
1899
+ addressQuality;
1563
1900
  static fromArray(data) {
1564
1901
  const str = (key) => {
1565
1902
  const v = data[key];
@@ -1569,6 +1906,8 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
1569
1906
  const v = data[key];
1570
1907
  return typeof v === "number" ? v : void 0;
1571
1908
  };
1909
+ const verdicts = data["providerVerdicts"];
1910
+ const quality = data["addressQuality"];
1572
1911
  return new _SmartEnrichmentResource(
1573
1912
  toSmartEnrichmentStatus(data["status"]),
1574
1913
  str("vatNumber"),
@@ -1577,7 +1916,10 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
1577
1916
  str("matchedCompanyName"),
1578
1917
  str("matchedAddress"),
1579
1918
  str("country"),
1580
- str("source")
1919
+ str("source"),
1920
+ toSmartEnrichmentMode(data["mode"]),
1921
+ Array.isArray(verdicts) ? verdicts.filter((v) => typeof v === "object" && v !== null) : [],
1922
+ typeof quality === "object" && quality !== null ? quality : void 0
1581
1923
  );
1582
1924
  }
1583
1925
  toArray() {
@@ -1589,7 +1931,10 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
1589
1931
  matchedCompanyName: this.matchedCompanyName ?? null,
1590
1932
  matchedAddress: this.matchedAddress ?? null,
1591
1933
  country: this.country ?? null,
1592
- source: this.source ?? null
1934
+ source: this.source ?? null,
1935
+ mode: this.mode ?? null,
1936
+ providerVerdicts: this.providerVerdicts,
1937
+ addressQuality: this.addressQuality ?? null
1593
1938
  };
1594
1939
  }
1595
1940
  };
@@ -1817,16 +2162,18 @@ var STATISTICS_INTERVALS = ["day", "week", "month"];
1817
2162
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
1818
2163
  var DEFAULT_POLL_TIMEOUT_MS = 12e4;
1819
2164
  var SmartEnrichmentEndpoint = class {
1820
- constructor(baseUrl, apiKey, tokenStorage, httpClient) {
2165
+ constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
1821
2166
  this.baseUrl = baseUrl;
1822
2167
  this.apiKey = apiKey;
1823
2168
  this.tokenStorage = tokenStorage;
1824
2169
  this.httpClient = httpClient;
2170
+ this.retryPolicy = retryPolicy;
1825
2171
  }
1826
2172
  baseUrl;
1827
2173
  apiKey;
1828
2174
  tokenStorage;
1829
2175
  httpClient;
2176
+ retryPolicy;
1830
2177
  /**
1831
2178
  * Single reverse lookup. Returns a confident result synchronously, or a `processing`
1832
2179
  * job (poll with get(job.jobId) or waitForCompletion(job.jobId)) when deeper resolution
@@ -1841,6 +2188,7 @@ var SmartEnrichmentEndpoint = class {
1841
2188
  if (input.street !== void 0) body["street"] = input.street;
1842
2189
  if (input.postalCode !== void 0) body["postalCode"] = input.postalCode;
1843
2190
  if (input.city !== void 0) body["city"] = input.city;
2191
+ if (input.mode !== void 0) body["mode"] = input.mode;
1844
2192
  const response = await this.sendRequest("POST", `${this.baseUrl}/smart-enrichment`, body);
1845
2193
  const data = await this.parseJsonResponse(response, [200, 202]);
1846
2194
  return SmartEnrichmentJob.fromArray(data);
@@ -1848,13 +2196,18 @@ var SmartEnrichmentEndpoint = class {
1848
2196
  /**
1849
2197
  * Bulk batch — always async. Returns a `processing` job; results arrive via the
1850
2198
  * `enrichment.completed` webhook and are retrievable via get(job.jobId).
2199
+ *
2200
+ * @param mode Search depth for every row in the batch. A row carrying its own `mode` overrides
2201
+ * it, so a caller can pay for `complex` on just the rows that need it.
1851
2202
  */
1852
- async bulkLookup(items) {
2203
+ async bulkLookup(items, mode) {
1853
2204
  if (items.length === 0) {
1854
2205
  throw new TaxoraException("bulkLookup requires at least one item.");
1855
2206
  }
1856
2207
  items.forEach((item, index) => this.validateInput(item, `items[${index}]`));
1857
- const response = await this.sendRequest("POST", `${this.baseUrl}/smart-enrichment/bulk`, { items });
2208
+ const body = { items };
2209
+ if (mode !== void 0) body["mode"] = mode;
2210
+ const response = await this.sendRequest("POST", `${this.baseUrl}/smart-enrichment/bulk`, body);
1858
2211
  const data = await this.parseJsonResponse(response, [200, 202]);
1859
2212
  return SmartEnrichmentJob.fromArray(data);
1860
2213
  }
@@ -1996,24 +2349,31 @@ var SmartEnrichmentEndpoint = class {
1996
2349
  async sendRequest(method, url, body) {
1997
2350
  const options = { headers: this.buildHeaders() };
1998
2351
  if (body) options.body = JSON.stringify(body);
1999
- return this.httpClient.request(method, url, options);
2352
+ const send = () => this.httpClient.request(method, url, options);
2353
+ return method === "GET" ? withResponseRetries(this.retryPolicy, "Smart Enrichment request", send) : send();
2000
2354
  }
2001
2355
  async parseJsonResponse(response, acceptedStatuses = [200]) {
2002
2356
  const responseText = await response.text();
2003
2357
  if (response.status === 422) {
2004
- throw new ValidationException("Validation failed", this.parseValidationErrors(responseText));
2358
+ throw new ValidationException(jsonErrorMessage(responseText) ?? "Validation failed", this.parseValidationErrors(responseText));
2005
2359
  }
2006
2360
  if (!response.ok && !acceptedStatuses.includes(response.status)) {
2007
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
2361
+ throw new HttpException(
2362
+ describeApiError(responseText, response.status),
2363
+ response.status,
2364
+ responseText,
2365
+ {},
2366
+ response.headers.get("retry-after")
2367
+ );
2008
2368
  }
2009
2369
  let parsed;
2010
2370
  try {
2011
2371
  parsed = JSON.parse(responseText);
2012
2372
  } catch {
2013
- throw new HttpException("Invalid JSON response", 0, responseText);
2373
+ throw new HttpException("Invalid JSON response", response.status, responseText);
2014
2374
  }
2015
2375
  if (typeof parsed !== "object" || parsed === null) {
2016
- throw new HttpException("Unexpected response format", 0, responseText);
2376
+ throw new HttpException("Unexpected response format", response.status, responseText);
2017
2377
  }
2018
2378
  const obj = parsed;
2019
2379
  if (obj["data"] !== void 0 && (typeof obj["data"] === "object" || Array.isArray(obj["data"]))) {
@@ -2029,19 +2389,25 @@ var SmartEnrichmentEndpoint = class {
2029
2389
  async parseRawJson(response) {
2030
2390
  const responseText = await response.text();
2031
2391
  if (response.status === 422) {
2032
- throw new ValidationException("Validation failed", this.parseValidationErrors(responseText));
2392
+ throw new ValidationException(jsonErrorMessage(responseText) ?? "Validation failed", this.parseValidationErrors(responseText));
2033
2393
  }
2034
2394
  if (!response.ok) {
2035
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
2395
+ throw new HttpException(
2396
+ describeApiError(responseText, response.status),
2397
+ response.status,
2398
+ responseText,
2399
+ {},
2400
+ response.headers.get("retry-after")
2401
+ );
2036
2402
  }
2037
2403
  let parsed;
2038
2404
  try {
2039
2405
  parsed = JSON.parse(responseText);
2040
2406
  } catch {
2041
- throw new HttpException("Invalid JSON response", 0, responseText);
2407
+ throw new HttpException("Invalid JSON response", response.status, responseText);
2042
2408
  }
2043
2409
  if (typeof parsed !== "object" || parsed === null) {
2044
- throw new HttpException("Unexpected response format", 0, responseText);
2410
+ throw new HttpException("Unexpected response format", response.status, responseText);
2045
2411
  }
2046
2412
  return parsed;
2047
2413
  }
@@ -2052,10 +2418,16 @@ var SmartEnrichmentEndpoint = class {
2052
2418
  async parseCsvResponse(response) {
2053
2419
  const responseText = await response.text();
2054
2420
  if (response.status === 422) {
2055
- throw new ValidationException("Validation failed", this.parseValidationErrors(responseText));
2421
+ throw new ValidationException(jsonErrorMessage(responseText) ?? "Validation failed", this.parseValidationErrors(responseText));
2056
2422
  }
2057
2423
  if (!response.ok) {
2058
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
2424
+ throw new HttpException(
2425
+ describeApiError(responseText, response.status),
2426
+ response.status,
2427
+ responseText,
2428
+ {},
2429
+ response.headers.get("retry-after")
2430
+ );
2059
2431
  }
2060
2432
  return responseText;
2061
2433
  }
@@ -2092,14 +2464,14 @@ var VatState = {
2092
2464
  function getFailedVatStates() {
2093
2465
  return [VatState.INVALID, VatState.FRAUD];
2094
2466
  }
2095
- var DESCRIPTIONS6 = {
2467
+ var DESCRIPTIONS7 = {
2096
2468
  [VatState.VALID]: "The VAT number is valid and active.",
2097
2469
  [VatState.INVALID]: "The VAT number is invalid or not registered.",
2098
2470
  [VatState.FRAUD]: "The VAT number has been flagged as potentially fraudulent.",
2099
2471
  [VatState.UNKNOWN]: "The VAT number state could not be determined."
2100
2472
  };
2101
2473
  function describeVatState(state) {
2102
- return DESCRIPTIONS6[state];
2474
+ return DESCRIPTIONS7[state];
2103
2475
  }
2104
2476
 
2105
2477
  // src/dto/CompanyAddress.ts
@@ -2564,16 +2936,18 @@ var VatValidationAddressInput = class _VatValidationAddressInput {
2564
2936
  // src/endpoints/VatEndpoint.ts
2565
2937
  var DATE_REGEX2 = /^\d{4}-\d{2}-\d{2}$/;
2566
2938
  var VatEndpoint = class {
2567
- constructor(baseUrl, apiKey, tokenStorage, httpClient) {
2939
+ constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
2568
2940
  this.baseUrl = baseUrl;
2569
2941
  this.apiKey = apiKey;
2570
2942
  this.tokenStorage = tokenStorage;
2571
2943
  this.httpClient = httpClient;
2944
+ this.retryPolicy = retryPolicy;
2572
2945
  }
2573
2946
  baseUrl;
2574
2947
  apiKey;
2575
2948
  tokenStorage;
2576
2949
  httpClient;
2950
+ retryPolicy;
2577
2951
  async validate(vatUid, companyName, provider, addressInput) {
2578
2952
  const body = { vat_uid: vatUid };
2579
2953
  if (companyName) body["company_name"] = companyName;
@@ -2581,44 +2955,44 @@ var VatEndpoint = class {
2581
2955
  if (addressInput) {
2582
2956
  body["address_input"] = addressInput instanceof VatValidationAddressInput ? addressInput.toArray() : addressInput;
2583
2957
  }
2584
- return this.validateWithGatewayRetry(body, 2);
2585
- }
2586
- async validateWithGatewayRetry(body, attemptsLeft) {
2587
- const response = await this.sendRequest("POST", `${this.baseUrl}/vat/validate`, body);
2588
- if (response.status === 504) {
2589
- if (attemptsLeft <= 1) {
2590
- const text = await response.text();
2591
- throw new HttpException("VAT validation timed out after multiple attempts", 504, text);
2592
- }
2593
- return this.validateWithGatewayRetry(body, attemptsLeft - 1);
2594
- }
2595
- const data = await this.parseJsonResponse(response);
2596
- return VatResource.fromArray(data);
2958
+ return withRetries(this.retryPolicy, "VAT validation", async () => {
2959
+ const response = await this.sendRequest("POST", `${this.baseUrl}/vat/validate`, body);
2960
+ const data = await this.parseJsonResponse(response);
2961
+ return VatResource.fromArray(data);
2962
+ });
2597
2963
  }
2598
2964
  async validateMultiple(vatUids, companyNames, provider) {
2599
2965
  const body = { vat_uids: vatUids };
2600
2966
  if (companyNames) body["company_names"] = companyNames;
2601
2967
  if (provider) body["source"] = provider;
2602
- const response = await this.sendRequest("POST", `${this.baseUrl}/vat/validate/multiple`, body);
2603
- const data = await this.parseJsonResponse(response);
2604
- return VatCollection.fromResponse(data);
2968
+ return withRetries(this.retryPolicy, "VAT validation", async () => {
2969
+ const response = await this.sendRequest("POST", `${this.baseUrl}/vat/validate/multiple`, body);
2970
+ const data = await this.parseJsonResponse(response);
2971
+ return VatCollection.fromResponse(data);
2972
+ });
2605
2973
  }
2606
2974
  async validateSchema(vatUid) {
2607
2975
  const body = { vat_uid: vatUid };
2608
- const response = await this.sendRequest("POST", `${this.baseUrl}/vat/validate/schema`, body);
2609
- return this.parseJsonResponse(response);
2976
+ return withRetries(this.retryPolicy, "VAT schema check", async () => {
2977
+ const response = await this.sendRequest("POST", `${this.baseUrl}/vat/validate/schema`, body);
2978
+ return this.parseJsonResponse(response);
2979
+ });
2610
2980
  }
2611
2981
  async state(vatUid) {
2612
- const response = await this.sendRequest("GET", `${this.baseUrl}/vat/state/${encodeURIComponent(vatUid)}`);
2613
- const data = await this.parseJsonResponse(response);
2614
- return VatResource.fromArray(data);
2982
+ return withRetries(this.retryPolicy, "VAT state lookup", async () => {
2983
+ const response = await this.sendRequest("GET", `${this.baseUrl}/vat/state/${encodeURIComponent(vatUid)}`);
2984
+ const data = await this.parseJsonResponse(response);
2985
+ return VatResource.fromArray(data);
2986
+ });
2615
2987
  }
2616
2988
  async history(vatUid) {
2617
2989
  let url = `${this.baseUrl}/vat/history`;
2618
2990
  if (vatUid) url += `?vat_uid=${encodeURIComponent(vatUid)}`;
2619
- const response = await this.sendRequest("GET", url);
2620
- const data = await this.parseJsonResponse(response);
2621
- return VatCollection.fromResponse(data);
2991
+ return withRetries(this.retryPolicy, "VAT history request", async () => {
2992
+ const response = await this.sendRequest("GET", url);
2993
+ const data = await this.parseJsonResponse(response);
2994
+ return VatCollection.fromResponse(data);
2995
+ });
2622
2996
  }
2623
2997
  async search(term, perPage) {
2624
2998
  const params = new URLSearchParams();
@@ -2626,16 +3000,20 @@ var VatEndpoint = class {
2626
3000
  if (perPage !== void 0) params.set("per_page", String(perPage));
2627
3001
  const queryString = params.toString();
2628
3002
  const url = `${this.baseUrl}/vat/search${queryString ? `?${queryString}` : ""}`;
2629
- const response = await this.sendRequest("GET", url);
2630
- const data = await this.parseJsonResponse(response);
2631
- return VatCollection.fromResponse(data);
3003
+ return withRetries(this.retryPolicy, "VAT search", async () => {
3004
+ const response = await this.sendRequest("GET", url);
3005
+ const data = await this.parseJsonResponse(response);
3006
+ return VatCollection.fromResponse(data);
3007
+ });
2632
3008
  }
2633
3009
  async certificate(uuid, lang) {
2634
3010
  let url = `${this.baseUrl}/vat/certificate/${encodeURIComponent(uuid)}`;
2635
3011
  if (lang) url += `?lang=${lang}`;
2636
- const response = await this.sendBinaryRequest("GET", url);
2637
- const buffer = await response.arrayBuffer();
2638
- return new Uint8Array(buffer);
3012
+ return withRetries(this.retryPolicy, "VAT certificate download", async () => {
3013
+ const response = await this.sendBinaryRequest("GET", url);
3014
+ const buffer = await response.arrayBuffer();
3015
+ return new Uint8Array(buffer);
3016
+ });
2639
3017
  }
2640
3018
  async certificatesBulkExport(fromDate, toDate, countries, lang) {
2641
3019
  return this.exportRequest(`${this.baseUrl}/vat/certificates/bulk-export`, fromDate, toDate, countries, lang);
@@ -2659,9 +3037,11 @@ var VatEndpoint = class {
2659
3037
  }
2660
3038
  async downloadBulkExport(exportId) {
2661
3039
  const url = `${this.baseUrl}/vat/certificates/bulk-export/${encodeURIComponent(exportId)}/download`;
2662
- const response = await this.sendBinaryRequest("GET", url);
2663
- const buffer = await response.arrayBuffer();
2664
- return new Uint8Array(buffer);
3040
+ return withRetries(this.retryPolicy, "VAT export download", async () => {
3041
+ const response = await this.sendBinaryRequest("GET", url);
3042
+ const buffer = await response.arrayBuffer();
3043
+ return new Uint8Array(buffer);
3044
+ });
2665
3045
  }
2666
3046
  buildHeaders() {
2667
3047
  const headers = {
@@ -2685,7 +3065,13 @@ var VatEndpoint = class {
2685
3065
  const response = await this.httpClient.request(method, url, { headers });
2686
3066
  if (!response.ok) {
2687
3067
  const text = await response.text();
2688
- throw new HttpException(`HTTP error ${response.status}`, response.status, text);
3068
+ throw new HttpException(
3069
+ describeApiError(text, response.status),
3070
+ response.status,
3071
+ text,
3072
+ {},
3073
+ response.headers.get("retry-after")
3074
+ );
2689
3075
  }
2690
3076
  return response;
2691
3077
  }
@@ -2700,19 +3086,25 @@ var VatEndpoint = class {
2700
3086
  }
2701
3087
  } catch {
2702
3088
  }
2703
- throw new ValidationException("Validation failed", errors);
3089
+ throw new ValidationException(jsonErrorMessage(responseText) ?? "Validation failed", errors);
2704
3090
  }
2705
3091
  if (!response.ok && !acceptedStatuses.includes(response.status)) {
2706
- throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
3092
+ throw new HttpException(
3093
+ describeApiError(responseText, response.status),
3094
+ response.status,
3095
+ responseText,
3096
+ {},
3097
+ response.headers.get("retry-after")
3098
+ );
2707
3099
  }
2708
3100
  let parsed;
2709
3101
  try {
2710
3102
  parsed = JSON.parse(responseText);
2711
3103
  } catch {
2712
- throw new HttpException("Invalid JSON response", 0, responseText);
3104
+ throw new HttpException("Invalid JSON response", response.status, responseText);
2713
3105
  }
2714
3106
  if (typeof parsed !== "object" || parsed === null) {
2715
- throw new HttpException("Unexpected response format", 0, responseText);
3107
+ throw new HttpException("Unexpected response format", response.status, responseText);
2716
3108
  }
2717
3109
  const obj = parsed;
2718
3110
  if (obj["data"] !== void 0 && (typeof obj["data"] === "object" || Array.isArray(obj["data"]))) {
@@ -2811,7 +3203,7 @@ var AuthRetryHttpClient = class {
2811
3203
  };
2812
3204
 
2813
3205
  // src/version.ts
2814
- var SDK_VERSION = "1.1.0";
3206
+ var SDK_VERSION = "1.2.0";
2815
3207
 
2816
3208
  // src/http/SdkVersionHttpClient.ts
2817
3209
  var SDK_VERSION_HEADER = "X-Taxora-SDK-Version";
@@ -2843,14 +3235,15 @@ var TaxoraClient = class {
2843
3235
  const environment = options.environment ?? Environment.SANDBOX;
2844
3236
  const tokenStorage = options.tokenStorage ?? new InMemoryTokenStorage();
2845
3237
  const httpClient = options.httpClient ?? new FetchHttpClient();
3238
+ const retryPolicy = options.retryPolicy ?? new RetryPolicy();
2846
3239
  const versionedClient = new SdkVersionHttpClient(httpClient);
2847
3240
  this.baseUrl = getBaseUrl(environment);
2848
- this.auth = new AuthEndpoint(this.baseUrl, options.apiKey, tokenStorage, versionedClient);
3241
+ this.auth = new AuthEndpoint(this.baseUrl, options.apiKey, tokenStorage, versionedClient, retryPolicy);
2849
3242
  const retryClient = new AuthRetryHttpClient(versionedClient, tokenStorage, () => this.auth.refresh());
2850
- this.vat = new VatEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
2851
- this.company = new CompanyEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
2852
- this.smartEnrichment = new SmartEnrichmentEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
2853
- this.eReporting = new EReportingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
3243
+ this.vat = new VatEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
3244
+ this.company = new CompanyEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
3245
+ this.smartEnrichment = new SmartEnrichmentEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
3246
+ this.eReporting = new EReportingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
2854
3247
  }
2855
3248
  };
2856
3249
 
@@ -2899,6 +3292,7 @@ var Language = {
2899
3292
  LoginIdentifier,
2900
3293
  ProviderDocument,
2901
3294
  ProviderDocumentLine,
3295
+ RetryPolicy,
2902
3296
  RevenueStatistics,
2903
3297
  ScoreBreakdown,
2904
3298
  SireneLookupResult,
@@ -2906,6 +3300,7 @@ var Language = {
2906
3300
  SmartEnrichmentHistoryPage,
2907
3301
  SmartEnrichmentHistoryRow,
2908
3302
  SmartEnrichmentJob,
3303
+ SmartEnrichmentMode,
2909
3304
  SmartEnrichmentResource,
2910
3305
  SmartEnrichmentStatistics,
2911
3306
  SmartEnrichmentStatus,
@@ -2921,10 +3316,12 @@ var Language = {
2921
3316
  VatResource,
2922
3317
  VatState,
2923
3318
  VatValidationAddressInput,
3319
+ describeApiError,
2924
3320
  describeComplianceEnrollmentStatus,
2925
3321
  describeComplianceTaxReportState,
2926
3322
  describeComplianceTransactionState,
2927
3323
  describeComplianceTransactionType,
3324
+ describeSmartEnrichmentMode,
2928
3325
  describeSmartEnrichmentStatus,
2929
3326
  describeVatState,
2930
3327
  getBaseUrl,
@@ -2933,6 +3330,7 @@ var Language = {
2933
3330
  toComplianceTaxReportState,
2934
3331
  toComplianceTransactionState,
2935
3332
  toComplianceTransactionType,
3333
+ toSmartEnrichmentMode,
2936
3334
  toSmartEnrichmentStatus
2937
3335
  });
2938
3336
  //# sourceMappingURL=index.cjs.map