eas-cli 16.14.0 → 16.15.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.
@@ -14,11 +14,11 @@ const log_1 = tslib_1.__importStar(require("../../log"));
14
14
  const ora_1 = require("../../ora");
15
15
  const projectUtils_1 = require("../../project/projectUtils");
16
16
  const json_1 = require("../../utils/json");
17
- const progress_1 = require("../../utils/progress");
18
17
  const WorkerAssets = tslib_1.__importStar(require("../../worker/assets"));
19
18
  const deployment_1 = require("../../worker/deployment");
20
19
  const upload_1 = require("../../worker/upload");
21
20
  const logs_1 = require("../../worker/utils/logs");
21
+ const MAX_UPLOAD_SIZE = 5e8; // 500MB
22
22
  const isDirectory = (directoryPath) => node_fs_1.default.promises
23
23
  .stat(directoryPath)
24
24
  .then(stat => stat.isDirectory())
@@ -96,14 +96,11 @@ class WorkerDeploy extends EasCommand_1.default {
96
96
  }
97
97
  }
98
98
  async function uploadTarballAsync(tarPath, uploadUrl) {
99
+ const payload = { filePath: tarPath };
99
100
  const { response } = await (0, upload_1.uploadAsync)({
100
- url: uploadUrl,
101
- filePath: tarPath,
102
- compress: false,
103
- headers: {
104
- accept: 'application/json',
105
- },
106
- });
101
+ baseURL: uploadUrl,
102
+ method: 'POST',
103
+ }, payload);
107
104
  if (response.status === 413) {
108
105
  throw new Error('Upload failed! (Payload too large)\n' +
109
106
  `The files in "${path.relative(projectDir, projectDist.path)}" (at: ${projectDir}) exceed the maximum file size (10MB gzip).`);
@@ -116,7 +113,7 @@ class WorkerDeploy extends EasCommand_1.default {
116
113
  if (!json.success || !json.result || typeof json.result !== 'object') {
117
114
  throw new Error(json.message ? `Upload failed: ${json.message}` : 'Upload failed!');
118
115
  }
119
- const { id, fullName, token } = json.result;
116
+ const { id, fullName, token, upload } = json.result;
120
117
  if (typeof token !== 'string') {
121
118
  throw new Error('Upload failed: API failed to return a deployment token');
122
119
  }
@@ -126,56 +123,57 @@ class WorkerDeploy extends EasCommand_1.default {
126
123
  else if (typeof fullName !== 'string') {
127
124
  throw new Error('Upload failed: API failed to return a script name');
128
125
  }
126
+ else if (!Array.isArray(upload) && upload !== undefined) {
127
+ throw new Error('Upload failed: API returned invalid asset upload instructions');
128
+ }
129
129
  const baseURL = new URL('/', uploadUrl).toString();
130
- return { id, fullName, baseURL, token };
130
+ return { id, fullName, baseURL, token, upload };
131
131
  }
132
132
  }
133
- async function uploadAssetsAsync(assetMap, deployParams) {
134
- const uploadParams = [];
135
- const assetPath = projectDist.type === 'server' ? projectDist.clientPath : projectDist.path;
136
- if (!assetPath) {
137
- return;
133
+ async function uploadAssetsAsync(assetFiles, deployParams) {
134
+ const baseURL = new URL('/asset/', deployParams.baseURL);
135
+ const uploadInit = { baseURL, method: 'POST' };
136
+ uploadInit.baseURL.searchParams.set('token', deployParams.token);
137
+ const uploadPayloads = [];
138
+ if (deployParams.upload) {
139
+ const assetsBySHA512 = assetFiles.reduce((map, asset) => {
140
+ map.set(asset.sha512, asset);
141
+ return map;
142
+ }, new Map());
143
+ const payloads = deployParams.upload
144
+ .map(instruction => instruction.sha512.map(sha512 => {
145
+ const asset = assetsBySHA512.get(sha512);
146
+ if (!asset) {
147
+ // NOTE(@kitten): This should never happen
148
+ throw new Error(`Uploading assets failed: API instructed us to upload an asset that does not exist`);
149
+ }
150
+ return asset;
151
+ }))
152
+ .filter(assets => assets && assets.length > 0)
153
+ .map(assets => (assets.length > 1 ? { multipart: assets } : { asset: assets[0] }));
154
+ uploadPayloads.push(...payloads);
138
155
  }
139
- for await (const asset of WorkerAssets.listAssetMapFilesAsync(assetPath, assetMap)) {
140
- const uploadURL = new URL(`/asset/${asset.sha512}`, deployParams.baseURL);
141
- uploadURL.searchParams.set('token', deployParams.token);
142
- uploadParams.push({ url: uploadURL.toString(), filePath: asset.path });
156
+ else {
157
+ // NOTE(@kitten): Legacy format which uploads assets one-by-one
158
+ uploadPayloads.push(...assetFiles.map(asset => ({ asset })));
143
159
  }
144
- const progress = {
145
- total: uploadParams.length,
146
- pending: 0,
147
- percent: 0,
148
- transferred: 0,
149
- };
150
- const updateProgress = (0, progress_1.createProgressTracker)({
151
- total: progress.total,
152
- message(ratio) {
153
- const percent = `${Math.floor(ratio * 100)}`;
154
- const details = chalk_1.default.dim(`(${progress.pending} Pending, ${progress.transferred} Completed, ${progress.total} Total)`);
155
- return `Uploading assets: ${percent.padStart(3)}% ${details}`;
156
- },
157
- completedMessage: 'Uploaded assets',
158
- });
160
+ const progressTotal = uploadPayloads.reduce((acc, payload) => acc + ('multipart' in payload ? payload.multipart.length : 1), 0);
161
+ const progressTracker = (0, upload_1.createProgressBar)(`Uploading ${progressTotal} assets`);
159
162
  try {
160
- for await (const signal of (0, upload_1.batchUploadAsync)(uploadParams)) {
161
- if ('response' in signal) {
162
- progress.pending--;
163
- progress.percent = ++progress.transferred / progress.total;
164
- }
165
- else {
166
- progress.pending++;
167
- }
168
- updateProgress({ progress });
163
+ for await (const signal of (0, upload_1.batchUploadAsync)(uploadInit, uploadPayloads, progressTracker.update)) {
164
+ progressTracker.update(signal.progress);
169
165
  }
170
166
  }
171
167
  catch (error) {
172
- updateProgress({ isComplete: true, error });
168
+ progressTracker.stop();
173
169
  throw error;
174
170
  }
175
- updateProgress({ isComplete: true });
171
+ finally {
172
+ progressTracker.stop();
173
+ }
176
174
  }
177
- let assetMap;
178
175
  let tarPath;
176
+ let assetFiles;
179
177
  let deployResult;
180
178
  let progress = (0, ora_1.ora)('Preparing project').start();
181
179
  try {
@@ -189,9 +187,9 @@ class WorkerDeploy extends EasCommand_1.default {
189
187
  'In case of conflict, the EAS environment variable values will be used: ' +
190
188
  manifestResult.conflictingVariableNames.join(' '));
191
189
  }
192
- assetMap = await WorkerAssets.createAssetMapAsync(projectDist.type === 'server' ? projectDist.clientPath : projectDist.path);
190
+ assetFiles = await WorkerAssets.collectAssetsAsync(projectDist.type === 'server' ? projectDist.clientPath : projectDist.path, { maxFileSize: MAX_UPLOAD_SIZE });
193
191
  tarPath = await WorkerAssets.packFilesIterableAsync(emitWorkerTarballAsync({
194
- assetMap,
192
+ assetMap: WorkerAssets.assetsToAssetsMap(assetFiles),
195
193
  manifest: manifestResult.manifest,
196
194
  }));
197
195
  if (flags.dryRun) {
@@ -232,7 +230,7 @@ class WorkerDeploy extends EasCommand_1.default {
232
230
  }
233
231
  throw error;
234
232
  }
235
- await uploadAssetsAsync(assetMap, deployResult);
233
+ await uploadAssetsAsync(assetFiles, deployResult);
236
234
  await finalizeDeployAsync(deployResult);
237
235
  let deploymentAlias = null;
238
236
  if (flags.aliasName) {
@@ -5,7 +5,7 @@ async function resolveAppleTeamIfAuthenticatedAsync(ctx, app) {
5
5
  if (!ctx.appStore.authCtx) {
6
6
  return null;
7
7
  }
8
- return await ctx.ios.createOrGetExistingAppleTeamAsync(ctx.graphqlClient, app.account, {
8
+ return await ctx.ios.createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(ctx.graphqlClient, app.account.id, {
9
9
  appleTeamIdentifier: ctx.appStore.authCtx.team.id,
10
10
  appleTeamName: ctx.appStore.authCtx.team.name,
11
11
  });
@@ -26,7 +26,7 @@ class SetUpTargetBuildCredentialsFromCredentialsJson {
26
26
  const appInfo = `@${this.app.account.name}/${this.app.projectName} (${this.app.bundleIdentifier})`;
27
27
  // new credentials from local json
28
28
  const appleTeamFromProvisioningProfile = (0, provisioningProfile_1.readAppleTeam)(this.targetCredentials.provisioningProfile);
29
- const appleTeam = await ctx.ios.createOrGetExistingAppleTeamAsync(ctx.graphqlClient, this.app.account, {
29
+ const appleTeam = await ctx.ios.createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(ctx.graphqlClient, this.app.account.id, {
30
30
  appleTeamIdentifier: appleTeamFromProvisioningProfile.teamId,
31
31
  appleTeamName: appleTeamFromProvisioningProfile.teamName,
32
32
  });
@@ -24,7 +24,7 @@ export declare function updateIosAppCredentialsAsync(graphqlClient: ExpoGraphqlC
24
24
  applePushKeyId?: string;
25
25
  ascApiKeyIdForSubmissions?: string;
26
26
  }): Promise<CommonIosAppCredentialsFragment>;
27
- export declare function createOrGetExistingAppleTeamAsync(graphqlClient: ExpoGraphqlClient, account: AccountFragment, { appleTeamIdentifier, appleTeamName }: {
27
+ export declare function createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(graphqlClient: ExpoGraphqlClient, accountId: string, { appleTeamIdentifier, appleTeamName }: {
28
28
  appleTeamIdentifier: string;
29
29
  appleTeamName?: string;
30
30
  }): Promise<AppleTeamFragment>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteAscApiKeyAsync = exports.getAscApiKeyForAppSubmissionsAsync = exports.getAscApiKeysForAccountAsync = exports.createAscApiKeyAsync = exports.deletePushKeyAsync = exports.getPushKeyForAppAsync = exports.getPushKeysForAccountAsync = exports.createPushKeyAsync = exports.deleteDistributionCertificateAsync = exports.createDistributionCertificateAsync = exports.getDistributionCertificatesForAccountAsync = exports.getDistributionCertificateForAppAsync = exports.deleteProvisioningProfilesAsync = exports.updateProvisioningProfileAsync = exports.getProvisioningProfileAsync = exports.createProvisioningProfileAsync = exports.getDevicesForAppleTeamAsync = exports.createOrGetExistingAppleAppIdentifierAsync = exports.createOrGetExistingAppleTeamAsync = exports.updateIosAppCredentialsAsync = exports.createOrGetIosAppCredentialsWithCommonFieldsAsync = exports.getIosAppCredentialsWithCommonFieldsAsync = exports.getIosAppCredentialsWithBuildCredentialsAsync = exports.createOrUpdateIosAppBuildCredentialsAsync = void 0;
3
+ exports.deleteAscApiKeyAsync = exports.getAscApiKeyForAppSubmissionsAsync = exports.getAscApiKeysForAccountAsync = exports.createAscApiKeyAsync = exports.deletePushKeyAsync = exports.getPushKeyForAppAsync = exports.getPushKeysForAccountAsync = exports.createPushKeyAsync = exports.deleteDistributionCertificateAsync = exports.createDistributionCertificateAsync = exports.getDistributionCertificatesForAccountAsync = exports.getDistributionCertificateForAppAsync = exports.deleteProvisioningProfilesAsync = exports.updateProvisioningProfileAsync = exports.getProvisioningProfileAsync = exports.createProvisioningProfileAsync = exports.getDevicesForAppleTeamAsync = exports.createOrGetExistingAppleAppIdentifierAsync = exports.createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync = exports.updateIosAppCredentialsAsync = exports.createOrGetIosAppCredentialsWithCommonFieldsAsync = exports.getIosAppCredentialsWithCommonFieldsAsync = exports.getIosAppCredentialsWithBuildCredentialsAsync = exports.createOrUpdateIosAppBuildCredentialsAsync = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const apple_utils_1 = require("@expo/apple-utils");
6
6
  const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
@@ -117,16 +117,22 @@ async function createOrGetExistingIosAppCredentialsWithBuildCredentialsAsync(gra
117
117
  }));
118
118
  }
119
119
  }
120
- async function createOrGetExistingAppleTeamAsync(graphqlClient, account, { appleTeamIdentifier, appleTeamName }) {
121
- const appleTeam = await AppleTeamQuery_1.AppleTeamQuery.getByAppleTeamIdentifierAsync(graphqlClient, account.id, appleTeamIdentifier);
120
+ async function createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(graphqlClient, accountId, { appleTeamIdentifier, appleTeamName }) {
121
+ const appleTeam = await AppleTeamQuery_1.AppleTeamQuery.getByAppleTeamIdentifierAsync(graphqlClient, accountId, appleTeamIdentifier);
122
122
  if (appleTeam) {
123
+ const didAppleTeamNameChange = appleTeamName && appleTeam && appleTeamName !== appleTeam.appleTeamName;
124
+ if (didAppleTeamNameChange) {
125
+ return await AppleTeamMutation_1.AppleTeamMutation.updateAppleTeamAsync(graphqlClient, {
126
+ appleTeamName,
127
+ }, appleTeam.id);
128
+ }
123
129
  return appleTeam;
124
130
  }
125
131
  else {
126
- return await AppleTeamMutation_1.AppleTeamMutation.createAppleTeamAsync(graphqlClient, { appleTeamIdentifier, appleTeamName }, account.id);
132
+ return await AppleTeamMutation_1.AppleTeamMutation.createAppleTeamAsync(graphqlClient, { appleTeamIdentifier, appleTeamName }, accountId);
127
133
  }
128
134
  }
129
- exports.createOrGetExistingAppleTeamAsync = createOrGetExistingAppleTeamAsync;
135
+ exports.createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync = createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync;
130
136
  async function createOrGetExistingAppleAppIdentifierAsync(graphqlClient, { account, projectName, bundleIdentifier, parentBundleIdentifier }, appleTeam) {
131
137
  const appleAppIdentifier = await AppleAppIdentifierQuery_1.AppleAppIdentifierQuery.byBundleIdentifierAsync(graphqlClient, account.name, bundleIdentifier);
132
138
  if (appleAppIdentifier) {
@@ -188,7 +194,7 @@ async function getDistributionCertificatesForAccountAsync(graphqlClient, account
188
194
  }
189
195
  exports.getDistributionCertificatesForAccountAsync = getDistributionCertificatesForAccountAsync;
190
196
  async function createDistributionCertificateAsync(graphqlClient, account, distCert) {
191
- const appleTeam = await createOrGetExistingAppleTeamAsync(graphqlClient, account, {
197
+ const appleTeam = await createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(graphqlClient, account.id, {
192
198
  appleTeamIdentifier: distCert.teamId,
193
199
  appleTeamName: distCert.teamName,
194
200
  });
@@ -206,7 +212,7 @@ async function deleteDistributionCertificateAsync(graphqlClient, distributionCer
206
212
  }
207
213
  exports.deleteDistributionCertificateAsync = deleteDistributionCertificateAsync;
208
214
  async function createPushKeyAsync(graphqlClient, account, pushKey) {
209
- const appleTeam = await createOrGetExistingAppleTeamAsync(graphqlClient, account, {
215
+ const appleTeam = await createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(graphqlClient, account.id, {
210
216
  appleTeamIdentifier: pushKey.teamId,
211
217
  appleTeamName: pushKey.teamName,
212
218
  });
@@ -232,7 +238,7 @@ async function deletePushKeyAsync(graphqlClient, pushKeyId) {
232
238
  exports.deletePushKeyAsync = deletePushKeyAsync;
233
239
  async function createAscApiKeyAsync(graphqlClient, account, ascApiKey) {
234
240
  const maybeAppleTeam = ascApiKey.teamId
235
- ? await createOrGetExistingAppleTeamAsync(graphqlClient, account, {
241
+ ? await createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync(graphqlClient, account.id, {
236
242
  appleTeamIdentifier: ascApiKey.teamId,
237
243
  appleTeamName: ascApiKey.teamName,
238
244
  })
@@ -1,8 +1,6 @@
1
1
  import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
2
- import { AccountFragment, AppleTeamFragment, AppleTeamInput } from '../../../../../graphql/generated';
3
- export type AppleTeamMutationResult = AppleTeamFragment & {
4
- account: AccountFragment;
5
- };
2
+ import { AppleTeamFragment, AppleTeamInput, AppleTeamUpdateInput } from '../../../../../graphql/generated';
6
3
  export declare const AppleTeamMutation: {
7
- createAppleTeamAsync(graphqlClient: ExpoGraphqlClient, appleTeamInput: AppleTeamInput, accountId: string): Promise<AppleTeamMutationResult>;
4
+ createAppleTeamAsync(graphqlClient: ExpoGraphqlClient, appleTeamInput: AppleTeamInput, accountId: string): Promise<AppleTeamFragment>;
5
+ updateAppleTeamAsync(graphqlClient: ExpoGraphqlClient, appleTeamInput: AppleTeamUpdateInput, appleTeamEntityId: string): Promise<AppleTeamFragment>;
8
6
  };
@@ -5,7 +5,6 @@ const tslib_1 = require("tslib");
5
5
  const graphql_1 = require("graphql");
6
6
  const graphql_tag_1 = tslib_1.__importDefault(require("graphql-tag"));
7
7
  const client_1 = require("../../../../../graphql/client");
8
- const Account_1 = require("../../../../../graphql/types/Account");
9
8
  const AppleTeam_1 = require("../../../../../graphql/types/credentials/AppleTeam");
10
9
  exports.AppleTeamMutation = {
11
10
  async createAppleTeamAsync(graphqlClient, appleTeamInput, accountId) {
@@ -16,15 +15,10 @@ exports.AppleTeamMutation = {
16
15
  createAppleTeam(appleTeamInput: $appleTeamInput, accountId: $accountId) {
17
16
  id
18
17
  ...AppleTeamFragment
19
- account {
20
- id
21
- ...AccountFragment
22
- }
23
18
  }
24
19
  }
25
20
  }
26
21
  ${(0, graphql_1.print)(AppleTeam_1.AppleTeamFragmentNode)}
27
- ${(0, graphql_1.print)(Account_1.AccountFragmentNode)}
28
22
  `, {
29
23
  appleTeamInput,
30
24
  accountId,
@@ -32,4 +26,26 @@ exports.AppleTeamMutation = {
32
26
  .toPromise());
33
27
  return data.appleTeam.createAppleTeam;
34
28
  },
29
+ async updateAppleTeamAsync(graphqlClient, appleTeamInput, appleTeamEntityId) {
30
+ const data = await (0, client_1.withErrorHandlingAsync)(graphqlClient
31
+ .mutation((0, graphql_tag_1.default) `
32
+ mutation UpdateAppleTeamMutation(
33
+ $appleTeamInput: AppleTeamUpdateInput!
34
+ $appleTeamEntityId: ID!
35
+ ) {
36
+ appleTeam {
37
+ updateAppleTeam(appleTeamUpdateInput: $appleTeamInput, id: $appleTeamEntityId) {
38
+ id
39
+ ...AppleTeamFragment
40
+ }
41
+ }
42
+ }
43
+ ${(0, graphql_1.print)(AppleTeam_1.AppleTeamFragmentNode)}
44
+ `, {
45
+ appleTeamInput,
46
+ appleTeamEntityId,
47
+ })
48
+ .toPromise());
49
+ return data.appleTeam.updateAppleTeam;
50
+ },
35
51
  };
@@ -5,8 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const assert_1 = tslib_1.__importDefault(require("assert"));
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
7
  const action_1 = tslib_1.__importDefault(require("./actions/create/action"));
8
- const AppleTeamMutation_1 = require("../credentials/ios/api/graphql/mutations/AppleTeamMutation");
9
- const AppleTeamQuery_1 = require("../credentials/ios/api/graphql/queries/AppleTeamQuery");
8
+ const GraphqlClient_1 = require("../credentials/ios/api/GraphqlClient");
10
9
  const log_1 = tslib_1.__importDefault(require("../log"));
11
10
  const projectUtils_1 = require("../project/projectUtils");
12
11
  const prompts_1 = require("../prompts");
@@ -27,7 +26,7 @@ class DeviceManager {
27
26
  log_1.default.addNewLineIfNone();
28
27
  const account = await this.resolveAccountAsync();
29
28
  const appleAuthCtx = await this.ctx.appStore.ensureAuthenticatedAsync();
30
- const appleTeam = await ensureAppleTeamExistsAsync(this.ctx.graphqlClient, account.id, {
29
+ const appleTeam = await (0, GraphqlClient_1.createOrGetExistingAppleTeamAndUpdateNameIfChangedAsync)(this.ctx.graphqlClient, account.id, {
31
30
  appleTeamIdentifier: appleAuthCtx.team.id,
32
31
  appleTeamName: appleAuthCtx.team.name,
33
32
  });
@@ -81,15 +80,3 @@ class AccountResolver {
81
80
  }
82
81
  }
83
82
  exports.AccountResolver = AccountResolver;
84
- async function ensureAppleTeamExistsAsync(graphqlClient, accountId, { appleTeamIdentifier, appleTeamName }) {
85
- const appleTeam = await AppleTeamQuery_1.AppleTeamQuery.getByAppleTeamIdentifierAsync(graphqlClient, accountId, appleTeamIdentifier);
86
- if (appleTeam) {
87
- return appleTeam;
88
- }
89
- else {
90
- return await AppleTeamMutation_1.AppleTeamMutation.createAppleTeamAsync(graphqlClient, {
91
- appleTeamIdentifier,
92
- appleTeamName,
93
- }, accountId);
94
- }
95
- }
@@ -9004,34 +9004,22 @@ export type CreateAppleTeamMutation = {
9004
9004
  id: string;
9005
9005
  appleTeamIdentifier: string;
9006
9006
  appleTeamName?: string | null;
9007
- account: {
9008
- __typename?: 'Account';
9009
- id: string;
9010
- name: string;
9011
- ownerUserActor?: {
9012
- __typename?: 'SSOUser';
9013
- id: string;
9014
- username: string;
9015
- } | {
9016
- __typename?: 'User';
9017
- id: string;
9018
- username: string;
9019
- } | null;
9020
- users: Array<{
9021
- __typename?: 'UserPermission';
9022
- role: Role;
9023
- actor: {
9024
- __typename?: 'Robot';
9025
- id: string;
9026
- } | {
9027
- __typename?: 'SSOUser';
9028
- id: string;
9029
- } | {
9030
- __typename?: 'User';
9031
- id: string;
9032
- };
9033
- }>;
9034
- };
9007
+ };
9008
+ };
9009
+ };
9010
+ export type UpdateAppleTeamMutationVariables = Exact<{
9011
+ appleTeamInput: AppleTeamUpdateInput;
9012
+ appleTeamEntityId: Scalars['ID']['input'];
9013
+ }>;
9014
+ export type UpdateAppleTeamMutation = {
9015
+ __typename?: 'RootMutation';
9016
+ appleTeam: {
9017
+ __typename?: 'AppleTeamMutation';
9018
+ updateAppleTeam: {
9019
+ __typename?: 'AppleTeam';
9020
+ id: string;
9021
+ appleTeamIdentifier: string;
9022
+ appleTeamName?: string | null;
9035
9023
  };
9036
9024
  };
9037
9025
  };
@@ -6,11 +6,24 @@ import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGr
6
6
  import { EnvironmentVariableEnvironment } from '../graphql/generated';
7
7
  interface AssetMapOptions {
8
8
  hashOptions?: HashOptions;
9
+ maxFileSize: number;
9
10
  }
11
+ export interface AssetFileEntry {
12
+ normalizedPath: string;
13
+ path: string;
14
+ size: number;
15
+ sha512: string;
16
+ type: string | null;
17
+ }
18
+ /** Collects assets from a given target path */
19
+ export declare function collectAssetsAsync(assetPath: string | undefined, options: AssetMapOptions): Promise<AssetFileEntry[]>;
10
20
  /** Mapping of normalized file paths to a SHA512 hash */
11
- export type AssetMap = Record<string, string>;
12
- /** Creates an asset map of a given target path */
13
- declare function createAssetMapAsync(assetPath?: string, options?: AssetMapOptions): Promise<AssetMap>;
21
+ export type AssetMap = Record<string, string | {
22
+ sha512: string;
23
+ size: number;
24
+ }>;
25
+ /** Converts array of asset entries into AssetMap (as sent to deployment-api) */
26
+ export declare function assetsToAssetsMap(assets: AssetFileEntry[]): AssetMap;
14
27
  export interface Manifest {
15
28
  env: Record<string, string | undefined>;
16
29
  }
@@ -31,16 +44,9 @@ interface WorkerFileEntry {
31
44
  data: Buffer | string;
32
45
  }
33
46
  /** Reads worker files while normalizing sourcemaps and providing normalized paths */
34
- declare function listWorkerFilesAsync(workerPath: string): AsyncGenerator<WorkerFileEntry>;
35
- interface AssetFileEntry {
36
- normalizedPath: string;
37
- sha512: string;
38
- path: string;
39
- }
40
- /** Reads files of an asset maps and enumerates normalized paths and data */
41
- declare function listAssetMapFilesAsync(assetPath: string, assetMap: AssetMap): AsyncGenerator<AssetFileEntry>;
47
+ export declare function listWorkerFilesAsync(workerPath: string): AsyncGenerator<WorkerFileEntry>;
42
48
  /** Entry of a normalized (gzip-safe) path and file data */
43
49
  export type FileEntry = readonly [normalizedPath: string, data: Buffer | string];
44
50
  /** Packs file entries into a tar.gz file (path to tgz returned) */
45
- declare function packFilesIterableAsync(iterable: Iterable<FileEntry> | AsyncIterable<FileEntry>, options?: GzipOptions): Promise<string>;
46
- export { createAssetMapAsync, listWorkerFilesAsync, listAssetMapFilesAsync, packFilesIterableAsync, };
51
+ export declare function packFilesIterableAsync(iterable: Iterable<FileEntry> | AsyncIterable<FileEntry>, options?: GzipOptions): Promise<string>;
52
+ export {};
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.packFilesIterableAsync = exports.listAssetMapFilesAsync = exports.listWorkerFilesAsync = exports.createAssetMapAsync = exports.createManifestAsync = void 0;
3
+ exports.packFilesIterableAsync = exports.listWorkerFilesAsync = exports.createManifestAsync = exports.assetsToAssetsMap = exports.collectAssetsAsync = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const env_1 = require("@expo/env");
6
+ const mime_1 = tslib_1.__importDefault(require("mime"));
6
7
  const minizlib_1 = require("minizlib");
7
8
  const node_crypto_1 = require("node:crypto");
8
9
  const node_fs_1 = tslib_1.__importStar(require("node:fs"));
@@ -50,9 +51,12 @@ function listFilesRecursively(basePath) {
50
51
  continue;
51
52
  }
52
53
  else if (dirent.isFile()) {
54
+ const absolutePath = node_path_1.default.resolve(target, dirent.name);
55
+ const stats = await node_fs_1.default.promises.stat(absolutePath);
53
56
  yield {
54
57
  normalizedPath,
55
- path: node_path_1.default.resolve(target, dirent.name),
58
+ path: absolutePath,
59
+ size: stats.size,
56
60
  };
57
61
  }
58
62
  else if (dirent.isDirectory()) {
@@ -62,17 +66,54 @@ function listFilesRecursively(basePath) {
62
66
  }
63
67
  return recurseAsync();
64
68
  }
65
- /** Creates an asset map of a given target path */
66
- async function createAssetMapAsync(assetPath, options) {
67
- const map = Object.create(null);
69
+ async function determineMimeTypeAsync(filePath) {
70
+ let contentType = mime_1.default.getType(node_path_1.default.basename(filePath));
71
+ if (!contentType) {
72
+ const fileContent = await node_fs_1.default.promises.readFile(filePath, 'utf-8');
73
+ try {
74
+ // check if file is valid JSON without an extension, e.g. for the apple app site association file
75
+ const parsedData = JSON.parse(fileContent);
76
+ if (parsedData) {
77
+ contentType = 'application/json';
78
+ }
79
+ }
80
+ catch { }
81
+ }
82
+ return contentType;
83
+ }
84
+ /** Collects assets from a given target path */
85
+ async function collectAssetsAsync(assetPath, options) {
86
+ const assets = [];
68
87
  if (assetPath) {
69
88
  for await (const file of listFilesRecursively(assetPath)) {
70
- map[file.normalizedPath] = await computeSha512HashAsync(file.path, options?.hashOptions);
89
+ if (file.size > options.maxFileSize) {
90
+ throw new Error(`Upload of "${file.normalizedPath}" aborted: File size is greater than the upload limit (>500MB)`);
91
+ }
92
+ const sha512$ = computeSha512HashAsync(file.path, options?.hashOptions);
93
+ const contentType$ = determineMimeTypeAsync(file.path);
94
+ assets.push({
95
+ normalizedPath: file.normalizedPath,
96
+ path: file.path,
97
+ size: file.size,
98
+ sha512: await sha512$,
99
+ type: await contentType$,
100
+ });
71
101
  }
72
102
  }
73
- return map;
103
+ return assets;
74
104
  }
75
- exports.createAssetMapAsync = createAssetMapAsync;
105
+ exports.collectAssetsAsync = collectAssetsAsync;
106
+ /** Converts array of asset entries into AssetMap (as sent to deployment-api) */
107
+ function assetsToAssetsMap(assets) {
108
+ return assets.reduce((map, entry) => {
109
+ map[entry.normalizedPath] = {
110
+ sha512: entry.sha512,
111
+ size: entry.size,
112
+ };
113
+ return map;
114
+ }, Object.create(null));
115
+ }
116
+ exports.assetsToAssetsMap = assetsToAssetsMap;
76
117
  /** Creates a manifest configuration sent up for deployment */
77
118
  async function createManifestAsync(params, graphqlClient) {
78
119
  // Resolve .env file variables
@@ -110,18 +151,6 @@ async function* listWorkerFilesAsync(workerPath) {
110
151
  }
111
152
  }
112
153
  exports.listWorkerFilesAsync = listWorkerFilesAsync;
113
- /** Reads files of an asset maps and enumerates normalized paths and data */
114
- async function* listAssetMapFilesAsync(assetPath, assetMap) {
115
- for (const normalizedPath in assetMap) {
116
- const filePath = node_path_1.default.resolve(assetPath, normalizedPath.split('/').join(node_path_1.default.sep));
117
- yield {
118
- normalizedPath,
119
- path: filePath,
120
- sha512: assetMap[normalizedPath],
121
- };
122
- }
123
- }
124
- exports.listAssetMapFilesAsync = listAssetMapFilesAsync;
125
154
  /** Packs file entries into a tar.gz file (path to tgz returned) */
126
155
  async function packFilesIterableAsync(iterable, options) {
127
156
  const writePath = `${await createTempWritePathAsync()}.tar.gz`;
@@ -1,23 +1,35 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import { HeadersInit, RequestInit, Response } from 'node-fetch';
4
- export interface UploadParams extends Omit<RequestInit, 'signal' | 'body'> {
4
+ import { AssetFileEntry } from './assets';
5
+ export type UploadPayload = {
5
6
  filePath: string;
6
- compress?: boolean;
7
- url: string;
7
+ } | {
8
+ asset: AssetFileEntry;
9
+ } | {
10
+ multipart: AssetFileEntry[];
11
+ };
12
+ export interface UploadRequestInit {
13
+ baseURL: string | URL;
8
14
  method?: string;
9
15
  headers?: HeadersInit;
10
- body?: undefined;
11
16
  signal?: AbortSignal;
12
17
  }
13
18
  export interface UploadResult {
14
- params: UploadParams;
19
+ payload: UploadPayload;
15
20
  response: Response;
16
21
  }
17
- export declare function uploadAsync(params: UploadParams): Promise<UploadResult>;
22
+ type OnProgressUpdateCallback = (progress: number) => void;
23
+ export declare function uploadAsync(init: UploadRequestInit, payload: UploadPayload, onProgressUpdate?: OnProgressUpdateCallback): Promise<UploadResult>;
18
24
  export declare function callUploadApiAsync(url: string | URL, init?: RequestInit): Promise<unknown>;
19
25
  export interface UploadPending {
20
- params: UploadParams;
26
+ payload: UploadPayload;
27
+ progress: number;
21
28
  }
22
- export type BatchUploadSignal = UploadResult | UploadPending;
23
- export declare function batchUploadAsync(uploads: readonly UploadParams[]): AsyncGenerator<BatchUploadSignal>;
29
+ export declare function batchUploadAsync(init: UploadRequestInit, payloads: UploadPayload[], onProgressUpdate?: OnProgressUpdateCallback): AsyncGenerator<UploadPending>;
30
+ interface UploadProgressBar {
31
+ update(progress: number): void;
32
+ stop(): void;
33
+ }
34
+ export declare function createProgressBar(label?: string): UploadProgressBar;
35
+ export {};