adapty 0.8.4 → 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.
Files changed (105) hide show
  1. package/README.md +1 -1
  2. package/bin/dev.js +2 -2
  3. package/bin/run.js +2 -2
  4. package/dist/commands/access-levels/create.js +1 -1
  5. package/dist/commands/access-levels/list.d.ts +1 -1
  6. package/dist/commands/apps/create.js +9 -6
  7. package/dist/commands/apps/list.d.ts +1 -1
  8. package/dist/commands/apps/update.js +7 -4
  9. package/dist/commands/asa/ad-groups/create.js +9 -7
  10. package/dist/commands/asa/ad-groups/get.js +3 -2
  11. package/dist/commands/asa/ad-groups/list.d.ts +1 -1
  12. package/dist/commands/asa/ad-groups/list.js +1 -1
  13. package/dist/commands/asa/ad-groups/update.js +22 -12
  14. package/dist/commands/asa/ads/create.js +7 -5
  15. package/dist/commands/asa/ads/get.js +3 -2
  16. package/dist/commands/asa/ads/list.d.ts +1 -1
  17. package/dist/commands/asa/ads/list.js +1 -1
  18. package/dist/commands/asa/ads/update.js +9 -5
  19. package/dist/commands/asa/apps/list.d.ts +1 -1
  20. package/dist/commands/asa/apps/list.js +1 -1
  21. package/dist/commands/asa/automations/create.js +9 -6
  22. package/dist/commands/asa/automations/get.js +3 -2
  23. package/dist/commands/asa/automations/list.d.ts +1 -1
  24. package/dist/commands/asa/automations/list.js +1 -1
  25. package/dist/commands/asa/automations/run.js +5 -3
  26. package/dist/commands/asa/automations/runs.d.ts +1 -1
  27. package/dist/commands/asa/automations/runs.js +4 -4
  28. package/dist/commands/asa/automations/update.js +17 -9
  29. package/dist/commands/asa/campaigns/bulk-create.js +31 -18
  30. package/dist/commands/asa/campaigns/bulk-list.js +7 -5
  31. package/dist/commands/asa/campaigns/bulk-status.js +3 -2
  32. package/dist/commands/asa/campaigns/create.js +10 -8
  33. package/dist/commands/asa/campaigns/get.js +3 -2
  34. package/dist/commands/asa/campaigns/list.d.ts +1 -1
  35. package/dist/commands/asa/campaigns/list.js +1 -1
  36. package/dist/commands/asa/campaigns/update.js +25 -15
  37. package/dist/commands/asa/competitors/summary.js +5 -5
  38. package/dist/commands/asa/connect.js +5 -3
  39. package/dist/commands/asa/creatives/list.d.ts +1 -1
  40. package/dist/commands/asa/creatives/list.js +1 -1
  41. package/dist/commands/asa/keywords/add.js +13 -10
  42. package/dist/commands/asa/keywords/list.d.ts +1 -1
  43. package/dist/commands/asa/keywords/list.js +1 -1
  44. package/dist/commands/asa/keywords/update.js +15 -10
  45. package/dist/commands/asa/metrics/index.d.ts +2 -2
  46. package/dist/commands/asa/metrics/index.js +22 -8
  47. package/dist/commands/asa/metrics/overview.js +3 -3
  48. package/dist/commands/asa/negative-keywords/add.js +10 -7
  49. package/dist/commands/asa/negative-keywords/list.d.ts +1 -1
  50. package/dist/commands/asa/negative-keywords/list.js +1 -1
  51. package/dist/commands/asa/orgs/list.d.ts +1 -1
  52. package/dist/commands/asa/orgs/list.js +1 -1
  53. package/dist/commands/asa/product-pages/list.d.ts +1 -1
  54. package/dist/commands/asa/product-pages/list.js +1 -1
  55. package/dist/commands/asa/product-pages/sync.js +1 -1
  56. package/dist/commands/asa/search-terms/list.d.ts +1 -1
  57. package/dist/commands/asa/search-terms/list.js +1 -1
  58. package/dist/commands/asa/whoami.js +7 -2
  59. package/dist/commands/auth/login.js +3 -1
  60. package/dist/commands/flows/config/get.js +2 -2
  61. package/dist/commands/flows/config/preview.d.ts +2 -2
  62. package/dist/commands/flows/config/preview.js +6 -4
  63. package/dist/commands/flows/config/update.js +5 -3
  64. package/dist/commands/flows/config/validate.js +5 -3
  65. package/dist/commands/flows/list.d.ts +1 -1
  66. package/dist/commands/flows/media/upload.js +1 -1
  67. package/dist/commands/flows/publish.js +5 -5
  68. package/dist/commands/paywalls/create.js +1 -1
  69. package/dist/commands/paywalls/list.d.ts +1 -1
  70. package/dist/commands/paywalls/placements.d.ts +2 -2
  71. package/dist/commands/paywalls/update.js +1 -1
  72. package/dist/commands/placements/create.js +17 -12
  73. package/dist/commands/placements/list.d.ts +1 -1
  74. package/dist/commands/placements/update.js +20 -15
  75. package/dist/commands/products/create.js +20 -13
  76. package/dist/commands/products/list.d.ts +1 -1
  77. package/dist/commands/products/update.js +1 -1
  78. package/dist/commands/segments/list.d.ts +1 -1
  79. package/dist/lib/api-client.d.ts +10 -6
  80. package/dist/lib/api-client.js +56 -35
  81. package/dist/lib/api-schemas.d.ts +56 -56
  82. package/dist/lib/app-url.js +2 -1
  83. package/dist/lib/asa-client.d.ts +13 -8
  84. package/dist/lib/asa-client.js +9 -4
  85. package/dist/lib/asa-flags.d.ts +19 -19
  86. package/dist/lib/asa-flags.js +38 -25
  87. package/dist/lib/asa-keyword-action.d.ts +10 -10
  88. package/dist/lib/asa-keyword-action.js +40 -25
  89. package/dist/lib/asa-schemas.d.ts +100 -80
  90. package/dist/lib/auth.js +2 -1
  91. package/dist/lib/client-from-config.d.ts +1 -1
  92. package/dist/lib/client-from-config.js +2 -1
  93. package/dist/lib/config.d.ts +2 -2
  94. package/dist/lib/confirm.d.ts +4 -4
  95. package/dist/lib/confirm.js +12 -7
  96. package/dist/lib/errors.d.ts +18 -18
  97. package/dist/lib/errors.js +12 -9
  98. package/dist/lib/flags.d.ts +3 -3
  99. package/dist/lib/flags.js +2 -1
  100. package/dist/lib/flow-help.js +11 -6
  101. package/dist/lib/output.js +23 -12
  102. package/dist/lib/preview.d.ts +5 -5
  103. package/dist/lib/preview.js +2 -1
  104. package/oclif.manifest.json +131 -131
  105. package/package.json +10 -8
@@ -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(config) {
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
  }
@@ -50,25 +50,25 @@ export declare const metricsScopeFlags: {
50
50
  campaign: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
51
51
  };
52
52
  export declare function metricsScopeBody(flags: {
53
- 'ad-group'?: string[];
54
- app?: string[];
55
- campaign?: string[];
53
+ 'ad-group'?: string[] | undefined;
54
+ 'app'?: string[] | undefined;
55
+ 'campaign'?: string[] | undefined;
56
56
  }): {
57
- campaign_id?: string[] | undefined;
58
- app_id?: string[] | undefined;
59
- ad_group_id?: string[] | undefined;
57
+ campaign_id?: string[];
58
+ app_id?: string[];
59
+ ad_group_id?: string[];
60
60
  };
61
61
  export declare const statusFilter: (options: string[]) => {
62
62
  status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
63
63
  };
64
- interface ScopeFlags {
65
- 'ad-group'?: string[];
66
- app?: string[];
67
- campaign?: string[];
68
- 'campaign-group'?: string[];
69
- search?: string;
70
- status?: string;
71
- }
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
+ };
72
72
  export declare function scopeParams(flags: ScopeFlags): QueryParams;
73
73
  export declare const scheduleFlags: {
74
74
  'end-time': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -80,8 +80,8 @@ export declare const pricingModelFlag: {
80
80
  export declare function startOfDayUtc(date: string | undefined): string | undefined;
81
81
  export declare function todayUtc(): string;
82
82
  export declare function periodParams(flags: {
83
- 'date-from'?: string;
84
- 'date-to'?: string;
83
+ 'date-from'?: string | undefined;
84
+ 'date-to'?: string | undefined;
85
85
  }): Record<string, string>;
86
86
  export declare function moneyFlag(description: string, opts?: {
87
87
  required?: boolean;
@@ -118,17 +118,17 @@ export declare const invoiceFlags: {
118
118
  'invoice-contact-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
119
119
  'invoice-order-number': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
120
120
  };
121
- 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;
122
122
  export declare function reportServingState(campaign: null | {
123
123
  internal_id: string;
124
124
  serving_state_reasons?: null | string[];
125
125
  serving_status?: null | string;
126
126
  }, warn: (msg: string) => void): void;
127
- interface BulkOutcome {
127
+ type BulkOutcome = {
128
128
  applied: unknown[];
129
129
  errors: AsaMutationError[];
130
130
  isValidationFailure: boolean;
131
131
  kind: string;
132
- }
132
+ };
133
133
  export declare function reportBulkOutcome({ applied, errors, isValidationFailure, kind }: BulkOutcome, log: (msg: string) => void): void;
134
134
  export {};
@@ -9,7 +9,7 @@ export const MAX_BY_DAYS = 16;
9
9
  export const ASA_METRIC_ENTITIES = ['ad', 'ad-group', 'campaign', 'keyword'];
10
10
  export const ASA_GROUP_BY_DIMENSIONS = ['country', 'day', 'month', 'quarter', 'week', 'year'];
11
11
  export const asaPaginationFlags = {
12
- page: Flags.integer({
12
+ 'page': Flags.integer({
13
13
  default: 1,
14
14
  description: 'Page number',
15
15
  min: 1,
@@ -27,9 +27,11 @@ export const byDaysFlag = {
27
27
  multiple: true,
28
28
  }),
29
29
  };
30
+ // eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
30
31
  export async function parseDate(input) {
31
- if (!DATE_REGEX.test(input))
32
+ if (!DATE_REGEX.test(input)) {
32
33
  throw new Error('Dates must be written as YYYY-MM-DD.');
34
+ }
33
35
  return input;
34
36
  }
35
37
  export const periodFlags = {
@@ -42,9 +44,11 @@ export const periodFlags = {
42
44
  parse: parseDate,
43
45
  }),
44
46
  };
47
+ // eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
45
48
  async function parseId(input) {
46
- if (!isValidUuid(input))
49
+ if (!isValidUuid(input)) {
47
50
  throw new Error('Ids are the UUIDs printed by the matching list command.');
51
+ }
48
52
  return input;
49
53
  }
50
54
  function idFilter(entity) {
@@ -52,7 +56,7 @@ function idFilter(entity) {
52
56
  }
53
57
  const searchFilter = { search: Flags.string({ description: 'Case-insensitive substring match on the name' }) };
54
58
  export const assetScopeFlags = {
55
- app: idFilter('app'),
59
+ 'app': idFilter('app'),
56
60
  'campaign-group': idFilter('campaign group'),
57
61
  };
58
62
  export const orgScopeFlags = { ...assetScopeFlags, ...searchFilter };
@@ -60,14 +64,14 @@ export const campaignScopeFlags = { ...orgScopeFlags, campaign: idFilter('campai
60
64
  export const adGroupScopeFlags = { ...campaignScopeFlags, 'ad-group': idFilter('ad group') };
61
65
  export const adScopeFlags = {
62
66
  'ad-group': idFilter('ad group'),
63
- campaign: idFilter('campaign'),
67
+ 'campaign': idFilter('campaign'),
64
68
  'campaign-group': idFilter('campaign group'),
65
69
  ...searchFilter,
66
70
  };
67
71
  export const metricsScopeFlags = {
68
72
  'ad-group': idFilter('ad group'),
69
- app: idFilter('app'),
70
- campaign: idFilter('campaign'),
73
+ 'app': idFilter('app'),
74
+ 'campaign': idFilter('campaign'),
71
75
  };
72
76
  export function metricsScopeBody(flags) {
73
77
  return {
@@ -108,22 +112,26 @@ export function todayUtc() {
108
112
  }
109
113
  export function periodParams(flags) {
110
114
  const params = {};
111
- if (flags['date-from'])
115
+ if (flags['date-from']) {
112
116
  params.date_from = flags['date-from'];
113
- if (flags['date-to'])
117
+ }
118
+ if (flags['date-to']) {
114
119
  params.date_to = flags['date-to'];
120
+ }
115
121
  return params;
116
122
  }
123
+ // eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
117
124
  async function parseMoney(input) {
118
- if (!MONEY_REGEX.test(input))
125
+ if (!MONEY_REGEX.test(input)) {
119
126
  throw new Error('Amounts must be plain numbers, e.g. 50 or 12.50.');
127
+ }
120
128
  return input;
121
129
  }
122
130
  export function moneyFlag(description, opts = {}) {
123
131
  return Flags.string({
124
132
  description: `${description} (amount, e.g. 50 or 12.50)`,
125
133
  parse: parseMoney,
126
- required: opts.required,
134
+ ...(opts.required === undefined ? {} : { required: opts.required }),
127
135
  });
128
136
  }
129
137
  export const currencyFlag = {
@@ -135,8 +143,8 @@ export const currencyFlag = {
135
143
  // --pause-original is targeting-keyword only. See lib/asa-keyword-action.ts.
136
144
  export const addKeywordActionFlags = {
137
145
  'cpt-bid': Flags.string({
138
- description: 'cpt_bid.value: the bid itself with --cpt-bid-type set_to, or a percent markup on the entity bid with ' +
139
- 'search_term_current_cpt / keyword_current_bid; not accepted with ad_group_default_bid',
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',
140
148
  parse: parseMoney,
141
149
  }),
142
150
  'cpt-bid-type': Flags.string({
@@ -147,7 +155,7 @@ export const addKeywordActionFlags = {
147
155
  description: 'Match type of the created keyword; the API has no default',
148
156
  options: KEYWORD_MATCH_TYPES,
149
157
  }),
150
- negate: Flags.string({
158
+ 'negate': Flags.string({
151
159
  description: 'Also add the search term as a negative keyword at this level (search-term rules)',
152
160
  exclusive: ['no-negate'],
153
161
  options: NEGATE_TYPES,
@@ -198,32 +206,37 @@ export const invoiceFlags = {
198
206
  };
199
207
  export function locInvoiceDetails(flags) {
200
208
  const names = Object.keys(INVOICE_FIELDS);
201
- const missing = names.filter((name) => flags[name] === undefined);
202
- if (missing.length === names.length)
209
+ const missing = names.filter(name => flags[name] === undefined);
210
+ if (missing.length === names.length) {
203
211
  return undefined;
212
+ }
204
213
  if (missing.length > 0) {
205
- throw new Error(`Invoicing Options need all five flags; missing: ${missing.map((name) => `--${name}`).join(', ')}`);
214
+ throw new Error(`Invoicing Options need all five flags; missing: ${missing.map(name => `--${name}`).join(', ')}`);
206
215
  }
207
- return Object.fromEntries(names.map((name) => [INVOICE_FIELDS[name], flags[name]]));
216
+ return Object.fromEntries(names.map(name => [INVOICE_FIELDS[name], flags[name]]));
208
217
  }
209
218
  const SERVING_HINTS = {
210
- 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`,
211
- 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 ...`,
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 ...`,
212
221
  };
213
222
  export function reportServingState(campaign, warn) {
214
- if (campaign?.serving_status !== 'NOT_RUNNING' || !campaign.serving_state_reasons?.length)
223
+ if (campaign?.serving_status !== 'NOT_RUNNING' || !campaign.serving_state_reasons?.length) {
215
224
  return;
225
+ }
216
226
  const reasons = campaign.serving_state_reasons;
217
- if (reasons.length === 1 && reasons[0] === 'PAUSED_BY_USER')
227
+ if (reasons.length === 1 && reasons[0] === 'PAUSED_BY_USER') {
218
228
  return;
229
+ }
219
230
  for (const reason of reasons) {
220
231
  const hint = SERVING_HINTS[reason];
221
- if (hint)
232
+ if (hint) {
222
233
  warn(hint(campaign.internal_id));
234
+ }
223
235
  }
224
- const other = reasons.filter((reason) => !SERVING_HINTS[reason]);
225
- if (other.length > 0)
236
+ const other = reasons.filter(reason => !SERVING_HINTS[reason]);
237
+ if (other.length > 0) {
226
238
  warn(`Not serving: ${other.join(', ')}`);
239
+ }
227
240
  }
228
241
  export function reportBulkOutcome({ applied, errors, isValidationFailure, kind }, log) {
229
242
  if (isValidationFailure) {
@@ -2,16 +2,16 @@ export declare const ADD_AS_KEYWORD_ACTION = "add-as-keyword-to";
2
2
  export declare const CPT_BID_TYPES: string[];
3
3
  export declare const KEYWORD_MATCH_TYPES: string[];
4
4
  export declare const NEGATE_TYPES: string[];
5
- export interface AddKeywordActionFlags {
6
- 'cpt-bid'?: string;
7
- 'cpt-bid-type'?: string;
8
- 'match-type'?: string;
9
- negate?: string;
10
- 'no-negate'?: boolean;
11
- 'pause-original'?: boolean;
12
- 'skip-enable-duplicates'?: boolean;
13
- 'target-ad-group'?: string[];
14
- }
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
15
  export declare function hasAddKeywordActionFlags(flags: AddKeywordActionFlags): boolean;
16
16
  export declare function buildAddKeywordParams(operateWith: unknown, stored: unknown, flags: AddKeywordActionFlags): Record<string, unknown>;
17
17
  export declare function requireSingleAction(actions: unknown): Record<string, unknown>;
@@ -29,15 +29,17 @@ function asRecord(value) {
29
29
  }
30
30
  function isFlagSet(flags, name) {
31
31
  const value = flags[name];
32
- if (value === undefined)
32
+ if (value === undefined) {
33
33
  return false;
34
- if (Array.isArray(value))
34
+ }
35
+ if (Array.isArray(value)) {
35
36
  return value.length > 0;
37
+ }
36
38
  // --no-negate has no negated form of its own, so only a true means it was passed.
37
39
  return name === 'no-negate' ? value === true : true;
38
40
  }
39
41
  export function hasAddKeywordActionFlags(flags) {
40
- return ALL_FLAGS.some((name) => isFlagSet(flags, name));
42
+ return ALL_FLAGS.some(name => isFlagSet(flags, name));
41
43
  }
42
44
  // Params are rebuilt, not patched: a rule may store the add-as-negative-keyword shape
43
45
  // ({target_type, ids}) under an add-as-keyword-to action, and the API picks the params variant by
@@ -64,46 +66,54 @@ function storedBoolean(value) {
64
66
  }
65
67
  function storedNegate(params) {
66
68
  const { enabled, type } = asRecord(params.negate);
67
- if (typeof enabled !== 'boolean')
69
+ if (typeof enabled !== 'boolean') {
68
70
  return undefined;
69
- if (type === null || type === undefined)
71
+ }
72
+ if (type === null || type === undefined) {
70
73
  return { enabled, type: null };
74
+ }
71
75
  return typeof type === 'string' && NEGATE_TYPES.includes(type) ? { enabled, type } : undefined;
72
76
  }
73
77
  function resolveNegate(flags, params) {
74
- if (flags.negate !== undefined)
78
+ if (flags.negate !== undefined) {
75
79
  return { enabled: true, type: flags.negate };
76
- if (flags['no-negate'] === true)
80
+ }
81
+ if (flags['no-negate'] === true) {
77
82
  return { enabled: false, type: null };
83
+ }
78
84
  return storedNegate(params) ?? { enabled: false, type: null };
79
85
  }
80
86
  function resolveCptBidValue(cptBidType, bid, params) {
81
- if (cptBidType === 'set_to')
87
+ if (cptBidType === 'set_to') {
82
88
  return bid === undefined ? storedCptBidValue(params) : Number(bid);
89
+ }
83
90
  if (cptBidType !== undefined && BID_TYPES_READING_MARKUP.has(cptBidType)) {
84
91
  return bid === undefined ? (storedCptBidValue(params) ?? null) : Number(bid);
85
92
  }
86
93
  return null;
87
94
  }
88
95
  function isSearchTermRule(operateWith) {
89
- if (operateWith === SEARCH_TERM)
96
+ if (operateWith === SEARCH_TERM) {
90
97
  return true;
91
- if (operateWith === TARGETING_KEYWORD)
98
+ }
99
+ if (operateWith === TARGETING_KEYWORD) {
92
100
  return false;
101
+ }
93
102
  const shown = typeof operateWith === 'string' && operateWith.length > 0 ? `"${operateWith}"` : 'missing';
94
103
  throw new Error(`${ADD_AS_KEYWORD_ACTION} runs on a "${SEARCH_TERM}" or "${TARGETING_KEYWORD}" rule only; this rule's operate_with is ${shown}.`);
95
104
  }
96
105
  function rejectForeignFlags(searchTerm, flags) {
97
- const foreign = (searchTerm ? TARGETING_KEYWORD_FLAGS : SEARCH_TERM_FLAGS).filter((name) => isFlagSet(flags, name));
98
- if (foreign.length === 0)
106
+ const foreign = (searchTerm ? TARGETING_KEYWORD_FLAGS : SEARCH_TERM_FLAGS).filter(name => isFlagSet(flags, name));
107
+ if (foreign.length === 0) {
99
108
  return;
109
+ }
100
110
  const applicable = [...SHARED_FLAGS, ...(searchTerm ? SEARCH_TERM_FLAGS : TARGETING_KEYWORD_FLAGS)];
101
- throw new Error(`${foreign.map((name) => dashed(name)).join(', ')} ${foreign.length === 1 ? 'has' : 'have'} no place in the params of an ` +
102
- `operate_with "${searchTerm ? SEARCH_TERM : TARGETING_KEYWORD}" rule, and the API drops params it cannot ` +
103
- `place. Applicable action flags: ${applicable.map((name) => dashed(name)).join(', ')}.`);
111
+ throw new Error(`${foreign.map(name => dashed(name)).join(', ')} ${foreign.length === 1 ? 'has' : 'have'} no place in the params of an `
112
+ + `operate_with "${searchTerm ? SEARCH_TERM : TARGETING_KEYWORD}" rule, and the API drops params it cannot `
113
+ + `place. Applicable action flags: ${applicable.map(name => dashed(name)).join(', ')}.`);
104
114
  }
105
115
  function missingFlagsError(missing) {
106
- const lines = missing.map((name) => ` ${dashed(name)} — ${MISSING_REASONS[name]}`);
116
+ const lines = missing.map(name => ` ${dashed(name)} — ${MISSING_REASONS[name]}`);
107
117
  return new Error(`The ${ADD_AS_KEYWORD_ACTION} params are incomplete. Pass:\n${lines.join('\n')}`);
108
118
  }
109
119
  export function buildAddKeywordParams(operateWith, stored, flags) {
@@ -112,23 +122,28 @@ export function buildAddKeywordParams(operateWith, stored, flags) {
112
122
  const params = asRecord(stored);
113
123
  const missing = [];
114
124
  const internalIds = flags['target-ad-group'] ?? storedInternalIds(params);
115
- if (internalIds.length === 0)
125
+ if (internalIds.length === 0) {
116
126
  missing.push('target-ad-group');
127
+ }
117
128
  const matchType = flags['match-type'] ?? storedMatchType(params);
118
- if (matchType === undefined)
129
+ if (matchType === undefined) {
119
130
  missing.push('match-type');
131
+ }
120
132
  const cptBidType = flags['cpt-bid-type'] ?? storedCptBidType(params);
121
- if (cptBidType === undefined)
133
+ if (cptBidType === undefined) {
122
134
  missing.push('cpt-bid-type');
135
+ }
123
136
  const bid = flags['cpt-bid'];
124
137
  if (bid !== undefined && cptBidType === BID_TYPE_IGNORING_VALUE) {
125
138
  throw new Error(`--cpt-bid has no meaning with --cpt-bid-type ${BID_TYPE_IGNORING_VALUE}; that type copies the target ad group's default bid.`);
126
139
  }
127
140
  const cptBidValue = resolveCptBidValue(cptBidType, bid, params);
128
- if (cptBidValue === undefined)
141
+ if (cptBidValue === undefined) {
129
142
  missing.push('cpt-bid');
130
- if (missing.length > 0)
143
+ }
144
+ if (missing.length > 0) {
131
145
  throw missingFlagsError(missing);
146
+ }
132
147
  const built = {
133
148
  cpt_bid: { type: cptBidType, value: cptBidValue ?? null },
134
149
  match_type: matchType,
@@ -136,12 +151,12 @@ export function buildAddKeywordParams(operateWith, stored, flags) {
136
151
  };
137
152
  if (searchTerm) {
138
153
  built.negate = resolveNegate(flags, params);
139
- built.skip_enable_duplicate_keywords =
140
- flags['skip-enable-duplicates'] ?? storedBoolean(params.skip_enable_duplicate_keywords) ?? false;
154
+ built.skip_enable_duplicate_keywords
155
+ = flags['skip-enable-duplicates'] ?? storedBoolean(params.skip_enable_duplicate_keywords) ?? false;
141
156
  }
142
157
  else {
143
- built.pause_in_original_ad_group =
144
- flags['pause-original'] ?? storedBoolean(params.pause_in_original_ad_group) ?? false;
158
+ built.pause_in_original_ad_group
159
+ = flags['pause-original'] ?? storedBoolean(params.pause_in_original_ad_group) ?? false;
145
160
  }
146
161
  return built;
147
162
  }