nav-osa-core
v0.2.0
Published
Shared TypeScript types, XML parser, XSD validator, and XML builder for the Hungarian NAV Online Invoice System (OSA)
Maintainers
Readme
nav-osa-core
Shared TypeScript types, XML parser, XSD validator, and XML builder for the Hungarian NAV Online Invoice System (OSA) version 3.0.
Hybrid architecture: parsing is done with libxml2-wasm (libxml2 compiled to WebAssembly), building with fast-xml-builder.
Contents
- Generic XML parser built on
libxml2-wasmconfigured for NAV XML documents - XML builders:
buildInvoiceXmlfor invoice data,buildApiRequestXmlfor API request XML (built onfast-xml-builder) - XSD validation with built-in lazy validator cache (libxml2-wasm)
Installation
npm install nav-osa-core nav-osa-typesUsage
Types
Types are provided by the separate nav-osa-types package:
import { InvoiceData, TaxNumberType, MonetaryType } from 'nav-osa-types';Parse XML
schemaName is required as the second argument — the XML is validated against that schema before parsing. Validation can be disabled with validate: false:
import { parseXml, XsdSchemaName } from 'nav-osa-core';
import { InvoiceData } from 'nav-osa-types';
const result = await parseXml<{ InvoiceData: InvoiceData }>(xmlString, XsdSchemaName.Data);
const resultNoValidation = await parseXml(xmlString, XsdSchemaName.Data, { validate: false });If validation fails, a detailed XmlValidationError is thrown:
import { XmlValidationError } from 'nav-osa-core';
try {
const result = await parseXml(xmlString, XsdSchemaName.Data);
} catch (err) {
if (err instanceof XmlValidationError) {
console.log('Validation failed:', err.errors);
}
}Validate XML
import { validateXml, ValidationResult, XsdSchemaName } from 'nav-osa-core';
const result: ValidationResult = await validateXml(xmlString, XsdSchemaName.Data);
if (!result.valid) {
console.log('Errors:', result.errors);
}Validators are cached by schema name after the first call.
Build invoice XML from JSON
Converts an InvoiceData object to XML and validates it against the built-in data.xsd schema:
import { buildInvoiceXml } from 'nav-osa-core';
import { InvoiceData } from 'nav-osa-types';
const invoice: InvoiceData = {
invoiceNumber: 'ABC-2025-001',
invoiceIssueDate: '2025-01-15',
completenessIndicator: false,
invoiceMain: {
invoice: {
invoiceHead: {
supplierInfo: { /* ... */ },
invoiceDetail: { /* ... */ },
},
invoiceSummary: { /* ... */ },
},
},
};
const xml = await buildInvoiceXml(invoice);If validation fails, a detailed XmlValidationError is thrown:
import { XmlValidationError } from 'nav-osa-core';
try {
const xml = await buildInvoiceXml(invoice);
} catch (err) {
if (err instanceof XmlValidationError) {
console.log('XSD validation errors:', err.errors);
}
}Build API request XML
Build and validate API request XML (TokenExchangeRequest, QueryInvoiceDigestRequest, etc.) with optional namespace prefixing:
import { buildApiRequestXml, XsdSchemaName } from 'nav-osa-core';
const xml = await buildApiRequestXml('TokenExchangeRequest', {
'@_xmlns': 'http://schemas.nav.gov.hu/OSA/3.0/api',
'@_xmlns:common': 'http://schemas.nav.gov.hu/NTCA/1.0/common',
header: {
requestId: 'RID...',
timestamp: '2025-01-01T00:00:00.000Z',
requestVersion: '3.0',
headerVersion: '1.0',
},
user: {
login: 'user',
passwordHash: {
'@_cryptoType': 'SHA-512',
'#text': 'hash...',
},
taxNumber: '12345678',
requestSignature: {
'@_cryptoType': 'SHA3-512',
'#text': 'sig...',
},
},
software: {
softwareId: '123456789012345678',
softwareName: 'TestApp',
softwareOperation: 'LOCAL_SOFTWARE',
softwareMainVersion: '1.0',
softwareDevName: 'Dev',
softwareDevContact: '[email protected]',
},
}, XsdSchemaName.InvoiceApi, {
namespacePrefix: 'common',
prefixRootKeys: ['header', 'user'],
});The namespacePrefix option controls which top-level keys receive a namespace prefix. With prefixRootKeys: ['header', 'user'], the output becomes:
<TokenExchangeRequest xmlns="..." xmlns:common="...">
<common:header>
<common:requestId>RID...</common:requestId>
...
</common:header>
<common:user>...</common:user>
<software>...</software>
</TokenExchangeRequest>XSD schemas
The module ships the official NAV XSD files and an enum to reference them:
XsdSchemaName.Common→common.xsd— NTCA Common typesXsdSchemaName.InvoiceBase→invoiceBase.xsd— Base invoice typesXsdSchemaName.Data→data.xsd— Invoice data typesXsdSchemaName.InvoiceApi→invoiceApi.xsd— API request/response types
import { validateXml, buildApiRequestXml, XsdSchemaName } from 'nav-osa-core';
// Validate against a named schema
await validateXml(xmlString, XsdSchemaName.Data);
// Build and validate API request
await buildApiRequestXml('TokenExchangeRequest', data, XsdSchemaName.InvoiceApi);Security options
The parser processes XML entities by default (processEntities: true) to protect against entity expansion attacks. For trusted XML (self-generated documents with no external input), you can disable this to reduce overhead:
import { parseXml, XsdSchemaName } from 'nav-osa-core';
const result = await parseXml(xmlString, XsdSchemaName.Data, { processEntities: false });Warning: Only disable entity processing when parsing XML you fully control. Never use this for external or untrusted input.
Payload size limit
The parser rejects XML payloads larger than 10 MB by default. You can override this:
import { parseXml, XsdSchemaName } from 'nav-osa-core';
const result = await parseXml(xmlString, XsdSchemaName.Data, { maxXmlSize: 50 * 1024 * 1024 });Security
- Network access disabled (
NONET) — XML parsing never fetches external resources, preventing XXE (XML External Entity) attacks. - Entity expansion protection (
processEntities: trueby default) — guards against billion laughs / exponential entity expansion attacks. Can be disabled for trusted self-generated XML to reduce overhead. - Payload size limit (
maxXmlSize: 10 MB by default) — prevents memory exhaustion from oversized XML inputs. HUGEflag — used only when loading the built-in XSD schemas (trusted, shipped with the package). Never applied to user-provided XML.
Support
If you find this package useful, consider supporting the development:
License
Apache-2.0
