@beliq/sdk 0.1.1 → 0.2.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/README.md +35 -5
- package/dist/{constants-bWOXCmJD.d.cts → constants-D3j_o7th.d.cts} +19 -1
- package/dist/{constants-bWOXCmJD.d.ts → constants-D3j_o7th.d.ts} +19 -1
- package/dist/helpers.cjs +11 -1
- package/dist/helpers.d.cts +6 -2
- package/dist/helpers.d.ts +6 -2
- package/dist/helpers.js +10 -1
- package/dist/index.cjs +81 -7
- package/dist/index.d.cts +188 -27
- package/dist/index.d.ts +188 -27
- package/dist/index.js +80 -7
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -52,9 +52,16 @@ if (!result.valid) {
|
|
|
52
52
|
Create an API key in the beliq dashboard under API Keys, then pass it to the client:
|
|
53
53
|
|
|
54
54
|
```ts
|
|
55
|
-
new Beliq({ apiKey: '
|
|
56
|
-
new Beliq({ apiKey: '
|
|
57
|
-
new Beliq({ apiKey: '
|
|
55
|
+
new Beliq({ apiKey: 'blq_live_...' }); // sends X-API-Key (default)
|
|
56
|
+
new Beliq({ apiKey: 'blq_live_...', auth: 'bearer' }); // sends Authorization: Bearer
|
|
57
|
+
new Beliq({ apiKey: 'blq_live_...', baseUrl: 'https://staging.beliq.eu' });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Keys are prefixed `blq_live_` (production, draws your plan quota) or `blq_test_` (sandbox, separate free allowance, watermarked output). `client.livemode` reports the mode from the key prefix before any request; generate and convert results also carry the authoritative `meta.livemode` from the response.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
|
|
64
|
+
if (!beliq.livemode) console.warn('running against the sandbox');
|
|
58
65
|
```
|
|
59
66
|
|
|
60
67
|
## API
|
|
@@ -62,12 +69,35 @@ new Beliq({ apiKey: 'blq_...', baseUrl: 'https://staging.beliq.eu' });
|
|
|
62
69
|
| Method | Endpoint | Input | Returns |
|
|
63
70
|
|---|---|---|---|
|
|
64
71
|
| `me()` | GET /v1/me | none | `AccountInfo` (no quota cost) |
|
|
65
|
-
| `generate(input)` | POST /v1/generate | EN 16931 invoice object | `{ contentType, bytes, xml?, meta }` |
|
|
72
|
+
| `generate(input)` | POST /v1/generate | EN 16931 invoice object | `{ contentType, bytes, xml?, sha256?, validationResult?, meta }` |
|
|
66
73
|
| `validate(document, options?)` | POST /v1/validate | XML or PDF | `ValidationResult` |
|
|
67
74
|
| `parse(document, options?)` | POST /v1/parse | XML or PDF | `ParseResult` |
|
|
68
75
|
| `convert(document, options)` | POST /v1/convert | XML or PDF | `{ contentType, bytes, meta }` |
|
|
69
76
|
|
|
70
|
-
`document` accepts a `string`, `Uint8Array`, `Buffer`, `ArrayBuffer`, or typed array. The content type is sniffed from the bytes (PDF vs XML) unless you pass `options.contentType`. `generate` and `convert` return raw document bytes plus the response-header metadata (`schematronVersion`, `pdfKind`, `sourceFormat`/`targetFormat`, `lostElements`, `conversionTools`); for an XML output, `generate` also decodes `xml`.
|
|
77
|
+
`document` accepts a `string`, `Uint8Array`, `Buffer`, `ArrayBuffer`, or typed array. The content type is sniffed from the bytes (PDF vs XML) unless you pass `options.contentType`. `generate` and `convert` return raw document bytes plus the response-header metadata (`schematronVersion`, `pdfKind`, `sourceFormat`/`targetFormat`, `lostElements`, `conversionTools`, `livemode`); for an XML output, `generate` also decodes `xml`.
|
|
78
|
+
|
|
79
|
+
### Verify-it-yourself seal
|
|
80
|
+
|
|
81
|
+
Pass `seal: true` to `generate` to also get the document `sha256` and the full `validationResult`. Hashing the returned bytes reproduces the hash, so a recipient can check the document independently:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { createHash } from 'node:crypto';
|
|
85
|
+
|
|
86
|
+
const doc = await beliq.generate({ standard: 'xrechnung', invoice, seal: true });
|
|
87
|
+
const ok = createHash('sha256').update(doc.bytes).digest('hex') === doc.sha256;
|
|
88
|
+
console.log(doc.validationResult?.valid, doc.meta.rulesetSha256, ok);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Curated option lists
|
|
92
|
+
|
|
93
|
+
`LIVE_GENERATE_PRESETS` is the set of public generate targets beliq.eu itself offers, each mapping to the API `standard` (plus `profile`/`facturxProfile`) it needs. NLCIUS is a Peppol BIS profile and lives here rather than in `LIVE_GENERATE_STANDARDS`. Connectors build their dropdowns from these lists.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { LIVE_GENERATE_PRESETS } from '@beliq/sdk';
|
|
97
|
+
|
|
98
|
+
const nlcius = LIVE_GENERATE_PRESETS.find((p) => p.id === 'nlcius');
|
|
99
|
+
await beliq.generate({ standard: nlcius!.standard, profile: nlcius!.profile, invoice });
|
|
100
|
+
```
|
|
71
101
|
|
|
72
102
|
Every option enum is typed from the OpenAPI spec, so wrong values fail at compile time. Errors throw `BeliqApiError` with a typed `.code`, HTTP `.status`, and any `.details`:
|
|
73
103
|
|
|
@@ -13,10 +13,28 @@ declare function sniffContentType(bytes: Uint8Array): string;
|
|
|
13
13
|
|
|
14
14
|
declare const DEFAULT_BASE_URL = "https://api.beliq.eu";
|
|
15
15
|
declare const LIVE_GENERATE_STANDARDS: readonly ["xrechnung", "zugferd", "facturx", "peppol-bis"];
|
|
16
|
+
/** A named generate target: the API `standard` plus the `profile`/`facturxProfile`/`output` it needs. */
|
|
17
|
+
interface GeneratePreset {
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
standard: (typeof LIVE_GENERATE_STANDARDS)[number];
|
|
21
|
+
output: 'xml' | 'pdf';
|
|
22
|
+
/** API `profile`; omitted lets the engine pick the standard's default. */
|
|
23
|
+
profile?: string;
|
|
24
|
+
/** API `facturxProfile`; Factur-X / ZUGFeRD only. */
|
|
25
|
+
facturxProfile?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Named generate targets surfaced to end users (connector dropdowns), mirroring
|
|
29
|
+
* the public set on beliq.eu's own generator. NLCIUS is a Peppol BIS profile,
|
|
30
|
+
* not a standalone standard, so it is reachable here rather than through
|
|
31
|
+
* LIVE_GENERATE_STANDARDS or the Factur-X-only LIVE_PROFILES.
|
|
32
|
+
*/
|
|
33
|
+
declare const LIVE_GENERATE_PRESETS: readonly GeneratePreset[];
|
|
16
34
|
declare const LIVE_PROFILES: readonly ["basicwl", "en16931", "extended", "extended-ctc-fr"];
|
|
17
35
|
declare const LIVE_VALIDATE_FORMATS: readonly ["auto", "cii", "ubl"];
|
|
18
36
|
declare const LIVE_PARSE_FORMATS: readonly ["auto", "cii", "ubl"];
|
|
19
37
|
declare const LIVE_CONVERT_SOURCE_FORMATS: readonly ["auto", "cii", "ubl", "zugferd", "facturx", "xrechnung", "peppol-bis"];
|
|
20
38
|
declare const LIVE_CONVERT_TARGET_FORMATS: readonly ["cii", "ubl", "zugferd", "facturx", "xrechnung", "peppol-bis"];
|
|
21
39
|
|
|
22
|
-
export { DEFAULT_BASE_URL as D, LIVE_CONVERT_SOURCE_FORMATS as L, type PlainObject as P, type DocumentInput as a, LIVE_CONVERT_TARGET_FORMATS as b,
|
|
40
|
+
export { DEFAULT_BASE_URL as D, type GeneratePreset as G, LIVE_CONVERT_SOURCE_FORMATS as L, type PlainObject as P, type DocumentInput as a, LIVE_CONVERT_TARGET_FORMATS as b, LIVE_GENERATE_PRESETS as c, LIVE_GENERATE_STANDARDS as d, LIVE_PARSE_FORMATS as e, LIVE_PROFILES as f, LIVE_VALIDATE_FORMATS as g, compactQuery as h, decodeUtf8 as i, isPlainObject as j, mergeDeep as m, sniffContentType as s, toBytes as t };
|
|
@@ -13,10 +13,28 @@ declare function sniffContentType(bytes: Uint8Array): string;
|
|
|
13
13
|
|
|
14
14
|
declare const DEFAULT_BASE_URL = "https://api.beliq.eu";
|
|
15
15
|
declare const LIVE_GENERATE_STANDARDS: readonly ["xrechnung", "zugferd", "facturx", "peppol-bis"];
|
|
16
|
+
/** A named generate target: the API `standard` plus the `profile`/`facturxProfile`/`output` it needs. */
|
|
17
|
+
interface GeneratePreset {
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
standard: (typeof LIVE_GENERATE_STANDARDS)[number];
|
|
21
|
+
output: 'xml' | 'pdf';
|
|
22
|
+
/** API `profile`; omitted lets the engine pick the standard's default. */
|
|
23
|
+
profile?: string;
|
|
24
|
+
/** API `facturxProfile`; Factur-X / ZUGFeRD only. */
|
|
25
|
+
facturxProfile?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Named generate targets surfaced to end users (connector dropdowns), mirroring
|
|
29
|
+
* the public set on beliq.eu's own generator. NLCIUS is a Peppol BIS profile,
|
|
30
|
+
* not a standalone standard, so it is reachable here rather than through
|
|
31
|
+
* LIVE_GENERATE_STANDARDS or the Factur-X-only LIVE_PROFILES.
|
|
32
|
+
*/
|
|
33
|
+
declare const LIVE_GENERATE_PRESETS: readonly GeneratePreset[];
|
|
16
34
|
declare const LIVE_PROFILES: readonly ["basicwl", "en16931", "extended", "extended-ctc-fr"];
|
|
17
35
|
declare const LIVE_VALIDATE_FORMATS: readonly ["auto", "cii", "ubl"];
|
|
18
36
|
declare const LIVE_PARSE_FORMATS: readonly ["auto", "cii", "ubl"];
|
|
19
37
|
declare const LIVE_CONVERT_SOURCE_FORMATS: readonly ["auto", "cii", "ubl", "zugferd", "facturx", "xrechnung", "peppol-bis"];
|
|
20
38
|
declare const LIVE_CONVERT_TARGET_FORMATS: readonly ["cii", "ubl", "zugferd", "facturx", "xrechnung", "peppol-bis"];
|
|
21
39
|
|
|
22
|
-
export { DEFAULT_BASE_URL as D, LIVE_CONVERT_SOURCE_FORMATS as L, type PlainObject as P, type DocumentInput as a, LIVE_CONVERT_TARGET_FORMATS as b,
|
|
40
|
+
export { DEFAULT_BASE_URL as D, type GeneratePreset as G, LIVE_CONVERT_SOURCE_FORMATS as L, type PlainObject as P, type DocumentInput as a, LIVE_CONVERT_TARGET_FORMATS as b, LIVE_GENERATE_PRESETS as c, LIVE_GENERATE_STANDARDS as d, LIVE_PARSE_FORMATS as e, LIVE_PROFILES as f, LIVE_VALIDATE_FORMATS as g, compactQuery as h, decodeUtf8 as i, isPlainObject as j, mergeDeep as m, sniffContentType as s, toBytes as t };
|
package/dist/helpers.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(helpers_exports, {
|
|
|
23
23
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
24
24
|
LIVE_CONVERT_SOURCE_FORMATS: () => LIVE_CONVERT_SOURCE_FORMATS,
|
|
25
25
|
LIVE_CONVERT_TARGET_FORMATS: () => LIVE_CONVERT_TARGET_FORMATS,
|
|
26
|
+
LIVE_GENERATE_PRESETS: () => LIVE_GENERATE_PRESETS,
|
|
26
27
|
LIVE_GENERATE_STANDARDS: () => LIVE_GENERATE_STANDARDS,
|
|
27
28
|
LIVE_PARSE_FORMATS: () => LIVE_PARSE_FORMATS,
|
|
28
29
|
LIVE_PROFILES: () => LIVE_PROFILES,
|
|
@@ -111,7 +112,8 @@ function buildRequest(params) {
|
|
|
111
112
|
path: "/v1/generate",
|
|
112
113
|
jsonBody: merged,
|
|
113
114
|
contentType: "application/json",
|
|
114
|
-
|
|
115
|
+
// JSON mode returns the seal envelope; binary mode returns the raw document body.
|
|
116
|
+
...params.sealed ? { accept: "application/json", outputKind: "json" } : { outputKind: "binary" }
|
|
115
117
|
};
|
|
116
118
|
}
|
|
117
119
|
case "validate": {
|
|
@@ -161,6 +163,13 @@ function buildRequest(params) {
|
|
|
161
163
|
// src/constants.ts
|
|
162
164
|
var DEFAULT_BASE_URL = "https://api.beliq.eu";
|
|
163
165
|
var LIVE_GENERATE_STANDARDS = ["xrechnung", "zugferd", "facturx", "peppol-bis"];
|
|
166
|
+
var LIVE_GENERATE_PRESETS = [
|
|
167
|
+
{ id: "xrechnung", label: "XRechnung", standard: "xrechnung", output: "xml" },
|
|
168
|
+
{ id: "factur-x", label: "Factur-X", standard: "facturx", output: "pdf", facturxProfile: "en16931" },
|
|
169
|
+
{ id: "zugferd", label: "ZUGFeRD", standard: "zugferd", output: "pdf" },
|
|
170
|
+
{ id: "peppol-bis", label: "Peppol BIS 3.0", standard: "peppol-bis", output: "xml" },
|
|
171
|
+
{ id: "nlcius", label: "NLCIUS", standard: "peppol-bis", output: "xml", profile: "netherlands-nlcius" }
|
|
172
|
+
];
|
|
164
173
|
var LIVE_PROFILES = ["basicwl", "en16931", "extended", "extended-ctc-fr"];
|
|
165
174
|
var LIVE_VALIDATE_FORMATS = ["auto", "cii", "ubl"];
|
|
166
175
|
var LIVE_PARSE_FORMATS = ["auto", "cii", "ubl"];
|
|
@@ -186,6 +195,7 @@ var LIVE_CONVERT_TARGET_FORMATS = [
|
|
|
186
195
|
DEFAULT_BASE_URL,
|
|
187
196
|
LIVE_CONVERT_SOURCE_FORMATS,
|
|
188
197
|
LIVE_CONVERT_TARGET_FORMATS,
|
|
198
|
+
LIVE_GENERATE_PRESETS,
|
|
189
199
|
LIVE_GENERATE_STANDARDS,
|
|
190
200
|
LIVE_PARSE_FORMATS,
|
|
191
201
|
LIVE_PROFILES,
|
package/dist/helpers.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PlainObject } from './constants-
|
|
2
|
-
export { D as DEFAULT_BASE_URL, a as DocumentInput, L as LIVE_CONVERT_SOURCE_FORMATS, b as LIVE_CONVERT_TARGET_FORMATS, c as
|
|
1
|
+
import { P as PlainObject } from './constants-D3j_o7th.cjs';
|
|
2
|
+
export { D as DEFAULT_BASE_URL, a as DocumentInput, G as GeneratePreset, L as LIVE_CONVERT_SOURCE_FORMATS, b as LIVE_CONVERT_TARGET_FORMATS, c as LIVE_GENERATE_PRESETS, d as LIVE_GENERATE_STANDARDS, e as LIVE_PARSE_FORMATS, f as LIVE_PROFILES, g as LIVE_VALIDATE_FORMATS, h as compactQuery, i as decodeUtf8, j as isPlainObject, m as mergeDeep, s as sniffContentType, t as toBytes } from './constants-D3j_o7th.cjs';
|
|
3
3
|
|
|
4
4
|
type Operation = 'me' | 'generate' | 'validate' | 'parse' | 'convert';
|
|
5
5
|
/** 'json' => parse the `{ success, data }` envelope; 'binary' => return raw bytes. */
|
|
@@ -15,6 +15,8 @@ interface BuildParams {
|
|
|
15
15
|
verify?: boolean;
|
|
16
16
|
template?: string;
|
|
17
17
|
pdfTemplateId?: string;
|
|
18
|
+
/** Request the JSON-mode seal (Accept: application/json) instead of the binary body. */
|
|
19
|
+
sealed?: boolean;
|
|
18
20
|
rawBody?: Uint8Array;
|
|
19
21
|
rawContentType?: string;
|
|
20
22
|
validateFormat?: string;
|
|
@@ -37,6 +39,8 @@ interface BuiltRequest {
|
|
|
37
39
|
rawBody?: Uint8Array;
|
|
38
40
|
/** Request content type; absent for GET. */
|
|
39
41
|
contentType?: string;
|
|
42
|
+
/** Accept header; set when the caller wants a JSON envelope from an otherwise-binary op. */
|
|
43
|
+
accept?: string;
|
|
40
44
|
outputKind: OutputKind;
|
|
41
45
|
}
|
|
42
46
|
declare function buildRequest(params: BuildParams): BuiltRequest;
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PlainObject } from './constants-
|
|
2
|
-
export { D as DEFAULT_BASE_URL, a as DocumentInput, L as LIVE_CONVERT_SOURCE_FORMATS, b as LIVE_CONVERT_TARGET_FORMATS, c as
|
|
1
|
+
import { P as PlainObject } from './constants-D3j_o7th.js';
|
|
2
|
+
export { D as DEFAULT_BASE_URL, a as DocumentInput, G as GeneratePreset, L as LIVE_CONVERT_SOURCE_FORMATS, b as LIVE_CONVERT_TARGET_FORMATS, c as LIVE_GENERATE_PRESETS, d as LIVE_GENERATE_STANDARDS, e as LIVE_PARSE_FORMATS, f as LIVE_PROFILES, g as LIVE_VALIDATE_FORMATS, h as compactQuery, i as decodeUtf8, j as isPlainObject, m as mergeDeep, s as sniffContentType, t as toBytes } from './constants-D3j_o7th.js';
|
|
3
3
|
|
|
4
4
|
type Operation = 'me' | 'generate' | 'validate' | 'parse' | 'convert';
|
|
5
5
|
/** 'json' => parse the `{ success, data }` envelope; 'binary' => return raw bytes. */
|
|
@@ -15,6 +15,8 @@ interface BuildParams {
|
|
|
15
15
|
verify?: boolean;
|
|
16
16
|
template?: string;
|
|
17
17
|
pdfTemplateId?: string;
|
|
18
|
+
/** Request the JSON-mode seal (Accept: application/json) instead of the binary body. */
|
|
19
|
+
sealed?: boolean;
|
|
18
20
|
rawBody?: Uint8Array;
|
|
19
21
|
rawContentType?: string;
|
|
20
22
|
validateFormat?: string;
|
|
@@ -37,6 +39,8 @@ interface BuiltRequest {
|
|
|
37
39
|
rawBody?: Uint8Array;
|
|
38
40
|
/** Request content type; absent for GET. */
|
|
39
41
|
contentType?: string;
|
|
42
|
+
/** Accept header; set when the caller wants a JSON envelope from an otherwise-binary op. */
|
|
43
|
+
accept?: string;
|
|
40
44
|
outputKind: OutputKind;
|
|
41
45
|
}
|
|
42
46
|
declare function buildRequest(params: BuildParams): BuiltRequest;
|
package/dist/helpers.js
CHANGED
|
@@ -72,7 +72,8 @@ function buildRequest(params) {
|
|
|
72
72
|
path: "/v1/generate",
|
|
73
73
|
jsonBody: merged,
|
|
74
74
|
contentType: "application/json",
|
|
75
|
-
|
|
75
|
+
// JSON mode returns the seal envelope; binary mode returns the raw document body.
|
|
76
|
+
...params.sealed ? { accept: "application/json", outputKind: "json" } : { outputKind: "binary" }
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
case "validate": {
|
|
@@ -122,6 +123,13 @@ function buildRequest(params) {
|
|
|
122
123
|
// src/constants.ts
|
|
123
124
|
var DEFAULT_BASE_URL = "https://api.beliq.eu";
|
|
124
125
|
var LIVE_GENERATE_STANDARDS = ["xrechnung", "zugferd", "facturx", "peppol-bis"];
|
|
126
|
+
var LIVE_GENERATE_PRESETS = [
|
|
127
|
+
{ id: "xrechnung", label: "XRechnung", standard: "xrechnung", output: "xml" },
|
|
128
|
+
{ id: "factur-x", label: "Factur-X", standard: "facturx", output: "pdf", facturxProfile: "en16931" },
|
|
129
|
+
{ id: "zugferd", label: "ZUGFeRD", standard: "zugferd", output: "pdf" },
|
|
130
|
+
{ id: "peppol-bis", label: "Peppol BIS 3.0", standard: "peppol-bis", output: "xml" },
|
|
131
|
+
{ id: "nlcius", label: "NLCIUS", standard: "peppol-bis", output: "xml", profile: "netherlands-nlcius" }
|
|
132
|
+
];
|
|
125
133
|
var LIVE_PROFILES = ["basicwl", "en16931", "extended", "extended-ctc-fr"];
|
|
126
134
|
var LIVE_VALIDATE_FORMATS = ["auto", "cii", "ubl"];
|
|
127
135
|
var LIVE_PARSE_FORMATS = ["auto", "cii", "ubl"];
|
|
@@ -146,6 +154,7 @@ export {
|
|
|
146
154
|
DEFAULT_BASE_URL,
|
|
147
155
|
LIVE_CONVERT_SOURCE_FORMATS,
|
|
148
156
|
LIVE_CONVERT_TARGET_FORMATS,
|
|
157
|
+
LIVE_GENERATE_PRESETS,
|
|
149
158
|
LIVE_GENERATE_STANDARDS,
|
|
150
159
|
LIVE_PARSE_FORMATS,
|
|
151
160
|
LIVE_PROFILES,
|
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
26
26
|
LIVE_CONVERT_SOURCE_FORMATS: () => LIVE_CONVERT_SOURCE_FORMATS,
|
|
27
27
|
LIVE_CONVERT_TARGET_FORMATS: () => LIVE_CONVERT_TARGET_FORMATS,
|
|
28
|
+
LIVE_GENERATE_PRESETS: () => LIVE_GENERATE_PRESETS,
|
|
28
29
|
LIVE_GENERATE_STANDARDS: () => LIVE_GENERATE_STANDARDS,
|
|
29
30
|
LIVE_PARSE_FORMATS: () => LIVE_PARSE_FORMATS,
|
|
30
31
|
LIVE_PROFILES: () => LIVE_PROFILES,
|
|
@@ -68,6 +69,18 @@ function toBytes(input) {
|
|
|
68
69
|
function decodeUtf8(bytes) {
|
|
69
70
|
return new TextDecoder("utf-8").decode(bytes);
|
|
70
71
|
}
|
|
72
|
+
function decodeBase64(input) {
|
|
73
|
+
const b64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
74
|
+
if (typeof atob === "function") {
|
|
75
|
+
const bin = atob(b64);
|
|
76
|
+
const out = new Uint8Array(bin.length);
|
|
77
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
const maybeBuffer = globalThis.Buffer;
|
|
81
|
+
if (maybeBuffer) return new Uint8Array(maybeBuffer.from(b64, "base64"));
|
|
82
|
+
throw new Error("beliq: no base64 decoder available in this runtime");
|
|
83
|
+
}
|
|
71
84
|
var PDF_MAGIC = [37, 80, 68, 70, 45];
|
|
72
85
|
function sniffContentType(bytes) {
|
|
73
86
|
const isPdf = bytes.length >= PDF_MAGIC.length && PDF_MAGIC.every((b, i) => bytes[i] === b);
|
|
@@ -106,7 +119,8 @@ function buildRequest(params) {
|
|
|
106
119
|
path: "/v1/generate",
|
|
107
120
|
jsonBody: merged,
|
|
108
121
|
contentType: "application/json",
|
|
109
|
-
|
|
122
|
+
// JSON mode returns the seal envelope; binary mode returns the raw document body.
|
|
123
|
+
...params.sealed ? { accept: "application/json", outputKind: "json" } : { outputKind: "binary" }
|
|
110
124
|
};
|
|
111
125
|
}
|
|
112
126
|
case "validate": {
|
|
@@ -191,6 +205,13 @@ function errorFromResponse(status, bytes) {
|
|
|
191
205
|
// src/constants.ts
|
|
192
206
|
var DEFAULT_BASE_URL = "https://api.beliq.eu";
|
|
193
207
|
var LIVE_GENERATE_STANDARDS = ["xrechnung", "zugferd", "facturx", "peppol-bis"];
|
|
208
|
+
var LIVE_GENERATE_PRESETS = [
|
|
209
|
+
{ id: "xrechnung", label: "XRechnung", standard: "xrechnung", output: "xml" },
|
|
210
|
+
{ id: "factur-x", label: "Factur-X", standard: "facturx", output: "pdf", facturxProfile: "en16931" },
|
|
211
|
+
{ id: "zugferd", label: "ZUGFeRD", standard: "zugferd", output: "pdf" },
|
|
212
|
+
{ id: "peppol-bis", label: "Peppol BIS 3.0", standard: "peppol-bis", output: "xml" },
|
|
213
|
+
{ id: "nlcius", label: "NLCIUS", standard: "peppol-bis", output: "xml", profile: "netherlands-nlcius" }
|
|
214
|
+
];
|
|
194
215
|
var LIVE_PROFILES = ["basicwl", "en16931", "extended", "extended-ctc-fr"];
|
|
195
216
|
var LIVE_VALIDATE_FORMATS = ["auto", "cii", "ubl"];
|
|
196
217
|
var LIVE_PARSE_FORMATS = ["auto", "cii", "ubl"];
|
|
@@ -229,6 +250,7 @@ function buildUrl(baseUrl, path, query) {
|
|
|
229
250
|
async function send(config, req) {
|
|
230
251
|
const headers = { ...authHeaders(config) };
|
|
231
252
|
if (req.contentType) headers["Content-Type"] = req.contentType;
|
|
253
|
+
if (req.accept) headers["Accept"] = req.accept;
|
|
232
254
|
const body = req.jsonBody !== void 0 ? JSON.stringify(req.jsonBody) : req.rawBody;
|
|
233
255
|
const res = await config.fetchImpl(buildUrl(config.baseUrl, req.path, req.query), {
|
|
234
256
|
method: req.method,
|
|
@@ -241,11 +263,31 @@ async function send(config, req) {
|
|
|
241
263
|
}
|
|
242
264
|
|
|
243
265
|
// src/client.ts
|
|
266
|
+
var TEST_KEY_PREFIX = "blq_test_";
|
|
267
|
+
function livemodeHeader(headers) {
|
|
268
|
+
const raw = headers.get("x-beliq-livemode");
|
|
269
|
+
if (raw === "true") return true;
|
|
270
|
+
if (raw === "false") return false;
|
|
271
|
+
return void 0;
|
|
272
|
+
}
|
|
273
|
+
function parseRulesetArtifacts(headers) {
|
|
274
|
+
const raw = headers.get("x-ruleset-artifacts");
|
|
275
|
+
if (!raw) return void 0;
|
|
276
|
+
try {
|
|
277
|
+
const parsed = JSON.parse(raw);
|
|
278
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
279
|
+
} catch {
|
|
280
|
+
return void 0;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
244
283
|
function generateMeta(headers) {
|
|
245
284
|
return {
|
|
246
285
|
schematronVersion: headers.get("x-schematron-version") ?? void 0,
|
|
247
286
|
pdfKind: headers.get("x-pdf-kind") ?? void 0,
|
|
248
|
-
outputEnvelope: headers.get("x-output-envelope") ?? void 0
|
|
287
|
+
outputEnvelope: headers.get("x-output-envelope") ?? void 0,
|
|
288
|
+
rulesetSha256: headers.get("x-ruleset-sha256") ?? void 0,
|
|
289
|
+
rulesetArtifacts: parseRulesetArtifacts(headers),
|
|
290
|
+
livemode: livemodeHeader(headers)
|
|
249
291
|
};
|
|
250
292
|
}
|
|
251
293
|
function convertMeta(headers) {
|
|
@@ -265,17 +307,25 @@ function convertMeta(headers) {
|
|
|
265
307
|
profileDetected: headers.get("x-profile-detected") ?? void 0,
|
|
266
308
|
lostElementsCount: countRaw != null ? Number(countRaw) : void 0,
|
|
267
309
|
lostElements,
|
|
268
|
-
conversionTools: headers.get("x-conversion-tools") ?? void 0
|
|
310
|
+
conversionTools: headers.get("x-conversion-tools") ?? void 0,
|
|
311
|
+
livemode: livemodeHeader(headers)
|
|
269
312
|
};
|
|
270
313
|
}
|
|
271
314
|
var Beliq = class {
|
|
272
315
|
#config;
|
|
316
|
+
/**
|
|
317
|
+
* True for a live key, false for a blq_test_ sandbox key, derived from the key
|
|
318
|
+
* prefix (the same rule the server applies). Available before any request; the
|
|
319
|
+
* per-response x-beliq-livemode header is surfaced on generate/convert meta.
|
|
320
|
+
*/
|
|
321
|
+
livemode;
|
|
273
322
|
constructor(options) {
|
|
274
323
|
if (!options?.apiKey) throw new Error("beliq: apiKey is required");
|
|
275
324
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
276
325
|
if (typeof fetchImpl !== "function") {
|
|
277
326
|
throw new Error("beliq: no global fetch available; pass options.fetch");
|
|
278
327
|
}
|
|
328
|
+
this.livemode = !options.apiKey.startsWith(TEST_KEY_PREFIX);
|
|
279
329
|
this.#config = {
|
|
280
330
|
apiKey: options.apiKey,
|
|
281
331
|
baseUrl: (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""),
|
|
@@ -289,14 +339,37 @@ var Beliq = class {
|
|
|
289
339
|
}
|
|
290
340
|
/** Generate a compliant e-invoice from an EN 16931 object. */
|
|
291
341
|
async generate(input) {
|
|
292
|
-
const res = await send(
|
|
342
|
+
const res = await send(
|
|
343
|
+
this.#config,
|
|
344
|
+
buildRequest({ operation: "generate", ...input, sealed: input.seal })
|
|
345
|
+
);
|
|
346
|
+
const meta = generateMeta(res.headers);
|
|
347
|
+
if (input.seal) {
|
|
348
|
+
const envelope = parseEnvelope(res.bytes);
|
|
349
|
+
if (envelope?.success === false) throw errorFromResponse(res.status, res.bytes);
|
|
350
|
+
const data = envelope?.data;
|
|
351
|
+
if (!data || data.output === void 0) {
|
|
352
|
+
throw new BeliqApiError("beliq: seal response was not a JSON envelope", {
|
|
353
|
+
status: res.status
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const bytes = decodeBase64(data.output);
|
|
357
|
+
const contentType2 = data.contentType ?? "application/octet-stream";
|
|
358
|
+
return {
|
|
359
|
+
contentType: contentType2,
|
|
360
|
+
bytes,
|
|
361
|
+
xml: contentType2.includes("xml") ? decodeUtf8(bytes) : void 0,
|
|
362
|
+
sha256: data.sha256,
|
|
363
|
+
validationResult: data.validationResult,
|
|
364
|
+
meta
|
|
365
|
+
};
|
|
366
|
+
}
|
|
293
367
|
const contentType = res.headers.get("content-type") ?? "application/octet-stream";
|
|
294
|
-
const isXml = contentType.includes("xml");
|
|
295
368
|
return {
|
|
296
369
|
contentType,
|
|
297
370
|
bytes: res.bytes,
|
|
298
|
-
xml:
|
|
299
|
-
meta
|
|
371
|
+
xml: contentType.includes("xml") ? decodeUtf8(res.bytes) : void 0,
|
|
372
|
+
meta
|
|
300
373
|
};
|
|
301
374
|
}
|
|
302
375
|
/** Validate a document against authority-pinned rules. */
|
|
@@ -360,6 +433,7 @@ var Beliq = class {
|
|
|
360
433
|
DEFAULT_BASE_URL,
|
|
361
434
|
LIVE_CONVERT_SOURCE_FORMATS,
|
|
362
435
|
LIVE_CONVERT_TARGET_FORMATS,
|
|
436
|
+
LIVE_GENERATE_PRESETS,
|
|
363
437
|
LIVE_GENERATE_STANDARDS,
|
|
364
438
|
LIVE_PARSE_FORMATS,
|
|
365
439
|
LIVE_PROFILES,
|