UNPKG

@warriorteam/redai-zalo-sdk

Version:

Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account v3.0, ZNS with Full Type Safety, Consultation Service, Broadcast Service, Group Messaging with List APIs, Social APIs, Enhanced Article Management, Promotion Service v3.0 with Multip

296 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, ...formData.getHeaders(), // Let form-data package set Content-Type with proper boundary }, 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