@capawesome/cli 1.3.2 → 1.4.1

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,25 @@
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.4.1](https://github.com/capawesome-team/cli/compare/v1.4.0...v1.4.1) (2025-02-16)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **bundles:** add retry mechanism for file upload on failure ([86a62da](https://github.com/capawesome-team/cli/commit/86a62daa2ae50d691791714ef6a5812a6e87dc4b))
11
+
12
+ ## [1.4.0](https://github.com/capawesome-team/cli/compare/v1.3.2...v1.4.0) (2025-01-29)
13
+
14
+
15
+ ### Features
16
+
17
+ * **bundles:** support custom properties ([#31](https://github.com/capawesome-team/cli/issues/31)) ([405634b](https://github.com/capawesome-team/cli/commit/405634b8a46a77a72ea9812fb350f54ca79a8387))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * convert command arguments to string if not undefined ([b147e21](https://github.com/capawesome-team/cli/commit/b147e214b4ee0da3babc82773b1426162f753c36)), closes [#33](https://github.com/capawesome-team/cli/issues/33)
23
+
5
24
  ## [1.3.2](https://github.com/capawesome-team/cli/compare/v1.3.1...v1.3.2) (2024-12-30)
6
25
 
7
26
 
package/README.md CHANGED
@@ -10,6 +10,16 @@ The Capawesome Cloud CLI can be installed globally via npm:
10
10
  npm install -g @capawesome/cli
11
11
  ```
12
12
 
13
+ ## Usage
14
+
15
+ The Capawesome Cloud CLI can be invoked with the `capawesome` command.
16
+
17
+ ```bash
18
+ npx capawesome <command> [options]
19
+ ```
20
+
21
+ You can find a list of available commands in the [Command Reference](https://capawesome.io/cloud/cli/).
22
+
13
23
  ## Help
14
24
 
15
25
  The Capawesome Cloud CLI ships with command documentation that is accessible with the `--help` flag.
@@ -18,10 +28,35 @@ The Capawesome Cloud CLI ships with command documentation that is accessible wit
18
28
  npx capawesome --help
19
29
  ```
20
30
 
31
+ ## Development
32
+
33
+ Run the following commands to get started with development:
34
+
35
+ 1. Clone the repository:
36
+
37
+ ```bash
38
+ git clone https://github.com/capawesome-team/cli.git
39
+ ```
40
+
41
+ 2. Install dependencies:
42
+
43
+ ```bash
44
+ npm install
45
+ ```
46
+
47
+ 3. Copy the `.capawesomerc.example` file to `.capawesomerc`
48
+ 4. Run your first command:
49
+
50
+ ```bash
51
+ npm start -- --help
52
+ ```
53
+
54
+ **Note:** The `--` is required to pass arguments to the script.
55
+
21
56
  ## Changelog
22
57
 
23
58
  See [CHANGELOG](./CHANGELOG.md).
24
59
 
25
60
  ## License
26
61
 
27
- See [LICENSE](./LICENSE.md).
62
+ See [LICENSE](./LICENSE.md).
@@ -52,6 +52,10 @@ exports.default = (0, citty_1.defineCommand)({
52
52
  type: 'string',
53
53
  description: 'Channel to associate the bundle with.',
54
54
  },
55
+ customProperty: {
56
+ type: 'string',
57
+ description: 'A custom property to assign to the bundle. Must be in the format `key=value`. Can be specified multiple times.',
58
+ },
55
59
  expiresInDays: {
56
60
  type: 'string',
57
61
  description: 'The number of days until the bundle is automatically deleted.',
@@ -86,19 +90,20 @@ exports.default = (0, citty_1.defineCommand)({
86
90
  consola_1.default.error('You must be logged in to run this command.');
87
91
  process.exit(1);
88
92
  }
89
- let androidMax = ctx.args.androidMax;
90
- let androidMin = ctx.args.androidMin;
93
+ let androidMax = ctx.args.androidMax === undefined ? undefined : ctx.args.androidMax + ''; // Convert to string
94
+ let androidMin = ctx.args.androidMin === undefined ? undefined : ctx.args.androidMin + ''; // Convert to string
91
95
  let appId = ctx.args.appId;
92
96
  let artifactType = ctx.args.artifactType === 'manifest' || ctx.args.artifactType === 'zip'
93
97
  ? ctx.args.artifactType
94
98
  : 'zip';
95
99
  let channelName = ctx.args.channel;
96
- let expiresInDays = ctx.args.expiresInDays;
97
- let iosMax = ctx.args.iosMax;
98
- let iosMin = ctx.args.iosMin;
100
+ let customProperty = ctx.args.customProperty;
101
+ let expiresInDays = ctx.args.expiresInDays === undefined ? undefined : ctx.args.expiresInDays + ''; // Convert to string
102
+ let iosMax = ctx.args.iosMax === undefined ? undefined : ctx.args.iosMax + ''; // Convert to string
103
+ let iosMin = ctx.args.iosMin === undefined ? undefined : ctx.args.iosMin + ''; // Convert to string
99
104
  let path = ctx.args.path;
100
105
  let privateKey = ctx.args.privateKey;
101
- let rolloutAsString = ctx.args.rollout;
106
+ let rolloutAsString = ctx.args.rollout === undefined ? undefined : ctx.args.rollout + ''; // Convert to string
102
107
  let url = ctx.args.url;
103
108
  // Validate the expiration days
104
109
  let expiresAt;
@@ -200,6 +205,7 @@ exports.default = (0, citty_1.defineCommand)({
200
205
  appId,
201
206
  artifactType,
202
207
  channelName,
208
+ customProperties: parseCustomProperties(customProperty),
203
209
  expiresAt: expiresAt,
204
210
  url,
205
211
  maxAndroidAppVersionCode: androidMax,
@@ -239,23 +245,31 @@ exports.default = (0, citty_1.defineCommand)({
239
245
  }),
240
246
  });
241
247
  const uploadFile = (options) => __awaiter(void 0, void 0, void 0, function* () {
242
- // Generate checksum
243
- const hash = yield (0, hash_1.createHash)(options.fileBuffer);
244
- // Sign the bundle
245
- let signature;
246
- if (options.privateKeyBuffer) {
247
- signature = yield (0, signature_1.createSignature)(options.privateKeyBuffer, options.fileBuffer);
248
+ try {
249
+ // Generate checksum
250
+ const hash = yield (0, hash_1.createHash)(options.fileBuffer);
251
+ // Sign the bundle
252
+ let signature;
253
+ if (options.privateKeyBuffer) {
254
+ signature = yield (0, signature_1.createSignature)(options.privateKeyBuffer, options.fileBuffer);
255
+ }
256
+ // Create the multipart upload
257
+ return yield app_bundle_files_1.default.create({
258
+ appId: options.appId,
259
+ appBundleId: options.appBundleId,
260
+ checksum: hash,
261
+ fileBuffer: options.fileBuffer,
262
+ fileName: options.fileName,
263
+ href: options.href,
264
+ signature,
265
+ });
266
+ }
267
+ catch (error) {
268
+ if (options.retryOnFailure) {
269
+ return uploadFile(Object.assign(Object.assign({}, options), { retryOnFailure: false }));
270
+ }
271
+ throw error;
248
272
  }
249
- // Create the multipart upload
250
- return app_bundle_files_1.default.create({
251
- appId: options.appId,
252
- appBundleId: options.appBundleId,
253
- checksum: hash,
254
- fileBuffer: options.fileBuffer,
255
- fileName: options.fileName,
256
- href: options.href,
257
- signature,
258
- });
259
273
  });
260
274
  const uploadFiles = (options) => __awaiter(void 0, void 0, void 0, function* () {
261
275
  // Generate the manifest file
@@ -282,6 +296,7 @@ const uploadFiles = (options) => __awaiter(void 0, void 0, void 0, function* ()
282
296
  fileName,
283
297
  href,
284
298
  privateKeyBuffer: options.privateKeyBuffer,
299
+ retryOnFailure: true,
285
300
  });
286
301
  yield uploadNextFile();
287
302
  });
@@ -315,3 +330,24 @@ const uploadZip = (options) => __awaiter(void 0, void 0, void 0, function* () {
315
330
  appBundleFileId: result.id,
316
331
  };
317
332
  });
333
+ const parseCustomProperties = (customProperty) => {
334
+ let customProperties;
335
+ if (customProperty) {
336
+ customProperties = {};
337
+ if (Array.isArray(customProperty)) {
338
+ for (const property of customProperty) {
339
+ const [key, value] = property.split('=');
340
+ if (key && value) {
341
+ customProperties[key] = value;
342
+ }
343
+ }
344
+ }
345
+ else {
346
+ const [key, value] = customProperty.split('=');
347
+ if (key && value) {
348
+ customProperties[key] = value;
349
+ }
350
+ }
351
+ }
352
+ return customProperties;
353
+ };
@@ -12,7 +12,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const form_data_1 = __importDefault(require("form-data"));
16
15
  const http_client_1 = __importDefault(require("../utils/http-client"));
17
16
  const authorization_service_1 = __importDefault(require("./authorization-service"));
18
17
  class AppBundlesServiceImpl {
@@ -21,34 +20,10 @@ class AppBundlesServiceImpl {
21
20
  }
22
21
  create(dto) {
23
22
  return __awaiter(this, void 0, void 0, function* () {
24
- const formData = new form_data_1.default();
25
- formData.append('artifactType', dto.artifactType);
26
- if (dto.channelName) {
27
- formData.append('channelName', dto.channelName);
28
- }
29
- if (dto.expiresAt) {
30
- formData.append('expiresAt', dto.expiresAt);
31
- }
32
- if (dto.url) {
33
- formData.append('url', dto.url);
34
- }
35
- if (dto.maxAndroidAppVersionCode) {
36
- formData.append('maxAndroidAppVersionCode', dto.maxAndroidAppVersionCode);
37
- }
38
- if (dto.maxIosAppVersionCode) {
39
- formData.append('maxIosAppVersionCode', dto.maxIosAppVersionCode);
40
- }
41
- if (dto.minAndroidAppVersionCode) {
42
- formData.append('minAndroidAppVersionCode', dto.minAndroidAppVersionCode);
43
- }
44
- if (dto.minIosAppVersionCode) {
45
- formData.append('minIosAppVersionCode', dto.minIosAppVersionCode);
46
- }
47
- if (dto.rolloutPercentage) {
48
- formData.append('rolloutPercentage', dto.rolloutPercentage.toString());
49
- }
50
- const response = yield this.httpClient.post(`/apps/${dto.appId}/bundles`, formData, {
51
- headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, formData.getHeaders()),
23
+ const response = yield this.httpClient.post(`/apps/${dto.appId}/bundles`, dto, {
24
+ headers: {
25
+ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
26
+ },
52
27
  });
53
28
  return response.data;
54
29
  });
@@ -53,7 +53,7 @@ class UpdateServiceImpl {
53
53
  }
54
54
  }
55
55
  catch (error) {
56
- consola_1.default.error('Failed to check for updates.');
56
+ consola_1.default.warn('Failed to check for updates.');
57
57
  }
58
58
  });
59
59
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capawesome/cli",
3
- "version": "1.3.2",
3
+ "version": "1.4.1",
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",