@bprotsyk/aso-core 2.1.114 → 2.1.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,131 @@
1
+ # Keitaro CLO Geos Sync Service
2
+
3
+ Сервіс для синхронізації гео-даних між Keitaro CLO потоками та додатками платформи.
4
+
5
+ ## Опис
6
+
7
+ Цей сервіс автоматично:
8
+ 1. Отримує всі кампанії з Keitaro
9
+ 2. Ідентифікує кампанії, які належать нашим додаткам
10
+ 3. Порівнює гео з CLO потоків Keitaro з гео в додатках
11
+ 4. Повертає список додатків, які потребують оновлення гео
12
+
13
+ ## Основні функції
14
+
15
+ ### `syncKeitaroCLOGeosWithApps(apps: IApp[])`
16
+ Основна функція синхронізації. Повертає загальний результат з усіма додатками та їх статусом.
17
+
18
+ ### `getAppGeoSyncDetails(appId: number, platform: string, apps: IApp[])`
19
+ Отримує детальну інформацію про синхронізацію для конкретного додатку та платформи.
20
+
21
+ ### `getAppsNeedingGeoUpdate(apps: IApp[])`
22
+ Повертає тільки список додатків, які потребують оновлення гео.
23
+
24
+ ## Інтерфейси
25
+
26
+ ### `IGeoSyncResult`
27
+ ```typescript
28
+ interface IGeoSyncResult {
29
+ appId: number; // ID додатку
30
+ platform: string; // Платформа (@, hw, sm, rs, xm, ap, tg, am)
31
+ keitaroGeos: string[]; // Гео з Keitaro CLO потоку
32
+ appGeos: string[]; // Поточні гео в додатку
33
+ missingGeos: string[]; // Гео, які відсутні в додатку
34
+ needsUpdate: boolean; // Чи потребує додаток оновлення
35
+ }
36
+ ```
37
+
38
+ ### `IGeoUpdateData`
39
+ ```typescript
40
+ interface IGeoUpdateData {
41
+ appId: number; // ID додатку
42
+ platform: string; // Платформа
43
+ newGeos: string[]; // Нові гео (поточні + відсутні)
44
+ }
45
+ ```
46
+
47
+ ### `IGeoSyncSummary`
48
+ ```typescript
49
+ interface IGeoSyncSummary {
50
+ totalApps: number; // Загальна кількість додатків
51
+ appsNeedingUpdate: number; // Кількість додатків, що потребують оновлення
52
+ updates: IGeoUpdateData[]; // Список оновлень
53
+ errors: string[]; // Список помилок
54
+ }
55
+ ```
56
+
57
+ ## Використання
58
+
59
+ ### Базовий приклад
60
+ ```typescript
61
+ import { KeitaroCLOGeosService } from './keitaro/keitaro-clo-geos';
62
+
63
+ // Список ваших додатків
64
+ const apps = [/* ваші додатки */];
65
+
66
+ // Синхронізація всіх додатків
67
+ const summary = await KeitaroCLOGeosService.syncKeitaroCLOGeosWithApps(apps);
68
+
69
+ console.log(`Потребують оновлення: ${summary.appsNeedingUpdate}`);
70
+ ```
71
+
72
+ ### Отримання конкретного додатку
73
+ ```typescript
74
+ // Деталі для додатку 1628 на платформі @
75
+ const details = await KeitaroCLOGeosService.getAppGeoSyncDetails(1628, '@', apps);
76
+
77
+ if (details?.needsUpdate) {
78
+ console.log(`Додаток ${details.appId} потребує оновлення гео`);
79
+ console.log(`Відсутні гео: ${details.missingGeos.join(', ')}`);
80
+ }
81
+ ```
82
+
83
+ ### Тільки додатки, що потребують оновлення
84
+ ```typescript
85
+ const updates = await KeitaroCLOGeosService.getAppsNeedingGeoUpdate(apps);
86
+
87
+ updates.forEach(update => {
88
+ console.log(`Додаток ${update.appId} (${update.platform}): ${update.newGeos.join(', ')}`);
89
+ });
90
+ ```
91
+
92
+ ## Логіка ідентифікації кампаній
93
+
94
+ Сервіс ідентифікує кампанії як "наші" за наступними критеріями:
95
+
96
+ 1. **ID додатку** в назві кампанії (наприклад: `#1628`, `[1628]`)
97
+ 2. **Bundle ID** або **Domain** в назві кампанії
98
+ 3. **Платформа** визначається за суфіксами:
99
+ - `(hw)` або `huawei` → `hw`
100
+ - `(sm)` або `samsung` → `sm`
101
+ - `(rs)` або `rustore` → `rs`
102
+ - `(xm)` або `xiaomi` → `xm`
103
+ - `(ap)` або `apkpure` → `ap`
104
+ - `(tg)` або `telegram` → `tg`
105
+ - `(am)` або `amazon` → `am`
106
+ - Без суфіксу → `@` (General)
107
+
108
+ ## CLO потоки
109
+
110
+ Сервіс шукає CLO потоки в кампаніях та аналізує їх фільтри за країною. Гео беруться з фільтра `country` в `payload`.
111
+
112
+ ## Тестування
113
+
114
+ Для тестування використовуйте файл `test-keitaro-clo-geos.js`:
115
+
116
+ ```bash
117
+ node test-keitaro-clo-geos.js
118
+ ```
119
+
120
+ ## Залежності
121
+
122
+ - `axios` - для HTTP запитів до Keitaro API
123
+ - `../network/keitaro/http` - конфігурація Keitaro API
124
+ - `../app/app` - інтерфейси додатків та платформ
125
+
126
+ ## Примітки
127
+
128
+ - Сервіс автоматично обробляє помилки та логує їх
129
+ - Гео порівнюються без урахування регістру
130
+ - Повертаються тільки додатки, де гео Keitaro не співпадає з гео додатку
131
+ - Для кожного додатку формується масив нових гео (поточні + відсутні)
package/lib/index.d.ts CHANGED
@@ -25,3 +25,4 @@ export { IDomain, IDomainSetupResult, DomainStatus, DomainTarget, CONST_CLOUFLAR
25
25
  export { INamecheapDomain, INamecheapBuyRequest, INamecheapContactInfo, NamecheapBuyRequestSchema, INamecheapGetDomainsResult, INamecheapBuyResult } from "./general/namecheap-domain";
26
26
  export { NginxTemplate } from "./templates/nginx-template";
27
27
  export { TraffleKeitaroService } from "./network/keitaro/traffle/traffle-keitaro-service";
28
+ export { KeitaroCLOGeosService } from "./keitaro/keitaro-clo-geos";
package/lib/index.js CHANGED
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.TraffleKeitaroService = exports.NginxTemplate = exports.NamecheapBuyRequestSchema = exports.getDomainTargetByIp = exports.CONST_CLOUFLARE_STATUS_READY = exports.DomainTarget = exports.DomainStatus = exports.ICloudflareDomainType = exports.ICloudflareDomainStatus = exports.KeitaroUtils = exports.KeitaroService = exports.ShapeDiv = exports.PanelUserSchema = exports.PanelUserAccessScope = exports.AlternativeOnActivityResult = exports.AlternativeOnBackPressed = exports.AlternativeNavigation = exports.AlternativeStorageType = exports.AlternativeNetworkTool = exports.AlternativeLogicType = exports.AlternativeSourceType = exports.AlternativeLayoutType = exports.AppType = exports.AppStatus = exports.EPlatform = exports.PlugType = exports.AppSchema = exports.IntegrationVersion = exports.SectionsListSchema = exports.DefaultSectionId = exports.OffersSectionSchema = exports.IOfferType = void 0;
26
+ exports.KeitaroCLOGeosService = exports.TraffleKeitaroService = exports.NginxTemplate = exports.NamecheapBuyRequestSchema = exports.getDomainTargetByIp = exports.CONST_CLOUFLARE_STATUS_READY = exports.DomainTarget = exports.DomainStatus = exports.ICloudflareDomainType = exports.ICloudflareDomainStatus = exports.KeitaroUtils = exports.KeitaroService = exports.ShapeDiv = exports.PanelUserSchema = exports.PanelUserAccessScope = exports.AlternativeOnActivityResult = exports.AlternativeOnBackPressed = exports.AlternativeNavigation = exports.AlternativeStorageType = exports.AlternativeNetworkTool = exports.AlternativeLogicType = exports.AlternativeSourceType = exports.AlternativeLayoutType = exports.AppType = exports.AppStatus = exports.EPlatform = exports.PlugType = exports.AppSchema = exports.IntegrationVersion = exports.SectionsListSchema = exports.DefaultSectionId = exports.OffersSectionSchema = exports.IOfferType = void 0;
27
27
  var offer_1 = require("./offers/offer");
28
28
  Object.defineProperty(exports, "IOfferType", { enumerable: true, get: function () { return offer_1.IOfferType; } });
29
29
  var section_1 = require("./offers/section");
@@ -70,3 +70,5 @@ var nginx_template_1 = require("./templates/nginx-template");
70
70
  Object.defineProperty(exports, "NginxTemplate", { enumerable: true, get: function () { return nginx_template_1.NginxTemplate; } });
71
71
  var traffle_keitaro_service_1 = require("./network/keitaro/traffle/traffle-keitaro-service");
72
72
  Object.defineProperty(exports, "TraffleKeitaroService", { enumerable: true, get: function () { return traffle_keitaro_service_1.TraffleKeitaroService; } });
73
+ var keitaro_clo_geos_1 = require("./keitaro/keitaro-clo-geos");
74
+ Object.defineProperty(exports, "KeitaroCLOGeosService", { enumerable: true, get: function () { return keitaro_clo_geos_1.KeitaroCLOGeosService; } });
@@ -0,0 +1,40 @@
1
+ import { IApp } from "../app/app";
2
+ export interface IGeoSyncResult {
3
+ appId: number;
4
+ platform: string;
5
+ keitaroGeos: string[];
6
+ appGeos: string[];
7
+ missingGeos: string[];
8
+ needsUpdate: boolean;
9
+ }
10
+ export interface IGeoUpdateData {
11
+ appId: number;
12
+ platform: string;
13
+ newGeos: string[];
14
+ }
15
+ export interface IGeoSyncSummary {
16
+ totalApps: number;
17
+ appsNeedingUpdate: number;
18
+ updates: IGeoUpdateData[];
19
+ errors: string[];
20
+ }
21
+ /**
22
+ * Основна функція синхронізації гео між Keitaro та додатками
23
+ */
24
+ export declare function syncKeitaroCLOGeosWithApps(apps: IApp[]): Promise<IGeoSyncSummary>;
25
+ /**
26
+ * Отримує детальну інформацію про синхронізацію для конкретного додатку
27
+ */
28
+ export declare function getAppGeoSyncDetails(appId: number, platform: string, apps: IApp[]): Promise<IGeoSyncResult | null>;
29
+ /**
30
+ * Отримує всі додатки, які потребують оновлення гео
31
+ */
32
+ export declare function getAppsNeedingGeoUpdate(apps: IApp[]): Promise<IGeoUpdateData[]>;
33
+ /**
34
+ * Експортуємо основні функції
35
+ */
36
+ export declare const KeitaroCLOGeosService: {
37
+ syncKeitaroCLOGeosWithApps: typeof syncKeitaroCLOGeosWithApps;
38
+ getAppGeoSyncDetails: typeof getAppGeoSyncDetails;
39
+ getAppsNeedingGeoUpdate: typeof getAppsNeedingGeoUpdate;
40
+ };
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.KeitaroCLOGeosService = exports.getAppsNeedingGeoUpdate = exports.getAppGeoSyncDetails = exports.syncKeitaroCLOGeosWithApps = void 0;
7
+ const http_1 = __importDefault(require("../network/keitaro/traffle/http"));
8
+ /**
9
+ * Отримує всі кампанії з Keitaro
10
+ */
11
+ async function getAllKeitaroCampaigns() {
12
+ try {
13
+ const { data: campaigns } = await http_1.default.get('campaigns');
14
+ return campaigns;
15
+ }
16
+ catch (error) {
17
+ console.error('Помилка отримання кампаній з Keitaro:', error);
18
+ throw error;
19
+ }
20
+ }
21
+ /**
22
+ * Отримує всі потоки для конкретної кампанії
23
+ */
24
+ async function getStreamsByCampaignId(campaignId) {
25
+ try {
26
+ const { data: streams } = await http_1.default.get(`campaigns/${campaignId}/streams`);
27
+ return streams;
28
+ }
29
+ catch (error) {
30
+ console.error(`Помилка отримання потоків для кампанії ${campaignId}:`, error);
31
+ throw error;
32
+ }
33
+ }
34
+ /**
35
+ * Отримує гео з CLO потоку кампанії
36
+ */
37
+ async function getCLOGeosFromCampaign(campaignId) {
38
+ try {
39
+ const streams = await getStreamsByCampaignId(campaignId);
40
+ console.log(`Отримано ${streams.length} потоків для кампанії ${campaignId}`);
41
+ const cloStream = streams.find(stream => stream.name === "CLO");
42
+ if (!cloStream) {
43
+ console.log(`CLO потік не знайдено для кампанії ${campaignId}`);
44
+ return [];
45
+ }
46
+ console.log(`Знайдено CLO потік:`, {
47
+ id: cloStream.id,
48
+ name: cloStream.name,
49
+ filters: cloStream.filters
50
+ });
51
+ if (!cloStream.filters || cloStream.filters.length === 0) {
52
+ console.log(`CLO потік не має фільтрів для кампанії ${campaignId}`);
53
+ return [];
54
+ }
55
+ // Шукаємо фільтр за країною в CLO потоці
56
+ const countryFilter = cloStream.filters.find(filter => filter.name === "country");
57
+ if (!countryFilter) {
58
+ console.log(`Фільтр country не знайдено в CLO потоці кампанії ${campaignId}`);
59
+ return [];
60
+ }
61
+ console.log(`Знайдено фільтр country:`, countryFilter);
62
+ if (!countryFilter.payload || !Array.isArray(countryFilter.payload)) {
63
+ console.log(`Фільтр country не має payload або payload не є масивом для кампанії ${campaignId}`);
64
+ return [];
65
+ }
66
+ console.log(`Гео з CLO потоку кампанії ${campaignId}:`, countryFilter.payload);
67
+ return countryFilter.payload;
68
+ }
69
+ catch (error) {
70
+ console.error(`Помилка отримання CLO гео для кампанії ${campaignId}:`, error);
71
+ return [];
72
+ }
73
+ }
74
+ /**
75
+ * Визначає платформу за назвою кампанії
76
+ */
77
+ function detectPlatformFromCampaignName(campaignName) {
78
+ const name = campaignName.toLowerCase();
79
+ if (name.includes('(hw)') || name.includes('huawei')) {
80
+ return 'hw';
81
+ }
82
+ else if (name.includes('(sm)') || name.includes('samsung')) {
83
+ return 'sm';
84
+ }
85
+ else if (name.includes('(rs)') || name.includes('rustore')) {
86
+ return 'rs';
87
+ }
88
+ else if (name.includes('(xm)') || name.includes('xiaomi')) {
89
+ return 'xm';
90
+ }
91
+ else if (name.includes('(ap)') || name.includes('apkpure')) {
92
+ return 'ap';
93
+ }
94
+ else if (name.includes('(tg)') || name.includes('telegram')) {
95
+ return 'tg';
96
+ }
97
+ else if (name.includes('(am)') || name.includes('amazon')) {
98
+ return 'am';
99
+ }
100
+ else {
101
+ return '@'; // General platform
102
+ }
103
+ }
104
+ /**
105
+ * Знаходить додаток за group кампанії
106
+ */
107
+ function findAppByGroup(group, apps) {
108
+ const groupId = parseInt(group);
109
+ if (isNaN(groupId))
110
+ return null;
111
+ return apps.find(app => app.id === groupId) || null;
112
+ }
113
+ /**
114
+ * Основна функція синхронізації гео між Keitaro та додатками
115
+ */
116
+ async function syncKeitaroCLOGeosWithApps(apps) {
117
+ console.log(`Починаємо синхронізацію гео для ${apps.length} додатків...`);
118
+ const summary = {
119
+ totalApps: apps.length,
120
+ appsNeedingUpdate: 0,
121
+ updates: [],
122
+ errors: []
123
+ };
124
+ try {
125
+ // Отримуємо всі кампанії з Keitaro
126
+ const allCampaigns = await getAllKeitaroCampaigns();
127
+ console.log(`Отримано ${allCampaigns.length} кампаній з Keitaro`);
128
+ // Діагностика: виводимо всі кампанії з group
129
+ console.log('\n=== Діагностика кампаній ===');
130
+ const campaignsWithGroup = allCampaigns.filter(c => c.group);
131
+ console.log(`Кампанії з group: ${campaignsWithGroup.length}`);
132
+ // Виводимо перші 10 кампаній з group для діагностики
133
+ campaignsWithGroup.slice(0, 10).forEach(campaign => {
134
+ console.log(` ID: ${campaign.id}, Group: "${campaign.group}", Name: "${campaign.name}"`);
135
+ });
136
+ if (campaignsWithGroup.length > 10) {
137
+ console.log(` ... та ще ${campaignsWithGroup.length - 10} кампаній`);
138
+ }
139
+ // Діагностика: шукаємо кампанії з нашими bundle
140
+ console.log('\n=== Пошук кампаній за bundle ===');
141
+ apps.forEach(app => {
142
+ const campaignsWithBundle = allCampaigns.filter(c => c.name.toLowerCase().includes(app.bundle.toLowerCase()));
143
+ console.log(`Кампанії з bundle "${app.bundle}": ${campaignsWithBundle.length}`);
144
+ campaignsWithBundle.forEach(campaign => {
145
+ console.log(` ID: ${campaign.id}, Group: "${campaign.group}", Name: "${campaign.name}"`);
146
+ });
147
+ });
148
+ // Створюємо мапу додатків за ID для швидкого пошуку
149
+ const appsMap = new Map();
150
+ apps.forEach(app => appsMap.set(app.id, app));
151
+ console.log(`\nШукаємо додатки з ID: ${Array.from(appsMap.keys()).join(', ')}`);
152
+ // Фільтруємо кампанії, які мають group відповідний до наших додатків
153
+ const ourCampaigns = allCampaigns.filter(campaign => {
154
+ const hasGroup = campaign.group && appsMap.has(parseInt(campaign.group));
155
+ if (hasGroup) {
156
+ console.log(`✅ Знайдено нашу кампанію за group: ID=${campaign.id}, name="${campaign.name}", group="${campaign.group}"`);
157
+ }
158
+ return hasGroup;
159
+ });
160
+ // Додатково шукаємо кампанії за bundle в назві
161
+ const campaignsByBundle = allCampaigns.filter(campaign => {
162
+ return apps.some(app => campaign.name.toLowerCase().includes(app.bundle.toLowerCase()));
163
+ });
164
+ console.log(`\nЗнайдено ${campaignsByBundle.length} кампаній за bundle`);
165
+ campaignsByBundle.forEach(campaign => {
166
+ const matchingApp = apps.find(app => campaign.name.toLowerCase().includes(app.bundle.toLowerCase()));
167
+ if (matchingApp) {
168
+ console.log(`✅ Знайдено кампанію за bundle: ID=${campaign.id}, name="${campaign.name}", bundle="${matchingApp.bundle}"`);
169
+ }
170
+ });
171
+ // Об'єднуємо результати
172
+ const allOurCampaigns = [...ourCampaigns, ...campaignsByBundle];
173
+ const uniqueCampaigns = allOurCampaigns.filter((campaign, index, self) => index === self.findIndex(c => c.id === campaign.id));
174
+ console.log(`\nВсього знайдено ${uniqueCampaigns.length} унікальних кампаній наших додатків`);
175
+ // Обробляємо кожну кампанію
176
+ for (const campaign of uniqueCampaigns) {
177
+ try {
178
+ const group = campaign.group;
179
+ if (!group)
180
+ continue;
181
+ const app = appsMap.get(parseInt(group));
182
+ if (!app) {
183
+ console.warn(`Додаток з ID ${group} не знайдено в списку додатків`);
184
+ continue;
185
+ }
186
+ console.log(`\nОбробляємо кампанію ${campaign.id} для додатку ${group}:`);
187
+ console.log(` Назва: ${campaign.name}`);
188
+ console.log(` Group: ${campaign.group}`);
189
+ // Визначаємо платформу за назвою кампанії
190
+ const platform = detectPlatformFromCampaignName(campaign.name);
191
+ console.log(` Визначена платформа: ${platform}`);
192
+ // Отримуємо гео з CLO потоку кампанії
193
+ console.log(` Отримуємо гео з CLO потоку...`);
194
+ const keitaroGeos = await getCLOGeosFromCampaign(campaign.id);
195
+ console.log(` Keitaro CLO гео: ${keitaroGeos.join(', ')}`);
196
+ // Отримуємо гео з додатку для конкретної платформи
197
+ const platformData = app.platforms[platform];
198
+ const appGeos = platformData?.geo || [];
199
+ console.log(` App гео для платформи ${platform}: ${appGeos.join(', ')}`);
200
+ // Порівнюємо гео
201
+ const missingGeos = keitaroGeos.filter(geo => !appGeos.includes(geo));
202
+ const needsUpdate = missingGeos.length > 0;
203
+ console.log(` Відсутні гео: ${missingGeos.join(', ')}`);
204
+ console.log(` Потребує оновлення: ${needsUpdate}`);
205
+ if (needsUpdate) {
206
+ summary.appsNeedingUpdate++;
207
+ const updateData = {
208
+ appId: parseInt(group),
209
+ platform: platform,
210
+ newGeos: [...appGeos, ...missingGeos]
211
+ };
212
+ summary.updates.push(updateData);
213
+ console.log(`✅ Додаток ${group} (${platform}) потребує оновлення гео:`);
214
+ console.log(` Кампанія: ${campaign.name}`);
215
+ console.log(` Keitaro гео: ${keitaroGeos.join(', ')}`);
216
+ console.log(` App гео: ${appGeos.join(', ')}`);
217
+ console.log(` Відсутні гео: ${missingGeos.join(', ')}`);
218
+ console.log(` Нові гео: ${updateData.newGeos.join(', ')}`);
219
+ }
220
+ else {
221
+ console.log(`✅ Додаток ${group} (${platform}) не потребує оновлення гео`);
222
+ }
223
+ }
224
+ catch (error) {
225
+ const errorMsg = `Помилка обробки кампанії ${campaign.id} (${campaign.name}): ${error}`;
226
+ console.error(errorMsg);
227
+ summary.errors.push(errorMsg);
228
+ }
229
+ }
230
+ console.log(`\nСинхронізація завершена. ${summary.appsNeedingUpdate} додатків потребують оновлення гео.`);
231
+ }
232
+ catch (error) {
233
+ const errorMsg = `Критична помилка синхронізації: ${error}`;
234
+ console.error(errorMsg);
235
+ summary.errors.push(errorMsg);
236
+ }
237
+ return summary;
238
+ }
239
+ exports.syncKeitaroCLOGeosWithApps = syncKeitaroCLOGeosWithApps;
240
+ /**
241
+ * Отримує детальну інформацію про синхронізацію для конкретного додатку
242
+ */
243
+ async function getAppGeoSyncDetails(appId, platform, apps) {
244
+ try {
245
+ const app = apps.find(a => a.id === appId);
246
+ if (!app) {
247
+ console.error(`Додаток з ID ${appId} не знайдено`);
248
+ return null;
249
+ }
250
+ const platformData = app.platforms[platform];
251
+ if (!platformData) {
252
+ console.error(`Платформа ${platform} не знайдена для додатку ${appId}`);
253
+ return null;
254
+ }
255
+ // Отримуємо всі кампанії та шукаємо нашу за group
256
+ const allCampaigns = await getAllKeitaroCampaigns();
257
+ const ourCampaign = allCampaigns.find(campaign => campaign.group === appId.toString());
258
+ if (!ourCampaign) {
259
+ console.error(`Кампанія для додатку ${appId} (group: ${appId}) не знайдена в Keitaro`);
260
+ return null;
261
+ }
262
+ console.log(`Знайдено кампанію для додатку ${appId}:`, {
263
+ id: ourCampaign.id,
264
+ name: ourCampaign.name,
265
+ group: ourCampaign.group
266
+ });
267
+ // Отримуємо гео з CLO потоку
268
+ const keitaroGeos = await getCLOGeosFromCampaign(ourCampaign.id);
269
+ const appGeos = platformData.geo || [];
270
+ // Порівнюємо гео
271
+ const missingGeos = keitaroGeos.filter(geo => !appGeos.includes(geo));
272
+ const needsUpdate = missingGeos.length > 0;
273
+ return {
274
+ appId,
275
+ platform,
276
+ keitaroGeos,
277
+ appGeos,
278
+ missingGeos,
279
+ needsUpdate
280
+ };
281
+ }
282
+ catch (error) {
283
+ console.error(`Помилка отримання деталей синхронізації для додатку ${appId}:`, error);
284
+ return null;
285
+ }
286
+ }
287
+ exports.getAppGeoSyncDetails = getAppGeoSyncDetails;
288
+ /**
289
+ * Отримує всі додатки, які потребують оновлення гео
290
+ */
291
+ async function getAppsNeedingGeoUpdate(apps) {
292
+ const summary = await syncKeitaroCLOGeosWithApps(apps);
293
+ return summary.updates;
294
+ }
295
+ exports.getAppsNeedingGeoUpdate = getAppsNeedingGeoUpdate;
296
+ /**
297
+ * Експортуємо основні функції
298
+ */
299
+ exports.KeitaroCLOGeosService = {
300
+ syncKeitaroCLOGeosWithApps,
301
+ getAppGeoSyncDetails,
302
+ getAppsNeedingGeoUpdate
303
+ };
@@ -37,6 +37,100 @@ declare function getTraffleAffiliateNetworks(): Promise<IAffiliateNetwork[]>;
37
37
  declare function deleteOfferById(id: number): Promise<any>;
38
38
  declare function addOffersToTraffleKeitaro(offers: ITraffleOffer[]): Promise<void>;
39
39
  declare function updateOfferLinkById(id: number, action_payload: string | object): Promise<any>;
40
+ declare function TrafleKeitaroParameters(parameters: any): Promise<{
41
+ parameters: {
42
+ keyword: {
43
+ name: string;
44
+ placeholder: string;
45
+ alias: string;
46
+ };
47
+ cost: {
48
+ name: string;
49
+ placeholder: string;
50
+ alias: string;
51
+ };
52
+ currency: {
53
+ name: string;
54
+ placeholder: string;
55
+ alias: string;
56
+ };
57
+ external_id: {
58
+ name: string;
59
+ placeholder: string;
60
+ alias: string;
61
+ };
62
+ creative_id: {
63
+ name: string;
64
+ placeholder: string;
65
+ alias: string;
66
+ };
67
+ ad_campaign_id: {
68
+ name: string;
69
+ placeholder: string;
70
+ alias: string;
71
+ };
72
+ source: {
73
+ name: string;
74
+ placeholder: string;
75
+ alias: string;
76
+ };
77
+ sub_id_1: {
78
+ name: string;
79
+ placeholder: string;
80
+ alias: string;
81
+ };
82
+ sub_id_2: {
83
+ name: string;
84
+ placeholder: string;
85
+ alias: string;
86
+ };
87
+ sub_id_3: {
88
+ name: string;
89
+ placeholder: string;
90
+ alias: string;
91
+ };
92
+ sub_id_4: {
93
+ name: string;
94
+ placeholder: string;
95
+ alias: string;
96
+ };
97
+ sub_id_5: {
98
+ name: string;
99
+ placeholder: string;
100
+ alias: string;
101
+ };
102
+ sub_id_10: {
103
+ name: string;
104
+ placeholder: string;
105
+ alias: string;
106
+ };
107
+ sub_id_15: {
108
+ name: string;
109
+ placeholder: string;
110
+ alias: string;
111
+ };
112
+ sub_id_16: {
113
+ name: string;
114
+ placeholder: any;
115
+ alias: string;
116
+ };
117
+ sub_id_17: {
118
+ name: string;
119
+ placeholder: string;
120
+ alias: string;
121
+ };
122
+ sub_id_18: {
123
+ name: string;
124
+ placeholder: string;
125
+ alias: string;
126
+ };
127
+ sub_id_19: {
128
+ name: string;
129
+ placeholder: any;
130
+ alias: string;
131
+ };
132
+ };
133
+ } | null>;
40
134
  declare function cloneTraffleCampaign(app: IApp, platform: EPlatform, addDefaultStreams?: boolean): Promise<IKeitaroCampaign | any>;
41
135
  export declare const TraffleKeitaroService: {
42
136
  addOffersToTraffleKeitaro: typeof addOffersToTraffleKeitaro;
@@ -47,5 +141,6 @@ export declare const TraffleKeitaroService: {
47
141
  getAllOffers: typeof getAllOffers;
48
142
  updateOfferLinkById: typeof updateOfferLinkById;
49
143
  cloneTraffleCampaign: typeof cloneTraffleCampaign;
144
+ TrafleKeitaroParameters: typeof TrafleKeitaroParameters;
50
145
  };
51
146
  export {};