@tucupy-tecnologia/cielo-ecommerce-sdk-unofficial
Version:
SDK Não Oficial para interagir com a API Cielo E-commerce usando Bun/Node.js
372 lines (361 loc) • 13.7 kB
JavaScript
// src/core/config.ts
var Environment;
((Environment2) => {
Environment2["SANDBOX_TRANSACTION"] = "https://apisandbox.cieloecommerce.cielo.com.br";
Environment2["SANDBOX_QUERY"] = "https://apiquerysandbox.cieloecommerce.cielo.com.br";
Environment2["PRODUCTION_TRANSACTION"] = "https://api.cieloecommerce.cielo.com.br";
Environment2["PRODUCTION_QUERY"] = "https://apiquery.cieloecommerce.cielo.com.br";
})(Environment ||= {});
// src/core/errors.ts
class CieloError extends Error {
constructor(message) {
super(message);
this.name = "CieloError";
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
}
class CieloApiError extends CieloError {
statusCode;
statusText;
errorData;
constructor(statusCode, statusText, errorData, message) {
const defaultMessage = `Cielo API Error: ${statusCode} ${statusText}`;
super(message || defaultMessage);
this.name = "CieloApiError";
this.statusCode = statusCode;
this.statusText = statusText;
this.errorData = errorData;
}
}
class CieloNetworkError extends CieloError {
cause;
constructor(message, cause) {
super(`Cielo Network Error: ${message}`);
this.name = "CieloNetworkError";
this.cause = cause;
}
}
// src/core/httpClient.ts
class HttpClient {
credentials;
baseUrl;
constructor(baseUrl, credentials) {
if (!credentials.merchantId || !credentials.merchantKey) {
throw new Error("MerchantId and MerchantKey are required.");
}
if (!baseUrl) {
throw new Error("Base URL is required for HttpClient.");
}
this.baseUrl = baseUrl;
this.credentials = credentials;
}
getHeaders(hasBody = true) {
const headers = {
MerchantId: this.credentials.merchantId,
MerchantKey: this.credentials.merchantKey,
RequestId: this.credentials.requestIdGenerator()
};
if (hasBody) {
headers["Content-Type"] = "application/json";
}
return headers;
}
async handleResponse(response) {
if (!response.ok) {
let errorData = null;
try {
errorData = await response.json();
console.error(`[HTTP Client] API Error Response Body (${response.status}):`, errorData);
} catch (e) {
try {
errorData = await response.text();
console.error(`[HTTP Client] API Error Response Text (${response.status}):`, errorData);
} catch {
console.error(`[HTTP Client] Failed to parse error response body.`);
errorData = "Failed to parse error response body";
}
}
throw new CieloApiError(response.status, response.statusText, errorData);
}
if (response.status === 204) {
console.log(`[HTTP Client] Received ${response.status} No Content`);
return {};
}
const responseData = await response.json();
console.log(`[HTTP Client] Success Response Body (${response.status}):`, responseData);
return responseData;
}
async get(path) {
const url = `${this.baseUrl}${path}`;
const headers = this.getHeaders(false);
const requestOptions = {
method: "GET",
headers
};
console.log(`[HTTP Client] GET ${url}`);
try {
const response = await fetch(url, requestOptions);
return await this.handleResponse(response);
} catch (error) {
if (error instanceof CieloApiError)
throw error;
console.error(`[HTTP Client] Network or unexpected error on GET ${url}:`, error);
throw new CieloNetworkError(error.message ?? "Unknown network error", error);
}
}
async post(path, body) {
const url = `${this.baseUrl}${path}`;
const headers = this.getHeaders(true);
const requestOptions = {
method: "POST",
headers,
body: JSON.stringify(body)
};
console.log(`[HTTP Client] POST ${url}`);
try {
const response = await fetch(url, requestOptions);
return await this.handleResponse(response);
} catch (error) {
if (error instanceof CieloApiError)
throw error;
console.error(`[HTTP Client] Network or unexpected error on POST ${url}:`, error);
throw new CieloNetworkError(error.message ?? "Unknown network error", error);
}
}
async put(path, queryParams, body) {
const url = new URL(`${this.baseUrl}${path}`);
if (queryParams) {
Object.entries(queryParams).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.append(key, String(value));
}
});
}
const urlString = url.toString();
const hasBody = body !== undefined && body !== null;
const headers = this.getHeaders(hasBody);
const requestOptions = {
method: "PUT",
headers,
body: hasBody ? JSON.stringify(body) : undefined
};
console.log(`[HTTP Client] PUT ${urlString}`);
try {
const response = await fetch(urlString, requestOptions);
return await this.handleResponse(response);
} catch (error) {
if (error instanceof CieloApiError)
throw error;
console.error(`[HTTP Client] Network or unexpected error on PUT ${urlString}:`, error);
throw new CieloNetworkError(error.message ?? "Unknown network error", error);
}
}
}
// src/services/binQueryService.ts
class BinQueryService {
httpClient;
basePath = "/1/cardBin/";
constructor(httpClient) {
this.httpClient = httpClient;
}
async queryBin(bin) {
if (!bin) {
throw new Error("BIN is required for query.");
}
const sanitizedBin = String(bin).trim();
if (!/^\d{6,9}$/.test(sanitizedBin)) {
throw new Error("Invalid BIN format. Must be 6 to 9 digits.");
}
const path = `${this.basePath}${sanitizedBin}`;
console.log(`[BinQueryService] Querying BIN ${sanitizedBin}...`);
return this.httpClient.get(path);
}
}
// src/services/paymentService.ts
class PaymentService {
httpClient;
salesBasePath = "/1/sales/";
constructor(httpClient) {
this.httpClient = httpClient;
}
async createCreditCardPayment(payload) {
if (!payload.MerchantOrderId) {
throw new Error("MerchantOrderId is required.");
}
if (!payload.Payment || !payload.Payment.CreditCard || !payload.Payment.Amount) {
throw new Error("Payment details (including CreditCard and Amount) are required.");
}
console.log(`[PaymentService] Creating credit card payment for Order ID: ${payload.MerchantOrderId}`);
return this.httpClient.post(this.salesBasePath, payload);
}
async createTokenizedPayment(payload) {
if (!payload.MerchantOrderId) {
throw new Error("MerchantOrderId is required.");
}
if (!payload.Payment || !payload.Payment.CreditCard || !payload.Payment.CreditCard.CardToken || !payload.Payment.CreditCard.SecurityCode || !payload.Payment.CreditCard.Brand) {
throw new Error("Payment details including CreditCard with CardToken, SecurityCode, and Brand are required for tokenized payment.");
}
payload.Payment.Type = "CreditCard";
console.log(`[PaymentService] Creating tokenized payment for Order ID: ${payload.MerchantOrderId}`);
return this.httpClient.post(this.salesBasePath, payload);
}
async createPixPayment(payload) {
if (!payload.MerchantOrderId) {
throw new Error("MerchantOrderId is required.");
}
if (!payload.Customer || !payload.Customer.Name || !payload.Customer.Identity || !payload.Customer.IdentityType) {
throw new Error("Customer details (Name, Identity, IdentityType) are required for Pix.");
}
if (!payload.Payment || !payload.Payment.Amount) {
throw new Error("Payment details (including Amount) are required for Pix.");
}
payload.Payment.Type = "Pix";
payload.Payment.Amount = Number(payload.Payment.Amount);
console.log(`[PaymentService] Creating Pix payment for Order ID: ${payload.MerchantOrderId}`);
return this.httpClient.post(this.salesBasePath, payload);
}
}
// src/services/queryService.ts
class QueryService {
httpClient;
salesBasePath = "/1/sales";
constructor(httpClient) {
this.httpClient = httpClient;
}
async queryByPaymentId(paymentId) {
if (!paymentId) {
throw new Error("PaymentId is required for query.");
}
const path = `${this.salesBasePath}/${paymentId}`;
console.log(`[QueryService] Querying by PaymentId: ${paymentId}...`);
return this.httpClient.get(path);
}
async queryByMerchantOrderId(merchantOrderId) {
if (!merchantOrderId) {
throw new Error("MerchantOrderId is required for query.");
}
const encodedMerchantOrderId = encodeURIComponent(merchantOrderId);
const path = `${this.salesBasePath}?merchantOrderId=${encodedMerchantOrderId}`;
console.log(`[QueryService] Querying by MerchantOrderId: ${merchantOrderId}...`);
const response = await this.httpClient.get(path);
if (response && Array.isArray(response.Payment)) {
return { Payment: response.Payment };
} else if (response && Array.isArray(response.Payments)) {
return response;
} else {
console.warn("[QueryService] Unexpected response format for queryByMerchantOrderId:", response);
return { Payment: [] };
}
}
}
// src/services/tokenizationService.ts
class TokenizationService {
httpClient;
cardBasePath = "/1/card/";
constructor(httpClient) {
this.httpClient = httpClient;
}
async createCardToken(payload) {
if (!payload.CustomerName || !payload.CardNumber || !payload.Holder || !payload.ExpirationDate || !payload.Brand) {
throw new Error("All fields (CustomerName, CardNumber, Holder, ExpirationDate, Brand) are required for tokenization.");
}
console.log(`[TokenizationService] Requesting token for card ending with ${payload.CardNumber.slice(-4)}`);
return this.httpClient.post(this.cardBasePath, payload);
}
}
// src/services/transactionService.ts
class TransactionService {
httpClient;
salesBasePath = "/1/sales/";
constructor(httpClient) {
this.httpClient = httpClient;
}
async captureByPaymentId(paymentId, params) {
if (!paymentId)
throw new Error("PaymentId is required for capture.");
const path = `${this.salesBasePath}${paymentId}/capture`;
console.log(`[TransactionService] Capturing transaction ${paymentId} with params:`, params);
return this.httpClient.put(path, params);
}
async voidByPaymentId(paymentId, params) {
if (!paymentId)
throw new Error("PaymentId is required for void.");
const path = `${this.salesBasePath}${paymentId}/void`;
console.log(`[TransactionService] Voiding transaction ${paymentId} with params:`, params);
return this.httpClient.put(path, params);
}
async voidByMerchantOrderId(merchantOrderId, params) {
if (!merchantOrderId)
throw new Error("MerchantOrderId is required for void.");
const encodedMerchantOrderId = encodeURIComponent(merchantOrderId);
const path = `${this.salesBasePath}OrderId/${encodedMerchantOrderId}/void`;
console.log(`[TransactionService] Voiding transaction by Order ID ${merchantOrderId} with params:`, params);
return this.httpClient.put(path, params);
}
async refundPixByPaymentId(paymentId, params) {
if (!paymentId)
throw new Error("PaymentId is required for Pix refund.");
const path = `${this.salesBasePath}${paymentId}/void`;
console.log(`[TransactionService] Refunding Pix transaction ${paymentId} with params:`, params);
return this.httpClient.put(path, params);
}
}
// src/services/zeroAuthService.ts
class ZeroAuthService {
httpClient;
basePathV1 = "/1/zeroauth/";
basePathV2 = "/2/zeroauth/";
constructor(httpClient) {
this.httpClient = httpClient;
}
async validateCard(payload) {
console.log("[ZeroAuthService] Validating standard card...");
return this.httpClient.post(this.basePathV1, payload);
}
async validateEWalletCard(payload) {
console.log("[ZeroAuthService] Validating e-wallet card...");
return this.httpClient.post(this.basePathV2, payload);
}
}
// src/index.ts
class CieloEcommerceSDK {
zeroAuth;
payment;
transaction;
tokenization;
binQuery;
query;
constructor(config) {
if (!config.merchantId || !config.merchantKey || !config.environment) {
throw new Error("CieloConfig requires merchantId, merchantKey, and environment (SANDBOX or PRODUCTION).");
}
const credentials = {
merchantId: config.merchantId,
merchantKey: config.merchantKey,
requestIdGenerator: config.requestIdGenerator ?? crypto.randomUUID
};
const transactionBaseUrl = config.environment === "PRODUCTION" ? "https://api.cieloecommerce.cielo.com.br" /* PRODUCTION_TRANSACTION */ : "https://apisandbox.cieloecommerce.cielo.com.br" /* SANDBOX_TRANSACTION */;
const queryBaseUrl = config.environment === "PRODUCTION" ? "https://apiquery.cieloecommerce.cielo.com.br" /* PRODUCTION_QUERY */ : "https://apiquerysandbox.cieloecommerce.cielo.com.br" /* SANDBOX_QUERY */;
const transactionHttpClient = new HttpClient(transactionBaseUrl, credentials);
this.zeroAuth = new ZeroAuthService(transactionHttpClient);
this.payment = new PaymentService(transactionHttpClient);
this.transaction = new TransactionService(transactionHttpClient);
this.tokenization = new TokenizationService(transactionHttpClient);
const queryHttpClient = new HttpClient(queryBaseUrl, credentials);
this.binQuery = new BinQueryService(queryHttpClient);
this.query = new QueryService(queryHttpClient);
console.log(`[CieloEcommerceSDK] Initialized for environment: ${config.environment}`);
}
}
export {
ZeroAuthService,
TransactionService,
PaymentService,
Environment,
CieloNetworkError,
CieloError,
CieloEcommerceSDK,
CieloApiError
};