@capawesome/cli 4.4.0 → 4.5.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.
@@ -0,0 +1,312 @@
1
+ import appAppleApiKeysService from '../../../services/app-apple-api-keys.js';
2
+ import appDestinationsService from '../../../services/app-destinations.js';
3
+ import appGoogleServiceAccountKeysService from '../../../services/app-google-service-account-keys.js';
4
+ import { withAuth } from '../../../utils/auth.js';
5
+ import { isInteractive } from '../../../utils/environment.js';
6
+ import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
7
+ import { defineCommand, defineOptions } from '@robingenz/zli';
8
+ import consola from 'consola';
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import { z } from 'zod';
12
+ export default defineCommand({
13
+ description: 'Create a new app destination.',
14
+ options: defineOptions(z.object({
15
+ appId: z.string().optional().describe('ID of the app.'),
16
+ name: z.string().optional().describe('Name of the destination.'),
17
+ platform: z.enum(['android', 'ios']).optional().describe('Platform of the destination (android, ios).'),
18
+ appleId: z.string().optional().describe('Apple ID for the destination.'),
19
+ appleAppId: z.string().optional().describe('Apple App ID for the destination.'),
20
+ appleTeamId: z.string().optional().describe('Apple Team ID for the destination.'),
21
+ appleAppPassword: z.string().optional().describe('Apple app-specific password for the destination.'),
22
+ appleApiKeyFile: z.string().optional().describe('Path to the Apple API key (.p8) file.'),
23
+ appleIssuerId: z.string().optional().describe('Apple Issuer ID for the destination.'),
24
+ androidPackageName: z.string().optional().describe('Android package name for the destination.'),
25
+ androidBuildArtifactType: z.enum(['aab', 'apk']).optional().describe('Android build artifact type (aab, apk).'),
26
+ androidReleaseStatus: z
27
+ .enum(['completed', 'draft'])
28
+ .optional()
29
+ .describe('Android release status (completed, draft).'),
30
+ googleServiceAccountKeyFile: z.string().optional().describe('Path to the Google service account key JSON file.'),
31
+ googlePlayTrack: z.string().optional().describe('Google Play track for the destination.'),
32
+ })),
33
+ action: withAuth(async (options, args) => {
34
+ let { appId, name, platform, appleId, appleAppId, appleTeamId, appleAppPassword, appleApiKeyFile, appleIssuerId, androidPackageName, androidBuildArtifactType, androidReleaseStatus, googleServiceAccountKeyFile, googlePlayTrack, } = options;
35
+ let appleApiKeyId;
36
+ let appAppleApiKeyId;
37
+ let appGoogleServiceAccountKeyId;
38
+ // 1. Select organization and app
39
+ if (!appId) {
40
+ if (!isInteractive()) {
41
+ consola.error('You must provide an app ID when running in non-interactive environment.');
42
+ process.exit(1);
43
+ }
44
+ const organizationId = await promptOrganizationSelection();
45
+ appId = await promptAppSelection(organizationId);
46
+ }
47
+ // 2. Enter destination name
48
+ if (!name) {
49
+ if (!isInteractive()) {
50
+ consola.error('You must provide the destination name when running in non-interactive environment.');
51
+ process.exit(1);
52
+ }
53
+ name = await prompt('Enter the name of the destination:', { type: 'text' });
54
+ if (!name) {
55
+ consola.error('You must provide a destination name.');
56
+ process.exit(1);
57
+ }
58
+ }
59
+ // 3. Select platform
60
+ if (!platform) {
61
+ if (!isInteractive()) {
62
+ consola.error('You must provide the platform when running in non-interactive environment.');
63
+ process.exit(1);
64
+ }
65
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
66
+ platform = await prompt('Select the platform:', {
67
+ type: 'select',
68
+ options: [
69
+ { label: 'Android', value: 'android' },
70
+ { label: 'iOS', value: 'ios' },
71
+ ],
72
+ });
73
+ if (!platform) {
74
+ consola.error('You must select a platform.');
75
+ process.exit(1);
76
+ }
77
+ }
78
+ if (platform === 'android') {
79
+ // 4. Ask for track
80
+ if (!googlePlayTrack) {
81
+ if (!isInteractive()) {
82
+ consola.error('You must provide the Google Play track when running in non-interactive environment.');
83
+ process.exit(1);
84
+ }
85
+ googlePlayTrack = await prompt('Enter the Google Play track:', { type: 'text' });
86
+ if (!googlePlayTrack) {
87
+ consola.error('You must provide a Google Play track.');
88
+ process.exit(1);
89
+ }
90
+ }
91
+ // 5. Ask for package name
92
+ if (!androidPackageName) {
93
+ if (!isInteractive()) {
94
+ consola.error('You must provide the Android package name when running in non-interactive environment.');
95
+ process.exit(1);
96
+ }
97
+ androidPackageName = await prompt('Enter the Android package name:', { type: 'text' });
98
+ if (!androidPackageName) {
99
+ consola.error('You must provide an Android package name.');
100
+ process.exit(1);
101
+ }
102
+ }
103
+ // 6. Ask for publishing format
104
+ if (!androidBuildArtifactType) {
105
+ if (!isInteractive()) {
106
+ consola.error('You must provide the Android build artifact type when running in non-interactive environment.');
107
+ process.exit(1);
108
+ }
109
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
110
+ androidBuildArtifactType = await prompt('Select the publishing format:', {
111
+ type: 'select',
112
+ options: [
113
+ { label: 'AAB', value: 'aab' },
114
+ { label: 'APK', value: 'apk' },
115
+ ],
116
+ });
117
+ if (!androidBuildArtifactType) {
118
+ consola.error('You must select a publishing format.');
119
+ process.exit(1);
120
+ }
121
+ }
122
+ // 7. Ask for release status
123
+ if (!androidReleaseStatus) {
124
+ if (!isInteractive()) {
125
+ consola.error('You must provide the Android release status when running in non-interactive environment.');
126
+ process.exit(1);
127
+ }
128
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
129
+ androidReleaseStatus = await prompt('Select the release status:', {
130
+ type: 'select',
131
+ options: [
132
+ { label: 'Draft', value: 'draft' },
133
+ { label: 'Completed', value: 'completed' },
134
+ ],
135
+ });
136
+ if (!androidReleaseStatus) {
137
+ consola.error('You must select a release status.');
138
+ process.exit(1);
139
+ }
140
+ }
141
+ // 8. Ask for JSON key path
142
+ if (!googleServiceAccountKeyFile) {
143
+ if (!isInteractive()) {
144
+ consola.error('You must provide the Google service account key file when running in non-interactive environment.');
145
+ process.exit(1);
146
+ }
147
+ googleServiceAccountKeyFile = await prompt('Enter the path to the Google service account key JSON file:', {
148
+ type: 'text',
149
+ });
150
+ if (!googleServiceAccountKeyFile) {
151
+ consola.error('You must provide a Google service account key file path.');
152
+ process.exit(1);
153
+ }
154
+ }
155
+ // Upload Google service account key file
156
+ const buffer = fs.readFileSync(googleServiceAccountKeyFile);
157
+ const fileName = path.basename(googleServiceAccountKeyFile);
158
+ const key = await appGoogleServiceAccountKeysService.create({
159
+ appId,
160
+ buffer,
161
+ fileName,
162
+ });
163
+ appGoogleServiceAccountKeyId = key.id;
164
+ }
165
+ if (platform === 'ios') {
166
+ // 9. Ask for authentication method
167
+ let authMethod;
168
+ if (appleApiKeyFile || appleIssuerId) {
169
+ authMethod = 'apiKey';
170
+ }
171
+ else if (appleId || appleAppId || appleAppPassword) {
172
+ authMethod = 'password';
173
+ }
174
+ else if (isInteractive()) {
175
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
176
+ authMethod = await prompt('Select the authentication method:', {
177
+ type: 'select',
178
+ options: [
179
+ { label: 'API Key', value: 'apiKey' },
180
+ { label: 'Password', value: 'password' },
181
+ ],
182
+ });
183
+ if (!authMethod) {
184
+ consola.error('You must select an authentication method.');
185
+ process.exit(1);
186
+ }
187
+ }
188
+ else {
189
+ consola.error('You must provide authentication options when running in non-interactive environment. Either pass --apple-api-key-file and --apple-issuer-id for API Key authentication or --apple-id, --apple-app-id, and --apple-app-password for Password authentication.');
190
+ process.exit(1);
191
+ }
192
+ if (authMethod === 'apiKey') {
193
+ // 10. Ask for p8 key file path
194
+ if (!appleApiKeyFile) {
195
+ if (!isInteractive()) {
196
+ consola.error('You must provide the Apple API key file when running in non-interactive environment.');
197
+ process.exit(1);
198
+ }
199
+ appleApiKeyFile = await prompt('Enter the path to the Apple API key (.p8) file:', {
200
+ type: 'text',
201
+ });
202
+ if (!appleApiKeyFile) {
203
+ consola.error('You must provide an Apple API key file path.');
204
+ process.exit(1);
205
+ }
206
+ }
207
+ // Upload Apple API key file
208
+ const buffer = fs.readFileSync(appleApiKeyFile);
209
+ const fileName = path.basename(appleApiKeyFile);
210
+ const key = await appAppleApiKeysService.create({
211
+ appId,
212
+ buffer,
213
+ fileName,
214
+ });
215
+ appAppleApiKeyId = key.id;
216
+ // 11. Ask for key ID
217
+ if (!appleApiKeyId) {
218
+ if (!isInteractive()) {
219
+ consola.error('You must provide the Apple API Key ID when running in non-interactive environment.');
220
+ process.exit(1);
221
+ }
222
+ appleApiKeyId = await prompt('Enter the Apple API Key ID:', { type: 'text' });
223
+ if (!appleApiKeyId) {
224
+ consola.error('You must provide an Apple API Key ID.');
225
+ process.exit(1);
226
+ }
227
+ }
228
+ // 12. Ask for issuer ID
229
+ if (!appleIssuerId) {
230
+ if (!isInteractive()) {
231
+ consola.error('You must provide the Apple Issuer ID when running in non-interactive environment.');
232
+ process.exit(1);
233
+ }
234
+ appleIssuerId = await prompt('Enter the Apple Issuer ID:', { type: 'text' });
235
+ if (!appleIssuerId) {
236
+ consola.error('You must provide an Apple Issuer ID.');
237
+ process.exit(1);
238
+ }
239
+ }
240
+ }
241
+ else if (authMethod === 'password') {
242
+ // 13. Ask for Apple ID
243
+ if (!appleId) {
244
+ if (!isInteractive()) {
245
+ consola.error('You must provide the Apple ID when running in non-interactive environment.');
246
+ process.exit(1);
247
+ }
248
+ appleId = await prompt('Enter the Apple ID:', { type: 'text' });
249
+ if (!appleId) {
250
+ consola.error('You must provide an Apple ID.');
251
+ process.exit(1);
252
+ }
253
+ }
254
+ // 14. Ask for Apple App ID
255
+ if (!appleAppId) {
256
+ if (!isInteractive()) {
257
+ consola.error('You must provide the Apple App ID when running in non-interactive environment.');
258
+ process.exit(1);
259
+ }
260
+ appleAppId = await prompt('Enter the Apple App ID:', { type: 'text' });
261
+ if (!appleAppId) {
262
+ consola.error('You must provide an Apple App ID.');
263
+ process.exit(1);
264
+ }
265
+ }
266
+ // 15. Ask for App-specific password
267
+ if (!appleAppPassword) {
268
+ if (!isInteractive()) {
269
+ consola.error('You must provide the App-specific password when running in non-interactive environment.');
270
+ process.exit(1);
271
+ }
272
+ appleAppPassword = await prompt('Enter the App-specific password:', { type: 'text' });
273
+ if (!appleAppPassword) {
274
+ consola.error('You must provide an App-specific password.');
275
+ process.exit(1);
276
+ }
277
+ }
278
+ }
279
+ // 16. Ask for team ID
280
+ if (!appleTeamId) {
281
+ if (!isInteractive()) {
282
+ consola.error('You must provide the Apple Team ID when running in non-interactive environment.');
283
+ process.exit(1);
284
+ }
285
+ appleTeamId = await prompt('Enter the Apple Team ID:', { type: 'text' });
286
+ if (!appleTeamId) {
287
+ consola.error('You must provide an Apple Team ID.');
288
+ process.exit(1);
289
+ }
290
+ }
291
+ }
292
+ const response = await appDestinationsService.create({
293
+ appId,
294
+ name,
295
+ platform: platform,
296
+ appleId,
297
+ appleAppId,
298
+ appleTeamId,
299
+ appleAppPassword,
300
+ appleApiKeyId,
301
+ appleIssuerId,
302
+ appAppleApiKeyId,
303
+ androidPackageName,
304
+ androidBuildArtifactType,
305
+ androidReleaseStatus,
306
+ appGoogleServiceAccountKeyId,
307
+ googlePlayTrack,
308
+ });
309
+ consola.info(`Destination ID: ${response.id}`);
310
+ consola.success('Destination created successfully.');
311
+ }),
312
+ });
@@ -0,0 +1,75 @@
1
+ import appDestinationsService from '../../../services/app-destinations.js';
2
+ import { withAuth } from '../../../utils/auth.js';
3
+ import { isInteractive } from '../../../utils/environment.js';
4
+ import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
5
+ import { defineCommand, defineOptions } from '@robingenz/zli';
6
+ import consola from 'consola';
7
+ import { z } from 'zod';
8
+ export default defineCommand({
9
+ description: 'Delete an app destination.',
10
+ options: defineOptions(z.object({
11
+ appId: z.string().optional().describe('ID of the app.'),
12
+ destinationId: z.string().optional().describe('ID of the destination.'),
13
+ name: z.string().optional().describe('Name of the destination.'),
14
+ platform: z.enum(['android', 'ios']).optional().describe('Platform of the destination (android, ios).'),
15
+ yes: z.boolean().optional().describe('Skip confirmation prompt.'),
16
+ }), { y: 'yes' }),
17
+ action: withAuth(async (options, args) => {
18
+ let { appId, destinationId, name, platform } = options;
19
+ if (!appId) {
20
+ if (!isInteractive()) {
21
+ consola.error('You must provide an app ID when running in non-interactive environment.');
22
+ process.exit(1);
23
+ }
24
+ const organizationId = await promptOrganizationSelection();
25
+ appId = await promptAppSelection(organizationId);
26
+ }
27
+ if (!destinationId) {
28
+ if (name && platform) {
29
+ const destinations = await appDestinationsService.findAll({ appId, name, platform });
30
+ const firstDestination = destinations[0];
31
+ if (!firstDestination) {
32
+ consola.error(`No destination found with name '${name}' and platform '${platform}'.`);
33
+ process.exit(1);
34
+ }
35
+ destinationId = firstDestination.id;
36
+ }
37
+ else if (isInteractive()) {
38
+ if (!platform) {
39
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
40
+ platform = await prompt('Select the platform:', {
41
+ type: 'select',
42
+ options: [
43
+ { label: 'Android', value: 'android' },
44
+ { label: 'iOS', value: 'ios' },
45
+ ],
46
+ });
47
+ }
48
+ const destinations = await appDestinationsService.findAll({ appId, platform });
49
+ if (!destinations.length) {
50
+ consola.error('No destinations found for this app. Create one first.');
51
+ process.exit(1);
52
+ }
53
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
54
+ destinationId = await prompt('Select the destination to delete:', {
55
+ type: 'select',
56
+ options: destinations.map((dest) => ({ label: dest.name, value: dest.id })),
57
+ });
58
+ }
59
+ else {
60
+ consola.error('You must provide the destination ID or --name and --platform when running in non-interactive environment.');
61
+ process.exit(1);
62
+ }
63
+ }
64
+ if (!options.yes && isInteractive()) {
65
+ const confirmed = await prompt('Are you sure you want to delete this destination?', {
66
+ type: 'confirm',
67
+ });
68
+ if (!confirmed) {
69
+ return;
70
+ }
71
+ }
72
+ await appDestinationsService.delete({ appId, destinationId });
73
+ consola.success('Destination deleted successfully.');
74
+ }),
75
+ });
@@ -0,0 +1,76 @@
1
+ import appDestinationsService from '../../../services/app-destinations.js';
2
+ import { withAuth } from '../../../utils/auth.js';
3
+ import { isInteractive } from '../../../utils/environment.js';
4
+ import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
5
+ import { defineCommand, defineOptions } from '@robingenz/zli';
6
+ import consola from 'consola';
7
+ import { z } from 'zod';
8
+ export default defineCommand({
9
+ description: 'Get an existing app destination.',
10
+ options: defineOptions(z.object({
11
+ appId: z.string().optional().describe('ID of the app.'),
12
+ destinationId: z.string().optional().describe('ID of the destination.'),
13
+ json: z.boolean().optional().describe('Output in JSON format.'),
14
+ name: z.string().optional().describe('Name of the destination.'),
15
+ platform: z.enum(['android', 'ios']).optional().describe('Platform of the destination (android, ios).'),
16
+ })),
17
+ action: withAuth(async (options, args) => {
18
+ let { appId, destinationId, name, platform } = options;
19
+ if (!appId) {
20
+ if (!isInteractive()) {
21
+ consola.error('You must provide an app ID when running in non-interactive environment.');
22
+ process.exit(1);
23
+ }
24
+ const organizationId = await promptOrganizationSelection();
25
+ appId = await promptAppSelection(organizationId);
26
+ }
27
+ if (!destinationId) {
28
+ if (name && platform) {
29
+ const destinations = await appDestinationsService.findAll({ appId, name, platform });
30
+ const firstDestination = destinations[0];
31
+ if (!firstDestination) {
32
+ consola.error(`No destination found with name '${name}' and platform '${platform}'.`);
33
+ process.exit(1);
34
+ }
35
+ destinationId = firstDestination.id;
36
+ }
37
+ else if (isInteractive()) {
38
+ if (!platform) {
39
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
40
+ platform = await prompt('Select the platform:', {
41
+ type: 'select',
42
+ options: [
43
+ { label: 'Android', value: 'android' },
44
+ { label: 'iOS', value: 'ios' },
45
+ ],
46
+ });
47
+ }
48
+ const destinations = await appDestinationsService.findAll({ appId, platform });
49
+ if (!destinations.length) {
50
+ consola.error('No destinations found for this app. Create one first.');
51
+ process.exit(1);
52
+ }
53
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
54
+ destinationId = await prompt('Select the destination:', {
55
+ type: 'select',
56
+ options: destinations.map((dest) => ({ label: dest.name, value: dest.id })),
57
+ });
58
+ }
59
+ else {
60
+ consola.error('You must provide the destination ID or --name and --platform when running in non-interactive environment.');
61
+ process.exit(1);
62
+ }
63
+ }
64
+ const destination = await appDestinationsService.findOneById({
65
+ appId,
66
+ destinationId,
67
+ });
68
+ if (options.json) {
69
+ console.log(JSON.stringify(destination, null, 2));
70
+ }
71
+ else {
72
+ console.table(destination);
73
+ consola.success('Destination retrieved successfully.');
74
+ }
75
+ }),
76
+ });
@@ -0,0 +1,41 @@
1
+ import appDestinationsService from '../../../services/app-destinations.js';
2
+ import { withAuth } from '../../../utils/auth.js';
3
+ import { isInteractive } from '../../../utils/environment.js';
4
+ import { promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
5
+ import { defineCommand, defineOptions } from '@robingenz/zli';
6
+ import consola from 'consola';
7
+ import { z } from 'zod';
8
+ export default defineCommand({
9
+ description: 'Retrieve a list of existing app destinations.',
10
+ options: defineOptions(z.object({
11
+ appId: z.string().optional().describe('ID of the app.'),
12
+ json: z.boolean().optional().describe('Output in JSON format.'),
13
+ limit: z.coerce.number().optional().describe('Limit for pagination.'),
14
+ offset: z.coerce.number().optional().describe('Offset for pagination.'),
15
+ platform: z.enum(['android', 'ios']).optional().describe('Filter by platform.'),
16
+ })),
17
+ action: withAuth(async (options, args) => {
18
+ let { appId, json, limit, offset, platform } = options;
19
+ if (!appId) {
20
+ if (!isInteractive()) {
21
+ consola.error('You must provide an app ID when running in non-interactive environment.');
22
+ process.exit(1);
23
+ }
24
+ const organizationId = await promptOrganizationSelection();
25
+ appId = await promptAppSelection(organizationId);
26
+ }
27
+ const destinations = await appDestinationsService.findAll({
28
+ appId,
29
+ limit,
30
+ offset,
31
+ platform,
32
+ });
33
+ if (json) {
34
+ console.log(JSON.stringify(destinations, null, 2));
35
+ }
36
+ else {
37
+ console.table(destinations);
38
+ consola.success('Destinations retrieved successfully.');
39
+ }
40
+ }),
41
+ });
@@ -0,0 +1,69 @@
1
+ import appDestinationsService from '../../../services/app-destinations.js';
2
+ import { withAuth } from '../../../utils/auth.js';
3
+ import { isInteractive } from '../../../utils/environment.js';
4
+ import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
5
+ import { defineCommand, defineOptions } from '@robingenz/zli';
6
+ import consola from 'consola';
7
+ import { z } from 'zod';
8
+ export default defineCommand({
9
+ description: 'Update an existing app destination.',
10
+ options: defineOptions(z.object({
11
+ appId: z.string().optional().describe('ID of the app.'),
12
+ destinationId: z.string().optional().describe('ID of the destination.'),
13
+ name: z.string().optional().describe('Name of the destination.'),
14
+ appleId: z.string().optional().describe('Apple ID for the destination.'),
15
+ appleAppId: z.string().optional().describe('Apple App ID for the destination.'),
16
+ appleTeamId: z.string().optional().describe('Apple Team ID for the destination.'),
17
+ appleAppPassword: z.string().optional().describe('Apple app-specific password for the destination.'),
18
+ appleApiKeyId: z.string().optional().describe('Apple API Key ID for the destination.'),
19
+ appleIssuerId: z.string().optional().describe('Apple Issuer ID for the destination.'),
20
+ appAppleApiKeyId: z.string().optional().describe('App Apple API Key ID for the destination.'),
21
+ androidPackageName: z.string().optional().describe('Android package name for the destination.'),
22
+ androidBuildArtifactType: z.enum(['aab', 'apk']).optional().describe('Android build artifact type (aab, apk).'),
23
+ androidReleaseStatus: z
24
+ .enum(['completed', 'draft'])
25
+ .optional()
26
+ .describe('Android release status (completed, draft).'),
27
+ appGoogleServiceAccountKeyId: z
28
+ .string()
29
+ .optional()
30
+ .describe('App Google Service Account Key ID for the destination.'),
31
+ googlePlayTrack: z.string().optional().describe('Google Play track for the destination.'),
32
+ })),
33
+ action: withAuth(async (options, args) => {
34
+ let { appId, destinationId, name, appleId, appleAppId, appleTeamId, appleAppPassword, appleApiKeyId, appleIssuerId, appAppleApiKeyId, androidPackageName, androidBuildArtifactType, androidReleaseStatus, appGoogleServiceAccountKeyId, googlePlayTrack, } = options;
35
+ if (!appId) {
36
+ if (!isInteractive()) {
37
+ consola.error('You must provide an app ID when running in non-interactive environment.');
38
+ process.exit(1);
39
+ }
40
+ const organizationId = await promptOrganizationSelection();
41
+ appId = await promptAppSelection(organizationId);
42
+ }
43
+ if (!destinationId) {
44
+ if (!isInteractive()) {
45
+ consola.error('You must provide the destination ID when running in non-interactive environment.');
46
+ process.exit(1);
47
+ }
48
+ destinationId = await prompt('Enter the destination ID:', { type: 'text' });
49
+ }
50
+ await appDestinationsService.update({
51
+ appId,
52
+ destinationId,
53
+ name,
54
+ appleId,
55
+ appleAppId,
56
+ appleTeamId,
57
+ appleAppPassword,
58
+ appleApiKeyId,
59
+ appleIssuerId,
60
+ appAppleApiKeyId,
61
+ androidPackageName,
62
+ androidBuildArtifactType,
63
+ androidReleaseStatus,
64
+ appGoogleServiceAccountKeyId,
65
+ googlePlayTrack,
66
+ });
67
+ consola.success('Destination updated successfully.');
68
+ }),
69
+ });
@@ -43,6 +43,9 @@ export default defineCommand({
43
43
  // Resolve absolute paths
44
44
  const absolutePublicKeyPath = pathModule.resolve(process.cwd(), publicKeyPath);
45
45
  const absolutePrivateKeyPath = pathModule.resolve(process.cwd(), privateKeyPath);
46
+ // Ensure parent directories exist
47
+ await fs.mkdir(pathModule.dirname(absolutePublicKeyPath), { recursive: true });
48
+ await fs.mkdir(pathModule.dirname(absolutePrivateKeyPath), { recursive: true });
46
49
  // Write the keys to files
47
50
  await fs.writeFile(absolutePublicKeyPath, publicKey, 'utf8');
48
51
  await fs.writeFile(absolutePrivateKeyPath, privateKey, 'utf8');
package/dist/index.js CHANGED
@@ -30,6 +30,11 @@ const config = defineConfig({
30
30
  'apps:bundles:create': await import('./commands/apps/bundles/create.js').then((mod) => mod.default),
31
31
  'apps:bundles:delete': await import('./commands/apps/bundles/delete.js').then((mod) => mod.default),
32
32
  'apps:bundles:update': await import('./commands/apps/bundles/update.js').then((mod) => mod.default),
33
+ 'apps:certificates:create': await import('./commands/apps/certificates/create.js').then((mod) => mod.default),
34
+ 'apps:certificates:delete': await import('./commands/apps/certificates/delete.js').then((mod) => mod.default),
35
+ 'apps:certificates:get': await import('./commands/apps/certificates/get.js').then((mod) => mod.default),
36
+ 'apps:certificates:list': await import('./commands/apps/certificates/list.js').then((mod) => mod.default),
37
+ 'apps:certificates:update': await import('./commands/apps/certificates/update.js').then((mod) => mod.default),
33
38
  'apps:channels:create': await import('./commands/apps/channels/create.js').then((mod) => mod.default),
34
39
  'apps:channels:delete': await import('./commands/apps/channels/delete.js').then((mod) => mod.default),
35
40
  'apps:channels:get': await import('./commands/apps/channels/get.js').then((mod) => mod.default),
@@ -37,17 +42,22 @@ const config = defineConfig({
37
42
  'apps:channels:pause': await import('./commands/apps/channels/pause.js').then((mod) => mod.default),
38
43
  'apps:channels:resume': await import('./commands/apps/channels/resume.js').then((mod) => mod.default),
39
44
  'apps:channels:update': await import('./commands/apps/channels/update.js').then((mod) => mod.default),
40
- 'apps:environments:create': await import('./commands/apps/environments/create.js').then((mod) => mod.default),
41
- 'apps:environments:delete': await import('./commands/apps/environments/delete.js').then((mod) => mod.default),
42
- 'apps:environments:list': await import('./commands/apps/environments/list.js').then((mod) => mod.default),
43
- 'apps:environments:set': await import('./commands/apps/environments/set.js').then((mod) => mod.default),
44
- 'apps:environments:unset': await import('./commands/apps/environments/unset.js').then((mod) => mod.default),
45
45
  'apps:deployments:create': await import('./commands/apps/deployments/create.js').then((mod) => mod.default),
46
46
  'apps:deployments:cancel': await import('./commands/apps/deployments/cancel.js').then((mod) => mod.default),
47
47
  'apps:deployments:logs': await import('./commands/apps/deployments/logs.js').then((mod) => mod.default),
48
+ 'apps:destinations:create': await import('./commands/apps/destinations/create.js').then((mod) => mod.default),
49
+ 'apps:destinations:delete': await import('./commands/apps/destinations/delete.js').then((mod) => mod.default),
50
+ 'apps:destinations:get': await import('./commands/apps/destinations/get.js').then((mod) => mod.default),
51
+ 'apps:destinations:list': await import('./commands/apps/destinations/list.js').then((mod) => mod.default),
52
+ 'apps:destinations:update': await import('./commands/apps/destinations/update.js').then((mod) => mod.default),
48
53
  'apps:devices:delete': await import('./commands/apps/devices/delete.js').then((mod) => mod.default),
49
54
  'apps:devices:forcechannel': await import('./commands/apps/devices/forcechannel.js').then((mod) => mod.default),
50
55
  'apps:devices:unforcechannel': await import('./commands/apps/devices/unforcechannel.js').then((mod) => mod.default),
56
+ 'apps:environments:create': await import('./commands/apps/environments/create.js').then((mod) => mod.default),
57
+ 'apps:environments:delete': await import('./commands/apps/environments/delete.js').then((mod) => mod.default),
58
+ 'apps:environments:list': await import('./commands/apps/environments/list.js').then((mod) => mod.default),
59
+ 'apps:environments:set': await import('./commands/apps/environments/set.js').then((mod) => mod.default),
60
+ 'apps:environments:unset': await import('./commands/apps/environments/unset.js').then((mod) => mod.default),
51
61
  'apps:liveupdates:bundle': await import('./commands/apps/liveupdates/bundle.js').then((mod) => mod.default),
52
62
  'apps:liveupdates:generatesigningkey': await import('./commands/apps/liveupdates/generate-signing-key.js').then((mod) => mod.default),
53
63
  'apps:liveupdates:rollback': await import('./commands/apps/liveupdates/rollback.js').then((mod) => mod.default),
@@ -0,0 +1,22 @@
1
+ import authorizationService from '../services/authorization-service.js';
2
+ import httpClient from '../utils/http-client.js';
3
+ import FormData from 'form-data';
4
+ class AppAppleApiKeysServiceImpl {
5
+ httpClient;
6
+ constructor(httpClient) {
7
+ this.httpClient = httpClient;
8
+ }
9
+ async create(dto) {
10
+ const formData = new FormData();
11
+ formData.append('file', dto.buffer, { filename: dto.fileName });
12
+ const response = await this.httpClient.post(`/v1/apps/${dto.appId}/apple-api-keys`, formData, {
13
+ headers: {
14
+ Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
15
+ ...formData.getHeaders(),
16
+ },
17
+ });
18
+ return response.data;
19
+ }
20
+ }
21
+ const appAppleApiKeysService = new AppAppleApiKeysServiceImpl(httpClient);
22
+ export default appAppleApiKeysService;