eas-cli 18.4.0 → 18.6.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 +92 -90
- package/build/build/android/prepareJob.js +2 -2
- package/build/build/ios/prepareJob.js +2 -2
- package/build/build/metadata.js +2 -1
- package/build/commandUtils/EasCommand.js +23 -2
- package/build/commandUtils/context/contextUtils/getProjectIdAsync.js +2 -0
- package/build/commandUtils/pagination.d.ts +2 -1
- package/build/commandUtils/pagination.js +3 -2
- package/build/commandUtils/workflow/fetchLogs.js +11 -2
- package/build/commandUtils/workflow/types.d.ts +5 -1
- package/build/commandUtils/workflow/utils.js +22 -16
- package/build/commands/deploy/index.js +18 -2
- package/build/commands/metadata/pull.d.ts +1 -0
- package/build/commands/metadata/pull.js +9 -4
- package/build/commands/metadata/push.d.ts +1 -0
- package/build/commands/metadata/push.js +9 -4
- package/build/commands/observe/events.d.ts +27 -0
- package/build/commands/observe/events.js +140 -0
- package/build/commands/observe/metrics.d.ts +21 -0
- package/build/commands/observe/metrics.js +111 -0
- package/build/commands/observe/versions.d.ts +19 -0
- package/build/commands/observe/versions.js +69 -0
- package/build/commands/project/onboarding.js +3 -0
- package/build/commands/workflow/logs.js +12 -12
- package/build/credentials/ios/IosCredentialsProvider.js +8 -4
- package/build/credentials/ios/utils/provisioningProfile.d.ts +1 -0
- package/build/credentials/ios/utils/provisioningProfile.js +15 -1
- package/build/graphql/generated.d.ts +1273 -73
- package/build/graphql/generated.js +59 -19
- package/build/graphql/queries/ObserveQuery.d.ts +35 -0
- package/build/graphql/queries/ObserveQuery.js +109 -0
- package/build/graphql/queries/UserQuery.js +3 -0
- package/build/graphql/types/Observe.d.ts +3 -0
- package/build/graphql/types/Observe.js +84 -0
- package/build/graphql/types/Update.js +3 -0
- package/build/metadata/apple/config/reader.d.ts +13 -1
- package/build/metadata/apple/config/reader.js +33 -0
- package/build/metadata/apple/config/writer.d.ts +11 -1
- package/build/metadata/apple/config/writer.js +57 -0
- package/build/metadata/apple/data.d.ts +7 -2
- package/build/metadata/apple/rules/infoRestrictedWords.js +6 -1
- package/build/metadata/apple/tasks/age-rating.d.ts +1 -1
- package/build/metadata/apple/tasks/age-rating.js +19 -3
- package/build/metadata/apple/tasks/app-clip.d.ts +37 -0
- package/build/metadata/apple/tasks/app-clip.js +404 -0
- package/build/metadata/apple/tasks/app-review-detail.js +7 -2
- package/build/metadata/apple/tasks/index.js +6 -0
- package/build/metadata/apple/tasks/previews.d.ts +18 -0
- package/build/metadata/apple/tasks/previews.js +212 -0
- package/build/metadata/apple/tasks/screenshots.d.ts +18 -0
- package/build/metadata/apple/tasks/screenshots.js +235 -0
- package/build/metadata/apple/types.d.ts +61 -1
- package/build/metadata/auth.d.ts +11 -1
- package/build/metadata/auth.js +96 -2
- package/build/metadata/download.d.ts +5 -1
- package/build/metadata/download.js +16 -8
- package/build/metadata/upload.d.ts +5 -1
- package/build/metadata/upload.js +11 -4
- package/build/observe/fetchEvents.d.ts +27 -0
- package/build/observe/fetchEvents.js +83 -0
- package/build/observe/fetchMetrics.d.ts +11 -0
- package/build/observe/fetchMetrics.js +78 -0
- package/build/observe/fetchVersions.d.ts +7 -0
- package/build/observe/fetchVersions.js +31 -0
- package/build/observe/formatEvents.d.ts +31 -0
- package/build/observe/formatEvents.js +99 -0
- package/build/observe/formatMetrics.d.ts +38 -0
- package/build/observe/formatMetrics.js +206 -0
- package/build/observe/formatVersions.d.ts +32 -0
- package/build/observe/formatVersions.js +92 -0
- package/build/observe/metricNames.d.ts +4 -0
- package/build/observe/metricNames.js +33 -0
- package/build/observe/startAndEndTime.d.ts +18 -0
- package/build/observe/startAndEndTime.js +36 -0
- package/build/project/projectUtils.d.ts +0 -2
- package/build/project/projectUtils.js +0 -12
- package/build/project/workflow.js +1 -1
- package/build/sentry.d.ts +2 -0
- package/build/sentry.js +22 -0
- package/build/update/utils.d.ts +2 -2
- package/build/update/utils.js +1 -0
- package/build/user/SessionManager.js +11 -0
- package/build/user/User.d.ts +2 -2
- package/build/user/User.js +3 -0
- package/build/user/expoBrowserAuthFlowLauncher.js +70 -13
- package/build/worker/upload.js +15 -5
- package/oclif.manifest.json +1794 -1306
- package/package.json +15 -11
- package/schema/metadata-0.json +213 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AppPlatform } from '../graphql/generated';
|
|
2
|
+
export type StatisticKey = 'min' | 'max' | 'median' | 'average' | 'p80' | 'p90' | 'p99' | 'eventCount';
|
|
3
|
+
export declare const STAT_ALIASES: Record<string, StatisticKey>;
|
|
4
|
+
export declare const STAT_DISPLAY_NAMES: Record<StatisticKey, string>;
|
|
5
|
+
export declare function resolveStatKey(input: string): StatisticKey;
|
|
6
|
+
export interface MetricValues {
|
|
7
|
+
min: number | null | undefined;
|
|
8
|
+
max: number | null | undefined;
|
|
9
|
+
median: number | null | undefined;
|
|
10
|
+
average: number | null | undefined;
|
|
11
|
+
p80: number | null | undefined;
|
|
12
|
+
p90: number | null | undefined;
|
|
13
|
+
p99: number | null | undefined;
|
|
14
|
+
eventCount: number | null | undefined;
|
|
15
|
+
}
|
|
16
|
+
type ObserveMetricsKey = `${string}:${AppPlatform}`;
|
|
17
|
+
export type ObserveMetricsMap = Map<ObserveMetricsKey, Map<string, MetricValues>>;
|
|
18
|
+
export type BuildNumbersMap = Map<ObserveMetricsKey, string[]>;
|
|
19
|
+
export type UpdateIdsMap = Map<ObserveMetricsKey, string[]>;
|
|
20
|
+
export declare function makeMetricsKey(appVersion: string, platform: AppPlatform): ObserveMetricsKey;
|
|
21
|
+
export type MetricValuesJson = Partial<Record<StatisticKey, number | null>>;
|
|
22
|
+
export interface ObserveMetricsVersionResult {
|
|
23
|
+
appVersion: string;
|
|
24
|
+
platform: AppPlatform;
|
|
25
|
+
metrics: Record<string, MetricValuesJson>;
|
|
26
|
+
}
|
|
27
|
+
export interface ObserveMetricsJsonOutput {
|
|
28
|
+
versions: ObserveMetricsVersionResult[];
|
|
29
|
+
totalEventCounts: Record<string, Record<string, number>>;
|
|
30
|
+
}
|
|
31
|
+
export declare function buildObserveMetricsJson(metricsMap: ObserveMetricsMap, metricNames: string[], stats: StatisticKey[], totalEventCounts?: Map<string, number>): ObserveMetricsJsonOutput;
|
|
32
|
+
export declare function buildObserveMetricsTable(metricsMap: ObserveMetricsMap, metricNames: string[], stats: StatisticKey[], options?: {
|
|
33
|
+
daysBack?: number;
|
|
34
|
+
buildNumbersMap?: BuildNumbersMap;
|
|
35
|
+
updateIdsMap?: UpdateIdsMap;
|
|
36
|
+
totalEventCounts?: Map<string, number>;
|
|
37
|
+
}): string;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.STAT_DISPLAY_NAMES = exports.STAT_ALIASES = void 0;
|
|
4
|
+
exports.resolveStatKey = resolveStatKey;
|
|
5
|
+
exports.makeMetricsKey = makeMetricsKey;
|
|
6
|
+
exports.buildObserveMetricsJson = buildObserveMetricsJson;
|
|
7
|
+
exports.buildObserveMetricsTable = buildObserveMetricsTable;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
10
|
+
const errors_1 = require("../commandUtils/errors");
|
|
11
|
+
const platform_1 = require("../platform");
|
|
12
|
+
const metricNames_1 = require("./metricNames");
|
|
13
|
+
exports.STAT_ALIASES = {
|
|
14
|
+
min: 'min',
|
|
15
|
+
max: 'max',
|
|
16
|
+
med: 'median',
|
|
17
|
+
median: 'median',
|
|
18
|
+
avg: 'average',
|
|
19
|
+
average: 'average',
|
|
20
|
+
p80: 'p80',
|
|
21
|
+
p90: 'p90',
|
|
22
|
+
p99: 'p99',
|
|
23
|
+
count: 'eventCount',
|
|
24
|
+
event_count: 'eventCount',
|
|
25
|
+
eventCount: 'eventCount',
|
|
26
|
+
};
|
|
27
|
+
exports.STAT_DISPLAY_NAMES = {
|
|
28
|
+
min: 'Min',
|
|
29
|
+
max: 'Max',
|
|
30
|
+
median: 'Med',
|
|
31
|
+
average: 'Avg',
|
|
32
|
+
p80: 'P80',
|
|
33
|
+
p90: 'P90',
|
|
34
|
+
p99: 'P99',
|
|
35
|
+
eventCount: 'Count',
|
|
36
|
+
};
|
|
37
|
+
function resolveStatKey(input) {
|
|
38
|
+
const resolved = exports.STAT_ALIASES[input];
|
|
39
|
+
if (resolved) {
|
|
40
|
+
return resolved;
|
|
41
|
+
}
|
|
42
|
+
throw new errors_1.EasCommandError(`Unknown statistic: "${input}". Valid options: ${Object.keys(exports.STAT_ALIASES).join(', ')}`);
|
|
43
|
+
}
|
|
44
|
+
function formatStatValue(stat, value) {
|
|
45
|
+
if (value == null) {
|
|
46
|
+
return '-';
|
|
47
|
+
}
|
|
48
|
+
if (stat === 'eventCount') {
|
|
49
|
+
return String(value);
|
|
50
|
+
}
|
|
51
|
+
return `${value.toFixed(2)}s`;
|
|
52
|
+
}
|
|
53
|
+
function formatMergedCell(stat, statValue, eventCount) {
|
|
54
|
+
const formatted = formatStatValue(stat, statValue);
|
|
55
|
+
const count = eventCount != null ? String(eventCount) : '-';
|
|
56
|
+
return `${formatted} (${count})`;
|
|
57
|
+
}
|
|
58
|
+
function makeMetricsKey(appVersion, platform) {
|
|
59
|
+
return `${appVersion}:${platform}`;
|
|
60
|
+
}
|
|
61
|
+
function parseMetricsKey(key) {
|
|
62
|
+
const lastColon = key.lastIndexOf(':');
|
|
63
|
+
return {
|
|
64
|
+
appVersion: key.slice(0, lastColon),
|
|
65
|
+
platform: key.slice(lastColon + 1),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function buildObserveMetricsJson(metricsMap, metricNames, stats, totalEventCounts) {
|
|
69
|
+
const versions = [];
|
|
70
|
+
for (const [key, versionMetrics] of metricsMap) {
|
|
71
|
+
const { appVersion, platform } = parseMetricsKey(key);
|
|
72
|
+
const metrics = {};
|
|
73
|
+
for (const metricName of metricNames) {
|
|
74
|
+
const values = versionMetrics.get(metricName);
|
|
75
|
+
const statValues = {};
|
|
76
|
+
for (const stat of stats) {
|
|
77
|
+
statValues[stat] = values?.[stat] ?? null;
|
|
78
|
+
}
|
|
79
|
+
metrics[metricName] = statValues;
|
|
80
|
+
}
|
|
81
|
+
versions.push({ appVersion, platform, metrics });
|
|
82
|
+
}
|
|
83
|
+
// Group total event counts by metric → platform
|
|
84
|
+
const counts = {};
|
|
85
|
+
if (totalEventCounts) {
|
|
86
|
+
for (const [key, count] of totalEventCounts) {
|
|
87
|
+
const lastColon = key.lastIndexOf(':');
|
|
88
|
+
const metricName = key.slice(0, lastColon);
|
|
89
|
+
const platform = key.slice(lastColon + 1);
|
|
90
|
+
if (!counts[metricName]) {
|
|
91
|
+
counts[metricName] = {};
|
|
92
|
+
}
|
|
93
|
+
counts[metricName][platform] = count;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { versions, totalEventCounts: counts };
|
|
97
|
+
}
|
|
98
|
+
function buildStatsDescription(displayStats) {
|
|
99
|
+
return displayStats.map(s => exports.STAT_DISPLAY_NAMES[s]).join(', ');
|
|
100
|
+
}
|
|
101
|
+
function buildTimeRangeDescription(daysBack) {
|
|
102
|
+
if (daysBack) {
|
|
103
|
+
return `for the last ${daysBack} days`;
|
|
104
|
+
}
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
function renderTable(headers, rows, footerRow) {
|
|
108
|
+
const allRows = footerRow ? [...rows, footerRow] : rows;
|
|
109
|
+
const colWidths = headers.map((h, i) => Math.max(h.length, ...allRows.map(r => (r[i] ?? '').length)));
|
|
110
|
+
const headerLine = headers.map((h, i) => h.padEnd(colWidths[i])).join(' ');
|
|
111
|
+
const separatorLine = colWidths.map(w => '-'.repeat(w)).join(' ');
|
|
112
|
+
const dataLines = rows.map(row => row.map((cell, i) => cell.padEnd(colWidths[i])).join(' '));
|
|
113
|
+
const lines = [chalk_1.default.bold(headerLine), separatorLine, ...dataLines];
|
|
114
|
+
if (footerRow) {
|
|
115
|
+
lines.push(separatorLine);
|
|
116
|
+
lines.push(footerRow.map((cell, i) => cell.padEnd(colWidths[i])).join(' '));
|
|
117
|
+
}
|
|
118
|
+
return lines.join('\n');
|
|
119
|
+
}
|
|
120
|
+
function buildObserveMetricsTable(metricsMap, metricNames, stats, options) {
|
|
121
|
+
const { versions: results } = buildObserveMetricsJson(metricsMap, metricNames, stats);
|
|
122
|
+
if (results.length === 0) {
|
|
123
|
+
return chalk_1.default.yellow('No metrics data found.');
|
|
124
|
+
}
|
|
125
|
+
const displayStats = stats.filter(s => s !== 'eventCount');
|
|
126
|
+
const hasEventCount = stats.includes('eventCount');
|
|
127
|
+
// Build summary header
|
|
128
|
+
const statsDesc = displayStats.length > 0 ? buildStatsDescription(displayStats) : 'Event count';
|
|
129
|
+
const timeDesc = buildTimeRangeDescription(options?.daysBack);
|
|
130
|
+
const countSuffix = hasEventCount && displayStats.length > 0 ? ' (event count)' : '';
|
|
131
|
+
const summaryLine = `${statsDesc} values${countSuffix}${timeDesc ? ` ${timeDesc}` : ''}`;
|
|
132
|
+
// Group results by platform
|
|
133
|
+
const byPlatform = new Map();
|
|
134
|
+
for (const result of results) {
|
|
135
|
+
if (!byPlatform.has(result.platform)) {
|
|
136
|
+
byPlatform.set(result.platform, []);
|
|
137
|
+
}
|
|
138
|
+
byPlatform.get(result.platform).push(result);
|
|
139
|
+
}
|
|
140
|
+
// Build metric column headers
|
|
141
|
+
const metricHeaders = [];
|
|
142
|
+
for (const m of metricNames) {
|
|
143
|
+
const name = (0, metricNames_1.getMetricDisplayName)(m);
|
|
144
|
+
if (displayStats.length > 0 && hasEventCount) {
|
|
145
|
+
// Merged mode: one column per metric
|
|
146
|
+
metricHeaders.push(name);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Separate columns per stat
|
|
150
|
+
for (const stat of displayStats.length > 0
|
|
151
|
+
? displayStats
|
|
152
|
+
: ['eventCount']) {
|
|
153
|
+
metricHeaders.push(`${name} ${exports.STAT_DISPLAY_NAMES[stat]}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Check if any version has updates
|
|
158
|
+
const hasUpdates = options?.updateIdsMap
|
|
159
|
+
? Array.from(options.updateIdsMap.values()).some(ids => ids.length > 0)
|
|
160
|
+
: false;
|
|
161
|
+
const headers = ['App Version', ...(hasUpdates ? ['Updates'] : []), ...metricHeaders];
|
|
162
|
+
const sections = [chalk_1.default.bold(summaryLine)];
|
|
163
|
+
for (const [platform, platformResults] of byPlatform) {
|
|
164
|
+
sections.push('');
|
|
165
|
+
sections.push(chalk_1.default.bold(platform_1.appPlatformDisplayNames[platform]));
|
|
166
|
+
const rows = platformResults.map(result => {
|
|
167
|
+
const key = makeMetricsKey(result.appVersion, result.platform);
|
|
168
|
+
const buildNumbers = options?.buildNumbersMap?.get(key);
|
|
169
|
+
const versionLabel = buildNumbers?.length
|
|
170
|
+
? `${result.appVersion} (${buildNumbers.join(', ')})`
|
|
171
|
+
: result.appVersion;
|
|
172
|
+
const updateIds = options?.updateIdsMap?.get(key);
|
|
173
|
+
const updatesLabel = updateIds?.length ? updateIds.join(', ') : '';
|
|
174
|
+
const metricCells = [];
|
|
175
|
+
for (const m of metricNames) {
|
|
176
|
+
const values = result.metrics[m];
|
|
177
|
+
if (displayStats.length > 0 && hasEventCount) {
|
|
178
|
+
for (const stat of displayStats) {
|
|
179
|
+
metricCells.push(formatMergedCell(stat, values?.[stat] ?? null, values?.eventCount ?? null));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
for (const stat of displayStats.length > 0
|
|
184
|
+
? displayStats
|
|
185
|
+
: ['eventCount']) {
|
|
186
|
+
metricCells.push(formatStatValue(stat, values?.[stat] ?? null));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return [versionLabel, ...(hasUpdates ? [updatesLabel] : []), ...metricCells];
|
|
191
|
+
});
|
|
192
|
+
let footerRow;
|
|
193
|
+
if (options?.totalEventCounts) {
|
|
194
|
+
const countCells = [];
|
|
195
|
+
for (const m of metricNames) {
|
|
196
|
+
const count = options.totalEventCounts.get(`${m}:${platform}`);
|
|
197
|
+
countCells.push(count != null ? count.toLocaleString() : '-');
|
|
198
|
+
}
|
|
199
|
+
if (countCells.some(c => c !== '-')) {
|
|
200
|
+
footerRow = ['Total events', ...(hasUpdates ? [''] : []), ...countCells];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
sections.push(renderTable(headers, rows, footerRow));
|
|
204
|
+
}
|
|
205
|
+
return sections.join('\n');
|
|
206
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AppVersionsResult } from './fetchVersions';
|
|
2
|
+
export interface AppVersionJson {
|
|
3
|
+
platform: string;
|
|
4
|
+
appVersion: string;
|
|
5
|
+
firstSeenAt: string;
|
|
6
|
+
eventCount: number;
|
|
7
|
+
uniqueUserCount: number;
|
|
8
|
+
buildNumbers: AppBuildNumberJson[];
|
|
9
|
+
updates: AppUpdateJson[];
|
|
10
|
+
}
|
|
11
|
+
export interface AppBuildNumberJson {
|
|
12
|
+
appBuildNumber: string;
|
|
13
|
+
firstSeenAt: string;
|
|
14
|
+
eventCount: number;
|
|
15
|
+
uniqueUserCount: number;
|
|
16
|
+
easBuilds: AppEasBuildJson[];
|
|
17
|
+
}
|
|
18
|
+
export interface AppUpdateJson {
|
|
19
|
+
appUpdateId: string;
|
|
20
|
+
firstSeenAt: string;
|
|
21
|
+
eventCount: number;
|
|
22
|
+
uniqueUserCount: number;
|
|
23
|
+
easBuilds: AppEasBuildJson[];
|
|
24
|
+
}
|
|
25
|
+
export interface AppEasBuildJson {
|
|
26
|
+
easBuildId: string;
|
|
27
|
+
firstSeenAt: string;
|
|
28
|
+
eventCount: number;
|
|
29
|
+
uniqueUserCount: number;
|
|
30
|
+
}
|
|
31
|
+
export declare function buildObserveVersionsJson(results: AppVersionsResult[]): AppVersionJson[];
|
|
32
|
+
export declare function buildObserveVersionsTable(results: AppVersionsResult[]): string;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildObserveVersionsJson = buildObserveVersionsJson;
|
|
4
|
+
exports.buildObserveVersionsTable = buildObserveVersionsTable;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
+
const platform_1 = require("../platform");
|
|
8
|
+
function formatDate(isoString) {
|
|
9
|
+
const date = new Date(isoString);
|
|
10
|
+
return date.toLocaleDateString('en-US', {
|
|
11
|
+
year: 'numeric',
|
|
12
|
+
month: 'short',
|
|
13
|
+
day: 'numeric',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function mapEasBuilds(easBuilds) {
|
|
17
|
+
return easBuilds.map(b => ({
|
|
18
|
+
easBuildId: b.easBuildId,
|
|
19
|
+
firstSeenAt: b.firstSeenAt,
|
|
20
|
+
eventCount: b.eventCount,
|
|
21
|
+
uniqueUserCount: b.uniqueUserCount,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
function mapBuildNumbers(buildNumbers) {
|
|
25
|
+
return buildNumbers.map(bn => ({
|
|
26
|
+
appBuildNumber: bn.appBuildNumber,
|
|
27
|
+
firstSeenAt: bn.firstSeenAt,
|
|
28
|
+
eventCount: bn.eventCount,
|
|
29
|
+
uniqueUserCount: bn.uniqueUserCount,
|
|
30
|
+
easBuilds: mapEasBuilds(bn.easBuilds),
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
function mapUpdates(updates) {
|
|
34
|
+
return updates.map(u => ({
|
|
35
|
+
appUpdateId: u.appUpdateId,
|
|
36
|
+
firstSeenAt: u.firstSeenAt,
|
|
37
|
+
eventCount: u.eventCount,
|
|
38
|
+
uniqueUserCount: u.uniqueUserCount,
|
|
39
|
+
easBuilds: mapEasBuilds(u.easBuilds),
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
function buildObserveVersionsJson(results) {
|
|
43
|
+
const output = [];
|
|
44
|
+
for (const { platform, appVersions } of results) {
|
|
45
|
+
for (const v of appVersions) {
|
|
46
|
+
output.push({
|
|
47
|
+
platform: platform,
|
|
48
|
+
appVersion: v.appVersion,
|
|
49
|
+
firstSeenAt: v.firstSeenAt,
|
|
50
|
+
eventCount: v.eventCount,
|
|
51
|
+
uniqueUserCount: v.uniqueUserCount,
|
|
52
|
+
buildNumbers: mapBuildNumbers(v.buildNumbers),
|
|
53
|
+
updates: mapUpdates(v.updates),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return output;
|
|
58
|
+
}
|
|
59
|
+
function renderTable(headers, rows) {
|
|
60
|
+
const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map(r => r[i].length)));
|
|
61
|
+
const headerLine = headers.map((h, i) => h.padEnd(colWidths[i])).join(' ');
|
|
62
|
+
const separatorLine = colWidths.map(w => '-'.repeat(w)).join(' ');
|
|
63
|
+
const dataLines = rows.map(row => row.map((cell, i) => cell.padEnd(colWidths[i])).join(' '));
|
|
64
|
+
return [chalk_1.default.bold(headerLine), separatorLine, ...dataLines].join('\n');
|
|
65
|
+
}
|
|
66
|
+
function buildObserveVersionsTable(results) {
|
|
67
|
+
const hasAnyVersions = results.some(r => r.appVersions.length > 0);
|
|
68
|
+
if (!hasAnyVersions) {
|
|
69
|
+
return chalk_1.default.yellow('No app versions found.');
|
|
70
|
+
}
|
|
71
|
+
const headers = ['App Version', 'First Seen', 'Events', 'Users', 'Builds', 'Updates'];
|
|
72
|
+
const sections = [];
|
|
73
|
+
for (const { platform, appVersions } of results) {
|
|
74
|
+
if (appVersions.length === 0) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (sections.length > 0) {
|
|
78
|
+
sections.push('');
|
|
79
|
+
}
|
|
80
|
+
sections.push(chalk_1.default.bold(platform_1.appPlatformDisplayNames[platform]));
|
|
81
|
+
const rows = appVersions.map(version => [
|
|
82
|
+
version.appVersion,
|
|
83
|
+
formatDate(version.firstSeenAt),
|
|
84
|
+
String(version.eventCount),
|
|
85
|
+
String(version.uniqueUserCount),
|
|
86
|
+
String(version.buildNumbers.length),
|
|
87
|
+
String(version.updates.length),
|
|
88
|
+
]);
|
|
89
|
+
sections.push(renderTable(headers, rows));
|
|
90
|
+
}
|
|
91
|
+
return sections.join('\n');
|
|
92
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.METRIC_SHORT_NAMES = exports.METRIC_ALIASES = void 0;
|
|
4
|
+
exports.resolveMetricName = resolveMetricName;
|
|
5
|
+
exports.getMetricDisplayName = getMetricDisplayName;
|
|
6
|
+
const errors_1 = require("../commandUtils/errors");
|
|
7
|
+
exports.METRIC_ALIASES = {
|
|
8
|
+
tti: 'expo.app_startup.tti',
|
|
9
|
+
ttr: 'expo.app_startup.ttr',
|
|
10
|
+
cold_launch: 'expo.app_startup.cold_launch_time',
|
|
11
|
+
warm_launch: 'expo.app_startup.warm_launch_time',
|
|
12
|
+
bundle_load: 'expo.app_startup.bundle_load_time',
|
|
13
|
+
};
|
|
14
|
+
const KNOWN_FULL_NAMES = new Set(Object.values(exports.METRIC_ALIASES));
|
|
15
|
+
exports.METRIC_SHORT_NAMES = {
|
|
16
|
+
'expo.app_startup.cold_launch_time': 'Cold Launch',
|
|
17
|
+
'expo.app_startup.warm_launch_time': 'Warm Launch',
|
|
18
|
+
'expo.app_startup.tti': 'TTI',
|
|
19
|
+
'expo.app_startup.ttr': 'TTR',
|
|
20
|
+
'expo.app_startup.bundle_load_time': 'Bundle Load',
|
|
21
|
+
};
|
|
22
|
+
function resolveMetricName(input) {
|
|
23
|
+
if (exports.METRIC_ALIASES[input]) {
|
|
24
|
+
return exports.METRIC_ALIASES[input];
|
|
25
|
+
}
|
|
26
|
+
if (KNOWN_FULL_NAMES.has(input) || input.includes('.')) {
|
|
27
|
+
return input;
|
|
28
|
+
}
|
|
29
|
+
throw new errors_1.EasCommandError(`Unknown metric: "${input}". Use a full metric name (e.g. expo.app_startup.tti) or a short alias: ${Object.keys(exports.METRIC_ALIASES).join(', ')}`);
|
|
30
|
+
}
|
|
31
|
+
function getMetricDisplayName(metricName) {
|
|
32
|
+
return exports.METRIC_SHORT_NAMES[metricName] ?? metricName;
|
|
33
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const DEFAULT_DAYS_BACK = 60;
|
|
2
|
+
export declare function startAndEndTime({ daysBack, start, end, }: {
|
|
3
|
+
daysBack?: number;
|
|
4
|
+
start?: string;
|
|
5
|
+
end?: string;
|
|
6
|
+
}): {
|
|
7
|
+
startTime: string;
|
|
8
|
+
endTime: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function resolveTimeRange(flags: {
|
|
11
|
+
days?: number;
|
|
12
|
+
start?: string;
|
|
13
|
+
end?: string;
|
|
14
|
+
}): {
|
|
15
|
+
daysBack?: number;
|
|
16
|
+
startTime: string;
|
|
17
|
+
endTime: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_DAYS_BACK = void 0;
|
|
4
|
+
exports.startAndEndTime = startAndEndTime;
|
|
5
|
+
exports.resolveTimeRange = resolveTimeRange;
|
|
6
|
+
const fetchMetrics_1 = require("./fetchMetrics");
|
|
7
|
+
exports.DEFAULT_DAYS_BACK = 60;
|
|
8
|
+
function startAndEndTime({ daysBack, start, end, }) {
|
|
9
|
+
let startTime;
|
|
10
|
+
let endTime;
|
|
11
|
+
if (daysBack) {
|
|
12
|
+
endTime = new Date().toISOString();
|
|
13
|
+
startTime = new Date(Date.now() - daysBack * 24 * 60 * 60 * 1000).toISOString();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
endTime = end ?? new Date().toISOString();
|
|
17
|
+
startTime =
|
|
18
|
+
start ?? new Date(Date.now() - exports.DEFAULT_DAYS_BACK * 24 * 60 * 60 * 1000).toISOString();
|
|
19
|
+
}
|
|
20
|
+
return { startTime, endTime };
|
|
21
|
+
}
|
|
22
|
+
function resolveTimeRange(flags) {
|
|
23
|
+
if (flags.start) {
|
|
24
|
+
(0, fetchMetrics_1.validateDateFlag)(flags.start, '--start');
|
|
25
|
+
}
|
|
26
|
+
if (flags.end) {
|
|
27
|
+
(0, fetchMetrics_1.validateDateFlag)(flags.end, '--end');
|
|
28
|
+
}
|
|
29
|
+
const daysBack = flags.days ?? (flags.start ? undefined : exports.DEFAULT_DAYS_BACK);
|
|
30
|
+
const { startTime, endTime } = startAndEndTime({
|
|
31
|
+
daysBack,
|
|
32
|
+
start: flags.start,
|
|
33
|
+
end: flags.end,
|
|
34
|
+
});
|
|
35
|
+
return { daysBack, startTime, endTime };
|
|
36
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { ExpoConfig } from '@expo/config';
|
|
2
2
|
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
|
3
3
|
import { AccountFragment } from '../graphql/generated';
|
|
4
|
-
import { Actor } from '../user/User';
|
|
5
|
-
export declare function getUsernameForBuildMetadataAndBuildJob(user: Actor): string | undefined;
|
|
6
4
|
/**
|
|
7
5
|
* Return a useful name describing the project config.
|
|
8
6
|
* - dynamic: app.config.js
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUsernameForBuildMetadataAndBuildJob = getUsernameForBuildMetadataAndBuildJob;
|
|
4
3
|
exports.getProjectConfigDescription = getProjectConfigDescription;
|
|
5
4
|
exports.isExpoUpdatesInstalled = isExpoUpdatesInstalled;
|
|
6
5
|
exports.isExpoNotificationsInstalled = isExpoNotificationsInstalled;
|
|
@@ -26,17 +25,6 @@ const api_1 = require("../api");
|
|
|
26
25
|
const AppQuery_1 = require("../graphql/queries/AppQuery");
|
|
27
26
|
const log_1 = tslib_1.__importStar(require("../log"));
|
|
28
27
|
const expoCli_1 = require("../utils/expoCli");
|
|
29
|
-
function getUsernameForBuildMetadataAndBuildJob(user) {
|
|
30
|
-
switch (user.__typename) {
|
|
31
|
-
case 'User':
|
|
32
|
-
return user.username;
|
|
33
|
-
case 'SSOUser':
|
|
34
|
-
return user.username;
|
|
35
|
-
case 'Robot':
|
|
36
|
-
// robot users don't have usernames
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
28
|
/**
|
|
41
29
|
* Return a useful name describing the project config.
|
|
42
30
|
* - dynamic: app.config.js
|
|
@@ -44,7 +44,7 @@ async function hasIgnoredIosProjectAsync(projectDir, vcsClient) {
|
|
|
44
44
|
const pbxProjectPath = config_plugins_1.IOSConfig.Paths.getPBXProjectPath(projectDir);
|
|
45
45
|
return await vcsClient.isFileIgnoredAsync(path_1.default.relative(vcsRootPath, pbxProjectPath));
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
catch {
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
50
|
}
|
package/build/sentry.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const Sentry = tslib_1.__importStar(require("@sentry/node"));
|
|
5
|
+
const easCli_1 = require("./utils/easCli");
|
|
6
|
+
Sentry.init({
|
|
7
|
+
dsn: process.env.EAS_CLI_SENTRY_DSN,
|
|
8
|
+
enabled: !!process.env.EAS_CLI_SENTRY_DSN,
|
|
9
|
+
environment: getSentryEnvironment(),
|
|
10
|
+
release: easCli_1.easCliVersion ? `eas-cli@${easCli_1.easCliVersion}` : undefined,
|
|
11
|
+
});
|
|
12
|
+
Sentry.setTag('source', 'eas-cli');
|
|
13
|
+
function getSentryEnvironment() {
|
|
14
|
+
if (process.env.EXPO_LOCAL) {
|
|
15
|
+
return 'local';
|
|
16
|
+
}
|
|
17
|
+
else if (process.env.EXPO_STAGING) {
|
|
18
|
+
return 'staging';
|
|
19
|
+
}
|
|
20
|
+
return 'production';
|
|
21
|
+
}
|
|
22
|
+
exports.default = Sentry;
|
package/build/update/utils.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ExpoConfig } from '@expo/config';
|
|
2
2
|
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
|
3
|
-
import { AppPlatform, Robot, SsoUser, Update, UpdateBranchFragment, UpdateFragment, UpdatePublishMutation, User } from '../graphql/generated';
|
|
3
|
+
import { AppPlatform, PartnerActor, Robot, SsoUser, Update, UpdateBranchFragment, UpdateFragment, UpdatePublishMutation, User } from '../graphql/generated';
|
|
4
4
|
import { RequestedPlatform } from '../platform';
|
|
5
5
|
export type FormatUpdateParameter = Pick<Update, 'id' | 'createdAt' | 'message'> & {
|
|
6
|
-
actor?: Pick<Robot, '__typename' | 'firstName'> | Pick<User, '__typename' | 'username'> | Pick<SsoUser, '__typename' | 'username'> | null;
|
|
6
|
+
actor?: Pick<Robot, '__typename' | 'firstName'> | Pick<User, '__typename' | 'username'> | Pick<SsoUser, '__typename' | 'username'> | Pick<PartnerActor, '__typename' | 'username'> | null;
|
|
7
7
|
};
|
|
8
8
|
export type UpdateJsonInfo = {
|
|
9
9
|
branch: string;
|
package/build/update/utils.js
CHANGED
|
@@ -51,6 +51,17 @@ class SessionManager {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
async logoutAsync() {
|
|
54
|
+
const sessionSecret = this.getSessionSecret();
|
|
55
|
+
if (sessionSecret) {
|
|
56
|
+
const apiV2Client = new api_1.ApiV2Client({ accessToken: null, sessionSecret });
|
|
57
|
+
try {
|
|
58
|
+
await apiV2Client.postAsync('auth/logout', { body: {} });
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
// Best-effort: clear the local session even if the server request fails
|
|
62
|
+
log_1.default.debug('Failed to invalidate session secret on server:', e);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
54
65
|
this.currentActor = undefined;
|
|
55
66
|
await this.setSessionAsync(undefined);
|
|
56
67
|
}
|
package/build/user/User.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { CurrentUserQuery, Robot, SsoUser, User } from '../graphql/generated';
|
|
1
|
+
import { CurrentUserQuery, PartnerActor, Robot, SsoUser, User } from '../graphql/generated';
|
|
2
2
|
export type Actor = NonNullable<CurrentUserQuery['meActor']>;
|
|
3
3
|
/**
|
|
4
4
|
* Resolve the name of the actor, either normal user, sso user or robot user.
|
|
5
5
|
* This should be used whenever the "current user" needs to be displayed.
|
|
6
6
|
* The display name CANNOT be used as project owner.
|
|
7
7
|
*/
|
|
8
|
-
export declare function getActorDisplayName(actor?: Pick<Robot, '__typename' | 'firstName'> | Pick<User, '__typename' | 'username'> | Pick<SsoUser, '__typename' | 'username'> | null): string;
|
|
8
|
+
export declare function getActorDisplayName(actor?: Pick<Robot, '__typename' | 'firstName'> | Pick<User, '__typename' | 'username'> | Pick<SsoUser, '__typename' | 'username'> | Pick<PartnerActor, '__typename' | 'username'> | null): string;
|
|
9
9
|
export declare function getActorUsername(actor?: Actor): string | null;
|
package/build/user/User.js
CHANGED
|
@@ -15,6 +15,8 @@ function getActorDisplayName(actor) {
|
|
|
15
15
|
return actor.firstName ? `${actor.firstName} (robot)` : 'robot';
|
|
16
16
|
case 'SSOUser':
|
|
17
17
|
return actor.username;
|
|
18
|
+
case 'PartnerActor':
|
|
19
|
+
return actor.username;
|
|
18
20
|
case undefined:
|
|
19
21
|
return 'unknown';
|
|
20
22
|
}
|
|
@@ -23,6 +25,7 @@ function getActorUsername(actor) {
|
|
|
23
25
|
switch (actor?.__typename) {
|
|
24
26
|
case 'User':
|
|
25
27
|
case 'SSOUser':
|
|
28
|
+
case 'PartnerActor':
|
|
26
29
|
return actor.username;
|
|
27
30
|
case 'Robot':
|
|
28
31
|
case undefined:
|