adapty 0.8.4-beta.1 → 0.8.5
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 +133 -3
- package/bin/dev.js +2 -2
- package/bin/run.js +2 -2
- package/dist/commands/access-levels/create.js +1 -1
- package/dist/commands/access-levels/list.d.ts +1 -1
- package/dist/commands/apps/create.js +9 -6
- package/dist/commands/apps/list.d.ts +1 -1
- package/dist/commands/apps/update.js +7 -4
- package/dist/commands/asa/ad-groups/create.js +9 -7
- package/dist/commands/asa/ad-groups/get.js +3 -2
- package/dist/commands/asa/ad-groups/list.d.ts +1 -1
- package/dist/commands/asa/ad-groups/list.js +1 -1
- package/dist/commands/asa/ad-groups/update.js +22 -12
- package/dist/commands/asa/ads/create.js +7 -5
- package/dist/commands/asa/ads/get.js +3 -2
- package/dist/commands/asa/ads/list.d.ts +1 -1
- package/dist/commands/asa/ads/list.js +1 -1
- package/dist/commands/asa/ads/update.js +9 -5
- package/dist/commands/asa/apps/list.d.ts +1 -1
- package/dist/commands/asa/apps/list.js +1 -1
- package/dist/commands/asa/automations/create.d.ts +9 -0
- package/dist/commands/asa/automations/create.js +26 -7
- package/dist/commands/asa/automations/get.js +3 -2
- package/dist/commands/asa/automations/list.d.ts +1 -1
- package/dist/commands/asa/automations/list.js +1 -1
- package/dist/commands/asa/automations/run.js +5 -3
- package/dist/commands/asa/automations/runs.d.ts +1 -1
- package/dist/commands/asa/automations/runs.js +4 -4
- package/dist/commands/asa/automations/update.d.ts +9 -0
- package/dist/commands/asa/automations/update.js +36 -12
- package/dist/commands/asa/campaigns/bulk-create.js +31 -18
- package/dist/commands/asa/campaigns/bulk-list.js +7 -5
- package/dist/commands/asa/campaigns/bulk-status.js +3 -2
- package/dist/commands/asa/campaigns/create.js +10 -8
- package/dist/commands/asa/campaigns/get.js +3 -2
- package/dist/commands/asa/campaigns/list.d.ts +1 -1
- package/dist/commands/asa/campaigns/list.js +1 -1
- package/dist/commands/asa/campaigns/update.js +25 -15
- package/dist/commands/asa/competitors/summary.js +5 -5
- package/dist/commands/asa/connect.js +5 -3
- package/dist/commands/asa/creatives/list.d.ts +1 -1
- package/dist/commands/asa/creatives/list.js +1 -1
- package/dist/commands/asa/keywords/add.js +13 -10
- package/dist/commands/asa/keywords/list.d.ts +1 -1
- package/dist/commands/asa/keywords/list.js +1 -1
- package/dist/commands/asa/keywords/update.js +15 -10
- package/dist/commands/asa/metrics/index.d.ts +6 -3
- package/dist/commands/asa/metrics/index.js +38 -14
- package/dist/commands/asa/metrics/overview.js +3 -3
- package/dist/commands/asa/negative-keywords/add.js +10 -7
- package/dist/commands/asa/negative-keywords/list.d.ts +1 -1
- package/dist/commands/asa/negative-keywords/list.js +1 -1
- package/dist/commands/asa/orgs/list.d.ts +1 -1
- package/dist/commands/asa/orgs/list.js +1 -1
- package/dist/commands/asa/product-pages/list.d.ts +1 -1
- package/dist/commands/asa/product-pages/list.js +1 -1
- package/dist/commands/asa/product-pages/sync.js +1 -1
- package/dist/commands/asa/search-terms/list.d.ts +1 -1
- package/dist/commands/asa/search-terms/list.js +1 -1
- package/dist/commands/asa/whoami.js +7 -2
- package/dist/commands/auth/login.js +3 -1
- package/dist/commands/flows/config/get.js +2 -2
- package/dist/commands/flows/config/preview.d.ts +2 -2
- package/dist/commands/flows/config/preview.js +6 -4
- package/dist/commands/flows/config/update.js +5 -3
- package/dist/commands/flows/config/validate.js +5 -3
- package/dist/commands/flows/list.d.ts +1 -1
- package/dist/commands/flows/media/upload.js +1 -1
- package/dist/commands/flows/publish.js +5 -5
- package/dist/commands/paywalls/create.js +1 -1
- package/dist/commands/paywalls/list.d.ts +1 -1
- package/dist/commands/paywalls/placements.d.ts +2 -2
- package/dist/commands/paywalls/update.js +1 -1
- package/dist/commands/placements/create.js +17 -12
- package/dist/commands/placements/list.d.ts +1 -1
- package/dist/commands/placements/update.js +20 -15
- package/dist/commands/products/create.js +20 -13
- package/dist/commands/products/list.d.ts +1 -1
- package/dist/commands/products/update.js +1 -1
- package/dist/commands/segments/list.d.ts +1 -1
- package/dist/lib/api-client.d.ts +10 -6
- package/dist/lib/api-client.js +56 -35
- package/dist/lib/api-schemas.d.ts +56 -56
- package/dist/lib/app-url.js +2 -1
- package/dist/lib/asa-client.d.ts +13 -8
- package/dist/lib/asa-client.js +9 -4
- package/dist/lib/asa-flags.d.ts +37 -13
- package/dist/lib/asa-flags.js +87 -20
- package/dist/lib/asa-keyword-action.d.ts +18 -0
- package/dist/lib/asa-keyword-action.js +175 -0
- package/dist/lib/asa-schemas.d.ts +100 -80
- package/dist/lib/auth.js +2 -1
- package/dist/lib/client-from-config.d.ts +1 -1
- package/dist/lib/client-from-config.js +2 -1
- package/dist/lib/config.d.ts +2 -2
- package/dist/lib/confirm.d.ts +4 -4
- package/dist/lib/confirm.js +12 -7
- package/dist/lib/errors.d.ts +18 -18
- package/dist/lib/errors.js +14 -10
- package/dist/lib/flags.d.ts +3 -3
- package/dist/lib/flags.js +2 -1
- package/dist/lib/flow-help.js +11 -6
- package/dist/lib/output.js +23 -12
- package/dist/lib/preview.d.ts +5 -5
- package/dist/lib/preview.js +2 -1
- package/oclif.manifest.json +372 -200
- package/package.json +10 -8
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export type ProductPeriod = 'annual' | 'consumable' | 'lifetime' | 'monthly' | 'nonsubscriptions' | 'semiannual' | 'trimonthly' | 'two_months' | 'uncategorised' | 'weekly';
|
|
2
|
-
export
|
|
2
|
+
export type VendorProductDTO = {
|
|
3
3
|
base_plan_id: null | string;
|
|
4
4
|
id: null | string;
|
|
5
5
|
product_id: null | string;
|
|
6
|
-
}
|
|
7
|
-
export
|
|
6
|
+
};
|
|
7
|
+
export type AppSummaryDTO = {
|
|
8
8
|
id: string;
|
|
9
9
|
sdk_key: null | string;
|
|
10
10
|
title: string;
|
|
11
|
-
}
|
|
12
|
-
export
|
|
11
|
+
};
|
|
12
|
+
export type AppDetailDTO = {
|
|
13
13
|
apple_bundle_id: null | string;
|
|
14
14
|
google_bundle_id: null | string;
|
|
15
15
|
id: string;
|
|
@@ -17,37 +17,37 @@ export interface AppDetailDTO {
|
|
|
17
17
|
sdk_key: null | string;
|
|
18
18
|
secret_key: null | string;
|
|
19
19
|
title: string;
|
|
20
|
-
}
|
|
21
|
-
export
|
|
20
|
+
};
|
|
21
|
+
export type AppCreateRequestDTO = {
|
|
22
22
|
apple_bundle_id?: null | string;
|
|
23
23
|
google_bundle_id?: null | string;
|
|
24
24
|
title: string;
|
|
25
|
-
}
|
|
26
|
-
export
|
|
25
|
+
};
|
|
26
|
+
export type AppUpdateRequestDTO = {
|
|
27
27
|
apple_bundle_id?: null | string;
|
|
28
28
|
google_bundle_id?: null | string;
|
|
29
29
|
title?: null | string;
|
|
30
|
-
}
|
|
31
|
-
export
|
|
30
|
+
};
|
|
31
|
+
export type AccessLevelDTO = {
|
|
32
32
|
id: string;
|
|
33
33
|
sdk_id: string;
|
|
34
34
|
title: null | string;
|
|
35
|
-
}
|
|
36
|
-
export
|
|
35
|
+
};
|
|
36
|
+
export type AccessLevelCreateRequestDTO = {
|
|
37
37
|
sdk_id: string;
|
|
38
38
|
title?: null | string;
|
|
39
|
-
}
|
|
40
|
-
export
|
|
39
|
+
};
|
|
40
|
+
export type AccessLevelUpdateRequestDTO = {
|
|
41
41
|
title?: null | string;
|
|
42
|
-
}
|
|
43
|
-
export
|
|
42
|
+
};
|
|
43
|
+
export type ProductDTO = {
|
|
44
44
|
access_level_id: string;
|
|
45
45
|
id: string;
|
|
46
46
|
period: ProductPeriod;
|
|
47
47
|
title: string;
|
|
48
48
|
vendor_products: Record<string, VendorProductDTO>;
|
|
49
|
-
}
|
|
50
|
-
export
|
|
49
|
+
};
|
|
50
|
+
export type ProductCreateRequestDTO = {
|
|
51
51
|
access_level_id: string;
|
|
52
52
|
android_base_plan_id?: null | string;
|
|
53
53
|
android_product_id?: null | string;
|
|
@@ -59,33 +59,33 @@ export interface ProductCreateRequestDTO {
|
|
|
59
59
|
stripe_price_id?: null | string;
|
|
60
60
|
stripe_product_id?: null | string;
|
|
61
61
|
title: string;
|
|
62
|
-
}
|
|
63
|
-
export
|
|
62
|
+
};
|
|
63
|
+
export type ProductUpdateRequestDTO = {
|
|
64
64
|
access_level_id: string;
|
|
65
65
|
title: string;
|
|
66
|
-
}
|
|
67
|
-
export
|
|
66
|
+
};
|
|
67
|
+
export type PaywallDTO = {
|
|
68
68
|
id: string;
|
|
69
69
|
product_ids: string[];
|
|
70
70
|
title: string;
|
|
71
|
-
}
|
|
72
|
-
export
|
|
71
|
+
};
|
|
72
|
+
export type PaywallWriteRequestDTO = {
|
|
73
73
|
product_ids?: string[];
|
|
74
74
|
title: string;
|
|
75
|
-
}
|
|
75
|
+
};
|
|
76
76
|
/** Flow lifecycle status. Values come from the server-side `FlowStatus` enum (e.g. draft, dirty, published). */
|
|
77
77
|
export type FlowStatus = string;
|
|
78
|
-
export
|
|
78
|
+
export type FlowDTO = {
|
|
79
79
|
id: string;
|
|
80
80
|
name: string;
|
|
81
81
|
status: FlowStatus;
|
|
82
82
|
updated_at: string;
|
|
83
|
-
}
|
|
84
|
-
export
|
|
83
|
+
};
|
|
84
|
+
export type FlowRemoteConfigDTO = {
|
|
85
85
|
data: string;
|
|
86
86
|
locale: string;
|
|
87
|
-
}
|
|
88
|
-
export
|
|
87
|
+
};
|
|
88
|
+
export type FlowConfigDTO = {
|
|
89
89
|
config: Record<string, unknown>;
|
|
90
90
|
/** Human message for a failed publication (raw passthrough from the flow version). */
|
|
91
91
|
publication_error?: null | string;
|
|
@@ -97,77 +97,77 @@ export interface FlowConfigDTO {
|
|
|
97
97
|
transform_error?: null | string;
|
|
98
98
|
/** Millisecond timestamp of the last content change; the value `expected_updated_at` is compared against on write. */
|
|
99
99
|
updated_at: number;
|
|
100
|
-
}
|
|
101
|
-
export
|
|
100
|
+
};
|
|
101
|
+
export type FlowWriteRequestDTO = {
|
|
102
102
|
name: string;
|
|
103
|
-
}
|
|
104
|
-
export
|
|
103
|
+
};
|
|
104
|
+
export type FlowConfigWriteRequestDTO = {
|
|
105
105
|
config: Record<string, unknown>;
|
|
106
106
|
/** Optimistic lock: the `updated_at` from a prior config read. Omit for last-write-wins. */
|
|
107
107
|
expected_updated_at?: null | number;
|
|
108
108
|
remote_configs?: FlowRemoteConfigDTO[];
|
|
109
|
-
}
|
|
110
|
-
export
|
|
109
|
+
};
|
|
110
|
+
export type FlowConfigValidateRequestDTO = {
|
|
111
111
|
config: Record<string, unknown>;
|
|
112
|
-
}
|
|
113
|
-
export
|
|
112
|
+
};
|
|
113
|
+
export type FlowConfigIssueDTO = {
|
|
114
114
|
/** Machine code, relayed from the transformer; absent until it reports path-level diagnostics. */
|
|
115
115
|
code?: null | string;
|
|
116
116
|
message: string;
|
|
117
117
|
/** Location of the issue; absent until the transformer reports path-level diagnostics. */
|
|
118
118
|
path?: null | string;
|
|
119
119
|
severity: string;
|
|
120
|
-
}
|
|
121
|
-
export
|
|
120
|
+
};
|
|
121
|
+
export type FlowConfigValidationDTO = {
|
|
122
122
|
issues: FlowConfigIssueDTO[];
|
|
123
123
|
valid: boolean;
|
|
124
|
-
}
|
|
125
|
-
export
|
|
124
|
+
};
|
|
125
|
+
export type MediaDTO = {
|
|
126
126
|
id: number;
|
|
127
127
|
name: string;
|
|
128
128
|
/** Base64-encoded preview thumbnail; absent when no preview was generated. */
|
|
129
129
|
preview_base64?: null | string;
|
|
130
130
|
/** CDN URL to reference from a flow config. */
|
|
131
131
|
url: string;
|
|
132
|
-
}
|
|
133
|
-
export
|
|
132
|
+
};
|
|
133
|
+
export type SegmentDTO = {
|
|
134
134
|
description: null | string;
|
|
135
135
|
id: string;
|
|
136
136
|
title: string;
|
|
137
|
-
}
|
|
138
|
-
export
|
|
137
|
+
};
|
|
138
|
+
export type PlacementPaywallAudienceEntryDTO = {
|
|
139
139
|
content_type: 'paywall';
|
|
140
140
|
paywall_id: string;
|
|
141
141
|
priority: number;
|
|
142
142
|
segment_ids?: string[];
|
|
143
|
-
}
|
|
144
|
-
export
|
|
143
|
+
};
|
|
144
|
+
export type PlacementFlowAudienceEntryDTO = {
|
|
145
145
|
content_type: 'flow';
|
|
146
146
|
/** The flow must be `published` (not draft) — the backend returns 400 otherwise. */
|
|
147
147
|
flow_id: string;
|
|
148
148
|
priority: number;
|
|
149
149
|
segment_ids?: string[];
|
|
150
|
-
}
|
|
150
|
+
};
|
|
151
151
|
export type PlacementAudienceEntryDTO = PlacementFlowAudienceEntryDTO | PlacementPaywallAudienceEntryDTO;
|
|
152
|
-
export
|
|
152
|
+
export type PlacementSummaryDTO = {
|
|
153
153
|
developer_id: string;
|
|
154
154
|
id: string;
|
|
155
155
|
/** Placement activation state: true = Live, false = Inactive. */
|
|
156
156
|
is_active: boolean;
|
|
157
157
|
title: string;
|
|
158
|
-
}
|
|
159
|
-
export
|
|
158
|
+
};
|
|
159
|
+
export type PlacementDetailDTO = {
|
|
160
160
|
audiences?: PlacementAudienceEntryDTO[];
|
|
161
161
|
developer_id: string;
|
|
162
162
|
id: string;
|
|
163
163
|
/** Placement activation state: true = Live, false = Inactive. */
|
|
164
164
|
is_active: boolean;
|
|
165
165
|
title: string;
|
|
166
|
-
}
|
|
167
|
-
export
|
|
166
|
+
};
|
|
167
|
+
export type PlacementWriteRequestDTO = {
|
|
168
168
|
audiences: null | PlacementAudienceEntryDTO[];
|
|
169
169
|
developer_id: string;
|
|
170
170
|
/** @deprecated use `audiences` */
|
|
171
171
|
paywall_id: null | string;
|
|
172
172
|
title: string;
|
|
173
|
-
}
|
|
173
|
+
};
|
package/dist/lib/app-url.js
CHANGED
|
@@ -20,8 +20,9 @@ export function appUrl(path) {
|
|
|
20
20
|
* ADAPTY_APP_URL the link is left exactly as issued — the API is free to serve it from any host.
|
|
21
21
|
*/
|
|
22
22
|
export function onAppHost(issuedUrl) {
|
|
23
|
-
if (!process.env[APP_URL_ENV_VAR])
|
|
23
|
+
if (!process.env[APP_URL_ENV_VAR]) {
|
|
24
24
|
return issuedUrl;
|
|
25
|
+
}
|
|
25
26
|
let issued;
|
|
26
27
|
try {
|
|
27
28
|
issued = new URL(issuedUrl);
|
package/dist/lib/asa-client.d.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
import { ApiClient } from './api-client.js';
|
|
2
|
+
import type { QueryParams } from './api-client.js';
|
|
1
3
|
import type { Config } from '@oclif/core';
|
|
2
|
-
import { ApiClient, type QueryParams } from './api-client.js';
|
|
3
4
|
export declare const ASA_API_URL = "https://api-asa-admin.adapty.io/api/v1/cli";
|
|
4
5
|
export declare const ASA_API_URL_ENV_VAR = "ADAPTY_ASA_API_URL";
|
|
5
|
-
export
|
|
6
|
-
|
|
6
|
+
export type AsaCommandContext = {
|
|
7
|
+
config: Config;
|
|
8
|
+
jsonEnabled: () => boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function createAsaClient(command: AsaCommandContext): Promise<ApiClient>;
|
|
11
|
+
export type AsaWriteOptions = {
|
|
7
12
|
body?: unknown;
|
|
8
|
-
idempotencyKey?: string;
|
|
9
|
-
params?: QueryParams;
|
|
10
|
-
}
|
|
11
|
-
export
|
|
13
|
+
idempotencyKey?: string | undefined;
|
|
14
|
+
params?: QueryParams | undefined;
|
|
15
|
+
};
|
|
16
|
+
export type AsaWriteOutcome<T> = {
|
|
12
17
|
replayed: boolean;
|
|
13
18
|
result: T;
|
|
14
|
-
}
|
|
19
|
+
};
|
|
15
20
|
export declare function asaWrite<T>(client: ApiClient, method: 'post' | 'put', path: string, opts?: AsaWriteOptions): Promise<AsaWriteOutcome<T>>;
|
|
16
21
|
export declare function noteReplay(replayed: boolean, log: (msg: string) => void): void;
|
package/dist/lib/asa-client.js
CHANGED
|
@@ -5,13 +5,16 @@ import { buildUserAgent } from './client-from-config.js';
|
|
|
5
5
|
import { AuthRequiredError, NetworkError } from './errors.js';
|
|
6
6
|
export const ASA_API_URL = 'https://api-asa-admin.adapty.io/api/v1/cli';
|
|
7
7
|
export const ASA_API_URL_ENV_VAR = 'ADAPTY_ASA_API_URL';
|
|
8
|
-
export async function createAsaClient(
|
|
8
|
+
export async function createAsaClient(command) {
|
|
9
|
+
const { config } = command;
|
|
9
10
|
const token = await resolveToken(config.configDir);
|
|
10
|
-
if (!token)
|
|
11
|
+
if (!token) {
|
|
11
12
|
throw new AuthRequiredError();
|
|
13
|
+
}
|
|
12
14
|
return new ApiClient({
|
|
13
15
|
defaultBaseUrl: ASA_API_URL,
|
|
14
16
|
errorFormat: 'asa',
|
|
17
|
+
quiet: command.jsonEnabled(),
|
|
15
18
|
token,
|
|
16
19
|
urlEnvVar: ASA_API_URL_ENV_VAR,
|
|
17
20
|
userAgent: buildUserAgent(config),
|
|
@@ -34,13 +37,15 @@ export async function asaWrite(client, method, path, opts = {}) {
|
|
|
34
37
|
return { replayed, result };
|
|
35
38
|
}
|
|
36
39
|
catch (error) {
|
|
37
|
-
if (!(error instanceof NetworkError))
|
|
40
|
+
if (!(error instanceof NetworkError)) {
|
|
38
41
|
throw error;
|
|
42
|
+
}
|
|
39
43
|
const result = await send();
|
|
40
44
|
return { replayed, result };
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
export function noteReplay(replayed, log) {
|
|
44
|
-
if (replayed)
|
|
48
|
+
if (replayed) {
|
|
45
49
|
log('Already applied earlier — showing the stored result.');
|
|
50
|
+
}
|
|
46
51
|
}
|
package/dist/lib/asa-flags.d.ts
CHANGED
|
@@ -44,17 +44,31 @@ export declare const adScopeFlags: {
|
|
|
44
44
|
campaign: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
45
45
|
'campaign-group': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
46
46
|
};
|
|
47
|
+
export declare const metricsScopeFlags: {
|
|
48
|
+
'ad-group': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
49
|
+
app: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
50
|
+
campaign: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
51
|
+
};
|
|
52
|
+
export declare function metricsScopeBody(flags: {
|
|
53
|
+
'ad-group'?: string[] | undefined;
|
|
54
|
+
'app'?: string[] | undefined;
|
|
55
|
+
'campaign'?: string[] | undefined;
|
|
56
|
+
}): {
|
|
57
|
+
campaign_id?: string[];
|
|
58
|
+
app_id?: string[];
|
|
59
|
+
ad_group_id?: string[];
|
|
60
|
+
};
|
|
47
61
|
export declare const statusFilter: (options: string[]) => {
|
|
48
62
|
status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
49
63
|
};
|
|
50
|
-
|
|
51
|
-
'ad-group'?: string[];
|
|
52
|
-
app?: string[];
|
|
53
|
-
campaign?: string[];
|
|
54
|
-
'campaign-group'?: string[];
|
|
55
|
-
search?: string;
|
|
56
|
-
status?: string;
|
|
57
|
-
}
|
|
64
|
+
type ScopeFlags = {
|
|
65
|
+
'ad-group'?: string[] | undefined;
|
|
66
|
+
'app'?: string[] | undefined;
|
|
67
|
+
'campaign'?: string[] | undefined;
|
|
68
|
+
'campaign-group'?: string[] | undefined;
|
|
69
|
+
'search'?: string | undefined;
|
|
70
|
+
'status'?: string | undefined;
|
|
71
|
+
};
|
|
58
72
|
export declare function scopeParams(flags: ScopeFlags): QueryParams;
|
|
59
73
|
export declare const scheduleFlags: {
|
|
60
74
|
'end-time': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -66,8 +80,8 @@ export declare const pricingModelFlag: {
|
|
|
66
80
|
export declare function startOfDayUtc(date: string | undefined): string | undefined;
|
|
67
81
|
export declare function todayUtc(): string;
|
|
68
82
|
export declare function periodParams(flags: {
|
|
69
|
-
'date-from'?: string;
|
|
70
|
-
'date-to'?: string;
|
|
83
|
+
'date-from'?: string | undefined;
|
|
84
|
+
'date-to'?: string | undefined;
|
|
71
85
|
}): Record<string, string>;
|
|
72
86
|
export declare function moneyFlag(description: string, opts?: {
|
|
73
87
|
required?: boolean;
|
|
@@ -75,6 +89,16 @@ export declare function moneyFlag(description: string, opts?: {
|
|
|
75
89
|
export declare const currencyFlag: {
|
|
76
90
|
currency: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
77
91
|
};
|
|
92
|
+
export declare const addKeywordActionFlags: {
|
|
93
|
+
'cpt-bid': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
94
|
+
'cpt-bid-type': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
95
|
+
'match-type': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
96
|
+
negate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
97
|
+
'no-negate': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
98
|
+
'pause-original': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
99
|
+
'skip-enable-duplicates': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
100
|
+
'target-ad-group': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
101
|
+
};
|
|
78
102
|
export declare const idempotencyFlags: {
|
|
79
103
|
'idempotency-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
80
104
|
};
|
|
@@ -94,17 +118,17 @@ export declare const invoiceFlags: {
|
|
|
94
118
|
'invoice-contact-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
95
119
|
'invoice-order-number': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
96
120
|
};
|
|
97
|
-
export declare function locInvoiceDetails(flags: Partial<Record<InvoiceFlagName, string>>): Record<keyof AsaLocInvoiceDetails, string> | undefined;
|
|
121
|
+
export declare function locInvoiceDetails(flags: Partial<Record<InvoiceFlagName, string | undefined>>): Record<keyof AsaLocInvoiceDetails, string> | undefined;
|
|
98
122
|
export declare function reportServingState(campaign: null | {
|
|
99
123
|
internal_id: string;
|
|
100
124
|
serving_state_reasons?: null | string[];
|
|
101
125
|
serving_status?: null | string;
|
|
102
126
|
}, warn: (msg: string) => void): void;
|
|
103
|
-
|
|
127
|
+
type BulkOutcome = {
|
|
104
128
|
applied: unknown[];
|
|
105
129
|
errors: AsaMutationError[];
|
|
106
130
|
isValidationFailure: boolean;
|
|
107
131
|
kind: string;
|
|
108
|
-
}
|
|
132
|
+
};
|
|
109
133
|
export declare function reportBulkOutcome({ applied, errors, isValidationFailure, kind }: BulkOutcome, log: (msg: string) => void): void;
|
|
110
134
|
export {};
|
package/dist/lib/asa-flags.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
+
import { CPT_BID_TYPES, KEYWORD_MATCH_TYPES, NEGATE_TYPES } from './asa-keyword-action.js';
|
|
2
3
|
import { describeListedError } from './errors.js';
|
|
3
4
|
import { isValidUuid } from './flags.js';
|
|
4
5
|
const DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
@@ -8,7 +9,7 @@ export const MAX_BY_DAYS = 16;
|
|
|
8
9
|
export const ASA_METRIC_ENTITIES = ['ad', 'ad-group', 'campaign', 'keyword'];
|
|
9
10
|
export const ASA_GROUP_BY_DIMENSIONS = ['country', 'day', 'month', 'quarter', 'week', 'year'];
|
|
10
11
|
export const asaPaginationFlags = {
|
|
11
|
-
page: Flags.integer({
|
|
12
|
+
'page': Flags.integer({
|
|
12
13
|
default: 1,
|
|
13
14
|
description: 'Page number',
|
|
14
15
|
min: 1,
|
|
@@ -26,9 +27,11 @@ export const byDaysFlag = {
|
|
|
26
27
|
multiple: true,
|
|
27
28
|
}),
|
|
28
29
|
};
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
|
|
29
31
|
export async function parseDate(input) {
|
|
30
|
-
if (!DATE_REGEX.test(input))
|
|
32
|
+
if (!DATE_REGEX.test(input)) {
|
|
31
33
|
throw new Error('Dates must be written as YYYY-MM-DD.');
|
|
34
|
+
}
|
|
32
35
|
return input;
|
|
33
36
|
}
|
|
34
37
|
export const periodFlags = {
|
|
@@ -41,9 +44,11 @@ export const periodFlags = {
|
|
|
41
44
|
parse: parseDate,
|
|
42
45
|
}),
|
|
43
46
|
};
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
|
|
44
48
|
async function parseId(input) {
|
|
45
|
-
if (!isValidUuid(input))
|
|
49
|
+
if (!isValidUuid(input)) {
|
|
46
50
|
throw new Error('Ids are the UUIDs printed by the matching list command.');
|
|
51
|
+
}
|
|
47
52
|
return input;
|
|
48
53
|
}
|
|
49
54
|
function idFilter(entity) {
|
|
@@ -51,7 +56,7 @@ function idFilter(entity) {
|
|
|
51
56
|
}
|
|
52
57
|
const searchFilter = { search: Flags.string({ description: 'Case-insensitive substring match on the name' }) };
|
|
53
58
|
export const assetScopeFlags = {
|
|
54
|
-
app: idFilter('app'),
|
|
59
|
+
'app': idFilter('app'),
|
|
55
60
|
'campaign-group': idFilter('campaign group'),
|
|
56
61
|
};
|
|
57
62
|
export const orgScopeFlags = { ...assetScopeFlags, ...searchFilter };
|
|
@@ -59,10 +64,22 @@ export const campaignScopeFlags = { ...orgScopeFlags, campaign: idFilter('campai
|
|
|
59
64
|
export const adGroupScopeFlags = { ...campaignScopeFlags, 'ad-group': idFilter('ad group') };
|
|
60
65
|
export const adScopeFlags = {
|
|
61
66
|
'ad-group': idFilter('ad group'),
|
|
62
|
-
campaign: idFilter('campaign'),
|
|
67
|
+
'campaign': idFilter('campaign'),
|
|
63
68
|
'campaign-group': idFilter('campaign group'),
|
|
64
69
|
...searchFilter,
|
|
65
70
|
};
|
|
71
|
+
export const metricsScopeFlags = {
|
|
72
|
+
'ad-group': idFilter('ad group'),
|
|
73
|
+
'app': idFilter('app'),
|
|
74
|
+
'campaign': idFilter('campaign'),
|
|
75
|
+
};
|
|
76
|
+
export function metricsScopeBody(flags) {
|
|
77
|
+
return {
|
|
78
|
+
...(flags['ad-group'] === undefined ? {} : { ad_group_id: flags['ad-group'] }),
|
|
79
|
+
...(flags.app === undefined ? {} : { app_id: flags.app }),
|
|
80
|
+
...(flags.campaign === undefined ? {} : { campaign_id: flags.campaign }),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
66
83
|
export const statusFilter = (options) => ({
|
|
67
84
|
status: Flags.string({ description: 'Keep only rows in this state', options }),
|
|
68
85
|
});
|
|
@@ -95,27 +112,72 @@ export function todayUtc() {
|
|
|
95
112
|
}
|
|
96
113
|
export function periodParams(flags) {
|
|
97
114
|
const params = {};
|
|
98
|
-
if (flags['date-from'])
|
|
115
|
+
if (flags['date-from']) {
|
|
99
116
|
params.date_from = flags['date-from'];
|
|
100
|
-
|
|
117
|
+
}
|
|
118
|
+
if (flags['date-to']) {
|
|
101
119
|
params.date_to = flags['date-to'];
|
|
120
|
+
}
|
|
102
121
|
return params;
|
|
103
122
|
}
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
|
|
104
124
|
async function parseMoney(input) {
|
|
105
|
-
if (!MONEY_REGEX.test(input))
|
|
125
|
+
if (!MONEY_REGEX.test(input)) {
|
|
106
126
|
throw new Error('Amounts must be plain numbers, e.g. 50 or 12.50.');
|
|
127
|
+
}
|
|
107
128
|
return input;
|
|
108
129
|
}
|
|
109
130
|
export function moneyFlag(description, opts = {}) {
|
|
110
131
|
return Flags.string({
|
|
111
132
|
description: `${description} (amount, e.g. 50 or 12.50)`,
|
|
112
133
|
parse: parseMoney,
|
|
113
|
-
required: opts.required,
|
|
134
|
+
...(opts.required === undefined ? {} : { required: opts.required }),
|
|
114
135
|
});
|
|
115
136
|
}
|
|
116
137
|
export const currencyFlag = {
|
|
117
138
|
currency: Flags.string({ default: 'USD', description: 'Currency code for the amounts in this call' }),
|
|
118
139
|
};
|
|
140
|
+
// Params of the add-as-keyword-to action, shared by `automations create` and `automations update`.
|
|
141
|
+
// The API picks the params variant by shape, so which of these apply depends on the rule's
|
|
142
|
+
// operate_with: --negate/--no-negate/--skip-enable-duplicates are search-term only,
|
|
143
|
+
// --pause-original is targeting-keyword only. See lib/asa-keyword-action.ts.
|
|
144
|
+
export const addKeywordActionFlags = {
|
|
145
|
+
'cpt-bid': Flags.string({
|
|
146
|
+
description: 'cpt_bid.value: the bid itself with --cpt-bid-type set_to, or a percent markup on the entity bid with '
|
|
147
|
+
+ 'search_term_current_cpt / keyword_current_bid; not accepted with ad_group_default_bid',
|
|
148
|
+
parse: parseMoney,
|
|
149
|
+
}),
|
|
150
|
+
'cpt-bid-type': Flags.string({
|
|
151
|
+
description: 'Where the bid of the created keyword comes from; the API has no default',
|
|
152
|
+
options: CPT_BID_TYPES,
|
|
153
|
+
}),
|
|
154
|
+
'match-type': Flags.string({
|
|
155
|
+
description: 'Match type of the created keyword; the API has no default',
|
|
156
|
+
options: KEYWORD_MATCH_TYPES,
|
|
157
|
+
}),
|
|
158
|
+
'negate': Flags.string({
|
|
159
|
+
description: 'Also add the search term as a negative keyword at this level (search-term rules)',
|
|
160
|
+
exclusive: ['no-negate'],
|
|
161
|
+
options: NEGATE_TYPES,
|
|
162
|
+
}),
|
|
163
|
+
'no-negate': Flags.boolean({
|
|
164
|
+
description: 'Leave no negative keyword behind (search-term rules)',
|
|
165
|
+
exclusive: ['negate'],
|
|
166
|
+
}),
|
|
167
|
+
'pause-original': Flags.boolean({
|
|
168
|
+
allowNo: true,
|
|
169
|
+
description: 'Pause the source keyword in its own ad group (targeting-keyword rules)',
|
|
170
|
+
}),
|
|
171
|
+
'skip-enable-duplicates': Flags.boolean({
|
|
172
|
+
allowNo: true,
|
|
173
|
+
description: 'Skip a keyword that already exists in the target ad group instead of enabling it (search-term rules)',
|
|
174
|
+
}),
|
|
175
|
+
'target-ad-group': Flags.string({
|
|
176
|
+
description: 'Ad group the keyword is added to (UUID), repeatable; a rule without one does nothing',
|
|
177
|
+
multiple: true,
|
|
178
|
+
parse: parseId,
|
|
179
|
+
}),
|
|
180
|
+
};
|
|
119
181
|
export const idempotencyFlags = {
|
|
120
182
|
'idempotency-key': Flags.string({
|
|
121
183
|
description: 'Idempotency key for this write; re-running with the same key replays the stored result instead of applying twice',
|
|
@@ -144,32 +206,37 @@ export const invoiceFlags = {
|
|
|
144
206
|
};
|
|
145
207
|
export function locInvoiceDetails(flags) {
|
|
146
208
|
const names = Object.keys(INVOICE_FIELDS);
|
|
147
|
-
const missing = names.filter(
|
|
148
|
-
if (missing.length === names.length)
|
|
209
|
+
const missing = names.filter(name => flags[name] === undefined);
|
|
210
|
+
if (missing.length === names.length) {
|
|
149
211
|
return undefined;
|
|
212
|
+
}
|
|
150
213
|
if (missing.length > 0) {
|
|
151
|
-
throw new Error(`Invoicing Options need all five flags; missing: ${missing.map(
|
|
214
|
+
throw new Error(`Invoicing Options need all five flags; missing: ${missing.map(name => `--${name}`).join(', ')}`);
|
|
152
215
|
}
|
|
153
|
-
return Object.fromEntries(names.map(
|
|
216
|
+
return Object.fromEntries(names.map(name => [INVOICE_FIELDS[name], flags[name]]));
|
|
154
217
|
}
|
|
155
218
|
const SERVING_HINTS = {
|
|
156
|
-
AUTOMATED_KEYWORDS_REQUIRED_AD_GROUP_MISSING:
|
|
157
|
-
MISSING_BO_OR_INVOICING_FIELDS:
|
|
219
|
+
AUTOMATED_KEYWORDS_REQUIRED_AD_GROUP_MISSING: campaignId => `Max Conversions campaign needs an automated ad group: adapty asa ad-groups create --campaign ${campaignId} --name "Automated Max Conv" --automated`,
|
|
220
|
+
MISSING_BO_OR_INVOICING_FIELDS: campaignId => `This organization bills by line of credit — add Invoicing Options: adapty asa campaigns update ${campaignId} --invoice-advertiser ... --invoice-order-number ... --invoice-contact-name ... --invoice-contact-email ... --invoice-billing-email ...`,
|
|
158
221
|
};
|
|
159
222
|
export function reportServingState(campaign, warn) {
|
|
160
|
-
if (campaign?.serving_status !== 'NOT_RUNNING' || !campaign.serving_state_reasons?.length)
|
|
223
|
+
if (campaign?.serving_status !== 'NOT_RUNNING' || !campaign.serving_state_reasons?.length) {
|
|
161
224
|
return;
|
|
225
|
+
}
|
|
162
226
|
const reasons = campaign.serving_state_reasons;
|
|
163
|
-
if (reasons.length === 1 && reasons[0] === 'PAUSED_BY_USER')
|
|
227
|
+
if (reasons.length === 1 && reasons[0] === 'PAUSED_BY_USER') {
|
|
164
228
|
return;
|
|
229
|
+
}
|
|
165
230
|
for (const reason of reasons) {
|
|
166
231
|
const hint = SERVING_HINTS[reason];
|
|
167
|
-
if (hint)
|
|
232
|
+
if (hint) {
|
|
168
233
|
warn(hint(campaign.internal_id));
|
|
234
|
+
}
|
|
169
235
|
}
|
|
170
|
-
const other = reasons.filter(
|
|
171
|
-
if (other.length > 0)
|
|
236
|
+
const other = reasons.filter(reason => !SERVING_HINTS[reason]);
|
|
237
|
+
if (other.length > 0) {
|
|
172
238
|
warn(`Not serving: ${other.join(', ')}`);
|
|
239
|
+
}
|
|
173
240
|
}
|
|
174
241
|
export function reportBulkOutcome({ applied, errors, isValidationFailure, kind }, log) {
|
|
175
242
|
if (isValidationFailure) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const ADD_AS_KEYWORD_ACTION = "add-as-keyword-to";
|
|
2
|
+
export declare const CPT_BID_TYPES: string[];
|
|
3
|
+
export declare const KEYWORD_MATCH_TYPES: string[];
|
|
4
|
+
export declare const NEGATE_TYPES: string[];
|
|
5
|
+
export type AddKeywordActionFlags = {
|
|
6
|
+
'cpt-bid'?: string | undefined;
|
|
7
|
+
'cpt-bid-type'?: string | undefined;
|
|
8
|
+
'match-type'?: string | undefined;
|
|
9
|
+
'negate'?: string | undefined;
|
|
10
|
+
'no-negate'?: boolean | undefined;
|
|
11
|
+
'pause-original'?: boolean | undefined;
|
|
12
|
+
'skip-enable-duplicates'?: boolean | undefined;
|
|
13
|
+
'target-ad-group'?: string[] | undefined;
|
|
14
|
+
};
|
|
15
|
+
export declare function hasAddKeywordActionFlags(flags: AddKeywordActionFlags): boolean;
|
|
16
|
+
export declare function buildAddKeywordParams(operateWith: unknown, stored: unknown, flags: AddKeywordActionFlags): Record<string, unknown>;
|
|
17
|
+
export declare function requireSingleAction(actions: unknown): Record<string, unknown>;
|
|
18
|
+
export declare function rebuildAddKeywordAction(actions: unknown, operateWith: unknown, flags: AddKeywordActionFlags): Record<string, unknown>[];
|