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.
Files changed (89) hide show
  1. package/README.md +92 -90
  2. package/build/build/android/prepareJob.js +2 -2
  3. package/build/build/ios/prepareJob.js +2 -2
  4. package/build/build/metadata.js +2 -1
  5. package/build/commandUtils/EasCommand.js +23 -2
  6. package/build/commandUtils/context/contextUtils/getProjectIdAsync.js +2 -0
  7. package/build/commandUtils/pagination.d.ts +2 -1
  8. package/build/commandUtils/pagination.js +3 -2
  9. package/build/commandUtils/workflow/fetchLogs.js +11 -2
  10. package/build/commandUtils/workflow/types.d.ts +5 -1
  11. package/build/commandUtils/workflow/utils.js +22 -16
  12. package/build/commands/deploy/index.js +18 -2
  13. package/build/commands/metadata/pull.d.ts +1 -0
  14. package/build/commands/metadata/pull.js +9 -4
  15. package/build/commands/metadata/push.d.ts +1 -0
  16. package/build/commands/metadata/push.js +9 -4
  17. package/build/commands/observe/events.d.ts +27 -0
  18. package/build/commands/observe/events.js +140 -0
  19. package/build/commands/observe/metrics.d.ts +21 -0
  20. package/build/commands/observe/metrics.js +111 -0
  21. package/build/commands/observe/versions.d.ts +19 -0
  22. package/build/commands/observe/versions.js +69 -0
  23. package/build/commands/project/onboarding.js +3 -0
  24. package/build/commands/workflow/logs.js +12 -12
  25. package/build/credentials/ios/IosCredentialsProvider.js +8 -4
  26. package/build/credentials/ios/utils/provisioningProfile.d.ts +1 -0
  27. package/build/credentials/ios/utils/provisioningProfile.js +15 -1
  28. package/build/graphql/generated.d.ts +1273 -73
  29. package/build/graphql/generated.js +59 -19
  30. package/build/graphql/queries/ObserveQuery.d.ts +35 -0
  31. package/build/graphql/queries/ObserveQuery.js +109 -0
  32. package/build/graphql/queries/UserQuery.js +3 -0
  33. package/build/graphql/types/Observe.d.ts +3 -0
  34. package/build/graphql/types/Observe.js +84 -0
  35. package/build/graphql/types/Update.js +3 -0
  36. package/build/metadata/apple/config/reader.d.ts +13 -1
  37. package/build/metadata/apple/config/reader.js +33 -0
  38. package/build/metadata/apple/config/writer.d.ts +11 -1
  39. package/build/metadata/apple/config/writer.js +57 -0
  40. package/build/metadata/apple/data.d.ts +7 -2
  41. package/build/metadata/apple/rules/infoRestrictedWords.js +6 -1
  42. package/build/metadata/apple/tasks/age-rating.d.ts +1 -1
  43. package/build/metadata/apple/tasks/age-rating.js +19 -3
  44. package/build/metadata/apple/tasks/app-clip.d.ts +37 -0
  45. package/build/metadata/apple/tasks/app-clip.js +404 -0
  46. package/build/metadata/apple/tasks/app-review-detail.js +7 -2
  47. package/build/metadata/apple/tasks/index.js +6 -0
  48. package/build/metadata/apple/tasks/previews.d.ts +18 -0
  49. package/build/metadata/apple/tasks/previews.js +212 -0
  50. package/build/metadata/apple/tasks/screenshots.d.ts +18 -0
  51. package/build/metadata/apple/tasks/screenshots.js +235 -0
  52. package/build/metadata/apple/types.d.ts +61 -1
  53. package/build/metadata/auth.d.ts +11 -1
  54. package/build/metadata/auth.js +96 -2
  55. package/build/metadata/download.d.ts +5 -1
  56. package/build/metadata/download.js +16 -8
  57. package/build/metadata/upload.d.ts +5 -1
  58. package/build/metadata/upload.js +11 -4
  59. package/build/observe/fetchEvents.d.ts +27 -0
  60. package/build/observe/fetchEvents.js +83 -0
  61. package/build/observe/fetchMetrics.d.ts +11 -0
  62. package/build/observe/fetchMetrics.js +78 -0
  63. package/build/observe/fetchVersions.d.ts +7 -0
  64. package/build/observe/fetchVersions.js +31 -0
  65. package/build/observe/formatEvents.d.ts +31 -0
  66. package/build/observe/formatEvents.js +99 -0
  67. package/build/observe/formatMetrics.d.ts +38 -0
  68. package/build/observe/formatMetrics.js +206 -0
  69. package/build/observe/formatVersions.d.ts +32 -0
  70. package/build/observe/formatVersions.js +92 -0
  71. package/build/observe/metricNames.d.ts +4 -0
  72. package/build/observe/metricNames.js +33 -0
  73. package/build/observe/startAndEndTime.d.ts +18 -0
  74. package/build/observe/startAndEndTime.js +36 -0
  75. package/build/project/projectUtils.d.ts +0 -2
  76. package/build/project/projectUtils.js +0 -12
  77. package/build/project/workflow.js +1 -1
  78. package/build/sentry.d.ts +2 -0
  79. package/build/sentry.js +22 -0
  80. package/build/update/utils.d.ts +2 -2
  81. package/build/update/utils.js +1 -0
  82. package/build/user/SessionManager.js +11 -0
  83. package/build/user/User.d.ts +2 -2
  84. package/build/user/User.js +3 -0
  85. package/build/user/expoBrowserAuthFlowLauncher.js +70 -13
  86. package/build/worker/upload.js +15 -5
  87. package/oclif.manifest.json +1794 -1306
  88. package/package.json +15 -11
  89. package/schema/metadata-0.json +213 -0
@@ -4,20 +4,65 @@ exports.getSessionUsingBrowserAuthFlowAsync = getSessionUsingBrowserAuthFlowAsyn
4
4
  const tslib_1 = require("tslib");
5
5
  const assert_1 = tslib_1.__importDefault(require("assert"));
6
6
  const better_opn_1 = tslib_1.__importDefault(require("better-opn"));
7
+ const crypto_1 = tslib_1.__importDefault(require("crypto"));
7
8
  const http_1 = tslib_1.__importDefault(require("http"));
8
- const querystring_1 = tslib_1.__importDefault(require("querystring"));
9
9
  const api_1 = require("../api");
10
+ const fetch_1 = tslib_1.__importDefault(require("../fetch"));
10
11
  const log_1 = tslib_1.__importDefault(require("../log"));
12
+ const CLIENT_ID = 'eas-cli';
13
+ function generateCodeVerifier() {
14
+ return crypto_1.default.randomBytes(32).toString('base64url');
15
+ }
16
+ function generateCodeChallenge(codeVerifier) {
17
+ return crypto_1.default.createHash('sha256').update(codeVerifier).digest('base64url');
18
+ }
19
+ function generateState() {
20
+ return crypto_1.default.randomBytes(32).toString('base64url');
21
+ }
22
+ async function exchangeCodeForSessionSecretAsync({ code, codeVerifier, redirectUri, }) {
23
+ const tokenUrl = `${(0, api_1.getExpoApiBaseUrl)()}/v2/auth/token`;
24
+ const response = await (0, fetch_1.default)(tokenUrl, {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ },
29
+ body: JSON.stringify({
30
+ grant_type: 'authorization_code',
31
+ code,
32
+ redirect_uri: redirectUri,
33
+ code_verifier: codeVerifier,
34
+ client_id: CLIENT_ID,
35
+ }),
36
+ });
37
+ const result = await response.json();
38
+ const sessionSecret = result?.data?.session_secret;
39
+ if (!sessionSecret) {
40
+ throw new Error('Failed to obtain session secret from token exchange.');
41
+ }
42
+ return sessionSecret;
43
+ }
11
44
  async function getSessionUsingBrowserAuthFlowAsync({ sso = false }) {
12
45
  const scheme = 'http';
13
46
  const hostname = 'localhost';
14
- const path = '/auth/callback';
47
+ const callbackPath = '/auth/callback';
15
48
  const expoWebsiteUrl = (0, api_1.getExpoWebsiteBaseUrl)();
49
+ const codeVerifier = generateCodeVerifier();
50
+ const codeChallenge = generateCodeChallenge(codeVerifier);
51
+ const state = generateState();
52
+ const buildRedirectUri = (port) => `${scheme}://${hostname}:${port}${callbackPath}`;
16
53
  const buildExpoLoginUrl = (port, sso) => {
17
- const params = querystring_1.default.stringify({
18
- confirm_account: true,
19
- app_redirect_uri: `${scheme}://${hostname}:${port}${path}`,
20
- });
54
+ // Note: we avoid URLSearchParams here because better-opn calls encodeURI()
55
+ // on the URL before passing it to AppleScript, which would double-encode
56
+ // the percent-encoded values from URLSearchParams.toString().
57
+ const params = [
58
+ `client_id=${CLIENT_ID}`,
59
+ `redirect_uri=${buildRedirectUri(port)}`,
60
+ `response_type=code`,
61
+ `code_challenge=${codeChallenge}`,
62
+ `code_challenge_method=S256`,
63
+ `state=${state}`,
64
+ `confirm_account=true`,
65
+ ].join('&');
21
66
  return `${expoWebsiteUrl}${sso ? '/sso-login' : '/login'}?${params}`;
22
67
  };
23
68
  // Start server and begin auth flow
@@ -34,22 +79,34 @@ async function getSessionUsingBrowserAuthFlowAsync({ sso = false }) {
34
79
  connection.destroy();
35
80
  }
36
81
  };
37
- try {
82
+ const handleRequestAsync = async () => {
38
83
  if (!(request.method === 'GET' && request.url?.includes('/auth/callback'))) {
39
84
  throw new Error('Unexpected login response.');
40
85
  }
41
86
  const url = new URL(request.url, `http:${request.headers.host}`);
42
- const sessionSecret = url.searchParams.get('session_secret');
43
- if (!sessionSecret) {
44
- throw new Error('Request missing session_secret search parameter.');
87
+ const code = url.searchParams.get('code');
88
+ const returnedState = url.searchParams.get('state');
89
+ if (!code) {
90
+ throw new Error('Request missing code search parameter.');
91
+ }
92
+ if (returnedState !== state) {
93
+ throw new Error('State mismatch. Possible CSRF attack.');
45
94
  }
95
+ const address = server.address();
96
+ (0, assert_1.default)(address !== null && typeof address === 'object');
97
+ const redirectUri = buildRedirectUri(address.port);
98
+ const sessionSecret = await exchangeCodeForSessionSecretAsync({
99
+ code,
100
+ codeVerifier,
101
+ redirectUri,
102
+ });
46
103
  resolve(sessionSecret);
47
104
  redirectAndCleanup('success');
48
- }
49
- catch (error) {
105
+ };
106
+ handleRequestAsync().catch(error => {
50
107
  redirectAndCleanup('error');
51
108
  reject(error);
52
- }
109
+ });
53
110
  });
54
111
  server.listen(0, hostname, () => {
55
112
  log_1.default.log('Waiting for browser login...');
@@ -166,6 +166,7 @@ async function* batchUploadAsync(init, payloads, onProgressUpdate) {
166
166
  (() => {
167
167
  onProgressUpdate(getProgressValue());
168
168
  });
169
+ let firstError = null;
169
170
  try {
170
171
  let index = 0;
171
172
  while (index < payloads.length || queue.size > 0) {
@@ -177,27 +178,36 @@ async function* batchUploadAsync(init, payloads, onProgressUpdate) {
177
178
  progressTracker[currentIndex] = progress;
178
179
  sendProgressUpdate();
179
180
  });
180
- const uploadPromise = uploadAsync(initWithSignal, payload, onChildProgressUpdate).finally(() => {
181
+ const uploadPromise = uploadAsync(initWithSignal, payload, onChildProgressUpdate).then(result => {
181
182
  queue.delete(uploadPromise);
182
183
  progressTracker[currentIndex] = 1;
184
+ return result;
185
+ }, error => {
186
+ queue.delete(uploadPromise);
187
+ firstError ??= error;
188
+ controller.abort();
189
+ throw error;
183
190
  });
184
191
  queue.add(uploadPromise);
185
192
  yield { payload, progress: getProgressValue() };
186
193
  }
194
+ if (firstError) {
195
+ break;
196
+ }
187
197
  yield {
188
198
  ...(await Promise.race(queue)),
189
199
  progress: getProgressValue(),
190
200
  };
191
201
  }
192
- if (queue.size > 0) {
193
- controller.abort();
194
- }
195
202
  }
196
203
  catch (error) {
197
204
  if (error.name !== 'AbortError') {
198
- throw error;
205
+ firstError ??= error;
199
206
  }
200
207
  }
208
+ if (firstError) {
209
+ throw firstError;
210
+ }
201
211
  }
202
212
  function createProgressBar(label = 'Uploading assets') {
203
213
  const queueProgressBar = new cli_progress_1.default.SingleBar({ format: `|{bar}| {percentage}% ${label}` }, cli_progress_1.default.Presets.rect);