@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/README.md +91 -1
- package/dist/index.cjs +524 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +188 -10
- package/dist/index.d.ts +188 -10
- package/dist/index.js +519 -126
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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",
|
|
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",
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
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(
|
|
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",
|
|
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",
|
|
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(
|
|
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
|
|
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 (
|
|
1854
|
+
if (VALUES6.includes(normalized)) {
|
|
1524
1855
|
return normalized;
|
|
1525
1856
|
}
|
|
1526
1857
|
}
|
|
1527
1858
|
return SmartEnrichmentStatus.UNKNOWN;
|
|
1528
1859
|
}
|
|
1529
|
-
var
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
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",
|
|
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",
|
|
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(
|
|
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",
|
|
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",
|
|
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(
|
|
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
|
|
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
|
|
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.
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
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
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
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
|
-
|
|
2609
|
-
|
|
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
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
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
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
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
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
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
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
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
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
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(
|
|
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(
|
|
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",
|
|
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",
|
|
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.
|
|
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
|