@capawesome/cli 1.8.1 → 1.10.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
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
+ ## [1.10.0](https://github.com/capawesome-team/cli/compare/v1.9.0...v1.10.0) (2025-05-02)
6
+
7
+
8
+ ### Features
9
+
10
+ * **apps:channels:** add update channel command ([8e93c85](https://github.com/capawesome-team/cli/commit/8e93c851e8b868cb608432dd76c52f149838e6b7))
11
+
12
+ ## [1.9.0](https://github.com/capawesome-team/cli/compare/v1.8.1...v1.9.0) (2025-04-17)
13
+
14
+
15
+ ### Features
16
+
17
+ * add `--ignore-errors` option to `apps:channels:create` command ([#48](https://github.com/capawesome-team/cli/issues/48)) ([3bfb65e](https://github.com/capawesome-team/cli/commit/3bfb65e3c6f9915a6a67b31525b1737497408d59))
18
+ * add `--name` option to `apps:channels:create` ([#46](https://github.com/capawesome-team/cli/issues/46)) ([d6190b7](https://github.com/capawesome-team/cli/commit/d6190b7c9617a0d197d062aa21d01fe26d6e172f))
19
+ * add support for `CAPAWESOME_CLOUD_TOKEN` env variable ([5a8de4c](https://github.com/capawesome-team/cli/commit/5a8de4c9230112e71f74ee72888a86de18d67be7)), closes [#28](https://github.com/capawesome-team/cli/issues/28)
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * `apps:bundles:create` command should always ask for a channel ([#47](https://github.com/capawesome-team/cli/issues/47)) ([fcd97a3](https://github.com/capawesome-team/cli/commit/fcd97a38a64599a8013da94e2f4ef3cdf2b641e5))
25
+ * **apps:channels:delete:** skip prompt in CI environment ([c455e15](https://github.com/capawesome-team/cli/commit/c455e15b711706a9422fc18fbec142f5fe86776d))
26
+
5
27
  ## [1.8.1](https://github.com/capawesome-team/cli/compare/v1.8.0...v1.8.1) (2025-04-07)
6
28
 
7
29
 
@@ -183,7 +183,6 @@ exports.default = (0, citty_1.defineCommand)({
183
183
  consola_1.default.error('It is not yet possible to provide a URL when creating a bundle with an artifact type of `manifest`.');
184
184
  process.exit(1);
185
185
  }
186
- // Let the user select an app and channel if not provided
187
186
  if (!appId) {
188
187
  const apps = yield apps_1.default.findAll();
189
188
  if (apps.length === 0) {
@@ -199,19 +198,19 @@ exports.default = (0, citty_1.defineCommand)({
199
198
  consola_1.default.error('You must select an app to deploy to.');
200
199
  process.exit(1);
201
200
  }
202
- if (!channelName) {
203
- const promptChannel = yield (0, prompt_1.prompt)('Do you want to deploy to a specific channel?', {
204
- type: 'select',
205
- options: ['Yes', 'No'],
201
+ }
202
+ if (!channelName) {
203
+ const promptChannel = yield (0, prompt_1.prompt)('Do you want to deploy to a specific channel?', {
204
+ type: 'select',
205
+ options: ['Yes', 'No'],
206
+ });
207
+ if (promptChannel === 'Yes') {
208
+ channelName = yield (0, prompt_1.prompt)('Enter the channel name:', {
209
+ type: 'text',
206
210
  });
207
- if (promptChannel === 'Yes') {
208
- channelName = yield (0, prompt_1.prompt)('Enter the channel name:', {
209
- type: 'text',
210
- });
211
- if (!channelName) {
212
- consola_1.default.error('The channel name must be at least one character long.');
213
- process.exit(1);
214
- }
211
+ if (!channelName) {
212
+ consola_1.default.error('The channel name must be at least one character long.');
213
+ process.exit(1);
215
214
  }
216
215
  }
217
216
  }
@@ -31,6 +31,10 @@ exports.default = (0, citty_1.defineCommand)({
31
31
  type: 'string',
32
32
  description: 'Maximum number of bundles that can be assigned to the channel. If more bundles are assigned, the oldest bundles will be automatically deleted.',
33
33
  },
34
+ ignoreErrors: {
35
+ type: 'boolean',
36
+ description: 'Whether to ignore errors or not.',
37
+ },
34
38
  name: {
35
39
  type: 'string',
36
40
  description: 'Name of the channel.',
@@ -39,7 +43,12 @@ exports.default = (0, citty_1.defineCommand)({
39
43
  run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
40
44
  let appId = ctx.args.appId;
41
45
  let bundleLimitAsString = ctx.args.bundleLimit;
46
+ let ignoreErrors = ctx.args.ignoreErrors;
42
47
  let name = ctx.args.name;
48
+ // Convert ignoreErrors to boolean
49
+ if (typeof ignoreErrors === 'string') {
50
+ ignoreErrors = ignoreErrors.toLowerCase() === 'true';
51
+ }
43
52
  // Validate the app ID
44
53
  if (!appId) {
45
54
  const apps = yield apps_1.default.findAll();
@@ -78,7 +87,7 @@ exports.default = (0, citty_1.defineCommand)({
78
87
  catch (error) {
79
88
  const message = (0, error_1.getMessageFromUnknownError)(error);
80
89
  consola_1.default.error(message);
81
- process.exit(1);
90
+ process.exit(ignoreErrors ? 0 : 1);
82
91
  }
83
92
  }),
84
93
  });
@@ -16,6 +16,7 @@ const citty_1 = require("citty");
16
16
  const consola_1 = __importDefault(require("consola"));
17
17
  const app_channels_1 = __importDefault(require("../../../services/app-channels"));
18
18
  const apps_1 = __importDefault(require("../../../services/apps"));
19
+ const ci_1 = require("../../../utils/ci");
19
20
  const error_1 = require("../../../utils/error");
20
21
  const prompt_1 = require("../../../utils/prompt");
21
22
  exports.default = (0, citty_1.defineCommand)({
@@ -29,11 +30,17 @@ exports.default = (0, citty_1.defineCommand)({
29
30
  },
30
31
  channelId: {
31
32
  type: 'string',
32
- description: 'ID of the channel.',
33
+ description: 'ID of the channel. Either the ID or name of the channel must be provided.',
34
+ },
35
+ name: {
36
+ type: 'string',
37
+ description: 'Name of the channel. Either the ID or name of the channel must be provided.',
33
38
  },
34
39
  },
35
40
  run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
36
41
  let appId = ctx.args.appId;
42
+ let channelId = ctx.args.channelId;
43
+ let channelName = ctx.args.name;
37
44
  if (!appId) {
38
45
  const apps = yield apps_1.default.findAll();
39
46
  if (!apps.length) {
@@ -46,26 +53,24 @@ exports.default = (0, citty_1.defineCommand)({
46
53
  options: apps.map((app) => ({ label: app.name, value: app.id })),
47
54
  });
48
55
  }
49
- let channel = ctx.args.channel;
50
- if (!channel) {
51
- channel = yield (0, prompt_1.prompt)('Enter the channel name:', {
56
+ if (!channelId && !channelName) {
57
+ channelName = yield (0, prompt_1.prompt)('Enter the channel name:', {
52
58
  type: 'text',
53
59
  });
54
60
  }
55
- if (typeof channel !== 'string') {
56
- consola_1.default.error('Channel name must be a string.');
57
- process.exit(1);
58
- }
59
- const confirmed = yield (0, prompt_1.prompt)('Are you sure you want to delete this channel?', {
60
- type: 'confirm',
61
- });
62
- if (!confirmed) {
63
- return;
61
+ if (!(0, ci_1.isRunningInCi)()) {
62
+ const confirmed = yield (0, prompt_1.prompt)('Are you sure you want to delete this channel?', {
63
+ type: 'confirm',
64
+ });
65
+ if (!confirmed) {
66
+ return;
67
+ }
64
68
  }
65
69
  try {
66
70
  yield app_channels_1.default.delete({
67
71
  appId,
68
- name: channel,
72
+ id: channelId,
73
+ name: channelName,
69
74
  });
70
75
  consola_1.default.success('Channel deleted successfully.');
71
76
  }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const citty_1 = require("citty");
16
+ const consola_1 = __importDefault(require("consola"));
17
+ const app_channels_1 = __importDefault(require("../../../services/app-channels"));
18
+ const apps_1 = __importDefault(require("../../../services/apps"));
19
+ const authorization_service_1 = __importDefault(require("../../../services/authorization-service"));
20
+ const error_1 = require("../../../utils/error");
21
+ const prompt_1 = require("../../../utils/prompt");
22
+ exports.default = (0, citty_1.defineCommand)({
23
+ meta: {
24
+ description: 'Update an existing app channel.',
25
+ },
26
+ args: {
27
+ appId: {
28
+ type: 'string',
29
+ description: 'ID of the app.',
30
+ },
31
+ channelId: {
32
+ type: 'string',
33
+ description: 'ID of the channel.',
34
+ },
35
+ bundleLimit: {
36
+ type: 'string',
37
+ description: 'Maximum number of bundles that can be assigned to the channel. If more bundles are assigned, the oldest bundles will be automatically deleted.',
38
+ },
39
+ name: {
40
+ type: 'string',
41
+ description: 'Name of the channel.',
42
+ },
43
+ },
44
+ run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
45
+ if (!authorization_service_1.default.hasAuthorizationToken()) {
46
+ consola_1.default.error('You must be logged in to run this command.');
47
+ process.exit(1);
48
+ }
49
+ let appId = ctx.args.appId;
50
+ let bundleLimitAsString = ctx.args.bundleLimit;
51
+ let channelId = ctx.args.channelId;
52
+ let name = ctx.args.name;
53
+ // Validate the bundle limit
54
+ let bundleLimit;
55
+ if (bundleLimitAsString) {
56
+ bundleLimit = parseInt(bundleLimitAsString, 10);
57
+ if (isNaN(bundleLimit)) {
58
+ consola_1.default.error('The bundle limit must be a number.');
59
+ process.exit(1);
60
+ }
61
+ }
62
+ if (!appId) {
63
+ const apps = yield apps_1.default.findAll();
64
+ if (!apps.length) {
65
+ consola_1.default.error('You must create an app before updating a channel.');
66
+ process.exit(1);
67
+ }
68
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
69
+ appId = yield (0, prompt_1.prompt)('Which app do you want to update the channel for?', {
70
+ type: 'select',
71
+ options: apps.map((app) => ({ label: app.name, value: app.id })),
72
+ });
73
+ }
74
+ if (!channelId) {
75
+ channelId = yield (0, prompt_1.prompt)('Enter the channel ID:', {
76
+ type: 'text',
77
+ });
78
+ }
79
+ // Update channel
80
+ try {
81
+ yield app_channels_1.default.update({
82
+ appId,
83
+ appChannelId: channelId,
84
+ name,
85
+ totalAppBundleLimit: bundleLimit,
86
+ });
87
+ consola_1.default.success('Channel updated successfully.');
88
+ }
89
+ catch (error) {
90
+ const message = (0, error_1.getMessageFromUnknownError)(error);
91
+ consola_1.default.error(message);
92
+ process.exit(1);
93
+ }
94
+ }),
95
+ });
@@ -22,16 +22,11 @@ exports.default = (0, citty_1.defineCommand)({
22
22
  description: 'Show current user',
23
23
  },
24
24
  run: () => __awaiter(void 0, void 0, void 0, function* () {
25
- var _a, _b;
26
25
  const { token } = userConfig_1.default.read();
27
26
  if (token) {
28
27
  try {
29
28
  const user = yield users_1.default.me();
30
- const email = user.email;
31
- const userProviderProfile = user.userProviderProfiles[0]
32
- ? ((_a = user.userProviderProfiles[0]) === null || _a === void 0 ? void 0 : _a.provider) + ':' + ((_b = user.userProviderProfiles[0]) === null || _b === void 0 ? void 0 : _b.providerUsername)
33
- : null;
34
- consola_1.default.info(`Logged in as ${email || userProviderProfile || '?'}.`);
29
+ consola_1.default.info(`Logged in as ${user.email}.`);
35
30
  }
36
31
  catch (error) {
37
32
  consola_1.default.error('Token is invalid. Please sign in again.');
package/dist/index.js CHANGED
@@ -67,6 +67,7 @@ const main = (0, citty_1.defineCommand)({
67
67
  'apps:bundles:update': Promise.resolve().then(() => __importStar(require('./commands/apps/bundles/update'))).then((mod) => mod.default),
68
68
  'apps:channels:create': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/create'))).then((mod) => mod.default),
69
69
  'apps:channels:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/delete'))).then((mod) => mod.default),
70
+ 'apps:channels:update': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/update'))).then((mod) => mod.default),
70
71
  'apps:devices:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/devices/delete'))).then((mod) => mod.default),
71
72
  'manifests:generate': Promise.resolve().then(() => __importStar(require('./commands/manifests/generate'))).then((mod) => mod.default),
72
73
  },
@@ -30,14 +30,33 @@ class AppChannelsServiceImpl {
30
30
  }
31
31
  delete(data) {
32
32
  return __awaiter(this, void 0, void 0, function* () {
33
- yield this.httpClient.delete(`/v1/apps/${data.appId}/channels`, {
33
+ if (data.id) {
34
+ yield this.httpClient.delete(`/v1/apps/${data.appId}/channels/${data.id}`, {
35
+ headers: {
36
+ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
37
+ },
38
+ });
39
+ }
40
+ else if (data.name) {
41
+ yield this.httpClient.delete(`/v1/apps/${data.appId}/channels`, {
42
+ headers: {
43
+ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
44
+ },
45
+ params: {
46
+ name: data.name,
47
+ },
48
+ });
49
+ }
50
+ });
51
+ }
52
+ update(dto) {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ const response = yield this.httpClient.patch(`/v1/apps/${dto.appId}/channels/${dto.appChannelId}`, dto, {
34
55
  headers: {
35
56
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
36
57
  },
37
- params: {
38
- name: data.name,
39
- },
40
58
  });
59
+ return response.data;
41
60
  });
42
61
  }
43
62
  }
@@ -9,7 +9,7 @@ class AuthorizationServiceImpl {
9
9
  this.userConfig = userConfig;
10
10
  }
11
11
  getCurrentAuthorizationToken() {
12
- return this.userConfig.read().token || process.env.CAPAWESOME_TOKEN || null;
12
+ return this.userConfig.read().token || process.env.CAPAWESOME_CLOUD_TOKEN || process.env.CAPAWESOME_TOKEN || null;
13
13
  }
14
14
  hasAuthorizationToken() {
15
15
  return !!this.getCurrentAuthorizationToken();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capawesome/cli",
3
- "version": "1.8.1",
3
+ "version": "1.10.0",
4
4
  "description": "The Capawesome Cloud Command Line Interface (CLI) to manage Live Updates and more.",
5
5
  "scripts": {
6
6
  "build": "patch-package && rimraf ./dist && tsc",