@ekwo-ai/factur-x 0.4.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rounding.js","sourceRoot":"","sources":["../src/rounding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,QAAQ,GAAG,CAAC;IACvD,MAAM,MAAM,GAAG,EAAE,IAAI,QAAQ,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IACxC,0EAA0E;IAC1E,4EAA4E;IAC5E,iDAAiD;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;IAC7D,qEAAqE;IACrE,sCAAsC;IACtC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Invoice, InvoiceLine, InvoiceTotals, VatCategory } from './types.js';
2
+ /** The one rounding rule, at two decimals. See `rounding.ts`. */
3
+ export declare function round2(v: number): number;
4
+ /** The VAT category of a line, explicit or derived from the parties. */
5
+ export declare function lineVatCategory(line: InvoiceLine, invoice: Invoice): VatCategory;
6
+ /** Line net amount (BT-131): explicit, or quantity × unit price rounded to the cent. */
7
+ export declare function lineNetAmount(line: InvoiceLine): number;
8
+ /**
9
+ * VAT breakdown and document totals, computed the way EN 16931 expects them:
10
+ * one group per category and rate, VAT computed on the rounded group basis.
11
+ */
12
+ export declare function computeTotals(invoice: Invoice): InvoiceTotals;
13
+ //# sourceMappingURL=totals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"totals.d.ts","sourceRoot":"","sources":["../src/totals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAC;AAIjG,iEAAiE;AACjE,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAExC;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW,CAUhF;AAED,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CA6B7D"}
package/dist/totals.js ADDED
@@ -0,0 +1,55 @@
1
+ import { roundCurrency } from './rounding.js';
2
+ import { defaultVatCategory } from './vat.js';
3
+ /** The one rounding rule, at two decimals. See `rounding.ts`. */
4
+ export function round2(v) {
5
+ return roundCurrency(v, 2);
6
+ }
7
+ /** The VAT category of a line, explicit or derived from the parties. */
8
+ export function lineVatCategory(line, invoice) {
9
+ return (line.vatCategory ??
10
+ defaultVatCategory({
11
+ rate: line.vatRate,
12
+ sellerCountry: invoice.seller.address.country,
13
+ buyerCountry: invoice.buyer.address.country,
14
+ buyerHasVatId: !!invoice.buyer.vatId,
15
+ }));
16
+ }
17
+ /** Line net amount (BT-131): explicit, or quantity × unit price rounded to the cent. */
18
+ export function lineNetAmount(line) {
19
+ return round2(line.netAmount ?? line.quantity * line.unitPrice);
20
+ }
21
+ /**
22
+ * VAT breakdown and document totals, computed the way EN 16931 expects them:
23
+ * one group per category and rate, VAT computed on the rounded group basis.
24
+ */
25
+ export function computeTotals(invoice) {
26
+ const groups = new Map();
27
+ let lineTotal = 0;
28
+ for (const line of invoice.lines) {
29
+ const category = lineVatCategory(line, invoice);
30
+ const rate = category === 'S' ? line.vatRate : 0;
31
+ const net = lineNetAmount(line);
32
+ lineTotal = round2(lineTotal + net);
33
+ const key = `${category}:${rate}`;
34
+ const group = groups.get(key) ?? { category, rate, basis: 0, tax: 0 };
35
+ group.basis = round2(group.basis + net);
36
+ groups.set(key, group);
37
+ }
38
+ let taxTotal = 0;
39
+ for (const group of groups.values()) {
40
+ group.tax = round2((group.basis * group.rate) / 100);
41
+ taxTotal = round2(taxTotal + group.tax);
42
+ }
43
+ const grandTotal = round2(lineTotal + taxTotal);
44
+ const prepaid = round2(invoice.prepaidAmount ?? 0);
45
+ return {
46
+ lineTotal,
47
+ taxBasisTotal: lineTotal,
48
+ taxTotal,
49
+ grandTotal,
50
+ prepaid,
51
+ duePayable: round2(grandTotal - prepaid),
52
+ breakdown: [...groups.values()],
53
+ };
54
+ }
55
+ //# sourceMappingURL=totals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"totals.js","sourceRoot":"","sources":["../src/totals.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C,iEAAiE;AACjE,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,OAAO,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,IAAiB,EAAE,OAAgB;IACjE,OAAO,CACL,IAAI,CAAC,WAAW;QAChB,kBAAkB,CAAC;YACjB,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO;YAC7C,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;YAC3C,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;SACrC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC/C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAChC,SAAS,GAAG,MAAM,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QACtE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACrD,QAAQ,GAAG,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC;IACnD,OAAO;QACL,SAAS;QACT,aAAa,EAAE,SAAS;QACxB,QAAQ;QACR,UAAU;QACV,OAAO;QACP,UAAU,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC;QACxC,SAAS,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;KAChC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Public types of `@ekwo-ai/factur-x`. The invoice model is deliberately
3
+ * small and neutral: it maps one-to-one to the EN 16931 semantic model
4
+ * without carrying any application-specific field.
5
+ */
6
+ /** ISO-8601 calendar date, `YYYY-MM-DD`. */
7
+ export type IsoDate = string;
8
+ /** ISO 4217 currency code, e.g. `"EUR"`. */
9
+ export type CurrencyCode = string;
10
+ /**
11
+ * VAT category codes of EN 16931 (UNTDID 5305 subset).
12
+ * - `S` standard rate
13
+ * - `Z` zero rated
14
+ * - `E` exempt
15
+ * - `AE` reverse charge
16
+ * - `K` intra-community supply
17
+ * - `G` export outside the EU
18
+ * - `O` not subject to VAT
19
+ */
20
+ export type VatCategory = 'S' | 'Z' | 'E' | 'AE' | 'K' | 'G' | 'O';
21
+ /**
22
+ * Factur-X / ZUGFeRD conformance levels. The generator emits the same
23
+ * structure for `basic` and `en16931`; the level only changes the guideline
24
+ * identifier in the XML and the XMP metadata of the PDF.
25
+ */
26
+ export type Profile = 'minimum' | 'basic-wl' | 'basic' | 'en16931' | 'extended';
27
+ /** Document type codes of UNTDID 1001 accepted by Factur-X. */
28
+ export type DocumentType = 'invoice' | 'credit-note' | 'corrected-invoice' | 'self-billed-invoice' | 'prepayment-invoice';
29
+ export interface PostalAddress {
30
+ line1: string;
31
+ line2?: string;
32
+ line3?: string;
33
+ postalCode: string;
34
+ city: string;
35
+ /** ISO 3166-1 alpha-2. */
36
+ country: string;
37
+ /** Region, province, state. */
38
+ subdivision?: string;
39
+ }
40
+ /**
41
+ * Legal registration identifier with its ISO 6523 ICD scheme
42
+ * (`"0002"` SIREN/SIRET, `"0208"` Belgian enterprise number, `"0009"` SIRET…).
43
+ */
44
+ export interface LegalIdentifier {
45
+ scheme: string;
46
+ value: string;
47
+ }
48
+ export interface Party {
49
+ name: string;
50
+ address: PostalAddress;
51
+ /** VAT identifier with country prefix, e.g. `"BE0123456749"`. */
52
+ vatId?: string;
53
+ /** Legal registration identifier (BT-30 / BT-47). */
54
+ legalId?: LegalIdentifier;
55
+ /** Electronic address (BT-34 / BT-49), e.g. an e-mail. */
56
+ electronicAddress?: {
57
+ scheme: string;
58
+ value: string;
59
+ };
60
+ /** Contact person (BG-6 / BG-9). */
61
+ contact?: {
62
+ name?: string;
63
+ phone?: string;
64
+ email?: string;
65
+ };
66
+ }
67
+ export interface InvoiceLine {
68
+ /** Line identifier (BT-126). Defaults to the 1-based position. */
69
+ id?: string;
70
+ /** Item name (BT-153). */
71
+ name: string;
72
+ /** Item description (BT-154). */
73
+ description?: string;
74
+ /** Invoiced quantity (BT-129). */
75
+ quantity: number;
76
+ /** UN/ECE Recommendation 20 unit code (BT-130). Defaults to `"C62"` (unit). */
77
+ unitCode?: string;
78
+ /** Net unit price, excluding VAT (BT-146). */
79
+ unitPrice: number;
80
+ /** VAT rate in percent (BT-152), e.g. `21`. */
81
+ vatRate: number;
82
+ /** VAT category (BT-151). Derived from the rate and the parties when omitted. */
83
+ vatCategory?: VatCategory;
84
+ /** Line net amount (BT-131). Defaults to `quantity × unitPrice`, rounded to the cent. */
85
+ netAmount?: number;
86
+ /** Line note (BT-127). */
87
+ note?: string;
88
+ /** Seller item identifier (BT-155). */
89
+ sellerItemId?: string;
90
+ }
91
+ export interface PaymentInstructions {
92
+ /** UNTDID 4461 code (BT-81). Defaults to `"58"` (SEPA credit transfer) when an IBAN is given. */
93
+ meansCode?: string;
94
+ /** Payee IBAN (BT-84). */
95
+ iban?: string;
96
+ /** Payee BIC (BT-86). Omitted from the XML below the EN 16931 level. */
97
+ bic?: string;
98
+ /** Remittance information (BT-83). */
99
+ reference?: string;
100
+ /** Free-text payment terms (BT-20). */
101
+ terms?: string;
102
+ }
103
+ export interface Invoice {
104
+ /** Invoice number (BT-1). */
105
+ number: string;
106
+ /** Defaults to `"invoice"`. */
107
+ type?: DocumentType;
108
+ /** Issue date (BT-2). */
109
+ issueDate: IsoDate;
110
+ /** Payment due date (BT-9). */
111
+ dueDate?: IsoDate;
112
+ /** Actual delivery date (BT-72). Defaults to the issue date. */
113
+ deliveryDate?: IsoDate;
114
+ /** Invoice currency (BT-5). Defaults to `"EUR"`. */
115
+ currency?: CurrencyCode;
116
+ seller: Party;
117
+ buyer: Party;
118
+ lines: InvoiceLine[];
119
+ /** Buyer reference (BT-10), e.g. the French « service exécutant » code. */
120
+ buyerReference?: string;
121
+ /** Purchase order reference (BT-13). */
122
+ orderReference?: string;
123
+ /** Contract reference (BT-12). */
124
+ contractReference?: string;
125
+ /** Invoice being corrected or credited (BG-3). */
126
+ precedingInvoice?: {
127
+ number: string;
128
+ issueDate?: IsoDate;
129
+ };
130
+ /** Invoice note (BT-22). */
131
+ note?: string;
132
+ payment?: PaymentInstructions;
133
+ /** Amount already paid (BT-113). */
134
+ prepaidAmount?: number;
135
+ /**
136
+ * Overrides the reason texts attached to exempt VAT categories (BT-120).
137
+ * Defaults are neutral English sentences; see {@link DEFAULT_EXEMPTION_REASONS}.
138
+ */
139
+ exemptionReasons?: Partial<Record<Exclude<VatCategory, 'S' | 'Z'>, string>>;
140
+ }
141
+ export interface VatBreakdown {
142
+ category: VatCategory;
143
+ rate: number;
144
+ /** Sum of the line net amounts in this group (BT-116). */
145
+ basis: number;
146
+ /** VAT amount of the group (BT-117). */
147
+ tax: number;
148
+ }
149
+ export interface InvoiceTotals {
150
+ /** Sum of line net amounts (BT-106). */
151
+ lineTotal: number;
152
+ /** Taxable amount (BT-109). */
153
+ taxBasisTotal: number;
154
+ /** Total VAT (BT-110). */
155
+ taxTotal: number;
156
+ /** Amount with VAT (BT-112). */
157
+ grandTotal: number;
158
+ /** Amount already paid (BT-113). */
159
+ prepaid: number;
160
+ /** Amount due for payment (BT-115). */
161
+ duePayable: number;
162
+ breakdown: VatBreakdown[];
163
+ }
164
+ export interface GenerateOptions {
165
+ /** Defaults to `"basic"`, the widest-supported level. */
166
+ profile?: Profile;
167
+ /** Business process identifier (BT-23). Defaults to `"A1"`. */
168
+ businessProcess?: string;
169
+ }
170
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEnE;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAEhF,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,aAAa,GAAG,mBAAmB,GAAG,qBAAqB,GAAG,oBAAoB,CAAC;AAE1H,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,aAAa,CAAC;IACvB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,oCAAoC;IACpC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,yFAAyF;IACzF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,yBAAyB;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,gBAAgB,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3D,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,GAAG,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,WAAW,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Public types of `@ekwo-ai/factur-x`. The invoice model is deliberately
3
+ * small and neutral: it maps one-to-one to the EN 16931 semantic model
4
+ * without carrying any application-specific field.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * UN/ECE Recommendation 20 unit codes, and a lenient mapping from the words
3
+ * people type on invoices (FR / NL / EN / DE).
4
+ */
5
+ export declare const UNIT_CODES: {
6
+ readonly UNIT: "C62";
7
+ readonly PIECE: "H87";
8
+ readonly HOUR: "HUR";
9
+ readonly DAY: "DAY";
10
+ readonly WEEK: "WEE";
11
+ readonly MONTH: "MON";
12
+ readonly YEAR: "ANN";
13
+ readonly KILOGRAM: "KGM";
14
+ readonly GRAM: "GRM";
15
+ readonly TONNE: "TNE";
16
+ readonly LITRE: "LTR";
17
+ readonly METRE: "MTR";
18
+ readonly SQUARE_METRE: "MTK";
19
+ readonly CUBIC_METRE: "MTQ";
20
+ readonly KILOMETRE: "KMT";
21
+ readonly KILOWATT_HOUR: "KWH";
22
+ readonly MEGAWATT_HOUR: "MWH";
23
+ readonly LOT: "LO";
24
+ readonly SET: "SET";
25
+ readonly PACKAGE: "XPK";
26
+ };
27
+ /**
28
+ * Returns the UN/ECE code for a unit written in words, passes a three-letter
29
+ * code through, and falls back to `C62` (unit).
30
+ */
31
+ export declare function toUnitCode(unit: string | null | undefined): string;
32
+ //# sourceMappingURL=units.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.d.ts","sourceRoot":"","sources":["../src/units.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CAqBb,CAAC;AAsBX;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAOlE"}
package/dist/units.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * UN/ECE Recommendation 20 unit codes, and a lenient mapping from the words
3
+ * people type on invoices (FR / NL / EN / DE).
4
+ */
5
+ export const UNIT_CODES = {
6
+ UNIT: 'C62',
7
+ PIECE: 'H87',
8
+ HOUR: 'HUR',
9
+ DAY: 'DAY',
10
+ WEEK: 'WEE',
11
+ MONTH: 'MON',
12
+ YEAR: 'ANN',
13
+ KILOGRAM: 'KGM',
14
+ GRAM: 'GRM',
15
+ TONNE: 'TNE',
16
+ LITRE: 'LTR',
17
+ METRE: 'MTR',
18
+ SQUARE_METRE: 'MTK',
19
+ CUBIC_METRE: 'MTQ',
20
+ KILOMETRE: 'KMT',
21
+ KILOWATT_HOUR: 'KWH',
22
+ MEGAWATT_HOUR: 'MWH',
23
+ LOT: 'LO',
24
+ SET: 'SET',
25
+ PACKAGE: 'XPK',
26
+ };
27
+ const WORDS = {
28
+ // hours
29
+ h: 'HUR', hr: 'HUR', hour: 'HUR', hours: 'HUR', heure: 'HUR', heures: 'HUR', uur: 'HUR', uren: 'HUR', stunde: 'HUR', stunden: 'HUR',
30
+ // days
31
+ d: 'DAY', j: 'DAY', day: 'DAY', days: 'DAY', jour: 'DAY', jours: 'DAY', dag: 'DAY', dagen: 'DAY', tag: 'DAY', tage: 'DAY',
32
+ // weeks, months, years
33
+ week: 'WEE', weeks: 'WEE', semaine: 'WEE', semaines: 'WEE', weken: 'WEE', woche: 'WEE',
34
+ month: 'MON', months: 'MON', mois: 'MON', maand: 'MON', maanden: 'MON', monat: 'MON', monate: 'MON',
35
+ year: 'ANN', years: 'ANN', an: 'ANN', ans: 'ANN', année: 'ANN', années: 'ANN', jaar: 'ANN', jahr: 'ANN',
36
+ // mass, volume, length, area
37
+ kg: 'KGM', kilo: 'KGM', g: 'GRM', t: 'TNE', tonne: 'TNE', l: 'LTR', litre: 'LTR', liter: 'LTR',
38
+ m: 'MTR', km: 'KMT', m2: 'MTK', 'm²': 'MTK', m3: 'MTQ', 'm³': 'MTQ',
39
+ // energy
40
+ kwh: 'KWH', mwh: 'MWH',
41
+ // counting
42
+ unit: 'C62', units: 'C62', unité: 'C62', unités: 'C62', eenheid: 'C62', stück: 'C62', stk: 'C62',
43
+ piece: 'H87', pieces: 'H87', pièce: 'H87', pièces: 'H87', pc: 'H87', pcs: 'H87', stuk: 'H87', stuks: 'H87',
44
+ lot: 'LO', set: 'SET', package: 'XPK', colis: 'XPK', pak: 'XPK',
45
+ };
46
+ /**
47
+ * Returns the UN/ECE code for a unit written in words, passes a three-letter
48
+ * code through, and falls back to `C62` (unit).
49
+ */
50
+ export function toUnitCode(unit) {
51
+ if (!unit)
52
+ return UNIT_CODES.UNIT;
53
+ const key = unit.trim().toLowerCase();
54
+ const mapped = WORDS[key];
55
+ if (mapped)
56
+ return mapped;
57
+ if (/^[A-Z0-9]{2,3}$/.test(unit.trim()))
58
+ return unit.trim();
59
+ return UNIT_CODES.UNIT;
60
+ }
61
+ //# sourceMappingURL=units.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.js","sourceRoot":"","sources":["../src/units.ts"],"names":[],"mappings":"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"}
package/dist/vat.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { VatCategory } from './types.js';
2
+ /** EU member states, ISO 3166-1 alpha-2. */
3
+ export declare const EU_COUNTRIES: ReadonlySet<string>;
4
+ export declare function isEuCountry(code: string): boolean;
5
+ /**
6
+ * Picks the VAT category of a line when the caller does not state it.
7
+ * Positive rate → standard. Zero rate: domestic → zero-rated; EU buyer with a
8
+ * VAT identifier → intra-community supply; EU buyer without → exempt;
9
+ * non-EU buyer → export.
10
+ */
11
+ export declare function defaultVatCategory(input: {
12
+ rate: number;
13
+ sellerCountry: string;
14
+ buyerCountry: string;
15
+ buyerHasVatId: boolean;
16
+ }): VatCategory;
17
+ /** Categories that require an exemption reason (BR-E-10, BR-AE-10, BR-IC-10, BR-G-10, BR-O-10). */
18
+ export declare const EXEMPT_CATEGORIES: ReadonlySet<VatCategory>;
19
+ /** VATEX exemption reason codes (BT-121) where one exists. */
20
+ export declare const EXEMPTION_REASON_CODES: Readonly<Partial<Record<VatCategory, string>>>;
21
+ /** Neutral default reason texts (BT-120). Override per invoice with `exemptionReasons`. */
22
+ export declare const DEFAULT_EXEMPTION_REASONS: Readonly<Record<Exclude<VatCategory, 'S' | 'Z'>, string>>;
23
+ //# sourceMappingURL=vat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vat.d.ts","sourceRoot":"","sources":["../src/vat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,4CAA4C;AAC5C,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,CAG3C,CAAC;AAEH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,WAAW,CAOd;AAED,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,WAAW,CAAuC,CAAC;AAE/F,8DAA8D;AAC9D,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAKjF,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,GAAG,GAAG,CAAC,EAAE,MAAM,CAAC,CAM/F,CAAC"}
package/dist/vat.js ADDED
@@ -0,0 +1,43 @@
1
+ /** EU member states, ISO 3166-1 alpha-2. */
2
+ export const EU_COUNTRIES = new Set([
3
+ 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU',
4
+ 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK',
5
+ ]);
6
+ export function isEuCountry(code) {
7
+ return EU_COUNTRIES.has(code.toUpperCase());
8
+ }
9
+ /**
10
+ * Picks the VAT category of a line when the caller does not state it.
11
+ * Positive rate → standard. Zero rate: domestic → zero-rated; EU buyer with a
12
+ * VAT identifier → intra-community supply; EU buyer without → exempt;
13
+ * non-EU buyer → export.
14
+ */
15
+ export function defaultVatCategory(input) {
16
+ if (input.rate > 0)
17
+ return 'S';
18
+ const seller = input.sellerCountry.toUpperCase();
19
+ const buyer = input.buyerCountry.toUpperCase();
20
+ if (seller === buyer)
21
+ return 'Z';
22
+ if (isEuCountry(buyer))
23
+ return input.buyerHasVatId ? 'K' : 'E';
24
+ return 'G';
25
+ }
26
+ /** Categories that require an exemption reason (BR-E-10, BR-AE-10, BR-IC-10, BR-G-10, BR-O-10). */
27
+ export const EXEMPT_CATEGORIES = new Set(['E', 'AE', 'K', 'G', 'O']);
28
+ /** VATEX exemption reason codes (BT-121) where one exists. */
29
+ export const EXEMPTION_REASON_CODES = {
30
+ K: 'VATEX-EU-IC',
31
+ AE: 'VATEX-EU-AE',
32
+ G: 'VATEX-EU-G',
33
+ O: 'VATEX-EU-O',
34
+ };
35
+ /** Neutral default reason texts (BT-120). Override per invoice with `exemptionReasons`. */
36
+ export const DEFAULT_EXEMPTION_REASONS = {
37
+ E: 'Exempt from VAT',
38
+ AE: 'Reverse charge: VAT to be accounted for by the recipient',
39
+ K: 'Intra-community supply, exempt from VAT',
40
+ G: 'Export outside the European Union, exempt from VAT',
41
+ O: 'Not subject to VAT',
42
+ };
43
+ //# sourceMappingURL=vat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vat.js","sourceRoot":"","sources":["../src/vat.ts"],"names":[],"mappings":"AAEA,4CAA4C;AAC5C,MAAM,CAAC,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC;IACvD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAClF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC7E,CAAC,CAAC;AAEH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAKlC;IACC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAC/C,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IACjC,IAAI,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC/D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mGAAmG;AACnG,MAAM,CAAC,MAAM,iBAAiB,GAA6B,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAE/F,8DAA8D;AAC9D,MAAM,CAAC,MAAM,sBAAsB,GAAmD;IACpF,CAAC,EAAE,aAAa;IAChB,EAAE,EAAE,aAAa;IACjB,CAAC,EAAE,YAAY;IACf,CAAC,EAAE,YAAY;CAChB,CAAC;AAEF,2FAA2F;AAC3F,MAAM,CAAC,MAAM,yBAAyB,GAA8D;IAClG,CAAC,EAAE,iBAAiB;IACpB,EAAE,EAAE,0DAA0D;IAC9D,CAAC,EAAE,yCAAyC;IAC5C,CAAC,EAAE,oDAAoD;IACvD,CAAC,EAAE,oBAAoB;CACxB,CAAC"}
package/dist/xmp.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { Profile } from './types.js';
2
+ /** XMP `fx:ConformanceLevel` values, exact spelling required by readers. */
3
+ export declare const CONFORMANCE_LEVELS: Readonly<Record<Profile, string>>;
4
+ export interface XmpOptions {
5
+ profile: Profile;
6
+ title?: string;
7
+ creator?: string;
8
+ producer?: string;
9
+ /** Timestamp written to the metadata. Defaults to now. */
10
+ date?: Date;
11
+ }
12
+ /**
13
+ * XMP packet declaring a PDF/A-3 document with the Factur-X extension schema,
14
+ * as required by the Factur-X specification (§ 6.2).
15
+ */
16
+ export declare function buildXmpMetadata(options: XmpOptions): string;
17
+ //# sourceMappingURL=xmp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xmp.d.ts","sourceRoot":"","sources":["../src/xmp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAMhE,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAsD5D"}
package/dist/xmp.js ADDED
@@ -0,0 +1,70 @@
1
+ /** XMP `fx:ConformanceLevel` values, exact spelling required by readers. */
2
+ export const CONFORMANCE_LEVELS = {
3
+ minimum: 'MINIMUM',
4
+ 'basic-wl': 'BASIC WL',
5
+ basic: 'BASIC',
6
+ en16931: 'EN 16931',
7
+ extended: 'EXTENDED',
8
+ };
9
+ function escapeXml(s) {
10
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
11
+ }
12
+ /**
13
+ * XMP packet declaring a PDF/A-3 document with the Factur-X extension schema,
14
+ * as required by the Factur-X specification (§ 6.2).
15
+ */
16
+ export function buildXmpMetadata(options) {
17
+ const date = (options.date ?? new Date()).toISOString();
18
+ const title = escapeXml(options.title ?? 'Invoice');
19
+ const creator = escapeXml(options.creator ?? '@ekwo-ai/factur-x');
20
+ const producer = escapeXml(options.producer ?? '@ekwo-ai/factur-x');
21
+ const property = (name, description) => `<rdf:li rdf:parseType="Resource"><pdfaProperty:name>${name}</pdfaProperty:name><pdfaProperty:valueType>Text</pdfaProperty:valueType><pdfaProperty:category>external</pdfaProperty:category><pdfaProperty:description>${description}</pdfaProperty:description></rdf:li>`;
22
+ return `<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
23
+ <x:xmpmeta xmlns:x="adobe:ns:meta/">
24
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
25
+ <rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">
26
+ <pdfaid:part>3</pdfaid:part>
27
+ <pdfaid:conformance>B</pdfaid:conformance>
28
+ </rdf:Description>
29
+ <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
30
+ <dc:title><rdf:Alt><rdf:li xml:lang="x-default">${title}</rdf:li></rdf:Alt></dc:title>
31
+ <dc:creator><rdf:Seq><rdf:li>${creator}</rdf:li></rdf:Seq></dc:creator>
32
+ </rdf:Description>
33
+ <rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
34
+ <pdf:Producer>${producer}</pdf:Producer>
35
+ </rdf:Description>
36
+ <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
37
+ <xmp:CreatorTool>${creator}</xmp:CreatorTool>
38
+ <xmp:CreateDate>${date}</xmp:CreateDate>
39
+ <xmp:ModifyDate>${date}</xmp:ModifyDate>
40
+ </rdf:Description>
41
+ <rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/" xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#" xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
42
+ <pdfaExtension:schemas>
43
+ <rdf:Bag>
44
+ <rdf:li rdf:parseType="Resource">
45
+ <pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>
46
+ <pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>
47
+ <pdfaSchema:prefix>fx</pdfaSchema:prefix>
48
+ <pdfaSchema:property>
49
+ <rdf:Seq>
50
+ ${property('DocumentFileName', 'name of the embedded XML invoice file')}
51
+ ${property('DocumentType', 'INVOICE')}
52
+ ${property('Version', 'The actual version of the Factur-X XML schema')}
53
+ ${property('ConformanceLevel', 'The conformance level of the embedded Factur-X data')}
54
+ </rdf:Seq>
55
+ </pdfaSchema:property>
56
+ </rdf:li>
57
+ </rdf:Bag>
58
+ </pdfaExtension:schemas>
59
+ </rdf:Description>
60
+ <rdf:Description rdf:about="" xmlns:fx="urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#">
61
+ <fx:DocumentType>INVOICE</fx:DocumentType>
62
+ <fx:DocumentFileName>factur-x.xml</fx:DocumentFileName>
63
+ <fx:Version>1.0</fx:Version>
64
+ <fx:ConformanceLevel>${CONFORMANCE_LEVELS[options.profile]}</fx:ConformanceLevel>
65
+ </rdf:Description>
66
+ </rdf:RDF>
67
+ </x:xmpmeta>
68
+ <?xpacket end="w"?>`;
69
+ }
70
+ //# sourceMappingURL=xmp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xmp.js","sourceRoot":"","sources":["../src/xmp.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAsC;IACnE,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,UAAU;IACtB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,UAAU;IACnB,QAAQ,EAAE,UAAU;CACrB,CAAC;AAWF,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAmB;IAClD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACxD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,IAAI,mBAAmB,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,IAAI,mBAAmB,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,WAAmB,EAAE,EAAE,CACrD,uDAAuD,IAAI,6JAA6J,WAAW,sCAAsC,CAAC;IAC5Q,OAAO;;;;;;;;wDAQ+C,KAAK;qCACxB,OAAO;;;sBAGtB,QAAQ;;;yBAGL,OAAO;wBACR,IAAI;wBACJ,IAAI;;;;;;;;;;;kBAWV,QAAQ,CAAC,kBAAkB,EAAE,uCAAuC,CAAC;kBACrE,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC;kBACnC,QAAQ,CAAC,SAAS,EAAE,+CAA+C,CAAC;kBACpE,QAAQ,CAAC,kBAAkB,EAAE,qDAAqD,CAAC;;;;;;;;;;;6BAWxE,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC;;;;oBAI5C,CAAC;AACrB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@ekwo-ai/factur-x",
3
+ "version": "0.4.0",
4
+ "description": "Factur-X / ZUGFeRD e-invoices in TypeScript: EN 16931 CII XML from a plain invoice object, PDF/A-3 embedding and extraction.",
5
+ "keywords": [
6
+ "factur-x",
7
+ "facturx",
8
+ "zugferd",
9
+ "en16931",
10
+ "cii",
11
+ "e-invoicing",
12
+ "einvoice",
13
+ "pdf-a3",
14
+ "invoice",
15
+ "peppol"
16
+ ],
17
+ "license": "MIT",
18
+ "author": "Ekwo AI",
19
+ "homepage": "https://github.com/Ekwo-ai/ekwo-os/tree/main/packages/formats/factur-x#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Ekwo-ai/ekwo-os.git",
23
+ "directory": "packages/formats/factur-x"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/Ekwo-ai/ekwo-os/issues"
27
+ },
28
+ "type": "module",
29
+ "sideEffects": false,
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE",
37
+ "CHANGELOG.md"
38
+ ],
39
+ "main": "./dist/index.js",
40
+ "types": "./dist/index.d.ts",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./dist/index.d.ts",
44
+ "import": "./dist/index.js"
45
+ },
46
+ "./pdf": {
47
+ "types": "./dist/pdf.d.ts",
48
+ "import": "./dist/pdf.js"
49
+ }
50
+ },
51
+ "scripts": {
52
+ "build": "tsc -p tsconfig.build.json",
53
+ "typecheck": "tsc -p tsconfig.json --noEmit",
54
+ "test": "vitest run",
55
+ "test:watch": "vitest",
56
+ "example": "tsx examples/basic.ts",
57
+ "prepublishOnly": "npm run typecheck && npm test && npm run build"
58
+ },
59
+ "dependencies": {
60
+ "pdf-lib": "^1.17.1"
61
+ },
62
+ "devDependencies": {
63
+ "@types/node": "^24.0.0",
64
+ "tsx": "^4.20.0",
65
+ "typescript": "^5.9.0",
66
+ "vitest": "^3.2.0"
67
+ }
68
+ }