UNPKG

@warriorteam/redai-zalo-sdk

Version:

Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account, ZNS, Consultation Service, Group Messaging, and Social APIs

297 lines 10.3 kB
"use strict"; /** * Base HTTP client for Zalo API */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseClient = void 0; const axios_1 = __importStar(require("axios")); const form_data_1 = __importDefault(require("form-data")); const common_1 = require("../types/common"); /** * Base client for making HTTP requests to Zalo API */ class BaseClient { constructor(config) { // Set default configuration this.config = { appId: config.appId, appSecret: config.appSecret, timeout: config.timeout || 30000, debug: config.debug || false, apiBaseUrl: config.apiBaseUrl || "https://openapi.zalo.me", retry: { attempts: config.retry?.attempts || 3, delay: config.retry?.delay || 1000, ...config.retry, }, }; this.logger = new common_1.ConsoleLogger(this.config.debug); // Create axios instance this.axios = axios_1.default.create({ baseURL: this.config.apiBaseUrl, timeout: this.config.timeout, headers: { "Content-Type": "application/json", "User-Agent": "RedAI-Zalo-SDK/1.0.0", }, }); this.setupInterceptors(); } /** * Setup axios interceptors for logging and error handling */ setupInterceptors() { // Request interceptor this.axios.interceptors.request.use((config) => { this.logger.debug(`Making ${config.method?.toUpperCase()} request to ${config.url}`, { headers: this.sanitizeHeaders(config.headers || {}), params: config.params, }); return config; }, (error) => { this.logger.error("Request setup error:", error.message); return Promise.reject(error); }); // Response interceptor this.axios.interceptors.response.use((response) => { this.logger.debug(`Received response from ${response.config.url}`, { status: response.status, data: response.data, }); return response; }, (error) => { this.handleAxiosError(error); return Promise.reject(error); }); } /** * Sanitize headers for logging (remove sensitive information) */ sanitizeHeaders(headers) { const sanitized = { ...headers }; if (sanitized.access_token) { sanitized.access_token = "***REDACTED***"; } if (sanitized.secret_key) { sanitized.secret_key = "***REDACTED***"; } return sanitized; } /** * Handle axios errors and log them */ handleAxiosError(error) { if (error.response) { this.logger.error(`HTTP ${error.response.status} error:`, { url: error.config?.url, status: error.response.status, statusText: error.response.statusText, data: error.response.data, }); } else if (error.request) { this.logger.error("No response received:", { url: error.config?.url, message: error.message, }); } else { this.logger.error("Request setup error:", error.message); } } /** * Make a GET request */ async get(url, accessToken, params) { return this.request({ method: "GET", url, headers: accessToken ? { access_token: accessToken } : {}, params, }); } /** * Make a POST request */ async post(url, accessToken, data, params) { return this.request({ method: "POST", url, headers: accessToken ? { access_token: accessToken } : {}, data, params, }); } /** * Make a PUT request */ async put(url, accessToken, data, params) { return this.request({ method: "PUT", url, headers: accessToken ? { access_token: accessToken } : {}, data, params, }); } /** * Make a DELETE request */ async delete(url, accessToken, params) { return this.request({ method: "DELETE", url, headers: accessToken ? { access_token: accessToken } : {}, params, }); } /** * Upload file using FormData */ async uploadFile(url, accessToken, file, filename, additionalFields) { const formData = new form_data_1.default(); formData.append("file", file, filename); if (additionalFields) { Object.entries(additionalFields).forEach(([key, value]) => { formData.append(key, value); }); } return this.request({ method: "POST", url, headers: { access_token: accessToken, "Content-Type": "multipart/form-data", ...formData.getHeaders(), }, data: formData, }); } /** * Make a generic HTTP request with retry logic */ async request(config) { let lastError; for (let attempt = 1; attempt <= (this.config.retry?.attempts || 3); attempt++) { try { const axiosConfig = { method: config.method, url: config.url, headers: config.headers, params: config.params, data: config.data, timeout: config.timeout || this.config.timeout, }; const response = await this.axios.request(axiosConfig); // Check for Zalo API errors in response this.validateZaloResponse(response.data); return response.data; } catch (error) { lastError = error; if (attempt < (this.config.retry?.attempts || 3) && this.shouldRetry(error)) { this.logger.warn(`Request failed, retrying (${attempt}/${this.config.retry?.attempts || 3})...`); await this.delay((this.config.retry?.delay || 1000) * attempt); continue; } break; } } throw this.createSDKError(lastError); } /** * Validate Zalo API response for errors */ validateZaloResponse(data) { if (data && typeof data === "object") { // Check for standard Zalo error format if ("error" in data && data.error !== 0) { const errorMessage = data.error_description || data.message || "Unknown Zalo API error"; throw new common_1.ZaloSDKError(errorMessage, data.error, data); } // Check for nested result error format if ("result" in data && data.result && typeof data.result === "object" && "error" in data.result && data.result.error !== 0) { const errorMessage = data.result.error_description || data.result.message || "Unknown Zalo API error"; throw new common_1.ZaloSDKError(errorMessage, data.result.error, data.result); } } } /** * Determine if request should be retried */ shouldRetry(error) { // Retry on network errors or 5xx server errors return (!error.response || (error.response.status >= 500 && error.response.status < 600)); } /** * Create SDK error from axios error */ createSDKError(error) { if (error instanceof common_1.ZaloSDKError) { return error; } if (error instanceof axios_1.AxiosError) { const response = error.response; if (response?.data) { const errorCode = response.data.error || response.status; const errorMessage = response.data.error_description || response.data.message || error.message; return new common_1.ZaloSDKError(errorMessage, errorCode, response.data); } } return new common_1.ZaloSDKError(error.message, -1, error); } /** * Delay execution for specified milliseconds */ delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } } exports.BaseClient = BaseClient; //# sourceMappingURL=base-client.js.map