@stackforge-eu/factur-x 1.0.7 → 1.1.0

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,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.1.0] — 2026-05-27
11
+
12
+ - **BREAKING:** Every `ram:GlobalID` and the legal-organization `ram:ID` now
13
+ carry the `@schemeID` attribute required by EN 16931. The XSD-canonical CII
14
+ mapping makes the scheme mandatory on `ram:GlobalID` (BT-29-1 / BT-46-1 for
15
+ parties, BT-157-1 for line items) and conditional on
16
+ `ram:SpecifiedLegalOrganization/ram:ID` (BT-30-1 / BT-47-1); without these
17
+ attributes Mustang / KoSIT / veraPDF's Factur-X profile reject the invoice
18
+ even though the embedded CII looked superficially correct. Three input
19
+ fields changed:
20
+ - `TradePartyInput.globalId` is now `IdentifierWithSchemeInput`
21
+ (`{ value: string; schemeID: string }`) instead of a bare `string`
22
+ - `InvoiceLineInput.standardIdentifier` is now `IdentifierWithSchemeInput`
23
+ instead of a bare `string` (sibling fix on top of #4 — the line-item
24
+ `ram:GlobalID` had the same defect as the party one)
25
+ - `LegalOrganizationInput.schemeID?: string` added (optional, mirrors the
26
+ conditional spec rule)
27
+ Migration: `globalId: "4000001000005"` →
28
+ `globalId: { value: "4000001000005", schemeID: "0088" }` (and the analogous
29
+ rewrite for `standardIdentifier`). The new `IdentifierWithSchemeInput` type
30
+ is exported from `src/index.ts`. Regression test added in
31
+ `tests/xsd-validator.test.ts` that drives all three schemed identifiers
32
+ through the EN16931 XSD in one go (thanks @sco-indy, #4).
33
+
34
+ ## [1.0.8] — 2026-05-27
35
+
36
+ - **PDF trailer was missing the `/ID` entry required by PDF/A-3.** ISO 19005-3
37
+ (and PDF 1.7 §14.4) require the trailer dictionary to carry an `/ID` array of
38
+ two byte strings: the first immutable identifier of the original document,
39
+ the second updated on every modification. `pdf-lib` initializes
40
+ `trailerInfo = {}` and never writes one on save, so veraPDF and the FNFE-MPE
41
+ Factur-X profile rejected every PDF this library produced as non-conformant.
42
+ Added `ensureIdTrailer` in `src/core/embed.ts` which runs after the first
43
+ `pdfDoc.save()` when `addPdfA3Metadata` is on: it computes an MD5 over the
44
+ serialized bytes (per PDF 1.7 §14.4 — uniqueness, not cryptographic strength,
45
+ is what matters), preserves any pre-existing first identifier, and writes the
46
+ pair before re-saving. Regression tests added in `tests/embed.test.ts`
47
+ covering both the no-existing-trailer and existing-trailer paths (thanks
48
+ @sco-indy, #3).
49
+
10
50
  ## [1.0.7] — 2026-05-27
11
51
 
12
52
  - **`fx:ConformanceLevel` in the XMP metadata used the raw `Profile` enum
@@ -113,6 +153,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
113
153
  - Deno compatibility test suite
114
154
 
115
155
  [Unreleased]: https://github.com/StackForge-EU/factur-x/commits/main
156
+ [1.1.0]: https://github.com/StackForge-EU/factur-x/compare/v1.0.8...v1.1.0
157
+ [1.0.8]: https://github.com/StackForge-EU/factur-x/compare/v1.0.7...v1.0.8
116
158
  [1.0.7]: https://github.com/StackForge-EU/factur-x/compare/v1.0.6...v1.0.7
117
159
  [1.0.6]: https://github.com/StackForge-EU/factur-x/compare/v1.0.5...v1.0.6
118
160
  [1.0.5]: https://github.com/StackForge-EU/factur-x/compare/v1.0.4...v1.0.5
package/dist/index.cjs CHANGED
@@ -4,6 +4,7 @@ var fs = require('fs');
4
4
  var path = require('path');
5
5
  var url = require('url');
6
6
  var console = require('console');
7
+ var crypto = require('crypto');
7
8
  var pdfLib = require('pdf-lib');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -339,13 +340,21 @@ function buildParty(p, profile) {
339
340
  const ids = Array.isArray(p.id) ? p.id : [p.id];
340
341
  for (const id of ids) x += tag("ram:ID", escapeXml(id));
341
342
  }
342
- if (p.globalId) x += tag("ram:GlobalID", escapeXml(p.globalId));
343
+ if (p.globalId) {
344
+ x += tag("ram:GlobalID", escapeXml(p.globalId.value), { schemeID: p.globalId.schemeID });
345
+ }
343
346
  x += tag("ram:Name", escapeXml(p.name));
344
347
  if (p.description && atLeast(profile, "EN16931" /* EN16931 */))
345
348
  x += tag("ram:Description", escapeXml(p.description));
346
349
  if (p.legalOrganization) {
347
350
  let lo = "";
348
- if (p.legalOrganization.id) lo += tag("ram:ID", escapeXml(p.legalOrganization.id));
351
+ if (p.legalOrganization.id) {
352
+ lo += tag(
353
+ "ram:ID",
354
+ escapeXml(p.legalOrganization.id),
355
+ p.legalOrganization.schemeID ? { schemeID: p.legalOrganization.schemeID } : void 0
356
+ );
357
+ }
349
358
  if (p.legalOrganization.tradingName)
350
359
  lo += tag("ram:TradingBusinessName", escapeXml(p.legalOrganization.tradingName));
351
360
  x += tag("ram:SpecifiedLegalOrganization", lo);
@@ -373,7 +382,11 @@ function buildLineItem(line, profile) {
373
382
  let doc = tag("ram:LineID", escapeXml(line.id));
374
383
  if (line.note) doc += tag("ram:IncludedNote", tag("ram:Content", escapeXml(line.note)));
375
384
  let prod = "";
376
- if (line.standardIdentifier) prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier));
385
+ if (line.standardIdentifier) {
386
+ prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier.value), {
387
+ schemeID: line.standardIdentifier.schemeID
388
+ });
389
+ }
377
390
  if (line.sellerAssignedId) prod += tag("ram:SellerAssignedID", escapeXml(line.sellerAssignedId));
378
391
  if (line.buyerAssignedId) prod += tag("ram:BuyerAssignedID", escapeXml(line.buyerAssignedId));
379
392
  prod += tag("ram:Name", escapeXml(line.name));
@@ -1122,6 +1135,17 @@ function resolveXmpConformanceLevel(profile, flavor) {
1122
1135
  if (flavor === "xrechnung" /* XRECHNUNG */) return "XRECHNUNG";
1123
1136
  return XMP_CONFORMANCE_LEVEL[profile];
1124
1137
  }
1138
+ function ensureIdTrailer(pdfDoc, pdfContentBytes) {
1139
+ const existingIdTrailer = pdfDoc.context.trailerInfo.ID;
1140
+ const currentContentHash = pdfLib.PDFHexString.of(crypto.createHash("md5").update(pdfContentBytes).digest("hex"));
1141
+ const hasValidIdTrailer = existingIdTrailer instanceof pdfLib.PDFArray && existingIdTrailer.size() === 2;
1142
+ if (hasValidIdTrailer) {
1143
+ const existingFirstId = existingIdTrailer.lookup(0);
1144
+ pdfDoc.context.trailerInfo.ID = pdfDoc.context.obj([existingFirstId, currentContentHash]);
1145
+ } else {
1146
+ pdfDoc.context.trailerInfo.ID = pdfDoc.context.obj([currentContentHash, currentContentHash]);
1147
+ }
1148
+ }
1125
1149
  function ensureOutputIntent(pdfDoc, iccBytes, identifier) {
1126
1150
  const existing = pdfDoc.catalog.lookup(pdfLib.PDFName.of("OutputIntents"));
1127
1151
  if (existing instanceof pdfLib.PDFArray && existing.size() > 0) return;
@@ -1397,9 +1421,13 @@ async function embedFacturX(options) {
1397
1421
  const metadataRef = pdfDoc.context.register(metadataStream);
1398
1422
  pdfDoc.catalog.set(pdfLib.PDFName.of("Metadata"), metadataRef);
1399
1423
  }
1400
- const resultPdf = await pdfDoc.save();
1424
+ let pdfContentBytes = await pdfDoc.save();
1425
+ if (addPdfA3Metadata) {
1426
+ ensureIdTrailer(pdfDoc, pdfContentBytes);
1427
+ pdfContentBytes = await pdfDoc.save();
1428
+ }
1401
1429
  return {
1402
- pdf: resultPdf,
1430
+ pdf: pdfContentBytes,
1403
1431
  xml,
1404
1432
  ...validation ? { validation } : {},
1405
1433
  ...xsdValidation ? { xsdValidation } : {}
package/dist/index.d.cts CHANGED
@@ -448,9 +448,18 @@ interface TaxRegistrationInput {
448
448
  interface LegalOrganizationInput {
449
449
  /** Registration identifier */
450
450
  id?: string;
451
+ /** Registration identifier scheme (ICD code list value, e.g. `"0002"` for SIRENE) */
452
+ schemeID?: string;
451
453
  /** Trading business name */
452
454
  tradingName?: string;
453
455
  }
456
+ /**
457
+ * Identifier value with its scheme identifier.
458
+ */
459
+ interface IdentifierWithSchemeInput {
460
+ value: string;
461
+ schemeID: string;
462
+ }
454
463
  /**
455
464
  * Trade party (seller, buyer, payee, etc.).
456
465
  *
@@ -468,10 +477,14 @@ interface TradePartyInput {
468
477
  */
469
478
  id?: string | string[];
470
479
  /**
471
- * Global identifier with scheme (e.g. GLN `"0088:1234567890123"`).
480
+ * Global identifier with scheme (e.g. GLN value `"4000001000005"` and
481
+ * ICD scheme `"0088"`).
482
+ *
483
+ * `schemeID` is required by EN 16931 for `ram:GlobalID`.
484
+ *
472
485
  * @see EN 16931 BT-29-1 / BT-46-1
473
486
  */
474
- globalId?: string;
487
+ globalId?: IdentifierWithSchemeInput;
475
488
  /** Postal address — mandatory for BASIC_WL and above */
476
489
  address?: AddressInput;
477
490
  /**
@@ -581,10 +594,14 @@ interface InvoiceLineInput {
581
594
  */
582
595
  description?: string;
583
596
  /**
584
- * Item standard identifier (e.g. GTIN/EAN).
597
+ * Item standard identifier (e.g. GTIN value `"4012345678901"` and ICD
598
+ * scheme `"0160"` for GS1).
599
+ *
600
+ * `schemeID` is required by EN 16931 for `ram:GlobalID` (BT-157-1).
601
+ *
585
602
  * @see EN 16931 BT-157
586
603
  */
587
- standardIdentifier?: string;
604
+ standardIdentifier?: IdentifierWithSchemeInput;
588
605
  /**
589
606
  * Seller-assigned item identifier.
590
607
  * @see EN 16931 BT-155
@@ -1435,4 +1452,4 @@ interface XRechnungResult {
1435
1452
  */
1436
1453
  declare function toXRechnung(input: FacturXInvoiceInput, options?: XRechnungOptions): XRechnungResult;
1437
1454
 
1438
- export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, Flavor, type FlavorConfig, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
1455
+ export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, Flavor, type FlavorConfig, type IdentifierWithSchemeInput, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
package/dist/index.d.ts CHANGED
@@ -448,9 +448,18 @@ interface TaxRegistrationInput {
448
448
  interface LegalOrganizationInput {
449
449
  /** Registration identifier */
450
450
  id?: string;
451
+ /** Registration identifier scheme (ICD code list value, e.g. `"0002"` for SIRENE) */
452
+ schemeID?: string;
451
453
  /** Trading business name */
452
454
  tradingName?: string;
453
455
  }
456
+ /**
457
+ * Identifier value with its scheme identifier.
458
+ */
459
+ interface IdentifierWithSchemeInput {
460
+ value: string;
461
+ schemeID: string;
462
+ }
454
463
  /**
455
464
  * Trade party (seller, buyer, payee, etc.).
456
465
  *
@@ -468,10 +477,14 @@ interface TradePartyInput {
468
477
  */
469
478
  id?: string | string[];
470
479
  /**
471
- * Global identifier with scheme (e.g. GLN `"0088:1234567890123"`).
480
+ * Global identifier with scheme (e.g. GLN value `"4000001000005"` and
481
+ * ICD scheme `"0088"`).
482
+ *
483
+ * `schemeID` is required by EN 16931 for `ram:GlobalID`.
484
+ *
472
485
  * @see EN 16931 BT-29-1 / BT-46-1
473
486
  */
474
- globalId?: string;
487
+ globalId?: IdentifierWithSchemeInput;
475
488
  /** Postal address — mandatory for BASIC_WL and above */
476
489
  address?: AddressInput;
477
490
  /**
@@ -581,10 +594,14 @@ interface InvoiceLineInput {
581
594
  */
582
595
  description?: string;
583
596
  /**
584
- * Item standard identifier (e.g. GTIN/EAN).
597
+ * Item standard identifier (e.g. GTIN value `"4012345678901"` and ICD
598
+ * scheme `"0160"` for GS1).
599
+ *
600
+ * `schemeID` is required by EN 16931 for `ram:GlobalID` (BT-157-1).
601
+ *
585
602
  * @see EN 16931 BT-157
586
603
  */
587
- standardIdentifier?: string;
604
+ standardIdentifier?: IdentifierWithSchemeInput;
588
605
  /**
589
606
  * Seller-assigned item identifier.
590
607
  * @see EN 16931 BT-155
@@ -1435,4 +1452,4 @@ interface XRechnungResult {
1435
1452
  */
1436
1453
  declare function toXRechnung(input: FacturXInvoiceInput, options?: XRechnungOptions): XRechnungResult;
1437
1454
 
1438
- export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, Flavor, type FlavorConfig, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
1455
+ export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, Flavor, type FlavorConfig, type IdentifierWithSchemeInput, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import console from 'console';
5
- import { AFRelationship, PDFDocument, PDFName, PDFArray, PDFDict, PDFStream, PDFRawStream, decodePDFRawStream, PDFString, PDFRef, PDFHexString } from 'pdf-lib';
5
+ import { createHash } from 'crypto';
6
+ import { AFRelationship, PDFDocument, PDFName, PDFArray, PDFDict, PDFStream, PDFRawStream, decodePDFRawStream, PDFString, PDFHexString, PDFRef } from 'pdf-lib';
6
7
 
7
8
  // src/types/input.ts
8
9
  var DocumentTypeCode = /* @__PURE__ */ ((DocumentTypeCode2) => {
@@ -309,13 +310,21 @@ function buildParty(p, profile) {
309
310
  const ids = Array.isArray(p.id) ? p.id : [p.id];
310
311
  for (const id of ids) x += tag("ram:ID", escapeXml(id));
311
312
  }
312
- if (p.globalId) x += tag("ram:GlobalID", escapeXml(p.globalId));
313
+ if (p.globalId) {
314
+ x += tag("ram:GlobalID", escapeXml(p.globalId.value), { schemeID: p.globalId.schemeID });
315
+ }
313
316
  x += tag("ram:Name", escapeXml(p.name));
314
317
  if (p.description && atLeast(profile, "EN16931" /* EN16931 */))
315
318
  x += tag("ram:Description", escapeXml(p.description));
316
319
  if (p.legalOrganization) {
317
320
  let lo = "";
318
- if (p.legalOrganization.id) lo += tag("ram:ID", escapeXml(p.legalOrganization.id));
321
+ if (p.legalOrganization.id) {
322
+ lo += tag(
323
+ "ram:ID",
324
+ escapeXml(p.legalOrganization.id),
325
+ p.legalOrganization.schemeID ? { schemeID: p.legalOrganization.schemeID } : void 0
326
+ );
327
+ }
319
328
  if (p.legalOrganization.tradingName)
320
329
  lo += tag("ram:TradingBusinessName", escapeXml(p.legalOrganization.tradingName));
321
330
  x += tag("ram:SpecifiedLegalOrganization", lo);
@@ -343,7 +352,11 @@ function buildLineItem(line, profile) {
343
352
  let doc = tag("ram:LineID", escapeXml(line.id));
344
353
  if (line.note) doc += tag("ram:IncludedNote", tag("ram:Content", escapeXml(line.note)));
345
354
  let prod = "";
346
- if (line.standardIdentifier) prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier));
355
+ if (line.standardIdentifier) {
356
+ prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier.value), {
357
+ schemeID: line.standardIdentifier.schemeID
358
+ });
359
+ }
347
360
  if (line.sellerAssignedId) prod += tag("ram:SellerAssignedID", escapeXml(line.sellerAssignedId));
348
361
  if (line.buyerAssignedId) prod += tag("ram:BuyerAssignedID", escapeXml(line.buyerAssignedId));
349
362
  prod += tag("ram:Name", escapeXml(line.name));
@@ -1092,6 +1105,17 @@ function resolveXmpConformanceLevel(profile, flavor) {
1092
1105
  if (flavor === "xrechnung" /* XRECHNUNG */) return "XRECHNUNG";
1093
1106
  return XMP_CONFORMANCE_LEVEL[profile];
1094
1107
  }
1108
+ function ensureIdTrailer(pdfDoc, pdfContentBytes) {
1109
+ const existingIdTrailer = pdfDoc.context.trailerInfo.ID;
1110
+ const currentContentHash = PDFHexString.of(createHash("md5").update(pdfContentBytes).digest("hex"));
1111
+ const hasValidIdTrailer = existingIdTrailer instanceof PDFArray && existingIdTrailer.size() === 2;
1112
+ if (hasValidIdTrailer) {
1113
+ const existingFirstId = existingIdTrailer.lookup(0);
1114
+ pdfDoc.context.trailerInfo.ID = pdfDoc.context.obj([existingFirstId, currentContentHash]);
1115
+ } else {
1116
+ pdfDoc.context.trailerInfo.ID = pdfDoc.context.obj([currentContentHash, currentContentHash]);
1117
+ }
1118
+ }
1095
1119
  function ensureOutputIntent(pdfDoc, iccBytes, identifier) {
1096
1120
  const existing = pdfDoc.catalog.lookup(PDFName.of("OutputIntents"));
1097
1121
  if (existing instanceof PDFArray && existing.size() > 0) return;
@@ -1367,9 +1391,13 @@ async function embedFacturX(options) {
1367
1391
  const metadataRef = pdfDoc.context.register(metadataStream);
1368
1392
  pdfDoc.catalog.set(PDFName.of("Metadata"), metadataRef);
1369
1393
  }
1370
- const resultPdf = await pdfDoc.save();
1394
+ let pdfContentBytes = await pdfDoc.save();
1395
+ if (addPdfA3Metadata) {
1396
+ ensureIdTrailer(pdfDoc, pdfContentBytes);
1397
+ pdfContentBytes = await pdfDoc.save();
1398
+ }
1371
1399
  return {
1372
- pdf: resultPdf,
1400
+ pdf: pdfContentBytes,
1373
1401
  xml,
1374
1402
  ...validation ? { validation } : {},
1375
1403
  ...xsdValidation ? { xsdValidation } : {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackforge-eu/factur-x",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Embed Factur-X, ZUGFeRD, and XRechnung structured invoice XML into PDF/A-3 documents",
6
6
  "keywords": [