@jackiemacklein/nettz-utils
Version:
Serviços de imagem, e-mail, códigos de barras, utilitários numéricos e componentes React para apps Node.js com TypeScript
131 lines (130 loc) • 6.28 kB
JavaScript
;
/**
* @author Jackiê Macklein
* @company Onside tecnologia/Nettz
* @copyright Todos direitos reservados.
* @description Cliente HTTP para API SuperTEF (listar POS, solicitar e consultar pagamentos).
* Documentação: https://supertef.apidog.io/
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSuperTefClient = createSuperTefClient;
const errors_1 = require("./errors");
const types_1 = require("./types");
function sleep(ms, signal) {
return new Promise((resolve, reject) => {
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
reject(new DOMException("Aborted", "AbortError"));
return;
}
const t = setTimeout(() => {
signal === null || signal === void 0 ? void 0 : signal.removeEventListener("abort", onAbort);
resolve();
}, ms);
const onAbort = () => {
clearTimeout(t);
signal === null || signal === void 0 ? void 0 : signal.removeEventListener("abort", onAbort);
reject(new DOMException("Aborted", "AbortError"));
};
signal === null || signal === void 0 ? void 0 : signal.addEventListener("abort", onAbort);
});
}
async function readResponseBody(res) {
try {
return await res.text();
}
catch {
return "";
}
}
function createSuperTefClient(config) {
var _a, _b, _c, _d;
const baseUrl = ((_a = config.baseUrl) !== null && _a !== void 0 ? _a : types_1.SUPERTEF_DEFAULT_BASE_URL).replace(/\/$/, "");
const timeoutMs = (_b = config.timeoutMs) !== null && _b !== void 0 ? _b : 30000;
const fetchFn = (_c = config.fetchImpl) !== null && _c !== void 0 ? _c : fetch;
const paymentLookupUsesQueryParam = (_d = config.paymentLookupUsesQueryParam) !== null && _d !== void 0 ? _d : true;
async function request(path, init) {
var _a, _b;
const url = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
const controller = new AbortController();
const t = setTimeout(() => controller.abort(), (_a = init === null || init === void 0 ? void 0 : init.timeoutMs) !== null && _a !== void 0 ? _a : timeoutMs);
try {
const res = await fetchFn(url, {
...init,
signal: (_b = init === null || init === void 0 ? void 0 : init.signal) !== null && _b !== void 0 ? _b : controller.signal,
headers: {
Accept: "application/json",
Authorization: `Bearer ${config.token}`,
...((init === null || init === void 0 ? void 0 : init.body) ? { "Content-Type": "application/json" } : {}),
...init === null || init === void 0 ? void 0 : init.headers,
},
});
const text = await readResponseBody(res);
if (!res.ok) {
throw new errors_1.SuperTefApiError(`SuperTEF HTTP ${res.status} ${res.statusText}`, res.status, text);
}
if (!text || text.trim() === "") {
return undefined;
}
try {
return JSON.parse(text);
}
catch {
throw new errors_1.SuperTefApiError("SuperTEF resposta não é JSON válido", res.status, text);
}
}
finally {
clearTimeout(t);
}
}
return {
baseUrl,
async listPos(params) {
const search = new URLSearchParams();
if ((params === null || params === void 0 ? void 0 : params.cliente_chave) != null && params.cliente_chave !== "") {
search.set("cliente_chave", params.cliente_chave);
}
if ((params === null || params === void 0 ? void 0 : params.page) != null && `${params.page}` !== "") {
search.set("page", String(params.page));
}
const q = search.toString();
return request(q ? `/pos?${q}` : "/pos");
},
async requestPayment(body) {
return request("/pagamentos", {
method: "POST",
body: JSON.stringify(body),
});
},
async getPaymentByUniqueId(paymentUniqueId) {
const path = paymentLookupUsesQueryParam
? `/pagamentos/by-uniqueid?${new URLSearchParams({
payment_uniqueid: String(paymentUniqueId),
}).toString()}`
: `/pagamentos/by-uniqueid/${encodeURIComponent(String(paymentUniqueId))}`;
return request(path);
},
async pollPaymentUntilFinal(paymentUniqueId, options) {
var _a, _b, _c;
const intervalMs = (_a = options === null || options === void 0 ? void 0 : options.intervalMs) !== null && _a !== void 0 ? _a : 4000;
const maxAttempts = (_b = options === null || options === void 0 ? void 0 : options.maxAttempts) !== null && _b !== void 0 ? _b : 120;
const requirePaid = (_c = options === null || options === void 0 ? void 0 : options.requirePaid) !== null && _c !== void 0 ? _c : true;
const signal = options === null || options === void 0 ? void 0 : options.signal;
/** 4 Pago, 5 Cancelado/Erro — documentação SuperTEF */
const isTerminal = (d) => d.payment_status === 4 || d.payment_status === 5;
let last = await this.getPaymentByUniqueId(paymentUniqueId);
let attempts = 0;
while (!isTerminal(last) && attempts < maxAttempts) {
await sleep(intervalMs, signal);
last = await this.getPaymentByUniqueId(paymentUniqueId);
attempts += 1;
}
if (!isTerminal(last)) {
throw new errors_1.SuperTefApiError(`SuperTEF: pagamento ${paymentUniqueId} não atingiu status final após ${attempts + 1} consulta(s)`, 408, JSON.stringify(last));
}
if (requirePaid && last.payment_status !== 4) {
throw new errors_1.SuperTefApiError(`SuperTEF: pagamento ${paymentUniqueId} não foi concluído com sucesso (status ${last.payment_status})`, 422, JSON.stringify(last));
}
return last;
},
};
}