@beliq/sdk 0.4.0 → 0.4.2

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 ADDED
@@ -0,0 +1,82 @@
1
+ # Changelog
2
+
3
+ `@beliq/sdk` is on a 0.x line, so a caret range pins the minor: `^0.4.0`
4
+ resolves 0.4.x and never reaches 0.5.0. Additive spec syncs ship as patches for
5
+ that reason, and a minor is reserved for a change that needs consumers to opt in.
6
+
7
+ ## 0.4.2 - 2026-09-23
8
+
9
+ - Invoices carry allowances and charges at document level (BG-20, BG-21) and
10
+ line level (BG-27, BG-28), on `/v1/generate` and `/v1/parse`, as
11
+ `allowances` and `charges`. A document-level entry states its own VAT
12
+ category and rate; a line-level entry inherits the line's.
13
+ - `GET /v1/rulesets` reports `previousChannel` on every ruleset: what
14
+ `Beliq-Ruleset: previous` reaches for that format today, with
15
+ `servingVersion`, `previousVersion` and a `fallbackReason` of `sunset`,
16
+ `notice-period` or `superseded`.
17
+ - The publish job runs in the `release` GitHub environment, whose only
18
+ deployment policy is the `v*.*.*` tag pattern, so an edit to the workflow
19
+ cannot publish from another ref.
20
+
21
+ ## 0.4.1 - 2026-09-21
22
+
23
+ - Invoice lines carry the item's price detail and identity: `grossPrice`
24
+ (BT-148) with the per-unit `priceDiscount` (BT-147), `priceBaseQuantity`
25
+ (BT-149/150), `standardItemId` (BT-157), `classifications` (BT-158),
26
+ `originCountryCode` (BT-159) and `attributes` (BG-32). A discount needs a
27
+ gross price and `unitPrice` must equal `grossPrice` minus `priceDiscount`, or
28
+ the API answers 400. With a base quantity the line net (BT-131) is quantity x
29
+ (`unitPrice` / `priceBaseQuantity`), which is what lets a caller who prices
30
+ per 100 units pass PEPPOL-EN16931-R120. The fatturapa, facturae and eslog
31
+ targets read none of these fields.
32
+ - The release workflow refuses a tag whose version disagrees with
33
+ `package.json`. Tagging v0.4.1 against a manifest reading 0.4.0 used to
34
+ publish 0.4.0 and exit green, leaving a tag naming a version that never
35
+ shipped.
36
+
37
+ ## 0.4.0 - 2026-09-19
38
+
39
+ - `GET /v1/rulesets` reports retained ruleset versions, so a caller can see
40
+ which older rule sets are still servable rather than only the current one.
41
+ - Participant enrollment codes and the invoice delivery fields are typed.
42
+ - BT-6 (VAT accounting currency) and BT-111 (VAT amount in the accounting
43
+ currency) are typed on the invoice.
44
+ - A scheduled ruleset change reports its capabilities.
45
+ - The README's quick-start invoice is one the API accepts as-is.
46
+ - An em-dash scrub gate runs over the whole tree before publish, and the
47
+ release workflow carries job timeouts and refuses a tag that is not on `main`.
48
+ - The `js-yaml` override floor is raised above GHSA-2883-xcg3-v3hh.
49
+
50
+ ## 0.3.1 - 2026-09-02
51
+
52
+ - A spent monthly quota is raised, not retried. A 429 carrying
53
+ `QUOTA_EXCEEDED` is terminal, so the SDK makes exactly one attempt; a 429
54
+ carrying `RATE_LIMITED` or `ACCOUNT_THROTTLED` still retries. Retrying an
55
+ exhausted quota only burned the caller's own backoff window.
56
+ - The France transmission verdict fields and pre-flight error codes are typed.
57
+ - GitHub Actions are pinned to commit SHAs.
58
+
59
+ ## 0.3.0 - 2026-08-30
60
+
61
+ - A per-standard profile map: which profile each standard accepts, and which
62
+ standards pin their own and reject one sent by the caller.
63
+ - A per-attempt deadline, and transient failures are retried.
64
+ - The transport defaults are exported from the package entry point, so a caller
65
+ can read the timeout and retry values the SDK ships with.
66
+ - The vendored `openapi.json` is asserted byte-identical to what beliq-api
67
+ generates, and the drift check is directional in the code rather than only in
68
+ its comment. Ten Peppol emit error codes, the 413 responses, the verdict
69
+ verification tier and the `/v1/me` response shape are typed; two error codes
70
+ the API no longer declares are dropped.
71
+ - eslint 10 and flat config.
72
+
73
+ ## 0.2.0 - 2026-07-24
74
+
75
+ - Types refreshed to API 0.2.0: the generate seal, `livemode`, and the NLCIUS
76
+ preset.
77
+
78
+ ## 0.1.1 - 2026-06-30
79
+
80
+ - First published release. TypeScript/JavaScript SDK for the beliq e-invoice
81
+ API: generate, validate, parse and convert, ESM and CommonJS with bundled
82
+ type declarations.
package/README.md CHANGED
@@ -192,7 +192,7 @@ BELIQ_API_KEY=blq_xxx npm run test:integration # hits the live API; draws quot
192
192
 
193
193
  ## Publishing
194
194
 
195
- Released to npm as [`@beliq/sdk`](https://www.npmjs.com/package/@beliq/sdk). Releases run from `.github/workflows/release.yml` via npm Trusted Publishing (OIDC, with provenance): push a `v*.*.*` tag to publish. No npm token is stored in the repo.
195
+ Released to npm as [`@beliq/sdk`](https://www.npmjs.com/package/@beliq/sdk). Releases run from `.github/workflows/release.yml` via npm Trusted Publishing (OIDC, with provenance): bump `version` in `package.json`, run `npm install --package-lock-only`, add the release's entry to [`CHANGELOG.md`](CHANGELOG.md), merge, then push a `v*.*.*` tag on the merge commit to publish. No npm token is stored in the repo.
196
196
 
197
197
  ## License
198
198
 
package/dist/index.d.cts CHANGED
@@ -13,6 +13,37 @@ interface components {
13
13
  vatCategoryCode: string;
14
14
  itemId?: string;
15
15
  buyerItemId?: string;
16
+ grossPrice?: number;
17
+ priceDiscount?: number;
18
+ priceBaseQuantity?: number;
19
+ standardItemId?: {
20
+ id: string;
21
+ schemeId: string;
22
+ };
23
+ classifications?: {
24
+ code: string;
25
+ listId: string;
26
+ listVersionId?: string;
27
+ }[];
28
+ originCountryCode?: string;
29
+ attributes?: {
30
+ name: string;
31
+ value: string;
32
+ }[];
33
+ allowances?: {
34
+ amount: number;
35
+ baseAmount?: number;
36
+ percentage?: number;
37
+ reason?: string;
38
+ reasonCode?: string;
39
+ }[];
40
+ charges?: {
41
+ amount: number;
42
+ baseAmount?: number;
43
+ percentage?: number;
44
+ reason?: string;
45
+ reasonCode?: string;
46
+ }[];
16
47
  subLines?: components["schemas"]["InvoiceLine"][];
17
48
  };
18
49
  };
@@ -235,6 +266,37 @@ interface operations {
235
266
  vatCategoryCode: string;
236
267
  itemId?: string;
237
268
  buyerItemId?: string;
269
+ grossPrice?: number;
270
+ priceDiscount?: number;
271
+ priceBaseQuantity?: number;
272
+ standardItemId?: {
273
+ id: string;
274
+ schemeId: string;
275
+ };
276
+ classifications?: {
277
+ code: string;
278
+ listId: string;
279
+ listVersionId?: string;
280
+ }[];
281
+ originCountryCode?: string;
282
+ attributes?: {
283
+ name: string;
284
+ value: string;
285
+ }[];
286
+ allowances?: {
287
+ amount: number;
288
+ baseAmount?: number;
289
+ percentage?: number;
290
+ reason?: string;
291
+ reasonCode?: string;
292
+ }[];
293
+ charges?: {
294
+ amount: number;
295
+ baseAmount?: number;
296
+ percentage?: number;
297
+ reason?: string;
298
+ reasonCode?: string;
299
+ }[];
238
300
  subLines?: components["schemas"]["InvoiceLine"][];
239
301
  }[];
240
302
  taxSummary?: {
@@ -273,6 +335,24 @@ interface operations {
273
335
  debitedAccountId?: string;
274
336
  };
275
337
  paymentTerms?: string;
338
+ allowances?: {
339
+ amount: number;
340
+ baseAmount?: number;
341
+ percentage?: number;
342
+ reason?: string;
343
+ reasonCode?: string;
344
+ vatCategoryCode: string;
345
+ vatRate?: number;
346
+ }[];
347
+ charges?: {
348
+ amount: number;
349
+ baseAmount?: number;
350
+ percentage?: number;
351
+ reason?: string;
352
+ reasonCode?: string;
353
+ vatCategoryCode: string;
354
+ vatRate?: number;
355
+ }[];
276
356
  totalNetAmount: number;
277
357
  totalTaxAmount: number;
278
358
  totalGrossAmount: number;
@@ -609,7 +689,7 @@ interface operations {
609
689
  franceCtc?: boolean;
610
690
  };
611
691
  header?: {
612
- /** @description Pin the validation ruleset for this request. A channel ("latest" or "previous"), or a comma-separated list of exact per-format pins as "<artifactKey>:<version>" (e.g. "xrechnung_schematron:2.4.0"). The two forms are mutually exclusive. Default (no header) uses "latest". Effective on this route only — parse/generate/convert accept but ignore it. The applied ruleset is echoed in the Beliq-Ruleset-Resolved response header; see GET /v1/rulesets for selectable channels. */
692
+ /** @description Pin the validation ruleset for this request. A channel ("latest" or "previous"), or a comma-separated list of exact per-format pins as "<artifactKey>:<version>" (e.g. "xrechnung_schematron:2.4.0"). The two forms are mutually exclusive. Default (no header) uses "latest". Effective on this route only: parse/generate/convert accept but ignore it. The applied ruleset is echoed in the Beliq-Ruleset-Resolved response header; see GET /v1/rulesets for selectable channels. */
613
693
  "Beliq-Ruleset"?: string;
614
694
  };
615
695
  path?: never;
@@ -1006,6 +1086,37 @@ interface operations {
1006
1086
  vatCategoryCode: string;
1007
1087
  itemId?: string;
1008
1088
  buyerItemId?: string;
1089
+ grossPrice?: number;
1090
+ priceDiscount?: number;
1091
+ priceBaseQuantity?: number;
1092
+ standardItemId?: {
1093
+ id: string;
1094
+ schemeId: string;
1095
+ };
1096
+ classifications?: {
1097
+ code: string;
1098
+ listId: string;
1099
+ listVersionId?: string;
1100
+ }[];
1101
+ originCountryCode?: string;
1102
+ attributes?: {
1103
+ name: string;
1104
+ value: string;
1105
+ }[];
1106
+ allowances?: {
1107
+ amount: number;
1108
+ baseAmount?: number;
1109
+ percentage?: number;
1110
+ reason?: string;
1111
+ reasonCode?: string;
1112
+ }[];
1113
+ charges?: {
1114
+ amount: number;
1115
+ baseAmount?: number;
1116
+ percentage?: number;
1117
+ reason?: string;
1118
+ reasonCode?: string;
1119
+ }[];
1009
1120
  subLines?: components["schemas"]["InvoiceLine"][];
1010
1121
  }[];
1011
1122
  taxSummary?: {
@@ -1044,6 +1155,24 @@ interface operations {
1044
1155
  debitedAccountId?: string;
1045
1156
  };
1046
1157
  paymentTerms?: string;
1158
+ allowances?: {
1159
+ amount: number;
1160
+ baseAmount?: number;
1161
+ percentage?: number;
1162
+ reason?: string;
1163
+ reasonCode?: string;
1164
+ vatCategoryCode: string;
1165
+ vatRate?: number;
1166
+ }[];
1167
+ charges?: {
1168
+ amount: number;
1169
+ baseAmount?: number;
1170
+ percentage?: number;
1171
+ reason?: string;
1172
+ reasonCode?: string;
1173
+ vatCategoryCode: string;
1174
+ vatRate?: number;
1175
+ }[];
1047
1176
  totalNetAmount: number;
1048
1177
  totalTaxAmount: number;
1049
1178
  totalGrossAmount: number;
@@ -1557,6 +1686,17 @@ interface operations {
1557
1686
  /** @description ISO 8601 date (YYYY-MM-DD) the authority made this version's successor mandatory, or null when it published no date. Once it has passed, `Beliq-Ruleset: previous` no longer resolves to this version and sets `rulesetFellBack: true`, because a document built to it is rejected by the receiving corner. An exact version pin is unaffected and still reaches it until `retainedUntil`. */
1558
1687
  supersededMandatoryOn: string | null;
1559
1688
  }[];
1689
+ /** @description What `Beliq-Ruleset: previous` reaches for this format, one row per rule artifact in its run set that retains a version. Empty for a format whose artifacts have never had a breaking bump. A `POST /v1/validate` request on `previous` sets `rulesetFellBack: true` only when EVERY artifact fell back, so this format falls back entirely exactly when no row here has a non-null `previousVersion`. Wider than `retained[]`, which covers only this format's own `versionKey`. */
1690
+ previousChannel: {
1691
+ /** @description The `versions.json` artefact key this row is about. Often this format's own `versionKey`, but not always: an overlay or a severity table that runs under the format's profiles decides its `previous` too, and names no format of its own. */
1692
+ versionKey: string;
1693
+ /** @description The version `latest` serves for this artefact today. The other half of the pair to compare against `previousVersion`. */
1694
+ servingVersion: string;
1695
+ /** @description The version `Beliq-Ruleset: previous` resolves to for this artefact today, or null when the channel falls back to `latest` for it. Pin it exactly as `Beliq-Ruleset: <versionKey>:<previousVersion>` to reach it regardless. */
1696
+ previousVersion: string | null;
1697
+ /** @description Why `previous` reaches nothing for this artefact; null exactly when `previousVersion` is set. `sunset` = every retained version is past its `retainedUntil`, so not even an exact pin resolves. `notice-period` = the only retained version is the one standing in for `latest` until a scheduled bump takes effect, so there is nothing behind it yet. `superseded` = the authority made the successor mandatory, so Beliq will not choose the older ruleset on your behalf; an exact pin still reaches it until `retainedUntil`. */
1698
+ fallbackReason: "sunset" | "notice-period" | "superseded" | null;
1699
+ }[];
1560
1700
  }[];
1561
1701
  channels: {
1562
1702
  id: "latest" | "previous";
package/dist/index.d.ts CHANGED
@@ -13,6 +13,37 @@ interface components {
13
13
  vatCategoryCode: string;
14
14
  itemId?: string;
15
15
  buyerItemId?: string;
16
+ grossPrice?: number;
17
+ priceDiscount?: number;
18
+ priceBaseQuantity?: number;
19
+ standardItemId?: {
20
+ id: string;
21
+ schemeId: string;
22
+ };
23
+ classifications?: {
24
+ code: string;
25
+ listId: string;
26
+ listVersionId?: string;
27
+ }[];
28
+ originCountryCode?: string;
29
+ attributes?: {
30
+ name: string;
31
+ value: string;
32
+ }[];
33
+ allowances?: {
34
+ amount: number;
35
+ baseAmount?: number;
36
+ percentage?: number;
37
+ reason?: string;
38
+ reasonCode?: string;
39
+ }[];
40
+ charges?: {
41
+ amount: number;
42
+ baseAmount?: number;
43
+ percentage?: number;
44
+ reason?: string;
45
+ reasonCode?: string;
46
+ }[];
16
47
  subLines?: components["schemas"]["InvoiceLine"][];
17
48
  };
18
49
  };
@@ -235,6 +266,37 @@ interface operations {
235
266
  vatCategoryCode: string;
236
267
  itemId?: string;
237
268
  buyerItemId?: string;
269
+ grossPrice?: number;
270
+ priceDiscount?: number;
271
+ priceBaseQuantity?: number;
272
+ standardItemId?: {
273
+ id: string;
274
+ schemeId: string;
275
+ };
276
+ classifications?: {
277
+ code: string;
278
+ listId: string;
279
+ listVersionId?: string;
280
+ }[];
281
+ originCountryCode?: string;
282
+ attributes?: {
283
+ name: string;
284
+ value: string;
285
+ }[];
286
+ allowances?: {
287
+ amount: number;
288
+ baseAmount?: number;
289
+ percentage?: number;
290
+ reason?: string;
291
+ reasonCode?: string;
292
+ }[];
293
+ charges?: {
294
+ amount: number;
295
+ baseAmount?: number;
296
+ percentage?: number;
297
+ reason?: string;
298
+ reasonCode?: string;
299
+ }[];
238
300
  subLines?: components["schemas"]["InvoiceLine"][];
239
301
  }[];
240
302
  taxSummary?: {
@@ -273,6 +335,24 @@ interface operations {
273
335
  debitedAccountId?: string;
274
336
  };
275
337
  paymentTerms?: string;
338
+ allowances?: {
339
+ amount: number;
340
+ baseAmount?: number;
341
+ percentage?: number;
342
+ reason?: string;
343
+ reasonCode?: string;
344
+ vatCategoryCode: string;
345
+ vatRate?: number;
346
+ }[];
347
+ charges?: {
348
+ amount: number;
349
+ baseAmount?: number;
350
+ percentage?: number;
351
+ reason?: string;
352
+ reasonCode?: string;
353
+ vatCategoryCode: string;
354
+ vatRate?: number;
355
+ }[];
276
356
  totalNetAmount: number;
277
357
  totalTaxAmount: number;
278
358
  totalGrossAmount: number;
@@ -609,7 +689,7 @@ interface operations {
609
689
  franceCtc?: boolean;
610
690
  };
611
691
  header?: {
612
- /** @description Pin the validation ruleset for this request. A channel ("latest" or "previous"), or a comma-separated list of exact per-format pins as "<artifactKey>:<version>" (e.g. "xrechnung_schematron:2.4.0"). The two forms are mutually exclusive. Default (no header) uses "latest". Effective on this route only — parse/generate/convert accept but ignore it. The applied ruleset is echoed in the Beliq-Ruleset-Resolved response header; see GET /v1/rulesets for selectable channels. */
692
+ /** @description Pin the validation ruleset for this request. A channel ("latest" or "previous"), or a comma-separated list of exact per-format pins as "<artifactKey>:<version>" (e.g. "xrechnung_schematron:2.4.0"). The two forms are mutually exclusive. Default (no header) uses "latest". Effective on this route only: parse/generate/convert accept but ignore it. The applied ruleset is echoed in the Beliq-Ruleset-Resolved response header; see GET /v1/rulesets for selectable channels. */
613
693
  "Beliq-Ruleset"?: string;
614
694
  };
615
695
  path?: never;
@@ -1006,6 +1086,37 @@ interface operations {
1006
1086
  vatCategoryCode: string;
1007
1087
  itemId?: string;
1008
1088
  buyerItemId?: string;
1089
+ grossPrice?: number;
1090
+ priceDiscount?: number;
1091
+ priceBaseQuantity?: number;
1092
+ standardItemId?: {
1093
+ id: string;
1094
+ schemeId: string;
1095
+ };
1096
+ classifications?: {
1097
+ code: string;
1098
+ listId: string;
1099
+ listVersionId?: string;
1100
+ }[];
1101
+ originCountryCode?: string;
1102
+ attributes?: {
1103
+ name: string;
1104
+ value: string;
1105
+ }[];
1106
+ allowances?: {
1107
+ amount: number;
1108
+ baseAmount?: number;
1109
+ percentage?: number;
1110
+ reason?: string;
1111
+ reasonCode?: string;
1112
+ }[];
1113
+ charges?: {
1114
+ amount: number;
1115
+ baseAmount?: number;
1116
+ percentage?: number;
1117
+ reason?: string;
1118
+ reasonCode?: string;
1119
+ }[];
1009
1120
  subLines?: components["schemas"]["InvoiceLine"][];
1010
1121
  }[];
1011
1122
  taxSummary?: {
@@ -1044,6 +1155,24 @@ interface operations {
1044
1155
  debitedAccountId?: string;
1045
1156
  };
1046
1157
  paymentTerms?: string;
1158
+ allowances?: {
1159
+ amount: number;
1160
+ baseAmount?: number;
1161
+ percentage?: number;
1162
+ reason?: string;
1163
+ reasonCode?: string;
1164
+ vatCategoryCode: string;
1165
+ vatRate?: number;
1166
+ }[];
1167
+ charges?: {
1168
+ amount: number;
1169
+ baseAmount?: number;
1170
+ percentage?: number;
1171
+ reason?: string;
1172
+ reasonCode?: string;
1173
+ vatCategoryCode: string;
1174
+ vatRate?: number;
1175
+ }[];
1047
1176
  totalNetAmount: number;
1048
1177
  totalTaxAmount: number;
1049
1178
  totalGrossAmount: number;
@@ -1557,6 +1686,17 @@ interface operations {
1557
1686
  /** @description ISO 8601 date (YYYY-MM-DD) the authority made this version's successor mandatory, or null when it published no date. Once it has passed, `Beliq-Ruleset: previous` no longer resolves to this version and sets `rulesetFellBack: true`, because a document built to it is rejected by the receiving corner. An exact version pin is unaffected and still reaches it until `retainedUntil`. */
1558
1687
  supersededMandatoryOn: string | null;
1559
1688
  }[];
1689
+ /** @description What `Beliq-Ruleset: previous` reaches for this format, one row per rule artifact in its run set that retains a version. Empty for a format whose artifacts have never had a breaking bump. A `POST /v1/validate` request on `previous` sets `rulesetFellBack: true` only when EVERY artifact fell back, so this format falls back entirely exactly when no row here has a non-null `previousVersion`. Wider than `retained[]`, which covers only this format's own `versionKey`. */
1690
+ previousChannel: {
1691
+ /** @description The `versions.json` artefact key this row is about. Often this format's own `versionKey`, but not always: an overlay or a severity table that runs under the format's profiles decides its `previous` too, and names no format of its own. */
1692
+ versionKey: string;
1693
+ /** @description The version `latest` serves for this artefact today. The other half of the pair to compare against `previousVersion`. */
1694
+ servingVersion: string;
1695
+ /** @description The version `Beliq-Ruleset: previous` resolves to for this artefact today, or null when the channel falls back to `latest` for it. Pin it exactly as `Beliq-Ruleset: <versionKey>:<previousVersion>` to reach it regardless. */
1696
+ previousVersion: string | null;
1697
+ /** @description Why `previous` reaches nothing for this artefact; null exactly when `previousVersion` is set. `sunset` = every retained version is past its `retainedUntil`, so not even an exact pin resolves. `notice-period` = the only retained version is the one standing in for `latest` until a scheduled bump takes effect, so there is nothing behind it yet. `superseded` = the authority made the successor mandatory, so Beliq will not choose the older ruleset on your behalf; an exact pin still reaches it until `retainedUntil`. */
1698
+ fallbackReason: "sunset" | "notice-period" | "superseded" | null;
1699
+ }[];
1560
1700
  }[];
1561
1701
  channels: {
1562
1702
  id: "latest" | "previous";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beliq/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Official beliq SDK: generate, validate, parse, and convert EU-compliant e-invoices (XRechnung, ZUGFeRD, Factur-X, Peppol BIS) against authority-pinned, drift-checked rules.",
5
5
  "keywords": [
6
6
  "beliq",
@@ -55,7 +55,8 @@
55
55
  },
56
56
  "files": [
57
57
  "dist",
58
- "examples"
58
+ "examples",
59
+ "CHANGELOG.md"
59
60
  ],
60
61
  "publishConfig": {
61
62
  "access": "public",