@analyticscli/growth-engineer 0.1.1-preview.15 → 0.1.1-preview.19
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/dist/runtime/export-asc-summary.mjs +239 -79
- package/dist/runtime/export-asc-summary.mjs.map +1 -1
- package/dist/runtime/openclaw-exporters-lib.d.mts +62 -2
- package/dist/runtime/openclaw-exporters-lib.mjs +166 -67
- package/dist/runtime/openclaw-exporters-lib.mjs.map +1 -1
- package/dist/runtime/openclaw-growth-runner.mjs +0 -16
- package/dist/runtime/openclaw-growth-runner.mjs.map +1 -1
- package/dist/runtime/openclaw-growth-start.mjs +74 -5
- package/dist/runtime/openclaw-growth-start.mjs.map +1 -1
- package/dist/runtime/openclaw-growth-status.mjs +2 -2
- package/dist/runtime/openclaw-growth-status.mjs.map +1 -1
- package/dist/runtime/openclaw-growth-wizard.mjs +145 -50
- package/dist/runtime/openclaw-growth-wizard.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -28,6 +28,16 @@ export declare function buildAscSummary(input: any): {
|
|
|
28
28
|
batchReports: any;
|
|
29
29
|
productionVersions: any[];
|
|
30
30
|
analytics: {
|
|
31
|
+
impressions: {
|
|
32
|
+
total: number;
|
|
33
|
+
previousTotal: number;
|
|
34
|
+
percentChange: number;
|
|
35
|
+
};
|
|
36
|
+
pageViewUnique: {
|
|
37
|
+
total: number;
|
|
38
|
+
previousTotal: number;
|
|
39
|
+
percentChange: number;
|
|
40
|
+
};
|
|
31
41
|
units: {
|
|
32
42
|
total: number;
|
|
33
43
|
previousTotal: number;
|
|
@@ -49,9 +59,59 @@ export declare function buildAscSummary(input: any): {
|
|
|
49
59
|
percentChange: number;
|
|
50
60
|
nonZeroDays: any;
|
|
51
61
|
};
|
|
62
|
+
crashes: {
|
|
63
|
+
total: number;
|
|
64
|
+
previousTotal: number;
|
|
65
|
+
percentChange: number;
|
|
66
|
+
};
|
|
67
|
+
sessions: {
|
|
68
|
+
total: number;
|
|
69
|
+
previousTotal: number;
|
|
70
|
+
percentChange: number;
|
|
71
|
+
};
|
|
72
|
+
activeDevices: {
|
|
73
|
+
total: number;
|
|
74
|
+
previousTotal: number;
|
|
75
|
+
percentChange: number;
|
|
76
|
+
};
|
|
77
|
+
installations: {
|
|
78
|
+
total: number;
|
|
79
|
+
previousTotal: number;
|
|
80
|
+
percentChange: number;
|
|
81
|
+
};
|
|
82
|
+
deletions: {
|
|
83
|
+
total: number;
|
|
84
|
+
previousTotal: number;
|
|
85
|
+
percentChange: number;
|
|
86
|
+
};
|
|
87
|
+
purchases: {
|
|
88
|
+
total: number;
|
|
89
|
+
previousTotal: number;
|
|
90
|
+
percentChange: number;
|
|
91
|
+
};
|
|
92
|
+
proceeds: {
|
|
93
|
+
total: number;
|
|
94
|
+
previousTotal: number;
|
|
95
|
+
percentChange: number;
|
|
96
|
+
};
|
|
97
|
+
payingUsers: {
|
|
98
|
+
total: number;
|
|
99
|
+
previousTotal: number;
|
|
100
|
+
percentChange: number;
|
|
101
|
+
};
|
|
102
|
+
subscriptions: {
|
|
103
|
+
total: number;
|
|
104
|
+
previousTotal: number;
|
|
105
|
+
percentChange: number;
|
|
106
|
+
};
|
|
107
|
+
trialStarts: {
|
|
108
|
+
total: number;
|
|
109
|
+
previousTotal: number;
|
|
110
|
+
percentChange: number;
|
|
111
|
+
};
|
|
52
112
|
totalCrashes: any;
|
|
53
|
-
crashBreakdown: any;
|
|
54
|
-
sourceBreakdown: any;
|
|
113
|
+
crashBreakdown: any[];
|
|
114
|
+
sourceBreakdown: any[];
|
|
55
115
|
overviewMetricCatalog: any[];
|
|
56
116
|
};
|
|
57
117
|
};
|
|
@@ -564,6 +564,30 @@ function summarizeSourceBreakdown(payload) {
|
|
|
564
564
|
.filter((entry) => entry.pageViewUnique > 0)
|
|
565
565
|
.sort((a, b) => b.pageViewUnique - a.pageViewUnique);
|
|
566
566
|
}
|
|
567
|
+
function normalizeBatchSourceBreakdown(entries) {
|
|
568
|
+
return (Array.isArray(entries) ? entries : [])
|
|
569
|
+
.map((entry) => ({
|
|
570
|
+
key: String(entry?.key || entry?.title || 'unknown'),
|
|
571
|
+
title: String(entry?.title || entry?.key || 'Unknown'),
|
|
572
|
+
impressions: coerceNumber(entry?.impressions) || 0,
|
|
573
|
+
pageViewUnique: coerceNumber(entry?.pageViewUnique) || 0,
|
|
574
|
+
units: coerceNumber(entry?.units) || 0,
|
|
575
|
+
redownloads: coerceNumber(entry?.redownloads) || 0,
|
|
576
|
+
purchases: coerceNumber(entry?.purchases) || 0,
|
|
577
|
+
proceeds: coerceNumber(entry?.proceeds) || 0,
|
|
578
|
+
}))
|
|
579
|
+
.filter((entry) => entry.impressions > 0 ||
|
|
580
|
+
entry.pageViewUnique > 0 ||
|
|
581
|
+
entry.units > 0 ||
|
|
582
|
+
entry.redownloads > 0 ||
|
|
583
|
+
entry.purchases > 0 ||
|
|
584
|
+
entry.proceeds > 0)
|
|
585
|
+
.sort((a, b) => {
|
|
586
|
+
const aValue = a.pageViewUnique || a.impressions || a.units || a.purchases || a.proceeds || 0;
|
|
587
|
+
const bValue = b.pageViewUnique || b.impressions || b.units || b.purchases || b.proceeds || 0;
|
|
588
|
+
return bValue - aValue;
|
|
589
|
+
});
|
|
590
|
+
}
|
|
567
591
|
function extractAscCrashBreakdowns(payload) {
|
|
568
592
|
const breakdowns = Array.isArray(payload?.appUsageBreakdowns) ? payload.appUsageBreakdowns : [];
|
|
569
593
|
return breakdowns
|
|
@@ -586,14 +610,6 @@ function totalAscCrashes(payload) {
|
|
|
586
610
|
return directTotal;
|
|
587
611
|
return extractAscCrashBreakdowns(payload).reduce((sum, entry) => sum + entry.value, 0);
|
|
588
612
|
}
|
|
589
|
-
function isLikelyAscWebAuthMissing(warnings) {
|
|
590
|
-
return warnings.some((warning) => {
|
|
591
|
-
const normalized = String(warning || '').toLowerCase();
|
|
592
|
-
return (normalized.includes('asc web auth login') ||
|
|
593
|
-
normalized.includes('web session is unauthorized') ||
|
|
594
|
-
normalized.includes('web session is expired'));
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
613
|
function collectAscOverviewMetricCatalog(payload) {
|
|
598
614
|
const sections = ['acquisition', 'sales', 'subscriptions'];
|
|
599
615
|
const metrics = [];
|
|
@@ -653,6 +669,38 @@ function collectAscOverviewMetricCatalog(payload) {
|
|
|
653
669
|
}
|
|
654
670
|
return [...byKey.values()];
|
|
655
671
|
}
|
|
672
|
+
function mergeMetricCatalogs(...catalogs) {
|
|
673
|
+
const byKey = new Map();
|
|
674
|
+
for (const catalog of catalogs) {
|
|
675
|
+
for (const metric of Array.isArray(catalog) ? catalog : []) {
|
|
676
|
+
const section = String(metric?.section || 'unknown');
|
|
677
|
+
const measure = String(metric?.measure || '').trim();
|
|
678
|
+
if (!measure)
|
|
679
|
+
continue;
|
|
680
|
+
const key = `${section}:${measure}`;
|
|
681
|
+
if (!byKey.has(key)) {
|
|
682
|
+
byKey.set(key, {
|
|
683
|
+
section,
|
|
684
|
+
measure,
|
|
685
|
+
total: coerceNumber(metric?.total),
|
|
686
|
+
previousTotal: coerceNumber(metric?.previousTotal),
|
|
687
|
+
percentChange: coerceNumber(metric?.percentChange),
|
|
688
|
+
type: String(metric?.type || 'COUNT'),
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return [...byKey.values()];
|
|
694
|
+
}
|
|
695
|
+
function metricSnapshot(metric) {
|
|
696
|
+
return metric
|
|
697
|
+
? {
|
|
698
|
+
total: coerceNumber(metric.total) ?? 0,
|
|
699
|
+
previousTotal: coerceNumber(metric.previousTotal),
|
|
700
|
+
percentChange: coerceNumber(metric.percentChange),
|
|
701
|
+
}
|
|
702
|
+
: null;
|
|
703
|
+
}
|
|
656
704
|
function formatMetricMovement(metric) {
|
|
657
705
|
const total = metric.total === null ? 'unknown' : round(metric.total);
|
|
658
706
|
const previous = metric.previousTotal === null ? null : ` previous ${round(metric.previousTotal)}`;
|
|
@@ -690,26 +738,47 @@ export function buildAscSummary(input) {
|
|
|
690
738
|
];
|
|
691
739
|
const topThemes = rankKeywordThemes(reviewTexts).slice(0, 2);
|
|
692
740
|
const analyticsMetricsPayload = input?.batchAnalyticsPayload || input?.analyticsMetricsPayload || input?.analyticsOverviewPayload;
|
|
741
|
+
const impressionsMetric = findAscMetric(analyticsMetricsPayload, 'impressions');
|
|
742
|
+
const pageViewsMetric = findAscMetric(analyticsMetricsPayload, 'pageViewUnique');
|
|
693
743
|
const unitsMetric = findAscMetric(analyticsMetricsPayload, 'units');
|
|
694
744
|
const redownloadsMetric = findAscMetric(analyticsMetricsPayload, 'redownloads');
|
|
695
745
|
const conversionRateMetric = findAscMetric(analyticsMetricsPayload || input?.analyticsOverviewPayload, 'conversionRate');
|
|
696
746
|
const crashRateMetric = findAscMetric(analyticsMetricsPayload, 'crashRate');
|
|
697
|
-
const
|
|
698
|
-
const
|
|
747
|
+
const crashesMetric = findAscMetric(analyticsMetricsPayload, 'crashes');
|
|
748
|
+
const sessionsMetric = findAscMetric(analyticsMetricsPayload, 'sessions');
|
|
749
|
+
const activeDevicesMetric = findAscMetric(analyticsMetricsPayload, 'activeDevices');
|
|
750
|
+
const installationsMetric = findAscMetric(analyticsMetricsPayload, 'installations');
|
|
751
|
+
const deletionsMetric = findAscMetric(analyticsMetricsPayload, 'deletions');
|
|
752
|
+
const purchasesMetric = findAscMetric(analyticsMetricsPayload, 'purchases');
|
|
753
|
+
const proceedsMetric = findAscMetric(analyticsMetricsPayload, 'proceeds');
|
|
754
|
+
const payingUsersMetric = findAscMetric(analyticsMetricsPayload, 'payingUsers');
|
|
755
|
+
const subscriptionsMetric = findAscMetric(analyticsMetricsPayload, 'subscriptions');
|
|
756
|
+
const trialStartsMetric = findAscMetric(analyticsMetricsPayload, 'trialStarts');
|
|
757
|
+
const sourceBreakdown = [
|
|
758
|
+
...normalizeBatchSourceBreakdown(input?.batchAnalyticsPayload?.sourceBreakdown),
|
|
759
|
+
...summarizeSourceBreakdown(input?.analyticsSourcesPayload),
|
|
760
|
+
];
|
|
761
|
+
const totalSourcePageViews = sourceBreakdown.reduce((sum, source) => sum + (source.pageViewUnique || source.impressions || source.units || 0), 0);
|
|
699
762
|
const topSource = sourceBreakdown[0] || null;
|
|
700
|
-
const crashBreakdown =
|
|
701
|
-
|
|
763
|
+
const crashBreakdown = [
|
|
764
|
+
...(Array.isArray(input?.batchAnalyticsPayload?.crashBreakdown)
|
|
765
|
+
? input.batchAnalyticsPayload.crashBreakdown
|
|
766
|
+
: []),
|
|
767
|
+
...extractAscCrashBreakdowns(input?.analyticsOverviewPayload),
|
|
768
|
+
]
|
|
769
|
+
.filter((entry) => coerceNumber(entry?.value) > 0)
|
|
770
|
+
.sort((a, b) => (coerceNumber(b?.value) || 0) - (coerceNumber(a?.value) || 0));
|
|
771
|
+
const totalCrashes = coerceNumber(crashesMetric?.total) ||
|
|
772
|
+
totalAscCrashes(input?.analyticsOverviewPayload) ||
|
|
773
|
+
crashBreakdown.reduce((sum, entry) => sum + (coerceNumber(entry?.value) || 0), 0);
|
|
702
774
|
const analyticsWarnings = Array.isArray(input?.analyticsWarnings) ? input.analyticsWarnings : [];
|
|
703
|
-
const webAuthMissing = isLikelyAscWebAuthMissing(analyticsWarnings);
|
|
704
775
|
const batchReports = Array.isArray(input?.batchReports) ? input.batchReports : [];
|
|
705
|
-
const analyticsAvailability =
|
|
706
|
-
? '
|
|
707
|
-
:
|
|
708
|
-
? '
|
|
709
|
-
:
|
|
710
|
-
|
|
711
|
-
: 'unknown';
|
|
712
|
-
const overviewMetricCatalog = collectAscOverviewMetricCatalog(input?.analyticsOverviewPayload);
|
|
776
|
+
const analyticsAvailability = analyticsWarnings.some((warning) => String(warning).includes('403'))
|
|
777
|
+
? 'not_public_or_not_analytics_ready'
|
|
778
|
+
: analyticsMetricsPayload || unitsMetric || conversionRateMetric || sourceBreakdown.length > 0 || totalCrashes > 0 || batchReports.length > 0
|
|
779
|
+
? 'available'
|
|
780
|
+
: 'unknown';
|
|
781
|
+
const overviewMetricCatalog = mergeMetricCatalogs(collectAscOverviewMetricCatalog(input?.analyticsOverviewPayload), input?.batchAnalyticsPayload?.overviewMetricCatalog);
|
|
713
782
|
const notableOverviewMetrics = overviewMetricCatalog
|
|
714
783
|
.filter((metric) => {
|
|
715
784
|
const measure = metric.measure.toLowerCase();
|
|
@@ -733,25 +802,6 @@ export function buildAscSummary(input) {
|
|
|
733
802
|
.filter((point) => Number(point.value) > 0)
|
|
734
803
|
.slice(-5);
|
|
735
804
|
const signals = [];
|
|
736
|
-
if (webAuthMissing) {
|
|
737
|
-
maybePushSignal(signals, {
|
|
738
|
-
id: 'asc_web_analytics_access_missing',
|
|
739
|
-
title: 'ASC web analytics access needs login refresh',
|
|
740
|
-
area: 'connector',
|
|
741
|
-
priority: 'high',
|
|
742
|
-
metric: 'asc_web_analytics_access',
|
|
743
|
-
current_value: 0,
|
|
744
|
-
baseline_value: 1,
|
|
745
|
-
delta_percent: -100,
|
|
746
|
-
evidence: analyticsWarnings.slice(0, 3),
|
|
747
|
-
suggested_actions: [
|
|
748
|
-
'Ask the OpenClaw user whether to enable experimental ASC web analytics for the specific missing metric that API-key batch reports could not provide',
|
|
749
|
-
'If the user accepts, set ASC_WEB_APPLE_ID in the host terminal and run: asc web auth login --apple-id "$ASC_WEB_APPLE_ID"',
|
|
750
|
-
'Continue using API-key ASC batch reports if the user declines or the Apple Account web session expires again',
|
|
751
|
-
],
|
|
752
|
-
keywords: ['asc', 'web_analytics', 'login', 'connector'],
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
805
|
if (blockingStatuses.length > 0) {
|
|
756
806
|
maybePushSignal(signals, {
|
|
757
807
|
id: 'asc_release_blockers_detected',
|
|
@@ -873,6 +923,60 @@ export function buildAscSummary(input) {
|
|
|
873
923
|
keywords: ['asc', 'analytics', 'overview_metrics', 'conversion', 'handlungsempfehlung'],
|
|
874
924
|
});
|
|
875
925
|
}
|
|
926
|
+
if (purchasesMetric || proceedsMetric || payingUsersMetric || subscriptionsMetric || trialStartsMetric) {
|
|
927
|
+
const purchases = coerceNumber(purchasesMetric?.total) || 0;
|
|
928
|
+
const proceeds = coerceNumber(proceedsMetric?.total) || 0;
|
|
929
|
+
const payingUsers = coerceNumber(payingUsersMetric?.total) || 0;
|
|
930
|
+
maybePushSignal(signals, {
|
|
931
|
+
id: 'asc_commerce_metrics_available',
|
|
932
|
+
title: 'ASC commerce metrics are available for store-to-revenue analysis',
|
|
933
|
+
area: 'revenue',
|
|
934
|
+
priority: 'low',
|
|
935
|
+
metric: purchasesMetric ? 'asc_purchases' : proceedsMetric ? 'asc_proceeds' : 'asc_commerce_metrics',
|
|
936
|
+
current_value: purchases || proceeds || payingUsers || coerceNumber(subscriptionsMetric?.total) || coerceNumber(trialStartsMetric?.total) || 0,
|
|
937
|
+
baseline_value: null,
|
|
938
|
+
delta_percent: null,
|
|
939
|
+
evidence: [
|
|
940
|
+
purchasesMetric ? `Purchases: ${purchases}` : null,
|
|
941
|
+
proceedsMetric ? `Developer proceeds: ${round(proceeds)}` : null,
|
|
942
|
+
payingUsersMetric ? `Paying users: ${payingUsers}` : null,
|
|
943
|
+
subscriptionsMetric ? `Subscriptions: ${coerceNumber(subscriptionsMetric.total) || 0}` : null,
|
|
944
|
+
trialStartsMetric ? `Trial starts: ${coerceNumber(trialStartsMetric.total) || 0}` : null,
|
|
945
|
+
].filter(Boolean),
|
|
946
|
+
suggested_actions: [
|
|
947
|
+
'Compare ASC commerce movement with RevenueCat/Paddle entitlement and subscription signals before changing pricing',
|
|
948
|
+
'Use download source and purchase source dimensions to separate acquisition quality from paywall or product issues',
|
|
949
|
+
],
|
|
950
|
+
keywords: ['asc', 'commerce', 'revenue', 'purchase', 'subscription'],
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
if (sessionsMetric || activeDevicesMetric || installationsMetric || deletionsMetric) {
|
|
954
|
+
maybePushSignal(signals, {
|
|
955
|
+
id: 'asc_usage_metrics_available',
|
|
956
|
+
title: 'ASC app usage metrics are available for retention checks',
|
|
957
|
+
area: 'retention',
|
|
958
|
+
priority: 'low',
|
|
959
|
+
metric: sessionsMetric ? 'asc_sessions' : activeDevicesMetric ? 'asc_active_devices' : 'asc_usage_metrics',
|
|
960
|
+
current_value: coerceNumber(sessionsMetric?.total) ||
|
|
961
|
+
coerceNumber(activeDevicesMetric?.total) ||
|
|
962
|
+
coerceNumber(installationsMetric?.total) ||
|
|
963
|
+
coerceNumber(deletionsMetric?.total) ||
|
|
964
|
+
0,
|
|
965
|
+
baseline_value: null,
|
|
966
|
+
delta_percent: null,
|
|
967
|
+
evidence: [
|
|
968
|
+
sessionsMetric ? `Sessions: ${coerceNumber(sessionsMetric.total) || 0}` : null,
|
|
969
|
+
activeDevicesMetric ? `Active devices: ${coerceNumber(activeDevicesMetric.total) || 0}` : null,
|
|
970
|
+
installationsMetric ? `Installations: ${coerceNumber(installationsMetric.total) || 0}` : null,
|
|
971
|
+
deletionsMetric ? `Deletions: ${coerceNumber(deletionsMetric.total) || 0}` : null,
|
|
972
|
+
].filter(Boolean),
|
|
973
|
+
suggested_actions: [
|
|
974
|
+
'Compare ASC usage and deletion movement with AnalyticsCLI retention cohorts and first-session funnels',
|
|
975
|
+
'Treat low-volume usage reports as directional because Apple applies privacy thresholds and opt-in limits',
|
|
976
|
+
],
|
|
977
|
+
keywords: ['asc', 'usage', 'sessions', 'retention', 'deletions'],
|
|
978
|
+
});
|
|
979
|
+
}
|
|
876
980
|
if (unitsMetric && coerceNumber(unitsMetric.total) !== null) {
|
|
877
981
|
const units = coerceNumber(unitsMetric.total) || 0;
|
|
878
982
|
const percentChange = coerceNumber(unitsMetric.percentChange);
|
|
@@ -928,24 +1032,25 @@ export function buildAscSummary(input) {
|
|
|
928
1032
|
}
|
|
929
1033
|
}
|
|
930
1034
|
if (topSource && totalSourcePageViews > 0) {
|
|
931
|
-
const
|
|
1035
|
+
const topSourceValue = topSource.pageViewUnique || topSource.impressions || topSource.units || topSource.purchases || topSource.proceeds || 0;
|
|
1036
|
+
const share = topSourceValue / totalSourcePageViews;
|
|
932
1037
|
if (share >= 0.5 || sourceBreakdown.length >= 2) {
|
|
933
1038
|
maybePushSignal(signals, {
|
|
934
1039
|
id: 'asc_source_mix_available',
|
|
935
1040
|
title: 'ASC source traffic is available for acquisition recommendations',
|
|
936
1041
|
area: 'acquisition',
|
|
937
1042
|
priority: share >= 0.7 ? 'medium' : 'low',
|
|
938
|
-
metric: 'asc_source_page_view_unique',
|
|
939
|
-
current_value:
|
|
1043
|
+
metric: topSource.pageViewUnique ? 'asc_source_page_view_unique' : topSource.impressions ? 'asc_source_impressions' : 'asc_source_units',
|
|
1044
|
+
current_value: topSourceValue,
|
|
940
1045
|
baseline_value: totalSourcePageViews,
|
|
941
1046
|
delta_percent: round(share * 100),
|
|
942
1047
|
evidence: [
|
|
943
|
-
`Top source: ${topSource.title} (${
|
|
1048
|
+
`Top source: ${topSource.title} (${topSourceValue} source-attributed events)`,
|
|
944
1049
|
`Source mix: ${sourceBreakdown
|
|
945
1050
|
.slice(0, 5)
|
|
946
|
-
.map((source) => `${source.title} ${source.pageViewUnique}`)
|
|
1051
|
+
.map((source) => `${source.title} ${source.pageViewUnique || source.impressions || source.units || source.purchases || source.proceeds || 0}`)
|
|
947
1052
|
.join(', ')}`,
|
|
948
|
-
'ASC
|
|
1053
|
+
'ASC source dimensions may represent impressions, product page views, downloads, purchases, or proceeds depending on the downloaded report instance',
|
|
949
1054
|
],
|
|
950
1055
|
suggested_actions: [
|
|
951
1056
|
'Turn the dominant source into a specific Handlungsempfehlung: Search -> ASO/keywords, Web Referrer -> landing pages/UTMs, Browse -> creative/category positioning, App Referrer -> cross-promo/deep links',
|
|
@@ -971,27 +1076,11 @@ export function buildAscSummary(input) {
|
|
|
971
1076
|
batchReports,
|
|
972
1077
|
productionVersions,
|
|
973
1078
|
analytics: {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
}
|
|
980
|
-
: null,
|
|
981
|
-
redownloads: redownloadsMetric
|
|
982
|
-
? {
|
|
983
|
-
total: coerceNumber(redownloadsMetric.total) ?? 0,
|
|
984
|
-
previousTotal: coerceNumber(redownloadsMetric.previousTotal),
|
|
985
|
-
percentChange: coerceNumber(redownloadsMetric.percentChange),
|
|
986
|
-
}
|
|
987
|
-
: null,
|
|
988
|
-
conversionRate: conversionRateMetric
|
|
989
|
-
? {
|
|
990
|
-
total: coerceNumber(conversionRateMetric.total) ?? 0,
|
|
991
|
-
previousTotal: coerceNumber(conversionRateMetric.previousTotal),
|
|
992
|
-
percentChange: coerceNumber(conversionRateMetric.percentChange),
|
|
993
|
-
}
|
|
994
|
-
: null,
|
|
1079
|
+
impressions: metricSnapshot(impressionsMetric),
|
|
1080
|
+
pageViewUnique: metricSnapshot(pageViewsMetric),
|
|
1081
|
+
units: metricSnapshot(unitsMetric),
|
|
1082
|
+
redownloads: metricSnapshot(redownloadsMetric),
|
|
1083
|
+
conversionRate: metricSnapshot(conversionRateMetric),
|
|
995
1084
|
crashRate: crashRateMetric
|
|
996
1085
|
? {
|
|
997
1086
|
total: coerceNumber(crashRateMetric.total) ?? 0,
|
|
@@ -1000,6 +1089,16 @@ export function buildAscSummary(input) {
|
|
|
1000
1089
|
nonZeroDays: nonZeroCrashRateDays,
|
|
1001
1090
|
}
|
|
1002
1091
|
: null,
|
|
1092
|
+
crashes: metricSnapshot(crashesMetric),
|
|
1093
|
+
sessions: metricSnapshot(sessionsMetric),
|
|
1094
|
+
activeDevices: metricSnapshot(activeDevicesMetric),
|
|
1095
|
+
installations: metricSnapshot(installationsMetric),
|
|
1096
|
+
deletions: metricSnapshot(deletionsMetric),
|
|
1097
|
+
purchases: metricSnapshot(purchasesMetric),
|
|
1098
|
+
proceeds: metricSnapshot(proceedsMetric),
|
|
1099
|
+
payingUsers: metricSnapshot(payingUsersMetric),
|
|
1100
|
+
subscriptions: metricSnapshot(subscriptionsMetric),
|
|
1101
|
+
trialStarts: metricSnapshot(trialStartsMetric),
|
|
1003
1102
|
totalCrashes,
|
|
1004
1103
|
crashBreakdown,
|
|
1005
1104
|
sourceBreakdown,
|