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
@@ -10,10 +10,17 @@ One row per entity, already aggregated server-side and sorted by --order-by, so
10
10
  call with --order-by and --page-size N — never sum pages yourself. Account-level totals are one call to
11
11
  asa metrics overview instead. The date window is capped by the finest --group-by period: 28 days when
12
12
  day is grouped, 90 with no period grouping, 180 by week, 365 by month and coarser — widen the window by
13
- coarsening the grouping, not by splitting into more calls. Each page is also capped at 5000 breakdown
14
- rows (entities × countries × periods); over it the call fails with 422 cli_response_too_large — coarsen
15
- the grouping, narrow the window, or reduce page[size]. Budget: 5 metrics calls per minute, at most
16
- 2 per 10 seconds, one at a time.
13
+ coarsening the grouping, not by splitting into more calls. Each page is also capped at a breakdown-row
14
+ count (entities × countries × periods); over it the call fails with 422 cli_response_too_large naming the
15
+ page[size] that fits — coarsen the grouping, narrow the window, or reduce page[size].
16
+
17
+ Money columns are in the campaign group currency, not USD, and spend and local_spend carry the same
18
+ figure; the currency itself comes from asa orgs list. Rate budgets and the breakdown-row cap are set per
19
+ company: read the current ones with asa whoami rather than assuming a default. meta.pagination.count is
20
+ the full entity count behind the filters, so take inventory from there instead of counting the rows on a
21
+ page. meta.max_valid_day says how many days the youngest cohort in the window has lived — any --by-days
22
+ window above it repeats the last real figure because that time has not passed yet, so treat those as
23
+ unreached rather than as a plateau.
17
24
 
18
25
  --metric is required and every metric named is computed over the whole entity set, so ask for the
19
26
  columns you actually read. subscribers and paid_subscribers (and arppu / arpas, which derive from them)
@@ -35,18 +42,18 @@ to make any call fast, since cost follows the number of entities aggregated, not
35
42
  ...metricsScopeFlags,
36
43
  'date-from': Flags.string({ description: 'Start of the period (YYYY-MM-DD)', required: true }),
37
44
  'date-to': Flags.string({ description: 'End of the period (YYYY-MM-DD)', required: true }),
38
- entity: Flags.string({ description: 'What to report on', options: ASA_METRIC_ENTITIES, required: true }),
45
+ 'entity': Flags.string({ description: 'What to report on', options: ASA_METRIC_ENTITIES, required: true }),
39
46
  'group-by': Flags.string({
40
47
  description: 'Break the rows down by a dimension, repeatable',
41
48
  multiple: true,
42
49
  options: ASA_GROUP_BY_DIMENSIONS,
43
50
  }),
44
- metric: Flags.string({
51
+ 'metric': Flags.string({
45
52
  description: 'Metric name (dashboard nomenclature, e.g. spend, taps, gross_roas), repeatable and required; every metric asked for is computed over the whole entity set, so list only what you read; a wrong name fails listing all valid ones',
46
53
  multiple: true,
47
54
  required: true,
48
55
  }),
49
- order: Flags.string({ default: 'desc', description: 'Sort direction', options: ['asc', 'desc'] }),
56
+ 'order': Flags.string({ default: 'desc', description: 'Sort direction', options: ['asc', 'desc'] }),
50
57
  'order-by': Flags.string({
51
58
  description: 'Metric or field to sort by; cohort metrics rank via their gross_/proceeds_/net_ names',
52
59
  }),
@@ -59,7 +66,7 @@ to make any call fast, since cost follows the number of entities aggregated, not
59
66
  if (flags['by-days'] && flags['by-days'].length > MAX_BY_DAYS) {
60
67
  this.error(`At most ${MAX_BY_DAYS} renewal windows per call, got ${flags['by-days'].length}.`, { exit: 2 });
61
68
  }
62
- const client = await createAsaClient(this.config);
69
+ const client = await createAsaClient(this);
63
70
  const { result } = await asaWrite(client, 'post', '/metrics', {
64
71
  body: {
65
72
  date_from: flags['date-from'],
@@ -75,7 +82,14 @@ to make any call fast, since cost follows the number of entities aggregated, not
75
82
  },
76
83
  params: paginationParams(flags),
77
84
  });
85
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- FIXME if you see this
78
86
  printList(result.data, this.log.bind(this), result.meta?.pagination);
87
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- FIXME if you see this
88
+ const horizon = result.meta?.max_valid_day;
89
+ if (horizon !== undefined && flags['by-days']?.some(day => day > horizon)) {
90
+ this.log(`\nCohort windows past day ${horizon} have not been reached by this date range yet; they repeat the last `
91
+ + 'figure actually observed rather than projecting it.');
92
+ }
79
93
  return result;
80
94
  }
81
95
  }
@@ -18,8 +18,8 @@ the 5-per-minute metrics budget with asa metrics.`;
18
18
  ...byDaysFlag,
19
19
  'date-from': Flags.string({ description: 'Start of the period (YYYY-MM-DD)', required: true }),
20
20
  'date-to': Flags.string({ description: 'End of the period (YYYY-MM-DD)', required: true }),
21
- entity: Flags.string({ description: 'What to report on', options: ASA_METRIC_ENTITIES, required: true }),
22
- metric: Flags.string({
21
+ 'entity': Flags.string({ description: 'What to report on', options: ASA_METRIC_ENTITIES, required: true }),
22
+ 'metric': Flags.string({
23
23
  description: 'Metric name, repeatable; cohort roots only here (revenue, roas, arpu), not their gross_/proceeds_/net_ variants; omit for every metric',
24
24
  multiple: true,
25
25
  }),
@@ -34,7 +34,7 @@ the 5-per-minute metrics budget with asa metrics.`;
34
34
  if (flags['by-days'] && flags['by-days'].length > MAX_BY_DAYS) {
35
35
  this.error(`At most ${MAX_BY_DAYS} renewal windows per call, got ${flags['by-days'].length}.`, { exit: 2 });
36
36
  }
37
- const client = await createAsaClient(this.config);
37
+ const client = await createAsaClient(this);
38
38
  const { result } = await asaWrite(client, 'post', '/metrics/overview', {
39
39
  body: {
40
40
  date_from: flags['date-from'],
@@ -19,25 +19,28 @@ export default class AsaNegativeKeywordsAdd extends Command {
19
19
  dependsOn: ['campaign'],
20
20
  description: 'Apply to every ad group of the campaign instead of the campaign itself',
21
21
  }),
22
- campaign: Flags.string({ description: 'Campaign ID (UUID)', exclusive: ['ad-group'] }),
22
+ 'campaign': Flags.string({ description: 'Campaign ID (UUID)', exclusive: ['ad-group'] }),
23
23
  'match-type': Flags.string({ default: 'EXACT', description: 'Match type', options: ['BROAD', 'EXACT'] }),
24
- status: Flags.string({ default: 'ACTIVE', description: 'Keyword status', options: ['ACTIVE', 'PAUSED'] }),
25
- text: Flags.string({ description: 'Keyword text, repeatable', multiple: true, required: true }),
24
+ 'status': Flags.string({ default: 'ACTIVE', description: 'Keyword status', options: ['ACTIVE', 'PAUSED'] }),
25
+ 'text': Flags.string({ description: 'Keyword text, repeatable', multiple: true, required: true }),
26
26
  };
27
27
  async run() {
28
28
  const { flags } = await this.parse(AsaNegativeKeywordsAdd);
29
29
  const target = flags['ad-group'] ?? flags.campaign;
30
- if (!target)
30
+ if (!target) {
31
31
  this.error('Pass either --ad-group or --campaign.', { exit: 2 });
32
- if (!isValidUuid(target))
32
+ }
33
+ if (!isValidUuid(target)) {
33
34
  this.error('Invalid ID format.', { exit: 2 });
35
+ }
34
36
  if (flags.text.length > MAX_BULK_ITEMS) {
35
37
  this.error(`A single call takes at most ${MAX_BULK_ITEMS} keywords, got ${flags.text.length}.`, { exit: 2 });
36
38
  }
39
+ // eslint-disable-next-line no-nested-ternary -- FIXME if you see this
37
40
  const scope = flags['ad-group'] ? 'AD_GROUP' : flags['all-ad-groups'] ? 'ALL_CAMPAIGN_AD_GROUPS' : 'CAMPAIGN';
38
41
  const parent = flags['ad-group'] ? { ad_group_id: flags['ad-group'] } : { campaign_id: flags.campaign };
39
42
  const body = {
40
- negative_keywords: flags.text.map((text) => ({
43
+ negative_keywords: flags.text.map(text => ({
41
44
  ...parent,
42
45
  match_type: flags['match-type'],
43
46
  status: flags.status,
@@ -53,7 +56,7 @@ export default class AsaNegativeKeywordsAdd extends Command {
53
56
  ? `Add ${flags.text.length} negative keyword(s) to every ad group of the campaign`
54
57
  : `Add ${flags.text.length} negative keyword(s) in ${scope} scope`,
55
58
  }, flags.yes);
56
- const client = await createAsaClient(this.config);
59
+ const client = await createAsaClient(this);
57
60
  const { replayed, result } = await asaWrite(client, 'post', '/negative-keywords', {
58
61
  body,
59
62
  idempotencyKey: flags['idempotency-key'],
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { AsaNegativeKeywordDTO } from '../../../lib/asa-schemas.js';
3
- import { type PaginatedResponse } from '../../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../../lib/flags.js';
4
4
  export default class AsaNegativeKeywordsList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;
@@ -17,7 +17,7 @@ export default class AsaNegativeKeywordsList extends Command {
17
17
  };
18
18
  async run() {
19
19
  const { flags } = await this.parse(AsaNegativeKeywordsList);
20
- const client = await createAsaClient(this.config);
20
+ const client = await createAsaClient(this);
21
21
  const result = await client.get('/negative-keywords', {
22
22
  ...paginationParams(flags),
23
23
  ...scopeParams(flags),
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { AsaCampaignGroupDTO } from '../../../lib/asa-schemas.js';
3
- import { type PaginatedResponse } from '../../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../../lib/flags.js';
4
4
  export default class AsaOrgsList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;
@@ -10,7 +10,7 @@ export default class AsaOrgsList extends Command {
10
10
  static flags = { ...asaPaginationFlags };
11
11
  async run() {
12
12
  const { flags } = await this.parse(AsaOrgsList);
13
- const client = await createAsaClient(this.config);
13
+ const client = await createAsaClient(this);
14
14
  const result = await client.get('/campaign-groups', paginationParams(flags));
15
15
  printList(result.data, this.log.bind(this), result.meta.pagination);
16
16
  return result;
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { AsaProductPageDTO } from '../../../lib/asa-schemas.js';
3
- import { type PaginatedResponse } from '../../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../../lib/flags.js';
4
4
  export default class AsaProductPagesList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;
@@ -13,7 +13,7 @@ export default class AsaProductPagesList extends Command {
13
13
  static flags = { ...asaPaginationFlags, ...assetScopeFlags };
14
14
  async run() {
15
15
  const { flags } = await this.parse(AsaProductPagesList);
16
- const client = await createAsaClient(this.config);
16
+ const client = await createAsaClient(this);
17
17
  const result = await client.get('/product-pages', {
18
18
  ...paginationParams(flags),
19
19
  ...scopeParams(flags),
@@ -16,7 +16,7 @@ export default class AsaProductPagesSync extends Command {
16
16
  const { flags } = await this.parse(AsaProductPagesSync);
17
17
  const body = { ...(flags['adam-id'] === undefined ? {} : { adam_id: flags['adam-id'] }) };
18
18
  await confirmMutation(this, { body, method: 'POST', path: '/product-pages/sync/', summary: 'Queue a product page refresh from Apple' }, flags.yes);
19
- const client = await createAsaClient(this.config);
19
+ const client = await createAsaClient(this);
20
20
  const { result } = await asaWrite(client, 'post', '/product-pages/sync', {
21
21
  body,
22
22
  idempotencyKey: flags['idempotency-key'],
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { AsaSearchTermDTO } from '../../../lib/asa-schemas.js';
3
- import { type PaginatedResponse } from '../../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../../lib/flags.js';
4
4
  export default class AsaSearchTermsList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;
@@ -13,7 +13,7 @@ export default class AsaSearchTermsList extends Command {
13
13
  static flags = { ...asaPaginationFlags, ...periodFlags, ...adGroupScopeFlags };
14
14
  async run() {
15
15
  const { flags } = await this.parse(AsaSearchTermsList);
16
- const client = await createAsaClient(this.config);
16
+ const client = await createAsaClient(this);
17
17
  const result = await client.get('/search-terms', {
18
18
  ...paginationParams(flags),
19
19
  ...periodParams(flags),
@@ -2,12 +2,17 @@ import { Command } from '@oclif/core';
2
2
  import { createAsaClient } from '../../lib/asa-client.js';
3
3
  import { printResponse } from '../../lib/output.js';
4
4
  export default class AsaWhoami extends Command {
5
- static description = 'Show which company the token unlocks and whether Apple Ads is connected';
5
+ static description = `Show which company the token unlocks, whether Apple Ads is connected, and the request budgets it gets
6
+
7
+ Limits are raised per company, so read them here rather than assuming the defaults: metrics_limit_per_minute
8
+ and metrics_burst_limit govern asa metrics, keywords_read_limit_per_minute the keyword lists,
9
+ metrics_inflight_limit how many analytics calls may overlap, and max_breakdown_rows_per_page the size a
10
+ grouped page may project to before it is refused.`;
6
11
  static enableJsonFlag = true;
7
12
  static examples = ['<%= config.bin %> asa whoami'];
8
13
  async run() {
9
14
  await this.parse(AsaWhoami);
10
- const client = await createAsaClient(this.config);
15
+ const client = await createAsaClient(this);
11
16
  const result = await client.get('/me');
12
17
  printResponse(result, this.log.bind(this));
13
18
  if (result.apple_credentials_status !== 'active') {
@@ -14,6 +14,7 @@ export default class AuthLogin extends Command {
14
14
  static description = 'Authenticate with Adapty via browser';
15
15
  static examples = ['<%= config.bin %> auth login'];
16
16
  async run() {
17
+ await this.parse(AuthLogin);
17
18
  const config = await readConfig(this.config.configDir);
18
19
  if (config.access_token && config.user) {
19
20
  this.log(`Already authenticated as ${config.user.email}. Re-authenticating...`);
@@ -31,7 +32,7 @@ export default class AuthLogin extends Command {
31
32
  const verificationUrl = this.verificationUrl(device.verification_uri_complete);
32
33
  this.log(`\nYour code: ${device.user_code}\n`);
33
34
  this.log(`If browser doesn't open, visit: ${verificationUrl}\n`);
34
- if (process.stdin.isTTY === true) {
35
+ if (process.stdin.isTTY) {
35
36
  try {
36
37
  await open(verificationUrl);
37
38
  }
@@ -46,6 +47,7 @@ export default class AuthLogin extends Command {
46
47
  // Handle Ctrl+C
47
48
  const onSignal = () => {
48
49
  this.log('\nLogin cancelled.');
50
+ // eslint-disable-next-line n/no-process-exit -- FIXME if you see this
49
51
  process.exit(0);
50
52
  };
51
53
  process.on('SIGINT', onSignal);
@@ -6,8 +6,8 @@ export default class FlowsConfigGet extends Command {
6
6
  static args = {
7
7
  flow_id: Args.string({ description: 'Flow ID (UUID)', required: true }),
8
8
  };
9
- static description = 'Read the flow builder config (404 until the config has been written at least once). ' +
10
- 'On a failed publish, `publication_status`, `transform_error` and `publication_error` show why.';
9
+ static description = 'Read the flow builder config (404 until the config has been written at least once). '
10
+ + 'On a failed publish, `publication_status`, `transform_error` and `publication_error` show why.';
11
11
  static enableJsonFlag = true;
12
12
  static examples = ['<%= config.bin %> flows config get --app UUID 550e8400-e29b-41d4-a716-446655440000'];
13
13
  static flags = {
@@ -1,7 +1,7 @@
1
1
  import { Command } from '@oclif/core';
2
- export interface PreviewResult {
2
+ export type PreviewResult = {
3
3
  render_url: string;
4
- }
4
+ };
5
5
  export default class FlowsConfigPreview extends Command {
6
6
  static args: {
7
7
  config_file: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
@@ -1,6 +1,6 @@
1
- import { Args, Command, Flags } from '@oclif/core';
2
1
  import { readFile } from 'node:fs/promises';
3
2
  import { resolve } from 'node:path';
3
+ import { Args, Command, Flags } from '@oclif/core';
4
4
  import open from 'open';
5
5
  import { APP_URL_ENV_VAR } from '../../../lib/app-url.js';
6
6
  import { buildRenderUrl, DEFAULT_DEVICE_ID, DEFAULT_ORIENTATION, normalizePreviewConfig, ORIENTATIONS, } from '../../../lib/preview.js';
@@ -26,7 +26,7 @@ export default class FlowsConfigPreview extends Command {
26
26
  description: 'Device orientation to render in',
27
27
  options: [...ORIENTATIONS],
28
28
  }),
29
- screen: Flags.string({ description: "Screen ID to render (default: the flow's first screen)" }),
29
+ screen: Flags.string({ description: 'Screen ID to render (default: the flow\'s first screen)' }),
30
30
  };
31
31
  async run() {
32
32
  const { args, flags } = await this.parse(FlowsConfigPreview);
@@ -47,17 +47,19 @@ export default class FlowsConfigPreview extends Command {
47
47
  }
48
48
  let renderUrl;
49
49
  try {
50
+ // eslint-disable-next-line @stylistic/max-len -- FIXME if you see this
50
51
  renderUrl = buildRenderUrl({ device: flags.device, orientation: flags.orientation, screen: flags.screen }, payload);
51
52
  }
52
53
  catch (error) {
53
54
  this.error(describeError(error), { exit: 2 });
54
55
  }
55
56
  const result = { render_url: renderUrl };
56
- if (this.jsonEnabled())
57
+ if (this.jsonEnabled()) {
57
58
  return result;
59
+ }
58
60
  // Piped output stays a bare URL so it composes — the whole config rides in the fragment, which
59
61
  // is why a TTY gets the browser opened instead of a screenful of base64.
60
- if (process.stdout.isTTY !== true) {
62
+ if (!process.stdout.isTTY) {
61
63
  this.log(renderUrl);
62
64
  return result;
63
65
  }
@@ -1,5 +1,5 @@
1
- import { Args, Command, Flags } from '@oclif/core';
2
1
  import { readFile } from 'node:fs/promises';
2
+ import { Args, Command, Flags } from '@oclif/core';
3
3
  import { createAuthenticatedClient } from '../../../lib/client-from-config.js';
4
4
  import { appFlag, isValidUuid } from '../../../lib/flags.js';
5
5
  import { printResponse } from '../../../lib/output.js';
@@ -16,7 +16,7 @@ export default class FlowsConfigUpdate extends Command {
16
16
  ];
17
17
  static flags = {
18
18
  ...appFlag,
19
- config: Flags.string({
19
+ 'config': Flags.string({
20
20
  description: 'Builder config as a JSON string',
21
21
  exactlyOne: ['config', 'config-file'],
22
22
  }),
@@ -50,6 +50,7 @@ export default class FlowsConfigUpdate extends Command {
50
50
  printResponse(result, this.log.bind(this));
51
51
  return result;
52
52
  }
53
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- FIXME if you see this
53
54
  parseJson(raw, label) {
54
55
  try {
55
56
  return JSON.parse(raw);
@@ -77,8 +78,9 @@ export default class FlowsConfigUpdate extends Command {
77
78
  }
78
79
  async readStdin() {
79
80
  const chunks = [];
80
- for await (const chunk of process.stdin)
81
+ for await (const chunk of process.stdin) {
81
82
  chunks.push(chunk);
83
+ }
82
84
  return Buffer.concat(chunks).toString('utf8');
83
85
  }
84
86
  }
@@ -1,5 +1,5 @@
1
- import { Args, Command, Flags } from '@oclif/core';
2
1
  import { readFile } from 'node:fs/promises';
2
+ import { Args, Command, Flags } from '@oclif/core';
3
3
  import { createAuthenticatedClient } from '../../../lib/client-from-config.js';
4
4
  import { appFlag, isValidUuid } from '../../../lib/flags.js';
5
5
  import { printResponse } from '../../../lib/output.js';
@@ -16,7 +16,7 @@ export default class FlowsConfigValidate extends Command {
16
16
  ];
17
17
  static flags = {
18
18
  ...appFlag,
19
- config: Flags.string({
19
+ 'config': Flags.string({
20
20
  description: 'Builder config as a JSON string',
21
21
  exactlyOne: ['config', 'config-file'],
22
22
  }),
@@ -43,6 +43,7 @@ export default class FlowsConfigValidate extends Command {
43
43
  }
44
44
  return result;
45
45
  }
46
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- FIXME if you see this
46
47
  parseJson(raw, label) {
47
48
  try {
48
49
  return JSON.parse(raw);
@@ -70,8 +71,9 @@ export default class FlowsConfigValidate extends Command {
70
71
  }
71
72
  async readStdin() {
72
73
  const chunks = [];
73
- for await (const chunk of process.stdin)
74
+ for await (const chunk of process.stdin) {
74
75
  chunks.push(chunk);
76
+ }
75
77
  return Buffer.concat(chunks).toString('utf8');
76
78
  }
77
79
  }
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { FlowDTO } from '../../lib/api-schemas.js';
3
- import { type PaginatedResponse } from '../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../lib/flags.js';
4
4
  export default class FlowsList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;
@@ -1,6 +1,6 @@
1
- import { Args, Command } from '@oclif/core';
2
1
  import { readFile } from 'node:fs/promises';
3
2
  import { basename, extname } from 'node:path';
3
+ import { Args, Command } from '@oclif/core';
4
4
  import { createAuthenticatedClient } from '../../../lib/client-from-config.js';
5
5
  import { appFlag } from '../../../lib/flags.js';
6
6
  import { printResponse } from '../../../lib/output.js';
@@ -9,8 +9,8 @@ export default class FlowsPublish extends Command {
9
9
  static args = {
10
10
  flow_id: Args.string({ description: 'Flow ID (UUID)', required: true }),
11
11
  };
12
- static description = 'Publish a flow (async — publication completes in the background). ' +
13
- 'Publishing is async: returns status `publishing`. Poll `adapty flows get <flow_id>` for `published`/`publication_failed`; on failure, `adapty flows config get <flow_id>` shows why.';
12
+ static description = 'Publish a flow (async — publication completes in the background). '
13
+ + 'Publishing is async: returns status `publishing`. Poll `adapty flows get <flow_id>` for `published`/`publication_failed`; on failure, `adapty flows config get <flow_id>` shows why.';
14
14
  static enableJsonFlag = true;
15
15
  static examples = ['<%= config.bin %> flows publish --app UUID 550e8400-e29b-41d4-a716-446655440000'];
16
16
  static flags = {
@@ -35,9 +35,9 @@ export default class FlowsPublish extends Command {
35
35
  }
36
36
  catch (error) {
37
37
  if (error instanceof ApiError && (error.statusCode === 400 || error.errorCode === 'validation_error')) {
38
- this.error(`Flow publish failed: ${error.message}\n` +
39
- 'Publishing needs a flow with a valid config. Fix it, then run `adapty flows publish` again:\n' +
40
- flowFixLinks(args.flow_id), { exit: 1 });
38
+ this.error(`Flow publish failed: ${error.message}\n`
39
+ + 'Publishing needs a flow with a valid config. Fix it, then run `adapty flows publish` again:\n'
40
+ + flowFixLinks(args.flow_id), { exit: 1 });
41
41
  }
42
42
  throw error;
43
43
  }
@@ -15,7 +15,7 @@ export default class PaywallsCreate extends Command {
15
15
  multiple: true,
16
16
  required: true,
17
17
  }),
18
- title: Flags.string({ description: 'Paywall title', required: true }),
18
+ 'title': Flags.string({ description: 'Paywall title', required: true }),
19
19
  };
20
20
  async run() {
21
21
  const { flags } = await this.parse(PaywallsCreate);
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { PaywallDTO } from '../../lib/api-schemas.js';
3
- import { type PaginatedResponse } from '../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../lib/flags.js';
4
4
  export default class PaywallsList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;
@@ -1,8 +1,8 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { PlacementSummaryDTO } from '../../lib/api-schemas.js';
3
- interface PlacementsByPaywallResponse {
3
+ type PlacementsByPaywallResponse = {
4
4
  data: PlacementSummaryDTO[];
5
- }
5
+ };
6
6
  export default class PaywallsPlacements extends Command {
7
7
  static args: {
8
8
  paywall_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
@@ -18,7 +18,7 @@ export default class PaywallsUpdate extends Command {
18
18
  multiple: true,
19
19
  required: true,
20
20
  }),
21
- title: Flags.string({ description: 'Paywall title', required: true }),
21
+ 'title': Flags.string({ description: 'Paywall title', required: true }),
22
22
  };
23
23
  async run() {
24
24
  const { args, flags } = await this.parse(PaywallsUpdate);
@@ -14,11 +14,11 @@ export default class PlacementsCreate extends Command {
14
14
  ];
15
15
  static flags = {
16
16
  ...appFlag,
17
- audiences: Flags.string({
18
- description: 'JSON array of audience entries. Every entry needs an explicit content_type. ' +
19
- 'Paywall: {content_type:"paywall", segment_ids, paywall_id, priority}. ' +
20
- 'Flow: {content_type:"flow", segment_ids, flow_id, priority}. ' +
21
- 'A flow must be published first (flows publish) — attaching a draft flow returns 400.',
17
+ 'audiences': Flags.string({
18
+ description: 'JSON array of audience entries. Every entry needs an explicit content_type. '
19
+ + 'Paywall: {content_type:"paywall", segment_ids, paywall_id, priority}. '
20
+ + 'Flow: {content_type:"flow", segment_ids, flow_id, priority}. '
21
+ + 'A flow must be published first (flows publish) — attaching a draft flow returns 400.',
22
22
  exactlyOne: ['paywall-id', 'audiences'],
23
23
  }),
24
24
  'developer-id': Flags.string({ description: 'Developer ID for the placement', required: true }),
@@ -26,7 +26,7 @@ export default class PlacementsCreate extends Command {
26
26
  description: 'Paywall ID (UUID). DEPRECATED: use --audiences.',
27
27
  exactlyOne: ['paywall-id', 'audiences'],
28
28
  }),
29
- title: Flags.string({ description: 'Placement title', required: true }),
29
+ 'title': Flags.string({ description: 'Placement title', required: true }),
30
30
  };
31
31
  async run() {
32
32
  const { flags } = await this.parse(PlacementsCreate);
@@ -37,13 +37,15 @@ export default class PlacementsCreate extends Command {
37
37
  title: flags.title,
38
38
  };
39
39
  if (flags['paywall-id']) {
40
- process.stderr.write('⚠️ --paywall-id is deprecated. Use --audiences instead.\n' +
41
- ' `paywall_id` will be removed from the API in a future release.\n');
40
+ process.stderr.write('⚠️ --paywall-id is deprecated. Use --audiences instead.\n'
41
+ + ' `paywall_id` will be removed from the API in a future release.\n');
42
+ // eslint-disable-next-line @typescript-eslint/no-deprecated -- FIXME if you see this
42
43
  body.paywall_id = flags['paywall-id'];
43
44
  }
44
45
  else {
45
46
  let parsed;
46
47
  try {
48
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME if you see this
47
49
  parsed = JSON.parse(flags.audiences);
48
50
  }
49
51
  catch (error) {
@@ -52,12 +54,14 @@ export default class PlacementsCreate extends Command {
52
54
  if (!Array.isArray(parsed)) {
53
55
  this.error('--audiences must be a JSON array of audience entries.', { exit: 2 });
54
56
  }
55
- for (const [index, entry] of parsed.entries()) {
57
+ const entries = parsed;
58
+ for (const [index, entry] of entries.entries()) {
56
59
  const problem = audienceEntryProblem(entry);
57
- if (problem)
60
+ if (problem) {
58
61
  this.error(`--audiences[${index}]: ${problem}`, { exit: 2 });
62
+ }
59
63
  }
60
- body.audiences = parsed;
64
+ body.audiences = entries;
61
65
  }
62
66
  const client = await createAuthenticatedClient(this.config);
63
67
  let result;
@@ -66,8 +70,9 @@ export default class PlacementsCreate extends Command {
66
70
  }
67
71
  catch (error) {
68
72
  const message = draftFlowError(error, flags.app, body.audiences);
69
- if (message)
73
+ if (message) {
70
74
  this.error(message, { exit: 2 });
75
+ }
71
76
  throw error;
72
77
  }
73
78
  this.log('Placement created!');
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { PlacementSummaryDTO } from '../../lib/api-schemas.js';
3
- import { type PaginatedResponse } from '../../lib/flags.js';
3
+ import type { PaginatedResponse } from '../../lib/flags.js';
4
4
  export default class PlacementsList extends Command {
5
5
  static description: string;
6
6
  static enableJsonFlag: boolean;