@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,299 @@
1
+ import { NavValidationError } from '../errors.js';
2
+ import { ROOTS, TYPES } from '../generated/schema.js';
3
+ import { NAMESPACE_URIS, XS_PRIMITIVES, } from './descriptor.js';
4
+ /** Prefixes used when a namespace is not the document's default. */
5
+ export const NS_PREFIXES = {
6
+ common: 'common',
7
+ base: 'base',
8
+ data: 'data',
9
+ api: 'api',
10
+ annul: 'annul',
11
+ metrics: 'metrics',
12
+ };
13
+ /**
14
+ * Serialise a document from its root element name.
15
+ *
16
+ * Element order, namespaces and cardinality all come from the generated
17
+ * descriptors, so the output follows the XSD's sequence order — which is what
18
+ * NAV validates against.
19
+ *
20
+ * @param rootName root element name, e.g. `InvoiceData` or `ManageInvoiceRequest`
21
+ * @param value the document, shaped like the generated type of that root
22
+ */
23
+ export function serializeDocument(rootName, value, options = {}) {
24
+ const root = ROOTS[rootName];
25
+ if (!root) {
26
+ throw new NavValidationError(`Unknown document root ${rootName}`, [
27
+ {
28
+ path: '',
29
+ code: 'UNKNOWN_ROOT',
30
+ message: `expected one of ${Object.keys(ROOTS).join(', ')}`,
31
+ },
32
+ ]);
33
+ }
34
+ const issues = [];
35
+ const element = buildElement(root.name, root.ns, root.type, value, rootName, issues);
36
+ if (issues.length > 0) {
37
+ throw new NavValidationError(`Cannot serialise ${rootName}`, issues);
38
+ }
39
+ const used = new Set();
40
+ collectNamespaces(element, used);
41
+ used.delete(root.ns);
42
+ const declarations = [
43
+ ...[...used]
44
+ .sort()
45
+ .map((ns) => [`xmlns:${NS_PREFIXES[ns]}`, NAMESPACE_URIS[ns]]),
46
+ ['xmlns', NAMESPACE_URIS[root.ns]],
47
+ ];
48
+ const indent = options.indent ?? false;
49
+ const body = render(element, root.ns, declarations, indent, 0);
50
+ const declaration = options.declaration === false ? '' : '<?xml version="1.0" encoding="UTF-8"?>';
51
+ if (!declaration)
52
+ return body;
53
+ return indent === false ? `${declaration}${body}` : `${declaration}\n${body}`;
54
+ }
55
+ function collectNamespaces(element, used) {
56
+ used.add(element.ns);
57
+ for (const child of element.children)
58
+ collectNamespaces(child, used);
59
+ }
60
+ function descriptorFor(typeKey, path) {
61
+ const descriptor = TYPES[typeKey];
62
+ if (!descriptor) {
63
+ throw new NavValidationError(`Unknown type ${typeKey}`, [
64
+ { path, code: 'UNKNOWN_TYPE', message: `not present in the generated schema` },
65
+ ]);
66
+ }
67
+ return descriptor;
68
+ }
69
+ function buildElement(name, ns, typeKey, value, path, issues) {
70
+ const primitive = XS_PRIMITIVES[typeKey];
71
+ if (primitive) {
72
+ return {
73
+ ns,
74
+ name,
75
+ attributes: [],
76
+ text: formatPrimitive(primitive, value, path, issues),
77
+ children: [],
78
+ };
79
+ }
80
+ const descriptor = descriptorFor(typeKey, path);
81
+ if (descriptor.kind === 'simple') {
82
+ return {
83
+ ns,
84
+ name,
85
+ attributes: [],
86
+ text: formatPrimitive(descriptor.primitive, value, path, issues),
87
+ children: [],
88
+ };
89
+ }
90
+ if (descriptor.content === 'simple') {
91
+ return buildSimpleContentElement(name, ns, descriptor, value, path, issues);
92
+ }
93
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
94
+ issues.push({
95
+ path,
96
+ code: 'EXPECTED_OBJECT',
97
+ message: `expected an object, got ${describe(value)}`,
98
+ });
99
+ return { ns, name, attributes: [], children: [] };
100
+ }
101
+ const record = value;
102
+ const children = [];
103
+ for (const field of descriptor.fields) {
104
+ const fieldValue = record[field.name];
105
+ const fieldPath = path ? `${path}.${field.name}` : field.name;
106
+ if (fieldValue === undefined || fieldValue === null) {
107
+ if (!field.optional) {
108
+ issues.push({ path: fieldPath, code: 'REQUIRED', message: 'is required' });
109
+ }
110
+ continue;
111
+ }
112
+ if (field.repeated) {
113
+ if (!Array.isArray(fieldValue)) {
114
+ issues.push({
115
+ path: fieldPath,
116
+ code: 'EXPECTED_ARRAY',
117
+ message: `is repeatable and expects an array, got ${describe(fieldValue)}`,
118
+ });
119
+ continue;
120
+ }
121
+ if (field.maxOccurs !== undefined && fieldValue.length > field.maxOccurs) {
122
+ issues.push({
123
+ path: fieldPath,
124
+ code: 'MAX_OCCURS',
125
+ message: `allows at most ${field.maxOccurs} entries, got ${fieldValue.length}`,
126
+ });
127
+ }
128
+ for (const [index, item] of fieldValue.entries()) {
129
+ children.push(buildElement(field.name, field.ns, field.type, item, `${fieldPath}.${index}`, issues));
130
+ }
131
+ continue;
132
+ }
133
+ if (Array.isArray(fieldValue)) {
134
+ issues.push({
135
+ path: fieldPath,
136
+ code: 'UNEXPECTED_ARRAY',
137
+ message: 'occurs at most once and does not accept an array',
138
+ });
139
+ continue;
140
+ }
141
+ children.push(buildElement(field.name, field.ns, field.type, fieldValue, fieldPath, issues));
142
+ }
143
+ const unknown = Object.keys(record).filter((key) => !descriptor.fields.some((field) => field.name === key));
144
+ for (const key of unknown) {
145
+ issues.push({
146
+ path: path ? `${path}.${key}` : key,
147
+ code: 'UNKNOWN_FIELD',
148
+ message: `is not part of ${descriptor.name}`,
149
+ });
150
+ }
151
+ return { ns, name, attributes: [], children };
152
+ }
153
+ function buildSimpleContentElement(name, ns, descriptor, value, path, issues) {
154
+ if (typeof value !== 'object' || value === null) {
155
+ issues.push({
156
+ path,
157
+ code: 'EXPECTED_OBJECT',
158
+ message: `expected an object with a value and attributes, got ${describe(value)}`,
159
+ });
160
+ return { ns, name, attributes: [], children: [] };
161
+ }
162
+ const record = value;
163
+ const contentKind = primitiveOf(descriptor.contentType, path);
164
+ const attributes = [];
165
+ for (const attribute of descriptor.attributes ?? []) {
166
+ const attributeValue = record[attribute.name];
167
+ if (attributeValue === undefined || attributeValue === null) {
168
+ if (attribute.required) {
169
+ issues.push({
170
+ path: `${path}@${attribute.name}`,
171
+ code: 'REQUIRED',
172
+ message: 'attribute is required',
173
+ });
174
+ }
175
+ continue;
176
+ }
177
+ attributes.push([
178
+ attribute.name,
179
+ formatPrimitive(primitiveOf(attribute.type, path), attributeValue, `${path}@${attribute.name}`, issues),
180
+ ]);
181
+ }
182
+ return {
183
+ ns,
184
+ name,
185
+ attributes,
186
+ text: formatPrimitive(contentKind, record['value'], `${path}.value`, issues),
187
+ children: [],
188
+ };
189
+ }
190
+ function primitiveOf(typeKey, path) {
191
+ if (!typeKey) {
192
+ throw new NavValidationError('Missing type', [
193
+ { path, code: 'UNKNOWN_TYPE', message: 'simple content without a declared type' },
194
+ ]);
195
+ }
196
+ const primitive = XS_PRIMITIVES[typeKey];
197
+ if (primitive)
198
+ return primitive;
199
+ const descriptor = descriptorFor(typeKey, path);
200
+ if (descriptor.kind !== 'simple') {
201
+ throw new NavValidationError('Unexpected complex type', [
202
+ { path, code: 'UNKNOWN_TYPE', message: `${typeKey} is not a simple type` },
203
+ ]);
204
+ }
205
+ return descriptor.primitive;
206
+ }
207
+ function formatPrimitive(kind, value, path, issues) {
208
+ switch (kind) {
209
+ case 'boolean':
210
+ if (typeof value === 'boolean')
211
+ return value ? 'true' : 'false';
212
+ if (value === 'true' || value === 'false')
213
+ return value;
214
+ issues.push({
215
+ path,
216
+ code: 'EXPECTED_BOOLEAN',
217
+ message: `expected a boolean, got ${describe(value)}`,
218
+ });
219
+ return '';
220
+ case 'integer':
221
+ if (typeof value === 'number') {
222
+ if (!Number.isInteger(value)) {
223
+ issues.push({
224
+ path,
225
+ code: 'EXPECTED_INTEGER',
226
+ message: `expected an integer, got ${value}`,
227
+ });
228
+ return '';
229
+ }
230
+ return String(value);
231
+ }
232
+ if (typeof value === 'string' && /^-?\d+$/.test(value))
233
+ return value;
234
+ issues.push({
235
+ path,
236
+ code: 'EXPECTED_INTEGER',
237
+ message: `expected an integer, got ${describe(value)}`,
238
+ });
239
+ return '';
240
+ case 'decimal':
241
+ // Strings are the intended representation: they survive 18 significant
242
+ // digits and rates like 0.27 without a floating point detour.
243
+ if (typeof value === 'string' && /^-?\d+(\.\d+)?$/.test(value))
244
+ return value;
245
+ if (typeof value === 'number' && Number.isFinite(value))
246
+ return String(value);
247
+ issues.push({
248
+ path,
249
+ code: 'EXPECTED_DECIMAL',
250
+ message: `expected a decimal, got ${describe(value)}`,
251
+ });
252
+ return '';
253
+ default:
254
+ if (typeof value === 'string')
255
+ return value;
256
+ if (typeof value === 'number' || typeof value === 'boolean')
257
+ return String(value);
258
+ issues.push({
259
+ path,
260
+ code: 'EXPECTED_STRING',
261
+ message: `expected a string, got ${describe(value)}`,
262
+ });
263
+ return '';
264
+ }
265
+ }
266
+ function describe(value) {
267
+ if (value === null)
268
+ return 'null';
269
+ if (Array.isArray(value))
270
+ return 'an array';
271
+ return typeof value;
272
+ }
273
+ function render(element, defaultNs, extraAttributes, indent, depth) {
274
+ const tag = element.ns === defaultNs ? element.name : `${NS_PREFIXES[element.ns]}:${element.name}`;
275
+ const attributes = [...element.attributes, ...extraAttributes]
276
+ .map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`)
277
+ .join('');
278
+ const pad = indent === false ? '' : indent.repeat(depth);
279
+ const newline = indent === false ? '' : '\n';
280
+ if (element.children.length === 0) {
281
+ const text = element.text ?? '';
282
+ if (text === '')
283
+ return `${pad}<${tag}${attributes}/>`;
284
+ return `${pad}<${tag}${attributes}>${escapeText(text)}</${tag}>`;
285
+ }
286
+ const children = element.children
287
+ .map((child) => render(child, defaultNs, [], indent, depth + 1))
288
+ .join(newline);
289
+ return `${pad}<${tag}${attributes}>${newline}${children}${newline}${pad}</${tag}>`;
290
+ }
291
+ function escapeText(value) {
292
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
293
+ }
294
+ function escapeAttribute(value) {
295
+ return escapeText(value)
296
+ .replace(/"/g, '&quot;')
297
+ .replace(/[\n\r\t]/g, (char) => (char === '\n' ? '&#10;' : char === '\r' ? '&#13;' : '&#9;'));
298
+ }
299
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/xml/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAwB,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EACL,cAAc,EACd,aAAa,GAKd,MAAM,iBAAiB,CAAC;AAEzB,oEAAoE;AACpE,MAAM,CAAC,MAAM,WAAW,GAA0B;IAChD,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;CACnB,CAAC;AAyBF;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,KAAc,EACd,UAA4B,EAAE;IAE9B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,kBAAkB,CAAC,yBAAyB,QAAQ,EAAE,EAAE;YAChE;gBACE,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,mBAAmB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAC5D;SACF,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,QAAQ,EAAE,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAS,CAAC;IAC9B,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAErB,MAAM,YAAY,GAA4B;QAC5C,GAAG,CAAC,GAAG,IAAI,CAAC;aACT,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,EAAE,EAAoB,EAAE,CAAC,CAAC,SAAS,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;QAClF,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KACnC,CAAC;IAEF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,wCAAwC,CAAC;IAClG,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,IAAI,EAAE,CAAC;AAChF,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAgB,EAAE,IAAgB;IAC3D,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ;QAAE,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CAAC,OAAe,EAAE,IAAY;IAClD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,kBAAkB,CAAC,gBAAgB,OAAO,EAAE,EAAE;YACtD,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,qCAAqC,EAAE;SAC/E,CAAC,CAAC;IACL,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,YAAY,CACnB,IAAY,EACZ,EAAS,EACT,OAAe,EACf,KAAc,EACd,IAAY,EACZ,MAAyB;IAEzB,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;YACL,EAAE;YACF,IAAI;YACJ,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC;YACrD,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAEhD,IAAI,UAAU,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO;YACL,EAAE;YACF,IAAI;YACJ,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC;YAChE,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,yBAAyB,CAAC,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,2BAA2B,QAAQ,CAAC,KAAK,CAAC,EAAE;SACtD,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAE9D,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACpD,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,gBAAgB;oBACtB,OAAO,EAAE,2CAA2C,QAAQ,CAAC,UAAU,CAAC,EAAE;iBAC3E,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBACzE,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,YAAY;oBAClB,OAAO,EAAE,kBAAkB,KAAK,CAAC,SAAS,iBAAiB,UAAU,CAAC,MAAM,EAAE;iBAC/E,CAAC,CAAC;YACL,CAAC;YACD,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;gBACjD,QAAQ,CAAC,IAAI,CACX,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,KAAK,EAAE,EAAE,MAAM,CAAC,CACtF,CAAC;YACJ,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,kDAAkD;aAC5D,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CACxC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAChE,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG;YACnC,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,kBAAkB,UAAU,CAAC,IAAI,EAAE;SAC7C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,yBAAyB,CAChC,IAAY,EACZ,EAAS,EACT,UAA6B,EAC7B,KAAc,EACd,IAAY,EACZ,MAAyB;IAEzB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,uDAAuD,QAAQ,CAAC,KAAK,CAAC,EAAE;SAClF,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,WAAW,GAAG,WAAW,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,UAAU,GAA4B,EAAE,CAAC;IAE/C,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YAC5D,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,GAAG,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE;oBACjC,IAAI,EAAE,UAAU;oBAChB,OAAO,EAAE,uBAAuB;iBACjC,CAAC,CAAC;YACL,CAAC;YACD,SAAS;QACX,CAAC;QACD,UAAU,CAAC,IAAI,CAAC;YACd,SAAS,CAAC,IAAI;YACd,eAAe,CACb,WAAW,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,EACjC,cAAc,EACd,GAAG,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,EAC3B,MAAM,CACP;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,EAAE;QACF,IAAI;QACJ,UAAU;QACV,IAAI,EAAE,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,QAAQ,EAAE,MAAM,CAAC;QAC5E,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,OAA2B,EAAE,IAAY;IAC5D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,kBAAkB,CAAC,cAAc,EAAE;YAC3C,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,wCAAwC,EAAE;SAClF,CAAC,CAAC;IACL,CAAC;IACD,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,kBAAkB,CAAC,yBAAyB,EAAE;YACtD,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,OAAO,uBAAuB,EAAE;SAC3E,CAAC,CAAC;IACL,CAAC;IACD,OAAO,UAAU,CAAC,SAAS,CAAC;AAC9B,CAAC;AAED,SAAS,eAAe,CACtB,IAAmB,EACnB,KAAc,EACd,IAAY,EACZ,MAAyB;IAEzB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAChE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO;gBAAE,OAAO,KAAK,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,2BAA2B,QAAQ,CAAC,KAAK,CAAC,EAAE;aACtD,CAAC,CAAC;YACH,OAAO,EAAE,CAAC;QAEZ,KAAK,SAAS;YACZ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI;wBACJ,IAAI,EAAE,kBAAkB;wBACxB,OAAO,EAAE,4BAA4B,KAAK,EAAE;qBAC7C,CAAC,CAAC;oBACH,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,4BAA4B,QAAQ,CAAC,KAAK,CAAC,EAAE;aACvD,CAAC,CAAC;YACH,OAAO,EAAE,CAAC;QAEZ,KAAK,SAAS;YACZ,uEAAuE;YACvE,8DAA8D;YAC9D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC7E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAC9E,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,2BAA2B,QAAQ,CAAC,KAAK,CAAC,EAAE;aACtD,CAAC,CAAC;YACH,OAAO,EAAE,CAAC;QAEZ;YACE,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAClF,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,0BAA0B,QAAQ,CAAC,KAAK,CAAC,EAAE;aACrD,CAAC,CAAC;YACH,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAC5C,OAAO,OAAO,KAAK,CAAC;AACtB,CAAC;AAED,SAAS,MAAM,CACb,OAAgB,EAChB,SAAgB,EAChB,eAAwC,EACxC,MAAsB,EACtB,KAAa;IAEb,MAAM,GAAG,GACP,OAAO,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IACzF,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,eAAe,CAAC;SAC3D,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,KAAK,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC;SAC9D,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,GAAG,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAE7C,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAChC,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,GAAG,GAAG,IAAI,GAAG,GAAG,UAAU,IAAI,CAAC;QACvD,OAAO,GAAG,GAAG,IAAI,GAAG,GAAG,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;IACnE,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;SAC9B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;SAC/D,IAAI,CAAC,OAAO,CAAC,CAAC;IACjB,OAAO,GAAG,GAAG,IAAI,GAAG,GAAG,UAAU,IAAI,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC;AACrF,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAClF,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,UAAU,CAAC,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAClG,CAAC"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@open-nav/core",
3
+ "version": "0.1.0",
4
+ "description": "Types, invoice building, XML serialisation and cryptography for the Hungarian NAV Online Számla API",
5
+ "keywords": [
6
+ "nav",
7
+ "onlineszamla",
8
+ "online-szamla",
9
+ "hungary",
10
+ "invoice",
11
+ "einvoice",
12
+ "tax"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "open-nav contributors",
16
+ "homepage": "https://github.com/eshton/open-nav#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/eshton/open-nav.git",
20
+ "directory": "packages/core"
21
+ },
22
+ "bugs": "https://github.com/eshton/open-nav/issues",
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js",
30
+ "default": "./dist/index.js"
31
+ },
32
+ "./package.json": "./package.json"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "src",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "sideEffects": false,
41
+ "engines": {
42
+ "node": ">=20.10.0"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "dependencies": {
48
+ "@noble/ciphers": "^1.2.1",
49
+ "@noble/hashes": "^1.7.1",
50
+ "fast-xml-parser": "^4.5.1"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc -b"
54
+ }
55
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Protocol level constants for the NAV Online Számla (Online Invoice) system.
3
+ *
4
+ * The reference documentation is published by NAV at
5
+ * https://onlineszamla.nav.gov.hu/dokumentaciok — this library targets
6
+ * interface version 3.0 of the invoice service.
7
+ */
8
+
9
+ /** XML namespace of the invoice service request/response envelopes. */
10
+ export const NS_API = 'http://schemas.nav.gov.hu/OSA/3.0/api';
11
+
12
+ /** XML namespace of the invoice payload (`InvoiceData`). */
13
+ export const NS_DATA = 'http://schemas.nav.gov.hu/OSA/3.0/data';
14
+
15
+ /** XML namespace of shared invoice building blocks (addresses, tax numbers). */
16
+ export const NS_BASE = 'http://schemas.nav.gov.hu/OSA/3.0/base';
17
+
18
+ /** XML namespace of the annulment payload (`InvoiceAnnulment`). */
19
+ export const NS_ANNUL = 'http://schemas.nav.gov.hu/OSA/3.0/annul';
20
+
21
+ /** XML namespace of the NTCA common header/user blocks. */
22
+ export const NS_COMMON = 'http://schemas.nav.gov.hu/NTCA/1.0/common';
23
+
24
+ /** Value of `header/requestVersion` for this interface version. */
25
+ export const REQUEST_VERSION = '3.0';
26
+
27
+ /** Value of `header/headerVersion` for this interface version. */
28
+ export const HEADER_VERSION = '1.0';
29
+
30
+ /** Base URL of the NAV production invoice service. */
31
+ export const PRODUCTION_BASE_URL = 'https://api.onlineszamla.nav.gov.hu/invoiceService/v3';
32
+
33
+ /** Base URL of the NAV test ("teszt") invoice service. */
34
+ export const TEST_BASE_URL = 'https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3';
35
+
36
+ /** Well known NAV environments and their base URLs. */
37
+ export const BASE_URLS = {
38
+ production: PRODUCTION_BASE_URL,
39
+ test: TEST_BASE_URL,
40
+ } as const;
41
+
42
+ export type NavEnvironment = keyof typeof BASE_URLS;
43
+
44
+ /** Operation names (path segments) exposed by the invoice service. */
45
+ export const OPERATIONS = [
46
+ 'tokenExchange',
47
+ 'manageInvoice',
48
+ 'manageAnnulment',
49
+ 'queryTransactionStatus',
50
+ 'queryTransactionList',
51
+ 'queryInvoiceData',
52
+ 'queryInvoiceDigest',
53
+ 'queryInvoiceChainDigest',
54
+ 'queryInvoiceCheck',
55
+ 'queryTaxpayer',
56
+ ] as const;
57
+
58
+ export type NavOperation = (typeof OPERATIONS)[number];
59
+
60
+ /**
61
+ * Maximum number of invoice operations NAV accepts in a single
62
+ * `manageInvoice` request.
63
+ */
64
+ export const MAX_INVOICE_BATCH_SIZE = 100;
65
+
66
+ /** Page size used by NAV for every paged query response. */
67
+ export const QUERY_PAGE_SIZE = 100;
68
+
69
+ /**
70
+ * Maximum length of the `requestId` header field. NAV also requires it to be
71
+ * unique per taxpayer, forever.
72
+ */
73
+ export const REQUEST_ID_MAX_LENGTH = 30;
74
+
75
+ /** Characters NAV allows in a `requestId`. */
76
+ export const REQUEST_ID_PATTERN = /^[+a-zA-Z0-9_]{1,30}$/;
@@ -0,0 +1,35 @@
1
+ import { getCryptoProvider } from './provider.js';
2
+
3
+ const encoder = new TextEncoder();
4
+
5
+ function toHexUpper(bytes: Uint8Array): string {
6
+ let out = '';
7
+ for (const byte of bytes) out += byte.toString(16).padStart(2, '0');
8
+ return out.toUpperCase();
9
+ }
10
+
11
+ /** Uppercase hexadecimal SHA-512 digest of a UTF-8 string. */
12
+ export function sha512(value: string): string {
13
+ return toHexUpper(getCryptoProvider().sha512(encoder.encode(value)));
14
+ }
15
+
16
+ /** Uppercase hexadecimal SHA3-512 digest of a UTF-8 string. */
17
+ export function sha3_512(value: string): string {
18
+ return toHexUpper(getCryptoProvider().sha3_512(encoder.encode(value)));
19
+ }
20
+
21
+ /**
22
+ * Hash of the technical user's password for the `user/passwordHash` field.
23
+ *
24
+ * NAV expects the uppercase hex SHA-512 digest of the password, declared on
25
+ * the element with `cryptoType="SHA-512"`.
26
+ */
27
+ export function passwordHash(password: string): string {
28
+ return sha512(password);
29
+ }
30
+
31
+ /** `cryptoType` attribute value used for `passwordHash`. */
32
+ export const PASSWORD_HASH_CRYPTO_TYPE = 'SHA-512';
33
+
34
+ /** `cryptoType` attribute value used for `requestSignature` and invoice hashes. */
35
+ export const SIGNATURE_CRYPTO_TYPE = 'SHA3-512';
@@ -0,0 +1,19 @@
1
+ import { createHash, createDecipheriv, randomBytes } from 'node:crypto';
2
+ import type { CryptoProvider } from './provider.js';
3
+
4
+ /**
5
+ * The default {@link CryptoProvider}, backed by Node's built-in `node:crypto`.
6
+ *
7
+ * Works on Node, Bun and Deno. It does **not** work on Cloudflare Workers,
8
+ * whose `node:crypto` lacks SHA-3 — use {@link createWebCryptoProvider} there.
9
+ */
10
+ export const nodeCryptoProvider: CryptoProvider = {
11
+ sha512: (data) => Uint8Array.from(createHash('sha512').update(data).digest()),
12
+ sha3_512: (data) => Uint8Array.from(createHash('sha3-512').update(data).digest()),
13
+ aes128EcbDecrypt: (ciphertext, key) => {
14
+ const decipher = createDecipheriv('aes-128-ecb', key, null);
15
+ decipher.setAutoPadding(false);
16
+ return Uint8Array.from(Buffer.concat([decipher.update(ciphertext), decipher.final()]));
17
+ },
18
+ randomBytes: (length) => Uint8Array.from(randomBytes(length)),
19
+ };
@@ -0,0 +1,37 @@
1
+ import { nodeCryptoProvider } from './node-provider.js';
2
+
3
+ /**
4
+ * The low-level cryptographic primitives the NAV protocol needs, abstracted so
5
+ * the library can run on any JavaScript runtime.
6
+ *
7
+ * The default is {@link nodeCryptoProvider}, backed by Node's built-in
8
+ * `node:crypto`. On runtimes whose `node:crypto` lacks SHA-3 — notably
9
+ * Cloudflare Workers (workerd/BoringSSL), where `createHash('sha3-512')` throws
10
+ * `Digest method not supported` — install {@link createWebCryptoProvider} via
11
+ * {@link setCryptoProvider} once at startup, before making any request.
12
+ */
13
+ export interface CryptoProvider {
14
+ /** Raw SHA-512 digest of `data`. */
15
+ sha512(data: Uint8Array): Uint8Array;
16
+ /** Raw SHA3-512 digest of `data`. */
17
+ sha3_512(data: Uint8Array): Uint8Array;
18
+ /** AES-128 ECB decryption without padding; `key` is exactly 16 bytes. */
19
+ aes128EcbDecrypt(ciphertext: Uint8Array, key: Uint8Array): Uint8Array;
20
+ /** `length` cryptographically strong random bytes. */
21
+ randomBytes(length: number): Uint8Array;
22
+ }
23
+
24
+ let activeProvider: CryptoProvider = nodeCryptoProvider;
25
+
26
+ /** The crypto provider currently backing every cryptographic helper. */
27
+ export function getCryptoProvider(): CryptoProvider {
28
+ return activeProvider;
29
+ }
30
+
31
+ /**
32
+ * Replace the active crypto provider. Call once at startup, before any NAV
33
+ * request — e.g. `setCryptoProvider(createWebCryptoProvider())` in a Worker.
34
+ */
35
+ export function setCryptoProvider(provider: CryptoProvider): void {
36
+ activeProvider = provider;
37
+ }
@@ -0,0 +1,63 @@
1
+ import { getCryptoProvider } from './provider.js';
2
+ import { REQUEST_ID_MAX_LENGTH, REQUEST_ID_PATTERN } from '../constants.js';
3
+ import { NavValidationError } from '../errors.js';
4
+
5
+ const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
6
+
7
+ /**
8
+ * Generate a `requestId` that satisfies NAV's constraints.
9
+ *
10
+ * NAV requires the value to match `[+a-zA-Z0-9_]{1,30}` and to be unique for
11
+ * the taxpayer across all requests ever sent — a replayed identifier is
12
+ * rejected with `INVALID_REQUEST_ID`. The generated value combines a
13
+ * millisecond timestamp with random characters, which is collision safe for
14
+ * practical throughput, but persisting issued identifiers is still the only
15
+ * way to be certain after a clock change.
16
+ *
17
+ * @param prefix optional caller prefix, useful for tracing (`[a-zA-Z0-9_+]`)
18
+ */
19
+ export function createRequestId(prefix = 'ON'): string {
20
+ assertRequestIdChars(prefix, 'prefix');
21
+ const stamp = Date.now().toString(36).toUpperCase();
22
+ const available = REQUEST_ID_MAX_LENGTH - prefix.length - stamp.length;
23
+ if (available < 4) {
24
+ throw new NavValidationError('requestId prefix is too long', [
25
+ {
26
+ path: 'prefix',
27
+ code: 'REQUEST_ID_PREFIX_TOO_LONG',
28
+ message: `leaves only ${available} characters of entropy, need at least 4`,
29
+ },
30
+ ]);
31
+ }
32
+ return `${prefix}${stamp}${randomChars(Math.min(available, 8))}`;
33
+ }
34
+
35
+ /** Throw unless `value` is a valid `requestId`. */
36
+ export function assertRequestId(value: string): void {
37
+ if (!REQUEST_ID_PATTERN.test(value)) {
38
+ throw new NavValidationError('Invalid requestId', [
39
+ {
40
+ path: 'requestId',
41
+ code: 'INVALID_REQUEST_ID',
42
+ message: `must match ${REQUEST_ID_PATTERN.source}, got ${JSON.stringify(value)}`,
43
+ },
44
+ ]);
45
+ }
46
+ }
47
+
48
+ function assertRequestIdChars(value: string, path: string): void {
49
+ if (!/^[+a-zA-Z0-9_]*$/.test(value)) {
50
+ throw new NavValidationError('Invalid requestId characters', [
51
+ { path, code: 'INVALID_REQUEST_ID', message: 'may only contain [+a-zA-Z0-9_]' },
52
+ ]);
53
+ }
54
+ }
55
+
56
+ function randomChars(length: number): string {
57
+ const bytes = getCryptoProvider().randomBytes(length);
58
+ let out = '';
59
+ for (let i = 0; i < length; i += 1) {
60
+ out += ALPHABET[bytes[i]! % ALPHABET.length];
61
+ }
62
+ return out;
63
+ }
@@ -0,0 +1,58 @@
1
+ import { sha3_512 } from './hash.js';
2
+ import { toSignatureTimestamp } from '../time.js';
3
+
4
+ /**
5
+ * A single invoice (or annulment) operation as it contributes to the request
6
+ * signature of a `manageInvoice` / `manageAnnulment` call.
7
+ */
8
+ export interface SignedOperation {
9
+ /** 1-based position inside the batch; operations are hashed in index order. */
10
+ index: number;
11
+ /** `CREATE`, `MODIFY`, `STORNO` or `ANNUL`. */
12
+ operation: string;
13
+ /** Base64 encoded payload exactly as it appears in the request XML. */
14
+ base64Payload: string;
15
+ }
16
+
17
+ /**
18
+ * Hash of one invoice operation, as consumed by {@link requestSignature} and
19
+ * as sent in the optional `electronicInvoiceHash` element.
20
+ *
21
+ * NAV defines it as `SHA3-512(operation || base64Payload)`, uppercase hex.
22
+ */
23
+ export function operationHash(operation: string, base64Payload: string): string {
24
+ return sha3_512(`${operation}${base64Payload}`);
25
+ }
26
+
27
+ /**
28
+ * Compute the `user/requestSignature` value.
29
+ *
30
+ * NAV specifies the signature as
31
+ *
32
+ * ```text
33
+ * SHA3-512( requestId || yyyyMMddHHmmss(timestamp) || signKey || hash(op1) || hash(op2) ... )
34
+ * ```
35
+ *
36
+ * where the per-operation hashes are only present for `manageInvoice` and
37
+ * `manageAnnulment` requests and must be concatenated in ascending `index`
38
+ * order. The timestamp must be the request header timestamp truncated to
39
+ * whole seconds and rendered in UTC without separators.
40
+ *
41
+ * @param requestId the `header/requestId` of the same request
42
+ * @param timestamp the `header/timestamp` of the same request
43
+ * @param signKey the technical user's signature key (aláírókulcs)
44
+ * @param operations invoice/annulment operations of the batch, if any
45
+ */
46
+ export function requestSignature(
47
+ requestId: string,
48
+ timestamp: Date | string,
49
+ signKey: string,
50
+ operations: SignedOperation[] = [],
51
+ ): string {
52
+ const operationDigests = [...operations]
53
+ .sort((a, b) => a.index - b.index)
54
+ .map((op) => operationHash(op.operation, op.base64Payload))
55
+ .join('');
56
+
57
+ return sha3_512(`${requestId}${toSignatureTimestamp(timestamp)}${signKey}${operationDigests}`);
58
+ }