@ekwo-ai/vat-consignment 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ekwo AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # `@ekwo-ai/vat-consignment`
2
+
3
+ The Belgian **periodic VAT return** — the XML Intervat takes for the monthly
4
+ or quarterly declaration — in TypeScript, with no dependencies.
5
+
6
+ Give it the figures a declaration was filed with and it gives you the file, a
7
+ name for it, and the list of what could not be put in it.
8
+
9
+ ```ts
10
+ import { generateVatConsignment } from '@ekwo-ai/vat-consignment';
11
+
12
+ const { file, filename, violations } = generateVatConsignment(boxes, {
13
+ declarant: { vatNumber: '0999999999', name: 'Demo', countryCode: 'BE' },
14
+ period: { year: 2026, quarter: 4 },
15
+ });
16
+ ```
17
+
18
+ `boxes` is a grid, what the grid holds, and an amount:
19
+
20
+ ```ts
21
+ [
22
+ { box: '03', kind: 'base', amount: '10000.00' },
23
+ { box: '54', kind: 'tax', amount: '2100.00' },
24
+ { box: '71', kind: 'total', amount: '2100.00' },
25
+ ]
26
+ ```
27
+
28
+ which is the row shape of `tax_filing_boxes` in
29
+ [Ekwo OS](https://github.com/Ekwo-ai/ekwo-os) — the figures **as they were
30
+ frozen at filing**. That is the input on purpose: what is deposited has to be
31
+ what the declaration says, and a file that recomputes from the ledger can
32
+ diverge from the filing it is meant to carry.
33
+
34
+ ## What it does
35
+
36
+ - Writes one `VATConsignment` holding one `VATDeclaration`
37
+ (`generateVatConsignment`) or as many as it is given
38
+ (`generateVatConsignments`), **valid against the schema the administration
39
+ publishes** — checked in this package's own tests, instance by instance.
40
+ - Writes the **representative** who files for the declarants, when there is
41
+ one. The schema repeats `VATDeclaration` and counts them in
42
+ `VATDeclarationsNbr`: it was drawn so that a firm deposits the returns of all
43
+ its clients in one file, in its own name. The block is optional and **every
44
+ field inside it is required**, so a representative is named entirely or
45
+ refused by exception — neither completed nor dropped, because a file that
46
+ silently loses its representative is sent under another authority than the
47
+ one that was meant. The state that issued its identifier is one of `ISSUERS`,
48
+ the schema's own list and not ISO's: Greece is `EL` there.
49
+ - Numbers the returns of a consignment by position unless told otherwise,
50
+ refuses two under one number, and says on each violation which return it is
51
+ in.
52
+ - Numbers every grid with two digits: `3` and `03` are the same grid, and the
53
+ form writes the second.
54
+ - Leaves out a grid at zero. An absent grid reads as a zero, and a return that
55
+ writes out its thirty empty boxes is one nobody can read.
56
+ - Writes a **nil return as a return**. The schema requires `Data` and at least
57
+ one `Amount` in it, and does not say which; so a period where nothing happened
58
+ says the one thing it has to say — that nothing is owed — on grid 71, which is
59
+ the grid that carries what is owed. A choice of this package, forced by the
60
+ schema and not specified by it (`NIL_GRID`).
61
+ - Always writes `ClientListingNihil`, because the schema requires it on every
62
+ return, and defaults it to `NO` — the absence of a claim, not a claim that
63
+ there will be a listing.
64
+ - Names the declaration it replaces, in `ReplacedVATDeclaration`, when it is a
65
+ corrective: pass `replacedDeclaration` the reference Intervat gave the first
66
+ one.
67
+ - Writes amounts with two decimals and a point. The French-language pages of
68
+ the administration show examples with a comma; the schema does not, and the
69
+ validator refuses one.
70
+ - Writes nothing for a field that was not given. A telephone number invented to
71
+ satisfy a validator travels to an administration as a telephone number — and
72
+ the schema, as it turns out, does not ask for one.
73
+
74
+ ## What comes back as a violation
75
+
76
+ The rest of the file stays valid, because a return that refuses to exist over
77
+ one unreadable figure helps nobody. Each of these is something the schema would
78
+ have refused — the tests put each one back in the file and watch validation
79
+ fail — which is what makes them violations of this format and not opinions of
80
+ this package.
81
+
82
+ | code | when |
83
+ |---|---|
84
+ | `unknown_grid` | the box is not one of the twenty-nine grids the schema lists (`GRIDS`) |
85
+ | `grid_twice` | the same grid was given twice, as a base and as a tax |
86
+ | `negative_amount` | the amount is below zero: every grid is a `PositiveAmount_Type` |
87
+ | `amount_out_of_range` | the amount is more than the schema can hold |
88
+ | `invalid_amount` | the amount is not a number |
89
+ | `reference_too_long` | the declarant's reference is over fourteen characters — left out |
90
+ | `invalid_phone` | the telephone number does not fit twenty digits — left out |
91
+
92
+ `grid_twice` is the one thing this format cannot hold: it gives every grid a
93
+ single value. A form that prints a base and a tax on the same line — the French
94
+ CA3 does, on line 08 — has no representation here, and that is a fact about
95
+ this file and not a defect of the figures.
96
+
97
+ `negative_amount` is worth a sentence too. This form never lets a grid go below
98
+ zero: what reduces a figure has a grid of its own — 48 and 49 for credit notes
99
+ issued, 61 and 62 for regularisations. A negative figure reaching this package
100
+ means the books netted something the form wants shown apart.
101
+
102
+ Three things are refused by exception instead, because they make the whole file
103
+ meaningless: a period that is neither a month nor a quarter, a declarant number
104
+ the schema cannot hold, and a corrective that names what it replaces in any
105
+ shape but the one Intervat uses.
106
+
107
+ ## What it does not do
108
+
109
+ - **It does not deposit anything.** Uploading the file needs a certificate, an
110
+ authenticated session and somebody on call; that is the operated side of this
111
+ project and not a library.
112
+ - **It does not decide what to ask for.** `Restitution` and `Payment` are
113
+ requests made to the administration, not consequences of the figures, so both
114
+ default to no and the caller says otherwise.
115
+ - **It does not claim anything about the annual customer listing.** The element
116
+ is required, so it is written; `NO` unless the caller says otherwise.
117
+ - **It does not know whether the representative holds a mandate** for each
118
+ declarant. That is a fact of the administration's records, not of the file;
119
+ a consignment without one is refused there, not here.
120
+ - **It computes nothing.** No total is derived, no grid is filled from another:
121
+ the figures come in frozen and go out unchanged.
122
+
123
+ ## Sources
124
+
125
+ - [Intervat](https://finances.belgium.be/fr/E-services/intervat) — the service
126
+ the file is deposited on, SPF Finances, and where its technical documentation
127
+ and XSD schemas are published.
128
+ - Schema `NewTVA-in_v0_9.xsd`, namespaces
129
+ `http://www.minfin.fgov.be/VATConsignment` and
130
+ `http://www.minfin.fgov.be/InputCommon`.
131
+ - Arrêté royal n° 1 du 29 décembre 1992 relatif aux mesures tendant à assurer
132
+ le paiement de la taxe sur la valeur ajoutée, **art. 18** — the form and its
133
+ frames; **art. 18, § 1er** — filed by the twentieth day of the month that
134
+ follows.
135
+ - Code de la TVA, **art. 53, § 1er, alinéa 1er, 2°** — the obligation to file.
136
+
137
+ ## What is verified, and what is not
138
+
139
+ **Verified**: every shape of file this package writes — a full return, a minimal
140
+ one, a nil one, a corrective, one carrying every grid at once, one under a
141
+ representative and one holding the returns of several declarants — validates
142
+ against `NewTVA-in_v0_9.xsd` and the four schemas it imports, in
143
+ `test/schema.test.ts`, with no network and no system tool. The list of grids in
144
+ the source is compared with the enumeration of the schema, number for number,
145
+ so it cannot drift from it; so is the list of states that issue a
146
+ representative's identifier. A representative missing any one field is shown to
147
+ be what the schema refuses. The schemas are kept unmodified under `test/xsd/`,
148
+ with where each came from; the package ships none of them.
149
+
150
+ The first version of this brick was written from a production filing and said
151
+ here that the schema had not been read. Reading it found four defects the same
152
+ day: `Data` and `ClientListingNihil` are required, every amount is a positive
153
+ one, and the grids are a closed list.
154
+
155
+ **Not verified**: what Intervat checks *beyond* the schema. The portal applies
156
+ business controls of its own — arithmetic between grids, warnings to justify
157
+ before signing — and those are rules of the form, not of the file. A return
158
+ that is valid here can still be questioned there. `Justification` and
159
+ `FileAttachment`, which the schema allows for exactly that, are not written by
160
+ this package yet.
161
+
162
+ ## Licence
163
+
164
+ MIT. See [`LICENSE`](./LICENSE).
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The Belgian periodic VAT return, as Intervat takes it.
3
+ *
4
+ * One XML document, `VATConsignment`, described by the schema the SPF Finances
5
+ * publishes as `NewTVA-in_v0_9.xsd`. Give it the figures a declaration was
6
+ * filed with — a grid, what the grid holds, an amount — and it writes the
7
+ * file, a name for it, and the list of what could not be put in it.
8
+ *
9
+ * The input is deliberately the **frozen** figures and not a computation: what
10
+ * is deposited has to be what the declaration says, and a file that recomputes
11
+ * can diverge from the filing it is supposed to carry.
12
+ *
13
+ * Sources are in the README. This package depends on nothing, reads no
14
+ * database and knows no accounting.
15
+ */
16
+ import type { ConsignedReturn, ConsignmentOptions, FiledBox, ReturnPeriod, VatConsignment, VatConsignmentOptions } from './types.js';
17
+ export type { Ask, ConsignedReturn, ConsignmentOptions, Declarant, FiledBox, Representative, ReturnPeriod, VatConsignment, VatConsignmentOptions, Violation, } from './types.js';
18
+ /**
19
+ * The grids of the form, which the schema closes: `GridNumberCode` is an
20
+ * enumeration, and a number that is not in it is refused by the validator
21
+ * however plausible it looks. Read from `NewTVA-in_v0_9.xsd`; a test compares
22
+ * this list with the schema file itself, so it cannot drift from it.
23
+ */
24
+ export declare const GRIDS: readonly string[];
25
+ /**
26
+ * The states that can have issued a representative's identifier:
27
+ * `MSCountryCode`, which the schema closes too. It is the schema's list and
28
+ * not ISO's — Greece is `EL` in it, and `XI` and `XU` are there — and a test
29
+ * compares it with the schema file, code for code.
30
+ */
31
+ export declare const ISSUERS: readonly string[];
32
+ /**
33
+ * The grid a nil return is written on. The schema requires `Data` and at least
34
+ * one `Amount` in it, and does not say which: so a return where nothing
35
+ * happened says the one thing it has to say — that nothing is owed — on the
36
+ * grid that carries what is owed. A choice of this package, forced by the
37
+ * schema and not specified by it.
38
+ */
39
+ export declare const NIL_GRID = "71";
40
+ export declare class VatConsignmentError extends Error {
41
+ name: string;
42
+ }
43
+ /**
44
+ * Two decimals with a point. The French-language pages of the administration
45
+ * write their examples with a comma; the schema does not, and a comma is
46
+ * refused by the validator.
47
+ */
48
+ export declare function formatAmount(value: string | number): string;
49
+ /** `3` and `03` are the same grid; the form writes the second. */
50
+ export declare function formatGrid(box: string): string;
51
+ /**
52
+ * A name for the file.
53
+ *
54
+ * The administration imposes none: Intervat takes the file that is uploaded
55
+ * and names the deposit itself. So this is a name of ours, stable and
56
+ * readable, and a caller is free to choose another.
57
+ */
58
+ export declare function vatConsignmentFileName(declarantVatNumber: string, period: ReturnPeriod): string;
59
+ /**
60
+ * Writes a consignment: one file, as many returns as it is given, and the
61
+ * representative who files them when there is one.
62
+ *
63
+ * This is the shape the schema was drawn for — `VATDeclaration` repeats and
64
+ * `VATDeclarationsNbr` counts them — and it is how a firm deposits the returns
65
+ * of all its clients at once, in its own name.
66
+ *
67
+ * Refuses, by exception, what would make the file meaningless: no return at
68
+ * all, a return whose period or declarant cannot be written, a representative
69
+ * named by halves, two returns under one sequence number — the number is the
70
+ * only thing that tells them apart in one file. Everything that is wrong with
71
+ * one figure comes back in `violations`, carrying the sequence number of the
72
+ * return it is in, and leaves the rest of the file valid.
73
+ *
74
+ * **Not checked**: that the representative holds a mandate for each declarant.
75
+ * That is a fact of the administration's records and not of this file.
76
+ */
77
+ export declare function generateVatConsignments(returns: ConsignedReturn[], consignment?: ConsignmentOptions): VatConsignment;
78
+ /**
79
+ * Writes one return, filed by the declarant itself: a consignment of one.
80
+ *
81
+ * Refuses, by exception, what would make the whole file meaningless: a period
82
+ * that is neither a month nor a quarter, or a declarant number the schema
83
+ * cannot hold. Everything that is wrong with one figure comes back in
84
+ * `violations` and leaves the rest of the file valid — a return that refuses
85
+ * to exist over one unreadable grid helps nobody.
86
+ */
87
+ export declare function generateVatConsignment(boxes: FiledBox[], options: VatConsignmentOptions): VatConsignment;
88
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,QAAQ,EAER,YAAY,EACZ,cAAc,EACd,qBAAqB,EAEtB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,GAAG,EACH,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,SAAS,GACV,MAAM,YAAY,CAAC;AAQpB;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,SAAS,MAAM,EAIjC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,SAAS,MAAM,EAInC,CAAC;AAoBH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,OAAO,CAAC;AAE7B,qBAAa,mBAAoB,SAAQ,KAAK;IACnC,IAAI,SAAyB;CACvC;AAUD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAI3D;AAOD,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAyID;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAS/F;AAkLD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,eAAe,EAAE,EAC1B,WAAW,GAAE,kBAAuB,GACnC,cAAc,CAiEhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAEhB"}
package/dist/index.js ADDED
@@ -0,0 +1,446 @@
1
+ /**
2
+ * The Belgian periodic VAT return, as Intervat takes it.
3
+ *
4
+ * One XML document, `VATConsignment`, described by the schema the SPF Finances
5
+ * publishes as `NewTVA-in_v0_9.xsd`. Give it the figures a declaration was
6
+ * filed with — a grid, what the grid holds, an amount — and it writes the
7
+ * file, a name for it, and the list of what could not be put in it.
8
+ *
9
+ * The input is deliberately the **frozen** figures and not a computation: what
10
+ * is deposited has to be what the declaration says, and a file that recomputes
11
+ * can diverge from the filing it is supposed to carry.
12
+ *
13
+ * Sources are in the README. This package depends on nothing, reads no
14
+ * database and knows no accounting.
15
+ */
16
+ const NS_RETURN = 'http://www.minfin.fgov.be/VATConsignment';
17
+ const NS_COMMON = 'http://www.minfin.fgov.be/InputCommon';
18
+ /** The schema's own pattern for the declarant's enterprise number. */
19
+ const DECLARANT_NUMBER = /^[0-1][0-9][0-9]{8}$/;
20
+ /**
21
+ * The grids of the form, which the schema closes: `GridNumberCode` is an
22
+ * enumeration, and a number that is not in it is refused by the validator
23
+ * however plausible it looks. Read from `NewTVA-in_v0_9.xsd`; a test compares
24
+ * this list with the schema file itself, so it cannot drift from it.
25
+ */
26
+ export const GRIDS = Object.freeze([
27
+ '00', '01', '02', '03', '44', '45', '46', '47', '48', '49',
28
+ '54', '55', '56', '57', '59', '61', '62', '63', '64',
29
+ '71', '72', '81', '82', '83', '84', '85', '86', '87', '88',
30
+ ]);
31
+ /**
32
+ * The states that can have issued a representative's identifier:
33
+ * `MSCountryCode`, which the schema closes too. It is the schema's list and
34
+ * not ISO's — Greece is `EL` in it, and `XI` and `XU` are there — and a test
35
+ * compares it with the schema file, code for code.
36
+ */
37
+ export const ISSUERS = Object.freeze([
38
+ 'AT', 'BG', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT',
39
+ 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'GB', 'MC', 'HR', 'XI', 'XU',
40
+ 'BE',
41
+ ]);
42
+ /** `RepresentativeIDType_Type`. */
43
+ const IDENTIFICATION_TYPES = ['NVAT', 'TIN', 'other'];
44
+ /** `EMail_Type`, as the schema writes it. */
45
+ const EMAIL = /^[^@]+@[^.]+\..+$/;
46
+ /** `PositiveAmount_Type`: the largest figure a grid can hold. */
47
+ const MAX_AMOUNT = 99_999_999_999.99;
48
+ /** `DeclarantReference_Type`: a token of at most fourteen characters. */
49
+ const MAX_REFERENCE = 14;
50
+ /** `IntervatDeclarationReference_Type`, for the declaration a corrective replaces. */
51
+ const DECLARATION_REFERENCE = /^[0-9]+-[0-9]{10}-[0-9]{6}$/;
52
+ /** `PhoneNumber_Type` allows twenty characters; digits are what is written. */
53
+ const MAX_PHONE = 20;
54
+ /**
55
+ * The grid a nil return is written on. The schema requires `Data` and at least
56
+ * one `Amount` in it, and does not say which: so a return where nothing
57
+ * happened says the one thing it has to say — that nothing is owed — on the
58
+ * grid that carries what is owed. A choice of this package, forced by the
59
+ * schema and not specified by it.
60
+ */
61
+ export const NIL_GRID = '71';
62
+ export class VatConsignmentError extends Error {
63
+ name = 'VatConsignmentError';
64
+ }
65
+ function escapeXml(value) {
66
+ return value
67
+ .replace(/&/g, '&')
68
+ .replace(/</g, '&lt;')
69
+ .replace(/>/g, '&gt;')
70
+ .replace(/"/g, '&quot;');
71
+ }
72
+ /**
73
+ * Two decimals with a point. The French-language pages of the administration
74
+ * write their examples with a comma; the schema does not, and a comma is
75
+ * refused by the validator.
76
+ */
77
+ export function formatAmount(value) {
78
+ const n = typeof value === 'number' ? value : Number(value);
79
+ if (!Number.isFinite(n))
80
+ throw new VatConsignmentError(`invalid amount: ${String(value)}`);
81
+ return n.toFixed(2);
82
+ }
83
+ /** Letters and digits, upper case: what an administration compares. */
84
+ function normalise(value) {
85
+ return value.replace(/[^A-Za-z0-9]/g, '').toUpperCase();
86
+ }
87
+ /** `3` and `03` are the same grid; the form writes the second. */
88
+ export function formatGrid(box) {
89
+ return box.trim().padStart(2, '0');
90
+ }
91
+ function periodElement(period) {
92
+ const lines = [];
93
+ if (period.month !== undefined) {
94
+ lines.push(` <ns2:Month>${String(period.month).padStart(2, '0')}</ns2:Month>`);
95
+ }
96
+ if (period.quarter !== undefined)
97
+ lines.push(` <ns2:Quarter>${period.quarter}</ns2:Quarter>`);
98
+ lines.push(` <ns2:Year>${period.year}</ns2:Year>`);
99
+ return lines.join('\n');
100
+ }
101
+ /**
102
+ * The declarant block. Its children live in the `InputCommon` namespace and
103
+ * not in the return's own, because the schema that declares them is a
104
+ * different one — a detail the validator is strict about and no example makes
105
+ * obvious.
106
+ *
107
+ * Nothing is filled in for an absent field. A telephone number invented to
108
+ * satisfy a validator travels to an administration as a telephone number.
109
+ */
110
+ function declarantElement(options, vatNumber) {
111
+ const d = options.declarant;
112
+ const optional = [
113
+ ['Name', d.name],
114
+ ['Street', d.street],
115
+ ['PostCode', d.postCode],
116
+ ['City', d.city],
117
+ ['CountryCode', d.countryCode],
118
+ ['EmailAddress', d.emailAddress],
119
+ ['Phone', phoneOf(d.phone)],
120
+ ];
121
+ const lines = [` <VATNumber>${vatNumber}</VATNumber>`];
122
+ for (const [tag, value] of optional) {
123
+ if (value !== undefined && value !== '') {
124
+ lines.push(` <${tag}>${escapeXml(value)}</${tag}>`);
125
+ }
126
+ }
127
+ return lines.join('\n');
128
+ }
129
+ /** Digits only, and nothing at all where they would not fit the schema. */
130
+ function phoneOf(phone) {
131
+ if (phone === undefined)
132
+ return undefined;
133
+ const digits = phone.replace(/[^0-9]/g, '');
134
+ return digits.length === 0 || digits.length > MAX_PHONE ? undefined : digits;
135
+ }
136
+ /**
137
+ * The grids of the file, from the figures the declaration was filed with.
138
+ *
139
+ * Five things are refused here rather than written out, and each of them
140
+ * comes back as a violation so that the rest of the return is still a return:
141
+ *
142
+ * - a grid the schema does not list — a box of another country's form, or a
143
+ * number that merely looks like one of this form's;
144
+ * - **the same grid twice**, which is the one thing this format cannot hold:
145
+ * it gives every grid a single value, and a form that prints a base and a
146
+ * tax on one line — the French CA3 does — has no representation here;
147
+ * - an amount that is not a number;
148
+ * - **a negative amount**: every grid is a `PositiveAmount_Type`, because this
149
+ * form keeps what reduces a figure on a grid of its own (48, 49, 61, 62)
150
+ * rather than letting any grid go below zero;
151
+ * - an amount beyond what the schema can hold.
152
+ *
153
+ * A grid at zero is left out. The administration reads an absent grid as a
154
+ * zero, and a return that writes out its thirty empty boxes is a return
155
+ * nobody can read.
156
+ */
157
+ function gridsOf(boxes) {
158
+ const violations = [];
159
+ const seen = new Map();
160
+ const grids = [];
161
+ for (const box of boxes) {
162
+ const grid = formatGrid(String(box.box ?? ''));
163
+ if (!GRIDS.includes(grid)) {
164
+ violations.push({
165
+ code: 'unknown_grid',
166
+ message: `${String(box.box)} is not a grid of this form: the schema lists the ones there are, and this is not among them`,
167
+ box: String(box.box),
168
+ });
169
+ continue;
170
+ }
171
+ const amount = Number(box.amount);
172
+ if (!Number.isFinite(amount)) {
173
+ violations.push({
174
+ code: 'invalid_amount',
175
+ message: `grid ${grid} carries ${String(box.amount)}, which is not an amount`,
176
+ box: grid,
177
+ });
178
+ continue;
179
+ }
180
+ if (amount < 0) {
181
+ violations.push({
182
+ code: 'negative_amount',
183
+ message: `grid ${grid} carries ${formatAmount(amount)}: no grid of this form goes below zero, and what reduces a figure has a grid of its own`,
184
+ box: grid,
185
+ });
186
+ continue;
187
+ }
188
+ if (amount > MAX_AMOUNT) {
189
+ violations.push({
190
+ code: 'amount_out_of_range',
191
+ message: `grid ${grid} carries ${formatAmount(amount)}, which is more than the schema can hold`,
192
+ box: grid,
193
+ });
194
+ continue;
195
+ }
196
+ const kind = box.kind ?? 'tax';
197
+ const already = seen.get(grid);
198
+ if (already !== undefined) {
199
+ violations.push({
200
+ code: 'grid_twice',
201
+ message: `grid ${grid} was given twice, as ${already} and as ${kind}: this form holds one figure per grid`,
202
+ box: grid,
203
+ });
204
+ continue;
205
+ }
206
+ seen.set(grid, kind);
207
+ if (Math.abs(amount) < 0.005)
208
+ continue;
209
+ grids.push({ grid, amount: formatAmount(amount) });
210
+ }
211
+ grids.sort((a, b) => Number(a.grid) - Number(b.grid));
212
+ return { grids, violations };
213
+ }
214
+ /**
215
+ * A name for the file.
216
+ *
217
+ * The administration imposes none: Intervat takes the file that is uploaded
218
+ * and names the deposit itself. So this is a name of ours, stable and
219
+ * readable, and a caller is free to choose another.
220
+ */
221
+ export function vatConsignmentFileName(declarantVatNumber, period) {
222
+ const number = normalise(declarantVatNumber).replace(/^BE/, '');
223
+ const suffix = period.month !== undefined
224
+ ? `M${String(period.month).padStart(2, '0')}`
225
+ : period.quarter !== undefined
226
+ ? `Q${period.quarter}`
227
+ : 'Y';
228
+ return `VATConsignment-${number}-${period.year}${suffix}.xml`;
229
+ }
230
+ /**
231
+ * The representative block: the party that files for the declarants of the
232
+ * consignment, in its own name.
233
+ *
234
+ * The schema makes the block optional and every field in it required. So a
235
+ * representative that lacks one is refused by exception, and is neither
236
+ * completed nor left out: a field made up travels to an administration as a
237
+ * fact, and a consignment that silently drops its representative is a file
238
+ * sent under another authority than the one that was meant.
239
+ */
240
+ function representativeElement(r) {
241
+ const missing = ['id', 'issuedBy', 'identificationType', 'name', 'street', 'postCode', 'city', 'countryCode', 'emailAddress', 'phone'].filter((field) => typeof r[field] !== 'string' || r[field].trim() === '');
242
+ if (missing.length > 0) {
243
+ throw new VatConsignmentError(`a representative is named entirely or not at all, and this one lacks: ${missing.join(', ')}`);
244
+ }
245
+ if (!ISSUERS.includes(r.issuedBy)) {
246
+ throw new VatConsignmentError(`the representative's identifier is issued by a state the schema lists, and ${r.issuedBy} is not one (Greece is EL there)`);
247
+ }
248
+ if (!IDENTIFICATION_TYPES.includes(r.identificationType)) {
249
+ throw new VatConsignmentError(`the representative's identifier is NVAT, TIN or other: ${String(r.identificationType)}`);
250
+ }
251
+ if (!EMAIL.test(r.emailAddress.trim())) {
252
+ throw new VatConsignmentError(`the representative's e-mail address is not one the schema takes: ${r.emailAddress}`);
253
+ }
254
+ const phone = phoneOf(r.phone);
255
+ if (phone === undefined) {
256
+ throw new VatConsignmentError(`the representative's telephone number does not fit the ${MAX_PHONE} digits the schema allows: ${r.phone}`);
257
+ }
258
+ const qualifier = r.identificationType === 'other' && r.otherQualifier !== undefined && r.otherQualifier !== ''
259
+ ? ` otherQlf="${escapeXml(r.otherQualifier)}"`
260
+ : '';
261
+ return [
262
+ ' <ns2:Representative>',
263
+ ` <RepresentativeID issuedBy="${r.issuedBy}" identificationType="${r.identificationType}"${qualifier}>${escapeXml(r.id.trim())}</RepresentativeID>`,
264
+ ` <Name>${escapeXml(r.name)}</Name>`,
265
+ ` <Street>${escapeXml(r.street)}</Street>`,
266
+ ` <PostCode>${escapeXml(r.postCode)}</PostCode>`,
267
+ ` <City>${escapeXml(r.city)}</City>`,
268
+ ` <CountryCode>${escapeXml(r.countryCode)}</CountryCode>`,
269
+ ` <EmailAddress>${escapeXml(r.emailAddress.trim())}</EmailAddress>`,
270
+ ` <Phone>${phone}</Phone>`,
271
+ ' </ns2:Representative>',
272
+ ].join('\n');
273
+ }
274
+ /** What would make one return meaningless: refused by exception, and its number cleaned. */
275
+ function declarantNumberOf(options) {
276
+ const { period } = options;
277
+ const named = [period.month !== undefined, period.quarter !== undefined].filter(Boolean).length;
278
+ if (named !== 1) {
279
+ throw new VatConsignmentError('the period of a return is one month or one quarter: name exactly one of them');
280
+ }
281
+ if (period.month !== undefined && (period.month < 1 || period.month > 12)) {
282
+ throw new VatConsignmentError(`month out of range: ${period.month}`);
283
+ }
284
+ if (period.quarter !== undefined && (period.quarter < 1 || period.quarter > 4)) {
285
+ throw new VatConsignmentError(`quarter out of range: ${period.quarter}`);
286
+ }
287
+ if (!Number.isInteger(period.year) || period.year < 2000) {
288
+ throw new VatConsignmentError(`year out of range: ${period.year}`);
289
+ }
290
+ const declarantNumber = normalise(options.declarant.vatNumber).replace(/^BE/, '');
291
+ if (!DECLARANT_NUMBER.test(declarantNumber)) {
292
+ throw new VatConsignmentError(`the declarant's number is ten digits without its country prefix: ${options.declarant.vatNumber}`);
293
+ }
294
+ if (options.replacedDeclaration !== undefined &&
295
+ !DECLARATION_REFERENCE.test(options.replacedDeclaration)) {
296
+ throw new VatConsignmentError(`the declaration being replaced is named by the reference Intervat gave it, digits-ten digits-six digits: ${options.replacedDeclaration}`);
297
+ }
298
+ return declarantNumber;
299
+ }
300
+ /** One `VATDeclaration`, and what could not be put in it. */
301
+ function declarationElement(boxes, options, declarantNumber, sequence) {
302
+ const { period } = options;
303
+ const { grids, violations } = gridsOf(boxes);
304
+ const ask = options.ask ?? {};
305
+ let declarantReference = options.declarantReference;
306
+ if (declarantReference !== undefined && declarantReference.length > MAX_REFERENCE) {
307
+ violations.push({
308
+ code: 'reference_too_long',
309
+ message: `the declarant's reference holds ${MAX_REFERENCE} characters at most, and ${declarantReference} is ${declarantReference.length}: left out`,
310
+ });
311
+ declarantReference = undefined;
312
+ }
313
+ if (options.declarant.phone !== undefined && phoneOf(options.declarant.phone) === undefined) {
314
+ violations.push({
315
+ code: 'invalid_phone',
316
+ message: `the telephone number does not fit the ${MAX_PHONE} digits the schema allows: left out`,
317
+ });
318
+ }
319
+ const parts = [];
320
+ const reference = declarantReference === undefined || declarantReference === ''
321
+ ? ''
322
+ : ` DeclarantReference="${escapeXml(declarantReference)}"`;
323
+ parts.push(` <ns2:VATDeclaration SequenceNumber="${sequence}"${reference}>`);
324
+ if (options.replacedDeclaration !== undefined) {
325
+ parts.push(` <ns2:ReplacedVATDeclaration>${options.replacedDeclaration}</ns2:ReplacedVATDeclaration>`);
326
+ }
327
+ parts.push(' <ns2:Declarant>');
328
+ parts.push(declarantElement(options, declarantNumber));
329
+ parts.push(' </ns2:Declarant>');
330
+ parts.push(' <ns2:Period>');
331
+ parts.push(periodElement(period));
332
+ parts.push(' </ns2:Period>');
333
+ // `Data` is required and so is one `Amount` inside it: a nil return is still
334
+ // a return, and it says that nothing is owed.
335
+ const written = grids.length > 0 ? grids : [{ grid: NIL_GRID, amount: formatAmount(0) }];
336
+ parts.push(' <ns2:Data>');
337
+ for (const { grid, amount } of written) {
338
+ parts.push(` <ns2:Amount GridNumber="${grid}">${amount}</ns2:Amount>`);
339
+ }
340
+ parts.push(' </ns2:Data>');
341
+ // Required on every return. `NO` is the absence of a claim.
342
+ parts.push(` <ns2:ClientListingNihil>${options.clientListingNihil === true ? 'YES' : 'NO'}</ns2:ClientListingNihil>`);
343
+ parts.push(` <ns2:Ask Restitution="${ask.restitution ? 'YES' : 'NO'}" Payment="${ask.payment ? 'YES' : 'NO'}"/>`);
344
+ if (options.comment !== undefined && options.comment !== '') {
345
+ parts.push(` <ns2:Comment>${escapeXml(options.comment)}</ns2:Comment>`);
346
+ }
347
+ parts.push(' </ns2:VATDeclaration>');
348
+ return { lines: parts, violations };
349
+ }
350
+ /**
351
+ * A name for a consignment of several returns: whose it is, the period when
352
+ * every return shares one, and how many it holds.
353
+ */
354
+ function consignmentFileName(owner, periods, count) {
355
+ const first = periods[0];
356
+ const shared = periods.every((p) => p.year === first.year && p.month === first.month && p.quarter === first.quarter);
357
+ const stem = shared
358
+ ? vatConsignmentFileName(owner, first).replace(/\.xml$/, '')
359
+ : `VATConsignment-${normalise(owner).replace(/^BE/, '')}`;
360
+ return `${stem}-x${count}.xml`;
361
+ }
362
+ /**
363
+ * Writes a consignment: one file, as many returns as it is given, and the
364
+ * representative who files them when there is one.
365
+ *
366
+ * This is the shape the schema was drawn for — `VATDeclaration` repeats and
367
+ * `VATDeclarationsNbr` counts them — and it is how a firm deposits the returns
368
+ * of all its clients at once, in its own name.
369
+ *
370
+ * Refuses, by exception, what would make the file meaningless: no return at
371
+ * all, a return whose period or declarant cannot be written, a representative
372
+ * named by halves, two returns under one sequence number — the number is the
373
+ * only thing that tells them apart in one file. Everything that is wrong with
374
+ * one figure comes back in `violations`, carrying the sequence number of the
375
+ * return it is in, and leaves the rest of the file valid.
376
+ *
377
+ * **Not checked**: that the representative holds a mandate for each declarant.
378
+ * That is a fact of the administration's records and not of this file.
379
+ */
380
+ export function generateVatConsignments(returns, consignment = {}) {
381
+ if (returns.length === 0) {
382
+ throw new VatConsignmentError('a consignment holds at least one return');
383
+ }
384
+ const several = returns.length > 1;
385
+ const violations = [];
386
+ const body = [];
387
+ const numbers = [];
388
+ const sequences = new Set();
389
+ returns.forEach(({ boxes, options }, index) => {
390
+ const sequence = options.sequenceNumber ?? index + 1;
391
+ if (!Number.isInteger(sequence) || sequence < 1) {
392
+ throw new VatConsignmentError(`a sequence number is a positive integer: ${sequence}`);
393
+ }
394
+ if (sequences.has(sequence)) {
395
+ throw new VatConsignmentError(`two returns of one consignment carry the sequence number ${sequence}, which is the only thing that tells them apart`);
396
+ }
397
+ sequences.add(sequence);
398
+ const declarantNumber = declarantNumberOf(options);
399
+ numbers.push(declarantNumber);
400
+ const written = declarationElement(boxes, options, declarantNumber, sequence);
401
+ body.push(...written.lines);
402
+ for (const violation of written.violations) {
403
+ violations.push(several ? { ...violation, declaration: sequence } : violation);
404
+ }
405
+ });
406
+ let representativeReference = consignment.representativeReference;
407
+ if (representativeReference !== undefined && representativeReference.length > MAX_REFERENCE) {
408
+ violations.push({
409
+ code: 'reference_too_long',
410
+ message: `the representative's reference holds ${MAX_REFERENCE} characters at most, and ${representativeReference} is ${representativeReference.length}: left out`,
411
+ });
412
+ representativeReference = undefined;
413
+ }
414
+ const parts = [];
415
+ parts.push('<?xml version="1.0" encoding="UTF-8"?>');
416
+ parts.push(`<ns2:VATConsignment xmlns:ns2="${NS_RETURN}" xmlns="${NS_COMMON}" VATDeclarationsNbr="${returns.length}">`);
417
+ if (consignment.representative !== undefined) {
418
+ parts.push(representativeElement(consignment.representative));
419
+ }
420
+ if (representativeReference !== undefined && representativeReference !== '') {
421
+ parts.push(` <ns2:RepresentativeReference>${escapeXml(representativeReference)}</ns2:RepresentativeReference>`);
422
+ }
423
+ parts.push(...body);
424
+ parts.push('</ns2:VATConsignment>');
425
+ const periods = returns.map(({ options }) => options.period);
426
+ return {
427
+ file: `${parts.join('\n')}\n`,
428
+ filename: several
429
+ ? consignmentFileName(consignment.representative?.id ?? numbers[0], periods, returns.length)
430
+ : vatConsignmentFileName(numbers[0], periods[0]),
431
+ violations,
432
+ };
433
+ }
434
+ /**
435
+ * Writes one return, filed by the declarant itself: a consignment of one.
436
+ *
437
+ * Refuses, by exception, what would make the whole file meaningless: a period
438
+ * that is neither a month nor a quarter, or a declarant number the schema
439
+ * cannot hold. Everything that is wrong with one figure comes back in
440
+ * `violations` and leaves the rest of the file valid — a return that refuses
441
+ * to exist over one unreadable grid helps nobody.
442
+ */
443
+ export function generateVatConsignment(boxes, options) {
444
+ return generateVatConsignments([{ boxes, options }]);
445
+ }
446
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * The shapes this package reads and returns.
3
+ *
4
+ * {@link FiledBox} is the row shape of `tax_filing_boxes` in
5
+ * [Ekwo OS](https://github.com/Ekwo-ai/ekwo-os) — the figures of a declaration
6
+ * as they were frozen at filing — declared here so that nothing is imported
7
+ * from it. Any book-keeping system that can produce a box, what the box holds
8
+ * and an amount can use this package; it reads no database and knows no
9
+ * accounting.
10
+ */
11
+ /**
12
+ * One figure of a periodic VAT return: the grid it goes in, what it is, and
13
+ * how much.
14
+ */
15
+ export interface FiledBox {
16
+ /**
17
+ * The grid, as the form numbers it: `00`, `03`, `54`, `71`. Written with its
18
+ * leading zero here or not, it goes out with one.
19
+ */
20
+ box: string;
21
+ /**
22
+ * What the figure is: `base`, `tax`, or `total` for one the form computes.
23
+ * This form gives every grid one value, so two kinds on one grid is a
24
+ * violation rather than a choice made here.
25
+ */
26
+ kind?: string | null;
27
+ /** The amount. A string keeps the cents. */
28
+ amount: string | number;
29
+ }
30
+ /** The party filing. */
31
+ export interface Declarant {
32
+ /**
33
+ * The Belgian enterprise number of the declarant, ten digits and no `BE`.
34
+ * Anything else is refused rather than cleaned up.
35
+ */
36
+ vatNumber: string;
37
+ name?: string;
38
+ street?: string;
39
+ postCode?: string;
40
+ city?: string;
41
+ /** ISO 3166-1 alpha-2 of the declarant's address. */
42
+ countryCode?: string;
43
+ emailAddress?: string;
44
+ /** Digits only, country code included, as an administration stores it. */
45
+ phone?: string;
46
+ }
47
+ /**
48
+ * The period the return covers. Exactly one of `month` or `quarter`: a return
49
+ * is filed on one cadence or the other, and the form has one element for each.
50
+ */
51
+ export interface ReturnPeriod {
52
+ year: number;
53
+ month?: number;
54
+ quarter?: number;
55
+ }
56
+ /**
57
+ * What the declarant asks the administration for, which is a request and not a
58
+ * consequence of the figures. Both default to no, because asking is a decision
59
+ * and a file that asks by itself is a file nobody meant to send.
60
+ */
61
+ export interface Ask {
62
+ /** A refund of the credit this period ends on. */
63
+ restitution?: boolean;
64
+ /** The payment forms the administration sends out. */
65
+ payment?: boolean;
66
+ }
67
+ export interface VatConsignmentOptions {
68
+ declarant: Declarant;
69
+ period: ReturnPeriod;
70
+ /** Sequence number of this return inside the consignment. Default 1. */
71
+ sequenceNumber?: number;
72
+ /** The declarant's own reference for this filing, at most 14 characters. */
73
+ declarantReference?: string;
74
+ /**
75
+ * The Intervat reference of the declaration this one replaces, as the
76
+ * administration gave it back — `digits-ten digits-six digits`. A corrective
77
+ * sent without it is an original, so a malformed one is refused outright
78
+ * rather than left out.
79
+ */
80
+ replacedDeclaration?: string;
81
+ ask?: Ask;
82
+ /**
83
+ * Whether the annual listing of customers will be nil, which the form asks on
84
+ * the return of the last period of the year. The schema requires the element
85
+ * on every return, so it is always written, and it defaults to `NO` — which
86
+ * is the absence of a claim, not a claim that there will be a listing.
87
+ */
88
+ clientListingNihil?: boolean;
89
+ /** Free text the administration displays with the filing. */
90
+ comment?: string;
91
+ }
92
+ /**
93
+ * The party that files for others: an accounting firm, a fiduciary, anyone
94
+ * holding a mandate. The schema makes the whole block optional and **every
95
+ * field of it required** once it is there, so every field is required here:
96
+ * a representative is named entirely or not at all.
97
+ */
98
+ export interface Representative {
99
+ /** The identifier, as the authority that issued it writes it. */
100
+ id: string;
101
+ /** The member state that issued the identifier: one of {@link ISSUERS}. */
102
+ issuedBy: string;
103
+ /** What the identifier is: a VAT number, a tax identification number, or something else. */
104
+ identificationType: 'NVAT' | 'TIN' | 'other';
105
+ /** What `other` is. Written only with that type. */
106
+ otherQualifier?: string;
107
+ name: string;
108
+ street: string;
109
+ postCode: string;
110
+ city: string;
111
+ /** ISO 3166-1 alpha-2 of the representative's address. */
112
+ countryCode: string;
113
+ emailAddress: string;
114
+ /** Digits are what is written; twenty at most. */
115
+ phone: string;
116
+ }
117
+ /** One return of a consignment that holds several. */
118
+ export interface ConsignedReturn {
119
+ boxes: FiledBox[];
120
+ /**
121
+ * What {@link VatConsignmentOptions} says, for this return. A sequence
122
+ * number left out is the position of the return in the file, from 1.
123
+ */
124
+ options: VatConsignmentOptions;
125
+ }
126
+ /** What belongs to the consignment and not to any one return in it. */
127
+ export interface ConsignmentOptions {
128
+ representative?: Representative;
129
+ /** The representative's own reference for this consignment, at most 14 characters. */
130
+ representativeReference?: string;
131
+ }
132
+ /** Something that does not add up, said in the terms of this format. */
133
+ export interface Violation {
134
+ /** A stable token, for a caller that branches on it. */
135
+ code: string;
136
+ /** What is wrong, in a sentence. */
137
+ message: string;
138
+ /** The grid the trouble is on, where there is one. */
139
+ box?: string;
140
+ /**
141
+ * The sequence number of the return the trouble is in, when the consignment
142
+ * holds several. Absent on a consignment of one, where it would say nothing.
143
+ */
144
+ declaration?: number;
145
+ }
146
+ export interface VatConsignment {
147
+ /** The XML, as text. */
148
+ file: string;
149
+ /** A name for it. See the README: the administration imposes none. */
150
+ filename: string;
151
+ /** Everything that could not be put in the file, and why. */
152
+ violations: Violation[];
153
+ }
154
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The shapes this package reads and returns.
3
+ *
4
+ * {@link FiledBox} is the row shape of `tax_filing_boxes` in
5
+ * [Ekwo OS](https://github.com/Ekwo-ai/ekwo-os) — the figures of a declaration
6
+ * as they were frozen at filing — declared here so that nothing is imported
7
+ * from it. Any book-keeping system that can produce a box, what the box holds
8
+ * and an amount can use this package; it reads no database and knows no
9
+ * accounting.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@ekwo-ai/vat-consignment",
3
+ "version": "0.4.0",
4
+ "description": "The Belgian periodic VAT return for Intervat (VATConsignment XML, schema NewTVA-in v0.9) in TypeScript, from the figures a declaration was filed with. Zero dependencies.",
5
+ "keywords": [
6
+ "intervat",
7
+ "vatconsignment",
8
+ "vat-return",
9
+ "declaration-tva",
10
+ "tva",
11
+ "vat",
12
+ "belgium",
13
+ "spf-finances",
14
+ "xml"
15
+ ],
16
+ "license": "MIT",
17
+ "author": "Ekwo AI",
18
+ "homepage": "https://github.com/Ekwo-ai/ekwo-os/tree/main/packages/formats/vat-consignment#readme",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/Ekwo-ai/ekwo-os.git",
22
+ "directory": "packages/formats/vat-consignment"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Ekwo-ai/ekwo-os/issues"
26
+ },
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "main": "./dist/index.js",
38
+ "types": "./dist/index.d.ts",
39
+ "exports": {
40
+ ".": {
41
+ "types": "./dist/index.d.ts",
42
+ "import": "./dist/index.js"
43
+ }
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -p tsconfig.build.json",
47
+ "typecheck": "tsc -p tsconfig.json --noEmit",
48
+ "test": "vitest run"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^24.0.0",
52
+ "typescript": "^5.9.0",
53
+ "vitest": "^3.2.0",
54
+ "xmllint-wasm": "^5.3.0"
55
+ }
56
+ }