eas-cli 0.49.0 → 0.50.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.
Files changed (37) hide show
  1. package/README.md +42 -42
  2. package/build/build/build.d.ts +6 -2
  3. package/build/build/build.js +191 -104
  4. package/build/build/runBuildAndSubmit.js +5 -1
  5. package/build/credentials/context.js +5 -0
  6. package/build/credentials/ios/actions/AscApiKeyUtils.js +0 -1
  7. package/build/credentials/ios/actions/ConfigureProvisioningProfile.js +1 -1
  8. package/build/credentials/ios/actions/CreateProvisioningProfile.js +1 -1
  9. package/build/credentials/ios/appstore/AppStoreApi.d.ts +5 -1
  10. package/build/credentials/ios/appstore/AppStoreApi.js +38 -15
  11. package/build/credentials/ios/appstore/ascApiKey.d.ts +21 -5
  12. package/build/credentials/ios/appstore/ascApiKey.js +28 -12
  13. package/build/credentials/ios/appstore/authenticate.d.ts +9 -18
  14. package/build/credentials/ios/appstore/authenticate.js +43 -3
  15. package/build/credentials/ios/appstore/authenticateTypes.d.ts +42 -0
  16. package/build/credentials/ios/appstore/authenticateTypes.js +16 -0
  17. package/build/credentials/ios/appstore/contractMessages.d.ts +3 -0
  18. package/build/credentials/ios/appstore/contractMessages.js +12 -0
  19. package/build/credentials/ios/appstore/distributionCertificate.d.ts +1 -1
  20. package/build/credentials/ios/appstore/ensureAppExists.d.ts +2 -2
  21. package/build/credentials/ios/appstore/ensureAppExists.js +12 -5
  22. package/build/credentials/ios/appstore/provisioningProfile.d.ts +1 -1
  23. package/build/credentials/ios/appstore/provisioningProfileAdhoc.d.ts +1 -1
  24. package/build/credentials/ios/appstore/pushKey.d.ts +4 -4
  25. package/build/credentials/ios/appstore/pushKey.js +8 -8
  26. package/build/credentials/ios/appstore/resolveCredentials.d.ts +10 -1
  27. package/build/credentials/ios/appstore/resolveCredentials.js +125 -3
  28. package/build/graphql/generated.d.ts +73 -0
  29. package/build/graphql/generated.js +16 -1
  30. package/build/graphql/types/Build.js +4 -0
  31. package/build/submit/ios/AppProduce.d.ts +0 -1
  32. package/build/submit/ios/AppProduce.js +5 -6
  33. package/build/submit/ios/AppSpecificPasswordSource.js +2 -2
  34. package/build/utils/code-signing.d.ts +0 -5
  35. package/build/utils/code-signing.js +5 -51
  36. package/oclif.manifest.json +1 -1
  37. package/package.json +6 -6
@@ -4,9 +4,12 @@ exports.waitForBuildEndAsync = exports.prepareBuildRequestForPlatformAsync = voi
4
4
  const tslib_1 = require("tslib");
5
5
  const eas_build_job_1 = require("@expo/eas-build-job");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
7
8
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
9
+ const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
8
10
  const common_1 = require("../analytics/common");
9
11
  const events_1 = require("../analytics/events");
12
+ const api_1 = require("../api");
10
13
  const generated_1 = require("../graphql/generated");
11
14
  const BuildQuery_1 = require("../graphql/queries/BuildQuery");
12
15
  const log_1 = tslib_1.__importStar(require("../log"));
@@ -54,7 +57,6 @@ async function prepareBuildRequestForPlatformAsync(builder) {
54
57
  credentials: credentialsResult === null || credentialsResult === void 0 ? void 0 : credentialsResult.credentials,
55
58
  });
56
59
  return async () => {
57
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
58
60
  if (ctx.localBuildOptions.enable) {
59
61
  await (0, local_1.runLocalBuildAsync)(job, ctx.localBuildOptions);
60
62
  return undefined;
@@ -64,31 +66,35 @@ async function prepareBuildRequestForPlatformAsync(builder) {
64
66
  return await sendBuildRequestAsync(builder, job, metadata);
65
67
  }
66
68
  catch (error) {
67
- if (((_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.errorCode) === 'TURTLE_DEPRECATED_JOB_FORMAT') {
68
- log_1.default.error('EAS Build API has changed, please upgrade to the latest eas-cli version.');
69
- throw new Error('Build request failed.');
70
- }
71
- else if (((_f = (_e = (_d = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.extensions) === null || _f === void 0 ? void 0 : _f.errorCode) === 'EAS_BUILD_DOWN_FOR_MAINTENANCE') {
72
- log_1.default.error('EAS Build is down for maintenance, please try again later. Check https://status.expo.dev/ for updates.');
73
- throw new Error('Build request failed.');
74
- }
75
- else if (((_j = (_h = (_g = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.extensions) === null || _j === void 0 ? void 0 : _j.errorCode) === 'EAS_BUILD_FREE_TIER_DISABLED') {
76
- log_1.default.error('EAS Build free tier is temporarily disabled, please try again later. Check https://status.expo.dev/ for updates.');
77
- throw new Error('Build request failed.');
78
- }
79
- else if (((_m = (_l = (_k = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.extensions) === null || _m === void 0 ? void 0 : _m.errorCode) === 'EAS_BUILD_TOO_MANY_PENDING_BUILDS') {
80
- log_1.default.error(`You have already reached the maximum number of pending ${platform_1.requestedPlatformDisplayNames[job.platform]} builds for your account. Try again later.`);
81
- throw new Error('Build request failed.');
82
- }
83
- else if (error === null || error === void 0 ? void 0 : error.graphQLErrors) {
84
- log_1.default.error('Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, please report the issue.');
85
- }
86
- throw error;
69
+ handleBuildRequestError(error, job.platform);
87
70
  }
88
71
  }
89
72
  };
90
73
  }
91
74
  exports.prepareBuildRequestForPlatformAsync = prepareBuildRequestForPlatformAsync;
75
+ function handleBuildRequestError(error, platform) {
76
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
77
+ if (((_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.errorCode) === 'TURTLE_DEPRECATED_JOB_FORMAT') {
78
+ log_1.default.error('EAS Build API has changed, please upgrade to the latest eas-cli version.');
79
+ throw new Error('Build request failed.');
80
+ }
81
+ else if (((_f = (_e = (_d = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.extensions) === null || _f === void 0 ? void 0 : _f.errorCode) === 'EAS_BUILD_DOWN_FOR_MAINTENANCE') {
82
+ log_1.default.error('EAS Build is down for maintenance, please try again later. Check https://status.expo.dev/ for updates.');
83
+ throw new Error('Build request failed.');
84
+ }
85
+ else if (((_j = (_h = (_g = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.extensions) === null || _j === void 0 ? void 0 : _j.errorCode) === 'EAS_BUILD_FREE_TIER_DISABLED') {
86
+ log_1.default.error('EAS Build free tier is temporarily disabled, please try again later. Check https://status.expo.dev/ for updates.');
87
+ throw new Error('Build request failed.');
88
+ }
89
+ else if (((_m = (_l = (_k = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.extensions) === null || _m === void 0 ? void 0 : _m.errorCode) === 'EAS_BUILD_TOO_MANY_PENDING_BUILDS') {
90
+ log_1.default.error(`You have already reached the maximum number of pending ${platform_1.requestedPlatformDisplayNames[platform]} builds for your account. Try again later.`);
91
+ throw new Error('Build request failed.');
92
+ }
93
+ else if (error === null || error === void 0 ? void 0 : error.graphQLErrors) {
94
+ log_1.default.error('Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, please report the issue.');
95
+ }
96
+ throw error;
97
+ }
92
98
  async function uploadProjectAsync(ctx) {
93
99
  let projectTarballPath;
94
100
  try {
@@ -130,96 +136,177 @@ async function sendBuildRequestAsync(builder, job, metadata) {
130
136
  trackingCtx: ctx.trackingCtx,
131
137
  });
132
138
  }
133
- async function waitForBuildEndAsync(buildIds, { timeoutSec = 3600, intervalSec = 30 } = {}) {
134
- log_1.default.log(`Waiting for build${buildIds.length > 1 ? 's' : ''} to complete. You can press Ctrl+C to exit.`);
135
- const spinner = (0, ora_1.ora)().start();
136
- let time = new Date().getTime();
137
- const endTime = time + timeoutSec * 1000;
138
- while (time <= endTime) {
139
- const builds = await Promise.all(buildIds.map(async (buildId) => {
140
- try {
141
- return await BuildQuery_1.BuildQuery.byIdAsync(buildId, { useCache: false });
142
- }
143
- catch (err) {
144
- log_1.default.debug('Failed to fetch the build status', err);
145
- return null;
146
- }
147
- }));
148
- if (builds.length === 1) {
149
- const [build] = builds;
150
- if (build !== null) {
151
- switch (build.status) {
152
- case generated_1.BuildStatus.Finished:
153
- spinner.succeed('Build finished');
154
- return builds;
155
- case generated_1.BuildStatus.New:
156
- spinner.text = 'Build created';
157
- break;
158
- case generated_1.BuildStatus.InQueue:
159
- spinner.text = 'Build queued...';
160
- break;
161
- case generated_1.BuildStatus.Canceled:
162
- spinner.text = 'Build canceled';
163
- spinner.stopAndPersist();
164
- return builds;
165
- case generated_1.BuildStatus.InProgress:
166
- spinner.text = 'Build in progress...';
167
- break;
168
- case generated_1.BuildStatus.Errored:
169
- spinner.fail('Build failed');
170
- if (build.error) {
171
- return builds;
172
- }
173
- else {
174
- throw new Error(`Standalone build failed!`);
175
- }
176
- default:
177
- spinner.warn('Unknown status');
178
- throw new Error(`Unknown build status: ${build.status} - aborting!`);
139
+ async function waitForBuildEndAsync({ buildIds, accountName }, {
140
+ // 2 hours (max build time limit) + 10 minutes (possible queue time )
141
+ timeoutSec = 2 * 60 * 60 + 10 * 60, intervalSec = 10, } = {}) {
142
+ const b = `build${buildIds.length > 1 ? 's' : ''}`;
143
+ log_1.default.log(`Waiting for ${b} to complete. You can press Ctrl+C to exit.`);
144
+ const spinner = (0, ora_1.ora)(`Waiting for ${b} to complete.`).start();
145
+ const endTime = new Date().getTime() + timeoutSec * 1000;
146
+ while (new Date().getTime() <= endTime) {
147
+ const builds = await getBuildsSafelyAsync(buildIds);
148
+ const { refetch } = builds.length === 1
149
+ ? await handleSingleBuildProgressAsync({ build: builds[0], accountName }, { spinner })
150
+ : await handleMultipleBuildsProgressAsync({ builds }, { spinner });
151
+ if (!refetch) {
152
+ return builds;
153
+ }
154
+ await (0, promise_1.sleepAsync)(intervalSec * 1000);
155
+ }
156
+ spinner.fail('Timed out');
157
+ throw new Error('Timeout reached! It is taking longer than expected to finish the build, aborting...');
158
+ }
159
+ exports.waitForBuildEndAsync = waitForBuildEndAsync;
160
+ async function getBuildsSafelyAsync(buildIds) {
161
+ const promises = buildIds.map(async (buildId) => {
162
+ try {
163
+ return await BuildQuery_1.BuildQuery.byIdAsync(buildId, { useCache: false });
164
+ }
165
+ catch (err) {
166
+ log_1.default.debug('Failed to fetch the build status', err);
167
+ return null;
168
+ }
169
+ });
170
+ return await Promise.all(promises);
171
+ }
172
+ let queueProgressBarStarted = false;
173
+ const queueProgressBar = new cli_progress_1.default.SingleBar({ format: '|{bar}| {estimatedWaitTime}' }, cli_progress_1.default.Presets.rect);
174
+ async function handleSingleBuildProgressAsync({ build, accountName }, { spinner }) {
175
+ if (build === null) {
176
+ spinner.text = 'Could not fetch the build status. Check your network connection.';
177
+ return { refetch: true };
178
+ }
179
+ if (queueProgressBarStarted && (build === null || build === void 0 ? void 0 : build.status) && build.status !== generated_1.BuildStatus.InQueue) {
180
+ if (build.status === generated_1.BuildStatus.InProgress) {
181
+ queueProgressBar.update(queueProgressBar.getTotal(), {
182
+ estimatedWaitTime: '',
183
+ });
184
+ }
185
+ queueProgressBar.stop();
186
+ log_1.default.newLine();
187
+ queueProgressBarStarted = false;
188
+ spinner.start('Build is about to start');
189
+ }
190
+ switch (build.status) {
191
+ case generated_1.BuildStatus.Finished:
192
+ spinner.succeed('Build finished');
193
+ return { refetch: false };
194
+ case generated_1.BuildStatus.New:
195
+ spinner.text = `Build is waiting to enter the queue. Check your concurrency limit at ${chalk_1.default.underline(formatAccountSubscriptionsUrl(accountName))}.`;
196
+ break;
197
+ case generated_1.BuildStatus.InQueue: {
198
+ spinner.text = 'Build queued...';
199
+ const progressBarPayload = typeof build.estimatedWaitTimeLeftSeconds === 'number'
200
+ ? { estimatedWaitTime: formatEstimatedWaitTime(build.estimatedWaitTimeLeftSeconds) }
201
+ : { estimatedWaitTime: '' };
202
+ if (!queueProgressBarStarted &&
203
+ typeof build.initialQueuePosition === 'number' &&
204
+ typeof build.queuePosition === 'number') {
205
+ spinner.stopAndPersist();
206
+ if (build.priority !== generated_1.BuildPriority.High) {
207
+ log_1.default.newLine();
208
+ log_1.default.log('Start builds sooner in the priority queue.');
209
+ log_1.default.log(`Sign up for EAS Production or Enterprise at ${chalk_1.default.underline(formatAccountSubscriptionsUrl(accountName))}`);
179
210
  }
211
+ log_1.default.newLine();
212
+ log_1.default.log('Waiting in queue');
213
+ queueProgressBar.start(build.initialQueuePosition + 1, build.initialQueuePosition - build.queuePosition + 1, progressBarPayload);
214
+ queueProgressBarStarted = true;
180
215
  }
181
- else {
182
- if (!spinner.text) {
183
- spinner.text = 'Could not fetch the build status. Check your network connection.';
184
- }
216
+ if (typeof build.queuePosition === 'number') {
217
+ queueProgressBar.update(build.queuePosition, progressBarPayload);
185
218
  }
219
+ break;
186
220
  }
187
- else {
188
- if (builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Finished).length === builds.length) {
189
- spinner.succeed('All builds have finished');
190
- return builds;
191
- }
192
- else if (builds.filter(build => (build === null || build === void 0 ? void 0 : build.status)
193
- ? [generated_1.BuildStatus.Finished, generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build.status)
194
- : false).length === builds.length) {
195
- spinner.fail('Some of the builds were canceled or failed.');
196
- return builds;
221
+ case generated_1.BuildStatus.Canceled:
222
+ spinner.fail('Build canceled');
223
+ return { refetch: false };
224
+ case generated_1.BuildStatus.InProgress:
225
+ spinner.text = 'Build in progress...';
226
+ break;
227
+ case generated_1.BuildStatus.Errored:
228
+ spinner.fail('Build failed');
229
+ if (build.error) {
230
+ return { refetch: false };
197
231
  }
198
232
  else {
199
- const newBuilds = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.New).length;
200
- const inQueue = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InQueue).length;
201
- const inProgress = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InProgress).length;
202
- const errored = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Errored).length;
203
- const finished = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Finished).length;
204
- const canceled = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Canceled).length;
205
- const unknown = builds.length - newBuilds - inQueue - inProgress - errored - finished - canceled;
206
- spinner.text = [
207
- newBuilds && `Builds created: ${newBuilds}`,
208
- inQueue && `Builds in queue: ${inQueue}`,
209
- inProgress && `Builds in progress: ${inProgress}`,
210
- canceled && `Builds canceled: ${canceled}`,
211
- errored && chalk_1.default.red(`Builds failed: ${errored}`),
212
- finished && chalk_1.default.green(`Builds finished: ${finished}`),
213
- unknown && chalk_1.default.red(`Builds with unknown status: ${unknown}`),
214
- ]
215
- .filter(i => i)
216
- .join('\t');
233
+ throw new Error('Standalone build failed!');
217
234
  }
235
+ default:
236
+ spinner.warn('Unknown status');
237
+ throw new Error(`Unknown build status: ${build.status} - aborting!`);
238
+ }
239
+ return { refetch: true };
240
+ }
241
+ const statusToDisplayName = {
242
+ [generated_1.BuildStatus.New]: 'waiting to enter the queue (concurrency limit reached)',
243
+ [generated_1.BuildStatus.InQueue]: 'in queue',
244
+ [generated_1.BuildStatus.InProgress]: 'in progress',
245
+ [generated_1.BuildStatus.Canceled]: 'canceled',
246
+ [generated_1.BuildStatus.Finished]: 'finished',
247
+ [generated_1.BuildStatus.Errored]: 'failed',
248
+ };
249
+ const platforms = [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios];
250
+ async function handleMultipleBuildsProgressAsync({ builds: maybeBuilds }, { spinner }) {
251
+ const buildCount = maybeBuilds.length;
252
+ const builds = maybeBuilds.filter(isBuildFragment);
253
+ const allFinished = builds.filter(build => build.status === generated_1.BuildStatus.Finished).length === buildCount;
254
+ const allSettled = builds.filter(build => [generated_1.BuildStatus.Finished, generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build.status)).length === buildCount;
255
+ if (allSettled) {
256
+ if (allFinished) {
257
+ spinner.succeed(formatSettledBuildsText(builds));
218
258
  }
219
- time = new Date().getTime();
220
- await (0, promise_1.sleepAsync)(intervalSec * 1000);
259
+ else {
260
+ spinner.fail(formatSettledBuildsText(builds));
261
+ }
262
+ return { refetch: false };
263
+ }
264
+ else {
265
+ spinner.text = formatPendingBuildsText(builds);
266
+ return { refetch: true };
221
267
  }
222
- spinner.warn('Timed out');
223
- throw new Error('Timeout reached! It is taking longer than expected to finish the build, aborting...');
224
268
  }
225
- exports.waitForBuildEndAsync = waitForBuildEndAsync;
269
+ function formatSettledBuildsText(builds) {
270
+ return platforms
271
+ .map(platform => {
272
+ const build = (0, nullthrows_1.default)(builds.find(build => build.platform === platform), `Build for platform ${platform} must be defined in this context`);
273
+ return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(statusToDisplayName[build.status])}`;
274
+ })
275
+ .join('\n ');
276
+ }
277
+ function formatPendingBuildsText(builds) {
278
+ return platforms
279
+ .map(platform => {
280
+ const build = builds.find(build => build.platform === platform);
281
+ const status = build ? statusToDisplayName[build.status] : 'unknown';
282
+ let extraInfo = '';
283
+ if ((build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InQueue &&
284
+ typeof build.initialQueuePosition === 'number' &&
285
+ typeof build.queuePosition === 'number') {
286
+ const percent = Math.floor(((build.initialQueuePosition - build.queuePosition + 1) /
287
+ (build.initialQueuePosition + 1)) *
288
+ 100);
289
+ const estimatedWaitTime = typeof build.estimatedWaitTimeLeftSeconds === 'number'
290
+ ? ` - ${formatEstimatedWaitTime(build.estimatedWaitTimeLeftSeconds)}`
291
+ : '';
292
+ extraInfo = ` - queue progress: ${chalk_1.default.bold(`${percent}%`)}${estimatedWaitTime}`;
293
+ }
294
+ return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(status)}${extraInfo}`;
295
+ })
296
+ .join('\n ');
297
+ }
298
+ function isBuildFragment(maybeBuild) {
299
+ return maybeBuild !== null;
300
+ }
301
+ function formatEstimatedWaitTime(estimatedWaitTimeLeftSeconds) {
302
+ if (estimatedWaitTimeLeftSeconds < 5 * 60) {
303
+ return 'starting soon...';
304
+ }
305
+ else {
306
+ const n = Math.floor(estimatedWaitTimeLeftSeconds / (10 * 60)) + 1;
307
+ return `starting in about ${n}0 minutes...`;
308
+ }
309
+ }
310
+ function formatAccountSubscriptionsUrl(accountName) {
311
+ return new URL(`/accounts/${accountName}/settings/subscriptions`, (0, api_1.getExpoWebsiteBaseUrl)()).toString();
312
+ }
@@ -98,7 +98,11 @@ async function runBuildAndSubmitAsync(projectDir, flags) {
98
98
  }
99
99
  return;
100
100
  }
101
- const builds = await (0, build_2.waitForBuildEndAsync)(startedBuilds.map(({ build }) => build.id));
101
+ const { accountName } = Object.values(buildCtxByPlatform)[0];
102
+ const builds = await (0, build_2.waitForBuildEndAsync)({
103
+ buildIds: startedBuilds.map(({ build }) => build.id),
104
+ accountName,
105
+ });
102
106
  (0, printBuildInfo_1.printBuildResults)(builds, flags.json);
103
107
  const haveAllBuildsFailedOrCanceled = builds.every(build => (build === null || build === void 0 ? void 0 : build.status) && [generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build === null || build === void 0 ? void 0 : build.status));
104
108
  if (haveAllBuildsFailedOrCanceled || !flags.autoSubmit) {
@@ -12,6 +12,7 @@ const User_1 = require("../user/User");
12
12
  const AndroidGraphqlClient = tslib_1.__importStar(require("./android/api/GraphqlClient"));
13
13
  const IosGraphqlClient = tslib_1.__importStar(require("./ios/api/GraphqlClient"));
14
14
  const AppStoreApi_1 = tslib_1.__importDefault(require("./ios/appstore/AppStoreApi"));
15
+ const authenticateTypes_1 = require("./ios/appstore/authenticateTypes");
15
16
  class CredentialsContext {
16
17
  constructor(options) {
17
18
  var _a, _b;
@@ -73,6 +74,10 @@ class CredentialsContext {
73
74
  if (this.nonInteractive) {
74
75
  return;
75
76
  }
77
+ if (this.appStore.defaultAuthenticationMode === authenticateTypes_1.AuthenticationMode.API_KEY) {
78
+ await this.appStore.ensureAuthenticatedAsync();
79
+ return;
80
+ }
76
81
  log_1.default.log(chalk_1.default.green('If you provide your Apple account credentials we will be able to generate all necessary build credentials and fully validate them.'));
77
82
  log_1.default.log(chalk_1.default.green('This is optional, but without Apple account access you will need to provide all the missing values manually and we can only run minimal validation on them.'));
78
83
  const confirm = await (0, prompts_1.confirmAsync)({
@@ -70,7 +70,6 @@ async function provideOrGenerateAscApiKeyAsync(ctx, purpose) {
70
70
  }
71
71
  exports.provideOrGenerateAscApiKeyAsync = provideOrGenerateAscApiKeyAsync;
72
72
  async function generateAscApiKeyAsync(ctx, purpose) {
73
- //console.log('debug');
74
73
  await ctx.appStore.ensureAuthenticatedAsync();
75
74
  const ascApiKey = await ctx.appStore.createAscApiKeyAsync({
76
75
  nickname: getAscApiKeyName(purpose),
@@ -46,7 +46,7 @@ class ConfigureProvisioningProfile {
46
46
  certP12: certificateP12,
47
47
  certPassword: certificatePassword,
48
48
  distCertSerialNumber: serialNumber,
49
- teamId: authCtx.appleId,
49
+ teamId: authCtx.team.id,
50
50
  });
51
51
  const bundleIdTag = `(${app.bundleIdentifier})`;
52
52
  const slugTag = `@${app.account.name}/${app.projectName}`;
@@ -45,7 +45,7 @@ class CreateProvisioningProfile {
45
45
  certP12: this.distributionCertificate.certificateP12,
46
46
  certPassword: this.distributionCertificate.certificatePassword,
47
47
  distCertSerialNumber: this.distributionCertificate.serialNumber,
48
- teamId: (_c = (_b = this.distributionCertificate.appleTeam) === null || _b === void 0 ? void 0 : _b.appleTeamIdentifier) !== null && _c !== void 0 ? _c : appleAuthCtx.appleId,
48
+ teamId: (_c = (_b = this.distributionCertificate.appleTeam) === null || _b === void 0 ? void 0 : _b.appleTeamIdentifier) !== null && _c !== void 0 ? _c : appleAuthCtx.team.id,
49
49
  });
50
50
  }
51
51
  }
@@ -1,9 +1,13 @@
1
1
  import { AscApiKey, AscApiKeyInfo, DistributionCertificate, DistributionCertificateStoreInfo, ProvisioningProfile, ProvisioningProfileStoreInfo, PushKey, PushKeyStoreInfo } from './Credentials.types';
2
- import { AuthCtx, Options as AuthenticateOptions } from './authenticate';
2
+ import { Options as AuthenticateOptions } from './authenticate';
3
+ import { AuthCtx, AuthenticationMode, UserAuthCtx } from './authenticateTypes';
3
4
  import { AppLookupParams, IosCapabilitiesOptions } from './ensureAppExists';
4
5
  import { ProfileClass } from './provisioningProfile';
5
6
  export default class AppStoreApi {
6
7
  authCtx?: AuthCtx;
8
+ defaultAuthenticationMode: AuthenticationMode;
9
+ constructor();
10
+ ensureUserAuthenticatedAsync(options?: AuthenticateOptions): Promise<UserAuthCtx>;
7
11
  ensureAuthenticatedAsync(options?: AuthenticateOptions): Promise<AuthCtx>;
8
12
  ensureBundleIdExistsAsync(app: AppLookupParams, options?: IosCapabilitiesOptions): Promise<void>;
9
13
  listDistributionCertificatesAsync(): Promise<DistributionCertificateStoreInfo[]>;
@@ -1,16 +1,39 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const log_1 = tslib_1.__importDefault(require("../../../log"));
3
5
  const ascApiKey_1 = require("./ascApiKey");
4
6
  const authenticate_1 = require("./authenticate");
7
+ const authenticateTypes_1 = require("./authenticateTypes");
5
8
  const distributionCertificate_1 = require("./distributionCertificate");
6
9
  const ensureAppExists_1 = require("./ensureAppExists");
7
10
  const provisioningProfile_1 = require("./provisioningProfile");
8
11
  const provisioningProfileAdhoc_1 = require("./provisioningProfileAdhoc");
9
12
  const pushKey_1 = require("./pushKey");
13
+ const resolveCredentials_1 = require("./resolveCredentials");
10
14
  class AppStoreApi {
15
+ constructor() {
16
+ this.defaultAuthenticationMode = (0, resolveCredentials_1.hasAscEnvVars)()
17
+ ? authenticateTypes_1.AuthenticationMode.API_KEY
18
+ : authenticateTypes_1.AuthenticationMode.USER;
19
+ }
20
+ async ensureUserAuthenticatedAsync(options) {
21
+ if (this.authCtx && !(0, authenticate_1.isUserAuthCtx)(this.authCtx)) {
22
+ // already authenticated, but with the wrong type
23
+ log_1.default.log(`Only user authentication is supported. Reauthenticating as user...`);
24
+ this.authCtx = undefined;
25
+ }
26
+ const updatedAuthCtx = await this.ensureAuthenticatedAsync({
27
+ ...options,
28
+ mode: authenticateTypes_1.AuthenticationMode.USER,
29
+ });
30
+ return (0, authenticate_1.assertUserAuthCtx)(updatedAuthCtx);
31
+ }
11
32
  async ensureAuthenticatedAsync(options) {
33
+ var _a;
12
34
  if (!this.authCtx) {
13
- this.authCtx = await (0, authenticate_1.authenticateAsync)(options);
35
+ const mode = (_a = options === null || options === void 0 ? void 0 : options.mode) !== null && _a !== void 0 ? _a : this.defaultAuthenticationMode;
36
+ this.authCtx = await (0, authenticate_1.authenticateAsync)({ mode, ...options });
14
37
  }
15
38
  return this.authCtx;
16
39
  }
@@ -31,16 +54,16 @@ class AppStoreApi {
31
54
  return await (0, distributionCertificate_1.revokeDistributionCertificateAsync)(ctx, ids);
32
55
  }
33
56
  async listPushKeysAsync() {
34
- const ctx = await this.ensureAuthenticatedAsync();
35
- return await (0, pushKey_1.listPushKeysAsync)(ctx);
57
+ const userCtx = await this.ensureUserAuthenticatedAsync();
58
+ return await (0, pushKey_1.listPushKeysAsync)(userCtx);
36
59
  }
37
60
  async createPushKeyAsync(name) {
38
- const ctx = await this.ensureAuthenticatedAsync();
39
- return await (0, pushKey_1.createPushKeyAsync)(ctx, name);
61
+ const userCtx = await this.ensureUserAuthenticatedAsync();
62
+ return await (0, pushKey_1.createPushKeyAsync)(userCtx, name);
40
63
  }
41
64
  async revokePushKeyAsync(ids) {
42
- const ctx = await this.ensureAuthenticatedAsync();
43
- return await (0, pushKey_1.revokePushKeyAsync)(ctx, ids);
65
+ const userCtx = await this.ensureUserAuthenticatedAsync();
66
+ return await (0, pushKey_1.revokePushKeyAsync)(userCtx, ids);
44
67
  }
45
68
  async useExistingProvisioningProfileAsync(bundleIdentifier, provisioningProfile, distCert) {
46
69
  const ctx = await this.ensureAuthenticatedAsync();
@@ -63,20 +86,20 @@ class AppStoreApi {
63
86
  return await (0, provisioningProfileAdhoc_1.createOrReuseAdhocProvisioningProfileAsync)(ctx, udids, bundleIdentifier, distCertSerialNumber);
64
87
  }
65
88
  async listAscApiKeysAsync() {
66
- const ctx = await this.ensureAuthenticatedAsync();
67
- return await (0, ascApiKey_1.listAscApiKeysAsync)(ctx);
89
+ const userCtx = await this.ensureUserAuthenticatedAsync();
90
+ return await (0, ascApiKey_1.listAscApiKeysAsync)(userCtx);
68
91
  }
69
92
  async getAscApiKeyAsync(keyId) {
70
- const ctx = await this.ensureAuthenticatedAsync();
71
- return await (0, ascApiKey_1.getAscApiKeyAsync)(ctx, keyId);
93
+ const userCtx = await this.ensureUserAuthenticatedAsync();
94
+ return await (0, ascApiKey_1.getAscApiKeyAsync)(userCtx, keyId);
72
95
  }
73
96
  async createAscApiKeyAsync({ nickname }) {
74
- const ctx = await this.ensureAuthenticatedAsync();
75
- return await (0, ascApiKey_1.createAscApiKeyAsync)(ctx, { nickname });
97
+ const userCtx = await this.ensureUserAuthenticatedAsync();
98
+ return await (0, ascApiKey_1.createAscApiKeyAsync)(userCtx, { nickname });
76
99
  }
77
100
  async revokeAscApiKeyAsync(keyId) {
78
- const ctx = await this.ensureAuthenticatedAsync();
79
- return await (0, ascApiKey_1.revokeAscApiKeyAsync)(ctx, keyId);
101
+ const userCtx = await this.ensureUserAuthenticatedAsync();
102
+ return await (0, ascApiKey_1.revokeAscApiKeyAsync)(userCtx, keyId);
80
103
  }
81
104
  }
82
105
  exports.default = AppStoreApi;
@@ -1,9 +1,25 @@
1
1
  /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
2
  import { ApiKey, ApiKeyProps } from '@expo/apple-utils';
3
3
  import { AscApiKey, AscApiKeyInfo } from './Credentials.types';
4
- import { AuthCtx } from './authenticate';
5
- export declare function listAscApiKeysAsync(authCtx: AuthCtx): Promise<AscApiKeyInfo[]>;
6
- export declare function getAscApiKeyAsync(authCtx: AuthCtx, keyId: string): Promise<AscApiKeyInfo | null>;
7
- export declare function createAscApiKeyAsync(authCtx: AuthCtx, { nickname, allAppsVisible, roles, keyType, }: Partial<Pick<ApiKeyProps, 'nickname' | 'roles' | 'allAppsVisible' | 'keyType'>>): Promise<AscApiKey>;
8
- export declare function revokeAscApiKeyAsync(authCtx: AuthCtx, keyId: string): Promise<AscApiKeyInfo>;
4
+ import { AuthCtx, UserAuthCtx } from './authenticateTypes';
5
+ /**
6
+ * List App Store Connect API Keys.
7
+ * **Does not support App Store Connect API (CI).**
8
+ */
9
+ export declare function listAscApiKeysAsync(userAuthCtx: UserAuthCtx): Promise<AscApiKeyInfo[]>;
10
+ /**
11
+ * Get an App Store Connect API Key.
12
+ * **Does not support App Store Connect API (CI).**
13
+ */
14
+ export declare function getAscApiKeyAsync(userAuthCtx: UserAuthCtx, keyId: string): Promise<AscApiKeyInfo | null>;
15
+ /**
16
+ * Create an App Store Connect API Key.
17
+ * **Does not support App Store Connect API (CI).**
18
+ */
19
+ export declare function createAscApiKeyAsync(userAuthCtx: UserAuthCtx, { nickname, allAppsVisible, roles, keyType, }: Partial<Pick<ApiKeyProps, 'nickname' | 'roles' | 'allAppsVisible' | 'keyType'>>): Promise<AscApiKey>;
20
+ /**
21
+ * Revoke an App Store Connect API Key.
22
+ * **Does not support App Store Connect API (CI).**
23
+ */
24
+ export declare function revokeAscApiKeyAsync(userAuthCtx: UserAuthCtx, keyId: string): Promise<AscApiKeyInfo>;
9
25
  export declare function getAscApiKeyInfo(apiKey: ApiKey, authCtx: AuthCtx): AscApiKeyInfo;
@@ -6,13 +6,17 @@ const apple_utils_1 = require("@expo/apple-utils");
6
6
  const log_1 = tslib_1.__importDefault(require("../../../log"));
7
7
  const ora_1 = require("../../../ora");
8
8
  const authenticate_1 = require("./authenticate");
9
- async function listAscApiKeysAsync(authCtx) {
9
+ /**
10
+ * List App Store Connect API Keys.
11
+ * **Does not support App Store Connect API (CI).**
12
+ */
13
+ async function listAscApiKeysAsync(userAuthCtx) {
10
14
  const spinner = (0, ora_1.ora)(`Fetching App Store Connect API Keys.`).start();
11
15
  try {
12
- const context = (0, authenticate_1.getRequestContext)(authCtx);
16
+ const context = (0, authenticate_1.getRequestContext)(userAuthCtx);
13
17
  const keys = await apple_utils_1.ApiKey.getAsync(context);
14
18
  spinner.succeed(`Fetched App Store Connect API Keys.`);
15
- return keys.map(key => getAscApiKeyInfo(key, authCtx));
19
+ return keys.map(key => getAscApiKeyInfo(key, userAuthCtx));
16
20
  }
17
21
  catch (error) {
18
22
  spinner.fail(`Failed to fetch App Store Connect API Keys.`);
@@ -20,14 +24,18 @@ async function listAscApiKeysAsync(authCtx) {
20
24
  }
21
25
  }
22
26
  exports.listAscApiKeysAsync = listAscApiKeysAsync;
23
- async function getAscApiKeyAsync(authCtx, keyId) {
27
+ /**
28
+ * Get an App Store Connect API Key.
29
+ * **Does not support App Store Connect API (CI).**
30
+ */
31
+ async function getAscApiKeyAsync(userAuthCtx, keyId) {
24
32
  var _a;
25
33
  const spinner = (0, ora_1.ora)(`Fetching App Store Connect API Key.`).start();
26
34
  try {
27
- const context = (0, authenticate_1.getRequestContext)(authCtx);
35
+ const context = (0, authenticate_1.getRequestContext)(userAuthCtx);
28
36
  const apiKey = await apple_utils_1.ApiKey.infoAsync(context, { id: keyId });
29
37
  spinner.succeed(`Fetched App Store Connect API Key (ID: ${keyId}).`);
30
- return getAscApiKeyInfo(apiKey, authCtx);
38
+ return getAscApiKeyInfo(apiKey, userAuthCtx);
31
39
  }
32
40
  catch (error) {
33
41
  const message = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
@@ -41,10 +49,14 @@ async function getAscApiKeyAsync(authCtx, keyId) {
41
49
  }
42
50
  }
43
51
  exports.getAscApiKeyAsync = getAscApiKeyAsync;
44
- async function createAscApiKeyAsync(authCtx, { nickname, allAppsVisible, roles, keyType, }) {
52
+ /**
53
+ * Create an App Store Connect API Key.
54
+ * **Does not support App Store Connect API (CI).**
55
+ */
56
+ async function createAscApiKeyAsync(userAuthCtx, { nickname, allAppsVisible, roles, keyType, }) {
45
57
  const spinner = (0, ora_1.ora)(`Creating App Store Connect API Key.`).start();
46
58
  try {
47
- const context = (0, authenticate_1.getRequestContext)(authCtx);
59
+ const context = (0, authenticate_1.getRequestContext)(userAuthCtx);
48
60
  const key = await apple_utils_1.ApiKey.createAsync(context, {
49
61
  nickname: nickname !== null && nickname !== void 0 ? nickname : `[expo] ${new Date().getTime()}`,
50
62
  allAppsVisible: allAppsVisible !== null && allAppsVisible !== void 0 ? allAppsVisible : true,
@@ -68,7 +80,7 @@ async function createAscApiKeyAsync(authCtx, { nickname, allAppsVisible, roles,
68
80
  const fullKey = await apple_utils_1.ApiKey.infoAsync(context, { id: key.id });
69
81
  spinner.succeed(`Created App Store Connect API Key.`);
70
82
  return {
71
- ...getAscApiKeyInfo(fullKey, authCtx),
83
+ ...getAscApiKeyInfo(fullKey, userAuthCtx),
72
84
  keyP8,
73
85
  };
74
86
  }
@@ -78,14 +90,18 @@ async function createAscApiKeyAsync(authCtx, { nickname, allAppsVisible, roles,
78
90
  }
79
91
  }
80
92
  exports.createAscApiKeyAsync = createAscApiKeyAsync;
81
- async function revokeAscApiKeyAsync(authCtx, keyId) {
93
+ /**
94
+ * Revoke an App Store Connect API Key.
95
+ * **Does not support App Store Connect API (CI).**
96
+ */
97
+ async function revokeAscApiKeyAsync(userAuthCtx, keyId) {
82
98
  const spinner = (0, ora_1.ora)(`Revoking App Store Connect API Key.`).start();
83
99
  try {
84
- const context = (0, authenticate_1.getRequestContext)(authCtx);
100
+ const context = (0, authenticate_1.getRequestContext)(userAuthCtx);
85
101
  const apiKey = await apple_utils_1.ApiKey.infoAsync(context, { id: keyId });
86
102
  const revokedKey = await apiKey.revokeAsync();
87
103
  spinner.succeed(`Revoked App Store Connect API Key.`);
88
- return getAscApiKeyInfo(revokedKey, authCtx);
104
+ return getAscApiKeyInfo(revokedKey, userAuthCtx);
89
105
  }
90
106
  catch (error) {
91
107
  log_1.default.error(error);