@bprotsyk/aso-core 2.1.198 → 2.1.224
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.
- package/lib/app/app.d.ts +2 -1
- package/lib/app/app.js +1 -0
- package/lib/keitaro/keitaro-offer.d.ts +14 -3
- package/lib/network/keitaro/keitaro-service.d.ts +27 -0
- package/lib/network/keitaro/keitaro-service.js +95 -0
- package/package.json +1 -1
- package/src/app/app.ts +2 -1
- package/src/keitaro/keitaro-offer.ts +14 -3
- package/src/network/keitaro/keitaro-service.ts +114 -1
package/lib/app/app.d.ts
CHANGED
|
@@ -177,7 +177,8 @@ export interface IDomainParams {
|
|
|
177
177
|
export declare enum AppStatus {
|
|
178
178
|
ARCHIVED = "ARCHIVED",
|
|
179
179
|
IN_DEVELOPMENT = "IN_DEVELOPMENT",
|
|
180
|
-
READY = "READY"
|
|
180
|
+
READY = "READY",
|
|
181
|
+
DISABLED = "DISABLED"
|
|
181
182
|
}
|
|
182
183
|
export interface IKeitaroDirectTrackingParams {
|
|
183
184
|
naming: string;
|
package/lib/app/app.js
CHANGED
|
@@ -78,6 +78,7 @@ var AppStatus;
|
|
|
78
78
|
AppStatus["ARCHIVED"] = "ARCHIVED";
|
|
79
79
|
AppStatus["IN_DEVELOPMENT"] = "IN_DEVELOPMENT";
|
|
80
80
|
AppStatus["READY"] = "READY";
|
|
81
|
+
AppStatus["DISABLED"] = "DISABLED";
|
|
81
82
|
})(AppStatus = exports.AppStatus || (exports.AppStatus = {}));
|
|
82
83
|
exports.AppSchema = new mongoose_1.Schema({
|
|
83
84
|
id: {
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export interface IKeitaroOffer {
|
|
2
2
|
id: number;
|
|
3
|
-
campaign_id
|
|
3
|
+
campaign_id?: number;
|
|
4
4
|
name: string;
|
|
5
|
-
url
|
|
6
|
-
country
|
|
5
|
+
url?: string;
|
|
6
|
+
country?: string | string[];
|
|
7
|
+
group_id?: number;
|
|
8
|
+
action_type?: string;
|
|
9
|
+
action_payload?: string;
|
|
10
|
+
affiliate_network_id?: number;
|
|
11
|
+
payout_value?: number;
|
|
12
|
+
payout_currency?: string;
|
|
13
|
+
payout_type?: string;
|
|
14
|
+
state?: string;
|
|
15
|
+
offer_type?: string;
|
|
16
|
+
payout_auto?: boolean;
|
|
17
|
+
payout_upsell?: boolean;
|
|
7
18
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IKeitaroStream } from "../../keitaro/keitaro-stream";
|
|
2
|
+
import { IOffer } from "../../offers/offer";
|
|
2
3
|
import { IKeitaroCampaign } from "../../keitaro/keitaro-campaign";
|
|
3
4
|
import { IKeitaroDomain } from "../../keitaro/keitaro-domain";
|
|
4
5
|
import { IApp, IAppKeitaroData, IntegrationType } from "../../app/app";
|
|
@@ -15,6 +16,28 @@ declare function updateCampaign(id: number, payload: Partial<IKeitaroCampaign>):
|
|
|
15
16
|
declare function createCampaign(campaignData: Partial<IKeitaroCampaign>): Promise<IKeitaroCampaign>;
|
|
16
17
|
declare function getDomains(onlyActive?: boolean): Promise<IKeitaroDomain[]>;
|
|
17
18
|
declare function getAllOffers(): Promise<IKeitaroOffer[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Create offer in Keitaro from our IOffer
|
|
21
|
+
* @param offer - Our internal IOffer object
|
|
22
|
+
* @returns Keitaro offer with ID
|
|
23
|
+
*/
|
|
24
|
+
declare function createOfferInKeitaro(offer: IOffer): Promise<IKeitaroOffer>;
|
|
25
|
+
declare function createStream(campaignId: number, streamData: Partial<IKeitaroStream>): Promise<IKeitaroStream>;
|
|
26
|
+
/**
|
|
27
|
+
* Get all offerwall campaigns (campaigns with [◈] prefix in group 106)
|
|
28
|
+
*/
|
|
29
|
+
declare function getOfferwallCampaigns(): Promise<IKeitaroCampaign[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Add our IOffer to Keitaro and distribute to all offerwall campaigns
|
|
32
|
+
* @param offer - Our internal IOffer object
|
|
33
|
+
* @returns Result with Keitaro offer ID and distribution stats
|
|
34
|
+
*/
|
|
35
|
+
declare function addOfferToKeitaro(offer: IOffer): Promise<{
|
|
36
|
+
keitaroOfferId: number;
|
|
37
|
+
success: number;
|
|
38
|
+
failed: number;
|
|
39
|
+
campaigns: string[];
|
|
40
|
+
}>;
|
|
18
41
|
declare function generateAlias(): string;
|
|
19
42
|
/**
|
|
20
43
|
* Clone a campaign for an app based on integration type
|
|
@@ -33,9 +56,13 @@ export declare const KeitaroService: {
|
|
|
33
56
|
createCampaign: typeof createCampaign;
|
|
34
57
|
updateCampaign: typeof updateCampaign;
|
|
35
58
|
cloneCampaignForApp: typeof cloneCampaignForApp;
|
|
59
|
+
getOfferwallCampaigns: typeof getOfferwallCampaigns;
|
|
36
60
|
getStreamsByCampaignId: typeof getStreamsByCampaignId;
|
|
61
|
+
createStream: typeof createStream;
|
|
37
62
|
getDomains: typeof getDomains;
|
|
38
63
|
getAllOffers: typeof getAllOffers;
|
|
64
|
+
createOfferInKeitaro: typeof createOfferInKeitaro;
|
|
65
|
+
addOfferToKeitaro: typeof addOfferToKeitaro;
|
|
39
66
|
generateAlias: typeof generateAlias;
|
|
40
67
|
campaignToKeitaroData: typeof campaignToKeitaroData;
|
|
41
68
|
};
|
|
@@ -39,6 +39,97 @@ async function getAllOffers() {
|
|
|
39
39
|
const { data: offers } = await http_1.default.get('offers');
|
|
40
40
|
return offers;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Create offer in Keitaro from our IOffer
|
|
44
|
+
* @param offer - Our internal IOffer object
|
|
45
|
+
* @returns Keitaro offer with ID
|
|
46
|
+
*/
|
|
47
|
+
async function createOfferInKeitaro(offer) {
|
|
48
|
+
const payload = {
|
|
49
|
+
name: `${offer.caption} ${offer.geo} (${offer.name})`,
|
|
50
|
+
group_id: DEFAULT_OFFERS_GROUP_ID,
|
|
51
|
+
action_type: 'http',
|
|
52
|
+
action_payload: offer.link,
|
|
53
|
+
affiliate_network_id: 0,
|
|
54
|
+
payout_value: 0,
|
|
55
|
+
payout_currency: 'USD',
|
|
56
|
+
payout_type: 'CPA',
|
|
57
|
+
state: offer.hidden ? 'disabled' : 'active',
|
|
58
|
+
country: [offer.geo],
|
|
59
|
+
offer_type: 'external',
|
|
60
|
+
payout_auto: true,
|
|
61
|
+
payout_upsell: true,
|
|
62
|
+
};
|
|
63
|
+
const { data: keitaroOffer } = await http_1.default.post('offers', payload);
|
|
64
|
+
return keitaroOffer;
|
|
65
|
+
}
|
|
66
|
+
// Stream operations
|
|
67
|
+
async function createStream(campaignId, streamData) {
|
|
68
|
+
const { data: stream } = await http_1.default.post('streams', {
|
|
69
|
+
...streamData,
|
|
70
|
+
campaign_id: campaignId
|
|
71
|
+
});
|
|
72
|
+
return stream;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get all offerwall campaigns (campaigns with [◈] prefix in group 106)
|
|
76
|
+
*/
|
|
77
|
+
async function getOfferwallCampaigns() {
|
|
78
|
+
const allCampaigns = await getAllCampaigns();
|
|
79
|
+
// Offerwall campaigns have [◈] in their name and are in group 106
|
|
80
|
+
return allCampaigns.filter(c => c.name.includes('[◈]') && c.group_id === DEFAULT_CAMPAIGNS_GROUP_ID);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Add our IOffer to Keitaro and distribute to all offerwall campaigns
|
|
84
|
+
* @param offer - Our internal IOffer object
|
|
85
|
+
* @returns Result with Keitaro offer ID and distribution stats
|
|
86
|
+
*/
|
|
87
|
+
async function addOfferToKeitaro(offer) {
|
|
88
|
+
// First, create the offer in Keitaro
|
|
89
|
+
const keitaroOffer = await createOfferInKeitaro(offer);
|
|
90
|
+
console.log(`Created Keitaro offer #${keitaroOffer.id}: ${keitaroOffer.name}`);
|
|
91
|
+
// Then distribute to all offerwall campaigns
|
|
92
|
+
const offerwallCampaigns = await getOfferwallCampaigns();
|
|
93
|
+
let success = 0;
|
|
94
|
+
let failed = 0;
|
|
95
|
+
const campaignNames = [];
|
|
96
|
+
for (const campaign of offerwallCampaigns) {
|
|
97
|
+
try {
|
|
98
|
+
// Check if stream with this offer already exists
|
|
99
|
+
const existingStreams = await getStreamsByCampaignId(campaign.id);
|
|
100
|
+
const streamExists = existingStreams.some(stream => stream.offers?.some(o => o.offer_id === keitaroOffer.id));
|
|
101
|
+
if (streamExists) {
|
|
102
|
+
console.log(`Stream with offer ${keitaroOffer.id} already exists in campaign ${campaign.name}`);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// Create a new stream with the offer
|
|
106
|
+
await createStream(campaign.id, {
|
|
107
|
+
name: `${offer.geo} - ${offer.caption} (${offer.name})`,
|
|
108
|
+
type: 'regular',
|
|
109
|
+
action_type: 'http',
|
|
110
|
+
weight: 100,
|
|
111
|
+
state: offer.hidden ? 'disabled' : 'active',
|
|
112
|
+
offers: [{
|
|
113
|
+
offer_id: keitaroOffer.id,
|
|
114
|
+
share: 100,
|
|
115
|
+
state: 'active'
|
|
116
|
+
}],
|
|
117
|
+
filters: [{
|
|
118
|
+
name: 'country',
|
|
119
|
+
mode: 'accept',
|
|
120
|
+
payload: [offer.geo]
|
|
121
|
+
}]
|
|
122
|
+
});
|
|
123
|
+
success++;
|
|
124
|
+
campaignNames.push(campaign.name);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error(`Failed to add offer to campaign ${campaign.name}:`, error);
|
|
128
|
+
failed++;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { keitaroOfferId: keitaroOffer.id, success, failed, campaigns: campaignNames };
|
|
132
|
+
}
|
|
42
133
|
// Generate random alias for campaigns
|
|
43
134
|
function generateAlias() {
|
|
44
135
|
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
@@ -152,12 +243,16 @@ exports.KeitaroService = {
|
|
|
152
243
|
createCampaign,
|
|
153
244
|
updateCampaign,
|
|
154
245
|
cloneCampaignForApp,
|
|
246
|
+
getOfferwallCampaigns,
|
|
155
247
|
// Stream operations
|
|
156
248
|
getStreamsByCampaignId,
|
|
249
|
+
createStream,
|
|
157
250
|
// Domain operations
|
|
158
251
|
getDomains,
|
|
159
252
|
// Offer operations
|
|
160
253
|
getAllOffers,
|
|
254
|
+
createOfferInKeitaro,
|
|
255
|
+
addOfferToKeitaro,
|
|
161
256
|
// Utilities
|
|
162
257
|
generateAlias,
|
|
163
258
|
campaignToKeitaroData,
|
package/package.json
CHANGED
package/src/app/app.ts
CHANGED
|
@@ -178,7 +178,8 @@ export interface IDomainParams {
|
|
|
178
178
|
export enum AppStatus {
|
|
179
179
|
ARCHIVED = "ARCHIVED",
|
|
180
180
|
IN_DEVELOPMENT = "IN_DEVELOPMENT",
|
|
181
|
-
READY = "READY"
|
|
181
|
+
READY = "READY",
|
|
182
|
+
DISABLED = "DISABLED"
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
export interface IKeitaroDirectTrackingParams {
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export interface IKeitaroOffer {
|
|
2
2
|
id: number;
|
|
3
|
-
campaign_id
|
|
3
|
+
campaign_id?: number;
|
|
4
4
|
name: string;
|
|
5
|
-
url
|
|
6
|
-
country
|
|
5
|
+
url?: string;
|
|
6
|
+
country?: string | string[];
|
|
7
|
+
group_id?: number;
|
|
8
|
+
action_type?: string;
|
|
9
|
+
action_payload?: string;
|
|
10
|
+
affiliate_network_id?: number;
|
|
11
|
+
payout_value?: number;
|
|
12
|
+
payout_currency?: string;
|
|
13
|
+
payout_type?: string;
|
|
14
|
+
state?: string;
|
|
15
|
+
offer_type?: string;
|
|
16
|
+
payout_auto?: boolean;
|
|
17
|
+
payout_upsell?: boolean;
|
|
7
18
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IKeitaroStream } from "../../keitaro/keitaro-stream";
|
|
2
|
-
import { IOffer } from "../../offers/offer"
|
|
2
|
+
import { IOffer } from "../../offers/offer";
|
|
3
3
|
import keitaroApi from "./http"
|
|
4
4
|
import { IKeitaroCampaign } from "../../keitaro/keitaro-campaign";
|
|
5
5
|
import { IKeitaroDomain } from "../../keitaro/keitaro-domain";
|
|
@@ -59,6 +59,115 @@ async function getAllOffers(): Promise<IKeitaroOffer[]> {
|
|
|
59
59
|
return offers
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Create offer in Keitaro from our IOffer
|
|
64
|
+
* @param offer - Our internal IOffer object
|
|
65
|
+
* @returns Keitaro offer with ID
|
|
66
|
+
*/
|
|
67
|
+
async function createOfferInKeitaro(offer: IOffer): Promise<IKeitaroOffer> {
|
|
68
|
+
const payload = {
|
|
69
|
+
name: `${offer.caption} ${offer.geo} (${offer.name})`,
|
|
70
|
+
group_id: DEFAULT_OFFERS_GROUP_ID,
|
|
71
|
+
action_type: 'http',
|
|
72
|
+
action_payload: offer.link,
|
|
73
|
+
affiliate_network_id: 0, // Can be set if we have partner mapping
|
|
74
|
+
payout_value: 0,
|
|
75
|
+
payout_currency: 'USD',
|
|
76
|
+
payout_type: 'CPA',
|
|
77
|
+
state: offer.hidden ? 'disabled' : 'active',
|
|
78
|
+
country: [offer.geo],
|
|
79
|
+
offer_type: 'external',
|
|
80
|
+
payout_auto: true,
|
|
81
|
+
payout_upsell: true,
|
|
82
|
+
};
|
|
83
|
+
const { data: keitaroOffer } = await keitaroApi.post<IKeitaroOffer>('offers', payload);
|
|
84
|
+
return keitaroOffer;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Stream operations
|
|
88
|
+
async function createStream(campaignId: number, streamData: Partial<IKeitaroStream>): Promise<IKeitaroStream> {
|
|
89
|
+
const { data: stream } = await keitaroApi.post<IKeitaroStream>('streams', {
|
|
90
|
+
...streamData,
|
|
91
|
+
campaign_id: campaignId
|
|
92
|
+
});
|
|
93
|
+
return stream;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get all offerwall campaigns (campaigns with [◈] prefix in group 106)
|
|
98
|
+
*/
|
|
99
|
+
async function getOfferwallCampaigns(): Promise<IKeitaroCampaign[]> {
|
|
100
|
+
const allCampaigns = await getAllCampaigns();
|
|
101
|
+
// Offerwall campaigns have [◈] in their name and are in group 106
|
|
102
|
+
return allCampaigns.filter(c =>
|
|
103
|
+
c.name.includes('[◈]') && c.group_id === DEFAULT_CAMPAIGNS_GROUP_ID
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Add our IOffer to Keitaro and distribute to all offerwall campaigns
|
|
109
|
+
* @param offer - Our internal IOffer object
|
|
110
|
+
* @returns Result with Keitaro offer ID and distribution stats
|
|
111
|
+
*/
|
|
112
|
+
async function addOfferToKeitaro(offer: IOffer): Promise<{
|
|
113
|
+
keitaroOfferId: number;
|
|
114
|
+
success: number;
|
|
115
|
+
failed: number;
|
|
116
|
+
campaigns: string[]
|
|
117
|
+
}> {
|
|
118
|
+
// First, create the offer in Keitaro
|
|
119
|
+
const keitaroOffer = await createOfferInKeitaro(offer);
|
|
120
|
+
console.log(`Created Keitaro offer #${keitaroOffer.id}: ${keitaroOffer.name}`);
|
|
121
|
+
|
|
122
|
+
// Then distribute to all offerwall campaigns
|
|
123
|
+
const offerwallCampaigns = await getOfferwallCampaigns();
|
|
124
|
+
let success = 0;
|
|
125
|
+
let failed = 0;
|
|
126
|
+
const campaignNames: string[] = [];
|
|
127
|
+
|
|
128
|
+
for (const campaign of offerwallCampaigns) {
|
|
129
|
+
try {
|
|
130
|
+
// Check if stream with this offer already exists
|
|
131
|
+
const existingStreams = await getStreamsByCampaignId(campaign.id);
|
|
132
|
+
const streamExists = existingStreams.some(stream =>
|
|
133
|
+
stream.offers?.some(o => o.offer_id === keitaroOffer.id)
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
if (streamExists) {
|
|
137
|
+
console.log(`Stream with offer ${keitaroOffer.id} already exists in campaign ${campaign.name}`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Create a new stream with the offer
|
|
142
|
+
await createStream(campaign.id, {
|
|
143
|
+
name: `${offer.geo} - ${offer.caption} (${offer.name})`,
|
|
144
|
+
type: 'regular',
|
|
145
|
+
action_type: 'http',
|
|
146
|
+
weight: 100,
|
|
147
|
+
state: offer.hidden ? 'disabled' : 'active',
|
|
148
|
+
offers: [{
|
|
149
|
+
offer_id: keitaroOffer.id,
|
|
150
|
+
share: 100,
|
|
151
|
+
state: 'active'
|
|
152
|
+
}],
|
|
153
|
+
filters: [{
|
|
154
|
+
name: 'country',
|
|
155
|
+
mode: 'accept',
|
|
156
|
+
payload: [offer.geo]
|
|
157
|
+
}]
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
success++;
|
|
161
|
+
campaignNames.push(campaign.name);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(`Failed to add offer to campaign ${campaign.name}:`, error);
|
|
164
|
+
failed++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return { keitaroOfferId: keitaroOffer.id, success, failed, campaigns: campaignNames };
|
|
169
|
+
}
|
|
170
|
+
|
|
62
171
|
// Generate random alias for campaigns
|
|
63
172
|
function generateAlias(): string {
|
|
64
173
|
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
@@ -191,15 +300,19 @@ export const KeitaroService = {
|
|
|
191
300
|
createCampaign,
|
|
192
301
|
updateCampaign,
|
|
193
302
|
cloneCampaignForApp,
|
|
303
|
+
getOfferwallCampaigns,
|
|
194
304
|
|
|
195
305
|
// Stream operations
|
|
196
306
|
getStreamsByCampaignId,
|
|
307
|
+
createStream,
|
|
197
308
|
|
|
198
309
|
// Domain operations
|
|
199
310
|
getDomains,
|
|
200
311
|
|
|
201
312
|
// Offer operations
|
|
202
313
|
getAllOffers,
|
|
314
|
+
createOfferInKeitaro,
|
|
315
|
+
addOfferToKeitaro,
|
|
203
316
|
|
|
204
317
|
// Utilities
|
|
205
318
|
generateAlias,
|