UNPKG

@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
// 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 };