This release changes no code. It changes what the SDK tells you, which in this case matters more.
What we said
importFile() and ImportInvoiceOptions carried this, in the JSDoc your editor shows you:
The document is transmitted to the Peppol network byte for byte — getpeppr does not regenerate it, so what your recipient receives is exactly what you signed or hashed.
The same claim was in our public API reference. An integrator read it, designed a hash chain around it, and then did what we had not: he measured it.
What is actually true
He was right, and the answer is more precise than either half of the old sentence.
We do not regenerate, normalise or repair your document. We forward the bytes you supplied, unchanged, to the network. That half is ours and it holds.
Byte-for-byte equality past that point is not guaranteed, because the network re-serialises the document in transit.
We reproduced it against the provider directly, with our own API out of the loop. On one test document, sent with four changes that alter the bytes without altering the XML:
| What we changed | What came back |
|---|---|
| namespace declarations reordered on indented lines | rewritten onto one line |
a numeric character reference A |
resolved to A |
| a space inside an open tag | dropped |
| deeper indentation between elements | kept |
That last row is the control. Indentation between elements is a text node, so a parser keeps it; the other two carry nothing a parser retains, so a parser drops them. Losing exactly those two is the signature of a faithful parse-and-re-serialise.
The content came through intact — 73 elements each side, same tags in the same order, not one text value different. What moved was 61 bytes of serialisation, of which 39 are the XML declaration that the Peppol envelope absorbs.
⚠️ That is one document and four kinds of difference. Read it as indicative, not as a warranty of what is preserved. Attributes, CDATA, comments and mixed content were not measured.
What to do if you seal your documents
Hash a canonical form (C14N) rather than the raw bytes. Your digest then survives any provider's serialisation, which also makes your evidence independent of ours — a better property than the one we had promised you.
Why our own measurement missed it
Worth saying plainly, because the mistake is easy to repeat.
We had measured byte preservation and got an identical SHA-256. But the test document had been generated by the provider itself, so it was already in the shape the serialiser emits — and an idempotent normaliser passes that test with full marks. The measurement was real; the conclusion we drew from it was not.
We had also taken & coming back as & as proof that nothing was re-serialised. A serialiser has to re-emit & that way, so that observation could never have told us anything. Only a non-mandatory entity discriminates.
Upgrading
npm install @getpeppr/sdk@4.1.1
No runtime change, no migration. If you are on 4.1.0 and you do not seal documents, nothing about your integration is affected.