eas-cli 0.53.0 → 0.53.1

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 (50) hide show
  1. package/README.md +42 -42
  2. package/build/analytics/events.d.ts +5 -1
  3. package/build/analytics/events.js +6 -1
  4. package/build/build/build.js +3 -1
  5. package/build/build/local.js +1 -1
  6. package/build/graphql/queries/UpdateQuery.js +1 -1
  7. package/build/metadata/apple/config/reader.d.ts +25 -0
  8. package/build/metadata/apple/config/reader.js +94 -0
  9. package/build/metadata/apple/config/writer.d.ts +23 -0
  10. package/build/metadata/apple/config/writer.js +85 -0
  11. package/build/metadata/apple/data.d.ts +20 -0
  12. package/build/metadata/apple/data.js +2 -0
  13. package/build/metadata/apple/task.d.ts +24 -0
  14. package/build/metadata/apple/task.js +6 -0
  15. package/build/metadata/apple/tasks/age-rating.d.ts +13 -0
  16. package/build/metadata/apple/tasks/age-rating.js +39 -0
  17. package/build/metadata/apple/tasks/app-info.d.ts +15 -0
  18. package/build/metadata/apple/tasks/app-info.js +71 -0
  19. package/build/metadata/apple/tasks/app-version.d.ts +27 -0
  20. package/build/metadata/apple/tasks/app-version.js +100 -0
  21. package/build/metadata/apple/tasks/index.d.ts +6 -0
  22. package/build/metadata/apple/tasks/index.js +13 -0
  23. package/build/metadata/apple/types.d.ts +50 -0
  24. package/build/metadata/apple/types.js +2 -0
  25. package/build/metadata/config.d.ts +22 -0
  26. package/build/metadata/config.js +32 -0
  27. package/build/metadata/context.d.ts +46 -0
  28. package/build/metadata/context.js +55 -0
  29. package/build/metadata/download.d.ts +6 -0
  30. package/build/metadata/download.js +58 -0
  31. package/build/metadata/errors.d.ts +37 -0
  32. package/build/metadata/errors.js +67 -0
  33. package/build/metadata/upload.d.ts +6 -0
  34. package/build/metadata/upload.js +54 -0
  35. package/build/metadata/utils/array.d.ts +1 -0
  36. package/build/metadata/utils/array.js +8 -0
  37. package/build/metadata/utils/asc.d.ts +4 -0
  38. package/build/metadata/utils/asc.js +2 -0
  39. package/build/metadata/utils/date.d.ts +12 -0
  40. package/build/metadata/utils/date.js +30 -0
  41. package/build/metadata/utils/log.d.ts +16 -0
  42. package/build/metadata/utils/log.js +23 -0
  43. package/build/metadata/utils/retry.d.ts +8 -0
  44. package/build/metadata/utils/retry.js +22 -0
  45. package/build/metadata/utils/telemetry.d.ts +20 -0
  46. package/build/metadata/utils/telemetry.js +87 -0
  47. package/build/submit/submit.js +1 -1
  48. package/build/submit/utils/errors.js +2 -0
  49. package/oclif.manifest.json +1 -1
  50. package/package.json +4 -3
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.downloadMetadataAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ const events_1 = require("../analytics/events");
8
+ const prompts_1 = require("../prompts");
9
+ const tasks_1 = require("./apple/tasks");
10
+ const config_1 = require("./config");
11
+ const context_1 = require("./context");
12
+ const errors_1 = require("./errors");
13
+ const telemetry_1 = require("./utils/telemetry");
14
+ /**
15
+ * Generate a local store configuration from the stores.
16
+ * Note, only App Store is supported at this time.
17
+ */
18
+ async function downloadMetadataAsync(metadataCtx) {
19
+ const filePath = path_1.default.resolve(metadataCtx.projectDir, metadataCtx.metadataPath);
20
+ const fileExists = await fs_extra_1.default.pathExists(filePath);
21
+ if (fileExists) {
22
+ const overwrite = await (0, prompts_1.confirmAsync)({
23
+ message: `Do you want to overwrite the existing store configuration "${metadataCtx.metadataPath}"?`,
24
+ });
25
+ if (!overwrite) {
26
+ throw new errors_1.MetadataValidationError(`Store configuration already exists at "${filePath}"`);
27
+ }
28
+ }
29
+ const { app, auth } = await (0, context_1.ensureMetadataAppStoreAuthenticatedAsync)(metadataCtx);
30
+ const { unsubscribeTelemetry, executionId } = (0, telemetry_1.subscribeTelemetry)(events_1.MetadataEvent.APPLE_METADATA_DOWNLOAD, { app, auth });
31
+ const errors = [];
32
+ const config = (0, config_1.createAppleWriter)();
33
+ const tasks = (0, tasks_1.createAppleTasks)(metadataCtx);
34
+ const taskCtx = { app };
35
+ for (const task of tasks) {
36
+ try {
37
+ await task.prepareAsync({ context: taskCtx });
38
+ }
39
+ catch (error) {
40
+ errors.push(error);
41
+ }
42
+ }
43
+ for (const task of tasks) {
44
+ try {
45
+ await task.downloadAsync({ config, context: taskCtx });
46
+ }
47
+ catch (error) {
48
+ errors.push(error);
49
+ }
50
+ }
51
+ await fs_extra_1.default.writeJson(filePath, config.toSchema(), { spaces: 2 });
52
+ unsubscribeTelemetry();
53
+ if (errors.length > 0) {
54
+ throw new errors_1.MetadataDownloadError(errors, executionId);
55
+ }
56
+ return filePath;
57
+ }
58
+ exports.downloadMetadataAsync = downloadMetadataAsync;
@@ -0,0 +1,37 @@
1
+ import type { ErrorObject } from 'ajv';
2
+ /**
3
+ * Before syncing data to the ASC API, we need to validate the metadata config.
4
+ * This error represents unrecoverable issues before syncing that data,
5
+ * and should contain useful information for the user to solve before trying again.
6
+ */
7
+ export declare class MetadataValidationError extends Error {
8
+ readonly errors?: ErrorObject[] | undefined;
9
+ constructor(message?: string, errors?: ErrorObject[] | undefined);
10
+ }
11
+ /**
12
+ * If a single entity failed to update, we don't block the other entities from uploading.
13
+ * We still attempt to update the data in the stores as much as possible.
14
+ * Because of that, we keep track of any errors encountered and throw this generic error.
15
+ * It contains that list of encountered errors to present to the user.
16
+ */
17
+ export declare class MetadataUploadError extends Error {
18
+ readonly errors: Error[];
19
+ readonly executionId: string;
20
+ constructor(errors: Error[], executionId: string);
21
+ }
22
+ /**
23
+ * If a single entity failed to download, we don't block the other entities from downloading.
24
+ * We sill attempt to pull in the data from the stores as much as possible.
25
+ * Because of that, we keep track of any errors envountered and throw this generic error.
26
+ * It contains that list of encountered errors to present to the user.
27
+ */
28
+ export declare class MetadataDownloadError extends Error {
29
+ readonly errors: Error[];
30
+ readonly executionId: string;
31
+ constructor(errors: Error[], executionId: string);
32
+ }
33
+ /**
34
+ * Handle a thrown metadata error by informing the user what went wrong.
35
+ * If a normal error is thrown, this method will re-throw that error to avoid consuming it.
36
+ */
37
+ export declare function handleMetadataError(error: Error): void;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleMetadataError = exports.MetadataDownloadError = exports.MetadataUploadError = exports.MetadataValidationError = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const log_1 = tslib_1.__importStar(require("../log"));
6
+ /**
7
+ * Before syncing data to the ASC API, we need to validate the metadata config.
8
+ * This error represents unrecoverable issues before syncing that data,
9
+ * and should contain useful information for the user to solve before trying again.
10
+ */
11
+ class MetadataValidationError extends Error {
12
+ constructor(message, errors) {
13
+ super(message !== null && message !== void 0 ? message : 'Store configuration validation failed');
14
+ this.errors = errors;
15
+ }
16
+ }
17
+ exports.MetadataValidationError = MetadataValidationError;
18
+ /**
19
+ * If a single entity failed to update, we don't block the other entities from uploading.
20
+ * We still attempt to update the data in the stores as much as possible.
21
+ * Because of that, we keep track of any errors encountered and throw this generic error.
22
+ * It contains that list of encountered errors to present to the user.
23
+ */
24
+ class MetadataUploadError extends Error {
25
+ constructor(errors, executionId) {
26
+ super(`Store configuration upload encountered ${errors.length === 1 ? 'an error' : `${errors.length} errors`}.`);
27
+ this.errors = errors;
28
+ this.executionId = executionId;
29
+ }
30
+ }
31
+ exports.MetadataUploadError = MetadataUploadError;
32
+ /**
33
+ * If a single entity failed to download, we don't block the other entities from downloading.
34
+ * We sill attempt to pull in the data from the stores as much as possible.
35
+ * Because of that, we keep track of any errors envountered and throw this generic error.
36
+ * It contains that list of encountered errors to present to the user.
37
+ */
38
+ class MetadataDownloadError extends Error {
39
+ constructor(errors, executionId) {
40
+ super(`Store configuration download encountered ${errors.length === 1 ? 'an error' : `${errors.length} errors`}.`);
41
+ this.errors = errors;
42
+ this.executionId = executionId;
43
+ }
44
+ }
45
+ exports.MetadataDownloadError = MetadataDownloadError;
46
+ /**
47
+ * Handle a thrown metadata error by informing the user what went wrong.
48
+ * If a normal error is thrown, this method will re-throw that error to avoid consuming it.
49
+ */
50
+ function handleMetadataError(error) {
51
+ var _a;
52
+ if (error instanceof MetadataValidationError) {
53
+ log_1.default.error(error.message);
54
+ log_1.default.log((_a = error.errors) === null || _a === void 0 ? void 0 : _a.map(err => ` - ${err.dataPath} ${err.message}`).join('\n'));
55
+ return;
56
+ }
57
+ if (error instanceof MetadataDownloadError || error instanceof MetadataUploadError) {
58
+ log_1.default.error(error.message);
59
+ log_1.default.log('Please check the logs for any configuration issues.');
60
+ log_1.default.log('If this issue persists, please open a new issue at:');
61
+ // TODO: add execution ID to the issue template link
62
+ log_1.default.log((0, log_1.link)('https://github.com/expo/eas-cli'));
63
+ return;
64
+ }
65
+ throw error;
66
+ }
67
+ exports.handleMetadataError = handleMetadataError;
@@ -0,0 +1,6 @@
1
+ import { MetadataContext } from './context';
2
+ /**
3
+ * Sync a local store configuration with the stores.
4
+ * Note, only App Store is supported at this time.
5
+ */
6
+ export declare function uploadMetadataAsync(metadataCtx: MetadataContext): Promise<void>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadMetadataAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ const events_1 = require("../analytics/events");
8
+ const tasks_1 = require("./apple/tasks");
9
+ const config_1 = require("./config");
10
+ const context_1 = require("./context");
11
+ const errors_1 = require("./errors");
12
+ const telemetry_1 = require("./utils/telemetry");
13
+ /**
14
+ * Sync a local store configuration with the stores.
15
+ * Note, only App Store is supported at this time.
16
+ */
17
+ async function uploadMetadataAsync(metadataCtx) {
18
+ const filePath = path_1.default.resolve(metadataCtx.projectDir, metadataCtx.metadataPath);
19
+ if (!(await fs_extra_1.default.pathExists(filePath))) {
20
+ throw new errors_1.MetadataValidationError(`Store configuration file not found "${filePath}"`);
21
+ }
22
+ const { app, auth } = await (0, context_1.ensureMetadataAppStoreAuthenticatedAsync)(metadataCtx);
23
+ const { unsubscribeTelemetry, executionId } = (0, telemetry_1.subscribeTelemetry)(events_1.MetadataEvent.APPLE_METADATA_UPLOAD, { app, auth });
24
+ const fileData = await fs_extra_1.default.readJson(filePath);
25
+ const { valid, errors: validationErrors } = (0, config_1.validateConfig)(fileData);
26
+ if (!valid) {
27
+ throw new errors_1.MetadataValidationError(`Store configuration errors found`, validationErrors);
28
+ }
29
+ const errors = [];
30
+ const config = (0, config_1.createAppleReader)(fileData);
31
+ const tasks = (0, tasks_1.createAppleTasks)(metadataCtx);
32
+ const taskCtx = { app };
33
+ for (const task of tasks) {
34
+ try {
35
+ await task.prepareAsync({ context: taskCtx });
36
+ }
37
+ catch (error) {
38
+ errors.push(error);
39
+ }
40
+ }
41
+ for (const task of tasks) {
42
+ try {
43
+ await task.uploadAsync({ config, context: taskCtx });
44
+ }
45
+ catch (error) {
46
+ errors.push(error);
47
+ }
48
+ }
49
+ unsubscribeTelemetry();
50
+ if (errors.length > 0) {
51
+ throw new errors_1.MetadataUploadError(errors, executionId);
52
+ }
53
+ }
54
+ exports.uploadMetadataAsync = uploadMetadataAsync;
@@ -0,0 +1 @@
1
+ export declare function unique<T = any>(items: T[]): T[];
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unique = void 0;
4
+ function unique(items) {
5
+ const set = new Set(items);
6
+ return [...set];
7
+ }
8
+ exports.unique = unique;
@@ -0,0 +1,4 @@
1
+ /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
+ import { ConnectModel } from '@expo/apple-utils';
3
+ /** Get the properties of a single App Store Connect entity */
4
+ export declare type AttributesOf<T extends ConnectModel> = T['attributes'];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Remove time precision from a date to avoid potential errors with the App Store.
3
+ *
4
+ * "status": "409",
5
+ * "code": "ENTITY_ERROR.ATTRIBUTE.INVALID",
6
+ * "title": "An attribute value is invalid.",
7
+ * "detail": "The attribute 'earliestReleaseDate' only allows hour precision",
8
+ * "source": {
9
+ * "pointer": "/data/attributes/earliestReleaseDate"
10
+ * }
11
+ */
12
+ export declare function removeDatePrecision(date: any): null | Date;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeDatePrecision = void 0;
4
+ /**
5
+ * Remove time precision from a date to avoid potential errors with the App Store.
6
+ *
7
+ * "status": "409",
8
+ * "code": "ENTITY_ERROR.ATTRIBUTE.INVALID",
9
+ * "title": "An attribute value is invalid.",
10
+ * "detail": "The attribute 'earliestReleaseDate' only allows hour precision",
11
+ * "source": {
12
+ * "pointer": "/data/attributes/earliestReleaseDate"
13
+ * }
14
+ */
15
+ function removeDatePrecision(date) {
16
+ if (date) {
17
+ try {
18
+ const result = new Date(date);
19
+ result.setMinutes(0);
20
+ result.setSeconds(0);
21
+ result.setMilliseconds(0);
22
+ if (!isNaN(result.getTime())) {
23
+ return result;
24
+ }
25
+ }
26
+ catch { }
27
+ }
28
+ return null;
29
+ }
30
+ exports.removeDatePrecision = removeDatePrecision;
@@ -0,0 +1,16 @@
1
+ import { Ora } from '../../ora';
2
+ declare type LogAsyncOptions = {
3
+ /** If the spinner representing the async action should be hidden, e.g. for JSON output */
4
+ hidden?: boolean;
5
+ /** The message to display when the action is pending */
6
+ pending: string;
7
+ /** The message to display when the action succeeded */
8
+ success: string;
9
+ /** The message to display when the action failed */
10
+ failure: string;
11
+ };
12
+ /**
13
+ * Log an asynchronous action using a spinner.
14
+ */
15
+ export declare function logAsync<T>(action: (spinner?: Ora) => Promise<T>, { hidden, ...message }: LogAsyncOptions): Promise<T>;
16
+ export {};
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logAsync = void 0;
4
+ const ora_1 = require("../../ora");
5
+ /**
6
+ * Log an asynchronous action using a spinner.
7
+ */
8
+ async function logAsync(action, { hidden, ...message }) {
9
+ if (hidden) {
10
+ return action();
11
+ }
12
+ const spinner = (0, ora_1.ora)(message.pending).start();
13
+ try {
14
+ const result = await action(spinner);
15
+ spinner.succeed(message.success);
16
+ return result;
17
+ }
18
+ catch (error) {
19
+ spinner.fail(message.failure);
20
+ throw error;
21
+ }
22
+ }
23
+ exports.logAsync = logAsync;
@@ -0,0 +1,8 @@
1
+ export declare function waitAsync(duration: number): Promise<void>;
2
+ declare type WithRetryOptions = {
3
+ tries?: number;
4
+ delay?: number;
5
+ onRetry?: (triesLeft: number) => void;
6
+ };
7
+ export declare function retryIfNullAsync<T>(method: () => Promise<T | null>, options?: WithRetryOptions): Promise<T | null>;
8
+ export {};
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.retryIfNullAsync = exports.waitAsync = void 0;
4
+ async function waitAsync(duration) {
5
+ return new Promise(resolve => setTimeout(resolve, duration));
6
+ }
7
+ exports.waitAsync = waitAsync;
8
+ async function retryIfNullAsync(method, options = {}) {
9
+ var _a;
10
+ let { tries = 5, delay = 1000 } = options;
11
+ while (tries > 0) {
12
+ const value = await method();
13
+ if (value !== null) {
14
+ return value;
15
+ }
16
+ tries--;
17
+ (_a = options.onRetry) === null || _a === void 0 ? void 0 : _a.call(options, tries);
18
+ await waitAsync(delay);
19
+ }
20
+ return null;
21
+ }
22
+ exports.retryIfNullAsync = retryIfNullAsync;
@@ -0,0 +1,20 @@
1
+ /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
+ import { App, Session } from '@expo/apple-utils';
3
+ import { MetadataEvent } from '../../analytics/events';
4
+ export declare type TelemetryContext = {
5
+ app: App;
6
+ auth: Partial<Session.AuthState>;
7
+ };
8
+ /**
9
+ * Subscribe the telemetry to the ongoing metadata requests and responses.
10
+ * When providing the app and auth info, we can scrub that data from the telemetry.
11
+ * Returns an execution ID to group all events of a single run together, and a unsubscribe function.
12
+ */
13
+ export declare function subscribeTelemetry(event: MetadataEvent, options: TelemetryContext): {
14
+ /** Unsubscribe the telemetry from all apple-utils events */
15
+ unsubscribeTelemetry: () => void;
16
+ /** The unique id added to all telemetry events from a single execution */
17
+ executionId: string;
18
+ };
19
+ /** Exposed for testing */
20
+ export declare function makeDataScrubber({ app, auth }: TelemetryContext): <T>(data: T) => string;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeDataScrubber = exports.subscribeTelemetry = void 0;
4
+ const apple_utils_1 = require("@expo/apple-utils");
5
+ const uuid_1 = require("uuid");
6
+ const events_1 = require("../../analytics/events");
7
+ /**
8
+ * Subscribe the telemetry to the ongoing metadata requests and responses.
9
+ * When providing the app and auth info, we can scrub that data from the telemetry.
10
+ * Returns an execution ID to group all events of a single run together, and a unsubscribe function.
11
+ */
12
+ function subscribeTelemetry(event, options) {
13
+ const executionId = (0, uuid_1.v4)();
14
+ const scrubber = makeDataScrubber(options);
15
+ const { interceptors } = (0, apple_utils_1.getRequestClient)();
16
+ const responseInterceptorId = interceptors.response.use(response => {
17
+ events_1.Analytics.logEvent(event, {
18
+ executionId,
19
+ type: 'response',
20
+ phase: 'resolved',
21
+ method: response.request.method.toUpperCase(),
22
+ url: scrubber(response.request.path),
23
+ status: String(response.status),
24
+ statusText: scrubber(response.statusText),
25
+ });
26
+ return response;
27
+ }, (error) => {
28
+ var _a, _b, _c;
29
+ events_1.Analytics.logEvent(event, {
30
+ executionId,
31
+ type: 'response',
32
+ phase: 'rejected',
33
+ method: error.request.method.toUpperCase(),
34
+ url: scrubber(error.config.url),
35
+ error: scrubber(error.message),
36
+ status: String((_a = error.response) === null || _a === void 0 ? void 0 : _a.status),
37
+ statusText: scrubber((_b = error.response) === null || _b === void 0 ? void 0 : _b.statusText),
38
+ input: scrubber(error.config.data),
39
+ output: scrubber((_c = error.response) === null || _c === void 0 ? void 0 : _c.data),
40
+ });
41
+ throw error;
42
+ });
43
+ function unsubscribeTelemetry() {
44
+ interceptors.response.eject(responseInterceptorId);
45
+ }
46
+ return { unsubscribeTelemetry, executionId };
47
+ }
48
+ exports.subscribeTelemetry = subscribeTelemetry;
49
+ /** Exposed for testing */
50
+ function makeDataScrubber({ app, auth }) {
51
+ var _a, _b;
52
+ const token = getAuthTokenString(auth);
53
+ const patterns = {
54
+ APPLE_APP_ID: new RegExp(app.id, 'gi'),
55
+ APPLE_USERNAME: auth.username ? new RegExp(auth.username, 'gi') : null,
56
+ APPLE_PASSWORD: auth.password ? new RegExp(auth.password, 'gi') : null,
57
+ APPLE_TOKEN: token ? new RegExp(token, 'gi') : null,
58
+ APPLE_TEAM_ID: ((_a = auth.context) === null || _a === void 0 ? void 0 : _a.teamId) ? new RegExp(auth.context.teamId, 'gi') : null,
59
+ APPLE_PROVIDER_ID: ((_b = auth.context) === null || _b === void 0 ? void 0 : _b.providerId)
60
+ ? new RegExp(String(auth.context.providerId), 'gi')
61
+ : null,
62
+ };
63
+ const iterator = Object.entries(patterns);
64
+ return function scrubber(data) {
65
+ if (!data) {
66
+ return String(data);
67
+ }
68
+ let value = typeof data === 'object' ? JSON.stringify(data) : String(data);
69
+ for (const [replacement, pattern] of iterator) {
70
+ if (pattern) {
71
+ value = value.replace(pattern, `{${replacement}}`);
72
+ }
73
+ }
74
+ return value;
75
+ };
76
+ }
77
+ exports.makeDataScrubber = makeDataScrubber;
78
+ function getAuthTokenString(auth) {
79
+ var _a;
80
+ if (!((_a = auth.context) === null || _a === void 0 ? void 0 : _a.token)) {
81
+ return null;
82
+ }
83
+ if (typeof auth.context.token === 'object') {
84
+ return auth.context.token.getToken();
85
+ }
86
+ return auth.context.token;
87
+ }
@@ -67,7 +67,7 @@ function printInstructionsForIosSubmission(submission) {
67
67
  '- It usually takes about 5-10 minutes depending on how busy Apple servers are.',
68
68
  // ascAppIdentifier should be always available for ios submissions but check it anyway
69
69
  ((_a = submission.iosConfig) === null || _a === void 0 ? void 0 : _a.ascAppIdentifier) &&
70
- `- When its done, you can see your build here: ${(0, log_1.link)(`https://appstoreconnect.apple.com/apps/${(_b = submission.iosConfig) === null || _b === void 0 ? void 0 : _b.ascAppIdentifier}/appstore/ios`)}`,
70
+ `- When it's done, you can see your build here: ${(0, log_1.link)(`https://appstoreconnect.apple.com/apps/${(_b = submission.iosConfig) === null || _b === void 0 ? void 0 : _b.ascAppIdentifier}/appstore/ios`)}`,
71
71
  ].join('\n');
72
72
  log_1.default.addNewLineIfNone();
73
73
  log_1.default.log(logMsg);
@@ -9,6 +9,7 @@ var SubmissionErrorCode;
9
9
  SubmissionErrorCode["ARCHIVE_DOWNLOAD_FORBIDDEN_ERROR"] = "SUBMISSION_SERVICE_COMMON_ARCHIVE_DOWNLOAD_FORBIDDEN_ERROR";
10
10
  SubmissionErrorCode["ARCHIVE_EXTRACT_NO_FILES_FOUND_ERROR"] = "SUBMISSION_SERVICE_COMMON_ARCHIVE_EXTRACT_NO_FILES_FOUND_ERROR";
11
11
  SubmissionErrorCode["ARCHIVE_EXTRACT_CORRUPT_ARCHIVE_ERROR"] = "SUBMISSION_SERVICE_COMMON_ARCHIVE_EXTRACT_CORRUPT_ARCHIVE_ERROR";
12
+ SubmissionErrorCode["UPLOAD_TAKING_TOO_LONG_ERROR"] = "SUBMISSION_SERVICE_COMMON_UPLOAD_TAKING_TOO_LONG_ERROR";
12
13
  SubmissionErrorCode["ANDROID_UNKNOWN_ERROR"] = "SUBMISSION_SERVICE_ANDROID_UNKNOWN_ERROR";
13
14
  SubmissionErrorCode["ANDROID_FIRST_UPLOAD_ERROR"] = "SUBMISSION_SERVICE_ANDROID_FIRST_UPLOAD_ERROR";
14
15
  SubmissionErrorCode["ANDROID_OLD_VERSION_CODE_ERROR"] = "SUBMISSION_SERVICE_ANDROID_OLD_VERSION_CODE_ERROR";
@@ -56,6 +57,7 @@ const SubmissionErrorMessages = {
56
57
  [SubmissionErrorCode.IOS_INVALID_PROVISIONING_PROFILE_SIGNATURE]: 'Invalid Provisioning Profile Signature (ITMS-90165)\n' +
57
58
  "Some of Apple's certificates have expired.\n" +
58
59
  'Please delete your Provisioning Profile from your account. Then rebuild the app interactively to generate a new one, and try submitting it to the App Store again.',
60
+ [SubmissionErrorCode.UPLOAD_TAKING_TOO_LONG_ERROR]: 'Submission has reached the timeout limit. Please try again.',
59
61
  };
60
62
  function printSubmissionError(error) {
61
63
  if (error.errorCode &&