@financica/scrada-client 0.2.1 → 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/dist/index.d.ts +64 -1
- package/dist/index.js +87 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -192,6 +192,37 @@ interface ScradaPeppolLookupResponse {
|
|
|
192
192
|
} | null;
|
|
193
193
|
}> | null;
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Peppol routing for `sendOutboundDocument`. The raw-UBL outbound endpoint does
|
|
197
|
+
* not parse the document for routing, so the sender, receiver, document type
|
|
198
|
+
* and process must be supplied as `x-scrada-peppol-*` request headers. All
|
|
199
|
+
* fields are required by Scrada; `externalReference` is optional (portal- and
|
|
200
|
+
* webhook-only, not used for Peppol).
|
|
201
|
+
*
|
|
202
|
+
* @see POST /company/{companyID}/peppol/outbound/document
|
|
203
|
+
*/
|
|
204
|
+
interface PeppolOutboundDocumentRouting {
|
|
205
|
+
/** Sender participant scheme — always `iso6523-actorid-upis`. */
|
|
206
|
+
senderScheme: string;
|
|
207
|
+
/** Sender participant id, e.g. `0208:0800279001`. */
|
|
208
|
+
senderId: string;
|
|
209
|
+
/** Receiver participant scheme — always `iso6523-actorid-upis`. */
|
|
210
|
+
receiverScheme: string;
|
|
211
|
+
/** Receiver participant id, e.g. `9925:BE0206582284`. */
|
|
212
|
+
receiverId: string;
|
|
213
|
+
/** ISO 3166-1 alpha-2 country where the sender is legally present (C1), e.g. `BE`. */
|
|
214
|
+
c1CountryCode: string;
|
|
215
|
+
/** Document type scheme, e.g. `busdox-docid-qns`. */
|
|
216
|
+
documentTypeScheme: string;
|
|
217
|
+
/** Document type value (the BIS Billing 3.0 Invoice or CreditNote doc-type id). */
|
|
218
|
+
documentTypeValue: string;
|
|
219
|
+
/** Process scheme, e.g. `cenbii-procid-ubl`. */
|
|
220
|
+
processScheme: string;
|
|
221
|
+
/** Process value, e.g. `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0`. */
|
|
222
|
+
processValue: string;
|
|
223
|
+
/** Optional caller reference surfaced in the Scrada portal and webhooks. */
|
|
224
|
+
externalReference?: string;
|
|
225
|
+
}
|
|
195
226
|
|
|
196
227
|
interface ScradaApiClientOptions {
|
|
197
228
|
apiKey: string;
|
|
@@ -227,6 +258,7 @@ declare class ScradaApiClient {
|
|
|
227
258
|
getInboundDocument(companyId: string, documentId: string): Promise<ScradaInboundDocumentResponse>;
|
|
228
259
|
getInboundDocumentPdf(companyId: string, documentId: string): Promise<ScradaInboundPdfResponse>;
|
|
229
260
|
confirmInboundDocument(companyId: string, documentId: string): Promise<void>;
|
|
261
|
+
private postOutbound;
|
|
230
262
|
/**
|
|
231
263
|
* @param options.idempotencyKey Sent as `Idempotency-Key`. A transient
|
|
232
264
|
* network-error retry with the same key is collapsed by Scrada, so the
|
|
@@ -236,7 +268,38 @@ declare class ScradaApiClient {
|
|
|
236
268
|
sendOutboundSalesInvoice(companyId: string, payload: PeppolOnlyInvoice, options?: {
|
|
237
269
|
idempotencyKey?: string;
|
|
238
270
|
}): Promise<string>;
|
|
271
|
+
/**
|
|
272
|
+
* Send a self-billing invoice or credit note (buyer issues the document
|
|
273
|
+
* on behalf of the supplier). Same payload shape as a sales invoice.
|
|
274
|
+
*
|
|
275
|
+
* @param options.idempotencyKey See `sendOutboundSalesInvoice`.
|
|
276
|
+
*/
|
|
277
|
+
sendOutboundSelfBillingInvoice(companyId: string, payload: PeppolOnlyInvoice, options?: {
|
|
278
|
+
idempotencyKey?: string;
|
|
279
|
+
}): Promise<string>;
|
|
280
|
+
/**
|
|
281
|
+
* Deliver a pre-built UBL document directly to Peppol. Use this when you
|
|
282
|
+
* already have a UBL XML string (BIS3 invoice, credit note, self-billing,
|
|
283
|
+
* Invoice Response, etc.); for JSON payloads use `sendOutboundSalesInvoice`
|
|
284
|
+
* or `sendOutboundSelfBillingInvoice` instead.
|
|
285
|
+
*
|
|
286
|
+
* The endpoint does not parse the UBL for routing, so `options.routing`
|
|
287
|
+
* (sender, receiver, document type and process) is required and sent as
|
|
288
|
+
* `x-scrada-peppol-*` headers — without it Scrada rejects the request with
|
|
289
|
+
* "Http header 'x-scrada-peppol-sender-scheme' is missing".
|
|
290
|
+
*
|
|
291
|
+
* @param options.idempotencyKey See `sendOutboundSalesInvoice`.
|
|
292
|
+
*/
|
|
293
|
+
sendOutboundDocument(companyId: string, ubl: string, options: {
|
|
294
|
+
routing: PeppolOutboundDocumentRouting;
|
|
295
|
+
idempotencyKey?: string;
|
|
296
|
+
}): Promise<string>;
|
|
239
297
|
getOutboundDocumentInfo(companyId: string, documentId: string): Promise<ScradaOutboundDocumentInfo>;
|
|
298
|
+
/**
|
|
299
|
+
* Fetch the rendered UBL XML for an outbound document — useful when the
|
|
300
|
+
* document was sent as JSON and Scrada generated the UBL.
|
|
301
|
+
*/
|
|
302
|
+
getOutboundDocumentUbl(companyId: string, documentId: string): Promise<string>;
|
|
240
303
|
lookupPeppolParticipant(companyId: string, scheme: string, id: string): Promise<ScradaPeppolLookupResponse>;
|
|
241
304
|
lookupPeppolParty(companyId: string, payload: Record<string, unknown>): Promise<ScradaPeppolLookupResponse>;
|
|
242
305
|
}
|
|
@@ -282,4 +345,4 @@ declare const summarizeScradaErrorDetails: (details: unknown) => string | null;
|
|
|
282
345
|
*/
|
|
283
346
|
declare const scradaApiErrorFromResponse: (response: Response) => Promise<ScradaApiError>;
|
|
284
347
|
|
|
285
|
-
export { type CompanyInvoiceLineVatType, type CompanyInvoiceTaxNumberType, type CompanyVatStatus, DEFAULT_PEPPOL_COMPANY_IDENTIFIER_SCHEME, DEFAULT_PEPPOL_DOCUMENT_TYPE_SCHEME, DEFAULT_PEPPOL_DOCUMENT_TYPE_VALUE, DEFAULT_PEPPOL_PROCESS_SCHEME, DEFAULT_PEPPOL_PROCESS_VALUE, DEFAULT_PEPPOL_SENDER_IDENTIFIER_SCHEME, DEFAULT_PEPPOL_VAT_IDENTIFIER_SCHEME, DEFAULT_SCRADA_API_BASE_URL, type PeppolOnlyInvoice, type PeppolOnlyInvoiceLine, type PeppolOnlyInvoiceParty, SCRADA_ATTACHMENT_FILE_TYPE_INVOICE, SCRADA_LANGUAGE_HEADER, type SalesInvoiceVatTotal, type ScradaAddress, ScradaApiClient, type ScradaApiClientOptions, ScradaApiError, type ScradaInboundDocumentResponse, type ScradaInboundDocumentSummary, type ScradaInboundPdfResponse, type ScradaInboundUnconfirmedResponse, type ScradaInvoiceAttachment, type ScradaOutboundDocumentInfo, type ScradaPeppolLookupResponse, createScradaApiClientFromEnv, scradaApiErrorFromResponse, summarizeScradaErrorDetails };
|
|
348
|
+
export { type CompanyInvoiceLineVatType, type CompanyInvoiceTaxNumberType, type CompanyVatStatus, DEFAULT_PEPPOL_COMPANY_IDENTIFIER_SCHEME, DEFAULT_PEPPOL_DOCUMENT_TYPE_SCHEME, DEFAULT_PEPPOL_DOCUMENT_TYPE_VALUE, DEFAULT_PEPPOL_PROCESS_SCHEME, DEFAULT_PEPPOL_PROCESS_VALUE, DEFAULT_PEPPOL_SENDER_IDENTIFIER_SCHEME, DEFAULT_PEPPOL_VAT_IDENTIFIER_SCHEME, DEFAULT_SCRADA_API_BASE_URL, type PeppolOnlyInvoice, type PeppolOnlyInvoiceLine, type PeppolOnlyInvoiceParty, type PeppolOutboundDocumentRouting, SCRADA_ATTACHMENT_FILE_TYPE_INVOICE, SCRADA_LANGUAGE_HEADER, type SalesInvoiceVatTotal, type ScradaAddress, ScradaApiClient, type ScradaApiClientOptions, ScradaApiError, type ScradaInboundDocumentResponse, type ScradaInboundDocumentSummary, type ScradaInboundPdfResponse, type ScradaInboundUnconfirmedResponse, type ScradaInvoiceAttachment, type ScradaOutboundDocumentInfo, type ScradaPeppolLookupResponse, createScradaApiClientFromEnv, scradaApiErrorFromResponse, summarizeScradaErrorDetails };
|
package/dist/index.js
CHANGED
|
@@ -101,6 +101,23 @@ var scradaApiErrorFromResponse = async (response) => {
|
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
// src/client.ts
|
|
104
|
+
var routingHeaders = (routing) => {
|
|
105
|
+
const headers = {
|
|
106
|
+
"x-scrada-peppol-sender-scheme": routing.senderScheme,
|
|
107
|
+
"x-scrada-peppol-sender-id": routing.senderId,
|
|
108
|
+
"x-scrada-peppol-receiver-scheme": routing.receiverScheme,
|
|
109
|
+
"x-scrada-peppol-receiver-id": routing.receiverId,
|
|
110
|
+
"x-scrada-peppol-c1-country-code": routing.c1CountryCode,
|
|
111
|
+
"x-scrada-peppol-document-type-scheme": routing.documentTypeScheme,
|
|
112
|
+
"x-scrada-peppol-document-type-value": routing.documentTypeValue,
|
|
113
|
+
"x-scrada-peppol-process-scheme": routing.processScheme,
|
|
114
|
+
"x-scrada-peppol-process-value": routing.processValue
|
|
115
|
+
};
|
|
116
|
+
if (routing.externalReference) {
|
|
117
|
+
headers["x-scrada-external-reference"] = routing.externalReference;
|
|
118
|
+
}
|
|
119
|
+
return headers;
|
|
120
|
+
};
|
|
104
121
|
var joinUrl = (baseUrl, path) => {
|
|
105
122
|
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
106
123
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
@@ -247,32 +264,90 @@ var ScradaApiClient = class {
|
|
|
247
264
|
});
|
|
248
265
|
}
|
|
249
266
|
// ── Outbound documents ──────────────────────────────────────────────
|
|
250
|
-
|
|
251
|
-
* @param options.idempotencyKey Sent as `Idempotency-Key`. A transient
|
|
252
|
-
* network-error retry with the same key is collapsed by Scrada, so the
|
|
253
|
-
* recipient's Peppol endpoint won't receive the same invoice twice. The
|
|
254
|
-
* caller should pass a deterministic key (typically the invoice ID).
|
|
255
|
-
*/
|
|
256
|
-
async sendOutboundSalesInvoice(companyId, payload, options) {
|
|
267
|
+
async postOutbound(params) {
|
|
257
268
|
const headers = {
|
|
258
|
-
"Content-Type":
|
|
269
|
+
"Content-Type": params.contentType,
|
|
270
|
+
...params.extraHeaders
|
|
259
271
|
};
|
|
260
|
-
if (
|
|
261
|
-
headers["Idempotency-Key"] =
|
|
272
|
+
if (params.idempotencyKey) {
|
|
273
|
+
headers["Idempotency-Key"] = params.idempotencyKey;
|
|
262
274
|
}
|
|
263
275
|
const response = await this.request({
|
|
264
|
-
path: `/company/${companyId}/peppol/outbound
|
|
276
|
+
path: `/company/${params.companyId}/peppol/outbound/${params.segment}`,
|
|
265
277
|
method: "POST",
|
|
266
278
|
headers,
|
|
267
|
-
body:
|
|
279
|
+
body: params.body
|
|
268
280
|
});
|
|
269
281
|
return normalizeDocumentId(response);
|
|
270
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* @param options.idempotencyKey Sent as `Idempotency-Key`. A transient
|
|
285
|
+
* network-error retry with the same key is collapsed by Scrada, so the
|
|
286
|
+
* recipient's Peppol endpoint won't receive the same invoice twice. The
|
|
287
|
+
* caller should pass a deterministic key (typically the invoice ID).
|
|
288
|
+
*/
|
|
289
|
+
async sendOutboundSalesInvoice(companyId, payload, options) {
|
|
290
|
+
return this.postOutbound({
|
|
291
|
+
companyId,
|
|
292
|
+
segment: "salesInvoice",
|
|
293
|
+
body: JSON.stringify(payload),
|
|
294
|
+
contentType: "application/json",
|
|
295
|
+
idempotencyKey: options?.idempotencyKey
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Send a self-billing invoice or credit note (buyer issues the document
|
|
300
|
+
* on behalf of the supplier). Same payload shape as a sales invoice.
|
|
301
|
+
*
|
|
302
|
+
* @param options.idempotencyKey See `sendOutboundSalesInvoice`.
|
|
303
|
+
*/
|
|
304
|
+
async sendOutboundSelfBillingInvoice(companyId, payload, options) {
|
|
305
|
+
return this.postOutbound({
|
|
306
|
+
companyId,
|
|
307
|
+
segment: "selfBillingInvoice",
|
|
308
|
+
body: JSON.stringify(payload),
|
|
309
|
+
contentType: "application/json",
|
|
310
|
+
idempotencyKey: options?.idempotencyKey
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Deliver a pre-built UBL document directly to Peppol. Use this when you
|
|
315
|
+
* already have a UBL XML string (BIS3 invoice, credit note, self-billing,
|
|
316
|
+
* Invoice Response, etc.); for JSON payloads use `sendOutboundSalesInvoice`
|
|
317
|
+
* or `sendOutboundSelfBillingInvoice` instead.
|
|
318
|
+
*
|
|
319
|
+
* The endpoint does not parse the UBL for routing, so `options.routing`
|
|
320
|
+
* (sender, receiver, document type and process) is required and sent as
|
|
321
|
+
* `x-scrada-peppol-*` headers — without it Scrada rejects the request with
|
|
322
|
+
* "Http header 'x-scrada-peppol-sender-scheme' is missing".
|
|
323
|
+
*
|
|
324
|
+
* @param options.idempotencyKey See `sendOutboundSalesInvoice`.
|
|
325
|
+
*/
|
|
326
|
+
async sendOutboundDocument(companyId, ubl, options) {
|
|
327
|
+
return this.postOutbound({
|
|
328
|
+
companyId,
|
|
329
|
+
segment: "document",
|
|
330
|
+
body: ubl,
|
|
331
|
+
contentType: "application/xml",
|
|
332
|
+
idempotencyKey: options.idempotencyKey,
|
|
333
|
+
extraHeaders: routingHeaders(options.routing)
|
|
334
|
+
});
|
|
335
|
+
}
|
|
271
336
|
async getOutboundDocumentInfo(companyId, documentId) {
|
|
272
337
|
return this.request({
|
|
273
338
|
path: `/company/${companyId}/peppol/outbound/document/${documentId}/info`
|
|
274
339
|
});
|
|
275
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Fetch the rendered UBL XML for an outbound document — useful when the
|
|
343
|
+
* document was sent as JSON and Scrada generated the UBL.
|
|
344
|
+
*/
|
|
345
|
+
async getOutboundDocumentUbl(companyId, documentId) {
|
|
346
|
+
return this.request({
|
|
347
|
+
path: `/company/${companyId}/peppol/outbound/document/${documentId}/ubl`,
|
|
348
|
+
expect: "text"
|
|
349
|
+
});
|
|
350
|
+
}
|
|
276
351
|
// ── Peppol participant lookup ───────────────────────────────────────
|
|
277
352
|
async lookupPeppolParticipant(companyId, scheme, id) {
|
|
278
353
|
return this.request({
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export const DEFAULT_SCRADA_API_BASE_URL = \"https://api.scrada.be/v1\";\n\n/** Language sent in the Scrada `Language` request header (server may localize errors). */\nexport const SCRADA_LANGUAGE_HEADER = \"EN\";\n\n// ── Peppol identifier scheme defaults ────────────────────────────────\n\nexport const DEFAULT_PEPPOL_SENDER_IDENTIFIER_SCHEME = \"iso6523-actorid-upis\";\n/** ISO/IEC 6523 0208: Belgian enterprise number (KBO/BCE). */\nexport const DEFAULT_PEPPOL_COMPANY_IDENTIFIER_SCHEME = \"0208\";\n/** ISO/IEC 6523 9925: Belgian VAT number scheme. */\nexport const DEFAULT_PEPPOL_VAT_IDENTIFIER_SCHEME = \"9925\";\nexport const DEFAULT_PEPPOL_DOCUMENT_TYPE_SCHEME = \"busdox-docid-qns\";\nexport const DEFAULT_PEPPOL_DOCUMENT_TYPE_VALUE =\n\t\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1\";\nexport const DEFAULT_PEPPOL_PROCESS_SCHEME = \"cenbii-procid-ubl\";\nexport const DEFAULT_PEPPOL_PROCESS_VALUE =\n\t\"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\";\n\n// ── Scrada attachment file type codes ────────────────────────────────\n\n/** Scrada `attachment.fileType` value for the primary invoice/credit note PDF. */\nexport const SCRADA_ATTACHMENT_FILE_TYPE_INVOICE = 1;\n","export class ScradaApiError extends Error {\n\tstatus: number;\n\tdetails: unknown;\n\n\tconstructor(message: string, status: number, details: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"ScradaApiError\";\n\t\tthis.status = status;\n\t\tthis.details = details;\n\t}\n}\n\nconst tryParseJson = (value: string): unknown => {\n\ttry {\n\t\treturn JSON.parse(value) as unknown;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst normalizeDetailMessage = (value: string) => value.trim().replace(/\\s+/g, \" \");\n\nconst collectDetailMessages = (value: unknown, collector: Set<string>, depth = 0) => {\n\tif (depth > 4 || value === null || value === undefined) return;\n\n\tif (typeof value === \"string\") {\n\t\tconst normalized = normalizeDetailMessage(value);\n\t\tif (normalized.length > 0) collector.add(normalized);\n\t\treturn;\n\t}\n\n\tif (Array.isArray(value)) {\n\t\tfor (const entry of value) {\n\t\t\tcollectDetailMessages(entry, collector, depth + 1);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (typeof value !== \"object\") return;\n\tconst record = value as Record<string, unknown>;\n\n\tconst preferredFields = [\n\t\t\"defaultFormat\",\n\t\t\"message\",\n\t\t\"error\",\n\t\t\"title\",\n\t\t\"detail\",\n\t\t\"description\",\n\t\t\"reason\",\n\t];\n\n\tfor (const field of preferredFields) {\n\t\tconst fieldValue = record[field];\n\t\tif (typeof fieldValue === \"string\") {\n\t\t\tconst normalized = normalizeDetailMessage(fieldValue);\n\t\t\tif (normalized.length > 0) collector.add(normalized);\n\t\t}\n\t}\n\n\tconst nestedFields = [\"details\", \"errors\", \"validationErrors\", \"modelState\"];\n\tfor (const field of nestedFields) {\n\t\tif (field in record) {\n\t\t\tcollectDetailMessages(record[field], collector, depth + 1);\n\t\t}\n\t}\n\n\tfor (const [key, fieldValue] of Object.entries(record)) {\n\t\tif (preferredFields.includes(key) || nestedFields.includes(key)) continue;\n\t\tif (typeof fieldValue === \"string\") {\n\t\t\tconst normalized = normalizeDetailMessage(fieldValue);\n\t\t\tif (normalized.length > 0 && /error|invalid|missing|required/i.test(key)) {\n\t\t\t\tcollector.add(normalized);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tArray.isArray(fieldValue) ||\n\t\t\t(fieldValue && typeof fieldValue === \"object\")\n\t\t) {\n\t\t\tcollectDetailMessages(fieldValue, collector, depth + 1);\n\t\t}\n\t}\n};\n\n/**\n * Walks a Scrada error response body and pulls out the human-readable\n * message strings. Returns `null` when nothing usable is found.\n *\n * Scrada returns errors in several shapes (string, `{message}`,\n * `{errors: [{detail}]}`, `{modelState: {...}}`, etc.); this collapses\n * them into a single ` | `-separated summary.\n */\nexport const summarizeScradaErrorDetails = (details: unknown): string | null => {\n\tconst collector = new Set<string>();\n\tcollectDetailMessages(details, collector);\n\tif (collector.size === 0) return null;\n\treturn Array.from(collector).slice(0, 6).join(\" | \");\n};\n\nconst coerceErrorMessage = (details: unknown, fallback: string) =>\n\tsummarizeScradaErrorDetails(details) ?? fallback;\n\n/**\n * Converts a non-2xx Scrada response into a ScradaApiError, parsing the body\n * as JSON when possible and extracting message strings via\n * {@link summarizeScradaErrorDetails}.\n */\nexport const scradaApiErrorFromResponse = async (\n\tresponse: Response,\n): Promise<ScradaApiError> => {\n\tconst textBody = await response.text();\n\tconst parsed = tryParseJson(textBody) ?? textBody;\n\treturn new ScradaApiError(\n\t\tcoerceErrorMessage(\n\t\t\tparsed,\n\t\t\t`Scrada request failed with status ${response.status}`,\n\t\t),\n\t\tresponse.status,\n\t\tparsed,\n\t);\n};\n","import { DEFAULT_SCRADA_API_BASE_URL, SCRADA_LANGUAGE_HEADER } from \"./constants\";\nimport { scradaApiErrorFromResponse } from \"./errors\";\nimport type {\n\tPeppolOnlyInvoice,\n\tScradaInboundDocumentResponse,\n\tScradaInboundUnconfirmedResponse,\n\tScradaOutboundDocumentInfo,\n\tScradaPeppolLookupResponse,\n} from \"./types\";\n\ntype ScradaRequestMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\nexport interface ScradaApiClientOptions {\n\tapiKey: string;\n\tpassword: string;\n\tbaseUrl?: string;\n\t/** Override the global `fetch` (e.g. for testing). */\n\tfetch?: typeof fetch;\n}\n\nexport interface ScradaInboundPdfResponse {\n\tarrayBuffer: ArrayBuffer;\n\tcontentType: string;\n\theaders: Record<string, string>;\n}\n\nconst joinUrl = (baseUrl: string, path: string) => {\n\tconst normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n\tconst normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n\treturn `${normalizedBase}${normalizedPath}`;\n};\n\nconst normalizeHeaders = (headers: Headers) => {\n\tconst result: Record<string, string> = {};\n\theaders.forEach((value, key) => {\n\t\tresult[key.toLowerCase()] = value;\n\t});\n\treturn result;\n};\n\nconst normalizeDocumentId = (value: unknown): string => {\n\tif (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n\tif (value && typeof value === \"object\") {\n\t\tconst record = value as Record<string, unknown>;\n\t\tif (typeof record.id === \"string\" && record.id.trim().length > 0) {\n\t\t\treturn record.id.trim();\n\t\t}\n\t\tif (\n\t\t\ttypeof record.documentID === \"string\" &&\n\t\t\trecord.documentID.trim().length > 0\n\t\t) {\n\t\t\treturn record.documentID.trim();\n\t\t}\n\t}\n\tthrow new Error(\"Unable to resolve document ID from Scrada response\");\n};\n\nconst tryParseJson = (value: string): unknown => {\n\ttry {\n\t\treturn JSON.parse(value) as unknown;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/**\n * HTTP client for the Scrada Peppol API.\n *\n * https://api.scrada.be/v1\n *\n * Authenticates with API key + password sent as `X-API-KEY` / `X-PASSWORD`\n * headers. All non-2xx responses surface as `ScradaApiError`.\n */\nexport class ScradaApiClient {\n\tprivate readonly apiKey: string;\n\tprivate readonly password: string;\n\tprivate readonly baseUrl: string;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(options: ScradaApiClientOptions) {\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.password = options.password;\n\t\tthis.baseUrl = options.baseUrl ?? DEFAULT_SCRADA_API_BASE_URL;\n\t\tthis.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n\t}\n\n\tprivate buildHeaders(extra?: HeadersInit): Headers {\n\t\tconst headers = new Headers({\n\t\t\t\"X-API-KEY\": this.apiKey,\n\t\t\t\"X-PASSWORD\": this.password,\n\t\t\tLanguage: SCRADA_LANGUAGE_HEADER,\n\t\t});\n\t\tif (extra) {\n\t\t\tconst extraHeaders = new Headers(extra);\n\t\t\textraHeaders.forEach((value, key) => {\n\t\t\t\theaders.set(key, value);\n\t\t\t});\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate async request<T>(params: {\n\t\tpath: string;\n\t\tmethod?: ScradaRequestMethod;\n\t\tbody?: BodyInit;\n\t\theaders?: HeadersInit;\n\t\texpect?: \"json\" | \"text\" | \"arrayBuffer\";\n\t}): Promise<T> {\n\t\tconst response = await this.fetchImpl(joinUrl(this.baseUrl, params.path), {\n\t\t\tmethod: params.method ?? \"GET\",\n\t\t\theaders: this.buildHeaders(params.headers),\n\t\t\tbody: params.body,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow await scradaApiErrorFromResponse(response);\n\t\t}\n\n\t\tconst expect = params.expect ?? \"json\";\n\t\tif (expect === \"arrayBuffer\") {\n\t\t\treturn (await response.arrayBuffer()) as T;\n\t\t}\n\t\tif (expect === \"text\") {\n\t\t\treturn (await response.text()) as T;\n\t\t}\n\n\t\tconst textBody = await response.text();\n\t\tif (!textBody) return null as T;\n\t\tconst parsed = tryParseJson(textBody);\n\t\tif (parsed !== null) return parsed as T;\n\t\treturn textBody as T;\n\t}\n\n\t// ── Peppol registration ─────────────────────────────────────────────\n\n\tasync registerCompany(\n\t\tcompanyId: string,\n\t\tpayload: Record<string, unknown>,\n\t): Promise<string> {\n\t\tconst response = await this.request<unknown>({\n\t\t\tpath: `/company/${companyId}/peppol/register`,\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\t\treturn normalizeDocumentId(response);\n\t}\n\n\tasync deregisterCompany(\n\t\tcompanyId: string,\n\t\tparticipantIdentifierScheme: string,\n\t\tparticipantIdentifierValue: string,\n\t): Promise<void> {\n\t\tawait this.request<null>({\n\t\t\tpath: `/company/${companyId}/peppol/deregister/${encodeURIComponent(\n\t\t\t\tparticipantIdentifierScheme,\n\t\t\t)}/${encodeURIComponent(participantIdentifierValue)}`,\n\t\t\tmethod: \"DELETE\",\n\t\t});\n\t}\n\n\t// ── Inbound documents ───────────────────────────────────────────────\n\n\tasync getUnconfirmedInboundDocuments(\n\t\tcompanyId: string,\n\t): Promise<ScradaInboundUnconfirmedResponse> {\n\t\treturn this.request<ScradaInboundUnconfirmedResponse>({\n\t\t\tpath: `/company/${companyId}/peppol/inbound/document/unconfirmed`,\n\t\t});\n\t}\n\n\tasync getInboundDocument(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<ScradaInboundDocumentResponse> {\n\t\tconst response = await this.fetchImpl(\n\t\t\tjoinUrl(\n\t\t\t\tthis.baseUrl,\n\t\t\t\t`/company/${companyId}/peppol/inbound/document/${documentId}`,\n\t\t\t),\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: this.buildHeaders(),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) throw await scradaApiErrorFromResponse(response);\n\n\t\treturn {\n\t\t\tbody: await response.text(),\n\t\t\tcontentType: response.headers.get(\"content-type\"),\n\t\t\theaders: normalizeHeaders(response.headers),\n\t\t};\n\t}\n\n\tasync getInboundDocumentPdf(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<ScradaInboundPdfResponse> {\n\t\tconst response = await this.fetchImpl(\n\t\t\tjoinUrl(\n\t\t\t\tthis.baseUrl,\n\t\t\t\t`/company/${companyId}/peppol/inbound/document/${documentId}/pdf`,\n\t\t\t),\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: this.buildHeaders(),\n\t\t\t},\n\t\t);\n\t\tif (!response.ok) throw await scradaApiErrorFromResponse(response);\n\n\t\treturn {\n\t\t\tarrayBuffer: await response.arrayBuffer(),\n\t\t\tcontentType: response.headers.get(\"content-type\") ?? \"application/pdf\",\n\t\t\theaders: normalizeHeaders(response.headers),\n\t\t};\n\t}\n\n\tasync confirmInboundDocument(companyId: string, documentId: string): Promise<void> {\n\t\tawait this.request<null>({\n\t\t\tpath: `/company/${companyId}/peppol/inbound/document/${documentId}/confirm`,\n\t\t\tmethod: \"PUT\",\n\t\t});\n\t}\n\n\t// ── Outbound documents ──────────────────────────────────────────────\n\n\t/**\n\t * @param options.idempotencyKey Sent as `Idempotency-Key`. A transient\n\t * network-error retry with the same key is collapsed by Scrada, so the\n\t * recipient's Peppol endpoint won't receive the same invoice twice. The\n\t * caller should pass a deterministic key (typically the invoice ID).\n\t */\n\tasync sendOutboundSalesInvoice(\n\t\tcompanyId: string,\n\t\tpayload: PeppolOnlyInvoice,\n\t\toptions?: { idempotencyKey?: string },\n\t): Promise<string> {\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t};\n\t\tif (options?.idempotencyKey) {\n\t\t\theaders[\"Idempotency-Key\"] = options.idempotencyKey;\n\t\t}\n\t\tconst response = await this.request<unknown>({\n\t\t\tpath: `/company/${companyId}/peppol/outbound/salesInvoice`,\n\t\t\tmethod: \"POST\",\n\t\t\theaders,\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\t\treturn normalizeDocumentId(response);\n\t}\n\n\tasync getOutboundDocumentInfo(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<ScradaOutboundDocumentInfo> {\n\t\treturn this.request<ScradaOutboundDocumentInfo>({\n\t\t\tpath: `/company/${companyId}/peppol/outbound/document/${documentId}/info`,\n\t\t});\n\t}\n\n\t// ── Peppol participant lookup ───────────────────────────────────────\n\n\tasync lookupPeppolParticipant(\n\t\tcompanyId: string,\n\t\tscheme: string,\n\t\tid: string,\n\t): Promise<ScradaPeppolLookupResponse> {\n\t\treturn this.request<ScradaPeppolLookupResponse>({\n\t\t\tpath: `/company/${companyId}/peppol/lookup/${encodeURIComponent(\n\t\t\t\tscheme,\n\t\t\t)}/${encodeURIComponent(id)}`,\n\t\t});\n\t}\n\n\tasync lookupPeppolParty(\n\t\tcompanyId: string,\n\t\tpayload: Record<string, unknown>,\n\t): Promise<ScradaPeppolLookupResponse> {\n\t\treturn this.request<ScradaPeppolLookupResponse>({\n\t\t\tpath: `/company/${companyId}/peppol/lookup`,\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\t}\n}\n\n/**\n * Create a Scrada API client from the canonical environment variables.\n * Throws when SCRADA_API_KEY or SCRADA_PASSWORD is missing.\n */\nexport const createScradaApiClientFromEnv = (\n\tenv: NodeJS.ProcessEnv = process.env,\n): ScradaApiClient => {\n\tconst apiKey = env.SCRADA_API_KEY;\n\tconst password = env.SCRADA_PASSWORD;\n\tif (!apiKey || !password) {\n\t\tthrow new Error(\n\t\t\t\"Scrada credentials are not configured. Set SCRADA_API_KEY and SCRADA_PASSWORD.\",\n\t\t);\n\t}\n\n\treturn new ScradaApiClient({\n\t\tapiKey,\n\t\tpassword,\n\t\tbaseUrl: env.SCRADA_API_BASE_URL,\n\t});\n};\n"],"mappings":"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","names":["tryParseJson"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export const DEFAULT_SCRADA_API_BASE_URL = \"https://api.scrada.be/v1\";\n\n/** Language sent in the Scrada `Language` request header (server may localize errors). */\nexport const SCRADA_LANGUAGE_HEADER = \"EN\";\n\n// ── Peppol identifier scheme defaults ────────────────────────────────\n\nexport const DEFAULT_PEPPOL_SENDER_IDENTIFIER_SCHEME = \"iso6523-actorid-upis\";\n/** ISO/IEC 6523 0208: Belgian enterprise number (KBO/BCE). */\nexport const DEFAULT_PEPPOL_COMPANY_IDENTIFIER_SCHEME = \"0208\";\n/** ISO/IEC 6523 9925: Belgian VAT number scheme. */\nexport const DEFAULT_PEPPOL_VAT_IDENTIFIER_SCHEME = \"9925\";\nexport const DEFAULT_PEPPOL_DOCUMENT_TYPE_SCHEME = \"busdox-docid-qns\";\nexport const DEFAULT_PEPPOL_DOCUMENT_TYPE_VALUE =\n\t\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1\";\nexport const DEFAULT_PEPPOL_PROCESS_SCHEME = \"cenbii-procid-ubl\";\nexport const DEFAULT_PEPPOL_PROCESS_VALUE =\n\t\"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\";\n\n// ── Scrada attachment file type codes ────────────────────────────────\n\n/** Scrada `attachment.fileType` value for the primary invoice/credit note PDF. */\nexport const SCRADA_ATTACHMENT_FILE_TYPE_INVOICE = 1;\n","export class ScradaApiError extends Error {\n\tstatus: number;\n\tdetails: unknown;\n\n\tconstructor(message: string, status: number, details: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"ScradaApiError\";\n\t\tthis.status = status;\n\t\tthis.details = details;\n\t}\n}\n\nconst tryParseJson = (value: string): unknown => {\n\ttry {\n\t\treturn JSON.parse(value) as unknown;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst normalizeDetailMessage = (value: string) => value.trim().replace(/\\s+/g, \" \");\n\nconst collectDetailMessages = (value: unknown, collector: Set<string>, depth = 0) => {\n\tif (depth > 4 || value === null || value === undefined) return;\n\n\tif (typeof value === \"string\") {\n\t\tconst normalized = normalizeDetailMessage(value);\n\t\tif (normalized.length > 0) collector.add(normalized);\n\t\treturn;\n\t}\n\n\tif (Array.isArray(value)) {\n\t\tfor (const entry of value) {\n\t\t\tcollectDetailMessages(entry, collector, depth + 1);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (typeof value !== \"object\") return;\n\tconst record = value as Record<string, unknown>;\n\n\tconst preferredFields = [\n\t\t\"defaultFormat\",\n\t\t\"message\",\n\t\t\"error\",\n\t\t\"title\",\n\t\t\"detail\",\n\t\t\"description\",\n\t\t\"reason\",\n\t];\n\n\tfor (const field of preferredFields) {\n\t\tconst fieldValue = record[field];\n\t\tif (typeof fieldValue === \"string\") {\n\t\t\tconst normalized = normalizeDetailMessage(fieldValue);\n\t\t\tif (normalized.length > 0) collector.add(normalized);\n\t\t}\n\t}\n\n\tconst nestedFields = [\"details\", \"errors\", \"validationErrors\", \"modelState\"];\n\tfor (const field of nestedFields) {\n\t\tif (field in record) {\n\t\t\tcollectDetailMessages(record[field], collector, depth + 1);\n\t\t}\n\t}\n\n\tfor (const [key, fieldValue] of Object.entries(record)) {\n\t\tif (preferredFields.includes(key) || nestedFields.includes(key)) continue;\n\t\tif (typeof fieldValue === \"string\") {\n\t\t\tconst normalized = normalizeDetailMessage(fieldValue);\n\t\t\tif (normalized.length > 0 && /error|invalid|missing|required/i.test(key)) {\n\t\t\t\tcollector.add(normalized);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tArray.isArray(fieldValue) ||\n\t\t\t(fieldValue && typeof fieldValue === \"object\")\n\t\t) {\n\t\t\tcollectDetailMessages(fieldValue, collector, depth + 1);\n\t\t}\n\t}\n};\n\n/**\n * Walks a Scrada error response body and pulls out the human-readable\n * message strings. Returns `null` when nothing usable is found.\n *\n * Scrada returns errors in several shapes (string, `{message}`,\n * `{errors: [{detail}]}`, `{modelState: {...}}`, etc.); this collapses\n * them into a single ` | `-separated summary.\n */\nexport const summarizeScradaErrorDetails = (details: unknown): string | null => {\n\tconst collector = new Set<string>();\n\tcollectDetailMessages(details, collector);\n\tif (collector.size === 0) return null;\n\treturn Array.from(collector).slice(0, 6).join(\" | \");\n};\n\nconst coerceErrorMessage = (details: unknown, fallback: string) =>\n\tsummarizeScradaErrorDetails(details) ?? fallback;\n\n/**\n * Converts a non-2xx Scrada response into a ScradaApiError, parsing the body\n * as JSON when possible and extracting message strings via\n * {@link summarizeScradaErrorDetails}.\n */\nexport const scradaApiErrorFromResponse = async (\n\tresponse: Response,\n): Promise<ScradaApiError> => {\n\tconst textBody = await response.text();\n\tconst parsed = tryParseJson(textBody) ?? textBody;\n\treturn new ScradaApiError(\n\t\tcoerceErrorMessage(\n\t\t\tparsed,\n\t\t\t`Scrada request failed with status ${response.status}`,\n\t\t),\n\t\tresponse.status,\n\t\tparsed,\n\t);\n};\n","import { DEFAULT_SCRADA_API_BASE_URL, SCRADA_LANGUAGE_HEADER } from \"./constants\";\nimport { scradaApiErrorFromResponse } from \"./errors\";\nimport type {\n\tPeppolOnlyInvoice,\n\tPeppolOutboundDocumentRouting,\n\tScradaInboundDocumentResponse,\n\tScradaInboundUnconfirmedResponse,\n\tScradaOutboundDocumentInfo,\n\tScradaPeppolLookupResponse,\n} from \"./types\";\n\n/** Map {@link PeppolOutboundDocumentRouting} to the `x-scrada-peppol-*` headers. */\nconst routingHeaders = (\n\trouting: PeppolOutboundDocumentRouting,\n): Record<string, string> => {\n\tconst headers: Record<string, string> = {\n\t\t\"x-scrada-peppol-sender-scheme\": routing.senderScheme,\n\t\t\"x-scrada-peppol-sender-id\": routing.senderId,\n\t\t\"x-scrada-peppol-receiver-scheme\": routing.receiverScheme,\n\t\t\"x-scrada-peppol-receiver-id\": routing.receiverId,\n\t\t\"x-scrada-peppol-c1-country-code\": routing.c1CountryCode,\n\t\t\"x-scrada-peppol-document-type-scheme\": routing.documentTypeScheme,\n\t\t\"x-scrada-peppol-document-type-value\": routing.documentTypeValue,\n\t\t\"x-scrada-peppol-process-scheme\": routing.processScheme,\n\t\t\"x-scrada-peppol-process-value\": routing.processValue,\n\t};\n\tif (routing.externalReference) {\n\t\theaders[\"x-scrada-external-reference\"] = routing.externalReference;\n\t}\n\treturn headers;\n};\n\ntype ScradaRequestMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\nexport interface ScradaApiClientOptions {\n\tapiKey: string;\n\tpassword: string;\n\tbaseUrl?: string;\n\t/** Override the global `fetch` (e.g. for testing). */\n\tfetch?: typeof fetch;\n}\n\nexport interface ScradaInboundPdfResponse {\n\tarrayBuffer: ArrayBuffer;\n\tcontentType: string;\n\theaders: Record<string, string>;\n}\n\nconst joinUrl = (baseUrl: string, path: string) => {\n\tconst normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n\tconst normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n\treturn `${normalizedBase}${normalizedPath}`;\n};\n\nconst normalizeHeaders = (headers: Headers) => {\n\tconst result: Record<string, string> = {};\n\theaders.forEach((value, key) => {\n\t\tresult[key.toLowerCase()] = value;\n\t});\n\treturn result;\n};\n\nconst normalizeDocumentId = (value: unknown): string => {\n\tif (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n\tif (value && typeof value === \"object\") {\n\t\tconst record = value as Record<string, unknown>;\n\t\tif (typeof record.id === \"string\" && record.id.trim().length > 0) {\n\t\t\treturn record.id.trim();\n\t\t}\n\t\tif (\n\t\t\ttypeof record.documentID === \"string\" &&\n\t\t\trecord.documentID.trim().length > 0\n\t\t) {\n\t\t\treturn record.documentID.trim();\n\t\t}\n\t}\n\tthrow new Error(\"Unable to resolve document ID from Scrada response\");\n};\n\nconst tryParseJson = (value: string): unknown => {\n\ttry {\n\t\treturn JSON.parse(value) as unknown;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/**\n * HTTP client for the Scrada Peppol API.\n *\n * https://api.scrada.be/v1\n *\n * Authenticates with API key + password sent as `X-API-KEY` / `X-PASSWORD`\n * headers. All non-2xx responses surface as `ScradaApiError`.\n */\nexport class ScradaApiClient {\n\tprivate readonly apiKey: string;\n\tprivate readonly password: string;\n\tprivate readonly baseUrl: string;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(options: ScradaApiClientOptions) {\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.password = options.password;\n\t\tthis.baseUrl = options.baseUrl ?? DEFAULT_SCRADA_API_BASE_URL;\n\t\tthis.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n\t}\n\n\tprivate buildHeaders(extra?: HeadersInit): Headers {\n\t\tconst headers = new Headers({\n\t\t\t\"X-API-KEY\": this.apiKey,\n\t\t\t\"X-PASSWORD\": this.password,\n\t\t\tLanguage: SCRADA_LANGUAGE_HEADER,\n\t\t});\n\t\tif (extra) {\n\t\t\tconst extraHeaders = new Headers(extra);\n\t\t\textraHeaders.forEach((value, key) => {\n\t\t\t\theaders.set(key, value);\n\t\t\t});\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate async request<T>(params: {\n\t\tpath: string;\n\t\tmethod?: ScradaRequestMethod;\n\t\tbody?: BodyInit;\n\t\theaders?: HeadersInit;\n\t\texpect?: \"json\" | \"text\" | \"arrayBuffer\";\n\t}): Promise<T> {\n\t\tconst response = await this.fetchImpl(joinUrl(this.baseUrl, params.path), {\n\t\t\tmethod: params.method ?? \"GET\",\n\t\t\theaders: this.buildHeaders(params.headers),\n\t\t\tbody: params.body,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow await scradaApiErrorFromResponse(response);\n\t\t}\n\n\t\tconst expect = params.expect ?? \"json\";\n\t\tif (expect === \"arrayBuffer\") {\n\t\t\treturn (await response.arrayBuffer()) as T;\n\t\t}\n\t\tif (expect === \"text\") {\n\t\t\treturn (await response.text()) as T;\n\t\t}\n\n\t\tconst textBody = await response.text();\n\t\tif (!textBody) return null as T;\n\t\tconst parsed = tryParseJson(textBody);\n\t\tif (parsed !== null) return parsed as T;\n\t\treturn textBody as T;\n\t}\n\n\t// ── Peppol registration ─────────────────────────────────────────────\n\n\tasync registerCompany(\n\t\tcompanyId: string,\n\t\tpayload: Record<string, unknown>,\n\t): Promise<string> {\n\t\tconst response = await this.request<unknown>({\n\t\t\tpath: `/company/${companyId}/peppol/register`,\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\t\treturn normalizeDocumentId(response);\n\t}\n\n\tasync deregisterCompany(\n\t\tcompanyId: string,\n\t\tparticipantIdentifierScheme: string,\n\t\tparticipantIdentifierValue: string,\n\t): Promise<void> {\n\t\tawait this.request<null>({\n\t\t\tpath: `/company/${companyId}/peppol/deregister/${encodeURIComponent(\n\t\t\t\tparticipantIdentifierScheme,\n\t\t\t)}/${encodeURIComponent(participantIdentifierValue)}`,\n\t\t\tmethod: \"DELETE\",\n\t\t});\n\t}\n\n\t// ── Inbound documents ───────────────────────────────────────────────\n\n\tasync getUnconfirmedInboundDocuments(\n\t\tcompanyId: string,\n\t): Promise<ScradaInboundUnconfirmedResponse> {\n\t\treturn this.request<ScradaInboundUnconfirmedResponse>({\n\t\t\tpath: `/company/${companyId}/peppol/inbound/document/unconfirmed`,\n\t\t});\n\t}\n\n\tasync getInboundDocument(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<ScradaInboundDocumentResponse> {\n\t\tconst response = await this.fetchImpl(\n\t\t\tjoinUrl(\n\t\t\t\tthis.baseUrl,\n\t\t\t\t`/company/${companyId}/peppol/inbound/document/${documentId}`,\n\t\t\t),\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: this.buildHeaders(),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) throw await scradaApiErrorFromResponse(response);\n\n\t\treturn {\n\t\t\tbody: await response.text(),\n\t\t\tcontentType: response.headers.get(\"content-type\"),\n\t\t\theaders: normalizeHeaders(response.headers),\n\t\t};\n\t}\n\n\tasync getInboundDocumentPdf(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<ScradaInboundPdfResponse> {\n\t\tconst response = await this.fetchImpl(\n\t\t\tjoinUrl(\n\t\t\t\tthis.baseUrl,\n\t\t\t\t`/company/${companyId}/peppol/inbound/document/${documentId}/pdf`,\n\t\t\t),\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: this.buildHeaders(),\n\t\t\t},\n\t\t);\n\t\tif (!response.ok) throw await scradaApiErrorFromResponse(response);\n\n\t\treturn {\n\t\t\tarrayBuffer: await response.arrayBuffer(),\n\t\t\tcontentType: response.headers.get(\"content-type\") ?? \"application/pdf\",\n\t\t\theaders: normalizeHeaders(response.headers),\n\t\t};\n\t}\n\n\tasync confirmInboundDocument(companyId: string, documentId: string): Promise<void> {\n\t\tawait this.request<null>({\n\t\t\tpath: `/company/${companyId}/peppol/inbound/document/${documentId}/confirm`,\n\t\t\tmethod: \"PUT\",\n\t\t});\n\t}\n\n\t// ── Outbound documents ──────────────────────────────────────────────\n\n\tprivate async postOutbound(params: {\n\t\tcompanyId: string;\n\t\tsegment: \"salesInvoice\" | \"selfBillingInvoice\" | \"document\";\n\t\tbody: BodyInit;\n\t\tcontentType: \"application/json\" | \"application/xml\";\n\t\tidempotencyKey?: string;\n\t\textraHeaders?: Record<string, string>;\n\t}): Promise<string> {\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Content-Type\": params.contentType,\n\t\t\t...params.extraHeaders,\n\t\t};\n\t\tif (params.idempotencyKey) {\n\t\t\theaders[\"Idempotency-Key\"] = params.idempotencyKey;\n\t\t}\n\t\tconst response = await this.request<unknown>({\n\t\t\tpath: `/company/${params.companyId}/peppol/outbound/${params.segment}`,\n\t\t\tmethod: \"POST\",\n\t\t\theaders,\n\t\t\tbody: params.body,\n\t\t});\n\t\treturn normalizeDocumentId(response);\n\t}\n\n\t/**\n\t * @param options.idempotencyKey Sent as `Idempotency-Key`. A transient\n\t * network-error retry with the same key is collapsed by Scrada, so the\n\t * recipient's Peppol endpoint won't receive the same invoice twice. The\n\t * caller should pass a deterministic key (typically the invoice ID).\n\t */\n\tasync sendOutboundSalesInvoice(\n\t\tcompanyId: string,\n\t\tpayload: PeppolOnlyInvoice,\n\t\toptions?: { idempotencyKey?: string },\n\t): Promise<string> {\n\t\treturn this.postOutbound({\n\t\t\tcompanyId,\n\t\t\tsegment: \"salesInvoice\",\n\t\t\tbody: JSON.stringify(payload),\n\t\t\tcontentType: \"application/json\",\n\t\t\tidempotencyKey: options?.idempotencyKey,\n\t\t});\n\t}\n\n\t/**\n\t * Send a self-billing invoice or credit note (buyer issues the document\n\t * on behalf of the supplier). Same payload shape as a sales invoice.\n\t *\n\t * @param options.idempotencyKey See `sendOutboundSalesInvoice`.\n\t */\n\tasync sendOutboundSelfBillingInvoice(\n\t\tcompanyId: string,\n\t\tpayload: PeppolOnlyInvoice,\n\t\toptions?: { idempotencyKey?: string },\n\t): Promise<string> {\n\t\treturn this.postOutbound({\n\t\t\tcompanyId,\n\t\t\tsegment: \"selfBillingInvoice\",\n\t\t\tbody: JSON.stringify(payload),\n\t\t\tcontentType: \"application/json\",\n\t\t\tidempotencyKey: options?.idempotencyKey,\n\t\t});\n\t}\n\n\t/**\n\t * Deliver a pre-built UBL document directly to Peppol. Use this when you\n\t * already have a UBL XML string (BIS3 invoice, credit note, self-billing,\n\t * Invoice Response, etc.); for JSON payloads use `sendOutboundSalesInvoice`\n\t * or `sendOutboundSelfBillingInvoice` instead.\n\t *\n\t * The endpoint does not parse the UBL for routing, so `options.routing`\n\t * (sender, receiver, document type and process) is required and sent as\n\t * `x-scrada-peppol-*` headers — without it Scrada rejects the request with\n\t * \"Http header 'x-scrada-peppol-sender-scheme' is missing\".\n\t *\n\t * @param options.idempotencyKey See `sendOutboundSalesInvoice`.\n\t */\n\tasync sendOutboundDocument(\n\t\tcompanyId: string,\n\t\tubl: string,\n\t\toptions: {\n\t\t\trouting: PeppolOutboundDocumentRouting;\n\t\t\tidempotencyKey?: string;\n\t\t},\n\t): Promise<string> {\n\t\treturn this.postOutbound({\n\t\t\tcompanyId,\n\t\t\tsegment: \"document\",\n\t\t\tbody: ubl,\n\t\t\tcontentType: \"application/xml\",\n\t\t\tidempotencyKey: options.idempotencyKey,\n\t\t\textraHeaders: routingHeaders(options.routing),\n\t\t});\n\t}\n\n\tasync getOutboundDocumentInfo(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<ScradaOutboundDocumentInfo> {\n\t\treturn this.request<ScradaOutboundDocumentInfo>({\n\t\t\tpath: `/company/${companyId}/peppol/outbound/document/${documentId}/info`,\n\t\t});\n\t}\n\n\t/**\n\t * Fetch the rendered UBL XML for an outbound document — useful when the\n\t * document was sent as JSON and Scrada generated the UBL.\n\t */\n\tasync getOutboundDocumentUbl(\n\t\tcompanyId: string,\n\t\tdocumentId: string,\n\t): Promise<string> {\n\t\treturn this.request<string>({\n\t\t\tpath: `/company/${companyId}/peppol/outbound/document/${documentId}/ubl`,\n\t\t\texpect: \"text\",\n\t\t});\n\t}\n\n\t// ── Peppol participant lookup ───────────────────────────────────────\n\n\tasync lookupPeppolParticipant(\n\t\tcompanyId: string,\n\t\tscheme: string,\n\t\tid: string,\n\t): Promise<ScradaPeppolLookupResponse> {\n\t\treturn this.request<ScradaPeppolLookupResponse>({\n\t\t\tpath: `/company/${companyId}/peppol/lookup/${encodeURIComponent(\n\t\t\t\tscheme,\n\t\t\t)}/${encodeURIComponent(id)}`,\n\t\t});\n\t}\n\n\tasync lookupPeppolParty(\n\t\tcompanyId: string,\n\t\tpayload: Record<string, unknown>,\n\t): Promise<ScradaPeppolLookupResponse> {\n\t\treturn this.request<ScradaPeppolLookupResponse>({\n\t\t\tpath: `/company/${companyId}/peppol/lookup`,\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify(payload),\n\t\t});\n\t}\n}\n\n/**\n * Create a Scrada API client from the canonical environment variables.\n * Throws when SCRADA_API_KEY or SCRADA_PASSWORD is missing.\n */\nexport const createScradaApiClientFromEnv = (\n\tenv: NodeJS.ProcessEnv = process.env,\n): ScradaApiClient => {\n\tconst apiKey = env.SCRADA_API_KEY;\n\tconst password = env.SCRADA_PASSWORD;\n\tif (!apiKey || !password) {\n\t\tthrow new Error(\n\t\t\t\"Scrada credentials are not configured. Set SCRADA_API_KEY and SCRADA_PASSWORD.\",\n\t\t);\n\t}\n\n\treturn new ScradaApiClient({\n\t\tapiKey,\n\t\tpassword,\n\t\tbaseUrl: env.SCRADA_API_BASE_URL,\n\t});\n};\n"],"mappings":"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","names":["tryParseJson"]}
|