/** Node.js 20+, no dependencies. Run only on the store server. */ export class DidbanClient { #base; #key; constructor(baseUrl, apiKey) { const url = new URL(baseUrl); if (url.username || url.password || url.search || url.hash || url.pathname !== '/' || !(url.protocol === 'https:' || url.protocol === 'http:' && ['127.0.0.1', 'localhost'].includes(url.hostname))) throw new Error('Use an HTTPS origin or localhost.'); if (!/^db_(test|live)_[A-Za-z0-9_-]{43}$/.test(apiKey)) throw new Error('Invalid API key.'); this.#base = url.origin; this.#key = apiKey; } createInvoice(requestId, amountRial, ttlMinutes = undefined, presentation = "hosted") { return this.#request('/api/v1/invoices', {request_id: requestId, amount_rial: amountRial, ttl_minutes: ttlMinutes, presentation}); } getInvoice(id) { if (!/^[0-9a-f-]{36}$/.test(id)) throw new Error('Invalid invoice ID.'); return this.#request('/api/v1/invoices/' + id); } getPaymentData(id) { if (!/^[0-9a-f-]{36}$/.test(id)) throw new Error('Invalid invoice ID.'); return this.#request('/api/v1/invoices/' + id + '/payment-data'); } getWallet() { return this.#request('/api/v1/wallet'); } async #request(path, body) { let response; try { response = await fetch(this.#base + path, { method: body === undefined ? 'GET' : 'POST', redirect: 'error', signal: AbortSignal.timeout(20000), headers: {Authorization: 'Bearer ' + this.#key, 'Content-Type': 'application/json', Accept: 'application/json'}, body: body === undefined ? undefined : JSON.stringify(body), }); } catch { throw new Error('Connection failed; retry only with the same request_id.'); } if (!response.ok) throw new Error('Didban HTTP ' + response.status); return response.json(); } }