@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 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
- Migration: `globalId: "4000001000005"` →
74
- `globalId: { value: "4000001000005", schemeID: "0088" }` (and the analogous
75
- rewrite for `standardIdentifier`). The new `IdentifierWithSchemeInput` type
76
- is exported from `src/index.ts`. Regression test added in
77
- `tests/xsd-validator.test.ts` that drives all three schemed identifiers
78
- through the EN16931 XSD in one go (thanks @sco-indy, #4).
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
- This element is not expected`. Reordered the three blocks in
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
- XmlBufferInputProvider
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
- const filePath = path__namespace.join(schemaDir, file);
1110
- buffers[filePath] = fs__namespace.readFileSync(filePath);
1111
- buffers[`file://${filePath}`] = buffers[filePath];
1112
- buffers[file] = buffers[filePath];
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
- const provider = new XmlBufferInputProvider(buffers);
1116
- xmlRegisterInputProvider(provider);
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: `file://${xsdPath}` });
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: "text/xml",
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
- XmlBufferInputProvider
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
- const filePath = path.join(schemaDir, file);
1080
- buffers[filePath] = fs.readFileSync(filePath);
1081
- buffers[`file://${filePath}`] = buffers[filePath];
1082
- buffers[file] = buffers[filePath];
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
- const provider = new XmlBufferInputProvider(buffers);
1086
- xmlRegisterInputProvider(provider);
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: `file://${xsdPath}` });
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: "text/xml",
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.0",
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
- "xml"
32
+ "germany",
33
+ "france",
34
+ "xml",
35
+ "typescript",
36
+ "deno"
19
37
  ],
20
38
  "license": "EUPL-1.2",
21
39
  "author": "StackForge UG",