@stackforge-eu/factur-x 1.2.0 → 1.2.1
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.
- package/CHANGELOG.md +13 -7
- package/dist/index.cjs +26 -10
- package/dist/index.js +27 -11
- package/package.json +20 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.1] — 2026-08-27
|
|
11
|
+
|
|
12
|
+
- Expanded npm `keywords` (e.g. `e-rechnung`, `pdfa`, `chorus-pro`, `un-cefact`,
|
|
13
|
+
spelling variants) so the package is easier to find on npm. No code changes.
|
|
14
|
+
|
|
10
15
|
## [1.2.0] — 2026-07-11
|
|
11
16
|
|
|
12
17
|
- **Updated to Factur-X 1.09 / ZUGFeRD 2.5** (spec dated 2026-06-10). Factur-X
|
|
@@ -70,12 +75,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
70
75
|
`ram:GlobalID` had the same defect as the party one)
|
|
71
76
|
- `LegalOrganizationInput.schemeID?: string` added (optional, mirrors the
|
|
72
77
|
conditional spec rule)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
Migration: `globalId: "4000001000005"` →
|
|
79
|
+
`globalId: { value: "4000001000005", schemeID: "0088" }` (and the analogous
|
|
80
|
+
rewrite for `standardIdentifier`). The new `IdentifierWithSchemeInput` type
|
|
81
|
+
is exported from `src/index.ts`. Regression test added in
|
|
82
|
+
`tests/xsd-validator.test.ts` that drives all three schemed identifiers
|
|
83
|
+
through the EN16931 XSD in one go (thanks @sco-indy, #4).
|
|
79
84
|
|
|
80
85
|
## [1.0.8] — 2026-05-27
|
|
81
86
|
|
|
@@ -122,7 +127,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
122
127
|
debtor account last. Any invoice combining a SEPA direct debit
|
|
123
128
|
(`payment.meansCode = "59"`) with `payment.debtorIban` plus a payee
|
|
124
129
|
IBAN/BIC failed XSD validation with `Element 'PayerPartyDebtorFinancialAccount':
|
|
125
|
-
|
|
130
|
+
This element is not expected`. Reordered the three blocks in
|
|
126
131
|
`src/core/xml-builder.ts`; regression test added in
|
|
127
132
|
`tests/xml-builder.test.ts`.
|
|
128
133
|
|
|
@@ -199,6 +204,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
199
204
|
- Deno compatibility test suite
|
|
200
205
|
|
|
201
206
|
[Unreleased]: https://github.com/StackForge-EU/factur-x/commits/main
|
|
207
|
+
[1.2.1]: https://github.com/StackForge-EU/factur-x/compare/v1.2.0...v1.2.1
|
|
202
208
|
[1.2.0]: https://github.com/StackForge-EU/factur-x/compare/v1.1.0...v1.2.0
|
|
203
209
|
[1.1.0]: https://github.com/StackForge-EU/factur-x/compare/v1.0.8...v1.1.0
|
|
204
210
|
[1.0.8]: https://github.com/StackForge-EU/factur-x/compare/v1.0.7...v1.0.8
|
package/dist/index.cjs
CHANGED
|
@@ -1100,26 +1100,42 @@ async function validateXsd(xml, profile, options) {
|
|
|
1100
1100
|
XmlValidateError,
|
|
1101
1101
|
xmlRegisterInputProvider,
|
|
1102
1102
|
xmlCleanupInputProvider,
|
|
1103
|
-
|
|
1103
|
+
openBuffer,
|
|
1104
|
+
readBuffer,
|
|
1105
|
+
closeBuffer
|
|
1104
1106
|
} = await import('libxml2-wasm');
|
|
1105
1107
|
const schemaDir = path__namespace.dirname(xsdPath);
|
|
1106
1108
|
const files = fs__namespace.readdirSync(schemaDir).filter((f) => f.endsWith(".xsd"));
|
|
1107
1109
|
const buffers = {};
|
|
1108
1110
|
for (const file of files) {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1111
|
+
buffers[file] = fs__namespace.readFileSync(path__namespace.join(schemaDir, file));
|
|
1112
|
+
}
|
|
1113
|
+
const schemaFileFor = (requested) => {
|
|
1114
|
+
const start = Math.max(requested.lastIndexOf("/"), requested.lastIndexOf("\\")) + 1;
|
|
1115
|
+
const segment = requested.slice(start);
|
|
1116
|
+
let name = segment;
|
|
1117
|
+
try {
|
|
1118
|
+
name = decodeURIComponent(segment);
|
|
1119
|
+
} catch {
|
|
1120
|
+
}
|
|
1121
|
+
return files.includes(name) ? name : void 0;
|
|
1122
|
+
};
|
|
1114
1123
|
xmlCleanupInputProvider();
|
|
1115
|
-
|
|
1116
|
-
|
|
1124
|
+
xmlRegisterInputProvider({
|
|
1125
|
+
match: (filename) => schemaFileFor(filename) !== void 0,
|
|
1126
|
+
open: (filename) => openBuffer(buffers[schemaFileFor(filename)]),
|
|
1127
|
+
read: readBuffer,
|
|
1128
|
+
close: (fd) => {
|
|
1129
|
+
closeBuffer(fd);
|
|
1130
|
+
return true;
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1117
1133
|
let xsdDoc;
|
|
1118
1134
|
let validator;
|
|
1119
1135
|
let xmlDoc;
|
|
1120
1136
|
try {
|
|
1121
1137
|
const xsdContent = fs__namespace.readFileSync(xsdPath, "utf-8");
|
|
1122
|
-
xsdDoc = XmlDocument.fromString(xsdContent, { url:
|
|
1138
|
+
xsdDoc = XmlDocument.fromString(xsdContent, { url: url.pathToFileURL(xsdPath).href });
|
|
1123
1139
|
validator = XsdValidator.fromDoc(xsdDoc);
|
|
1124
1140
|
xmlDoc = XmlDocument.fromString(xml);
|
|
1125
1141
|
validator.validate(xmlDoc);
|
|
@@ -1391,7 +1407,7 @@ async function embedFacturX(options) {
|
|
|
1391
1407
|
const xmlBytes = new TextEncoder().encode(xml);
|
|
1392
1408
|
const afRel = resolveAfRelationship(profile, options.afRelationship);
|
|
1393
1409
|
await pdfDoc.attach(xmlBytes, flavorConfig.attachmentFilename, {
|
|
1394
|
-
mimeType: "
|
|
1410
|
+
mimeType: "application/xml",
|
|
1395
1411
|
afRelationship: afRel,
|
|
1396
1412
|
description: "Factur-X Invoice"
|
|
1397
1413
|
});
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
3
|
+
import { pathToFileURL, fileURLToPath } from 'url';
|
|
4
4
|
import console from 'console';
|
|
5
5
|
import { createHash } from 'crypto';
|
|
6
6
|
import { AFRelationship, PDFDocument, PDFName, PDFArray, PDFDict, PDFStream, PDFRawStream, decodePDFRawStream, PDFString, PDFHexString, PDFRef } from 'pdf-lib';
|
|
@@ -1070,26 +1070,42 @@ async function validateXsd(xml, profile, options) {
|
|
|
1070
1070
|
XmlValidateError,
|
|
1071
1071
|
xmlRegisterInputProvider,
|
|
1072
1072
|
xmlCleanupInputProvider,
|
|
1073
|
-
|
|
1073
|
+
openBuffer,
|
|
1074
|
+
readBuffer,
|
|
1075
|
+
closeBuffer
|
|
1074
1076
|
} = await import('libxml2-wasm');
|
|
1075
1077
|
const schemaDir = path.dirname(xsdPath);
|
|
1076
1078
|
const files = fs.readdirSync(schemaDir).filter((f) => f.endsWith(".xsd"));
|
|
1077
1079
|
const buffers = {};
|
|
1078
1080
|
for (const file of files) {
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1081
|
+
buffers[file] = fs.readFileSync(path.join(schemaDir, file));
|
|
1082
|
+
}
|
|
1083
|
+
const schemaFileFor = (requested) => {
|
|
1084
|
+
const start = Math.max(requested.lastIndexOf("/"), requested.lastIndexOf("\\")) + 1;
|
|
1085
|
+
const segment = requested.slice(start);
|
|
1086
|
+
let name = segment;
|
|
1087
|
+
try {
|
|
1088
|
+
name = decodeURIComponent(segment);
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
return files.includes(name) ? name : void 0;
|
|
1092
|
+
};
|
|
1084
1093
|
xmlCleanupInputProvider();
|
|
1085
|
-
|
|
1086
|
-
|
|
1094
|
+
xmlRegisterInputProvider({
|
|
1095
|
+
match: (filename) => schemaFileFor(filename) !== void 0,
|
|
1096
|
+
open: (filename) => openBuffer(buffers[schemaFileFor(filename)]),
|
|
1097
|
+
read: readBuffer,
|
|
1098
|
+
close: (fd) => {
|
|
1099
|
+
closeBuffer(fd);
|
|
1100
|
+
return true;
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1087
1103
|
let xsdDoc;
|
|
1088
1104
|
let validator;
|
|
1089
1105
|
let xmlDoc;
|
|
1090
1106
|
try {
|
|
1091
1107
|
const xsdContent = fs.readFileSync(xsdPath, "utf-8");
|
|
1092
|
-
xsdDoc = XmlDocument.fromString(xsdContent, { url:
|
|
1108
|
+
xsdDoc = XmlDocument.fromString(xsdContent, { url: pathToFileURL(xsdPath).href });
|
|
1093
1109
|
validator = XsdValidator.fromDoc(xsdDoc);
|
|
1094
1110
|
xmlDoc = XmlDocument.fromString(xml);
|
|
1095
1111
|
validator.validate(xmlDoc);
|
|
@@ -1361,7 +1377,7 @@ async function embedFacturX(options) {
|
|
|
1361
1377
|
const xmlBytes = new TextEncoder().encode(xml);
|
|
1362
1378
|
const afRel = resolveAfRelationship(profile, options.afRelationship);
|
|
1363
1379
|
await pdfDoc.attach(xmlBytes, flavorConfig.attachmentFilename, {
|
|
1364
|
-
mimeType: "
|
|
1380
|
+
mimeType: "application/xml",
|
|
1365
1381
|
afRelationship: afRel,
|
|
1366
1382
|
description: "Factur-X Invoice"
|
|
1367
1383
|
});
|
package/package.json
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackforge-eu/factur-x",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Embed Factur-X, ZUGFeRD, and XRechnung structured invoice XML into PDF/A-3 documents",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"factur-x",
|
|
8
|
+
"facturx",
|
|
8
9
|
"zugferd",
|
|
9
10
|
"xrechnung",
|
|
11
|
+
"e-rechnung",
|
|
12
|
+
"chorus-pro",
|
|
10
13
|
"en16931",
|
|
14
|
+
"en-16931",
|
|
11
15
|
"cii",
|
|
16
|
+
"un-cefact",
|
|
17
|
+
"cross-industry-invoice",
|
|
12
18
|
"pdf",
|
|
19
|
+
"pdfa",
|
|
20
|
+
"pdf-a",
|
|
13
21
|
"pdf-a3",
|
|
22
|
+
"pdfa3",
|
|
23
|
+
"xmp",
|
|
14
24
|
"invoice",
|
|
15
25
|
"e-invoice",
|
|
16
26
|
"e-invoicing",
|
|
27
|
+
"einvoice",
|
|
28
|
+
"e-invoice-eu",
|
|
29
|
+
"electronic-invoice",
|
|
30
|
+
"b2g",
|
|
17
31
|
"eu",
|
|
18
|
-
"
|
|
32
|
+
"germany",
|
|
33
|
+
"france",
|
|
34
|
+
"xml",
|
|
35
|
+
"typescript",
|
|
36
|
+
"deno"
|
|
19
37
|
],
|
|
20
38
|
"license": "EUPL-1.2",
|
|
21
39
|
"author": "StackForge UG",
|