eas-cli 0.54.1 → 0.55.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 (44) hide show
  1. package/README.md +44 -44
  2. package/build/build/android/build.js +2 -1
  3. package/build/build/build.d.ts +2 -2
  4. package/build/build/build.js +9 -3
  5. package/build/build/context.d.ts +2 -0
  6. package/build/build/createContext.d.ts +3 -1
  7. package/build/build/createContext.js +2 -1
  8. package/build/build/ios/build.js +2 -1
  9. package/build/build/runBuildAndSubmit.d.ts +2 -0
  10. package/build/build/runBuildAndSubmit.js +15 -2
  11. package/build/build/types.d.ts +4 -0
  12. package/build/build/types.js +6 -1
  13. package/build/commands/build/index.d.ts +2 -0
  14. package/build/commands/build/index.js +8 -1
  15. package/build/commands/update/index.d.ts +1 -0
  16. package/build/commands/update/index.js +12 -3
  17. package/build/env.d.ts +11 -0
  18. package/build/env.js +12 -0
  19. package/build/graphql/generated.d.ts +15 -0
  20. package/build/graphql/generated.js +9 -1
  21. package/build/graphql/mutations/BuildMutation.d.ts +3 -1
  22. package/build/graphql/mutations/BuildMutation.js +14 -2
  23. package/build/graphql/queries/WebhookQuery.d.ts +1 -1
  24. package/build/metadata/apple/config/reader.d.ts +2 -1
  25. package/build/metadata/apple/config/reader.js +66 -9
  26. package/build/metadata/apple/config/writer.d.ts +3 -2
  27. package/build/metadata/apple/config/writer.js +64 -12
  28. package/build/metadata/apple/data.d.ts +2 -1
  29. package/build/metadata/apple/tasks/app-review-detail.d.ts +14 -0
  30. package/build/metadata/apple/tasks/app-review-detail.js +49 -0
  31. package/build/metadata/apple/tasks/app-version.js +2 -2
  32. package/build/metadata/apple/tasks/index.js +2 -1
  33. package/build/metadata/apple/types.d.ts +9 -11
  34. package/build/metadata/errors.d.ts +5 -0
  35. package/build/metadata/errors.js +18 -9
  36. package/build/metadata/upload.js +13 -3
  37. package/build/project/android/applicationId.js +4 -0
  38. package/build/project/publish.js +7 -2
  39. package/build/project/workflow.js +13 -11
  40. package/build/uploads.d.ts +6 -0
  41. package/build/uploads.js +15 -3
  42. package/oclif.manifest.json +1 -1
  43. package/package.json +4 -4
  44. package/schema/metadata-0.json +396 -336
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
4
4
  const core_1 = require("@oclif/core");
5
5
  const path_1 = tslib_1.__importDefault(require("path"));
6
6
  const runBuildAndSubmit_1 = require("../../build/runBuildAndSubmit");
7
+ const types_1 = require("../../build/types");
7
8
  const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
8
9
  const log_1 = tslib_1.__importDefault(require("../../log"));
9
10
  const platform_1 = require("../../platform");
@@ -20,7 +21,7 @@ class Build extends EasCommand_1.default {
20
21
  await (0, runBuildAndSubmit_1.runBuildAndSubmitAsync)(projectDir, flags);
21
22
  }
22
23
  async sanitizeFlagsAsync(flags) {
23
- var _a;
24
+ var _a, _b;
24
25
  const nonInteractive = flags['non-interactive'];
25
26
  if (!flags.local && flags.output) {
26
27
  core_1.Errors.error('--output is allowed only for local builds', { exit: 1 });
@@ -73,6 +74,7 @@ class Build extends EasCommand_1.default {
73
74
  json: flags['json'],
74
75
  autoSubmit: flags['auto-submit'] || flags['auto-submit-with-profile'] !== undefined,
75
76
  submitProfile: (_a = flags['auto-submit-with-profile']) !== null && _a !== void 0 ? _a : profile,
77
+ userInputResourceClass: (_b = flags['resource-class']) !== null && _b !== void 0 ? _b : types_1.UserInputResourceClass.DEFAULT,
76
78
  };
77
79
  }
78
80
  }
@@ -129,4 +131,9 @@ Build.flags = {
129
131
  helpValue: 'PROFILE_NAME',
130
132
  exclusive: ['auto-submit'],
131
133
  }),
134
+ 'resource-class': core_1.Flags.enum({
135
+ options: Object.values(types_1.UserInputResourceClass),
136
+ hidden: true,
137
+ description: 'The instance type that will be used to run this build [experimental]',
138
+ }),
132
139
  };
@@ -30,3 +30,4 @@ export default class UpdatePublish extends EasCommand {
30
30
  runAsync(): Promise<void>;
31
31
  }
32
32
  export declare function getUpdatesToRepublishInteractiveAsync(projectId: string, branchName: string, platformFlag: string, pageSize: number, offset?: number, cumulativeUpdates?: Exclude<Exclude<ViewBranchUpdatesQuery['app'], null | undefined>['byId']['updateBranchByName'], null | undefined>['updates']): Promise<Exclude<Exclude<ViewBranchUpdatesQuery['app'], null | undefined>['byId']['updateBranchByName'], null | undefined>['updates']>;
33
+ export declare const truncatePublishUpdateMessage: (originalMessage: string) => string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUpdatesToRepublishInteractiveAsync = exports.ensureBranchExistsAsync = exports.defaultPublishPlatforms = void 0;
3
+ exports.truncatePublishUpdateMessage = exports.getUpdatesToRepublishInteractiveAsync = exports.ensureBranchExistsAsync = exports.defaultPublishPlatforms = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const config_plugins_1 = require("@expo/config-plugins");
6
6
  const eas_build_job_1 = require("@expo/eas-build-job");
@@ -278,6 +278,7 @@ class UpdatePublish extends EasCommand_1.default {
278
278
  throw e;
279
279
  }
280
280
  }
281
+ const truncatedMessage = (0, exports.truncatePublishUpdateMessage)(message);
281
282
  const runtimeToPlatformMapping = {};
282
283
  for (const runtime of new Set(Object.values(runtimeVersions))) {
283
284
  runtimeToPlatformMapping[runtime] = Object.entries(runtimeVersions)
@@ -302,7 +303,7 @@ class UpdatePublish extends EasCommand_1.default {
302
303
  branchId,
303
304
  updateInfoGroup: localUpdateInfoGroup,
304
305
  runtimeVersion: republish ? oldRuntimeVersion : runtime,
305
- message,
306
+ message: truncatedMessage,
306
307
  awaitingCodeSigningInfo: !!codeSigningInfo,
307
308
  };
308
309
  });
@@ -374,7 +375,7 @@ class UpdatePublish extends EasCommand_1.default {
374
375
  ? [{ label: 'Android update ID', value: newAndroidUpdate.id }]
375
376
  : []),
376
377
  ...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
377
- { label: 'Message', value: message },
378
+ { label: 'Message', value: truncatedMessage },
378
379
  { label: 'Website link', value: updateGroupLink },
379
380
  ]));
380
381
  log_1.default.addNewLineIfNone();
@@ -513,3 +514,11 @@ async function checkEASUpdateURLIsSetAsync(exp) {
513
514
  throw new Error(`The update URL is incorrectly configured for EAS Update. Please set updates.url to ${expectedURL} in your app.json.`);
514
515
  }
515
516
  }
517
+ const truncatePublishUpdateMessage = (originalMessage) => {
518
+ if (originalMessage.length > 1024) {
519
+ log_1.default.warn('Update message exceeds the allowed 1024 character limit. Truncating message...');
520
+ return originalMessage.substring(0, 1021) + '...';
521
+ }
522
+ return originalMessage;
523
+ };
524
+ exports.truncatePublishUpdateMessage = truncatePublishUpdateMessage;
package/build/env.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ declare const _default: {
2
+ /**
3
+ * Dangerous overrides, use only if you know what you are doing
4
+ */
5
+ /**
6
+ * Overrides applicationId from Android project, setting this option will also
7
+ * ignore failures when parsing build.gradle.
8
+ */
9
+ overrideAndroidApplicationId: string | undefined;
10
+ };
11
+ export default _default;
package/build/env.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = {
4
+ /**
5
+ * Dangerous overrides, use only if you know what you are doing
6
+ */
7
+ /**
8
+ * Overrides applicationId from Android project, setting this option will also
9
+ * ignore failures when parsing build.gradle.
10
+ */
11
+ overrideAndroidApplicationId: process.env.EAS_DANGEROUS_OVERRIDE_ANDROID_APPLICATION_ID,
12
+ };
@@ -1331,6 +1331,7 @@ export declare type Build = ActivityTimelineProjectActivity & BuildOrBuildJob &
1331
1331
  queuePosition?: Maybe<Scalars['Int']>;
1332
1332
  reactNativeVersion?: Maybe<Scalars['String']>;
1333
1333
  releaseChannel?: Maybe<Scalars['String']>;
1334
+ resourceClass?: Maybe<BuildResourceClass>;
1334
1335
  runtimeVersion?: Maybe<Scalars['String']>;
1335
1336
  sdkVersion?: Maybe<Scalars['String']>;
1336
1337
  status: BuildStatus;
@@ -1496,11 +1497,13 @@ export declare type BuildMutationCancelBuildArgs = {
1496
1497
  };
1497
1498
  export declare type BuildMutationCreateAndroidBuildArgs = {
1498
1499
  appId: Scalars['ID'];
1500
+ buildParams?: InputMaybe<BuildParamsInput>;
1499
1501
  job: AndroidJobInput;
1500
1502
  metadata?: InputMaybe<BuildMetadataInput>;
1501
1503
  };
1502
1504
  export declare type BuildMutationCreateIosBuildArgs = {
1503
1505
  appId: Scalars['ID'];
1506
+ buildParams?: InputMaybe<BuildParamsInput>;
1504
1507
  job: IosJobInput;
1505
1508
  metadata?: InputMaybe<BuildMetadataInput>;
1506
1509
  };
@@ -1513,6 +1516,9 @@ export declare type BuildMutationRetryBuildArgs = {
1513
1516
  export declare type BuildOrBuildJob = {
1514
1517
  id: Scalars['ID'];
1515
1518
  };
1519
+ export declare type BuildParamsInput = {
1520
+ resourceClass: BuildResourceClass;
1521
+ };
1516
1522
  export declare enum BuildPriority {
1517
1523
  High = "HIGH",
1518
1524
  Normal = "NORMAL"
@@ -1568,6 +1574,13 @@ export declare type BuildQueryAllForAppArgs = {
1568
1574
  export declare type BuildQueryByIdArgs = {
1569
1575
  buildId: Scalars['ID'];
1570
1576
  };
1577
+ export declare enum BuildResourceClass {
1578
+ AndroidDefault = "ANDROID_DEFAULT",
1579
+ AndroidLarge = "ANDROID_LARGE",
1580
+ IosDefault = "IOS_DEFAULT",
1581
+ IosLarge = "IOS_LARGE",
1582
+ Legacy = "LEGACY"
1583
+ }
1571
1584
  export declare enum BuildStatus {
1572
1585
  Canceled = "CANCELED",
1573
1586
  Errored = "ERRORED",
@@ -5750,6 +5763,7 @@ export declare type CreateAndroidBuildMutationVariables = Exact<{
5750
5763
  appId: Scalars['ID'];
5751
5764
  job: AndroidJobInput;
5752
5765
  metadata?: InputMaybe<BuildMetadataInput>;
5766
+ buildParams?: InputMaybe<BuildParamsInput>;
5753
5767
  }>;
5754
5768
  export declare type CreateAndroidBuildMutation = {
5755
5769
  __typename?: 'RootMutation';
@@ -5827,6 +5841,7 @@ export declare type CreateIosBuildMutationVariables = Exact<{
5827
5841
  appId: Scalars['ID'];
5828
5842
  job: IosJobInput;
5829
5843
  metadata?: InputMaybe<BuildMetadataInput>;
5844
+ buildParams?: InputMaybe<BuildParamsInput>;
5830
5845
  }>;
5831
5846
  export declare type CreateIosBuildMutation = {
5832
5847
  __typename?: 'RootMutation';
@@ -6,7 +6,7 @@
6
6
  * For more info and docs, visit https://graphql-code-generator.com/
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.WebhookType = exports.UsageMetricsGranularity = exports.UsageMetricType = exports.UploadSessionType = exports.SubmissionStatus = exports.SubmissionAndroidTrack = exports.SubmissionAndroidReleaseStatus = exports.SubmissionAndroidArchiveType = exports.StandardOffer = exports.SecondFactorMethod = exports.Role = exports.ProjectArchiveSourceType = exports.Permission = exports.Order = exports.OfferType = exports.MailchimpTag = exports.MailchimpAudience = exports.IosSchemeBuildConfiguration = exports.IosManagedBuildType = exports.IosDistributionType = exports.IosBuildType = exports.InvoiceDiscountType = exports.Feature = exports.EasServiceMetric = exports.EasBuildDeprecationInfoType = exports.DistributionType = exports.CacheControlScope = exports.BuildWorkflow = exports.BuildStatus = exports.BuildPriority = exports.BuildJobStatus = exports.BuildJobLogsFormat = exports.BuildIosEnterpriseProvisioning = exports.BuildCredentialsSource = exports.AssetMetadataStatus = exports.AppsFilter = exports.AppleDeviceClass = exports.AppStoreConnectUserRole = exports.AppSort = exports.AppPrivacy = exports.AppPlatform = exports.AndroidKeystoreType = exports.AndroidFcmVersion = exports.AndroidBuildType = exports.ActivityTimelineProjectActivityType = void 0;
9
+ exports.WebhookType = exports.UsageMetricsGranularity = exports.UsageMetricType = exports.UploadSessionType = exports.SubmissionStatus = exports.SubmissionAndroidTrack = exports.SubmissionAndroidReleaseStatus = exports.SubmissionAndroidArchiveType = exports.StandardOffer = exports.SecondFactorMethod = exports.Role = exports.ProjectArchiveSourceType = exports.Permission = exports.Order = exports.OfferType = exports.MailchimpTag = exports.MailchimpAudience = exports.IosSchemeBuildConfiguration = exports.IosManagedBuildType = exports.IosDistributionType = exports.IosBuildType = exports.InvoiceDiscountType = exports.Feature = exports.EasServiceMetric = exports.EasBuildDeprecationInfoType = exports.DistributionType = exports.CacheControlScope = exports.BuildWorkflow = exports.BuildStatus = exports.BuildResourceClass = exports.BuildPriority = exports.BuildJobStatus = exports.BuildJobLogsFormat = exports.BuildIosEnterpriseProvisioning = exports.BuildCredentialsSource = exports.AssetMetadataStatus = exports.AppsFilter = exports.AppleDeviceClass = exports.AppStoreConnectUserRole = exports.AppSort = exports.AppPrivacy = exports.AppPlatform = exports.AndroidKeystoreType = exports.AndroidFcmVersion = exports.AndroidBuildType = exports.ActivityTimelineProjectActivityType = void 0;
10
10
  var ActivityTimelineProjectActivityType;
11
11
  (function (ActivityTimelineProjectActivityType) {
12
12
  ActivityTimelineProjectActivityType["Build"] = "BUILD";
@@ -115,6 +115,14 @@ var BuildPriority;
115
115
  BuildPriority["High"] = "HIGH";
116
116
  BuildPriority["Normal"] = "NORMAL";
117
117
  })(BuildPriority = exports.BuildPriority || (exports.BuildPriority = {}));
118
+ var BuildResourceClass;
119
+ (function (BuildResourceClass) {
120
+ BuildResourceClass["AndroidDefault"] = "ANDROID_DEFAULT";
121
+ BuildResourceClass["AndroidLarge"] = "ANDROID_LARGE";
122
+ BuildResourceClass["IosDefault"] = "IOS_DEFAULT";
123
+ BuildResourceClass["IosLarge"] = "IOS_LARGE";
124
+ BuildResourceClass["Legacy"] = "LEGACY";
125
+ })(BuildResourceClass = exports.BuildResourceClass || (exports.BuildResourceClass = {}));
118
126
  var BuildStatus;
119
127
  (function (BuildStatus) {
120
128
  BuildStatus["Canceled"] = "CANCELED";
@@ -1,4 +1,4 @@
1
- import { AndroidJobInput, BuildFragment, BuildMetadataInput, EasBuildDeprecationInfo, IosJobInput } from '../generated';
1
+ import { AndroidJobInput, BuildFragment, BuildMetadataInput, BuildParamsInput, EasBuildDeprecationInfo, IosJobInput } from '../generated';
2
2
  export interface BuildResult {
3
3
  build: BuildFragment;
4
4
  deprecationInfo?: EasBuildDeprecationInfo | null;
@@ -8,10 +8,12 @@ export declare const BuildMutation: {
8
8
  appId: string;
9
9
  job: AndroidJobInput;
10
10
  metadata: BuildMetadataInput;
11
+ buildParams: BuildParamsInput;
11
12
  }): Promise<BuildResult>;
12
13
  createIosBuildAsync(input: {
13
14
  appId: string;
14
15
  job: IosJobInput;
15
16
  metadata: BuildMetadataInput;
17
+ buildParams: BuildParamsInput;
16
18
  }): Promise<BuildResult>;
17
19
  };
@@ -16,9 +16,15 @@ exports.BuildMutation = {
16
16
  $appId: ID!
17
17
  $job: AndroidJobInput!
18
18
  $metadata: BuildMetadataInput
19
+ $buildParams: BuildParamsInput
19
20
  ) {
20
21
  build {
21
- createAndroidBuild(appId: $appId, job: $job, metadata: $metadata) {
22
+ createAndroidBuild(
23
+ appId: $appId
24
+ job: $job
25
+ metadata: $metadata
26
+ buildParams: $buildParams
27
+ ) {
22
28
  build {
23
29
  id
24
30
  ...BuildFragment
@@ -43,9 +49,15 @@ exports.BuildMutation = {
43
49
  $appId: ID!
44
50
  $job: IosJobInput!
45
51
  $metadata: BuildMetadataInput
52
+ $buildParams: BuildParamsInput
46
53
  ) {
47
54
  build {
48
- createIosBuild(appId: $appId, job: $job, metadata: $metadata) {
55
+ createIosBuild(
56
+ appId: $appId
57
+ job: $job
58
+ metadata: $metadata
59
+ buildParams: $buildParams
60
+ ) {
49
61
  build {
50
62
  id
51
63
  ...BuildFragment
@@ -1,5 +1,5 @@
1
1
  import { WebhookFilter, WebhookFragment } from '../generated';
2
2
  export declare const WebhookQuery: {
3
- byAppIdAsync(appId: string, webhookFilter?: WebhookFilter | undefined): Promise<WebhookFragment[]>;
3
+ byAppIdAsync(appId: string, webhookFilter?: WebhookFilter): Promise<WebhookFragment[]>;
4
4
  byIdAsync(webhookId: string): Promise<WebhookFragment>;
5
5
  };
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
- import { AgeRatingDeclaration, AppInfoLocalization, AppStoreVersion, AppStoreVersionLocalization, CategoryIds } from '@expo/apple-utils';
2
+ import { AgeRatingDeclaration, AppInfoLocalization, AppStoreReviewDetail, AppStoreVersion, AppStoreVersionLocalization, CategoryIds } from '@expo/apple-utils';
3
3
  import { AttributesOf } from '../../utils/asc';
4
4
  import { AppleMetadata } from '../types';
5
5
  declare type PartialExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>;
@@ -21,5 +21,6 @@ export declare class AppleConfigReader {
21
21
  getVersionLocale(locale: string, context: {
22
22
  versionIsFirst: boolean;
23
23
  }): Partial<AttributesOf<AppStoreVersionLocalization>> | null;
24
+ getReviewDetails(): Partial<AttributesOf<AppStoreReviewDetail>> | null;
24
25
  }
25
26
  export {};
@@ -16,21 +16,43 @@ class AppleConfigReader {
16
16
  this.schema = schema;
17
17
  }
18
18
  getAgeRating() {
19
- return this.schema.advisory || null;
19
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
20
+ const attributes = this.schema.advisory;
21
+ if (!attributes) {
22
+ return null;
23
+ }
24
+ return {
25
+ alcoholTobaccoOrDrugUseOrReferences: (_a = attributes.alcoholTobaccoOrDrugUseOrReferences) !== null && _a !== void 0 ? _a : apple_utils_1.Rating.NONE,
26
+ contests: (_b = attributes.contests) !== null && _b !== void 0 ? _b : apple_utils_1.Rating.NONE,
27
+ gamblingSimulated: (_c = attributes.gamblingSimulated) !== null && _c !== void 0 ? _c : apple_utils_1.Rating.NONE,
28
+ horrorOrFearThemes: (_d = attributes.horrorOrFearThemes) !== null && _d !== void 0 ? _d : apple_utils_1.Rating.NONE,
29
+ matureOrSuggestiveThemes: (_e = attributes.matureOrSuggestiveThemes) !== null && _e !== void 0 ? _e : apple_utils_1.Rating.NONE,
30
+ medicalOrTreatmentInformation: (_f = attributes.medicalOrTreatmentInformation) !== null && _f !== void 0 ? _f : apple_utils_1.Rating.NONE,
31
+ profanityOrCrudeHumor: (_g = attributes.profanityOrCrudeHumor) !== null && _g !== void 0 ? _g : apple_utils_1.Rating.NONE,
32
+ sexualContentGraphicAndNudity: (_h = attributes.sexualContentGraphicAndNudity) !== null && _h !== void 0 ? _h : apple_utils_1.Rating.NONE,
33
+ sexualContentOrNudity: (_j = attributes.sexualContentOrNudity) !== null && _j !== void 0 ? _j : apple_utils_1.Rating.NONE,
34
+ violenceCartoonOrFantasy: (_k = attributes.violenceCartoonOrFantasy) !== null && _k !== void 0 ? _k : apple_utils_1.Rating.NONE,
35
+ violenceRealistic: (_l = attributes.violenceRealistic) !== null && _l !== void 0 ? _l : apple_utils_1.Rating.NONE,
36
+ violenceRealisticProlongedGraphicOrSadistic: (_m = attributes.violenceRealisticProlongedGraphicOrSadistic) !== null && _m !== void 0 ? _m : apple_utils_1.Rating.NONE,
37
+ gambling: (_o = attributes.gambling) !== null && _o !== void 0 ? _o : false,
38
+ unrestrictedWebAccess: (_p = attributes.unrestrictedWebAccess) !== null && _p !== void 0 ? _p : false,
39
+ kidsAgeBand: (_q = attributes.kidsAgeBand) !== null && _q !== void 0 ? _q : null,
40
+ seventeenPlus: (_r = attributes.seventeenPlus) !== null && _r !== void 0 ? _r : false,
41
+ };
20
42
  }
21
43
  getLocales() {
22
44
  // TODO: filter "default" locales, add option to add non-localized info to the config
23
45
  return (0, uniq_1.default)(Object.keys(this.schema.info || {}));
24
46
  }
25
47
  getInfoLocale(locale) {
26
- var _a, _b;
48
+ var _a;
27
49
  const info = (_a = this.schema.info) === null || _a === void 0 ? void 0 : _a[locale];
28
50
  if (!info) {
29
51
  return null;
30
52
  }
31
53
  return {
32
54
  locale,
33
- name: (_b = info.title) !== null && _b !== void 0 ? _b : 'no name provided',
55
+ name: info.title,
34
56
  subtitle: info.subtitle,
35
57
  privacyChoicesUrl: info.privacyChoicesUrl,
36
58
  privacyPolicyText: info.privacyPolicyText,
@@ -38,13 +60,31 @@ class AppleConfigReader {
38
60
  };
39
61
  }
40
62
  getCategories() {
41
- if (Array.isArray(this.schema.categories) && this.schema.categories.length > 0) {
42
- return {
43
- primaryCategory: this.schema.categories[0],
44
- secondaryCategory: this.schema.categories[1],
45
- };
63
+ const { categories } = this.schema;
64
+ if (!categories || categories.length <= 0) {
65
+ return null;
46
66
  }
47
- return null;
67
+ // We validate the categories based on enums, but they will still be strings here.
68
+ const categoryIds = {};
69
+ if (Array.isArray(categories[0])) {
70
+ categoryIds.primaryCategory = categories[0][0];
71
+ categoryIds.primarySubcategoryOne = categories[0][1];
72
+ categoryIds.primarySubcategoryTwo = categories[0][2];
73
+ }
74
+ else {
75
+ categoryIds.primaryCategory = categories[0];
76
+ }
77
+ if (Array.isArray(categories[1])) {
78
+ categoryIds.secondaryCategory = categories[1][0];
79
+ categoryIds.secondarySubcategoryOne = categories[1][1];
80
+ categoryIds.secondarySubcategoryTwo = categories[1][2];
81
+ }
82
+ else {
83
+ categoryIds.secondaryCategory = categories[1];
84
+ }
85
+ // Because we handle categories as normal strings,
86
+ // the type doesn't match with the actual CategoryIds types.
87
+ return categoryIds;
48
88
  }
49
89
  /** Get the `AppStoreVersion` object. */
50
90
  getVersion() {
@@ -91,5 +131,22 @@ class AppleConfigReader {
91
131
  supportUrl: info.supportUrl,
92
132
  };
93
133
  }
134
+ getReviewDetails() {
135
+ const review = this.schema.review;
136
+ if (!review) {
137
+ return null;
138
+ }
139
+ return {
140
+ contactFirstName: review.firstName,
141
+ contactLastName: review.lastName,
142
+ contactEmail: review.email,
143
+ contactPhone: review.phone,
144
+ demoAccountName: review.demoUsername,
145
+ demoAccountPassword: review.demoPassword,
146
+ demoAccountRequired: review.demoRequired,
147
+ notes: review.notes,
148
+ // TODO: add attachment
149
+ };
150
+ }
94
151
  }
95
152
  exports.AppleConfigReader = AppleConfigReader;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
- import { AgeRatingDeclaration, AppInfo, AppInfoLocalization, AppStoreVersion, AppStoreVersionLocalization } from '@expo/apple-utils';
2
+ import { AgeRatingDeclaration, AppInfo, AppInfoLocalization, AppStoreReviewDetail, AppStoreVersion, AppStoreVersionLocalization } from '@expo/apple-utils';
3
3
  import { AttributesOf } from '../../utils/asc';
4
4
  import { AppleMetadata } from '../types';
5
5
  /**
@@ -16,8 +16,9 @@ export declare class AppleConfigWriter {
16
16
  };
17
17
  setAgeRating(attributes: AttributesOf<AgeRatingDeclaration>): void;
18
18
  setInfoLocale(attributes: AttributesOf<AppInfoLocalization>): void;
19
- setCategories({ primaryCategory, secondaryCategory }: AttributesOf<AppInfo>): void;
19
+ setCategories(attributes: Pick<AttributesOf<AppInfo>, 'primaryCategory' | 'primarySubcategoryOne' | 'primarySubcategoryTwo' | 'secondaryCategory' | 'secondarySubcategoryOne' | 'secondarySubcategoryTwo'>): void;
20
20
  setVersion(attributes: Omit<AttributesOf<AppStoreVersion>, 'releaseType' | 'earliestReleaseDate'>): void;
21
21
  setVersionRelease(attributes: Pick<AttributesOf<AppStoreVersion>, 'releaseType' | 'earliestReleaseDate'>): void;
22
22
  setVersionLocale(attributes: AttributesOf<AppStoreVersionLocalization>): void;
23
+ setReviewDetails(attributes: AttributesOf<AppStoreReviewDetail>): void;
23
24
  }
@@ -18,7 +18,25 @@ class AppleConfigWriter {
18
18
  };
19
19
  }
20
20
  setAgeRating(attributes) {
21
- this.schema.advisory = attributes;
21
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
22
+ this.schema.advisory = {
23
+ alcoholTobaccoOrDrugUseOrReferences: (_a = attributes.alcoholTobaccoOrDrugUseOrReferences) !== null && _a !== void 0 ? _a : apple_utils_1.Rating.NONE,
24
+ contests: (_b = attributes.contests) !== null && _b !== void 0 ? _b : apple_utils_1.Rating.NONE,
25
+ gamblingSimulated: (_c = attributes.gamblingSimulated) !== null && _c !== void 0 ? _c : apple_utils_1.Rating.NONE,
26
+ horrorOrFearThemes: (_d = attributes.horrorOrFearThemes) !== null && _d !== void 0 ? _d : apple_utils_1.Rating.NONE,
27
+ matureOrSuggestiveThemes: (_e = attributes.matureOrSuggestiveThemes) !== null && _e !== void 0 ? _e : apple_utils_1.Rating.NONE,
28
+ medicalOrTreatmentInformation: (_f = attributes.medicalOrTreatmentInformation) !== null && _f !== void 0 ? _f : apple_utils_1.Rating.NONE,
29
+ profanityOrCrudeHumor: (_g = attributes.profanityOrCrudeHumor) !== null && _g !== void 0 ? _g : apple_utils_1.Rating.NONE,
30
+ sexualContentGraphicAndNudity: (_h = attributes.sexualContentGraphicAndNudity) !== null && _h !== void 0 ? _h : apple_utils_1.Rating.NONE,
31
+ sexualContentOrNudity: (_j = attributes.sexualContentOrNudity) !== null && _j !== void 0 ? _j : apple_utils_1.Rating.NONE,
32
+ violenceCartoonOrFantasy: (_k = attributes.violenceCartoonOrFantasy) !== null && _k !== void 0 ? _k : apple_utils_1.Rating.NONE,
33
+ violenceRealistic: (_l = attributes.violenceRealistic) !== null && _l !== void 0 ? _l : apple_utils_1.Rating.NONE,
34
+ violenceRealisticProlongedGraphicOrSadistic: (_m = attributes.violenceRealisticProlongedGraphicOrSadistic) !== null && _m !== void 0 ? _m : apple_utils_1.Rating.NONE,
35
+ gambling: (_o = attributes.gambling) !== null && _o !== void 0 ? _o : false,
36
+ unrestrictedWebAccess: (_p = attributes.unrestrictedWebAccess) !== null && _p !== void 0 ? _p : false,
37
+ kidsAgeBand: (_q = attributes.kidsAgeBand) !== null && _q !== void 0 ? _q : null,
38
+ seventeenPlus: (_r = attributes.seventeenPlus) !== null && _r !== void 0 ? _r : false,
39
+ };
22
40
  }
23
41
  setInfoLocale(attributes) {
24
42
  var _a, _b, _c;
@@ -26,21 +44,41 @@ class AppleConfigWriter {
26
44
  const existing = (_b = this.schema.info[attributes.locale]) !== null && _b !== void 0 ? _b : {};
27
45
  this.schema.info[attributes.locale] = {
28
46
  ...existing,
29
- title: (_c = attributes.name) !== null && _c !== void 0 ? _c : 'no name provided',
47
+ title: (_c = attributes.name) !== null && _c !== void 0 ? _c : '',
30
48
  subtitle: optional(attributes.subtitle),
31
49
  privacyPolicyUrl: optional(attributes.privacyPolicyUrl),
32
50
  privacyPolicyText: optional(attributes.privacyPolicyText),
33
51
  privacyChoicesUrl: optional(attributes.privacyChoicesUrl),
34
52
  };
35
53
  }
36
- setCategories({ primaryCategory, secondaryCategory }) {
54
+ setCategories(attributes) {
55
+ var _a, _b, _c, _d, _e, _f;
56
+ this.schema.categories = undefined;
57
+ if (!attributes.primaryCategory && !attributes.secondaryCategory) {
58
+ return;
59
+ }
37
60
  this.schema.categories = [];
38
- // TODO: see why these types are conflicting
39
- if (primaryCategory) {
40
- this.schema.categories.push(primaryCategory.id);
41
- if (secondaryCategory) {
42
- this.schema.categories.push(secondaryCategory.id);
43
- }
61
+ if (attributes.primaryCategory && attributes.primarySubcategoryOne) {
62
+ this.schema.categories[0] = [
63
+ attributes.primaryCategory.id,
64
+ (_a = attributes.primarySubcategoryOne) === null || _a === void 0 ? void 0 : _a.id,
65
+ (_b = attributes.primarySubcategoryTwo) === null || _b === void 0 ? void 0 : _b.id,
66
+ ].filter(Boolean);
67
+ }
68
+ else {
69
+ // If only the secondaryCategory was provided,
70
+ // autofill with an empty string and cause a store config error.
71
+ this.schema.categories[0] = (_d = (_c = attributes.primaryCategory) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : '';
72
+ }
73
+ if (attributes.secondaryCategory && attributes.secondarySubcategoryOne) {
74
+ this.schema.categories[1] = [
75
+ attributes.secondaryCategory.id,
76
+ (_e = attributes.secondarySubcategoryOne) === null || _e === void 0 ? void 0 : _e.id,
77
+ (_f = attributes.secondarySubcategoryTwo) === null || _f === void 0 ? void 0 : _f.id,
78
+ ].filter(Boolean);
79
+ }
80
+ else if (attributes.secondaryCategory) {
81
+ this.schema.categories[1] = attributes.secondaryCategory.id;
44
82
  }
45
83
  }
46
84
  setVersion(attributes) {
@@ -58,9 +96,9 @@ class AppleConfigWriter {
58
96
  };
59
97
  }
60
98
  if (attributes.releaseType === apple_utils_1.ReleaseType.MANUAL) {
61
- this.schema.release = {
62
- automaticRelease: false,
63
- };
99
+ // ReleaseType.MANUAL is the default behavior, so we don't need to configure it.
100
+ // Setting `"automaticRelease": false` is a bit confusing for people who don't know what automaticRelease does.
101
+ this.schema.release = undefined;
64
102
  }
65
103
  }
66
104
  setVersionLocale(attributes) {
@@ -77,6 +115,20 @@ class AppleConfigWriter {
77
115
  supportUrl: optional(attributes.supportUrl),
78
116
  };
79
117
  }
118
+ setReviewDetails(attributes) {
119
+ var _a, _b, _c, _d;
120
+ this.schema.review = {
121
+ firstName: (_a = attributes.contactFirstName) !== null && _a !== void 0 ? _a : '',
122
+ lastName: (_b = attributes.contactLastName) !== null && _b !== void 0 ? _b : '',
123
+ email: (_c = attributes.contactEmail) !== null && _c !== void 0 ? _c : '',
124
+ phone: (_d = attributes.contactPhone) !== null && _d !== void 0 ? _d : '',
125
+ demoUsername: optional(attributes.demoAccountName),
126
+ demoPassword: optional(attributes.demoAccountPassword),
127
+ demoRequired: optional(attributes.demoAccountRequired),
128
+ notes: optional(attributes.notes),
129
+ // TODO: add attachment
130
+ };
131
+ }
80
132
  }
81
133
  exports.AppleConfigWriter = AppleConfigWriter;
82
134
  /** Helper function to convert `T | null` to `T | undefined`, required for the entity properties */
@@ -2,6 +2,7 @@
2
2
  import type { App } from '@expo/apple-utils';
3
3
  import type { AgeRatingData } from './tasks/age-rating';
4
4
  import type { AppInfoData } from './tasks/app-info';
5
+ import type { AppReviewData } from './tasks/app-review-detail';
5
6
  import type { AppVersionData } from './tasks/app-version';
6
7
  /**
7
8
  * The fully prepared apple data, used within the `downloadAsync` or `uploadAsync` tasks.
@@ -9,7 +10,7 @@ import type { AppVersionData } from './tasks/app-version';
9
10
  */
10
11
  export declare type AppleData = {
11
12
  app: App;
12
- } & AppInfoData & AppVersionData & AgeRatingData;
13
+ } & AppInfoData & AppVersionData & AgeRatingData & AppReviewData;
13
14
  /**
14
15
  * The unprepared partial apple data, used within the `prepareAsync` tasks.
15
16
  * It contains a reference to the app, each task should populate the necessary data.
@@ -0,0 +1,14 @@
1
+ /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
+ import { AppStoreReviewDetail } from '@expo/apple-utils';
3
+ import { AppleTask, TaskDownloadOptions, TaskPrepareOptions, TaskUploadOptions } from '../task';
4
+ export declare type AppReviewData = {
5
+ /** The current app info that should be edited */
6
+ reviewDetail: AppStoreReviewDetail;
7
+ };
8
+ /** Handle all contact, demo account, or instruction info that are required for the App Store review team. */
9
+ export declare class AppReviewDetailTask extends AppleTask {
10
+ name: () => string;
11
+ prepareAsync({ context }: TaskPrepareOptions): Promise<void>;
12
+ downloadAsync({ config, context }: TaskDownloadOptions): Promise<void>;
13
+ uploadAsync({ config, context }: TaskUploadOptions): Promise<void>;
14
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppReviewDetailTask = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const log_1 = tslib_1.__importDefault(require("../../../log"));
8
+ const log_2 = require("../../utils/log");
9
+ const task_1 = require("../task");
10
+ /** Handle all contact, demo account, or instruction info that are required for the App Store review team. */
11
+ class AppReviewDetailTask extends task_1.AppleTask {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.name = () => 'app review detail';
15
+ }
16
+ async prepareAsync({ context }) {
17
+ var _a;
18
+ (0, assert_1.default)(context.version, `App version not initialized, can't download store review details`);
19
+ context.reviewDetail = (_a = (await context.version.getAppStoreReviewDetailAsync())) !== null && _a !== void 0 ? _a : undefined;
20
+ }
21
+ async downloadAsync({ config, context }) {
22
+ if (context.reviewDetail) {
23
+ config.setReviewDetails(context.reviewDetail.attributes);
24
+ }
25
+ }
26
+ async uploadAsync({ config, context }) {
27
+ const reviewDetail = config.getReviewDetails();
28
+ if (!reviewDetail) {
29
+ return log_1.default.log((0, chalk_1.default) `{dim - Skipped store review details, not configured}`);
30
+ }
31
+ (0, assert_1.default)(context.version, `App version not initialized, can't upload store review details`);
32
+ const { versionString } = context.version.attributes;
33
+ if (!context.reviewDetail) {
34
+ // We can't set the demo required property when creating, omit it from the request
35
+ const { demoAccountRequired, ...reviewDetailsToCreate } = reviewDetail;
36
+ context.reviewDetail = await (0, log_2.logAsync)(() => context.version.createReviewDetailAsync(reviewDetailsToCreate), {
37
+ pending: `Creating store review details for ${chalk_1.default.bold(versionString)}...`,
38
+ success: `Created store review details for ${chalk_1.default.bold(versionString)}`,
39
+ failure: `Failed creating store review details for ${chalk_1.default.bold(versionString)}`,
40
+ });
41
+ }
42
+ context.reviewDetail = await (0, log_2.logAsync)(() => context.reviewDetail.updateAsync(reviewDetail), {
43
+ pending: `Updating store review details for ${chalk_1.default.bold(versionString)}...`,
44
+ success: `Updated store review details for ${chalk_1.default.bold(versionString)}`,
45
+ failure: `Failed updating store review details for ${chalk_1.default.bold(versionString)}`,
46
+ });
47
+ }
48
+ }
49
+ exports.AppReviewDetailTask = AppReviewDetailTask;
@@ -49,8 +49,8 @@ class AppVersionTask extends task_1.AppleTask {
49
49
  .join(' and ');
50
50
  context.version = await (0, log_2.logAsync)(() => context.version.updateAsync({ ...version, ...release }), {
51
51
  pending: `Updating ${description} info for ${chalk_1.default.bold(versionString)}...`,
52
- success: `Updated ${description} info for ${chalk_1.default.bold(versionString)}...`,
53
- failure: `Failed updating ${description} info for ${chalk_1.default.bold(versionString)}...`,
52
+ success: `Updated ${description} info for ${chalk_1.default.bold(versionString)}`,
53
+ failure: `Failed updating ${description} info for ${chalk_1.default.bold(versionString)}`,
54
54
  });
55
55
  }
56
56
  const locales = config.getLocales();
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAppleTasks = void 0;
4
4
  const age_rating_1 = require("./age-rating");
5
5
  const app_info_1 = require("./app-info");
6
+ const app_review_detail_1 = require("./app-review-detail");
6
7
  const app_version_1 = require("./app-version");
7
8
  /**
8
9
  * List of all eligible tasks to sync local store configuration to the App store.
9
10
  */
10
11
  function createAppleTasks(_ctx) {
11
- return [new app_version_1.AppVersionTask(), new app_info_1.AppInfoTask(), new age_rating_1.AgeRatingTask()];
12
+ return [new app_version_1.AppVersionTask(), new app_info_1.AppInfoTask(), new age_rating_1.AgeRatingTask(), new app_review_detail_1.AppReviewDetailTask()];
12
13
  }
13
14
  exports.createAppleTasks = createAppleTasks;