@bprotsyk/aso-core 2.1.121 → 2.1.122

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.
@@ -132,6 +132,7 @@ declare function TrafleKeitaroParameters(parameters: any): Promise<{
132
132
  };
133
133
  } | null>;
134
134
  declare function cloneTraffleCampaign(app: IApp, platform: EPlatform, addDefaultStreams?: boolean): Promise<IKeitaroCampaign | any>;
135
+ export declare function updateStreamsForApp(app: IApp, platform: EPlatform): Promise<boolean>;
135
136
  export declare const TraffleKeitaroService: {
136
137
  addOffersToTraffleKeitaro: typeof addOffersToTraffleKeitaro;
137
138
  getTraffleOffersGroups: typeof getTraffleOffersGroups;
@@ -142,5 +143,6 @@ export declare const TraffleKeitaroService: {
142
143
  updateOfferLinkById: typeof updateOfferLinkById;
143
144
  cloneTraffleCampaign: typeof cloneTraffleCampaign;
144
145
  TrafleKeitaroParameters: typeof TrafleKeitaroParameters;
146
+ updateStreamsForApp: typeof updateStreamsForApp;
145
147
  };
146
148
  export {};
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TraffleKeitaroService = exports.ITraffleTrafficType = void 0;
6
+ exports.TraffleKeitaroService = exports.updateStreamsForApp = exports.ITraffleTrafficType = void 0;
7
7
  const http_1 = __importDefault(require("./http"));
8
8
  const app_1 = require("../../../app/app");
9
9
  const openai_1 = require("../../../network/openai/openai");
@@ -709,6 +709,113 @@ async function cloneTraffleCampaign(app, platform, addDefaultStreams) {
709
709
  const updatedCampaign = await getCampaignById(newCampaign.id);
710
710
  return updatedCampaign;
711
711
  }
712
+ async function findCampaignForAppPlatform(app, platform) {
713
+ let allCampaigns = await getAllCampaigns();
714
+ let matchingCampaign = [];
715
+ if (platform && platform !== app_1.EPlatform.GENERAL) {
716
+ const platformName = (0, app_1.getPlatformName)(platform);
717
+ matchingCampaign = allCampaigns.filter((c) => {
718
+ const hasDomain = c.name.includes(app.domainParams.name);
719
+ const hasGroup = c.group == app.id.toString();
720
+ const platformPattern = new RegExp(`\\(.*${platformName}.*\\)\\s*$`);
721
+ const hasPlatform = platformPattern.test(c.name);
722
+ return hasGroup && hasDomain && hasPlatform;
723
+ });
724
+ }
725
+ else {
726
+ matchingCampaign = allCampaigns.filter((c) => {
727
+ const hasBundle = c.name.includes(`[${app.bundle}]`);
728
+ const hasDomain = c.name.includes(app.domainParams.name);
729
+ const noPlatformAtEnd = !/\(.*(?:iOS|Android|Desktop|Mobile).*\)\s*$/.test(c.name);
730
+ return hasBundle && hasDomain && noPlatformAtEnd;
731
+ });
732
+ }
733
+ return matchingCampaign.length > 0 ? matchingCampaign[0] : null;
734
+ }
735
+ function arraysIntersect(a, b) {
736
+ if (!a || !b || a.length === 0 || b.length === 0)
737
+ return false;
738
+ const setA = new Set(a);
739
+ for (const item of b) {
740
+ if (setA.has(item))
741
+ return true;
742
+ }
743
+ return false;
744
+ }
745
+ async function updateStreamState(streamId, newState) {
746
+ console.log(`Updating stream ${streamId} to state: ${newState}`);
747
+ try {
748
+ await http_1.default.put(`streams/${streamId}`, { state: newState });
749
+ console.log(`Successfully updated stream ${streamId} to ${newState}`);
750
+ }
751
+ catch (error) {
752
+ console.error(`Failed to update stream ${streamId}:`, error.response?.data || error.message);
753
+ throw error;
754
+ }
755
+ }
756
+ async function updateStreamsForApp(app, platform) {
757
+ try {
758
+ const platformData = app.platforms[platform];
759
+ if (!platformData) {
760
+ console.log(`No platform data for platform ${platform}`);
761
+ return false;
762
+ }
763
+ const campaign = await findCampaignForAppPlatform(app, platform);
764
+ if (!campaign) {
765
+ console.log(`No campaign found for app ${app.id} (${app.bundle}) and platform ${platform}`);
766
+ return false;
767
+ }
768
+ const streams = await getStreamsByCampaignId(campaign.id);
769
+ let changed = false;
770
+ if (!Array.isArray(streams) || streams.length === 0) {
771
+ console.log(`No streams found for campaign ${campaign.id}`);
772
+ return false;
773
+ }
774
+ console.log(`Found ${streams.length} streams for campaign ${campaign.id}:`);
775
+ streams.forEach((s) => {
776
+ console.log(`- Stream ${s.id}: "${s.name}" (state: ${s.state})`);
777
+ });
778
+ if (!platformData.enabled) {
779
+ for (const s of streams) {
780
+ const isClo = s.name === "CLO";
781
+ const hasCountryFilter = Array.isArray(s.filters) && s.filters.some((f) => f?.name === "country");
782
+ if ((isClo || hasCountryFilter) && s.state !== "disabled") {
783
+ await updateStreamState(s.id, "disabled");
784
+ changed = true;
785
+ }
786
+ }
787
+ return changed;
788
+ }
789
+ // enabled: turn on CLO and geo streams that match platform geo. Leave others as-is.
790
+ const platformGeo = platformData.geo || [];
791
+ for (const s of streams) {
792
+ const isClo = s.name === "CLO";
793
+ if (isClo && s.state !== "active") {
794
+ await updateStreamState(s.id, "active");
795
+ changed = true;
796
+ continue;
797
+ }
798
+ const countryFilter = Array.isArray(s.filters) ? s.filters.find((f) => f?.name === "country") : null;
799
+ if (!countryFilter)
800
+ continue;
801
+ // Heuristic: enable only geo streams whose payload intersects platform geo when mode is 'accept'.
802
+ const mode = countryFilter?.mode;
803
+ const payload = Array.isArray(countryFilter?.payload) ? countryFilter.payload : [];
804
+ if (mode === "accept" && arraysIntersect(payload, platformGeo)) {
805
+ if (s.state !== "active") {
806
+ await updateStreamState(s.id, "active");
807
+ changed = true;
808
+ }
809
+ }
810
+ }
811
+ return changed;
812
+ }
813
+ catch (error) {
814
+ console.error("Failed to update streams for app:", error);
815
+ return false;
816
+ }
817
+ }
818
+ exports.updateStreamsForApp = updateStreamsForApp;
712
819
  exports.TraffleKeitaroService = {
713
- addOffersToTraffleKeitaro, getTraffleOffersGroups, getTraffleAffiliateNetworks, createGroup, deleteOfferById, getAllOffers, updateOfferLinkById, cloneTraffleCampaign, TrafleKeitaroParameters
820
+ addOffersToTraffleKeitaro, getTraffleOffersGroups, getTraffleAffiliateNetworks, createGroup, deleteOfferById, getAllOffers, updateOfferLinkById, cloneTraffleCampaign, TrafleKeitaroParameters, updateStreamsForApp
714
821
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bprotsyk/aso-core",
3
- "version": "2.1.121",
3
+ "version": "2.1.122",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "scripts": {
@@ -856,7 +856,121 @@ async function cloneTraffleCampaign(app: IApp, platform: EPlatform, addDefaultSt
856
856
  return updatedCampaign;
857
857
  }
858
858
 
859
+ async function findCampaignForAppPlatform(app: IApp, platform: EPlatform): Promise<IKeitaroCampaign | null> {
860
+ let allCampaigns = await getAllCampaigns();
861
+ let matchingCampaign: IKeitaroCampaign[] = [];
862
+
863
+ if (platform && platform !== EPlatform.GENERAL) {
864
+ const platformName = getPlatformName(platform);
865
+ matchingCampaign = allCampaigns.filter((c) => {
866
+ const hasDomain = c.name.includes(app.domainParams.name);
867
+ const hasGroup = c.group == app.id.toString();
868
+ const platformPattern = new RegExp(`\\(.*${platformName}.*\\)\\s*$`);
869
+ const hasPlatform = platformPattern.test(c.name);
870
+ return hasGroup && hasDomain && hasPlatform;
871
+ });
872
+ } else {
873
+ matchingCampaign = allCampaigns.filter((c) => {
874
+ const hasBundle = c.name.includes(`[${app.bundle}]`);
875
+ const hasDomain = c.name.includes(app.domainParams.name);
876
+ const noPlatformAtEnd = !/\(.*(?:iOS|Android|Desktop|Mobile).*\)\s*$/.test(c.name);
877
+ return hasBundle && hasDomain && noPlatformAtEnd;
878
+ });
879
+ }
880
+
881
+ return matchingCampaign.length > 0 ? matchingCampaign[0] : null;
882
+ }
883
+
884
+ function arraysIntersect<T>(a: T[] | null | undefined, b: T[] | null | undefined): boolean {
885
+ if (!a || !b || a.length === 0 || b.length === 0) return false;
886
+ const setA = new Set(a);
887
+ for (const item of b) {
888
+ if (setA.has(item)) return true;
889
+ }
890
+ return false;
891
+ }
892
+
893
+ async function updateStreamState(streamId: number, newState: string): Promise<void> {
894
+ console.log(`Updating stream ${streamId} to state: ${newState}`);
895
+ try {
896
+ await keitaroApi.put(`streams/${streamId}`, { state: newState });
897
+ console.log(`Successfully updated stream ${streamId} to ${newState}`);
898
+ } catch (error: any) {
899
+ console.error(`Failed to update stream ${streamId}:`, error.response?.data || error.message);
900
+ throw error;
901
+ }
902
+ }
903
+
904
+ export async function updateStreamsForApp(app: IApp, platform: EPlatform): Promise<boolean> {
905
+ try {
906
+ const platformData = app.platforms[platform];
907
+ if (!platformData) {
908
+ console.log(`No platform data for platform ${platform}`);
909
+ return false;
910
+ }
911
+
912
+ const campaign = await findCampaignForAppPlatform(app, platform);
913
+ if (!campaign) {
914
+ console.log(`No campaign found for app ${app.id} (${app.bundle}) and platform ${platform}`);
915
+ return false;
916
+ }
917
+
918
+ const streams = await getStreamsByCampaignId(campaign.id);
919
+ let changed = false;
920
+
921
+ if (!Array.isArray(streams) || streams.length === 0) {
922
+ console.log(`No streams found for campaign ${campaign.id}`);
923
+ return false;
924
+ }
925
+
926
+ console.log(`Found ${streams.length} streams for campaign ${campaign.id}:`);
927
+ streams.forEach((s: any) => {
928
+ console.log(`- Stream ${s.id}: "${s.name}" (state: ${s.state})`);
929
+ });
930
+
931
+ if (!platformData.enabled) {
932
+ for (const s of streams) {
933
+ const isClo = s.name === "CLO";
934
+ const hasCountryFilter = Array.isArray(s.filters) && s.filters.some((f: any) => f?.name === "country");
935
+ if ((isClo || hasCountryFilter) && s.state !== "disabled") {
936
+ await updateStreamState((s as any).id, "disabled");
937
+ changed = true;
938
+ }
939
+ }
940
+ return changed;
941
+ }
942
+
943
+ // enabled: turn on CLO and geo streams that match platform geo. Leave others as-is.
944
+ const platformGeo = platformData.geo || [];
945
+ for (const s of streams) {
946
+ const isClo = s.name === "CLO";
947
+ if (isClo && s.state !== "active") {
948
+ await updateStreamState((s as any).id, "active");
949
+ changed = true;
950
+ continue;
951
+ }
952
+
953
+ const countryFilter = Array.isArray(s.filters) ? s.filters.find((f: any) => f?.name === "country") : null;
954
+ if (!countryFilter) continue;
955
+
956
+ // Heuristic: enable only geo streams whose payload intersects platform geo when mode is 'accept'.
957
+ const mode: string | undefined = countryFilter?.mode;
958
+ const payload: string[] = Array.isArray(countryFilter?.payload) ? countryFilter.payload : [];
959
+ if (mode === "accept" && arraysIntersect(payload, platformGeo)) {
960
+ if (s.state !== "active") {
961
+ await updateStreamState((s as any).id, "active");
962
+ changed = true;
963
+ }
964
+ }
965
+ }
966
+
967
+ return changed;
968
+ } catch (error) {
969
+ console.error("Failed to update streams for app:", error);
970
+ return false;
971
+ }
972
+ }
859
973
 
860
974
  export const TraffleKeitaroService = {
861
- addOffersToTraffleKeitaro, getTraffleOffersGroups, getTraffleAffiliateNetworks, createGroup, deleteOfferById, getAllOffers, updateOfferLinkById, cloneTraffleCampaign, TrafleKeitaroParameters
975
+ addOffersToTraffleKeitaro, getTraffleOffersGroups, getTraffleAffiliateNetworks, createGroup, deleteOfferById, getAllOffers, updateOfferLinkById, cloneTraffleCampaign, TrafleKeitaroParameters, updateStreamsForApp
862
976
  }
@@ -1,93 +0,0 @@
1
- const { KeitaroCLOGeosService } = require('./lib/keitaro/keitaro-clo-geos');
2
-
3
- // Тестові дані додатків
4
- const testApps = [
5
- {
6
- id: 9999,
7
- bundle: "com.test.app2",
8
- name: "Test App 2",
9
- domainParams: {
10
- name: "test.com"
11
- },
12
- platforms: {
13
- '@': {
14
- geo: ["US"],
15
- enabled: true
16
- }
17
- }
18
- },
19
- {
20
- id: 9998,
21
- bundle: "com.test.app222",
22
- name: "Test App 222",
23
- domainParams: {
24
- name: "test2.com"
25
- },
26
- platforms: {
27
- '@': {
28
- geo: ["UA"],
29
- enabled: true
30
- }
31
- }
32
- }
33
- ];
34
-
35
- async function testGeoSync() {
36
- try {
37
- console.log('=== Тестування синхронізації гео Keitaro CLO ===\n');
38
-
39
- // Тест 1: Отримання додатків, які потребують оновлення гео
40
- console.log('1. Отримання додатків, які потребують оновлення гео...');
41
- const appsNeedingUpdate = await KeitaroCLOGeosService.getAppsNeedingGeoUpdate(testApps);
42
- console.log(`Результат: ${appsNeedingUpdate.length} додатків потребують оновлення\n`);
43
-
44
- // Тест 2: Детальна синхронізація
45
- console.log('2. Повна синхронізація гео...');
46
- const syncSummary = await KeitaroCLOGeosService.syncKeitaroCLOGeosWithApps(testApps);
47
- console.log('Результат синхронізації:');
48
- console.log(`- Всього додатків: ${syncSummary.totalApps}`);
49
- console.log(`- Потребують оновлення: ${syncSummary.appsNeedingUpdate}`);
50
- console.log(`- Помилки: ${syncSummary.errors.length}\n`);
51
-
52
- // Тест 3: Деталі для конкретного додатку (використовуємо наявний ID 9999)
53
- console.log('3. Деталі синхронізації для додатку 9999...');
54
- const appDetails = await KeitaroCLOGeosService.getAppGeoSyncDetails(9999, '@', testApps);
55
- if (appDetails) {
56
- // console.log('Деталі додатку:');
57
- // console.log(`- App ID: ${appDetails.appId}`);
58
- // console.log(`- Платформа: ${appDetails.platform}`);
59
- // console.log(`- Keitaro гео: ${appDetails.keitaroGeos.join(', ')}`);
60
- // console.log(`- App гео: ${appDetails.appGeos.join(', ')}`);
61
- // console.log(`- Відсутні гео: ${appDetails.missingGeos.join(', ')}`);
62
- // console.log(`- Потребує оновлення: ${appDetails.needsUpdate}\n`);
63
- console.log(`appDetails: ${JSON.stringify(appDetails)}`);
64
- } else {
65
- console.log('Додаток не знайдено або помилка\n');
66
- }
67
-
68
-
69
-
70
- // Виводимо всі оновлення
71
- if (syncSummary.updates.length > 0) {
72
- console.log('5. Список оновлень гео:');
73
- syncSummary.updates.forEach((update, index) => {
74
- console.log(`${index + 1}. Додаток ${update.appId} (${update.platform}):`);
75
- console.log(` Нові гео: ${update.newGeos.join(', ')}`);
76
- });
77
- }
78
-
79
- // Виводимо помилки, якщо є
80
- if (syncSummary.errors.length > 0) {
81
- console.log('\n6. Помилки:');
82
- syncSummary.errors.forEach((error, index) => {
83
- console.log(`${index + 1}. ${error}`);
84
- });
85
- }
86
-
87
- } catch (error) {
88
- console.error('Помилка тестування:', error);
89
- }
90
- }
91
-
92
- // Запускаємо тест
93
- testGeoSync();
package/test-keitaro.js DELETED
@@ -1,61 +0,0 @@
1
- const { TraffleKeitaroService } = require('./lib/network/keitaro/traffle/traffle-keitaro-service');
2
- const { EPlatform } = require('./lib/app/app');
3
-
4
- async function testClone() {
5
- try {
6
- // Тестові дані для створення кампанії з trackingParams
7
- const testApp = {
8
- id: 9998,
9
- bundle: "com.test.app222",
10
- name: "Test App",
11
- platforms: {
12
- '@': {
13
- geo: ["UA"],
14
- appsflyerParams: {
15
- apiToken: "test_token",
16
- devKey: "test_dev_key"
17
- },
18
- direct: {
19
- enabled: true,
20
- keitaroData: {
21
- trackingCampaignAlias: "test123",
22
- trackingCampaignId: 9999,
23
- trackingCampaignName: "[9998] Test App ET [com.test.app222] [Android] test2.com",
24
- trackingDomainName: "test2.com",
25
- campingToken: "test_token_123",
26
- trackingParams: {
27
-
28
- advertising_id: "old_advertising_id",
29
- appsflyer_device_id: "old_device_id"
30
- }
31
- }
32
- }
33
- }
34
- },
35
- domainParams: {
36
- name: "test2.com"
37
- }
38
- };
39
-
40
- // Створюємо Traffle кампанію
41
- const result = await TraffleKeitaroService.cloneTraffleCampaign(
42
- testApp,
43
- EPlatform.GENERAL,
44
- true // addDefaultStreams
45
- );
46
-
47
- console.log('Cloned campaign:', result);
48
- console.log(`domain`, result.domain.split('/')[2]);
49
-
50
- // Показуємо оновлені trackingParams
51
- console.log('Updated trackingParams:', testApp.platforms['@'].direct.keitaroData.trackingParams);
52
- } catch (error) {
53
- console.error('Error:', error);
54
- }
55
- }
56
-
57
- testClone();
58
-
59
-
60
-
61
-