@open-nav/client 0.1.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.
@@ -0,0 +1,155 @@
1
+ import { QUERY_PAGE_SIZE, decodeInvoiceData, serializeDocument, } from '@open-nav/core';
2
+ /**
3
+ * Bulk retrieval of invoices from NAV.
4
+ *
5
+ * Two things make this more than a loop. NAV caps a digest query at **35
6
+ * days** — `BAD_QUERY_PARAM_RANGE_EXCEEDED`, "Date interval defined by the
7
+ * query parameters must not exceed 35 days" — so any useful range has to be
8
+ * split. And an inbound invoice must be fetched with the supplier's tax
9
+ * number, which is only knowable from the digest entry that named it.
10
+ */
11
+ /** Longest interval NAV accepts in one digest query. */
12
+ export const MAX_QUERY_DAYS = 35;
13
+ /**
14
+ * Split a date range into windows NAV will accept.
15
+ *
16
+ * Inclusive at both ends, so a 35 day window spans `dateFrom` to
17
+ * `dateFrom + 34 days`: NAV compares the two dates given, and 35 days apart
18
+ * is already over the line.
19
+ */
20
+ export function chunkDateRange(dateFrom, dateTo, maxDays = MAX_QUERY_DAYS) {
21
+ const start = parseDate(dateFrom, 'dateFrom');
22
+ const end = parseDate(dateTo, 'dateTo');
23
+ if (start > end) {
24
+ throw new RangeError(`dateFrom ${dateFrom} is after dateTo ${dateTo}`);
25
+ }
26
+ const windows = [];
27
+ const dayMs = 86_400_000;
28
+ for (let cursor = start; cursor <= end; cursor += maxDays * dayMs) {
29
+ const windowEnd = Math.min(cursor + (maxDays - 1) * dayMs, end);
30
+ windows.push({ dateFrom: formatDate(cursor), dateTo: formatDate(windowEnd) });
31
+ }
32
+ return windows;
33
+ }
34
+ function parseDate(value, field) {
35
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
36
+ throw new RangeError(`${field} must be yyyy-mm-dd, got ${JSON.stringify(value)}`);
37
+ }
38
+ const timestamp = Date.parse(`${value}T00:00:00Z`);
39
+ if (Number.isNaN(timestamp))
40
+ throw new RangeError(`${field} is not a real date: ${value}`);
41
+ return timestamp;
42
+ }
43
+ function formatDate(timestamp) {
44
+ return new Date(timestamp).toISOString().slice(0, 10);
45
+ }
46
+ /**
47
+ * Walk every digest entry in a date range, across windows and pages.
48
+ *
49
+ * A digest is a summary. It is enough to decide what to fetch, and cheap:
50
+ * one request per hundred invoices.
51
+ */
52
+ export async function* iterateInvoiceDigests(client, options) {
53
+ const direction = options.direction ?? 'INBOUND';
54
+ const windows = chunkDateRange(options.dateFrom, options.dateTo);
55
+ const pause = pauser(options);
56
+ let seen = 0;
57
+ for (const [windowIndex, window] of windows.entries()) {
58
+ let page = 1;
59
+ let availablePage = 1;
60
+ do {
61
+ if (seen > 0 || page > 1)
62
+ await pause();
63
+ const response = await client.queryInvoiceDigest({
64
+ page,
65
+ invoiceDirection: direction,
66
+ invoiceQueryParams: {
67
+ mandatoryQueryParams: {
68
+ invoiceIssueDate: { dateFrom: window.dateFrom, dateTo: window.dateTo },
69
+ },
70
+ },
71
+ });
72
+ const result = response.invoiceDigestResult;
73
+ availablePage = result.availablePage;
74
+ const entries = result.invoiceDigest ?? [];
75
+ for (const digest of entries) {
76
+ seen += 1;
77
+ options.onProgress?.({
78
+ window,
79
+ windowIndex,
80
+ windowCount: windows.length,
81
+ seen,
82
+ fetched: 0,
83
+ });
84
+ yield { digest, window };
85
+ }
86
+ // NAV reports 0 available pages for an empty result.
87
+ if (entries.length < QUERY_PAGE_SIZE)
88
+ break;
89
+ page += 1;
90
+ } while (page <= availablePage);
91
+ }
92
+ }
93
+ /**
94
+ * Walk every invoice in a date range, fetching each in full.
95
+ *
96
+ * One request per invoice, so this is the expensive one; pace it with
97
+ * `delayMs` and consider whether the digest alone answers your question.
98
+ */
99
+ export async function* iterateInvoices(client, options) {
100
+ const direction = options.direction ?? 'INBOUND';
101
+ const pause = pauser(options);
102
+ let fetched = 0;
103
+ let seen = 0;
104
+ for await (const { digest, window } of iterateInvoiceDigests(client, {
105
+ ...options,
106
+ // Progress is reported here instead, where the counts are complete.
107
+ ...(options.onProgress ? { onProgress: undefined } : {}),
108
+ })) {
109
+ seen += 1;
110
+ await pause();
111
+ const response = await client.queryInvoiceData({
112
+ invoiceNumberQuery: {
113
+ invoiceNumber: digest.invoiceNumber,
114
+ invoiceDirection: direction,
115
+ // Only meaningful when querying as the customer: NAV answers
116
+ // BAD_QUERY_PARAM_SUPPLIER_NOT_EXPECTED if it is sent otherwise.
117
+ ...(direction === 'INBOUND' ? { supplierTaxNumber: digest.supplierTaxNumber } : {}),
118
+ ...(digest.batchIndex !== undefined ? { batchIndex: digest.batchIndex } : {}),
119
+ },
120
+ });
121
+ const result = response.invoiceDataResult;
122
+ if (!result)
123
+ continue; // Listed in the digest but no longer retrievable.
124
+ const invoice = decodeInvoiceData(result.invoiceData, {
125
+ compressed: result.compressedContentIndicator,
126
+ });
127
+ fetched += 1;
128
+ options.onProgress?.({
129
+ window,
130
+ windowIndex: 0,
131
+ windowCount: 0,
132
+ seen,
133
+ fetched,
134
+ });
135
+ yield {
136
+ digest,
137
+ invoice,
138
+ xml: serializeDocument('InvoiceData', invoice, { indent: ' ' }),
139
+ auditData: result.auditData,
140
+ };
141
+ }
142
+ }
143
+ /** Collect a whole range into memory. Convenient, but unbounded. */
144
+ export async function downloadInvoices(client, options) {
145
+ const collected = [];
146
+ for await (const entry of iterateInvoices(client, options))
147
+ collected.push(entry);
148
+ return collected;
149
+ }
150
+ function pauser(options) {
151
+ const delayMs = options.delayMs ?? 250;
152
+ const sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
153
+ return () => (delayMs > 0 ? sleep(delayMs) : Promise.resolve());
154
+ }
155
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from './client.js';
2
+ export * from './credentials.js';
3
+ export * from './transport.js';
4
+ export * from './transaction.js';
5
+ export * from './download.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './client.js';
2
+ export * from './credentials.js';
3
+ export * from './transport.js';
4
+ export * from './transaction.js';
5
+ export * from './download.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { type ProcessingResultType, type QueryTransactionStatusResponse } from '@open-nav/core';
2
+ import type { NavClient } from './client.js';
3
+ export interface WaitForTransactionOptions {
4
+ /** Give up after this long. Defaults to 60 000 ms. */
5
+ timeoutMs?: number;
6
+ /** First delay before polling, in ms. Defaults to 1 000. */
7
+ initialDelayMs?: number;
8
+ /** Cap on the delay between polls, in ms. Defaults to 8 000. */
9
+ maxDelayMs?: number;
10
+ /** Ask NAV to echo the submitted request. Defaults to false. */
11
+ returnOriginalRequest?: boolean;
12
+ /**
13
+ * Throw {@link NavInvoiceRejectedError} when any invoice is ABORTED.
14
+ * Defaults to false, so callers can inspect partial success themselves.
15
+ */
16
+ throwOnRejection?: boolean;
17
+ /** Called after every poll, for progress reporting. */
18
+ onPoll?: (results: ProcessingResultType[], attempt: number) => void;
19
+ /** Injectable sleep, for deterministic tests. */
20
+ sleep?: (ms: number) => Promise<void>;
21
+ }
22
+ export interface TransactionOutcome {
23
+ transactionId: string;
24
+ /** Per-invoice results, in batch index order. */
25
+ results: ProcessingResultType[];
26
+ /** Invoices NAV stored successfully. */
27
+ accepted: ProcessingResultType[];
28
+ /** Invoices NAV rejected outright. */
29
+ rejected: ProcessingResultType[];
30
+ /**
31
+ * Invoices stored with warnings.
32
+ *
33
+ * A `DONE` invoice can still carry `WARN` business messages. They do not
34
+ * block the report but usually mean something is wrong with the data, so
35
+ * they are surfaced separately rather than folded into `accepted` silently.
36
+ */
37
+ warnings: ProcessingResultType[];
38
+ /** The final status response, if any poll returned one. */
39
+ response?: QueryTransactionStatusResponse;
40
+ }
41
+ /**
42
+ * Poll a transaction until every invoice reaches a terminal state.
43
+ *
44
+ * `manageInvoice` returns a transaction id, not a verdict: NAV validates
45
+ * asynchronously and the outcome appears later, per invoice, split across
46
+ * technical and business validation messages. This resolves that into one
47
+ * result.
48
+ */
49
+ export declare function waitForTransaction(client: NavClient, transactionId: string, options?: WaitForTransactionOptions): Promise<TransactionOutcome>;
50
+ //# sourceMappingURL=transaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,8BAA8B,EACpC,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,WAAW,yBAAyB;IACxC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,uDAAuD;IACvD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,iDAAiD;IACjD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,wCAAwC;IACxC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,sCAAsC;IACtC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC;;;;;;OAMG;IACH,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,8BAA8B,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,kBAAkB,CAAC,CA4C7B"}
@@ -0,0 +1,67 @@
1
+ import { NavInvoiceRejectedError, NavTransportError, } from '@open-nav/core';
2
+ /** Statuses NAV will not move on from. */
3
+ const TERMINAL_STATUSES = new Set(['DONE', 'ABORTED']);
4
+ /**
5
+ * Poll a transaction until every invoice reaches a terminal state.
6
+ *
7
+ * `manageInvoice` returns a transaction id, not a verdict: NAV validates
8
+ * asynchronously and the outcome appears later, per invoice, split across
9
+ * technical and business validation messages. This resolves that into one
10
+ * result.
11
+ */
12
+ export async function waitForTransaction(client, transactionId, options = {}) {
13
+ const timeoutMs = options.timeoutMs ?? 60_000;
14
+ const maxDelayMs = options.maxDelayMs ?? 8_000;
15
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
16
+ let delayMs = options.initialDelayMs ?? 1_000;
17
+ const deadline = Date.now() + timeoutMs;
18
+ let attempt = 0;
19
+ let last;
20
+ for (;;) {
21
+ await sleep(Math.min(delayMs, Math.max(0, deadline - Date.now())));
22
+ attempt += 1;
23
+ const response = await client.queryTransactionStatus({
24
+ transactionId,
25
+ ...(options.returnOriginalRequest === undefined
26
+ ? {}
27
+ : { returnOriginalRequest: options.returnOriginalRequest }),
28
+ });
29
+ last = response;
30
+ const results = response.processingResults?.processingResult ?? [];
31
+ options.onPoll?.(results, attempt);
32
+ // An empty result set means NAV has accepted the batch but not yet
33
+ // recorded per-invoice outcomes; that is still in progress, not done.
34
+ if (results.length > 0 &&
35
+ results.every((result) => TERMINAL_STATUSES.has(result.invoiceStatus))) {
36
+ return summarise(transactionId, results, response, options);
37
+ }
38
+ if (Date.now() >= deadline) {
39
+ throw new NavTransportError(`Transaction ${transactionId} did not reach a terminal state within ${timeoutMs}ms ` +
40
+ `(last seen: ${describeStatuses(results)})`);
41
+ }
42
+ delayMs = Math.min(delayMs * 2, maxDelayMs);
43
+ }
44
+ }
45
+ function summarise(transactionId, results, response, options) {
46
+ const ordered = [...results].sort((a, b) => a.index - b.index);
47
+ const rejected = ordered.filter((result) => result.invoiceStatus === 'ABORTED');
48
+ const accepted = ordered.filter((result) => result.invoiceStatus === 'DONE');
49
+ const warnings = accepted.filter((result) => (result.businessValidationMessages ?? []).some((message) => message.validationResultCode === 'WARN'));
50
+ if (rejected.length > 0 && options.throwOnRejection) {
51
+ throw new NavInvoiceRejectedError(transactionId, rejected.map((result) => ({
52
+ index: result.index,
53
+ invoiceStatus: result.invoiceStatus,
54
+ messages: [
55
+ ...(result.technicalValidationMessages ?? []),
56
+ ...(result.businessValidationMessages ?? []),
57
+ ],
58
+ })));
59
+ }
60
+ return { transactionId, results: ordered, accepted, rejected, warnings, response };
61
+ }
62
+ function describeStatuses(results) {
63
+ if (results.length === 0)
64
+ return 'no per-invoice results yet';
65
+ return results.map((result) => `#${result.index} ${result.invoiceStatus}`).join(', ');
66
+ }
67
+ //# sourceMappingURL=transaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export interface TransportOptions {
2
+ /** Injectable for testing and for runtimes with a custom fetch. */
3
+ fetch?: typeof globalThis.fetch;
4
+ /** Per-attempt timeout in milliseconds. Defaults to 30 000. */
5
+ timeoutMs?: number;
6
+ /**
7
+ * Retries for transport failures and 5xx responses. Defaults to 2.
8
+ *
9
+ * Only idempotent failures are retried: a `manageInvoice` that reached NAV
10
+ * must never be resent, because the `requestId` would be rejected as a
11
+ * replay and, worse, a genuinely delivered batch could be duplicated.
12
+ */
13
+ retries?: number;
14
+ /** Extra headers, e.g. a correlation id for your own logs. */
15
+ headers?: Record<string, string>;
16
+ }
17
+ export interface NavResponse {
18
+ root: string;
19
+ value: unknown;
20
+ status: number;
21
+ body: string;
22
+ }
23
+ /** POST an XML request to a NAV operation and parse the response. */
24
+ export declare function postXml(baseUrl: string, operation: string, xml: string, options?: TransportOptions, retryable?: boolean): Promise<NavResponse>;
25
+ /**
26
+ * Read a `Retry-After` header, which may be seconds or an HTTP date.
27
+ *
28
+ * Capped, because a header asking us to wait an hour would hang a download
29
+ * that the caller would rather see fail.
30
+ */
31
+ export declare function parseRetryAfter(value: string | null, now?: number): number | undefined;
32
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,qEAAqE;AACrE,wBAAsB,OAAO,CAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,gBAAqB,EAC9B,SAAS,UAAO,GACf,OAAO,CAAC,WAAW,CAAC,CAsEtB;AAgFD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,SAAa,GAAG,MAAM,GAAG,SAAS,CAU1F"}
@@ -0,0 +1,149 @@
1
+ import { NavApiError, NavTransportError, parseDocument, } from '@open-nav/core';
2
+ const DEFAULT_TIMEOUT_MS = 30_000;
3
+ const DEFAULT_RETRIES = 2;
4
+ /** POST an XML request to a NAV operation and parse the response. */
5
+ export async function postXml(baseUrl, operation, xml, options = {}, retryable = true) {
6
+ const doFetch = options.fetch ?? globalThis.fetch;
7
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
8
+ const attempts = retryable ? (options.retries ?? DEFAULT_RETRIES) + 1 : 1;
9
+ const url = `${baseUrl.replace(/\/+$/, '')}/${operation}`;
10
+ let lastError;
11
+ let retryAfterMs;
12
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
13
+ if (attempt > 0) {
14
+ // 500ms, 1s, 2s ... NAV rate limits per taxpayer, so backing off is
15
+ // both polite and necessary. A Retry-After header overrides the curve.
16
+ await delay(retryAfterMs ?? 500 * 2 ** (attempt - 1));
17
+ retryAfterMs = undefined;
18
+ }
19
+ let response;
20
+ try {
21
+ response = await withTimeout((signal) => doFetch(url, {
22
+ method: 'POST',
23
+ body: xml,
24
+ signal,
25
+ headers: {
26
+ 'content-type': 'application/xml; charset=utf-8',
27
+ accept: 'application/xml',
28
+ ...options.headers,
29
+ },
30
+ }), timeoutMs);
31
+ }
32
+ catch (cause) {
33
+ lastError = new NavTransportError(`${operation} request to NAV failed`, { cause });
34
+ continue;
35
+ }
36
+ const body = await response.text();
37
+ if (response.ok) {
38
+ return { ...parseResponseBody(body, response.status), status: response.status, body };
39
+ }
40
+ const error = toApiError(body, response.status);
41
+ // 429 and 503 are "later, not never": back off for as long as NAV asks.
42
+ // A bulk download makes one request per invoice, so this is the difference
43
+ // between a pull that finishes and one that dies a third of the way in.
44
+ if (response.status === 429 || response.status === 503) {
45
+ lastError = error;
46
+ retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));
47
+ continue;
48
+ }
49
+ // Any other 4xx is a decision by NAV and will not change on retry.
50
+ if (response.status < 500 || response.status === 501) {
51
+ // Except one: NAV registers the requestId on receipt, so a retry of a
52
+ // request that did reach it comes back as a replay. That verdict says
53
+ // nothing about what went wrong — the first attempt's error does, and
54
+ // reporting the replay instead sends you looking for a bug in your id
55
+ // generation rather than at the failure that caused the retry.
56
+ if (error.errorCode === 'INVALID_REQUEST_ID' && lastError !== undefined)
57
+ throw lastError;
58
+ throw error;
59
+ }
60
+ lastError = error;
61
+ }
62
+ throw lastError instanceof Error
63
+ ? lastError
64
+ : new NavTransportError(`${operation} request to NAV failed`);
65
+ }
66
+ function parseResponseBody(body, status) {
67
+ try {
68
+ // NAV may deploy schema additions ahead of the published XSDs, and a new
69
+ // optional element must not break an otherwise successful response.
70
+ return parseDocument(body, { unknownElements: 'ignore' });
71
+ }
72
+ catch (cause) {
73
+ throw new NavApiError({
74
+ message: `NAV returned a response that could not be parsed: ${cause.message}`,
75
+ status,
76
+ responseBody: body,
77
+ });
78
+ }
79
+ }
80
+ /**
81
+ * Turn an error body into a typed error.
82
+ *
83
+ * NAV signals failure with `GeneralErrorResponse` (Online Számla specific,
84
+ * carrying technical validation messages) or `GeneralExceptionResponse` (the
85
+ * NTCA-wide shape, used for malformed requests). Both are handled, and so is
86
+ * a body that is neither — a gateway HTML page, for instance.
87
+ */
88
+ function toApiError(body, status) {
89
+ let parsed;
90
+ try {
91
+ parsed = parseDocument(body, { unknownElements: 'ignore' });
92
+ }
93
+ catch {
94
+ parsed = undefined;
95
+ }
96
+ if (!parsed) {
97
+ return new NavApiError({
98
+ message: `NAV returned HTTP ${status} with an unrecognised body`,
99
+ status,
100
+ responseBody: body,
101
+ });
102
+ }
103
+ const value = parsed.value;
104
+ const result = value.result ?? value;
105
+ const parts = [result.errorCode, result.message].filter(Boolean);
106
+ return new NavApiError({
107
+ message: parts.length > 0
108
+ ? `NAV rejected the request: ${parts.join(' - ')}`
109
+ : `NAV returned HTTP ${status} (${parsed.root})`,
110
+ status,
111
+ funcCode: result.funcCode,
112
+ errorCode: result.errorCode,
113
+ validationMessages: value.technicalValidationMessages ?? [],
114
+ responseBody: body,
115
+ });
116
+ }
117
+ async function withTimeout(run, timeoutMs) {
118
+ const controller = new AbortController();
119
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
120
+ try {
121
+ return await run(controller.signal);
122
+ }
123
+ finally {
124
+ clearTimeout(timer);
125
+ }
126
+ }
127
+ function delay(ms) {
128
+ return new Promise((resolve) => setTimeout(resolve, ms));
129
+ }
130
+ /**
131
+ * Read a `Retry-After` header, which may be seconds or an HTTP date.
132
+ *
133
+ * Capped, because a header asking us to wait an hour would hang a download
134
+ * that the caller would rather see fail.
135
+ */
136
+ export function parseRetryAfter(value, now = Date.now()) {
137
+ if (!value)
138
+ return undefined;
139
+ const trimmed = value.trim();
140
+ if (/^\d+$/.test(trimmed)) {
141
+ return Math.min(Number(trimmed) * 1000, MAX_RETRY_AFTER_MS);
142
+ }
143
+ const timestamp = Date.parse(trimmed);
144
+ if (Number.isNaN(timestamp))
145
+ return undefined;
146
+ return Math.min(Math.max(timestamp - now, 0), MAX_RETRY_AFTER_MS);
147
+ }
148
+ const MAX_RETRY_AFTER_MS = 60_000;
149
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,aAAa,GAEd,MAAM,gBAAgB,CAAC;AA0BxB,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAe,EACf,SAAiB,EACjB,GAAW,EACX,UAA4B,EAAE,EAC9B,SAAS,GAAG,IAAI;IAEhB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAC1D,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;IAE1D,IAAI,SAAkB,CAAC;IACvB,IAAI,YAAgC,CAAC;IACrC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACvD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,oEAAoE;YACpE,uEAAuE;YACvE,MAAM,KAAK,CAAC,YAAY,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;YACtD,YAAY,GAAG,SAAS,CAAC;QAC3B,CAAC;QAED,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,WAAW,CAC1B,CAAC,MAAM,EAAE,EAAE,CACT,OAAO,CAAC,GAAG,EAAE;gBACX,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,GAAG;gBACT,MAAM;gBACN,OAAO,EAAE;oBACP,cAAc,EAAE,gCAAgC;oBAChD,MAAM,EAAE,iBAAiB;oBACzB,GAAG,OAAO,CAAC,OAAO;iBACnB;aACF,CAAC,EACJ,SAAS,CACV,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,iBAAiB,CAAC,GAAG,SAAS,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YACnF,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,EAAE,GAAG,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QACxF,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEhD,wEAAwE;QACxE,2EAA2E;QAC3E,wEAAwE;QACxE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvD,SAAS,GAAG,KAAK,CAAC;YAClB,YAAY,GAAG,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;YACpE,SAAS;QACX,CAAC;QAED,mEAAmE;QACnE,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACrD,sEAAsE;YACtE,sEAAsE;YACtE,sEAAsE;YACtE,sEAAsE;YACtE,+DAA+D;YAC/D,IAAI,KAAK,CAAC,SAAS,KAAK,oBAAoB,IAAI,SAAS,KAAK,SAAS;gBAAE,MAAM,SAAS,CAAC;YACzF,MAAM,KAAK,CAAC;QACd,CAAC;QACD,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,MAAM,SAAS,YAAY,KAAK;QAC9B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,iBAAiB,CAAC,GAAG,SAAS,wBAAwB,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,MAAc;IACrD,IAAI,CAAC;QACH,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,aAAa,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CAAC;YACpB,OAAO,EAAE,qDAAsD,KAAe,CAAC,OAAO,EAAE;YACxF,MAAM;YACN,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,UAAU,CAAC,IAAY,EAAE,MAAc;IAC9C,IAAI,MAAoD,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,WAAW,CAAC;YACrB,OAAO,EAAE,qBAAqB,MAAM,4BAA4B;YAChE,MAAM;YACN,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAMpB,CAAC;IACF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC;IACrC,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjE,OAAO,IAAI,WAAW,CAAC;QACrB,OAAO,EACL,KAAK,CAAC,MAAM,GAAG,CAAC;YACd,CAAC,CAAC,6BAA6B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YAClD,CAAC,CAAC,qBAAqB,MAAM,KAAK,MAAM,CAAC,IAAI,GAAG;QACpD,MAAM;QACN,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,kBAAkB,EAAE,KAAK,CAAC,2BAA2B,IAAI,EAAE;QAC3D,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,GAAwC,EACxC,SAAiB;IAEjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACpE,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,kBAAkB,GAAG,MAAM,CAAC"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@open-nav/client",
3
+ "version": "0.1.0",
4
+ "description": "API client for the Hungarian Tax Authority (NAV) Online Számla 3.0 invoice service",
5
+ "keywords": [
6
+ "nav",
7
+ "onlineszamla",
8
+ "online-szamla",
9
+ "hungary",
10
+ "invoice",
11
+ "einvoice",
12
+ "tax",
13
+ "api"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "open-nav contributors",
17
+ "homepage": "https://github.com/eshton/open-nav#readme",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/eshton/open-nav.git",
21
+ "directory": "packages/client"
22
+ },
23
+ "bugs": "https://github.com/eshton/open-nav/issues",
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js",
31
+ "default": "./dist/index.js"
32
+ },
33
+ "./package.json": "./package.json"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "src",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "sideEffects": false,
42
+ "engines": {
43
+ "node": ">=20.10.0"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "dependencies": {
49
+ "@open-nav/core": "^0.1.0"
50
+ },
51
+ "scripts": {
52
+ "build": "tsc -b"
53
+ }
54
+ }