adapty 0.3.0 → 0.4.0
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/README.md +134 -5
- package/dist/commands/asa/ad-groups/create.d.ts +22 -0
- package/dist/commands/asa/ad-groups/create.js +54 -0
- package/dist/commands/asa/ad-groups/get.d.ts +11 -0
- package/dist/commands/asa/ad-groups/get.js +21 -0
- package/dist/commands/asa/ad-groups/list.d.ts +18 -0
- package/dist/commands/asa/ad-groups/list.js +24 -0
- package/dist/commands/asa/ad-groups/update.d.ts +23 -0
- package/dist/commands/asa/ad-groups/update.js +62 -0
- package/dist/commands/asa/ads/create.d.ts +16 -0
- package/dist/commands/asa/ads/create.js +41 -0
- package/dist/commands/asa/ads/get.d.ts +11 -0
- package/dist/commands/asa/ads/get.js +21 -0
- package/dist/commands/asa/ads/list.d.ts +18 -0
- package/dist/commands/asa/ads/list.js +24 -0
- package/dist/commands/asa/ads/update.d.ts +17 -0
- package/dist/commands/asa/ads/update.js +44 -0
- package/dist/commands/asa/apps/list.d.ts +13 -0
- package/dist/commands/asa/apps/list.js +18 -0
- package/dist/commands/asa/automations/create.d.ts +16 -0
- package/dist/commands/asa/automations/create.js +60 -0
- package/dist/commands/asa/automations/get.d.ts +11 -0
- package/dist/commands/asa/automations/get.js +21 -0
- package/dist/commands/asa/automations/list.d.ts +13 -0
- package/dist/commands/asa/automations/list.js +18 -0
- package/dist/commands/asa/automations/run.d.ts +16 -0
- package/dist/commands/asa/automations/run.js +41 -0
- package/dist/commands/asa/automations/runs.d.ts +16 -0
- package/dist/commands/asa/automations/runs.js +24 -0
- package/dist/commands/asa/automations/update.d.ts +21 -0
- package/dist/commands/asa/automations/update.js +73 -0
- package/dist/commands/asa/campaigns/create.d.ts +25 -0
- package/dist/commands/asa/campaigns/create.js +67 -0
- package/dist/commands/asa/campaigns/get.d.ts +11 -0
- package/dist/commands/asa/campaigns/get.js +21 -0
- package/dist/commands/asa/campaigns/list.d.ts +17 -0
- package/dist/commands/asa/campaigns/list.js +24 -0
- package/dist/commands/asa/campaigns/update.d.ts +23 -0
- package/dist/commands/asa/campaigns/update.js +66 -0
- package/dist/commands/asa/competitors/summary.d.ts +11 -0
- package/dist/commands/asa/competitors/summary.js +56 -0
- package/dist/commands/asa/connect.d.ts +12 -0
- package/dist/commands/asa/connect.js +39 -0
- package/dist/commands/asa/creatives/list.d.ts +15 -0
- package/dist/commands/asa/creatives/list.js +24 -0
- package/dist/commands/asa/keywords/add.d.ts +20 -0
- package/dist/commands/asa/keywords/add.js +73 -0
- package/dist/commands/asa/keywords/list.d.ts +19 -0
- package/dist/commands/asa/keywords/list.js +24 -0
- package/dist/commands/asa/keywords/update.d.ts +21 -0
- package/dist/commands/asa/keywords/update.js +64 -0
- package/dist/commands/asa/metrics/index.d.ts +21 -0
- package/dist/commands/asa/metrics/index.js +68 -0
- package/dist/commands/asa/metrics/overview.d.ts +15 -0
- package/dist/commands/asa/metrics/overview.js +51 -0
- package/dist/commands/asa/negative-keywords/add.d.ts +18 -0
- package/dist/commands/asa/negative-keywords/add.js +70 -0
- package/dist/commands/asa/negative-keywords/list.d.ts +19 -0
- package/dist/commands/asa/negative-keywords/list.js +29 -0
- package/dist/commands/asa/orgs/list.d.ts +13 -0
- package/dist/commands/asa/orgs/list.js +18 -0
- package/dist/commands/asa/product-pages/list.d.ts +15 -0
- package/dist/commands/asa/product-pages/list.js +24 -0
- package/dist/commands/asa/product-pages/sync.d.ts +13 -0
- package/dist/commands/asa/product-pages/sync.js +28 -0
- package/dist/commands/asa/search-terms/list.d.ts +20 -0
- package/dist/commands/asa/search-terms/list.js +25 -0
- package/dist/commands/asa/whoami.d.ts +8 -0
- package/dist/commands/asa/whoami.js +22 -0
- package/dist/lib/api-client.d.ts +15 -3
- package/dist/lib/api-client.js +49 -17
- package/dist/lib/asa-client.d.ts +16 -0
- package/dist/lib/asa-client.js +46 -0
- package/dist/lib/asa-confirm.d.ts +18 -0
- package/dist/lib/asa-confirm.js +41 -0
- package/dist/lib/asa-flags.d.ts +88 -0
- package/dist/lib/asa-flags.js +137 -0
- package/dist/lib/asa-schemas.d.ts +287 -0
- package/dist/lib/asa-schemas.js +1 -0
- package/dist/lib/errors.d.ts +25 -2
- package/dist/lib/errors.js +48 -7
- package/dist/lib/output.js +45 -15
- package/oclif.manifest.json +2802 -157
- package/package.json +40 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { describeListedError } from './errors.js';
|
|
3
|
+
import { isValidUuid } from './flags.js';
|
|
4
|
+
const DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
5
|
+
const MONEY_REGEX = /^\d+(\.\d{1,6})?$/;
|
|
6
|
+
export const MAX_BULK_ITEMS = 100;
|
|
7
|
+
export const MAX_BY_DAYS = 16;
|
|
8
|
+
export const ASA_METRIC_ENTITIES = ['ad', 'ad-group', 'campaign', 'keyword'];
|
|
9
|
+
export const ASA_GROUP_BY_DIMENSIONS = ['country', 'day', 'month', 'quarter', 'week', 'year'];
|
|
10
|
+
export const asaPaginationFlags = {
|
|
11
|
+
page: Flags.integer({
|
|
12
|
+
default: 1,
|
|
13
|
+
description: 'Page number',
|
|
14
|
+
min: 1,
|
|
15
|
+
}),
|
|
16
|
+
'page-size': Flags.integer({
|
|
17
|
+
default: 100,
|
|
18
|
+
description: 'Items per page (max 1000); prefer one big page over a pagination loop',
|
|
19
|
+
max: 1000,
|
|
20
|
+
min: 1,
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
export const byDaysFlag = {
|
|
24
|
+
'by-days': Flags.integer({
|
|
25
|
+
description: 'Renewal window in days for cohort metrics, repeatable; omit for the dashboard defaults',
|
|
26
|
+
multiple: true,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
async function parseDate(input) {
|
|
30
|
+
if (!DATE_REGEX.test(input))
|
|
31
|
+
throw new Error('Dates must be written as YYYY-MM-DD.');
|
|
32
|
+
return input;
|
|
33
|
+
}
|
|
34
|
+
export const periodFlags = {
|
|
35
|
+
'date-from': Flags.string({
|
|
36
|
+
description: 'Start of the reporting period (YYYY-MM-DD), defaults to today',
|
|
37
|
+
parse: parseDate,
|
|
38
|
+
}),
|
|
39
|
+
'date-to': Flags.string({
|
|
40
|
+
description: 'End of the reporting period (YYYY-MM-DD), defaults to today',
|
|
41
|
+
parse: parseDate,
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
async function parseId(input) {
|
|
45
|
+
if (!isValidUuid(input))
|
|
46
|
+
throw new Error('Ids are the UUIDs printed by the matching list command.');
|
|
47
|
+
return input;
|
|
48
|
+
}
|
|
49
|
+
function idFilter(entity) {
|
|
50
|
+
return Flags.string({ description: `Keep only rows in this ${entity}; repeatable`, multiple: true, parse: parseId });
|
|
51
|
+
}
|
|
52
|
+
const searchFilter = { search: Flags.string({ description: 'Case-insensitive substring match on the name' }) };
|
|
53
|
+
export const assetScopeFlags = {
|
|
54
|
+
app: idFilter('app'),
|
|
55
|
+
'campaign-group': idFilter('campaign group'),
|
|
56
|
+
};
|
|
57
|
+
export const orgScopeFlags = { ...assetScopeFlags, ...searchFilter };
|
|
58
|
+
export const campaignScopeFlags = { ...orgScopeFlags, campaign: idFilter('campaign') };
|
|
59
|
+
export const adGroupScopeFlags = { ...campaignScopeFlags, 'ad-group': idFilter('ad group') };
|
|
60
|
+
export const adScopeFlags = {
|
|
61
|
+
'ad-group': idFilter('ad group'),
|
|
62
|
+
campaign: idFilter('campaign'),
|
|
63
|
+
'campaign-group': idFilter('campaign group'),
|
|
64
|
+
...searchFilter,
|
|
65
|
+
};
|
|
66
|
+
export const statusFilter = (options) => ({
|
|
67
|
+
status: Flags.string({ description: 'Keep only rows in this state', options }),
|
|
68
|
+
});
|
|
69
|
+
export function scopeParams(flags) {
|
|
70
|
+
return {
|
|
71
|
+
ad_group_id: flags['ad-group'],
|
|
72
|
+
app_id: flags.app,
|
|
73
|
+
campaign_group_id: flags['campaign-group'],
|
|
74
|
+
campaign_id: flags.campaign,
|
|
75
|
+
search: flags.search,
|
|
76
|
+
status: flags.status,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export const scheduleFlags = {
|
|
80
|
+
'end-time': Flags.string({ description: 'Schedule end (YYYY-MM-DD)', parse: parseDate }),
|
|
81
|
+
'start-time': Flags.string({ description: 'Schedule start (YYYY-MM-DD), defaults to today', parse: parseDate }),
|
|
82
|
+
};
|
|
83
|
+
export const pricingModelFlag = {
|
|
84
|
+
'pricing-model': Flags.string({
|
|
85
|
+
default: 'CPC',
|
|
86
|
+
description: 'Pricing model; Apple requires one on every ad group',
|
|
87
|
+
options: ['CPC', 'CPM'],
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
90
|
+
export function startOfDayUtc(date) {
|
|
91
|
+
return date === undefined ? undefined : `${date}T00:00:00Z`;
|
|
92
|
+
}
|
|
93
|
+
export function todayUtc() {
|
|
94
|
+
return new Date().toISOString().slice(0, 10);
|
|
95
|
+
}
|
|
96
|
+
export function periodParams(flags) {
|
|
97
|
+
const params = {};
|
|
98
|
+
if (flags['date-from'])
|
|
99
|
+
params.date_from = flags['date-from'];
|
|
100
|
+
if (flags['date-to'])
|
|
101
|
+
params.date_to = flags['date-to'];
|
|
102
|
+
return params;
|
|
103
|
+
}
|
|
104
|
+
async function parseMoney(input) {
|
|
105
|
+
if (!MONEY_REGEX.test(input))
|
|
106
|
+
throw new Error('Amounts must be plain numbers, e.g. 50 or 12.50.');
|
|
107
|
+
return input;
|
|
108
|
+
}
|
|
109
|
+
export function moneyFlag(description, opts = {}) {
|
|
110
|
+
return Flags.string({
|
|
111
|
+
description: `${description} (amount, e.g. 50 or 12.50)`,
|
|
112
|
+
parse: parseMoney,
|
|
113
|
+
required: opts.required,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
export const currencyFlag = {
|
|
117
|
+
currency: Flags.string({ default: 'USD', description: 'Currency code for the amounts in this call' }),
|
|
118
|
+
};
|
|
119
|
+
export const idempotencyFlags = {
|
|
120
|
+
'idempotency-key': Flags.string({
|
|
121
|
+
description: 'Idempotency key for this write; re-running with the same key replays the stored result instead of applying twice',
|
|
122
|
+
}),
|
|
123
|
+
};
|
|
124
|
+
export function money(amount, currency) {
|
|
125
|
+
return amount === undefined ? undefined : { amount, currency };
|
|
126
|
+
}
|
|
127
|
+
export function reportBulkOutcome({ applied, errors, isValidationFailure, kind }, log) {
|
|
128
|
+
if (isValidationFailure) {
|
|
129
|
+
log(`Nothing was applied: the batch failed validation before Apple was called.`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
log(`${applied.length} ${kind} applied, ${errors.length} rejected.`);
|
|
133
|
+
}
|
|
134
|
+
for (const error of errors) {
|
|
135
|
+
log(` ${describeListedError(error).text}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
export type AsaAccessSource = 'allowlist' | 'legacy' | 'none' | 'payg';
|
|
2
|
+
export type AsaAppleCredentialsStatus = 'active' | 'expired' | 'invalid' | 'unset';
|
|
3
|
+
export type AsaKeywordMatchType = 'BROAD' | 'EXACT';
|
|
4
|
+
export type AsaKeywordStatus = 'ACTIVE' | 'PAUSED';
|
|
5
|
+
export type AsaStatus = 'ENABLED' | 'PAUSED';
|
|
6
|
+
export type AsaNegativeKeywordScope = 'AD_GROUP' | 'ALL_CAMPAIGN_AD_GROUPS' | 'CAMPAIGN';
|
|
7
|
+
export interface AsaMoney {
|
|
8
|
+
amount: string;
|
|
9
|
+
currency: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AsaMetricsDTO {
|
|
12
|
+
avg_cpm: string;
|
|
13
|
+
avg_cpt: string;
|
|
14
|
+
impressions: number;
|
|
15
|
+
ipm: string;
|
|
16
|
+
local_spend: string;
|
|
17
|
+
tap_install_cpi: string;
|
|
18
|
+
tap_install_rate: string;
|
|
19
|
+
tap_installs: number;
|
|
20
|
+
tap_new_downloads: number;
|
|
21
|
+
tap_redownloads: number;
|
|
22
|
+
taps: number;
|
|
23
|
+
total_avg_cpi: string;
|
|
24
|
+
total_install_rate: string;
|
|
25
|
+
total_installs: number;
|
|
26
|
+
total_new_downloads: number;
|
|
27
|
+
total_redownloads: number;
|
|
28
|
+
ttr: string;
|
|
29
|
+
view_installs: number;
|
|
30
|
+
view_new_downloads: number;
|
|
31
|
+
view_redownloads: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AsaMeDTO {
|
|
34
|
+
access_source: AsaAccessSource;
|
|
35
|
+
apple_credentials_status: AsaAppleCredentialsStatus;
|
|
36
|
+
company_id: string;
|
|
37
|
+
}
|
|
38
|
+
export interface AsaAppleOAuthDTO {
|
|
39
|
+
auth_url: string;
|
|
40
|
+
}
|
|
41
|
+
export interface AsaAppDTO {
|
|
42
|
+
adam_id: number;
|
|
43
|
+
bundle_id: null | string;
|
|
44
|
+
campaign_group_ids: string[];
|
|
45
|
+
country_or_region_codes: string[];
|
|
46
|
+
developer_name: null | string;
|
|
47
|
+
internal_id: string;
|
|
48
|
+
last_synced_at: string;
|
|
49
|
+
name: string;
|
|
50
|
+
}
|
|
51
|
+
export interface AsaCampaignGroupDTO {
|
|
52
|
+
currency: string;
|
|
53
|
+
internal_id: string;
|
|
54
|
+
last_synced_at: string;
|
|
55
|
+
org_id: number;
|
|
56
|
+
org_name: string;
|
|
57
|
+
parent_org_id: number;
|
|
58
|
+
time_zone: string;
|
|
59
|
+
}
|
|
60
|
+
export interface AsaCampaignDTO {
|
|
61
|
+
ad_channel_type: string;
|
|
62
|
+
adam_id: number;
|
|
63
|
+
app_id: string;
|
|
64
|
+
bidding_strategy: null | string;
|
|
65
|
+
billing_event: string;
|
|
66
|
+
budget_amount: AsaMoney | null;
|
|
67
|
+
campaign_group_id: string;
|
|
68
|
+
campaign_id: number;
|
|
69
|
+
countries_or_regions: string[];
|
|
70
|
+
daily_budget_amount: AsaMoney | null;
|
|
71
|
+
end_time: null | string;
|
|
72
|
+
internal_id: string;
|
|
73
|
+
name: string;
|
|
74
|
+
org_id: number;
|
|
75
|
+
start_time: null | string;
|
|
76
|
+
status: AsaStatus;
|
|
77
|
+
supply_sources: string[];
|
|
78
|
+
target_cpa: AsaMoney | null;
|
|
79
|
+
}
|
|
80
|
+
export interface AsaAdGroupDTO {
|
|
81
|
+
ad_group_id: number;
|
|
82
|
+
app_id: string;
|
|
83
|
+
automated_keywords_opt_in: boolean | null;
|
|
84
|
+
bidding_strategy: null | string;
|
|
85
|
+
campaign_group_id: string;
|
|
86
|
+
campaign_id: string;
|
|
87
|
+
cpa_goal: AsaMoney | null;
|
|
88
|
+
default_bid_amount: AsaMoney;
|
|
89
|
+
end_time: null | string;
|
|
90
|
+
internal_id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
payment_model: null | string;
|
|
93
|
+
pricing_model: null | string;
|
|
94
|
+
start_time: null | string;
|
|
95
|
+
status: AsaStatus | null;
|
|
96
|
+
target_cpa: AsaMoney | null;
|
|
97
|
+
}
|
|
98
|
+
export interface AsaKeywordDTO {
|
|
99
|
+
ad_group_id: string;
|
|
100
|
+
app_id: string;
|
|
101
|
+
bid_amount: AsaMoney;
|
|
102
|
+
campaign_group_id: string;
|
|
103
|
+
campaign_id: string;
|
|
104
|
+
creation_time: null | string;
|
|
105
|
+
internal_id: string;
|
|
106
|
+
keyword_id: number;
|
|
107
|
+
match_type: AsaKeywordMatchType;
|
|
108
|
+
status: AsaKeywordStatus | null;
|
|
109
|
+
text: string;
|
|
110
|
+
}
|
|
111
|
+
export interface AsaSearchTermDTO {
|
|
112
|
+
ad_group_id: string;
|
|
113
|
+
app_id: string;
|
|
114
|
+
campaign_group_id: string;
|
|
115
|
+
campaign_id: string;
|
|
116
|
+
country_or_region: string;
|
|
117
|
+
keyword_id: null | string;
|
|
118
|
+
match_type: AsaKeywordMatchType | null;
|
|
119
|
+
metrics: AsaMetricsDTO;
|
|
120
|
+
rank: null | number;
|
|
121
|
+
search_popularity: null | number;
|
|
122
|
+
source: null | string;
|
|
123
|
+
text: null | string;
|
|
124
|
+
}
|
|
125
|
+
export interface AsaNegativeKeywordDTO {
|
|
126
|
+
ad_group_id: null | string;
|
|
127
|
+
ad_group_name: null | string;
|
|
128
|
+
campaign_id: string;
|
|
129
|
+
campaign_name: null | string;
|
|
130
|
+
internal_id: string;
|
|
131
|
+
last_synced_at: string;
|
|
132
|
+
match_type: AsaKeywordMatchType;
|
|
133
|
+
status: AsaKeywordStatus;
|
|
134
|
+
text: string;
|
|
135
|
+
}
|
|
136
|
+
export interface AsaCreativeDTO {
|
|
137
|
+
adam_id: number;
|
|
138
|
+
app_id: string;
|
|
139
|
+
campaign_group_id: string;
|
|
140
|
+
creative_id: number;
|
|
141
|
+
internal_id: string;
|
|
142
|
+
name: string;
|
|
143
|
+
org_id: number;
|
|
144
|
+
product_page_id: null | string;
|
|
145
|
+
state: string;
|
|
146
|
+
state_reasons: string[];
|
|
147
|
+
type: string;
|
|
148
|
+
}
|
|
149
|
+
export interface AsaProductPageDTO {
|
|
150
|
+
adam_id: number;
|
|
151
|
+
app_id: string;
|
|
152
|
+
deep_link: null | string;
|
|
153
|
+
external_id: number;
|
|
154
|
+
internal_id: string;
|
|
155
|
+
language_codes: string[];
|
|
156
|
+
languages: string[];
|
|
157
|
+
last_synced_at: string;
|
|
158
|
+
name: string;
|
|
159
|
+
state: string;
|
|
160
|
+
}
|
|
161
|
+
export interface AsaAdDTO {
|
|
162
|
+
ad_group_id: string;
|
|
163
|
+
ad_group_name: null | string;
|
|
164
|
+
ad_id: number;
|
|
165
|
+
app_id: null | string;
|
|
166
|
+
campaign_group_id: string;
|
|
167
|
+
campaign_id: string;
|
|
168
|
+
creation_time: null | string;
|
|
169
|
+
creative_id: null | string;
|
|
170
|
+
creative_type: string;
|
|
171
|
+
internal_id: string;
|
|
172
|
+
last_synced_at: string;
|
|
173
|
+
name: string;
|
|
174
|
+
product_page_id: null | string;
|
|
175
|
+
product_page_name: null | string;
|
|
176
|
+
serving_state_reasons: string[];
|
|
177
|
+
serving_status: string;
|
|
178
|
+
status: AsaStatus;
|
|
179
|
+
}
|
|
180
|
+
export interface AsaAutomationDTO {
|
|
181
|
+
actions: unknown[];
|
|
182
|
+
apply_to: unknown[];
|
|
183
|
+
conditions: unknown[];
|
|
184
|
+
created_at: string;
|
|
185
|
+
date_last_run: null | string;
|
|
186
|
+
date_next_run: null | string;
|
|
187
|
+
id: string;
|
|
188
|
+
name: string;
|
|
189
|
+
operate_with: string;
|
|
190
|
+
rba_type: string;
|
|
191
|
+
run_frequency: Record<string, unknown>;
|
|
192
|
+
status: number;
|
|
193
|
+
updated_at: string;
|
|
194
|
+
}
|
|
195
|
+
export interface AsaAutomationRunDTO {
|
|
196
|
+
[key: string]: unknown;
|
|
197
|
+
id?: string;
|
|
198
|
+
}
|
|
199
|
+
export interface AsaAutomationRunEnqueuedDTO {
|
|
200
|
+
automation_id: string;
|
|
201
|
+
dry_run: boolean;
|
|
202
|
+
run_id: null | string;
|
|
203
|
+
}
|
|
204
|
+
export interface AsaProductPageSyncDTO {
|
|
205
|
+
accepted_at: string;
|
|
206
|
+
message: string;
|
|
207
|
+
org_targets: number;
|
|
208
|
+
replayed: boolean;
|
|
209
|
+
state: string;
|
|
210
|
+
sync_id: string;
|
|
211
|
+
}
|
|
212
|
+
export interface AsaCompetitorTopAppDTO {
|
|
213
|
+
adamId: number;
|
|
214
|
+
avgSov: string;
|
|
215
|
+
countries: string[];
|
|
216
|
+
iconUrl: null | string;
|
|
217
|
+
name: null | string;
|
|
218
|
+
termsCount: number;
|
|
219
|
+
}
|
|
220
|
+
export interface AsaCompetitorContestedTermDTO {
|
|
221
|
+
competitorCount: number;
|
|
222
|
+
maxSov: string;
|
|
223
|
+
term: string;
|
|
224
|
+
}
|
|
225
|
+
export interface AsaCompetitorsSummaryTotalDTO {
|
|
226
|
+
competitorsCount: number;
|
|
227
|
+
countriesAsaCount: number;
|
|
228
|
+
countriesWithAsaTerms: number;
|
|
229
|
+
mostContestedTerms: AsaCompetitorContestedTermDTO[];
|
|
230
|
+
topAppsByPerformance: AsaCompetitorTopAppDTO[];
|
|
231
|
+
totalUniqueTerms: number;
|
|
232
|
+
}
|
|
233
|
+
export interface AsaCompetitorAppTermsDTO {
|
|
234
|
+
adamId: number;
|
|
235
|
+
countries: Record<string, {
|
|
236
|
+
sov: string;
|
|
237
|
+
term: string;
|
|
238
|
+
}[]>;
|
|
239
|
+
iconUrl: null | string;
|
|
240
|
+
name: null | string;
|
|
241
|
+
}
|
|
242
|
+
export interface AsaCompetitorsSummaryDTO {
|
|
243
|
+
byApps: AsaCompetitorAppTermsDTO[];
|
|
244
|
+
total: AsaCompetitorsSummaryTotalDTO;
|
|
245
|
+
}
|
|
246
|
+
export interface AsaMutationError {
|
|
247
|
+
apple_error_code?: null | string;
|
|
248
|
+
apple_error_message?: null | string;
|
|
249
|
+
entity_type?: string;
|
|
250
|
+
input_ref?: null | number;
|
|
251
|
+
operation?: string;
|
|
252
|
+
retryable?: boolean;
|
|
253
|
+
validation_error_code?: string;
|
|
254
|
+
validation_error_message?: string;
|
|
255
|
+
}
|
|
256
|
+
export interface AsaCampaignMutationDTO {
|
|
257
|
+
campaign: AsaCampaignMutationEntity | null;
|
|
258
|
+
errors: AsaMutationError[];
|
|
259
|
+
}
|
|
260
|
+
export interface AsaCampaignMutationEntity {
|
|
261
|
+
campaign_group_id: string;
|
|
262
|
+
campaign_id: number;
|
|
263
|
+
internal_id: string;
|
|
264
|
+
name: string;
|
|
265
|
+
status: AsaStatus;
|
|
266
|
+
}
|
|
267
|
+
export interface AsaAdGroupMutationDTO {
|
|
268
|
+
ad_group: null | Record<string, unknown>;
|
|
269
|
+
errors: AsaMutationError[];
|
|
270
|
+
}
|
|
271
|
+
export interface AsaAdMutationDTO {
|
|
272
|
+
ad: AsaAdDTO | null;
|
|
273
|
+
errors: AsaMutationError[];
|
|
274
|
+
}
|
|
275
|
+
export interface AsaKeywordMutationDTO {
|
|
276
|
+
errors: AsaMutationError[];
|
|
277
|
+
is_validation_failure: boolean;
|
|
278
|
+
keywords: Record<string, unknown>[];
|
|
279
|
+
}
|
|
280
|
+
export interface AsaNegativeKeywordMutationDTO {
|
|
281
|
+
errors: AsaMutationError[];
|
|
282
|
+
is_validation_failure: boolean;
|
|
283
|
+
negative_keywords: Record<string, unknown>[];
|
|
284
|
+
}
|
|
285
|
+
export interface AsaAutomationMutationDTO {
|
|
286
|
+
automation: AsaAutomationDTO | null;
|
|
287
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/lib/errors.d.ts
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
export interface ApiErrorBody {
|
|
2
|
+
detail?: string;
|
|
2
3
|
error?: string;
|
|
3
4
|
error_code?: string;
|
|
4
5
|
errors?: Record<string, string[]>;
|
|
6
|
+
retry_after_seconds?: number;
|
|
5
7
|
status_code?: number;
|
|
6
8
|
}
|
|
9
|
+
export type ApiErrorFormat = 'asa' | 'developer';
|
|
10
|
+
export interface ApiErrorOptions {
|
|
11
|
+
detail?: string;
|
|
12
|
+
retryAfterSeconds?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ListedError {
|
|
15
|
+
apple_error_code?: null | string;
|
|
16
|
+
apple_error_message?: null | string;
|
|
17
|
+
error_code?: string;
|
|
18
|
+
field_name?: null | string;
|
|
19
|
+
input_ref?: null | number;
|
|
20
|
+
message?: string;
|
|
21
|
+
validation_error_code?: string;
|
|
22
|
+
validation_error_message?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function describeListedError(error: ListedError): {
|
|
25
|
+
code: string | undefined;
|
|
26
|
+
text: string;
|
|
27
|
+
};
|
|
7
28
|
export declare class ApiError extends Error {
|
|
8
29
|
statusCode: number;
|
|
9
30
|
errorCode: string;
|
|
10
31
|
fieldErrors: Record<string, string[]>;
|
|
11
|
-
|
|
32
|
+
detail?: string;
|
|
33
|
+
retryAfterSeconds?: number;
|
|
34
|
+
constructor(statusCode: number, errorCode: string, fieldErrors: Record<string, string[]>, opts?: ApiErrorOptions);
|
|
12
35
|
toHuman(): string;
|
|
13
36
|
toJSON(): ApiErrorBody;
|
|
14
37
|
}
|
|
@@ -20,4 +43,4 @@ export declare class NetworkError extends Error {
|
|
|
20
43
|
export declare class AuthRequiredError extends Error {
|
|
21
44
|
constructor();
|
|
22
45
|
}
|
|
23
|
-
export declare function parseApiError(statusCode: number, body: unknown): ApiError;
|
|
46
|
+
export declare function parseApiError(statusCode: number, body: unknown, opts?: ApiErrorOptions, format?: ApiErrorFormat): ApiError;
|
package/dist/lib/errors.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
+
export function describeListedError(error) {
|
|
2
|
+
const code = error.error_code ?? error.apple_error_code ?? error.validation_error_code ?? undefined;
|
|
3
|
+
const reason = error.message ?? error.apple_error_message ?? error.validation_error_message ?? code ?? 'rejected';
|
|
4
|
+
const position = error.input_ref === null || error.input_ref === undefined ? '' : ` (item ${error.input_ref + 1})`;
|
|
5
|
+
return { code, text: `${reason}${position}` };
|
|
6
|
+
}
|
|
1
7
|
export class ApiError extends Error {
|
|
2
8
|
statusCode;
|
|
3
9
|
errorCode;
|
|
4
10
|
fieldErrors;
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
detail;
|
|
12
|
+
retryAfterSeconds;
|
|
13
|
+
constructor(statusCode, errorCode, fieldErrors, opts = {}) {
|
|
14
|
+
super(opts.detail ?? errorCode);
|
|
7
15
|
this.statusCode = statusCode;
|
|
8
16
|
this.errorCode = errorCode;
|
|
9
17
|
this.fieldErrors = fieldErrors;
|
|
10
18
|
this.name = 'ApiError';
|
|
19
|
+
this.detail = opts.detail;
|
|
20
|
+
this.retryAfterSeconds = opts.retryAfterSeconds;
|
|
11
21
|
}
|
|
12
22
|
toHuman() {
|
|
13
23
|
const lines = [`Error: ${this.errorCode}`];
|
|
@@ -24,8 +34,10 @@ export class ApiError extends Error {
|
|
|
24
34
|
}
|
|
25
35
|
toJSON() {
|
|
26
36
|
return {
|
|
37
|
+
detail: this.detail,
|
|
27
38
|
error_code: this.errorCode,
|
|
28
39
|
errors: Object.keys(this.fieldErrors).length > 0 ? this.fieldErrors : undefined,
|
|
40
|
+
retry_after_seconds: this.retryAfterSeconds,
|
|
29
41
|
status_code: this.statusCode,
|
|
30
42
|
};
|
|
31
43
|
}
|
|
@@ -48,16 +60,45 @@ export class AuthRequiredError extends Error {
|
|
|
48
60
|
this.name = 'AuthRequiredError';
|
|
49
61
|
}
|
|
50
62
|
}
|
|
51
|
-
|
|
63
|
+
function parseListedErrors(errors, statusCode, opts) {
|
|
64
|
+
const fieldErrors = {};
|
|
65
|
+
for (const item of errors) {
|
|
66
|
+
if (item.field_name && item.message) {
|
|
67
|
+
fieldErrors[item.field_name] = [...(fieldErrors[item.field_name] ?? []), item.message];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const described = errors.map((item) => describeListedError(item));
|
|
71
|
+
const detail = described.map((item) => item.text).join('; ');
|
|
72
|
+
return new ApiError(statusCode, described[0]?.code ?? `http_${statusCode}`, fieldErrors, {
|
|
73
|
+
...opts,
|
|
74
|
+
detail: detail || undefined,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function parseApiError(statusCode, body, opts = {}, format = 'developer') {
|
|
52
78
|
if (!body || typeof body !== 'object') {
|
|
53
|
-
return new ApiError(statusCode, `http_${statusCode}`, {});
|
|
79
|
+
return new ApiError(statusCode, `http_${statusCode}`, {}, opts);
|
|
54
80
|
}
|
|
55
81
|
const parsed = body;
|
|
82
|
+
if (format === 'asa' && Array.isArray(parsed.errors) && parsed.errors.length > 0) {
|
|
83
|
+
return parseListedErrors(parsed.errors, statusCode, opts);
|
|
84
|
+
}
|
|
56
85
|
if (parsed.error_code) {
|
|
57
|
-
return new ApiError(statusCode, parsed.error_code, parsed.errors ?? {});
|
|
86
|
+
return new ApiError(statusCode, parsed.error_code, parsed.errors ?? {}, opts);
|
|
58
87
|
}
|
|
59
88
|
if (parsed.error) {
|
|
60
|
-
return new ApiError(statusCode, parsed.error, {});
|
|
89
|
+
return new ApiError(statusCode, parsed.error, {}, opts);
|
|
90
|
+
}
|
|
91
|
+
if (format === 'asa' && Array.isArray(parsed.detail)) {
|
|
92
|
+
const fieldErrors = {};
|
|
93
|
+
for (const item of parsed.detail) {
|
|
94
|
+
const field = (item.loc ?? []).slice(1).join('.') || 'body';
|
|
95
|
+
if (item.msg)
|
|
96
|
+
fieldErrors[field] = [...(fieldErrors[field] ?? []), item.msg];
|
|
97
|
+
}
|
|
98
|
+
return new ApiError(statusCode, `http_${statusCode}`, fieldErrors, opts);
|
|
99
|
+
}
|
|
100
|
+
if (format === 'asa' && typeof parsed.detail === 'string') {
|
|
101
|
+
return new ApiError(statusCode, `http_${statusCode}`, {}, { ...opts, detail: parsed.detail });
|
|
61
102
|
}
|
|
62
|
-
return new ApiError(statusCode, `http_${statusCode}`, {});
|
|
103
|
+
return new ApiError(statusCode, `http_${statusCode}`, {}, opts);
|
|
63
104
|
}
|
package/dist/lib/output.js
CHANGED
|
@@ -11,30 +11,60 @@ function formatLabel(snakeKey) {
|
|
|
11
11
|
})
|
|
12
12
|
.join(' ');
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
function isScalar(value) {
|
|
15
|
+
return typeof value !== 'object' || value === null;
|
|
16
|
+
}
|
|
17
|
+
function renderArrayItems(items, indent) {
|
|
18
|
+
const childIndent = indent + ' ';
|
|
19
|
+
const lines = [];
|
|
20
|
+
for (const item of items) {
|
|
21
|
+
if (item === undefined || item === null)
|
|
22
|
+
continue;
|
|
23
|
+
if (Array.isArray(item)) {
|
|
24
|
+
lines.push(...renderArrayItems(item, childIndent));
|
|
25
|
+
}
|
|
26
|
+
else if (isScalar(item)) {
|
|
27
|
+
lines.push(`${indent}- ${String(item)}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const rendered = renderObject(item, childIndent);
|
|
31
|
+
if (rendered.length === 0)
|
|
32
|
+
continue;
|
|
33
|
+
lines.push(`${indent}- ${rendered[0].slice(childIndent.length)}`, ...rendered.slice(1));
|
|
34
|
+
}
|
|
23
35
|
}
|
|
24
|
-
return
|
|
36
|
+
return lines;
|
|
25
37
|
}
|
|
26
|
-
|
|
38
|
+
function renderObject(data, indent) {
|
|
39
|
+
const lines = [];
|
|
27
40
|
for (const [key, value] of Object.entries(data)) {
|
|
28
41
|
if (value === undefined || value === null)
|
|
29
42
|
continue;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
43
|
+
const label = `${indent}${formatLabel(key)}:`;
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
if (value.length === 0)
|
|
46
|
+
continue;
|
|
47
|
+
if (value.every((v) => isScalar(v))) {
|
|
48
|
+
lines.push(`${label} ${value.map(String).join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
lines.push(label, ...renderArrayItems(value, indent + ' '));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (isScalar(value)) {
|
|
55
|
+
lines.push(`${label} ${String(value)}`);
|
|
33
56
|
}
|
|
34
57
|
else {
|
|
35
|
-
|
|
58
|
+
const nested = renderObject(value, indent + ' ');
|
|
59
|
+
if (nested.length > 0)
|
|
60
|
+
lines.push(label, ...nested);
|
|
36
61
|
}
|
|
37
62
|
}
|
|
63
|
+
return lines;
|
|
64
|
+
}
|
|
65
|
+
export function printResponse(data, log) {
|
|
66
|
+
for (const line of renderObject(data, ''))
|
|
67
|
+
log(line);
|
|
38
68
|
}
|
|
39
69
|
export function printList(items, log, pagination) {
|
|
40
70
|
for (const [i, item] of items.entries()) {
|