adapty 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/cli/base/adapty/flags.d.ts +65 -0
- package/dist/cli/base/adapty/flags.js +95 -0
- package/dist/cli/base/adapty/index.d.ts +1 -0
- package/dist/cli/base/adapty/index.js +1 -0
- package/dist/cli/base/attribution/flags.d.ts +3 -3
- package/dist/cli/base/attribution/flags.js +5 -20
- package/dist/cli/commands/analytics/catalog.d.ts +10 -0
- package/dist/cli/commands/analytics/catalog.js +52 -0
- package/dist/cli/commands/analytics/chart.d.ts +21 -0
- package/dist/cli/commands/analytics/chart.js +47 -0
- package/dist/cli/commands/analytics/cohort.d.ts +19 -0
- package/dist/cli/commands/analytics/cohort.js +40 -0
- package/dist/cli/commands/analytics/conversion.d.ts +20 -0
- package/dist/cli/commands/analytics/conversion.js +44 -0
- package/dist/cli/commands/analytics/funnel.d.ts +16 -0
- package/dist/cli/commands/analytics/funnel.js +32 -0
- package/dist/cli/commands/analytics/ltv.d.ts +19 -0
- package/dist/cli/commands/analytics/ltv.js +40 -0
- package/dist/cli/commands/analytics/retention.d.ts +17 -0
- package/dist/cli/commands/analytics/retention.js +41 -0
- package/dist/cli/commands/analytics/values.d.ts +11 -0
- package/dist/cli/commands/analytics/values.js +33 -0
- package/dist/cli/commands/attribution/report/command.js +6 -11
- package/dist/cli/commands/product-offers/create.d.ts +15 -0
- package/dist/cli/commands/product-offers/create.js +41 -0
- package/dist/cli/commands/product-offers/get.d.ts +13 -0
- package/dist/cli/commands/product-offers/get.js +16 -0
- package/dist/cli/commands/product-offers/list.d.ts +11 -0
- package/dist/cli/commands/product-offers/list.js +15 -0
- package/dist/cli/commands/product-offers/update.d.ts +20 -0
- package/dist/cli/commands/product-offers/update.js +41 -0
- package/dist/cli/errors.js +8 -1
- package/dist/cli/input/app.js +1 -11
- package/dist/cli/input/filter.d.ts +11 -0
- package/dist/cli/input/filter.js +16 -0
- package/dist/cli/input/offer.d.ts +3 -0
- package/dist/cli/input/offer.js +9 -0
- package/dist/cli/input/period.d.ts +10 -0
- package/dist/cli/input/period.js +23 -0
- package/dist/cli/input/product.d.ts +3 -0
- package/dist/cli/input/product.js +9 -0
- package/dist/cli/input/uuid.d.ts +6 -0
- package/dist/cli/input/uuid.js +11 -0
- package/dist/cli/views/analytics/csv.d.ts +3 -0
- package/dist/cli/views/analytics/csv.js +16 -0
- package/dist/cli/views/analytics/human.d.ts +41 -0
- package/dist/cli/views/analytics/human.js +134 -0
- package/dist/cli/views/analytics/segments.d.ts +68 -0
- package/dist/cli/views/analytics/segments.js +189 -0
- package/dist/commands/analytics/catalog.d.ts +1 -0
- package/dist/commands/analytics/catalog.js +2 -0
- package/dist/commands/analytics/chart.d.ts +1 -0
- package/dist/commands/analytics/chart.js +2 -0
- package/dist/commands/analytics/cohort.d.ts +1 -0
- package/dist/commands/analytics/cohort.js +2 -0
- package/dist/commands/analytics/conversion.d.ts +1 -0
- package/dist/commands/analytics/conversion.js +2 -0
- package/dist/commands/analytics/funnel.d.ts +1 -0
- package/dist/commands/analytics/funnel.js +2 -0
- package/dist/commands/analytics/ltv.d.ts +1 -0
- package/dist/commands/analytics/ltv.js +2 -0
- package/dist/commands/analytics/retention.d.ts +1 -0
- package/dist/commands/analytics/retention.js +2 -0
- package/dist/commands/analytics/values.d.ts +1 -0
- package/dist/commands/analytics/values.js +2 -0
- package/dist/commands/product-offers/create.d.ts +1 -0
- package/dist/commands/product-offers/create.js +2 -0
- package/dist/commands/product-offers/get.d.ts +1 -0
- package/dist/commands/product-offers/get.js +2 -0
- package/dist/commands/product-offers/list.d.ts +1 -0
- package/dist/commands/product-offers/list.js +2 -0
- package/dist/commands/product-offers/update.d.ts +1 -0
- package/dist/commands/product-offers/update.js +2 -0
- package/dist/lib/api-schemas.d.ts +1 -0
- package/dist/sdk/adapty/analytics/catalog.d.ts +51 -0
- package/dist/sdk/adapty/analytics/catalog.js +5 -0
- package/dist/sdk/adapty/analytics/chart.d.ts +41 -0
- package/dist/sdk/adapty/analytics/chart.js +6 -0
- package/dist/sdk/adapty/analytics/cohort.d.ts +79 -0
- package/dist/sdk/adapty/analytics/cohort.js +4 -0
- package/dist/sdk/adapty/analytics/conversion.d.ts +55 -0
- package/dist/sdk/adapty/analytics/conversion.js +7 -0
- package/dist/sdk/adapty/analytics/funnel.d.ts +41 -0
- package/dist/sdk/adapty/analytics/funnel.js +3 -0
- package/dist/sdk/adapty/analytics/index.d.ts +24 -0
- package/dist/sdk/adapty/analytics/index.js +13 -0
- package/dist/sdk/adapty/analytics/ltv.d.ts +27 -0
- package/dist/sdk/adapty/analytics/ltv.js +4 -0
- package/dist/sdk/adapty/analytics/model.d.ts +53 -0
- package/dist/sdk/adapty/analytics/model.js +12 -0
- package/dist/sdk/adapty/analytics/query.d.ts +48 -0
- package/dist/sdk/adapty/analytics/query.js +52 -0
- package/dist/sdk/adapty/analytics/renewal-periods.d.ts +23 -0
- package/dist/sdk/adapty/analytics/renewal-periods.js +27 -0
- package/dist/sdk/adapty/analytics/resource.d.ts +29 -0
- package/dist/sdk/adapty/analytics/resource.js +72 -0
- package/dist/sdk/adapty/analytics/retention.d.ts +32 -0
- package/dist/sdk/adapty/analytics/retention.js +6 -0
- package/dist/sdk/adapty/analytics/values.d.ts +20 -0
- package/dist/sdk/adapty/analytics/values.js +1 -0
- package/dist/sdk/adapty/index.d.ts +8 -0
- package/dist/sdk/adapty/index.js +6 -0
- package/dist/sdk/adapty/product-offers/create.d.ts +5 -0
- package/dist/sdk/adapty/product-offers/create.js +12 -0
- package/dist/sdk/adapty/product-offers/index.d.ts +9 -0
- package/dist/sdk/adapty/product-offers/index.js +5 -0
- package/dist/sdk/adapty/product-offers/model.d.ts +48 -0
- package/dist/sdk/adapty/product-offers/model.js +30 -0
- package/dist/sdk/adapty/product-offers/resource.d.ts +21 -0
- package/dist/sdk/adapty/product-offers/resource.js +28 -0
- package/dist/sdk/adapty/product-offers/update.d.ts +19 -0
- package/dist/sdk/adapty/product-offers/update.js +42 -0
- package/dist/sdk/attribution/index.d.ts +1 -1
- package/dist/sdk/attribution/index.js +1 -1
- package/dist/sdk/attribution/report.d.ts +0 -2
- package/dist/sdk/attribution/report.js +2 -26
- package/dist/sdk/core/dates.d.ts +15 -0
- package/dist/sdk/core/dates.js +34 -0
- package/dist/sdk/core/errors.d.ts +3 -0
- package/oclif.manifest.json +1163 -128
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -72,6 +72,19 @@ adapty products create --app UUID [flags]
|
|
|
72
72
|
adapty products update --app UUID PRODUCT_ID [flags]
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
### Product offers
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
adapty product-offers list --app UUID --product UUID
|
|
79
|
+
adapty product-offers get OFFER_ID --app UUID
|
|
80
|
+
adapty product-offers create --app UUID --product UUID --title "Spring" --type promotional|win_back [--ios-offer-id ID] [--android-offer-id ID]
|
|
81
|
+
adapty product-offers update OFFER_ID --app UUID [--title ...] [--type ...] [--ios-offer-id ID | --clear-ios-offer-id] [--android-offer-id ID | --clear-android-offer-id]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`list` returns every offer on one page. `create` needs at least one store offer id; `win_back` is App Store only.
|
|
85
|
+
`update` reads the offer and writes it back whole: it keeps every field you leave out, overwrites a dashboard edit made
|
|
86
|
+
in between, and refuses to clear the last store side. Introductory offers are read-only. Offers are deleted in the dashboard.
|
|
87
|
+
|
|
75
88
|
### Paywalls
|
|
76
89
|
|
|
77
90
|
```sh
|
|
@@ -618,6 +631,38 @@ too. A burst of 429s puts the token into an escalating cool-down (`cli_cooldown_
|
|
|
618
631
|
not waiting out the pause in a loop. An automation run is queued rather than awaited: `run` prints a run ID
|
|
619
632
|
and the outcome shows up in `adapty asa automations runs`.
|
|
620
633
|
|
|
634
|
+
### Analytics
|
|
635
|
+
|
|
636
|
+
The analytics of an app, as the dashboard shows them, live under `adapty analytics`: the charts, conversions, the
|
|
637
|
+
funnel, retention, LTV and cohorts, all on the Developer API with the same token.
|
|
638
|
+
|
|
639
|
+
```sh
|
|
640
|
+
adapty analytics catalog --app APP_UUID # operations, charts, conversions, filters
|
|
641
|
+
adapty analytics values --app APP_UUID --dimension country # what --filter country=... takes
|
|
642
|
+
adapty analytics chart --app APP_UUID --chart revenue --date-from 2026-07-01 --date-to 2026-09-30 \
|
|
643
|
+
--group-by country --compare-from 2026-04-01 --compare-to 2026-06-30
|
|
644
|
+
adapty analytics funnel --app APP_UUID --date-from 2026-07-01 --date-to 2026-09-30 --csv
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
Every data command (`chart`, `conversion`, `funnel`, `retention`, `ltv`, `cohort`) answers in one shape: the
|
|
648
|
+
number of the period, then segments with the total first (`is_total`), each group keyed by the raw backend value.
|
|
649
|
+
`--json` prints the API answer unchanged; `--csv` prints a table made from it (one row per group, total first; a
|
|
650
|
+
compared period in `compare.*` columns);
|
|
651
|
+
the human view prints a short table (one row per group, total first, money with 2 decimals, `—` for a missing
|
|
652
|
+
value) and `No data for this period.` for an empty window. The analytics numbers never add to the `attribution`
|
|
653
|
+
numbers. Dates are
|
|
654
|
+
inclusive days of `--timezone`, else the app time zone. Only `chart` and `conversion` take a compared period. Bad
|
|
655
|
+
input exits 2 before anything is sent; a refusal exits 4 with the API's error code; a missing token or an app the
|
|
656
|
+
token cannot access (403) exits 3; an Adapty that cannot be reached (no connection) exits 5 with
|
|
657
|
+
`Could not reach <url>`, or `code: network_error` and `status: 0` under `--json`. Each analytics route has its own
|
|
658
|
+
rate limits, as the Export API: 2 requests per second per app and 360 per minute for all callers together. Over a limit, the command exits 4 with the wait
|
|
659
|
+
(`retry_after_seconds` in `--json`).
|
|
660
|
+
|
|
661
|
+
The analytics queries are stricter than the Export API and the dashboard: a filter or grouping that the report does
|
|
662
|
+
not take is a 400 that names the field, never ignored; the funnel refuses the `cancellation_reason` filter; retention
|
|
663
|
+
and conversion group by the dashboard's retention list; retention, LTV, cohort and funnel take no compared period.
|
|
664
|
+
The full list is in `docs/agent/analytics.md`.
|
|
665
|
+
|
|
621
666
|
### Attribution
|
|
622
667
|
|
|
623
668
|
Attribution analytics across ad networks live under `adapty attribution` and talk to the attribution service
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AnalyticsFilter, PeriodUnit } from '../../../sdk/adapty/index.js';
|
|
2
|
+
/** The flags the analytics commands share. A flag left out leaves its field out: the backend default applies. */
|
|
3
|
+
/** Days of the query time zone: `--timezone`, else the app zone. */
|
|
4
|
+
export declare const periodFlags: {
|
|
5
|
+
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
/** Only the chart and the conversion take them: the other queries mix two periods into one. */
|
|
9
|
+
export declare const compareFlags: {
|
|
10
|
+
'compare-from': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'compare-to': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
export declare const filterFlags: {
|
|
14
|
+
filter: import("@oclif/core/interfaces").OptionFlag<AnalyticsFilter[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
export declare const groupByFlag: {
|
|
18
|
+
'group-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
};
|
|
20
|
+
/** The text differs per command: the period of one point, or the length of one cohort. */
|
|
21
|
+
export declare const granularityFlag: (description: string) => {
|
|
22
|
+
granularity: import("@oclif/core/interfaces").OptionFlag<"day" | "week" | "month" | "quarter" | "year" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
};
|
|
24
|
+
export declare const revenueBasisFlag: {
|
|
25
|
+
'revenue-basis': import("@oclif/core/interfaces").OptionFlag<"gross" | "proceeds" | "net" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
|
+
};
|
|
27
|
+
export declare const renewalPeriodFlags: {
|
|
28
|
+
'period-type': import("@oclif/core/interfaces").OptionFlag<"renewals" | "days" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
29
|
+
'renewal-days': import("@oclif/core/interfaces").OptionFlag<number[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
|
+
};
|
|
31
|
+
export declare const csvFlag: {
|
|
32
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
33
|
+
};
|
|
34
|
+
type QueryFlags = {
|
|
35
|
+
'app': string;
|
|
36
|
+
'date-from': string;
|
|
37
|
+
'date-to': string;
|
|
38
|
+
'filter'?: AnalyticsFilter[] | undefined;
|
|
39
|
+
'timezone'?: string | undefined;
|
|
40
|
+
};
|
|
41
|
+
/** Where the shared flags meet the sdk's field names. */
|
|
42
|
+
export declare const queryParams: (flags: QueryFlags) => {
|
|
43
|
+
appId: string;
|
|
44
|
+
dateFrom: string;
|
|
45
|
+
dateTo: string;
|
|
46
|
+
filters: AnalyticsFilter[] | undefined;
|
|
47
|
+
timezone: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
/** The compare flags as the sdk names them; a chart and a conversion take them. */
|
|
50
|
+
export declare const compareParams: (flags: {
|
|
51
|
+
"compare-from"?: string | undefined;
|
|
52
|
+
"compare-to"?: string | undefined;
|
|
53
|
+
}) => {
|
|
54
|
+
compareFrom: string | undefined;
|
|
55
|
+
compareTo: string | undefined;
|
|
56
|
+
};
|
|
57
|
+
/** The grouping and the period of one point as the sdk names them; a command without one of the flags leaves it out. */
|
|
58
|
+
export declare const groupingParams: (flags: {
|
|
59
|
+
"granularity"?: PeriodUnit | undefined;
|
|
60
|
+
"group-by"?: string | undefined;
|
|
61
|
+
}) => {
|
|
62
|
+
granularity: "day" | "week" | "month" | "quarter" | "year" | undefined;
|
|
63
|
+
groupBy: string | undefined;
|
|
64
|
+
};
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { periodTypes, periodUnits, revenueBases } from '../../../sdk/adapty/index.js';
|
|
3
|
+
import { usageError } from '../../errors.js';
|
|
4
|
+
import { splitFilter } from '../../input/filter.js';
|
|
5
|
+
import { dateParser, dayRangeFlags } from '../../input/period.js';
|
|
6
|
+
/** The flags the analytics commands share. A flag left out leaves its field out: the backend default applies. */
|
|
7
|
+
/** Days of the query time zone: `--timezone`, else the app zone. */
|
|
8
|
+
export const periodFlags = dayRangeFlags('in the --timezone zone, else the app time zone');
|
|
9
|
+
/** Only the chart and the conversion take them: the other queries mix two periods into one. */
|
|
10
|
+
export const compareFlags = {
|
|
11
|
+
'compare-from': Flags.string({
|
|
12
|
+
description: 'First day of a period to compare with, inclusive (YYYY-MM-DD); needs --compare-to',
|
|
13
|
+
parse: dateParser,
|
|
14
|
+
}),
|
|
15
|
+
'compare-to': Flags.string({
|
|
16
|
+
description: 'Last day of a period to compare with, inclusive (YYYY-MM-DD); needs --compare-from',
|
|
17
|
+
parse: dateParser,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* `dimension=value[,value]` with every value exactly as written. An empty value is a value: `country=` keeps the
|
|
22
|
+
* data without a country, as the dashboard filter does.
|
|
23
|
+
*/
|
|
24
|
+
const parseExactFilter = (input) => {
|
|
25
|
+
const filter = splitFilter(input);
|
|
26
|
+
return filter === undefined
|
|
27
|
+
? Promise.reject(usageError(`Expected dimension=value[,value] (an empty value is a value), got "${input}".`))
|
|
28
|
+
: Promise.resolve(filter);
|
|
29
|
+
};
|
|
30
|
+
export const filterFlags = {
|
|
31
|
+
filter: Flags.custom({
|
|
32
|
+
description: 'Keep the data whose dimension has one of the values: dimension=value[,value] (repeatable; `\\,` '
|
|
33
|
+
+ 'for a comma inside a value; values exactly as written, an empty one too, e.g. country= for no country). '
|
|
34
|
+
+ 'Dimensions: `adapty analytics catalog`; values: `adapty analytics values`',
|
|
35
|
+
multiple: true,
|
|
36
|
+
parse: parseExactFilter,
|
|
37
|
+
})(),
|
|
38
|
+
timezone: Flags.string({
|
|
39
|
+
description: 'IANA time zone of the days, e.g. Europe/Berlin; the app time zone when omitted',
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
export const groupByFlag = {
|
|
43
|
+
'group-by': Flags.string({
|
|
44
|
+
description: 'One grouping of this operation, as `adapty analytics catalog` lists it (e.g. country)',
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
/** The text differs per command: the period of one point, or the length of one cohort. */
|
|
48
|
+
export const granularityFlag = (description) => ({
|
|
49
|
+
granularity: Flags.option({ description, options: periodUnits })(),
|
|
50
|
+
});
|
|
51
|
+
export const revenueBasisFlag = {
|
|
52
|
+
'revenue-basis': Flags.option({
|
|
53
|
+
description: 'Which revenue the money values use: gross (default), proceeds (after store commission) or net (also after taxes)',
|
|
54
|
+
options: revenueBases,
|
|
55
|
+
})(),
|
|
56
|
+
};
|
|
57
|
+
export const renewalPeriodFlags = {
|
|
58
|
+
'period-type': Flags.option({
|
|
59
|
+
description: 'Count per renewal (renewals, default) or per day since the install (days)',
|
|
60
|
+
options: periodTypes,
|
|
61
|
+
})(),
|
|
62
|
+
'renewal-days': Flags.integer({
|
|
63
|
+
delimiter: ',',
|
|
64
|
+
description: 'The days to count with --period-type days (comma-separated or repeatable); the backend list when omitted',
|
|
65
|
+
min: 0,
|
|
66
|
+
multiple: true,
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
export const csvFlag = {
|
|
70
|
+
csv: Flags.boolean({
|
|
71
|
+
description: 'Print a CSV table made from the API answer: one row per group, the total first (is_total true; '
|
|
72
|
+
+ 'a null key is an empty cell, an empty key is written ""); a compared period in compare.* columns of the same row; '
|
|
73
|
+
+ 'the numbers of the whole answer in data.* and meta.* columns. No groups: the header line, and "No data for '
|
|
74
|
+
+ 'this period." with those numbers on stderr',
|
|
75
|
+
exclusive: ['json'],
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
/** Where the shared flags meet the sdk's field names. */
|
|
79
|
+
export const queryParams = (flags) => ({
|
|
80
|
+
appId: flags.app,
|
|
81
|
+
dateFrom: flags['date-from'],
|
|
82
|
+
dateTo: flags['date-to'],
|
|
83
|
+
filters: flags.filter,
|
|
84
|
+
timezone: flags.timezone,
|
|
85
|
+
});
|
|
86
|
+
/** The compare flags as the sdk names them; a chart and a conversion take them. */
|
|
87
|
+
export const compareParams = (flags) => ({
|
|
88
|
+
compareFrom: flags['compare-from'],
|
|
89
|
+
compareTo: flags['compare-to'],
|
|
90
|
+
});
|
|
91
|
+
/** The grouping and the period of one point as the sdk names them; a command without one of the flags leaves it out. */
|
|
92
|
+
export const groupingParams = (flags) => ({
|
|
93
|
+
granularity: flags.granularity,
|
|
94
|
+
groupBy: flags['group-by'],
|
|
95
|
+
});
|
|
@@ -3,3 +3,4 @@ export { build } from './build.js';
|
|
|
3
3
|
export { MigrationCommand } from './migration-command.js';
|
|
4
4
|
export { openSession, resolveSession } from './openSession.js';
|
|
5
5
|
export type { AuthenticatedSession, ResolvedSession } from '../session.js';
|
|
6
|
+
export { compareFlags, compareParams, csvFlag, filterFlags, granularityFlag, groupByFlag, groupingParams, periodFlags, queryParams, renewalPeriodFlags, revenueBasisFlag, } from './flags.js';
|
|
@@ -2,3 +2,4 @@ export { AdaptyCommand } from './adapty-command.js';
|
|
|
2
2
|
export { build } from './build.js';
|
|
3
3
|
export { MigrationCommand } from './migration-command.js';
|
|
4
4
|
export { openSession, resolveSession } from './openSession.js';
|
|
5
|
+
export { compareFlags, compareParams, csvFlag, filterFlags, granularityFlag, groupByFlag, groupingParams, periodFlags, queryParams, renewalPeriodFlags, revenueBasisFlag, } from './flags.js';
|
|
@@ -3,9 +3,6 @@ export declare const periodFlags: {
|
|
|
3
3
|
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
4
4
|
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
5
5
|
};
|
|
6
|
-
export declare const revenueBasisFlag: {
|
|
7
|
-
'revenue-basis': import("@oclif/core/interfaces").OptionFlag<"gross" | "proceeds" | "net" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
};
|
|
9
6
|
/** Where the period flags meet the sdk's field names. */
|
|
10
7
|
export declare const periodParams: (flags: {
|
|
11
8
|
"date-from": string;
|
|
@@ -14,3 +11,6 @@ export declare const periodParams: (flags: {
|
|
|
14
11
|
dateFrom: string;
|
|
15
12
|
dateTo: string;
|
|
16
13
|
};
|
|
14
|
+
export declare const revenueBasisFlag: {
|
|
15
|
+
'revenue-basis': import("@oclif/core/interfaces").OptionFlag<"gross" | "proceeds" | "net" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
};
|
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
/** The shape only: whether the day exists and the order of the two are sdk rules. */
|
|
5
|
-
const dateParser = (input) => (ISO_DATE.test(input)
|
|
6
|
-
? Promise.resolve(input)
|
|
7
|
-
: Promise.reject(usageError('Dates must be written as YYYY-MM-DD.')));
|
|
2
|
+
import { revenueBases } from '../../../sdk/attribution/index.js';
|
|
3
|
+
import { dayRangeFlags } from '../../input/period.js';
|
|
8
4
|
/** An inclusive day range, both ends required. */
|
|
9
|
-
export const periodFlags =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
parse: dateParser,
|
|
13
|
-
required: true,
|
|
14
|
-
}),
|
|
15
|
-
'date-to': Flags.string({
|
|
16
|
-
description: 'Last day of the period, inclusive (YYYY-MM-DD, in the app timezone)',
|
|
17
|
-
parse: dateParser,
|
|
18
|
-
required: true,
|
|
19
|
-
}),
|
|
20
|
-
};
|
|
5
|
+
export const periodFlags = dayRangeFlags('in the app timezone');
|
|
6
|
+
/** Where the period flags meet the sdk's field names. */
|
|
7
|
+
export const periodParams = (flags) => ({ dateFrom: flags['date-from'], dateTo: flags['date-to'] });
|
|
21
8
|
export const revenueBasisFlag = {
|
|
22
9
|
'revenue-basis': Flags.option({
|
|
23
10
|
description: 'Which revenue the revenue metrics use; the backend default applies when omitted',
|
|
24
11
|
options: revenueBases,
|
|
25
12
|
})(),
|
|
26
13
|
};
|
|
27
|
-
/** Where the period flags meet the sdk's field names. */
|
|
28
|
-
export const periodParams = (flags) => ({ dateFrom: flags['date-from'], dateTo: flags['date-to'] });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import type { CatalogResponse } from '../../../sdk/adapty/index.js';
|
|
3
|
+
export default class AnalyticsCatalog extends AdaptyCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<CatalogResponse>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import { appIdFlag } from '../../input/app.js';
|
|
3
|
+
const list = (items) => (items.length === 0 ? 'none' : items.join(', '));
|
|
4
|
+
const groupings = (segmentations) => list(segmentations.map(segmentation => segmentation.key));
|
|
5
|
+
/** Under the catalog's own names, so a reader knows what to look for in --json and what a flag takes. */
|
|
6
|
+
const describeOption = (option) => {
|
|
7
|
+
const values = option.values === null ? '' : ` ${option.values.join('|')}`;
|
|
8
|
+
const fallback = option.default === null ? '' : ` (default ${String(option.default)})`;
|
|
9
|
+
return `${option.name}${values}${fallback}`;
|
|
10
|
+
};
|
|
11
|
+
const describeOperation = (operation) => {
|
|
12
|
+
const perChart = operation.id === 'metrics' ? 'per chart, see Charts' : undefined;
|
|
13
|
+
return [
|
|
14
|
+
`${operation.id} (${operation.method} ${operation.path}; ${operation.can_compare ? 'can compare two periods' : 'one period only'})`,
|
|
15
|
+
` options: ${operation.options.map(option => describeOption(option)).join('; ')}`,
|
|
16
|
+
` groupings: ${perChart ?? groupings(operation.segmentations)}`,
|
|
17
|
+
` filters: ${perChart ?? list(operation.filters)}`,
|
|
18
|
+
].join('\n');
|
|
19
|
+
};
|
|
20
|
+
const describeChart = (chart) => [
|
|
21
|
+
`${chart.id}: ${chart.title} (${chart.unit}${chart.takes_revenue_basis ? ', takes revenue_basis' : ''})`,
|
|
22
|
+
` groupings: ${groupings(chart.segmentations)}`,
|
|
23
|
+
` filters: ${list(chart.filters)}`,
|
|
24
|
+
].join('\n');
|
|
25
|
+
const renderCatalog = ({ data }) => [
|
|
26
|
+
'Operations',
|
|
27
|
+
...data.operations.map(operation => describeOperation(operation)),
|
|
28
|
+
'',
|
|
29
|
+
'Charts',
|
|
30
|
+
...data.charts.map(chart => describeChart(chart)),
|
|
31
|
+
'',
|
|
32
|
+
'Conversions',
|
|
33
|
+
...data.conversions.map(conversion => `${conversion.id}: ${conversion.title}`),
|
|
34
|
+
'',
|
|
35
|
+
'Dimensions',
|
|
36
|
+
...data.dimensions.map(dimension => `${dimension.key}: ${dimension.label}`),
|
|
37
|
+
].join('\n');
|
|
38
|
+
export default class AnalyticsCatalog extends AdaptyCommand {
|
|
39
|
+
static description = 'List what the analytics of an app can answer: the six operations with their options, '
|
|
40
|
+
+ 'groupings and filters, every chart and conversion, and every filter dimension';
|
|
41
|
+
static examples = [
|
|
42
|
+
'<%= config.bin %> analytics catalog --app APP_UUID',
|
|
43
|
+
'<%= config.bin %> analytics catalog --app APP_UUID --json',
|
|
44
|
+
];
|
|
45
|
+
static flags = { ...appIdFlag };
|
|
46
|
+
async run() {
|
|
47
|
+
const { flags } = await this.parse(AnalyticsCatalog);
|
|
48
|
+
const catalog = await this.adapty.analytics.catalog(flags.app);
|
|
49
|
+
this.render(catalog, renderCatalog);
|
|
50
|
+
return catalog;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import type { ChartResponse } from '../../../sdk/adapty/index.js';
|
|
3
|
+
export default class AnalyticsChart extends AdaptyCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'revenue-basis': import("@oclif/core/interfaces").OptionFlag<"gross" | "proceeds" | "net" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
granularity: import("@oclif/core/interfaces").OptionFlag<"day" | "week" | "month" | "quarter" | "year" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
filter: import("@oclif/core/interfaces").OptionFlag<import("../../../sdk/adapty/index.js").AnalyticsFilter[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'group-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'compare-from': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
'compare-to': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
chart: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
};
|
|
20
|
+
run(): Promise<ChartResponse>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { validateChart } from '../../../sdk/adapty/index.js';
|
|
3
|
+
import { assertValid } from '../../../sdk/core/validation.js';
|
|
4
|
+
import { AdaptyCommand, compareFlags, compareParams, csvFlag, filterFlags, granularityFlag, groupByFlag, groupingParams, periodFlags, queryParams, revenueBasisFlag, } from '../../base/adapty/index.js';
|
|
5
|
+
import { appIdFlag } from '../../input/app.js';
|
|
6
|
+
import { analyticsView, chartTable } from '../../views/analytics/human.js';
|
|
7
|
+
import { csvNotice } from '../../views/analytics/segments.js';
|
|
8
|
+
export default class AnalyticsChart extends AdaptyCommand {
|
|
9
|
+
static description = 'Read one chart of the analytics of an app (revenue, MRR, installs, ...): '
|
|
10
|
+
+ 'the number of the period, its points and its groups, the total first';
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> analytics chart --app APP_UUID --chart revenue --date-from 2026-07-01 --date-to 2026-09-30',
|
|
13
|
+
'<%= config.bin %> analytics chart --app APP_UUID --chart revenue --date-from 2026-07-01 --date-to 2026-09-30 --group-by country --csv',
|
|
14
|
+
'<%= config.bin %> analytics chart --app APP_UUID --chart mrr --date-from 2026-07-01 --date-to 2026-09-30 --compare-from 2026-04-01 --compare-to 2026-06-30 --json',
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
...appIdFlag,
|
|
18
|
+
chart: Flags.string({
|
|
19
|
+
description: 'The chart, as `adapty analytics catalog` lists it',
|
|
20
|
+
required: true,
|
|
21
|
+
}),
|
|
22
|
+
...periodFlags,
|
|
23
|
+
...compareFlags,
|
|
24
|
+
...groupByFlag,
|
|
25
|
+
...filterFlags,
|
|
26
|
+
...granularityFlag('The period of one point (default month)'),
|
|
27
|
+
...revenueBasisFlag,
|
|
28
|
+
...csvFlag,
|
|
29
|
+
};
|
|
30
|
+
async run() {
|
|
31
|
+
const { flags } = await this.parse(AnalyticsChart);
|
|
32
|
+
const input = {
|
|
33
|
+
...queryParams(flags),
|
|
34
|
+
chartId: flags.chart,
|
|
35
|
+
...compareParams(flags),
|
|
36
|
+
...groupingParams(flags),
|
|
37
|
+
revenueBasis: flags['revenue-basis'],
|
|
38
|
+
};
|
|
39
|
+
// Before this.adapty: bad input is exit 2 even without a token
|
|
40
|
+
assertValid(validateChart(input));
|
|
41
|
+
const answer = await this.adapty.analytics.chart(input);
|
|
42
|
+
this.render(answer, analyticsView(flags.csv, chartTable));
|
|
43
|
+
// Beside a CSV of a period without data, its summary; an empty text otherwise
|
|
44
|
+
process.stderr.write(csvNotice(answer, flags.csv));
|
|
45
|
+
return answer;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import type { CohortResponse } from '../../../sdk/adapty/index.js';
|
|
3
|
+
export default class AnalyticsCohort extends AdaptyCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'period-type': import("@oclif/core/interfaces").OptionFlag<"renewals" | "days" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'renewal-days': import("@oclif/core/interfaces").OptionFlag<number[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'revenue-basis': import("@oclif/core/interfaces").OptionFlag<"gross" | "proceeds" | "net" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
granularity: import("@oclif/core/interfaces").OptionFlag<"day" | "week" | "month" | "quarter" | "year" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
filter: import("@oclif/core/interfaces").OptionFlag<import("../../../sdk/adapty/index.js").AnalyticsFilter[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<CohortResponse>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { validateCohort } from '../../../sdk/adapty/index.js';
|
|
2
|
+
import { assertValid } from '../../../sdk/core/validation.js';
|
|
3
|
+
import { AdaptyCommand, csvFlag, filterFlags, granularityFlag, groupingParams, periodFlags, queryParams, renewalPeriodFlags, revenueBasisFlag, } from '../../base/adapty/index.js';
|
|
4
|
+
import { appIdFlag } from '../../input/app.js';
|
|
5
|
+
import { analyticsView, cohortTable } from '../../views/analytics/human.js';
|
|
6
|
+
import { csvNotice } from '../../views/analytics/segments.js';
|
|
7
|
+
export default class AnalyticsCohort extends AdaptyCommand {
|
|
8
|
+
static description = 'Read the install cohorts of an app: revenue, subscribers and averages of each '
|
|
9
|
+
+ 'cohort per renewal (or day), with predictions, the total first (no grouping, no compared period)';
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> analytics cohort --app APP_UUID --date-from 2026-07-01 --date-to 2026-09-30',
|
|
12
|
+
'<%= config.bin %> analytics cohort --app APP_UUID --date-from 2026-07-01 --date-to 2026-09-30 --granularity week --revenue-basis proceeds --csv',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
...appIdFlag,
|
|
16
|
+
...periodFlags,
|
|
17
|
+
...filterFlags,
|
|
18
|
+
...granularityFlag('The length of one cohort (default month)'),
|
|
19
|
+
...revenueBasisFlag,
|
|
20
|
+
...renewalPeriodFlags,
|
|
21
|
+
...csvFlag,
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
const { flags } = await this.parse(AnalyticsCohort);
|
|
25
|
+
const input = {
|
|
26
|
+
...queryParams(flags),
|
|
27
|
+
...groupingParams(flags),
|
|
28
|
+
periodType: flags['period-type'],
|
|
29
|
+
renewalDays: flags['renewal-days'],
|
|
30
|
+
revenueBasis: flags['revenue-basis'],
|
|
31
|
+
};
|
|
32
|
+
// Before this.adapty: bad input is exit 2 even without a token
|
|
33
|
+
assertValid(validateCohort(input));
|
|
34
|
+
const answer = await this.adapty.analytics.cohort(input);
|
|
35
|
+
this.render(answer, analyticsView(flags.csv, cohortTable));
|
|
36
|
+
// Beside a CSV of a period without data, its summary; an empty text otherwise
|
|
37
|
+
process.stderr.write(csvNotice(answer, flags.csv));
|
|
38
|
+
return answer;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import type { ConversionResponse } from '../../../sdk/adapty/index.js';
|
|
3
|
+
export default class AnalyticsConversion extends AdaptyCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
granularity: import("@oclif/core/interfaces").OptionFlag<"day" | "week" | "month" | "quarter" | "year" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
filter: import("@oclif/core/interfaces").OptionFlag<import("../../../sdk/adapty/index.js").AnalyticsFilter[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'group-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'compare-from': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'compare-to': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
conversion: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
};
|
|
19
|
+
run(): Promise<ConversionResponse>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { validateConversion } from '../../../sdk/adapty/index.js';
|
|
3
|
+
import { assertValid } from '../../../sdk/core/validation.js';
|
|
4
|
+
import { AdaptyCommand, compareFlags, compareParams, csvFlag, filterFlags, granularityFlag, groupByFlag, groupingParams, periodFlags, queryParams, } from '../../base/adapty/index.js';
|
|
5
|
+
import { appIdFlag } from '../../input/app.js';
|
|
6
|
+
import { analyticsView, conversionTable } from '../../views/analytics/human.js';
|
|
7
|
+
import { csvNotice } from '../../views/analytics/segments.js';
|
|
8
|
+
export default class AnalyticsConversion extends AdaptyCommand {
|
|
9
|
+
static description = 'Read one conversion of the analytics of an app (install → trial, trial → paid, ...): '
|
|
10
|
+
+ 'the rate in percent with its two counts, per point and per group, the total first';
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> analytics conversion --app APP_UUID --conversion trial-paid --date-from 2026-07-01 --date-to 2026-09-30',
|
|
13
|
+
'<%= config.bin %> analytics conversion --app APP_UUID --conversion install-paid --date-from 2026-07-01 --date-to 2026-09-30 --granularity month --group-by country --csv',
|
|
14
|
+
];
|
|
15
|
+
static flags = {
|
|
16
|
+
...appIdFlag,
|
|
17
|
+
conversion: Flags.string({
|
|
18
|
+
description: 'The conversion, as `adapty analytics catalog` lists it',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
...periodFlags,
|
|
22
|
+
...compareFlags,
|
|
23
|
+
...groupByFlag,
|
|
24
|
+
...filterFlags,
|
|
25
|
+
...granularityFlag('The period of one point (default day)'),
|
|
26
|
+
...csvFlag,
|
|
27
|
+
};
|
|
28
|
+
async run() {
|
|
29
|
+
const { flags } = await this.parse(AnalyticsConversion);
|
|
30
|
+
const input = {
|
|
31
|
+
...queryParams(flags),
|
|
32
|
+
...compareParams(flags),
|
|
33
|
+
conversionId: flags.conversion,
|
|
34
|
+
...groupingParams(flags),
|
|
35
|
+
};
|
|
36
|
+
// Before this.adapty: bad input is exit 2 even without a token
|
|
37
|
+
assertValid(validateConversion(input));
|
|
38
|
+
const answer = await this.adapty.analytics.conversion(input);
|
|
39
|
+
this.render(answer, analyticsView(flags.csv, conversionTable));
|
|
40
|
+
// Beside a CSV of a period without data, its summary; an empty text otherwise
|
|
41
|
+
process.stderr.write(csvNotice(answer, flags.csv));
|
|
42
|
+
return answer;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import type { FunnelResponse } from '../../../sdk/adapty/index.js';
|
|
3
|
+
export default class AnalyticsFunnel extends AdaptyCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
filter: import("@oclif/core/interfaces").OptionFlag<import("../../../sdk/adapty/index.js").AnalyticsFilter[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'group-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<FunnelResponse>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { validateFunnel } from '../../../sdk/adapty/index.js';
|
|
2
|
+
import { assertValid } from '../../../sdk/core/validation.js';
|
|
3
|
+
import { AdaptyCommand, csvFlag, filterFlags, groupByFlag, groupingParams, periodFlags, queryParams, } from '../../base/adapty/index.js';
|
|
4
|
+
import { appIdFlag } from '../../input/app.js';
|
|
5
|
+
import { analyticsView, funnelTable } from '../../views/analytics/human.js';
|
|
6
|
+
import { csvNotice } from '../../views/analytics/segments.js';
|
|
7
|
+
export default class AnalyticsFunnel extends AdaptyCommand {
|
|
8
|
+
static description = 'Read the funnel of an app, from install to renewals: the count at each step, '
|
|
9
|
+
+ 'per group, the total first (no compared period: the funnel query cannot keep two periods apart)';
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> analytics funnel --app APP_UUID --date-from 2026-07-01 --date-to 2026-09-30',
|
|
12
|
+
'<%= config.bin %> analytics funnel --app APP_UUID --date-from 2026-07-01 --date-to 2026-09-30 --group-by country --csv',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
...appIdFlag,
|
|
16
|
+
...periodFlags,
|
|
17
|
+
...groupByFlag,
|
|
18
|
+
...filterFlags,
|
|
19
|
+
...csvFlag,
|
|
20
|
+
};
|
|
21
|
+
async run() {
|
|
22
|
+
const { flags } = await this.parse(AnalyticsFunnel);
|
|
23
|
+
const input = { ...queryParams(flags), ...groupingParams(flags) };
|
|
24
|
+
// Before this.adapty: bad input is exit 2 even without a token
|
|
25
|
+
assertValid(validateFunnel(input));
|
|
26
|
+
const answer = await this.adapty.analytics.funnel(input);
|
|
27
|
+
this.render(answer, analyticsView(flags.csv, funnelTable));
|
|
28
|
+
// Beside a CSV of a period without data, its summary; an empty text otherwise
|
|
29
|
+
process.stderr.write(csvNotice(answer, flags.csv));
|
|
30
|
+
return answer;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../base/adapty/index.js';
|
|
2
|
+
import type { LtvResponse } from '../../../sdk/adapty/index.js';
|
|
3
|
+
export default class AnalyticsLtv extends AdaptyCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'period-type': import("@oclif/core/interfaces").OptionFlag<"renewals" | "days" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'renewal-days': import("@oclif/core/interfaces").OptionFlag<number[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'revenue-basis': import("@oclif/core/interfaces").OptionFlag<"gross" | "proceeds" | "net" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
filter: import("@oclif/core/interfaces").OptionFlag<import("../../../sdk/adapty/index.js").AnalyticsFilter[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'group-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
'date-from': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
'date-to': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<LtvResponse>;
|
|
19
|
+
}
|