@capawesome/cli 4.5.0 → 4.6.0-dev.80c962a.1774597304
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.
- package/CHANGELOG.md +7 -0
- package/dist/commands/apps/builds/create.js +22 -0
- package/dist/commands/apps/certificates/create.js +3 -19
- package/dist/commands/apps/certificates/update.js +3 -1
- package/dist/commands/apps/devices/forcechannel.js +9 -7
- package/dist/commands/apps/devices/probe.js +70 -0
- package/dist/commands/apps/devices/unforcechannel.js +9 -7
- package/dist/commands/apps/liveupdates/bundle.js +6 -1
- package/dist/commands/apps/liveupdates/generate-manifest.js +6 -1
- package/dist/commands/apps/liveupdates/upload.js +8 -1
- package/dist/index.js +1 -0
- package/dist/services/app-certificates.js +0 -1
- package/dist/services/app-devices.js +44 -0
- package/dist/utils/file.js +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [4.6.0](https://github.com/capawesome-team/cli/compare/v4.5.0...v4.6.0) (2026-03-18)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add `apps:devices:probe` command ([#129](https://github.com/capawesome-team/cli/issues/129)) ([33607cd](https://github.com/capawesome-team/cli/commit/33607cdb2e65e26c48d114d694b876db3762b8ec))
|
|
11
|
+
|
|
5
12
|
## [4.5.0](https://github.com/capawesome-team/cli/compare/v4.4.0...v4.5.0) (2026-03-15)
|
|
6
13
|
|
|
7
14
|
|
|
@@ -3,6 +3,7 @@ import appBuildsService from '../../../services/app-builds.js';
|
|
|
3
3
|
import appCertificatesService from '../../../services/app-certificates.js';
|
|
4
4
|
import appEnvironmentsService from '../../../services/app-environments.js';
|
|
5
5
|
import { unescapeAnsi } from '../../../utils/ansi.js';
|
|
6
|
+
import { parseKeyValuePairs } from '../../../utils/app-environments.js';
|
|
6
7
|
import { withAuth } from '../../../utils/auth.js';
|
|
7
8
|
import { isInteractive } from '../../../utils/environment.js';
|
|
8
9
|
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
|
|
@@ -61,6 +62,14 @@ export default defineCommand({
|
|
|
61
62
|
.string()
|
|
62
63
|
.optional()
|
|
63
64
|
.describe('The type of build. For iOS, supported values are `simulator`, `development`, `ad-hoc`, `app-store`, and `enterprise`. For Android, supported values are `debug` and `release`. For Web, no type is required.'),
|
|
65
|
+
variable: z
|
|
66
|
+
.array(z.string())
|
|
67
|
+
.optional()
|
|
68
|
+
.describe('Ad hoc environment variable in key=value format. Can be specified multiple times.'),
|
|
69
|
+
variableFile: z
|
|
70
|
+
.string()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('Path to a file containing ad hoc environment variables in .env format.'),
|
|
64
73
|
zip: z
|
|
65
74
|
.union([z.boolean(), z.string()])
|
|
66
75
|
.optional()
|
|
@@ -197,9 +206,22 @@ export default defineCommand({
|
|
|
197
206
|
}
|
|
198
207
|
}
|
|
199
208
|
}
|
|
209
|
+
// Parse ad hoc environment variables from inline and file
|
|
210
|
+
const variablesMap = new Map();
|
|
211
|
+
if (options.variableFile) {
|
|
212
|
+
const fileContent = await fs.readFile(options.variableFile, 'utf-8');
|
|
213
|
+
const fileVariables = parseKeyValuePairs(fileContent);
|
|
214
|
+
fileVariables.forEach((v) => variablesMap.set(v.key, v.value));
|
|
215
|
+
}
|
|
216
|
+
if (options.variable) {
|
|
217
|
+
const inlineVariables = parseKeyValuePairs(options.variable.join('\n'));
|
|
218
|
+
inlineVariables.forEach((v) => variablesMap.set(v.key, v.value));
|
|
219
|
+
}
|
|
220
|
+
const adHocEnvironmentVariables = variablesMap.size > 0 ? Object.fromEntries(variablesMap) : undefined;
|
|
200
221
|
// Create the app build
|
|
201
222
|
consola.start('Creating build...');
|
|
202
223
|
const response = await appBuildsService.create({
|
|
224
|
+
adHocEnvironmentVariables,
|
|
203
225
|
appCertificateName: certificate,
|
|
204
226
|
appEnvironmentName: environment,
|
|
205
227
|
appId,
|
|
@@ -74,24 +74,9 @@ export default defineCommand({
|
|
|
74
74
|
process.exit(1);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
// 4.
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
consola.error('You must provide the certificate type when running in non-interactive environment.');
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
84
|
-
type = await prompt('Select the certificate type:', {
|
|
85
|
-
type: 'select',
|
|
86
|
-
options: [
|
|
87
|
-
{ label: 'Development', value: 'development' },
|
|
88
|
-
{ label: 'Production', value: 'production' },
|
|
89
|
-
],
|
|
90
|
-
});
|
|
91
|
-
if (!type) {
|
|
92
|
-
consola.error('You must select a certificate type.');
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
77
|
+
// 4. Warn if deprecated --type option is used
|
|
78
|
+
if (type) {
|
|
79
|
+
consola.warn('The --type option is deprecated and will be removed in a future version. The certificate type is now detected automatically.');
|
|
95
80
|
}
|
|
96
81
|
// 5. Enter certificate file path
|
|
97
82
|
if (!file) {
|
|
@@ -167,7 +152,6 @@ export default defineCommand({
|
|
|
167
152
|
fileName,
|
|
168
153
|
name,
|
|
169
154
|
platform: platform,
|
|
170
|
-
type: type,
|
|
171
155
|
password,
|
|
172
156
|
keyAlias,
|
|
173
157
|
keyPassword,
|
|
@@ -36,11 +36,13 @@ export default defineCommand({
|
|
|
36
36
|
}
|
|
37
37
|
certificateId = await prompt('Enter the certificate ID:', { type: 'text' });
|
|
38
38
|
}
|
|
39
|
+
if (type) {
|
|
40
|
+
consola.warn('The --type option is deprecated and will be removed in a future version. The certificate type is now detected automatically.');
|
|
41
|
+
}
|
|
39
42
|
await appCertificatesService.update({
|
|
40
43
|
appId,
|
|
41
44
|
certificateId,
|
|
42
45
|
name,
|
|
43
|
-
type,
|
|
44
46
|
password,
|
|
45
47
|
keyAlias,
|
|
46
48
|
keyPassword,
|
|
@@ -10,11 +10,11 @@ export default defineCommand({
|
|
|
10
10
|
description: 'Force a device to use a specific channel.',
|
|
11
11
|
options: defineOptions(z.object({
|
|
12
12
|
appId: z.string().uuid({ message: 'App ID must be a UUID.' }).optional().describe('ID of the app.'),
|
|
13
|
-
deviceId: z.string().optional().describe('ID of the device.'),
|
|
13
|
+
deviceId: z.array(z.string()).optional().describe('ID of the device. Can be specified multiple times.'),
|
|
14
14
|
channel: z.string().optional().describe('Name of the channel to force.'),
|
|
15
15
|
})),
|
|
16
16
|
action: withAuth(async (options, args) => {
|
|
17
|
-
let { appId, deviceId, channel } = options;
|
|
17
|
+
let { appId, deviceId: deviceIds, channel } = options;
|
|
18
18
|
if (!appId) {
|
|
19
19
|
if (!isInteractive()) {
|
|
20
20
|
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
@@ -23,14 +23,15 @@ export default defineCommand({
|
|
|
23
23
|
const organizationId = await promptOrganizationSelection();
|
|
24
24
|
appId = await promptAppSelection(organizationId);
|
|
25
25
|
}
|
|
26
|
-
if (!
|
|
26
|
+
if (!deviceIds || deviceIds.length === 0) {
|
|
27
27
|
if (!isInteractive()) {
|
|
28
28
|
consola.error('You must provide the device ID when running in non-interactive environment.');
|
|
29
29
|
process.exit(1);
|
|
30
30
|
}
|
|
31
|
-
deviceId = await prompt('Enter the device ID:', {
|
|
31
|
+
const deviceId = await prompt('Enter the device ID:', {
|
|
32
32
|
type: 'text',
|
|
33
33
|
});
|
|
34
|
+
deviceIds = [deviceId];
|
|
34
35
|
}
|
|
35
36
|
if (!channel) {
|
|
36
37
|
if (!isInteractive()) {
|
|
@@ -56,11 +57,12 @@ export default defineCommand({
|
|
|
56
57
|
consola.error('Channel ID not found.');
|
|
57
58
|
process.exit(1);
|
|
58
59
|
}
|
|
59
|
-
await appDevicesService.
|
|
60
|
+
await appDevicesService.updateMany({
|
|
60
61
|
appId,
|
|
61
|
-
|
|
62
|
+
deviceIds,
|
|
62
63
|
forcedAppChannelId: channelId,
|
|
63
64
|
});
|
|
64
|
-
|
|
65
|
+
const deviceCount = deviceIds.length;
|
|
66
|
+
consola.success(`${deviceCount === 1 ? 'Device' : `${deviceCount} devices`} forced to channel successfully.`);
|
|
65
67
|
}),
|
|
66
68
|
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import appDevicesService from '../../../services/app-devices.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 { AxiosError } from 'axios';
|
|
7
|
+
import consola from 'consola';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
export default defineCommand({
|
|
10
|
+
description: 'Check whether a device would receive a live update.',
|
|
11
|
+
options: defineOptions(z.object({
|
|
12
|
+
appId: z.string().optional().describe('ID of the app.'),
|
|
13
|
+
deviceId: z.string().optional().describe('ID of the device.'),
|
|
14
|
+
json: z.boolean().optional().describe('Output in JSON format.'),
|
|
15
|
+
})),
|
|
16
|
+
action: withAuth(async (options) => {
|
|
17
|
+
let { appId, deviceId, json } = options;
|
|
18
|
+
if (!appId) {
|
|
19
|
+
if (!isInteractive()) {
|
|
20
|
+
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const organizationId = await promptOrganizationSelection();
|
|
24
|
+
appId = await promptAppSelection(organizationId);
|
|
25
|
+
}
|
|
26
|
+
if (!deviceId) {
|
|
27
|
+
if (!isInteractive()) {
|
|
28
|
+
consola.error('You must provide the device ID when running in non-interactive environment.');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
deviceId = await prompt('Enter the device ID:', {
|
|
32
|
+
type: 'text',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const device = await appDevicesService.findOneById({ appId, deviceId });
|
|
36
|
+
try {
|
|
37
|
+
const result = await appDevicesService.probe({
|
|
38
|
+
appId,
|
|
39
|
+
appVersionCode: device.appVersionCode,
|
|
40
|
+
appVersionName: device.appVersionName,
|
|
41
|
+
channelName: device.appChannel?.name,
|
|
42
|
+
customId: device.customId ?? undefined,
|
|
43
|
+
deviceId: device.id,
|
|
44
|
+
osVersion: device.osVersion,
|
|
45
|
+
platform: device.platform,
|
|
46
|
+
pluginVersion: device.pluginVersion,
|
|
47
|
+
});
|
|
48
|
+
if (json) {
|
|
49
|
+
console.log(JSON.stringify(result, null, 2));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.table(result);
|
|
53
|
+
consola.success('Update available for this device.');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof AxiosError && error.response?.status === 404) {
|
|
58
|
+
if (json) {
|
|
59
|
+
console.log(JSON.stringify({ bundleId: null }, null, 2));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
consola.info('No update available for this device.');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
@@ -9,10 +9,10 @@ export default defineCommand({
|
|
|
9
9
|
description: 'Remove the forced channel from a device.',
|
|
10
10
|
options: defineOptions(z.object({
|
|
11
11
|
appId: z.string().uuid({ message: 'App ID must be a UUID.' }).optional().describe('ID of the app.'),
|
|
12
|
-
deviceId: z.string().optional().describe('ID of the device.'),
|
|
12
|
+
deviceId: z.array(z.string()).optional().describe('ID of the device. Can be specified multiple times.'),
|
|
13
13
|
})),
|
|
14
14
|
action: withAuth(async (options, args) => {
|
|
15
|
-
let { appId, deviceId } = options;
|
|
15
|
+
let { appId, deviceId: deviceIds } = options;
|
|
16
16
|
if (!appId) {
|
|
17
17
|
if (!isInteractive()) {
|
|
18
18
|
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
@@ -21,20 +21,22 @@ export default defineCommand({
|
|
|
21
21
|
const organizationId = await promptOrganizationSelection();
|
|
22
22
|
appId = await promptAppSelection(organizationId);
|
|
23
23
|
}
|
|
24
|
-
if (!
|
|
24
|
+
if (!deviceIds || deviceIds.length === 0) {
|
|
25
25
|
if (!isInteractive()) {
|
|
26
26
|
consola.error('You must provide the device ID when running in non-interactive environment.');
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
|
-
deviceId = await prompt('Enter the device ID:', {
|
|
29
|
+
const deviceId = await prompt('Enter the device ID:', {
|
|
30
30
|
type: 'text',
|
|
31
31
|
});
|
|
32
|
+
deviceIds = [deviceId];
|
|
32
33
|
}
|
|
33
|
-
await appDevicesService.
|
|
34
|
+
await appDevicesService.updateMany({
|
|
34
35
|
appId,
|
|
35
|
-
|
|
36
|
+
deviceIds,
|
|
36
37
|
forcedAppChannelId: null,
|
|
37
38
|
});
|
|
38
|
-
|
|
39
|
+
const deviceCount = deviceIds.length;
|
|
40
|
+
consola.success(`Forced channel removed from ${deviceCount === 1 ? 'device' : `${deviceCount} devices`} successfully.`);
|
|
39
41
|
}),
|
|
40
42
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isInteractive } from '../../../utils/environment.js';
|
|
2
|
-
import { fileExistsAtPath, isDirectory } from '../../../utils/file.js';
|
|
2
|
+
import { directoryContainsSourceMaps, fileExistsAtPath, isDirectory } from '../../../utils/file.js';
|
|
3
3
|
import { generateManifestJson } from '../../../utils/manifest.js';
|
|
4
4
|
import { prompt } from '../../../utils/prompt.js';
|
|
5
5
|
import zip from '../../../utils/zip.js';
|
|
@@ -62,6 +62,11 @@ export default defineCommand({
|
|
|
62
62
|
consola.error(`Directory must contain an index.html file: ${inputPath}`);
|
|
63
63
|
process.exit(1);
|
|
64
64
|
}
|
|
65
|
+
// Check for source maps
|
|
66
|
+
const containsSourceMaps = await directoryContainsSourceMaps(inputPath);
|
|
67
|
+
if (containsSourceMaps) {
|
|
68
|
+
consola.warn('Source map files were detected in the specified path. Source maps should not be distributed to end users as they expose your original source code and increase the download size. Consider excluding source map files from your build output.');
|
|
69
|
+
}
|
|
65
70
|
// 2. Output path resolution
|
|
66
71
|
if (!outputPath) {
|
|
67
72
|
outputPath = './bundle.zip';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isInteractive } from '../../../utils/environment.js';
|
|
2
|
-
import { fileExistsAtPath } from '../../../utils/file.js';
|
|
2
|
+
import { directoryContainsSourceMaps, fileExistsAtPath } from '../../../utils/file.js';
|
|
3
3
|
import { generateManifestJson } from '../../../utils/manifest.js';
|
|
4
4
|
import { prompt } from '../../../utils/prompt.js';
|
|
5
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
@@ -32,6 +32,11 @@ export default defineCommand({
|
|
|
32
32
|
consola.error(`The path does not exist.`);
|
|
33
33
|
process.exit(1);
|
|
34
34
|
}
|
|
35
|
+
// Check for source maps
|
|
36
|
+
const containsSourceMaps = await directoryContainsSourceMaps(path);
|
|
37
|
+
if (containsSourceMaps) {
|
|
38
|
+
consola.warn('Source map files were detected in the specified path. Source maps should not be distributed to end users as they expose your original source code and increase the download size. Consider excluding source map files from your build output.');
|
|
39
|
+
}
|
|
35
40
|
// Generate the manifest file
|
|
36
41
|
await generateManifestJson(path);
|
|
37
42
|
consola.success('Manifest file generated.');
|
|
@@ -5,7 +5,7 @@ import appsService from '../../../services/apps.js';
|
|
|
5
5
|
import { withAuth } from '../../../utils/auth.js';
|
|
6
6
|
import { createBufferFromPath, createBufferFromReadStream, createBufferFromString, isPrivateKeyContent, } from '../../../utils/buffer.js';
|
|
7
7
|
import { isInteractive } from '../../../utils/environment.js';
|
|
8
|
-
import { fileExistsAtPath, getFilesInDirectoryAndSubdirectories, isDirectory } from '../../../utils/file.js';
|
|
8
|
+
import { directoryContainsSourceMaps, fileExistsAtPath, getFilesInDirectoryAndSubdirectories, isDirectory, } from '../../../utils/file.js';
|
|
9
9
|
import { createHash } from '../../../utils/hash.js';
|
|
10
10
|
import { generateManifestJson } from '../../../utils/manifest.js';
|
|
11
11
|
import { formatPrivateKey } from '../../../utils/private-key.js';
|
|
@@ -156,6 +156,13 @@ export default defineCommand({
|
|
|
156
156
|
consola.error('The path must be either a folder or a zip file.');
|
|
157
157
|
process.exit(1);
|
|
158
158
|
}
|
|
159
|
+
// Check for source maps
|
|
160
|
+
if (pathIsDirectory) {
|
|
161
|
+
const containsSourceMaps = await directoryContainsSourceMaps(path);
|
|
162
|
+
if (containsSourceMaps) {
|
|
163
|
+
consola.warn('Source map files were detected in the specified path. Source maps should not be distributed to end users as they expose your original source code and increase the download size. Consider excluding source map files from your build output.');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
159
166
|
// Check that the path is a directory when creating a bundle with an artifact type of manifest
|
|
160
167
|
if (artifactType === 'manifest') {
|
|
161
168
|
const pathIsDirectory = await isDirectory(path);
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ const config = defineConfig({
|
|
|
52
52
|
'apps:destinations:update': await import('./commands/apps/destinations/update.js').then((mod) => mod.default),
|
|
53
53
|
'apps:devices:delete': await import('./commands/apps/devices/delete.js').then((mod) => mod.default),
|
|
54
54
|
'apps:devices:forcechannel': await import('./commands/apps/devices/forcechannel.js').then((mod) => mod.default),
|
|
55
|
+
'apps:devices:probe': await import('./commands/apps/devices/probe.js').then((mod) => mod.default),
|
|
55
56
|
'apps:devices:unforcechannel': await import('./commands/apps/devices/unforcechannel.js').then((mod) => mod.default),
|
|
56
57
|
'apps:environments:create': await import('./commands/apps/environments/create.js').then((mod) => mod.default),
|
|
57
58
|
'apps:environments:delete': await import('./commands/apps/environments/delete.js').then((mod) => mod.default),
|
|
@@ -11,7 +11,6 @@ class AppCertificatesServiceImpl {
|
|
|
11
11
|
formData.append('file', dto.buffer, { filename: dto.fileName });
|
|
12
12
|
formData.append('name', dto.name);
|
|
13
13
|
formData.append('platform', dto.platform);
|
|
14
|
-
formData.append('type', dto.type);
|
|
15
14
|
if (dto.password) {
|
|
16
15
|
formData.append('password', dto.password);
|
|
17
16
|
}
|
|
@@ -12,6 +12,42 @@ class AppDevicesServiceImpl {
|
|
|
12
12
|
},
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
|
+
async findOneById(data) {
|
|
16
|
+
const response = await this.httpClient.get(`/v1/apps/${data.appId}/devices/${data.deviceId}`, {
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
|
|
19
|
+
},
|
|
20
|
+
params: {
|
|
21
|
+
relations: 'appChannel',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
|
26
|
+
async probe(data) {
|
|
27
|
+
const params = {
|
|
28
|
+
appVersionCode: data.appVersionCode,
|
|
29
|
+
appVersionName: data.appVersionName,
|
|
30
|
+
osVersion: data.osVersion,
|
|
31
|
+
platform: data.platform.toString(),
|
|
32
|
+
pluginVersion: data.pluginVersion,
|
|
33
|
+
};
|
|
34
|
+
if (data.channelName) {
|
|
35
|
+
params.channelName = data.channelName;
|
|
36
|
+
}
|
|
37
|
+
if (data.customId) {
|
|
38
|
+
params.customId = data.customId;
|
|
39
|
+
}
|
|
40
|
+
if (data.deviceId) {
|
|
41
|
+
params.deviceId = data.deviceId;
|
|
42
|
+
}
|
|
43
|
+
const response = await this.httpClient.get(`/v1/apps/${data.appId}/bundles/latest`, {
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
|
|
46
|
+
},
|
|
47
|
+
params,
|
|
48
|
+
});
|
|
49
|
+
return response.data;
|
|
50
|
+
}
|
|
15
51
|
async update(data) {
|
|
16
52
|
await this.httpClient.patch(`/v1/apps/${data.appId}/devices/${data.deviceId}`, { forcedAppChannelId: data.forcedAppChannelId }, {
|
|
17
53
|
headers: {
|
|
@@ -19,6 +55,14 @@ class AppDevicesServiceImpl {
|
|
|
19
55
|
},
|
|
20
56
|
});
|
|
21
57
|
}
|
|
58
|
+
async updateMany(data) {
|
|
59
|
+
const ids = data.deviceIds.join(',');
|
|
60
|
+
await this.httpClient.patch(`/v1/apps/${data.appId}/devices?ids=${ids}`, { forcedAppChannelId: data.forcedAppChannelId }, {
|
|
61
|
+
headers: {
|
|
62
|
+
Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
22
66
|
}
|
|
23
67
|
const appDevicesService = new AppDevicesServiceImpl(httpClient);
|
|
24
68
|
export default appDevicesService;
|
package/dist/utils/file.js
CHANGED
|
@@ -35,6 +35,10 @@ export const getFilesInDirectoryAndSubdirectories = async (path) => {
|
|
|
35
35
|
await walk(path);
|
|
36
36
|
return files;
|
|
37
37
|
};
|
|
38
|
+
export const directoryContainsSourceMaps = async (path) => {
|
|
39
|
+
const files = await getFilesInDirectoryAndSubdirectories(path);
|
|
40
|
+
return files.some((file) => file.name.endsWith('.js.map') || file.name.endsWith('.css.map'));
|
|
41
|
+
};
|
|
38
42
|
export const fileExistsAtPath = async (path) => {
|
|
39
43
|
return new Promise((resolve) => {
|
|
40
44
|
fs.access(path, fs.constants.F_OK, (err) => {
|