UNPKG

n8n-nodes-zalo-nnt

Version:

Unofficial Zalo integration for n8n - Send messages, manage groups, user operations with QR login. No API key required, works via browser simulation.

171 lines 7.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZaloChatHistory = void 0; const n8n_workflow_1 = require("n8n-workflow"); const zca_js_1 = require("zca-js"); const helper_1 = require("../utils/helper"); const ZaloChatHistory_properties_1 = require("./ZaloChatHistory.properties"); const utils_1 = require("./utils"); let api; class ZaloChatHistory { constructor() { this.description = { displayName: 'Lịch Sử Chat Zalo by diginno.net', name: 'zaloChatHistory', icon: 'file:../shared/image.svg', group: ['transform'], version: 1, description: 'Lấy lịch sử tin nhắn từ Zalo (cá nhân & nhóm) by diginno.net', defaults: { name: 'Lịch Sử Chat Zalo by diginno.net', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'zaloApi', required: true, }, ], properties: ZaloChatHistory_properties_1.zaloChatHistoryProperties, }; } async execute() { const returnData = []; const items = this.getInputData(); const zaloCred = await this.getCredentials('zaloApi'); let cookieFromCred = zaloCred.cookie; try { cookieFromCred = JSON.parse(zaloCred.cookie); } catch { } const imeiFromCred = zaloCred.imei; const userAgentFromCred = zaloCred.userAgent; try { const zalo = new zca_js_1.Zalo({ imageMetadataGetter: helper_1.imageMetadataGetter, }); api = await zalo.login({ cookie: cookieFromCred, imei: imeiFromCred, userAgent: userAgentFromCred, }); if (!api) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to initialize Zalo API. Check your credentials.'); } if (!api.listener) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Zalo WebSocket listener not available.'); } try { this.logger.info('Starting WebSocket listener...'); api.listener.start({ retryOnClose: false }); await new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('WebSocket connection timeout')); }, 10000); api.listener.once('connected', () => { clearTimeout(timeout); this.logger.info('WebSocket listener connected'); resolve(true); }); api.listener.once('error', (error) => { clearTimeout(timeout); reject(error); }); }); } catch (error) { if (error.message !== 'Already started') { throw error; } this.logger.info('WebSocket listener already started'); } } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Zalo login error: ${error.message}`); } for (let i = 0; i < items.length; i++) { try { const operation = this.getNodeParameter('operation', i); const filterByThreadId = this.getNodeParameter('filterByThreadId', i, true); const threadId = this.getNodeParameter('threadId', i, ''); const fetchAll = this.getNodeParameter('fetchAll', i, false); const limit = this.getNodeParameter('limit', i, 20); const lastMsgId = this.getNodeParameter('lastMsgId', i, ''); const includeReactions = this.getNodeParameter('includeReactions', i, false); const sortOrder = this.getNodeParameter('sortOrder', i, 'desc'); const fromDate = this.getNodeParameter('fromDate', i, ''); const toDate = this.getNodeParameter('toDate', i, ''); const delayBetweenRequests = this.getNodeParameter('delayBetweenRequests', i, 1000); const maxPages = this.getNodeParameter('maxPages', i, 50); const params = (0, utils_1.parseHistoryParams)({ operation, threadId, filterByThreadId, limit, lastMsgId, includeReactions, sortOrder, fromDate: fromDate ? new Date(fromDate).getTime() : null, toDate: toDate ? new Date(toDate).getTime() : null, fetchAll, delayBetweenRequests, maxPages, }); const target = filterByThreadId ? `thread ${threadId}` : 'ALL threads (no filter)'; if (fetchAll) { this.logger.info(`Fetching ALL ${operation} for ${target} (maxPages: ${maxPages}, delay: ${delayBetweenRequests}ms)`); } else { this.logger.info(`Fetching ${operation} for ${target} (limit: ${limit}, lastMsgId: ${lastMsgId || 'null'})`); } if (!api || !api.listener) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Zalo API or listener not initialized'); } const result = await (0, utils_1.getChatHistory)(api, params, api.listener, 30000); this.logger.info(`Retrieved ${result.totalCount}/${result.fetchedCount} messages in ${result.pagesRequested} page(s) ` + `(hasMore: ${result.hasMore}, lastMsgId: ${result.lastMsgId})`); if (fetchAll && result.hasMore) { this.logger.warn(`Chạm trần ${maxPages} trang — backlog chưa vét hết. Chạy lại với "ID Tin Nhắn Cuối" = "${result.lastMsgId}" để kéo tiếp.`); } if (result.filterByThreadId && result.fetchedCount > 0 && result.totalCount === 0) { this.logger.warn(`Zalo trả về ${result.fetchedCount} tin nhưng không tin nào thuộc hội thoại ${threadId}. Truyền lastMsgId="${result.lastMsgId}" để kéo tiếp phần backlog cũ hơn.`); } const responseData = { success: true, operation, threadId: result.threadId, threadType: result.threadType === 0 ? 'user' : 'group', filterByThreadId: result.filterByThreadId, messages: result.messages, hasMore: result.hasMore, lastMsgId: result.lastMsgId, totalCount: result.totalCount, fetchedCount: result.fetchedCount, pagesRequested: result.pagesRequested, }; returnData.push({ json: responseData, }); } catch (error) { this.logger.error('Error fetching chat history:', error); if (this.continueOnFail()) { returnData.push({ json: { success: false, error: error.message, }, }); } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i }); } } } return [returnData]; } } exports.ZaloChatHistory = ZaloChatHistory; //# sourceMappingURL=ZaloChatHistory.node.js.map