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.
Files changed (107) hide show
  1. package/README.md +133 -3
  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.d.ts +9 -0
  22. package/dist/commands/asa/automations/create.js +26 -7
  23. package/dist/commands/asa/automations/get.js +3 -2
  24. package/dist/commands/asa/automations/list.d.ts +1 -1
  25. package/dist/commands/asa/automations/list.js +1 -1
  26. package/dist/commands/asa/automations/run.js +5 -3
  27. package/dist/commands/asa/automations/runs.d.ts +1 -1
  28. package/dist/commands/asa/automations/runs.js +4 -4
  29. package/dist/commands/asa/automations/update.d.ts +9 -0
  30. package/dist/commands/asa/automations/update.js +36 -12
  31. package/dist/commands/asa/campaigns/bulk-create.js +31 -18
  32. package/dist/commands/asa/campaigns/bulk-list.js +7 -5
  33. package/dist/commands/asa/campaigns/bulk-status.js +3 -2
  34. package/dist/commands/asa/campaigns/create.js +10 -8
  35. package/dist/commands/asa/campaigns/get.js +3 -2
  36. package/dist/commands/asa/campaigns/list.d.ts +1 -1
  37. package/dist/commands/asa/campaigns/list.js +1 -1
  38. package/dist/commands/asa/campaigns/update.js +25 -15
  39. package/dist/commands/asa/competitors/summary.js +5 -5
  40. package/dist/commands/asa/connect.js +5 -3
  41. package/dist/commands/asa/creatives/list.d.ts +1 -1
  42. package/dist/commands/asa/creatives/list.js +1 -1
  43. package/dist/commands/asa/keywords/add.js +13 -10
  44. package/dist/commands/asa/keywords/list.d.ts +1 -1
  45. package/dist/commands/asa/keywords/list.js +1 -1
  46. package/dist/commands/asa/keywords/update.js +15 -10
  47. package/dist/commands/asa/metrics/index.d.ts +6 -3
  48. package/dist/commands/asa/metrics/index.js +38 -14
  49. package/dist/commands/asa/metrics/overview.js +3 -3
  50. package/dist/commands/asa/negative-keywords/add.js +10 -7
  51. package/dist/commands/asa/negative-keywords/list.d.ts +1 -1
  52. package/dist/commands/asa/negative-keywords/list.js +1 -1
  53. package/dist/commands/asa/orgs/list.d.ts +1 -1
  54. package/dist/commands/asa/orgs/list.js +1 -1
  55. package/dist/commands/asa/product-pages/list.d.ts +1 -1
  56. package/dist/commands/asa/product-pages/list.js +1 -1
  57. package/dist/commands/asa/product-pages/sync.js +1 -1
  58. package/dist/commands/asa/search-terms/list.d.ts +1 -1
  59. package/dist/commands/asa/search-terms/list.js +1 -1
  60. package/dist/commands/asa/whoami.js +7 -2
  61. package/dist/commands/auth/login.js +3 -1
  62. package/dist/commands/flows/config/get.js +2 -2
  63. package/dist/commands/flows/config/preview.d.ts +2 -2
  64. package/dist/commands/flows/config/preview.js +6 -4
  65. package/dist/commands/flows/config/update.js +5 -3
  66. package/dist/commands/flows/config/validate.js +5 -3
  67. package/dist/commands/flows/list.d.ts +1 -1
  68. package/dist/commands/flows/media/upload.js +1 -1
  69. package/dist/commands/flows/publish.js +5 -5
  70. package/dist/commands/paywalls/create.js +1 -1
  71. package/dist/commands/paywalls/list.d.ts +1 -1
  72. package/dist/commands/paywalls/placements.d.ts +2 -2
  73. package/dist/commands/paywalls/update.js +1 -1
  74. package/dist/commands/placements/create.js +17 -12
  75. package/dist/commands/placements/list.d.ts +1 -1
  76. package/dist/commands/placements/update.js +20 -15
  77. package/dist/commands/products/create.js +20 -13
  78. package/dist/commands/products/list.d.ts +1 -1
  79. package/dist/commands/products/update.js +1 -1
  80. package/dist/commands/segments/list.d.ts +1 -1
  81. package/dist/lib/api-client.d.ts +10 -6
  82. package/dist/lib/api-client.js +56 -35
  83. package/dist/lib/api-schemas.d.ts +56 -56
  84. package/dist/lib/app-url.js +2 -1
  85. package/dist/lib/asa-client.d.ts +13 -8
  86. package/dist/lib/asa-client.js +9 -4
  87. package/dist/lib/asa-flags.d.ts +37 -13
  88. package/dist/lib/asa-flags.js +87 -20
  89. package/dist/lib/asa-keyword-action.d.ts +18 -0
  90. package/dist/lib/asa-keyword-action.js +175 -0
  91. package/dist/lib/asa-schemas.d.ts +100 -80
  92. package/dist/lib/auth.js +2 -1
  93. package/dist/lib/client-from-config.d.ts +1 -1
  94. package/dist/lib/client-from-config.js +2 -1
  95. package/dist/lib/config.d.ts +2 -2
  96. package/dist/lib/confirm.d.ts +4 -4
  97. package/dist/lib/confirm.js +12 -7
  98. package/dist/lib/errors.d.ts +18 -18
  99. package/dist/lib/errors.js +14 -10
  100. package/dist/lib/flags.d.ts +3 -3
  101. package/dist/lib/flags.js +2 -1
  102. package/dist/lib/flow-help.js +11 -6
  103. package/dist/lib/output.js +23 -12
  104. package/dist/lib/preview.d.ts +5 -5
  105. package/dist/lib/preview.js +2 -1
  106. package/oclif.manifest.json +372 -200
  107. package/package.json +10 -8
@@ -1,17 +1,17 @@
1
- export interface ApiErrorBody {
2
- detail?: string;
3
- error?: string;
4
- error_code?: string;
5
- errors?: Record<string, string[]>;
6
- retry_after_seconds?: number;
7
- status_code?: number;
8
- }
1
+ export type ApiErrorBody = {
2
+ detail?: string | undefined;
3
+ error?: string | undefined;
4
+ error_code?: string | undefined;
5
+ errors?: Record<string, string[]> | undefined;
6
+ retry_after_seconds?: number | undefined;
7
+ status_code?: number | undefined;
8
+ };
9
9
  export type ApiErrorFormat = 'asa' | 'developer';
10
- export interface ApiErrorOptions {
11
- detail?: string;
12
- retryAfterSeconds?: number;
13
- }
14
- export interface ListedError {
10
+ export type ApiErrorOptions = {
11
+ detail?: string | undefined;
12
+ retryAfterSeconds?: number | undefined;
13
+ };
14
+ export type ListedError = {
15
15
  apple_error_code?: null | string;
16
16
  apple_error_message?: null | string;
17
17
  error_code?: string;
@@ -20,18 +20,18 @@ export interface ListedError {
20
20
  message?: string;
21
21
  validation_error_code?: string;
22
22
  validation_error_message?: string;
23
- }
23
+ };
24
24
  export declare function describeListedError(error: ListedError): {
25
25
  code: string | undefined;
26
26
  text: string;
27
27
  };
28
28
  export declare class ApiError extends Error {
29
- statusCode: number;
29
+ code?: string | undefined;
30
+ detail?: string | undefined;
30
31
  errorCode: string;
31
32
  fieldErrors: Record<string, string[]>;
32
- code?: string;
33
- detail?: string;
34
- retryAfterSeconds?: number;
33
+ retryAfterSeconds?: number | undefined;
34
+ statusCode: number;
35
35
  constructor(statusCode: number, errorCode: string, fieldErrors: Record<string, string[]>, opts?: ApiErrorOptions);
36
36
  private static humanMessage;
37
37
  toHuman(): string;
@@ -2,33 +2,36 @@ export function describeListedError(error) {
2
2
  const code = error.error_code ?? error.apple_error_code ?? error.validation_error_code ?? undefined;
3
3
  const reason = error.message ?? error.apple_error_message ?? error.validation_error_message ?? code ?? 'rejected';
4
4
  const position = error.input_ref === null || error.input_ref === undefined ? '' : ` (item ${error.input_ref + 1})`;
5
- return { code, text: `${reason}${position}` };
5
+ const field = error.field_name ? `${error.field_name}: ` : '';
6
+ return { code, text: `${field}${reason}${position}` };
6
7
  }
7
8
  export class ApiError extends Error {
8
- statusCode;
9
- errorCode;
10
- fieldErrors;
11
9
  // Read by oclif's prettyPrint to render a `Code: ...` line under the message.
12
10
  code;
13
11
  detail;
12
+ errorCode;
13
+ fieldErrors;
14
14
  retryAfterSeconds;
15
+ statusCode;
15
16
  constructor(statusCode, errorCode, fieldErrors, opts = {}) {
16
17
  // `message` is what oclif's default error renderer prints. Prefer the server's human text (an ASA
17
18
  // `detail` or the developer API's field errors) over the bare code, which reads as gibberish on its own.
18
19
  super(ApiError.humanMessage(errorCode, fieldErrors, opts.detail));
20
+ this.name = 'ApiError';
19
21
  this.statusCode = statusCode;
20
22
  this.errorCode = errorCode;
21
23
  this.fieldErrors = fieldErrors;
22
- this.name = 'ApiError';
23
24
  this.detail = opts.detail;
24
25
  this.retryAfterSeconds = opts.retryAfterSeconds;
25
26
  // Surface real server codes as a secondary line; hide synthetic `http_<status>` fallbacks.
26
- if (!errorCode.startsWith('http_'))
27
+ if (!errorCode.startsWith('http_')) {
27
28
  this.code = errorCode;
29
+ }
28
30
  }
29
31
  static humanMessage(errorCode, fieldErrors, detail) {
30
- if (detail)
32
+ if (detail) {
31
33
  return detail;
34
+ }
32
35
  const parts = [];
33
36
  for (const [field, msgs] of Object.entries(fieldErrors)) {
34
37
  for (const msg of msgs) {
@@ -85,8 +88,8 @@ function parseListedErrors(errors, statusCode, opts) {
85
88
  fieldErrors[item.field_name] = [...(fieldErrors[item.field_name] ?? []), item.message];
86
89
  }
87
90
  }
88
- const described = errors.map((item) => describeListedError(item));
89
- const detail = described.map((item) => item.text).join('; ');
91
+ const described = errors.map(item => describeListedError(item));
92
+ const detail = described.map(item => item.text).join('; ');
90
93
  return new ApiError(statusCode, described[0]?.code ?? `http_${statusCode}`, fieldErrors, {
91
94
  ...opts,
92
95
  detail: detail || undefined,
@@ -110,8 +113,9 @@ export function parseApiError(statusCode, body, opts = {}, format = 'developer')
110
113
  const fieldErrors = {};
111
114
  for (const item of parsed.detail) {
112
115
  const field = (item.loc ?? []).slice(1).join('.') || 'body';
113
- if (item.msg)
116
+ if (item.msg) {
114
117
  fieldErrors[field] = [...(fieldErrors[field] ?? []), item.msg];
118
+ }
115
119
  }
116
120
  return new ApiError(statusCode, `http_${statusCode}`, fieldErrors, opts);
117
121
  }
@@ -2,7 +2,7 @@ export declare function isValidUuid(value: string): boolean;
2
2
  export declare const appFlag: {
3
3
  app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
4
4
  };
5
- export interface PaginatedResponse<T> {
5
+ export type PaginatedResponse<T> = {
6
6
  data: T[];
7
7
  meta: {
8
8
  pagination: {
@@ -11,12 +11,12 @@ export interface PaginatedResponse<T> {
11
11
  pages: number;
12
12
  };
13
13
  };
14
- }
14
+ };
15
15
  export declare const paginationFlags: {
16
16
  page: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
17
17
  'page-size': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
18
18
  };
19
19
  export declare function paginationParams(flags: {
20
- page: number;
20
+ 'page': number;
21
21
  'page-size': number;
22
22
  }): Record<string, string>;
package/dist/lib/flags.js CHANGED
@@ -6,6 +6,7 @@ export function isValidUuid(value) {
6
6
  export const appFlag = {
7
7
  app: Flags.string({
8
8
  description: 'App ID (UUID)',
9
+ // eslint-disable-next-line @typescript-eslint/require-await -- FIXME if you see this
9
10
  async parse(input) {
10
11
  if (!isValidUuid(input)) {
11
12
  throw new Error('Invalid app ID format. Run `adapty apps list` to find your app ID.');
@@ -16,7 +17,7 @@ export const appFlag = {
16
17
  }),
17
18
  };
18
19
  export const paginationFlags = {
19
- page: Flags.integer({
20
+ 'page': Flags.integer({
20
21
  default: 1,
21
22
  description: 'Page number',
22
23
  min: 1,
@@ -17,11 +17,16 @@ const DRAFT_FLOW_MARKER = 'Flow must be published before placing in a placement'
17
17
  * `flowId` is taken from the single flow audience, or `<FLOW_ID>` when it is ambiguous.
18
18
  */
19
19
  export function draftFlowError(error, app, audiences) {
20
- if (!(error instanceof ApiError) || !error.message.includes(DRAFT_FLOW_MARKER))
20
+ if (!(error instanceof ApiError) || !error.message.includes(DRAFT_FLOW_MARKER)) {
21
21
  return null;
22
- const flows = (audiences ?? []).filter((a) => a.content_type === 'flow' && typeof a.flow_id === 'string');
23
- const flowId = flows.length === 1 ? flows[0].flow_id : '<FLOW_ID>';
24
- return ('Cannot attach a draft flow to a placement — publish it first.\n' +
25
- `Publish: adapty flows publish --app ${app} ${flowId}\n` +
26
- flowFixLinks(flowId));
22
+ }
23
+ const flowIds = (audiences ?? [])
24
+ .filter(a => a.content_type === 'flow')
25
+ .map(a => a.flow_id)
26
+ .filter((id) => typeof id === 'string');
27
+ const onlyFlowId = flowIds.length === 1 ? flowIds[0] : undefined;
28
+ const flowId = onlyFlowId ?? '<FLOW_ID>';
29
+ return ('Cannot attach a draft flow to a placement — publish it first.\n'
30
+ + `Publish: adapty flows publish --app ${app} ${flowId}\n`
31
+ + flowFixLinks(flowId));
27
32
  }
@@ -3,10 +3,12 @@ function formatLabel(snakeKey) {
3
3
  return snakeKey
4
4
  .split('_')
5
5
  .map((w) => {
6
- if (w === 'ids')
6
+ if (w === 'ids') {
7
7
  return 'IDs';
8
- if (UPPER_WORDS.has(w))
8
+ }
9
+ if (UPPER_WORDS.has(w)) {
9
10
  return w.toUpperCase();
11
+ }
10
12
  return w.charAt(0).toUpperCase() + w.slice(1);
11
13
  })
12
14
  .join(' ');
@@ -18,19 +20,22 @@ function renderArrayItems(items, indent) {
18
20
  const childIndent = indent + ' ';
19
21
  const lines = [];
20
22
  for (const item of items) {
21
- if (item === undefined || item === null)
23
+ if (item === undefined || item === null) {
22
24
  continue;
25
+ }
23
26
  if (Array.isArray(item)) {
24
27
  lines.push(...renderArrayItems(item, childIndent));
25
28
  }
26
29
  else if (isScalar(item)) {
30
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string -- FIXME if you see this
27
31
  lines.push(`${indent}- ${String(item)}`);
28
32
  }
29
33
  else {
30
- const rendered = renderObject(item, childIndent);
31
- if (rendered.length === 0)
34
+ const [head, ...rest] = renderObject(item, childIndent);
35
+ if (head === undefined) {
32
36
  continue;
33
- lines.push(`${indent}- ${rendered[0].slice(childIndent.length)}`, ...rendered.slice(1));
37
+ }
38
+ lines.push(`${indent}- ${head.slice(childIndent.length)}`, ...rest);
34
39
  }
35
40
  }
36
41
  return lines;
@@ -38,13 +43,15 @@ function renderArrayItems(items, indent) {
38
43
  function renderObject(data, indent) {
39
44
  const lines = [];
40
45
  for (const [key, value] of Object.entries(data)) {
41
- if (value === undefined || value === null)
46
+ if (value === undefined || value === null) {
42
47
  continue;
48
+ }
43
49
  const label = `${indent}${formatLabel(key)}:`;
44
50
  if (Array.isArray(value)) {
45
- if (value.length === 0)
51
+ if (value.length === 0) {
46
52
  continue;
47
- if (value.every((v) => isScalar(v))) {
53
+ }
54
+ if (value.every(v => isScalar(v))) {
48
55
  lines.push(`${label} ${value.map(String).join(', ')}`);
49
56
  }
50
57
  else {
@@ -52,25 +59,29 @@ function renderObject(data, indent) {
52
59
  }
53
60
  }
54
61
  else if (isScalar(value)) {
62
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string -- FIXME if you see this
55
63
  lines.push(`${label} ${String(value)}`);
56
64
  }
57
65
  else {
58
66
  const nested = renderObject(value, indent + ' ');
59
- if (nested.length > 0)
67
+ if (nested.length > 0) {
60
68
  lines.push(label, ...nested);
69
+ }
61
70
  }
62
71
  }
63
72
  return lines;
64
73
  }
65
74
  export function printResponse(data, log) {
66
- for (const line of renderObject(data, ''))
75
+ for (const line of renderObject(data, '')) {
67
76
  log(line);
77
+ }
68
78
  }
69
79
  export function printList(items, log, pagination) {
70
80
  for (const [i, item] of items.entries()) {
71
81
  printResponse(item, log);
72
- if (i < items.length - 1)
82
+ if (i < items.length - 1) {
73
83
  log('---');
84
+ }
74
85
  }
75
86
  if (pagination) {
76
87
  log('');
@@ -5,10 +5,10 @@ export declare const DEFAULT_DEVICE_ID = "iphone-14";
5
5
  export declare const ORIENTATIONS: readonly ["landscape", "portrait"];
6
6
  export declare const DEFAULT_ORIENTATION = "portrait";
7
7
  /** Payload the render page expects. Wire format shared with the UI, hence camelCase. */
8
- export interface PreviewPayload {
8
+ export type PreviewPayload = {
9
9
  flow: Record<string, unknown>;
10
10
  remoteConfigs: unknown[];
11
- }
11
+ };
12
12
  /**
13
13
  * Accepts either a dashboard-api envelope (`{config, remote_configs, ...}`) or a bare
14
14
  * builder config, and returns the shape the render page injects.
@@ -18,10 +18,10 @@ export interface PreviewPayload {
18
18
  * rejected there instead — better to say so here, against the file the user named.
19
19
  */
20
20
  export declare function normalizePreviewConfig(raw: unknown): PreviewPayload;
21
- export interface RenderTarget {
21
+ export type RenderTarget = {
22
22
  device: string;
23
23
  orientation: string;
24
24
  /** Omitted lets the render page fall back to the flow's first screen. */
25
- screen?: string;
26
- }
25
+ screen?: string | undefined;
26
+ };
27
27
  export declare function buildRenderUrl(target: RenderTarget, payload: PreviewPayload): string;
@@ -39,8 +39,9 @@ function encodeConfigFragment(payload) {
39
39
  }
40
40
  export function buildRenderUrl(target, payload) {
41
41
  const url = appUrl(PREVIEW_PATH);
42
- if (target.screen)
42
+ if (target.screen) {
43
43
  url.searchParams.set('screen', target.screen);
44
+ }
44
45
  url.searchParams.set('device', target.device);
45
46
  url.searchParams.set('orientation', target.orientation);
46
47
  url.hash = `config=${encodeConfigFragment(payload)}`;