@stackforge-eu/factur-x 1.0.6 → 1.0.7

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 CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.7] — 2026-05-27
11
+
12
+ - **`fx:ConformanceLevel` in the XMP metadata used the raw `Profile` enum
13
+ identifier instead of the Factur-X / ZUGFeRD spec label.** The XMP packet
14
+ emitted `EN16931` / `BASIC_WL` where the spec requires `EN 16931` /
15
+ `BASIC WL`, so strict ZUGFeRD / Factur-X validators (Mustangproject, the
16
+ FNFE-MPE check tool, veraPDF's Factur-X profile) rejected every PDF this
17
+ library produced even though the embedded CII XML was correct. Added a
18
+ `Profile` → XMP-label mapping and routed `buildXmpMetadata` through it in
19
+ `src/core/embed.ts` (thanks @sco-indy, #2).
20
+ - **`flavor: Flavor.XRECHNUNG` still advertised `EN 16931` in the XMP packet.**
21
+ Hybrid XRechnung PDFs carry the EN16931 profile internally but per ZUGFeRD
22
+ 2.x §2.4.4 must declare `XRECHNUNG` as the conformance level so the KoSIT /
23
+ ZUGFeRD validators route them through the XRechnung schematron set rather
24
+ than the vanilla Factur-X one. `resolveXmpConformanceLevel` in
25
+ `src/core/embed.ts` now special-cases the XRechnung flavor; the existing
26
+ `toXRechnung` → XML flow is unaffected. Regression test added in
27
+ `tests/embed.test.ts` covering all five profiles and the XRechnung flavor.
28
+
10
29
  ## [1.0.6] — 2026-05-23
11
30
 
12
31
  - **`SpecifiedTradeSettlementPaymentMeans` emitted its child elements in the
@@ -94,6 +113,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
94
113
  - Deno compatibility test suite
95
114
 
96
115
  [Unreleased]: https://github.com/StackForge-EU/factur-x/commits/main
116
+ [1.0.7]: https://github.com/StackForge-EU/factur-x/compare/v1.0.6...v1.0.7
97
117
  [1.0.6]: https://github.com/StackForge-EU/factur-x/compare/v1.0.5...v1.0.6
98
118
  [1.0.5]: https://github.com/StackForge-EU/factur-x/compare/v1.0.4...v1.0.5
99
119
  [1.0.4]: https://github.com/StackForge-EU/factur-x/compare/v1.0.3...v1.0.4
package/dist/index.cjs CHANGED
@@ -1111,6 +1111,17 @@ var AF_RELATIONSHIP_MAP = {
1111
1111
  Data: pdfLib.AFRelationship.Data,
1112
1112
  Source: pdfLib.AFRelationship.Source
1113
1113
  };
1114
+ var XMP_CONFORMANCE_LEVEL = {
1115
+ ["MINIMUM" /* MINIMUM */]: "MINIMUM",
1116
+ ["BASIC_WL" /* BASIC_WL */]: "BASIC WL",
1117
+ ["BASIC" /* BASIC */]: "BASIC",
1118
+ ["EN16931" /* EN16931 */]: "EN 16931",
1119
+ ["EXTENDED" /* EXTENDED */]: "EXTENDED"
1120
+ };
1121
+ function resolveXmpConformanceLevel(profile, flavor) {
1122
+ if (flavor === "xrechnung" /* XRECHNUNG */) return "XRECHNUNG";
1123
+ return XMP_CONFORMANCE_LEVEL[profile];
1124
+ }
1114
1125
  function ensureOutputIntent(pdfDoc, iccBytes, identifier) {
1115
1126
  const existing = pdfDoc.catalog.lookup(pdfLib.PDFName.of("OutputIntents"));
1116
1127
  if (existing instanceof pdfLib.PDFArray && existing.size() > 0) return;
@@ -1375,7 +1386,7 @@ async function embedFacturX(options) {
1375
1386
  createDate: isoDate,
1376
1387
  modifyDate: isoDate,
1377
1388
  documentFileName: flavorConfig.attachmentFilename,
1378
- conformanceLevel: profile
1389
+ conformanceLevel: resolveXmpConformanceLevel(profile, flavor)
1379
1390
  });
1380
1391
  const xmpBytes = new TextEncoder().encode(xmpXml);
1381
1392
  const metadataStream = pdfDoc.context.stream(xmpBytes, {
package/dist/index.js CHANGED
@@ -1081,6 +1081,17 @@ var AF_RELATIONSHIP_MAP = {
1081
1081
  Data: AFRelationship.Data,
1082
1082
  Source: AFRelationship.Source
1083
1083
  };
1084
+ var XMP_CONFORMANCE_LEVEL = {
1085
+ ["MINIMUM" /* MINIMUM */]: "MINIMUM",
1086
+ ["BASIC_WL" /* BASIC_WL */]: "BASIC WL",
1087
+ ["BASIC" /* BASIC */]: "BASIC",
1088
+ ["EN16931" /* EN16931 */]: "EN 16931",
1089
+ ["EXTENDED" /* EXTENDED */]: "EXTENDED"
1090
+ };
1091
+ function resolveXmpConformanceLevel(profile, flavor) {
1092
+ if (flavor === "xrechnung" /* XRECHNUNG */) return "XRECHNUNG";
1093
+ return XMP_CONFORMANCE_LEVEL[profile];
1094
+ }
1084
1095
  function ensureOutputIntent(pdfDoc, iccBytes, identifier) {
1085
1096
  const existing = pdfDoc.catalog.lookup(PDFName.of("OutputIntents"));
1086
1097
  if (existing instanceof PDFArray && existing.size() > 0) return;
@@ -1345,7 +1356,7 @@ async function embedFacturX(options) {
1345
1356
  createDate: isoDate,
1346
1357
  modifyDate: isoDate,
1347
1358
  documentFileName: flavorConfig.attachmentFilename,
1348
- conformanceLevel: profile
1359
+ conformanceLevel: resolveXmpConformanceLevel(profile, flavor)
1349
1360
  });
1350
1361
  const xmpBytes = new TextEncoder().encode(xmpXml);
1351
1362
  const metadataStream = pdfDoc.context.stream(xmpBytes, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackforge-eu/factur-x",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
5
  "description": "Embed Factur-X, ZUGFeRD, and XRechnung structured invoice XML into PDF/A-3 documents",
6
6
  "keywords": [