@open-nav/core 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.
Files changed (133) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +132 -0
  3. package/dist/constants.d.ts +49 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +58 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/crypto/hash.d.ts +16 -0
  8. package/dist/crypto/hash.d.ts.map +1 -0
  9. package/dist/crypto/hash.js +30 -0
  10. package/dist/crypto/hash.js.map +1 -0
  11. package/dist/crypto/node-provider.d.ts +9 -0
  12. package/dist/crypto/node-provider.d.ts.map +1 -0
  13. package/dist/crypto/node-provider.js +18 -0
  14. package/dist/crypto/node-provider.js.map +1 -0
  15. package/dist/crypto/provider.d.ts +28 -0
  16. package/dist/crypto/provider.d.ts.map +1 -0
  17. package/dist/crypto/provider.js +14 -0
  18. package/dist/crypto/provider.js.map +1 -0
  19. package/dist/crypto/request-id.d.ts +16 -0
  20. package/dist/crypto/request-id.d.ts.map +1 -0
  21. package/dist/crypto/request-id.js +59 -0
  22. package/dist/crypto/request-id.js.map +1 -0
  23. package/dist/crypto/signature.d.ts +40 -0
  24. package/dist/crypto/signature.d.ts.map +1 -0
  25. package/dist/crypto/signature.js +38 -0
  26. package/dist/crypto/signature.js.map +1 -0
  27. package/dist/crypto/token.d.ts +14 -0
  28. package/dist/crypto/token.d.ts.map +1 -0
  29. package/dist/crypto/token.js +82 -0
  30. package/dist/crypto/token.js.map +1 -0
  31. package/dist/crypto/web-provider.d.ts +18 -0
  32. package/dist/crypto/web-provider.d.ts.map +1 -0
  33. package/dist/crypto/web-provider.js +31 -0
  34. package/dist/crypto/web-provider.js.map +1 -0
  35. package/dist/errors.d.ts +75 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +71 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/generated/fault-codes.d.ts +1343 -0
  40. package/dist/generated/fault-codes.d.ts.map +1 -0
  41. package/dist/generated/fault-codes.js +1331 -0
  42. package/dist/generated/fault-codes.js.map +1 -0
  43. package/dist/generated/index.d.ts +4 -0
  44. package/dist/generated/index.d.ts.map +1 -0
  45. package/dist/generated/index.js +5 -0
  46. package/dist/generated/index.js.map +1 -0
  47. package/dist/generated/schema.d.ts +13 -0
  48. package/dist/generated/schema.d.ts.map +1 -0
  49. package/dist/generated/schema.js +3756 -0
  50. package/dist/generated/schema.js.map +1 -0
  51. package/dist/generated/types.d.ts +5580 -0
  52. package/dist/generated/types.d.ts.map +1 -0
  53. package/dist/generated/types.js +6 -0
  54. package/dist/generated/types.js.map +1 -0
  55. package/dist/index.d.ts +23 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +23 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/invoice/payload.d.ts +40 -0
  60. package/dist/invoice/payload.d.ts.map +1 -0
  61. package/dist/invoice/payload.js +66 -0
  62. package/dist/invoice/payload.js.map +1 -0
  63. package/dist/money/decimal.d.ts +69 -0
  64. package/dist/money/decimal.d.ts.map +1 -0
  65. package/dist/money/decimal.js +190 -0
  66. package/dist/money/decimal.js.map +1 -0
  67. package/dist/money/summary.d.ts +60 -0
  68. package/dist/money/summary.d.ts.map +1 -0
  69. package/dist/money/summary.js +236 -0
  70. package/dist/money/summary.js.map +1 -0
  71. package/dist/time.d.ts +16 -0
  72. package/dist/time.d.ts.map +1 -0
  73. package/dist/time.js +41 -0
  74. package/dist/time.js.map +1 -0
  75. package/dist/validation/issue.d.ts +67 -0
  76. package/dist/validation/issue.d.ts.map +1 -0
  77. package/dist/validation/issue.js +40 -0
  78. package/dist/validation/issue.js.map +1 -0
  79. package/dist/validation/rules.d.ts +34 -0
  80. package/dist/validation/rules.d.ts.map +1 -0
  81. package/dist/validation/rules.js +290 -0
  82. package/dist/validation/rules.js.map +1 -0
  83. package/dist/validation/schema.d.ts +14 -0
  84. package/dist/validation/schema.d.ts.map +1 -0
  85. package/dist/validation/schema.js +231 -0
  86. package/dist/validation/schema.js.map +1 -0
  87. package/dist/validation/tax-number.d.ts +39 -0
  88. package/dist/validation/tax-number.d.ts.map +1 -0
  89. package/dist/validation/tax-number.js +79 -0
  90. package/dist/validation/tax-number.js.map +1 -0
  91. package/dist/validation/validate.d.ts +29 -0
  92. package/dist/validation/validate.d.ts.map +1 -0
  93. package/dist/validation/validate.js +33 -0
  94. package/dist/validation/validate.js.map +1 -0
  95. package/dist/xml/descriptor.d.ts +82 -0
  96. package/dist/xml/descriptor.d.ts.map +1 -0
  97. package/dist/xml/descriptor.js +32 -0
  98. package/dist/xml/descriptor.js.map +1 -0
  99. package/dist/xml/read.d.ts +25 -0
  100. package/dist/xml/read.d.ts.map +1 -0
  101. package/dist/xml/read.js +230 -0
  102. package/dist/xml/read.js.map +1 -0
  103. package/dist/xml/write.d.ts +28 -0
  104. package/dist/xml/write.d.ts.map +1 -0
  105. package/dist/xml/write.js +299 -0
  106. package/dist/xml/write.js.map +1 -0
  107. package/package.json +55 -0
  108. package/src/constants.ts +76 -0
  109. package/src/crypto/hash.ts +35 -0
  110. package/src/crypto/node-provider.ts +19 -0
  111. package/src/crypto/provider.ts +37 -0
  112. package/src/crypto/request-id.ts +63 -0
  113. package/src/crypto/signature.ts +58 -0
  114. package/src/crypto/token.ts +86 -0
  115. package/src/crypto/web-provider.ts +32 -0
  116. package/src/errors.ts +109 -0
  117. package/src/generated/fault-codes.ts +1338 -0
  118. package/src/generated/index.ts +4 -0
  119. package/src/generated/schema.ts +3760 -0
  120. package/src/generated/types.ts +5829 -0
  121. package/src/index.ts +22 -0
  122. package/src/invoice/payload.ts +102 -0
  123. package/src/money/decimal.ts +218 -0
  124. package/src/money/summary.ts +380 -0
  125. package/src/time.ts +44 -0
  126. package/src/validation/issue.ts +102 -0
  127. package/src/validation/rules.ts +548 -0
  128. package/src/validation/schema.ts +315 -0
  129. package/src/validation/tax-number.ts +96 -0
  130. package/src/validation/validate.ts +45 -0
  131. package/src/xml/descriptor.ts +112 -0
  132. package/src/xml/read.ts +303 -0
  133. package/src/xml/write.ts +391 -0
@@ -0,0 +1,82 @@
1
+ import { getCryptoProvider } from './provider.js';
2
+ import { NavValidationError } from '../errors.js';
3
+ const EXCHANGE_KEY_LENGTH = 16;
4
+ const encoder = new TextEncoder();
5
+ const decoder = new TextDecoder();
6
+ /** Decode a base64 string to bytes on any runtime (no Node Buffer). */
7
+ function base64ToBytes(base64) {
8
+ let binary;
9
+ try {
10
+ binary = atob(base64);
11
+ }
12
+ catch {
13
+ throw new NavValidationError('Invalid encoded exchange token', [
14
+ {
15
+ path: 'encodedExchangeToken',
16
+ code: 'EXCHANGE_TOKEN_LENGTH',
17
+ message: 'not valid base64',
18
+ },
19
+ ]);
20
+ }
21
+ const bytes = new Uint8Array(binary.length);
22
+ for (let i = 0; i < binary.length; i += 1)
23
+ bytes[i] = binary.charCodeAt(i);
24
+ return bytes;
25
+ }
26
+ /**
27
+ * Decrypt the `encodedExchangeToken` returned by `tokenExchange`.
28
+ *
29
+ * NAV encrypts the 16 character exchange token with AES-128 in ECB mode using
30
+ * the technical user's exchange key (csereklucs / "XML aláírás kulcs" pair) as
31
+ * the raw key, then base64 encodes the result. Padding is optional in
32
+ * practice: NAV historically returned an unpadded 16 byte block, while some
33
+ * environments return a PKCS#7 padded 32 byte block, so both are accepted.
34
+ *
35
+ * @param encodedToken base64 payload from the response
36
+ * @param exchangeKey 16 character exchange key of the technical user
37
+ */
38
+ export function decodeExchangeToken(encodedToken, exchangeKey) {
39
+ const keyBytes = encoder.encode(exchangeKey);
40
+ // AES-128 needs a 16-byte key. NAV keys are 16 ASCII characters, so char
41
+ // length and byte length coincide; guard on bytes so a non-ASCII key fails
42
+ // here with a NAV code rather than deep inside the cipher.
43
+ if (keyBytes.length !== EXCHANGE_KEY_LENGTH) {
44
+ throw new NavValidationError('Invalid NAV exchange key', [
45
+ {
46
+ path: 'credentials.exchangeKey',
47
+ code: 'EXCHANGE_KEY_LENGTH',
48
+ message: `must be exactly ${EXCHANGE_KEY_LENGTH} bytes, got ${keyBytes.length}`,
49
+ },
50
+ ]);
51
+ }
52
+ const ciphertext = base64ToBytes(encodedToken);
53
+ if (ciphertext.length === 0 || ciphertext.length % 16 !== 0) {
54
+ throw new NavValidationError('Invalid encoded exchange token', [
55
+ {
56
+ path: 'encodedExchangeToken',
57
+ code: 'EXCHANGE_TOKEN_LENGTH',
58
+ message: `expected a multiple of the 16 byte AES block size, got ${ciphertext.length}`,
59
+ },
60
+ ]);
61
+ }
62
+ const plaintext = getCryptoProvider().aes128EcbDecrypt(ciphertext, keyBytes);
63
+ return decoder.decode(stripPkcs7(plaintext));
64
+ }
65
+ /**
66
+ * Remove PKCS#7 padding if, and only if, the buffer actually carries it.
67
+ * NAV's unpadded tokens consist of printable ASCII, so a trailing byte in the
68
+ * 1..16 range is an unambiguous padding marker.
69
+ */
70
+ function stripPkcs7(buffer) {
71
+ const last = buffer.at(-1);
72
+ if (last === undefined || last < 1 || last > 16 || last >= buffer.length) {
73
+ return buffer;
74
+ }
75
+ for (let i = buffer.length - last; i < buffer.length; i += 1) {
76
+ if (buffer[i] !== last) {
77
+ return buffer;
78
+ }
79
+ }
80
+ return buffer.subarray(0, buffer.length - last);
81
+ }
82
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/crypto/token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { CryptoProvider } from './provider.js';
2
+ /**
3
+ * A {@link CryptoProvider} for runtimes without SHA-3 in `node:crypto` —
4
+ * Cloudflare Workers, browsers, Deno, Bun.
5
+ *
6
+ * Uses `@noble/hashes` for SHA-512 / SHA3-512 (WebCrypto offers neither a
7
+ * synchronous digest nor SHA-3), `@noble/ciphers` for the AES-128-ECB exchange
8
+ * token (WebCrypto has no ECB mode), and `crypto.getRandomValues` for
9
+ * randomness. Every operation is synchronous, matching {@link nodeCryptoProvider}.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { setCryptoProvider, createWebCryptoProvider } from '@open-nav/core';
14
+ * setCryptoProvider(createWebCryptoProvider());
15
+ * ```
16
+ */
17
+ export declare function createWebCryptoProvider(): CryptoProvider;
18
+ //# sourceMappingURL=web-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-provider.d.ts","sourceRoot":"","sources":["../../src/crypto/web-provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,IAAI,cAAc,CAWxD"}
@@ -0,0 +1,31 @@
1
+ import { sha512 } from '@noble/hashes/sha2';
2
+ import { sha3_512 } from '@noble/hashes/sha3';
3
+ import { ecb } from '@noble/ciphers/aes';
4
+ /**
5
+ * A {@link CryptoProvider} for runtimes without SHA-3 in `node:crypto` —
6
+ * Cloudflare Workers, browsers, Deno, Bun.
7
+ *
8
+ * Uses `@noble/hashes` for SHA-512 / SHA3-512 (WebCrypto offers neither a
9
+ * synchronous digest nor SHA-3), `@noble/ciphers` for the AES-128-ECB exchange
10
+ * token (WebCrypto has no ECB mode), and `crypto.getRandomValues` for
11
+ * randomness. Every operation is synchronous, matching {@link nodeCryptoProvider}.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { setCryptoProvider, createWebCryptoProvider } from '@open-nav/core';
16
+ * setCryptoProvider(createWebCryptoProvider());
17
+ * ```
18
+ */
19
+ export function createWebCryptoProvider() {
20
+ return {
21
+ sha512: (data) => sha512(data),
22
+ sha3_512: (data) => sha3_512(data),
23
+ aes128EcbDecrypt: (ciphertext, key) => ecb(key, { disablePadding: true }).decrypt(ciphertext),
24
+ randomBytes: (length) => {
25
+ const bytes = new Uint8Array(length);
26
+ globalThis.crypto.getRandomValues(bytes);
27
+ return bytes;
28
+ },
29
+ };
30
+ }
31
+ //# sourceMappingURL=web-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-provider.js","sourceRoot":"","sources":["../../src/crypto/web-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAGzC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;QAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;QAClC,gBAAgB,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QAC7F,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE;YACtB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;YACrC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,75 @@
1
+ /** Base class for every error raised by the open-nav packages. */
2
+ export declare class NavError extends Error {
3
+ constructor(message: string, options?: {
4
+ cause?: unknown;
5
+ });
6
+ }
7
+ /**
8
+ * Raised when data fails local validation before a request is ever sent to
9
+ * NAV — a malformed tax number, an unbalanced invoice, a bad `requestId`.
10
+ */
11
+ export declare class NavValidationError extends NavError {
12
+ /** Machine readable issues, in document order. */
13
+ readonly issues: ValidationIssue[];
14
+ constructor(message: string, issues?: ValidationIssue[]);
15
+ }
16
+ export interface ValidationIssue {
17
+ /** Dotted path of the offending value, e.g. `invoiceLines.1.quantity`. */
18
+ path: string;
19
+ /** Human readable description of the problem. */
20
+ message: string;
21
+ /** Stable identifier so callers can branch on a specific rule. */
22
+ code?: string;
23
+ }
24
+ /** Raised when the transport fails (DNS, TLS, timeout, connection reset). */
25
+ export declare class NavTransportError extends NavError {
26
+ }
27
+ /**
28
+ * Raised when NAV replies with a `GeneralErrorResponse`, or with any other
29
+ * non-success HTTP status.
30
+ */
31
+ export declare class NavApiError extends NavError {
32
+ /** HTTP status code of the response. */
33
+ readonly status: number;
34
+ /** `result/funcCode`, e.g. `ERROR`. */
35
+ readonly funcCode?: string;
36
+ /** `result/errorCode`, e.g. `INVALID_SECURITY_USER`. */
37
+ readonly errorCode?: string;
38
+ /** Validation messages NAV attached to the error. */
39
+ readonly validationMessages: NavValidationMessage[];
40
+ /** Raw response body, kept for logging and bug reports. */
41
+ readonly responseBody: string;
42
+ constructor(init: {
43
+ message: string;
44
+ status: number;
45
+ funcCode?: string;
46
+ errorCode?: string;
47
+ validationMessages?: NavValidationMessage[];
48
+ responseBody?: string;
49
+ });
50
+ }
51
+ export interface NavValidationMessage {
52
+ /** `ERROR` blocks processing, `WARN` does not. */
53
+ validationResultCode: 'ERROR' | 'WARN' | 'INFO' | string;
54
+ validationErrorCode?: string;
55
+ message?: string;
56
+ /** Only present on technical validation messages. */
57
+ lineNumber?: number;
58
+ /** Only present on business validation messages. */
59
+ tag?: string;
60
+ value?: string;
61
+ }
62
+ /**
63
+ * Raised when an invoice batch was accepted by NAV but at least one invoice
64
+ * was rejected during processing.
65
+ */
66
+ export declare class NavInvoiceRejectedError extends NavError {
67
+ readonly transactionId: string;
68
+ readonly rejected: Array<{
69
+ index: number;
70
+ invoiceStatus: string;
71
+ messages: NavValidationMessage[];
72
+ }>;
73
+ constructor(transactionId: string, rejected: NavInvoiceRejectedError['rejected']);
74
+ }
75
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAI3D;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IAC9C,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC;gBAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,eAAe,EAAO;CAI5D;AAED,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,QAAQ;CAAG;AAElD;;;GAGG;AACH,qBAAa,WAAY,SAAQ,QAAQ;IACvC,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;IACpD,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,IAAI,EAAE;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,kBAAkB,CAAC,EAAE,oBAAoB,EAAE,CAAC;QAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;CAQF;AAED,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,oBAAoB,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACzD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;IACnD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,oBAAoB,EAAE,CAAC;KAClC,CAAC,CAAC;gBAES,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB,CAAC,UAAU,CAAC;CAajF"}
package/dist/errors.js ADDED
@@ -0,0 +1,71 @@
1
+ /** Base class for every error raised by the open-nav packages. */
2
+ export class NavError extends Error {
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.name = new.target.name;
6
+ }
7
+ }
8
+ /**
9
+ * Raised when data fails local validation before a request is ever sent to
10
+ * NAV — a malformed tax number, an unbalanced invoice, a bad `requestId`.
11
+ */
12
+ export class NavValidationError extends NavError {
13
+ /** Machine readable issues, in document order. */
14
+ issues;
15
+ constructor(message, issues = []) {
16
+ super(issues.length > 0 ? `${message}: ${formatIssues(issues)}` : message);
17
+ this.issues = issues;
18
+ }
19
+ }
20
+ function formatIssues(issues) {
21
+ return issues.map((issue) => `${issue.path || '<root>'} ${issue.message}`).join('; ');
22
+ }
23
+ /** Raised when the transport fails (DNS, TLS, timeout, connection reset). */
24
+ export class NavTransportError extends NavError {
25
+ }
26
+ /**
27
+ * Raised when NAV replies with a `GeneralErrorResponse`, or with any other
28
+ * non-success HTTP status.
29
+ */
30
+ export class NavApiError extends NavError {
31
+ /** HTTP status code of the response. */
32
+ status;
33
+ /** `result/funcCode`, e.g. `ERROR`. */
34
+ funcCode;
35
+ /** `result/errorCode`, e.g. `INVALID_SECURITY_USER`. */
36
+ errorCode;
37
+ /** Validation messages NAV attached to the error. */
38
+ validationMessages;
39
+ /** Raw response body, kept for logging and bug reports. */
40
+ responseBody;
41
+ constructor(init) {
42
+ super(init.message);
43
+ this.status = init.status;
44
+ this.funcCode = init.funcCode;
45
+ this.errorCode = init.errorCode;
46
+ this.validationMessages = init.validationMessages ?? [];
47
+ this.responseBody = init.responseBody ?? '';
48
+ }
49
+ }
50
+ /**
51
+ * Raised when an invoice batch was accepted by NAV but at least one invoice
52
+ * was rejected during processing.
53
+ */
54
+ export class NavInvoiceRejectedError extends NavError {
55
+ transactionId;
56
+ rejected;
57
+ constructor(transactionId, rejected) {
58
+ const detail = rejected
59
+ .map((entry) => {
60
+ const reasons = entry.messages
61
+ .map((m) => [m.validationErrorCode, m.message].filter(Boolean).join(': '))
62
+ .join(' | ');
63
+ return `#${entry.index} ${entry.invoiceStatus}${reasons ? ` (${reasons})` : ''}`;
64
+ })
65
+ .join('; ');
66
+ super(`Transaction ${transactionId} contains rejected invoices: ${detail}`);
67
+ this.transactionId = transactionId;
68
+ this.rejected = rejected;
69
+ }
70
+ }
71
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe,EAAE,OAA6B;QACxD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IAC9B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,kBAAmB,SAAQ,QAAQ;IAC9C,kDAAkD;IACzC,MAAM,CAAoB;IAEnC,YAAY,OAAe,EAAE,SAA4B,EAAE;QACzD,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAWD,SAAS,YAAY,CAAC,MAAyB;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxF,CAAC;AAED,6EAA6E;AAC7E,MAAM,OAAO,iBAAkB,SAAQ,QAAQ;CAAG;AAElD;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,QAAQ;IACvC,wCAAwC;IAC/B,MAAM,CAAS;IACxB,uCAAuC;IAC9B,QAAQ,CAAU;IAC3B,wDAAwD;IAC/C,SAAS,CAAU;IAC5B,qDAAqD;IAC5C,kBAAkB,CAAyB;IACpD,2DAA2D;IAClD,YAAY,CAAS;IAE9B,YAAY,IAOX;QACC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC;QACxD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC;IAC9C,CAAC;CACF;AAcD;;;GAGG;AACH,MAAM,OAAO,uBAAwB,SAAQ,QAAQ;IAC1C,aAAa,CAAS;IACtB,QAAQ,CAId;IAEH,YAAY,aAAqB,EAAE,QAA6C;QAC9E,MAAM,MAAM,GAAG,QAAQ;aACpB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ;iBAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;iBACzE,IAAI,CAAC,KAAK,CAAC,CAAC;YACf,OAAO,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACnF,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC,eAAe,aAAa,gCAAgC,MAAM,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF"}