UNPKG

n8n-nodes-keitaro

Version:

Полноценная интеграция с Keitaro Tracker API для n8n

1,249 lines (1,248 loc) 155 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Keitaro = void 0; // Функция для определения типа данных на основе ресурса function getTypedResponse(resource, data) { switch (resource) { case 'campaign': return data; case 'stream': return data; case 'landing': return data; case 'offer': return data; case 'traffic': return data; case 'user': return data; case 'blacklist': return data; case 'bot': return data; case 'postback': return data; case 'source': return data; case 'conversion': return data; case 'domain': return data; case 'click': return data; case 'filter': return data; case 'settings': return data; case 'log': return data; case 'stats': return data; case 'group': return data; default: return data; } } // Функция для определения типа ответа function getResponseData(response) { // Проверяем разные форматы ответа API Keitaro if (response && typeof response === 'object') { // Проверяем поле status для определения успешности запроса if ('status' in response) { // Если статус не "success", выбрасываем ошибку if (response.status !== 'success' && response.status !== 200) { const errorMessage = response.error || response.message || 'Неизвестная ошибка API'; throw new Error(`Ошибка API: ${errorMessage}`); } } if ('data' in response && response.data !== undefined) { return response.data; } else if ('response' in response && response.response !== undefined) { return response.response; } else if ('result' in response && response.result !== undefined) { return response.result; } else if ('body' in response && response.body !== undefined) { return response.body; } } // Если не удалось найти данные в известных полях, возвращаем весь ответ return response; } // Функция для безопасного логирования объектов function safeStringify(obj) { try { return JSON.stringify(obj, (key, value) => { // Исключаем циклические ссылки if (key === 'socket' || key === '_httpMessage' || key === 'req' || key === 'res') { return '[Circular]'; } return value; }, 2); } catch (error) { return `[Не удалось сериализовать объект: ${error instanceof Error ? error.message : String(error)}]`; } } // Хелпер для создания пути API function getApiPath(resourceMap, resource, resourceId, operation) { // Специальная обработка для клика с операцией getAll - используем /clicks/log if (resource === 'click' && operation === 'getAll') { return '/admin_api/v1/clicks/log'; } // Специальная обработка для конверсий с операцией getAll - используем /conversions/log if (resource === 'conversion' && operation === 'getAll') { return '/admin_api/v1/conversions/log'; } // Специальная обработка для статистики if (resource === 'stats' && operation === 'getAll') { return '/admin_api/v1/report/build'; } // Специальная обработка для конверсий if (resource === 'conversion') { return `/admin_api/v1/conversions${resourceId ? `/${resourceId}` : ''}`; } const resourcePath = resourceMap[resource]; if (!resourcePath) { throw new Error(`Неизвестный ресурс: ${resource}`); } return `/admin_api/v1/${resourcePath}${resourceId ? `/${resourceId}` : ''}`; } // Хелпер для форматирования URL API function formatBaseUrl(domain) { let baseUrl = domain.trim(); // Удаляем завершающий слеш, если он есть if (baseUrl.endsWith('/')) { baseUrl = baseUrl.slice(0, -1); } // Добавляем протокол, если его нет if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) { baseUrl = `https://${baseUrl}`; } return baseUrl; } class Keitaro { constructor() { this.description = { displayName: 'Keitaro', name: 'keitaro', icon: 'file:keitaro.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Работа с API Keitaro', defaults: { name: 'Keitaro', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'keitaroApi', required: true, }, ], requestDefaults: { baseURL: '={{$credentials.domain}}', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, }, properties: [ { displayName: 'Ресурс', name: 'resource', type: 'options', noDataExpression: true, required: true, options: [ { name: 'Кампания', value: 'campaign', }, { name: 'Поток', value: 'stream', }, { name: 'Лендинг', value: 'landing', }, { name: 'Оффер', value: 'offer', }, { name: 'Трафик', value: 'traffic', }, { name: 'Пользователь', value: 'user', }, { name: 'Блэклист', value: 'blacklist', }, { name: 'Бот', value: 'bot', }, { name: 'Постбэк', value: 'postback', }, { name: 'Источник', value: 'source', }, { name: 'Конверсия', value: 'conversion', }, { name: 'Домен', value: 'domain', }, { name: 'Клик', value: 'click', }, { name: 'Фильтр', value: 'filter', }, { name: 'Настройки', value: 'settings', }, { name: 'Лог', value: 'log', }, { name: 'Статистика', value: 'stats', }, { name: 'Группа', value: 'group', }, ], default: 'campaign', description: 'Тип ресурса для работы', }, { displayName: 'Операция', name: 'operation', type: 'options', noDataExpression: true, required: true, displayOptions: { show: { resource: [ 'campaign', 'stream', 'landing', 'offer', 'traffic', 'user', 'blacklist', 'bot', 'postback', 'source', 'conversion', 'domain', 'click', 'filter', 'settings', 'log', 'stats', 'group', ], }, }, options: [ { name: 'Получить', value: 'get', description: 'Получить информацию', action: 'Получить информацию', }, { name: 'Получить Все', value: 'getAll', description: 'Получить список всех записей', action: 'Получить список всех записей', }, { name: 'Создать', value: 'create', description: 'Создать новую запись', action: 'Создать новую запись', }, { name: 'Обновить', value: 'update', description: 'Обновить существующую запись', action: 'Обновить существующую запись', }, { name: 'Удалить', value: 'delete', description: 'Удалить запись', action: 'Удалить запись', }, { name: 'Тестировать', value: 'test', description: 'Тестировать постбэк (отправить тестовую конверсию)', action: 'Тестировать постбэк', displayOptions: { show: { resource: [ 'postback', ], }, }, }, ], default: 'get', }, { displayName: 'ID Кампании', name: 'campaignId', type: 'string', required: true, displayOptions: { show: { resource: ['campaign'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID кампании', }, { displayName: 'Данные Кампании', name: 'campaignData', type: 'json', required: true, displayOptions: { show: { resource: ['campaign'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные кампании в формате JSON', }, { displayName: 'ID Потока', name: 'streamId', type: 'string', required: true, displayOptions: { show: { resource: ['stream'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID потока', }, { displayName: 'Данные Потока', name: 'streamData', type: 'json', required: true, displayOptions: { show: { resource: ['stream'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные потока в формате JSON', }, { displayName: 'ID Лендинга', name: 'landingId', type: 'string', required: true, displayOptions: { show: { resource: ['landing'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID лендинга', }, { displayName: 'Данные Лендинга', name: 'landingData', type: 'json', required: true, displayOptions: { show: { resource: ['landing'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные лендинга в формате JSON', }, { displayName: 'ID Оффера', name: 'offerId', type: 'string', required: true, displayOptions: { show: { resource: ['offer'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID оффера', }, { displayName: 'Данные Оффера', name: 'offerData', type: 'json', required: true, displayOptions: { show: { resource: ['offer'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные оффера в формате JSON', }, { displayName: 'ID Пользователя', name: 'userId', type: 'string', required: true, displayOptions: { show: { resource: ['user'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID пользователя', }, { displayName: 'Данные Пользователя', name: 'userData', type: 'json', required: true, displayOptions: { show: { resource: ['user'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные пользователя в формате JSON', }, { displayName: 'ID Блэклиста', name: 'blacklistId', type: 'string', required: true, displayOptions: { show: { resource: ['blacklist'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID записи в блэклисте', }, { displayName: 'Данные Блэклиста', name: 'blacklistData', type: 'json', required: true, displayOptions: { show: { resource: ['blacklist'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные записи в блэклисте в формате JSON', }, { displayName: 'ID Бота', name: 'botId', type: 'string', required: true, displayOptions: { show: { resource: ['bot'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID бота', }, { displayName: 'Данные Бота', name: 'botData', type: 'json', required: true, displayOptions: { show: { resource: ['bot'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные бота в формате JSON', }, { displayName: 'ID Постбэка', name: 'postbackId', type: 'string', required: true, displayOptions: { show: { resource: ['postback'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID постбэка', }, { displayName: 'Название постбэка', name: 'postbackName', type: 'string', required: true, displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: '', description: 'Название постбэка', }, { displayName: 'URL постбэка', name: 'postbackUrl', type: 'string', required: true, displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: '', placeholder: 'https://example.com/postback?clickid={sub_id_1}&status={status}', description: 'URL для отправки постбэка. Можно использовать макросы: {sub_id_1}, {status}, {revenue}, и т.д.', }, { displayName: 'Статус', name: 'postbackStatus', type: 'options', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, options: [ { name: 'Активный', value: 'active', }, { name: 'Неактивный', value: 'inactive', }, ], default: 'active', description: 'Статус постбэка', }, { displayName: 'Триггер', name: 'postbackTrigger', type: 'options', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, options: [ { name: 'Конверсия', value: 'conversion', description: 'Срабатывает при любой конверсии', }, { name: 'Лид', value: 'lead', description: 'Срабатывает только при получении лида', }, { name: 'Продажа', value: 'sale', description: 'Срабатывает только при продаже', }, ], default: 'conversion', description: 'Когда отправлять постбэк', }, { displayName: 'HTTP метод', name: 'postbackMethod', type: 'options', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, options: [ { name: 'GET', value: 'GET', }, { name: 'POST', value: 'POST', }, ], default: 'GET', description: 'HTTP метод для отправки постбэка', }, { displayName: 'Статусы лидов', name: 'leadStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: 'lead,registration,new', description: 'Статусы для лидов, перечисленные через запятую. Если партнерская сеть отправит один из этих статусов, Keitaro запишет его как "Лид".', }, { displayName: 'Статусы продаж', name: 'saleStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: 'sale,paid,billed,completed', description: 'Статусы для продаж, перечисленные через запятую. Если партнерская сеть отправит один из этих статусов, Keitaro запишет его как "Продажа".', }, { displayName: 'Отклоненные статусы', name: 'rejectedStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: 'rejected,canceled,fake,fraud', description: 'Статусы для отклоненных конверсий, перечисленные через запятую. Если партнерская сеть отправит один из этих статусов, Keitaro запишет его как "Отклонено".', }, { displayName: 'Дополнительные настройки', name: 'postbackAdvanced', type: 'boolean', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: false, description: 'Показать дополнительные настройки постбэка', }, { displayName: 'Ключ постбэка', name: 'postbackKey', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: '', description: 'Ключ для аутентификации постбэка. Обеспечивает дополнительную безопасность.', }, { displayName: 'Валюта', name: 'postbackCurrency', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 'USD', description: 'Валюта, используемая по умолчанию для конверсий.', }, { displayName: 'Таймаут (сек)', name: 'postbackTimeout', type: 'number', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 30, description: 'Таймаут отправки постбэка в секундах.', }, { displayName: 'Количество повторных попыток', name: 'postbackRetryCount', type: 'number', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 3, description: 'Сколько раз пытаться повторно отправить постбэк в случае ошибки.', }, { displayName: 'Задержка между попытками (сек)', name: 'postbackRetryDelay', type: 'number', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 60, description: 'Задержка между повторными попытками в секундах.', }, { displayName: 'Кампании', name: 'postbackCampaigns', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: '', description: 'ID кампаний через запятую, для которых будет отправляться постбэк. Оставьте пустым для всех кампаний.', }, { displayName: 'Страны', name: 'postbackCountries', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: '', description: 'Коды стран через запятую, для которых будет отправляться постбэк. Оставьте пустым для всех стран.', }, { displayName: 'ID Источника', name: 'sourceId', type: 'string', required: true, displayOptions: { show: { resource: ['source'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID источника', }, { displayName: 'Данные Источника', name: 'sourceData', type: 'json', required: true, displayOptions: { show: { resource: ['source'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные источника в формате JSON', }, { displayName: 'ID Конверсии', name: 'conversionId', type: 'string', required: true, displayOptions: { show: { resource: ['conversion'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID конверсии', }, { displayName: 'Данные Конверсии', name: 'conversionData', type: 'json', required: true, displayOptions: { show: { resource: ['conversion'], operation: ['create', 'update'], }, }, default: '{"click_id":"CLICK_ID_HERE","status":"lead","revenue":0}', description: 'Данные конверсии в формате JSON. Обязательно укажите click_id.', }, { displayName: 'Упрощенное создание конверсии', name: 'conversionSimple', type: 'fixedCollection', typeOptions: { multipleValues: false, }, displayOptions: { show: { resource: ['conversion'], operation: ['create'], }, }, default: {}, placeholder: 'Добавить параметры конверсии', options: [ { name: 'values', displayName: 'Параметры конверсии', values: [ { displayName: 'ID клика (click_id)', name: 'click_id', type: 'string', required: true, default: '', description: 'ID клика, для которого регистрируется конверсия', }, { displayName: 'Статус', name: 'status', type: 'options', options: [ { name: 'Лид', value: 'lead', }, { name: 'Продажа', value: 'sale', }, { name: 'Отклонено', value: 'rejected', }, { name: 'Регистрация', value: 'reg', }, { name: 'Депозит', value: 'dep', }, ], default: 'lead', description: 'Статус конверсии', }, { displayName: 'Сумма дохода', name: 'revenue', type: 'number', default: 0, description: 'Сумма дохода от конверсии', }, { displayName: 'Валюта', name: 'currency', type: 'string', default: 'USD', description: 'Валюта дохода', }, { displayName: 'ID транзакции', name: 'transaction_id', type: 'string', default: '', description: 'ID транзакции (для повторных продаж/upsell)', }, { displayName: 'Комментарий', name: 'comment', type: 'string', default: '', description: 'Комментарий к конверсии', }, ], }, ], description: 'Упрощенный способ создания конверсии', }, { displayName: 'ID Домена', name: 'domainId', type: 'string', required: true, displayOptions: { show: { resource: ['domain'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID домена', }, { displayName: 'Данные Домена', name: 'domainData', type: 'json', required: true, displayOptions: { show: { resource: ['domain'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные домена в формате JSON', }, { displayName: 'ID Клика', name: 'clickId', type: 'string', required: true, displayOptions: { show: { resource: ['click'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID клика', }, { displayName: 'Данные Клика', name: 'clickData', type: 'json', required: true, displayOptions: { show: { resource: ['click'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные клика в формате JSON', }, { displayName: 'ID Фильтра', name: 'filterId', type: 'string', required: true, displayOptions: { show: { resource: ['filter'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID фильтра', }, { displayName: 'Данные Фильтра', name: 'filterData', type: 'json', required: true, displayOptions: { show: { resource: ['filter'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные фильтра в формате JSON', }, { displayName: 'ID Настроек', name: 'settingsId', type: 'string', required: true, displayOptions: { show: { resource: ['settings'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID настроек', }, { displayName: 'Данные Настроек', name: 'settingsData', type: 'json', required: true, displayOptions: { show: { resource: ['settings'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные настроек в формате JSON', }, { displayName: 'ID Лога', name: 'logId', type: 'string', required: true, displayOptions: { show: { resource: ['log'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID лога', }, { displayName: 'Данные Лога', name: 'logData', type: 'json', required: true, displayOptions: { show: { resource: ['log'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные лога в формате JSON', }, { displayName: 'ID Статистики', name: 'statsId', type: 'string', required: true, displayOptions: { show: { resource: ['stats'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID статистики', }, { displayName: 'Данные Статистики', name: 'statsData', type: 'json', required: true, displayOptions: { show: { resource: ['stats'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные статистики в формате JSON', }, { displayName: 'ID Группы', name: 'groupId', type: 'string', required: true, displayOptions: { show: { resource: ['group'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID группы', }, { displayName: 'Данные Группы', name: 'groupData', type: 'json', required: true, displayOptions: { show: { resource: ['group'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные группы в формате JSON', }, // Параметры для получения кликов { displayName: 'Параметры Фильтрации Кликов', name: 'clickParameters', type: 'fixedCollection', placeholder: 'Добавить параметр', default: {}, displayOptions: { show: { resource: [ 'click', ], operation: [ 'getAll', ], }, }, typeOptions: { multipleValues: false, }, description: 'Параметры для получения кликов', options: [ { name: 'range', displayName: 'Диапазон дат', values: [ { displayName: 'Начальная дата', name: 'from', type: 'string', default: '', description: 'Начальная дата в формате YYYY-MM-DD', }, { displayName: 'Конечная Дата', name: 'to', type: 'string', default: '', description: 'Конечная дата в формате YYYY-MM-DD', }, { displayName: 'Часовой пояс', name: 'timezone', type: 'string', default: '', description: 'Часовой пояс, например Europe/Moscow', }, ] }, { name: 'interval', displayName: 'Интервал', values: [ { displayName: 'Интервал', name: 'interval', type: 'options', options: [ { name: 'Сегодня', value: 'today', }, { name: 'Вчера', value: 'yesterday', }, { name: '7 дней назад', value: '7_days_ago', }, { name: 'Первый день этой недели', value: 'first_day_of_this_week', }, { name: '1 месяц назад', value: '1_month_ago', }, { name: 'Первый день этого месяца', value: 'first_day_of_this_month', }, { name: '1 год назад', value: '1_year_ago', }, { name: 'Первый день этого года', value: 'first_day_of_this_year', }, { name: 'За все время', value: 'all_time', }, ], default: '', description: 'Предустановленный интервал времени', }, ], }, { name: 'mainFilters', displayName: 'Основные фильтры', values: [ { displayName: 'ID Кампании', name: 'campaign_id', type: 'string', default: '', description: 'Фильтрация по ID кампании', }, { displayName: 'ID Потока', name: 'stream_id', type: 'string', default: '', description: 'Фильтрация по ID потока', }, { displayName: 'ID Лендинга', name: 'landing_id', type: 'string', default: '', description: 'Фильтрация по ID лендинга', }, {