@financica/scrada-client 0.3.0 → 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 +39 -2
- package/dist/index.js +26 -2
- 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;
|
|
@@ -252,9 +283,15 @@ declare class ScradaApiClient {
|
|
|
252
283
|
* Invoice Response, etc.); for JSON payloads use `sendOutboundSalesInvoice`
|
|
253
284
|
* or `sendOutboundSelfBillingInvoice` instead.
|
|
254
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
|
+
*
|
|
255
291
|
* @param options.idempotencyKey See `sendOutboundSalesInvoice`.
|
|
256
292
|
*/
|
|
257
|
-
sendOutboundDocument(companyId: string, ubl: string, options
|
|
293
|
+
sendOutboundDocument(companyId: string, ubl: string, options: {
|
|
294
|
+
routing: PeppolOutboundDocumentRouting;
|
|
258
295
|
idempotencyKey?: string;
|
|
259
296
|
}): Promise<string>;
|
|
260
297
|
getOutboundDocumentInfo(companyId: string, documentId: string): Promise<ScradaOutboundDocumentInfo>;
|
|
@@ -308,4 +345,4 @@ declare const summarizeScradaErrorDetails: (details: unknown) => string | null;
|
|
|
308
345
|
*/
|
|
309
346
|
declare const scradaApiErrorFromResponse: (response: Response) => Promise<ScradaApiError>;
|
|
310
347
|
|
|
311
|
-
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}`;
|
|
@@ -249,7 +266,8 @@ var ScradaApiClient = class {
|
|
|
249
266
|
// ── Outbound documents ──────────────────────────────────────────────
|
|
250
267
|
async postOutbound(params) {
|
|
251
268
|
const headers = {
|
|
252
|
-
"Content-Type": params.contentType
|
|
269
|
+
"Content-Type": params.contentType,
|
|
270
|
+
...params.extraHeaders
|
|
253
271
|
};
|
|
254
272
|
if (params.idempotencyKey) {
|
|
255
273
|
headers["Idempotency-Key"] = params.idempotencyKey;
|
|
@@ -298,6 +316,11 @@ var ScradaApiClient = class {
|
|
|
298
316
|
* Invoice Response, etc.); for JSON payloads use `sendOutboundSalesInvoice`
|
|
299
317
|
* or `sendOutboundSelfBillingInvoice` instead.
|
|
300
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
|
+
*
|
|
301
324
|
* @param options.idempotencyKey See `sendOutboundSalesInvoice`.
|
|
302
325
|
*/
|
|
303
326
|
async sendOutboundDocument(companyId, ubl, options) {
|
|
@@ -306,7 +329,8 @@ var ScradaApiClient = class {
|
|
|
306
329
|
segment: "document",
|
|
307
330
|
body: ubl,
|
|
308
331
|
contentType: "application/xml",
|
|
309
|
-
idempotencyKey: options
|
|
332
|
+
idempotencyKey: options.idempotencyKey,
|
|
333
|
+
extraHeaders: routingHeaders(options.routing)
|
|
310
334
|
});
|
|
311
335
|
}
|
|
312
336
|
async getOutboundDocumentInfo(companyId, documentId) {
|
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\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}): Promise<string> {\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Content-Type\": params.contentType,\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 * @param options.idempotencyKey See `sendOutboundSalesInvoice`.\n\t */\n\tasync sendOutboundDocument(\n\t\tcompanyId: string,\n\t\tubl: string,\n\t\toptions?: { idempotencyKey?: string },\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});\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"]}
|
|
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"]}
|