@capawesome/cli 0.0.14 → 0.0.15

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,18 @@
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
+ ## [0.0.15](https://github.com/capawesome-team/cli/compare/v0.0.14...v0.0.15) (2024-10-20)
6
+
7
+
8
+ ### Features
9
+
10
+ * **bundles:** support artifact type `manifest` ([#14](https://github.com/capawesome-team/cli/issues/14)) ([5e92c5e](https://github.com/capawesome-team/cli/commit/5e92c5e74574748c1c9ceaab3bf7ae94430dfb71))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * error message on sign-in if client is offline ([#13](https://github.com/capawesome-team/cli/issues/13)) ([56404f6](https://github.com/capawesome-team/cli/commit/56404f6e779dc851fa1bd7914921fa9744e9eeeb))
16
+
5
17
  ## [0.0.14](https://github.com/capawesome-team/cli/compare/v0.0.13...v0.0.14) (2024-09-30)
6
18
 
7
19
 
@@ -14,18 +14,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const citty_1 = require("citty");
16
16
  const consola_1 = __importDefault(require("consola"));
17
- const prompt_1 = require("../../../utils/prompt");
18
- const zip_1 = __importDefault(require("../../../utils/zip"));
19
17
  const form_data_1 = __importDefault(require("form-data"));
20
- const node_fs_1 = require("node:fs");
21
- const authorization_service_1 = __importDefault(require("../../../services/authorization-service"));
22
- const apps_1 = __importDefault(require("../../../services/apps"));
18
+ const fs_1 = require("fs");
19
+ const app_bundle_files_1 = __importDefault(require("../../../services/app-bundle-files"));
23
20
  const app_bundles_1 = __importDefault(require("../../../services/app-bundles"));
21
+ const apps_1 = __importDefault(require("../../../services/apps"));
22
+ const authorization_service_1 = __importDefault(require("../../../services/authorization-service"));
23
+ const buffer_1 = require("../../../utils/buffer");
24
24
  const error_1 = require("../../../utils/error");
25
+ const file_1 = require("../../../utils/file");
25
26
  const hash_1 = require("../../../utils/hash");
26
- const buffer_1 = require("../../../utils/buffer");
27
+ const manifest_1 = require("../../../utils/manifest");
28
+ const prompt_1 = require("../../../utils/prompt");
27
29
  const signature_1 = require("../../../utils/signature");
28
- const file_1 = require("../../../utils/file");
30
+ const zip_1 = __importDefault(require("../../../utils/zip"));
29
31
  exports.default = (0, citty_1.defineCommand)({
30
32
  meta: {
31
33
  description: 'Create a new app bundle.',
@@ -43,6 +45,10 @@ exports.default = (0, citty_1.defineCommand)({
43
45
  type: 'string',
44
46
  description: 'App ID to deploy to.',
45
47
  },
48
+ artifactType: {
49
+ type: 'string',
50
+ description: 'The type of artifact to deploy. Must be either `manifest` or `zip`. The default is `zip`.',
51
+ },
46
52
  channel: {
47
53
  type: 'string',
48
54
  description: 'Channel to associate the bundle with.',
@@ -77,10 +83,18 @@ exports.default = (0, citty_1.defineCommand)({
77
83
  consola_1.default.error('You must be logged in to run this command.');
78
84
  return;
79
85
  }
80
- const { androidMax, androidMin, privateKey, rollout, iosMax, iosMin } = ctx.args;
86
+ let androidMax = ctx.args.androidMax;
87
+ let androidMin = ctx.args.androidMin;
81
88
  let appId = ctx.args.appId;
89
+ let artifactType = ctx.args.artifactType === 'manifest' || ctx.args.artifactType === 'zip'
90
+ ? ctx.args.artifactType
91
+ : 'zip';
82
92
  let channelName = ctx.args.channel;
93
+ let iosMax = ctx.args.iosMax;
94
+ let iosMin = ctx.args.iosMin;
83
95
  let path = ctx.args.path;
96
+ let privateKey = ctx.args.privateKey;
97
+ let rollout = ctx.args.rollout;
84
98
  let url = ctx.args.url;
85
99
  if (!path && !url) {
86
100
  path = yield (0, prompt_1.prompt)('Enter the path to the app bundle:', {
@@ -91,6 +105,19 @@ exports.default = (0, citty_1.defineCommand)({
91
105
  return;
92
106
  }
93
107
  }
108
+ if (artifactType === 'manifest' && path) {
109
+ const pathIsDirectory = (0, file_1.isDirectory)(path);
110
+ if (!pathIsDirectory) {
111
+ consola_1.default.error('The path must be a folder when creating a bundle with an artifact type of `manifest`.');
112
+ return;
113
+ }
114
+ }
115
+ // Check if the path exists
116
+ const pathExists = yield (0, file_1.fileExistsAtPath)(path);
117
+ if (!pathExists) {
118
+ consola_1.default.error(`The path does not exist.`);
119
+ return;
120
+ }
94
121
  if (!appId) {
95
122
  const apps = yield apps_1.default.findAll();
96
123
  if (apps.length === 0) {
@@ -102,6 +129,10 @@ exports.default = (0, citty_1.defineCommand)({
102
129
  type: 'select',
103
130
  options: apps.map((app) => ({ label: app.name, value: app.id })),
104
131
  });
132
+ if (!appId) {
133
+ consola_1.default.error('You must select an app to deploy to.');
134
+ return;
135
+ }
105
136
  if (!channelName) {
106
137
  const promptChannel = yield (0, prompt_1.prompt)('Do you want to deploy to a specific channel?', {
107
138
  type: 'select',
@@ -111,6 +142,10 @@ exports.default = (0, citty_1.defineCommand)({
111
142
  channelName = yield (0, prompt_1.prompt)('Enter the channel name:', {
112
143
  type: 'text',
113
144
  });
145
+ if (!channelName) {
146
+ consola_1.default.error('The channel name must be at least one character long.');
147
+ return;
148
+ }
114
149
  }
115
150
  }
116
151
  }
@@ -133,26 +168,7 @@ exports.default = (0, citty_1.defineCommand)({
133
168
  }
134
169
  // Create form data
135
170
  const formData = new form_data_1.default();
136
- if (path) {
137
- let fileBuffer;
138
- if (zip_1.default.isZipped(path)) {
139
- const readStream = (0, node_fs_1.createReadStream)(path);
140
- fileBuffer = yield (0, buffer_1.createBuffer)(readStream);
141
- }
142
- else {
143
- consola_1.default.start('Zipping folder...');
144
- fileBuffer = yield zip_1.default.zipFolder(path);
145
- }
146
- consola_1.default.start('Generating checksum...');
147
- const hash = yield (0, hash_1.createHash)(fileBuffer);
148
- formData.append('file', fileBuffer, { filename: 'bundle.zip' });
149
- formData.append('checksum', hash);
150
- if (privateKeyBuffer) {
151
- consola_1.default.start('Signing bundle...');
152
- const signature = yield (0, signature_1.createSignature)(privateKeyBuffer, fileBuffer);
153
- formData.append('signature', signature);
154
- }
155
- }
171
+ formData.append('artifactType', artifactType || 'zip');
156
172
  if (url) {
157
173
  formData.append('url', url);
158
174
  }
@@ -179,21 +195,123 @@ exports.default = (0, citty_1.defineCommand)({
179
195
  if (iosMin) {
180
196
  formData.append('minIosAppVersionCode', iosMin);
181
197
  }
182
- if (path) {
183
- consola_1.default.start('Uploading...');
184
- }
185
- else {
186
- consola_1.default.start('Creating...');
187
- }
188
- // Upload the bundle
198
+ let appBundleId;
189
199
  try {
190
- const response = yield app_bundles_1.default.create({ appId: appId, formData: formData });
200
+ // Create the app bundle
201
+ consola_1.default.start('Creating bundle...');
202
+ const response = yield app_bundles_1.default.create({
203
+ appId,
204
+ artifactType,
205
+ channelName,
206
+ url,
207
+ maxAndroidAppVersionCode: androidMax,
208
+ maxIosAppVersionCode: iosMax,
209
+ minAndroidAppVersionCode: androidMin,
210
+ minIosAppVersionCode: androidMin,
211
+ });
212
+ appBundleId = response.id;
213
+ if (path) {
214
+ let appBundleFileId;
215
+ // Upload the app bundle files
216
+ if (artifactType === 'manifest') {
217
+ yield uploadFiles({ appId, appBundleId: response.id, path, privateKeyBuffer });
218
+ }
219
+ else {
220
+ const result = yield uploadZip({ appId, appBundleId: response.id, path, privateKeyBuffer });
221
+ appBundleFileId = result.appBundleFileId;
222
+ }
223
+ // Update the app bundle
224
+ consola_1.default.start('Updating bundle...');
225
+ yield app_bundles_1.default.update({ appBundleFileId, appId, artifactStatus: 'ready', appBundleId: response.id });
226
+ }
191
227
  consola_1.default.success('Bundle successfully created.');
192
228
  consola_1.default.info(`Bundle ID: ${response.id}`);
193
229
  }
194
230
  catch (error) {
231
+ if (appBundleId) {
232
+ yield app_bundles_1.default.delete({ appId, appBundleId }).catch(() => {
233
+ // No-op
234
+ });
235
+ }
195
236
  const message = (0, error_1.getMessageFromUnknownError)(error);
196
237
  consola_1.default.error(message);
197
238
  }
198
239
  }),
199
240
  });
241
+ 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
+ }
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
+ });
260
+ const uploadFiles = (options) => __awaiter(void 0, void 0, void 0, function* () {
261
+ // Generate the manifest file
262
+ yield (0, manifest_1.generateManifestJson)(options.path);
263
+ // Get all files in the directory
264
+ const files = yield (0, file_1.getFilesInDirectoryAndSubdirectories)(options.path);
265
+ // Iterate over each file
266
+ const MAX_CONCURRENT_UPLOADS = 20;
267
+ let fileIndex = 0;
268
+ const uploadNextFile = () => __awaiter(void 0, void 0, void 0, function* () {
269
+ if (fileIndex >= files.length) {
270
+ return;
271
+ }
272
+ const file = files[fileIndex];
273
+ fileIndex++;
274
+ consola_1.default.start(`Uploading file (${fileIndex}/${files.length})...`);
275
+ const fileBuffer = yield (0, buffer_1.createBufferFromPath)(file.path);
276
+ const fileName = file.name;
277
+ const href = file.path.replace(options.path + '/', '');
278
+ yield uploadFile({
279
+ appId: options.appId,
280
+ appBundleId: options.appBundleId,
281
+ fileBuffer,
282
+ fileName,
283
+ href,
284
+ privateKeyBuffer: options.privateKeyBuffer,
285
+ });
286
+ yield uploadNextFile();
287
+ });
288
+ const uploadPromises = Array(MAX_CONCURRENT_UPLOADS);
289
+ for (let i = 0; i < MAX_CONCURRENT_UPLOADS; i++) {
290
+ uploadPromises[i] = uploadNextFile();
291
+ }
292
+ yield Promise.all(uploadPromises);
293
+ });
294
+ const uploadZip = (options) => __awaiter(void 0, void 0, void 0, function* () {
295
+ // Read the zip file
296
+ let fileBuffer;
297
+ if (zip_1.default.isZipped(options.path)) {
298
+ const readStream = (0, fs_1.createReadStream)(options.path);
299
+ fileBuffer = yield (0, buffer_1.createBufferFromReadStream)(readStream);
300
+ }
301
+ else {
302
+ consola_1.default.start('Zipping folder...');
303
+ fileBuffer = yield zip_1.default.zipFolder(options.path);
304
+ }
305
+ // Upload the zip file
306
+ consola_1.default.start('Uploading file...');
307
+ const result = yield uploadFile({
308
+ appId: options.appId,
309
+ appBundleId: options.appBundleId,
310
+ fileBuffer,
311
+ fileName: 'bundle.zip',
312
+ privateKeyBuffer: options.privateKeyBuffer,
313
+ });
314
+ return {
315
+ appBundleFileId: result.id,
316
+ };
317
+ });
@@ -14,10 +14,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const citty_1 = require("citty");
16
16
  const consola_1 = __importDefault(require("consola"));
17
- const apps_1 = __importDefault(require("../../../services/apps"));
18
- const prompt_1 = require("../../../utils/prompt");
19
17
  const app_bundles_1 = __importDefault(require("../../../services/app-bundles"));
18
+ const apps_1 = __importDefault(require("../../../services/apps"));
20
19
  const error_1 = require("../../../utils/error");
20
+ const prompt_1 = require("../../../utils/prompt");
21
21
  exports.default = (0, citty_1.defineCommand)({
22
22
  meta: {
23
23
  description: 'Delete an app bundle.',
@@ -64,7 +64,7 @@ exports.default = (0, citty_1.defineCommand)({
64
64
  try {
65
65
  yield app_bundles_1.default.delete({
66
66
  appId,
67
- bundleId,
67
+ appBundleId: bundleId,
68
68
  });
69
69
  consola_1.default.success('Bundle deleted successfully.');
70
70
  }
@@ -14,11 +14,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const citty_1 = require("citty");
16
16
  const consola_1 = __importDefault(require("consola"));
17
- const prompt_1 = require("../../../utils/prompt");
18
- const authorization_service_1 = __importDefault(require("../../../services/authorization-service"));
19
- const apps_1 = __importDefault(require("../../../services/apps"));
20
17
  const app_bundles_1 = __importDefault(require("../../../services/app-bundles"));
18
+ const apps_1 = __importDefault(require("../../../services/apps"));
19
+ const authorization_service_1 = __importDefault(require("../../../services/authorization-service"));
21
20
  const error_1 = require("../../../utils/error");
21
+ const prompt_1 = require("../../../utils/prompt");
22
22
  exports.default = (0, citty_1.defineCommand)({
23
23
  meta: {
24
24
  description: 'Update an app bundle.',
@@ -84,7 +84,7 @@ exports.default = (0, citty_1.defineCommand)({
84
84
  const rolloutAsNumber = parseFloat(rollout);
85
85
  yield app_bundles_1.default.update({
86
86
  appId,
87
- bundleId,
87
+ appBundleId: bundleId,
88
88
  maxAndroidAppVersionCode: androidMax,
89
89
  maxIosAppVersionCode: iosMax,
90
90
  minAndroidAppVersionCode: androidMin,
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -12,11 +35,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
36
  };
14
37
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const axios_1 = __importDefault(require("axios"));
38
+ const axios_1 = __importStar(require("axios"));
16
39
  const citty_1 = require("citty");
17
40
  const consola_1 = __importDefault(require("consola"));
18
41
  const config_1 = require("../config");
19
42
  const users_1 = __importDefault(require("../services/users"));
43
+ const error_1 = require("../utils/error");
20
44
  const prompt_1 = require("../utils/prompt");
21
45
  const userConfig_1 = __importDefault(require("../utils/userConfig"));
22
46
  exports.default = (0, citty_1.defineCommand)({
@@ -31,6 +55,7 @@ exports.default = (0, citty_1.defineCommand)({
31
55
  },
32
56
  },
33
57
  run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
58
+ var _a;
34
59
  let token = ctx.args.token;
35
60
  if (token === undefined) {
36
61
  consola_1.default.warn('If you have signed up via an OAuth provider, please sign in using the `--token` argument.');
@@ -68,7 +93,12 @@ exports.default = (0, citty_1.defineCommand)({
68
93
  }
69
94
  catch (error) {
70
95
  userConfig_1.default.write({});
71
- consola_1.default.error('Invalid token. Please provide a valid token. You can create a token at https://cloud.capawesome.io/settings/tokens.');
96
+ let message = (0, error_1.getMessageFromUnknownError)(error);
97
+ if (error instanceof axios_1.AxiosError && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
98
+ message =
99
+ 'Invalid token. Please provide a valid token. You can create a token at https://cloud.capawesome.io/settings/tokens.';
100
+ }
101
+ consola_1.default.error(message);
72
102
  }
73
103
  }
74
104
  }),
@@ -0,0 +1,51 @@
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 file_1 = require("../../utils/file");
18
+ const manifest_1 = require("../../utils/manifest");
19
+ const prompt_1 = require("../../utils/prompt");
20
+ exports.default = (0, citty_1.defineCommand)({
21
+ meta: {
22
+ description: 'Generate a manifest file.',
23
+ },
24
+ args: {
25
+ path: {
26
+ type: 'string',
27
+ description: 'Path to the web assets folder (e.g. `www` or `dist`).',
28
+ },
29
+ },
30
+ run: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
31
+ let path = ctx.args.path;
32
+ if (!path) {
33
+ path = yield (0, prompt_1.prompt)('Enter the path to the web assets folder:', {
34
+ type: 'text',
35
+ });
36
+ if (!path) {
37
+ consola_1.default.error('You must provide a path to the web assets folder.');
38
+ return;
39
+ }
40
+ }
41
+ // Check if the path exists
42
+ const pathExists = yield (0, file_1.fileExistsAtPath)(path);
43
+ if (!pathExists) {
44
+ consola_1.default.error(`The path does not exist.`);
45
+ return;
46
+ }
47
+ // Generate the manifest file
48
+ yield (0, manifest_1.generateManifestJson)(path);
49
+ consola_1.default.success('Manifest file generated.');
50
+ }),
51
+ });
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.API_URL = void 0;
3
+ exports.MANIFEST_JSON_FILE_NAME = exports.API_URL = void 0;
4
4
  exports.API_URL = 'https://api.cloud.capawesome.io/v1';
5
- // export const API_URL = 'http://api.cloud.capawesome.local/v1'
5
+ // export const API_URL = 'http://api.cloud.capawesome.local/v1';
6
+ exports.MANIFEST_JSON_FILE_NAME = 'capawesome-live-update-manifest.json'; // Do NOT change this!
package/dist/index.js CHANGED
@@ -54,6 +54,7 @@ const main = (0, citty_1.defineCommand)({
54
54
  'apps:channels:create': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/create'))).then((mod) => mod.default),
55
55
  'apps:channels:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/delete'))).then((mod) => mod.default),
56
56
  'apps:devices:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/devices/delete'))).then((mod) => mod.default),
57
+ 'manifests:generate': Promise.resolve().then(() => __importStar(require('./commands/manifests/generate'))).then((mod) => mod.default),
57
58
  },
58
59
  });
59
60
  (0, citty_1.runMain)(main);
@@ -0,0 +1,41 @@
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 form_data_1 = __importDefault(require("form-data"));
16
+ const http_client_1 = __importDefault(require("../utils/http-client"));
17
+ const authorization_service_1 = __importDefault(require("./authorization-service"));
18
+ class AppBundleFilesServiceImpl {
19
+ constructor(httpClient) {
20
+ this.httpClient = httpClient;
21
+ }
22
+ create(dto) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const formData = new form_data_1.default();
25
+ formData.append('checksum', dto.checksum);
26
+ formData.append('file', dto.fileBuffer, { filename: dto.fileName });
27
+ if (dto.href) {
28
+ formData.append('href', dto.href);
29
+ }
30
+ if (dto.signature) {
31
+ formData.append('signature', dto.signature);
32
+ }
33
+ const response = yield this.httpClient.post(`/apps/${dto.appId}/bundles/${dto.appBundleId}/files`, formData, {
34
+ headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, formData.getHeaders()),
35
+ });
36
+ return response.data;
37
+ });
38
+ }
39
+ }
40
+ const appBundleFilesService = new AppBundleFilesServiceImpl(http_client_1.default);
41
+ exports.default = appBundleFilesService;
@@ -12,46 +12,61 @@ 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"));
15
16
  const http_client_1 = __importDefault(require("../utils/http-client"));
16
17
  const authorization_service_1 = __importDefault(require("./authorization-service"));
17
18
  class AppBundlesServiceImpl {
18
19
  constructor(httpClient) {
19
20
  this.httpClient = httpClient;
20
21
  }
21
- create(data) {
22
+ create(dto) {
22
23
  return __awaiter(this, void 0, void 0, function* () {
23
- const response = yield this.httpClient.post(`/apps/${data.appId}/bundles`, data.formData, {
24
- headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, data.formData.getHeaders()),
25
- });
26
- if (!response.success) {
27
- throw response.error;
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.url) {
30
+ formData.append('url', dto.url);
31
+ }
32
+ if (dto.maxAndroidAppVersionCode) {
33
+ formData.append('maxAndroidAppVersionCode', dto.maxAndroidAppVersionCode);
34
+ }
35
+ if (dto.maxIosAppVersionCode) {
36
+ formData.append('maxIosAppVersionCode', dto.maxIosAppVersionCode);
37
+ }
38
+ if (dto.minAndroidAppVersionCode) {
39
+ formData.append('minAndroidAppVersionCode', dto.minAndroidAppVersionCode);
28
40
  }
41
+ if (dto.minIosAppVersionCode) {
42
+ formData.append('minIosAppVersionCode', dto.minIosAppVersionCode);
43
+ }
44
+ if (dto.rolloutPercentage) {
45
+ formData.append('rolloutPercentage', dto.rolloutPercentage.toString());
46
+ }
47
+ const response = yield this.httpClient.post(`/apps/${dto.appId}/bundles`, formData, {
48
+ headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, formData.getHeaders()),
49
+ });
29
50
  return response.data;
30
51
  });
31
52
  }
32
- update(data) {
53
+ update(dto) {
33
54
  return __awaiter(this, void 0, void 0, function* () {
34
- const response = yield this.httpClient.patch(`/apps/${data.appId}/bundles/${data.bundleId}`, data, {
55
+ const response = yield this.httpClient.patch(`/apps/${dto.appId}/bundles/${dto.appBundleId}`, dto, {
35
56
  headers: {
36
57
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
37
58
  },
38
59
  });
39
- if (!response.success) {
40
- throw response.error;
41
- }
42
60
  return response.data;
43
61
  });
44
62
  }
45
- delete(data) {
63
+ delete(dto) {
46
64
  return __awaiter(this, void 0, void 0, function* () {
47
- const response = yield this.httpClient.delete(`/apps/${data.appId}/bundles/${data.bundleId}`, {
65
+ yield this.httpClient.delete(`/apps/${dto.appId}/bundles/${dto.appBundleId}`, {
48
66
  headers: {
49
67
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
50
68
  },
51
69
  });
52
- if (!response.success) {
53
- throw response.error;
54
- }
55
70
  });
56
71
  }
57
72
  }
@@ -25,15 +25,12 @@ class AppChannelsServiceImpl {
25
25
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
26
26
  },
27
27
  });
28
- if (!response.success) {
29
- throw response.error;
30
- }
31
28
  return response.data;
32
29
  });
33
30
  }
34
31
  delete(data) {
35
32
  return __awaiter(this, void 0, void 0, function* () {
36
- const response = yield this.httpClient.delete(`/apps/${data.appId}/channels`, {
33
+ yield this.httpClient.delete(`/apps/${data.appId}/channels`, {
37
34
  headers: {
38
35
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
39
36
  },
@@ -41,9 +38,6 @@ class AppChannelsServiceImpl {
41
38
  name: data.name,
42
39
  },
43
40
  });
44
- if (!response.success) {
45
- throw response.error;
46
- }
47
41
  });
48
42
  }
49
43
  }
@@ -20,14 +20,11 @@ class AppDevicesServiceImpl {
20
20
  }
21
21
  delete(data) {
22
22
  return __awaiter(this, void 0, void 0, function* () {
23
- const res = yield this.httpClient.delete(`/apps/${data.appId}/devices/${data.deviceId}`, {
23
+ yield this.httpClient.delete(`/apps/${data.appId}/devices/${data.deviceId}`, {
24
24
  headers: {
25
25
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
26
26
  },
27
27
  });
28
- if (!res.success) {
29
- throw res.error;
30
- }
31
28
  });
32
29
  }
33
30
  }
@@ -25,22 +25,16 @@ class AppsServiceImpl {
25
25
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
26
26
  },
27
27
  });
28
- if (!response.success) {
29
- throw response.error;
30
- }
31
28
  return response.data;
32
29
  });
33
30
  }
34
31
  delete(dto) {
35
32
  return __awaiter(this, void 0, void 0, function* () {
36
- const response = yield this.httpClient.delete(`/apps/${dto.id}`, {
33
+ yield this.httpClient.delete(`/apps/${dto.id}`, {
37
34
  headers: {
38
35
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
39
36
  },
40
37
  });
41
- if (!response.success) {
42
- throw response.error;
43
- }
44
38
  });
45
39
  }
46
40
  findAll() {
@@ -50,9 +44,6 @@ class AppsServiceImpl {
50
44
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
51
45
  },
52
46
  });
53
- if (!response.success) {
54
- throw response.error;
55
- }
56
47
  return response.data;
57
48
  });
58
49
  }
@@ -45,13 +45,15 @@ class UpdateServiceImpl {
45
45
  }
46
46
  checkForUpdate() {
47
47
  return __awaiter(this, void 0, void 0, function* () {
48
- const response = yield this.httpClient.get(`https://registry.npmjs.org/${package_json_1.default.name}/latest`);
49
- if (!response.success) {
50
- throw response.error;
48
+ try {
49
+ const response = yield this.httpClient.get(`https://registry.npmjs.org/${package_json_1.default.name}/latest`);
50
+ const latestVersion = response.data.version;
51
+ if (semver.gt(latestVersion, package_json_1.default.version)) {
52
+ consola_1.default.warn(`New version of Capawesome CLI available: ${package_json_1.default.name}@${latestVersion}. Please update to receive the latest features and bug fixes.`);
53
+ }
51
54
  }
52
- const latestVersion = response.data.version;
53
- if (semver.gt(latestVersion, package_json_1.default.version)) {
54
- consola_1.default.warn(`New version of Capawesome CLI available: ${package_json_1.default.name}@${latestVersion}. Please update to receive the latest features and bug fixes.`);
55
+ catch (error) {
56
+ consola_1.default.error('Failed to check for updates.');
55
57
  }
56
58
  });
57
59
  }
@@ -25,9 +25,6 @@ class UsersServiceImpl {
25
25
  Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
26
26
  },
27
27
  });
28
- if (!response.success) {
29
- throw response.error;
30
- }
31
28
  return response.data;
32
29
  });
33
30
  }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -16,6 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./app"), exports);
18
18
  __exportStar(require("./app-bundle"), exports);
19
- __exportStar(require("./app-device"), exports);
20
19
  __exportStar(require("./app-channel"), exports);
20
+ __exportStar(require("./app-device"), exports);
21
21
  __exportStar(require("./user"), exports);
@@ -32,8 +32,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.createBufferFromPath = exports.createBuffer = void 0;
36
- const createBuffer = (data) => __awaiter(void 0, void 0, void 0, function* () {
35
+ exports.createBufferFromReadStream = exports.createBufferFromPath = void 0;
36
+ const createBufferFromPath = (path) => __awaiter(void 0, void 0, void 0, function* () {
37
+ const fs = yield Promise.resolve().then(() => __importStar(require('fs')));
38
+ const stream = fs.createReadStream(path);
39
+ return (0, exports.createBufferFromReadStream)(stream);
40
+ });
41
+ exports.createBufferFromPath = createBufferFromPath;
42
+ const createBufferFromReadStream = (data) => __awaiter(void 0, void 0, void 0, function* () {
37
43
  const chunks = [];
38
44
  return new Promise((resolve, reject) => {
39
45
  data.on('readable', () => {
@@ -48,10 +54,4 @@ const createBuffer = (data) => __awaiter(void 0, void 0, void 0, function* () {
48
54
  data.on('error', reject);
49
55
  });
50
56
  });
51
- exports.createBuffer = createBuffer;
52
- const createBufferFromPath = (path) => __awaiter(void 0, void 0, void 0, function* () {
53
- const fs = yield Promise.resolve().then(() => __importStar(require('fs')));
54
- const stream = fs.createReadStream(path);
55
- return (0, exports.createBuffer)(stream);
56
- });
57
- exports.createBufferFromPath = createBufferFromPath;
57
+ exports.createBufferFromReadStream = createBufferFromReadStream;
@@ -14,7 +14,7 @@ const getMessageFromUnknownError = (error) => {
14
14
  };
15
15
  exports.getMessageFromUnknownError = getMessageFromUnknownError;
16
16
  const getErrorMessageFromAxiosError = (error) => {
17
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
17
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
18
18
  let message = 'An unknown network error has occurred.';
19
19
  if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
20
20
  message = 'Your token is no longer valid. Please sign in again.';
@@ -25,5 +25,8 @@ const getErrorMessageFromAxiosError = (error) => {
25
25
  else if ((_j = (_h = (_g = (_f = error.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.error) === null || _h === void 0 ? void 0 : _h.issues[0]) === null || _j === void 0 ? void 0 : _j.message) {
26
26
  message = ((_k = error.response) === null || _k === void 0 ? void 0 : _k.data).error.issues[0].message;
27
27
  }
28
+ else if (typeof ((_l = error.response) === null || _l === void 0 ? void 0 : _l.data) === 'string') {
29
+ message = error.response.data;
30
+ }
28
31
  return message;
29
32
  };
@@ -32,7 +32,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.fileExistsAtPath = void 0;
35
+ exports.writeFile = exports.isDirectory = exports.fileExistsAtPath = exports.getFilesInDirectoryAndSubdirectories = void 0;
36
+ const getFilesInDirectoryAndSubdirectories = (path) => __awaiter(void 0, void 0, void 0, function* () {
37
+ const fs = yield Promise.resolve().then(() => __importStar(require('fs')));
38
+ const pathModule = yield Promise.resolve().then(() => __importStar(require('path')));
39
+ const files = [];
40
+ const walk = (directory) => __awaiter(void 0, void 0, void 0, function* () {
41
+ const dirEntries = yield fs.promises.readdir(directory, { withFileTypes: true }).catch(() => []);
42
+ for (const dirEntry of dirEntries) {
43
+ const fullPath = pathModule.join(directory, dirEntry.name);
44
+ if (dirEntry.isDirectory()) {
45
+ yield walk(fullPath);
46
+ }
47
+ else {
48
+ files.push({
49
+ name: dirEntry.name,
50
+ path: fullPath,
51
+ });
52
+ }
53
+ }
54
+ });
55
+ yield walk(path);
56
+ return files;
57
+ });
58
+ exports.getFilesInDirectoryAndSubdirectories = getFilesInDirectoryAndSubdirectories;
36
59
  const fileExistsAtPath = (path) => __awaiter(void 0, void 0, void 0, function* () {
37
60
  const fs = yield Promise.resolve().then(() => __importStar(require('fs')));
38
61
  return new Promise((resolve) => {
@@ -42,3 +65,26 @@ const fileExistsAtPath = (path) => __awaiter(void 0, void 0, void 0, function* (
42
65
  });
43
66
  });
44
67
  exports.fileExistsAtPath = fileExistsAtPath;
68
+ const isDirectory = (path) => __awaiter(void 0, void 0, void 0, function* () {
69
+ const fs = yield Promise.resolve().then(() => __importStar(require('fs')));
70
+ return new Promise((resolve) => {
71
+ fs.lstat(path, (err, stats) => {
72
+ resolve(stats.isDirectory());
73
+ });
74
+ });
75
+ });
76
+ exports.isDirectory = isDirectory;
77
+ const writeFile = (path, data) => __awaiter(void 0, void 0, void 0, function* () {
78
+ const fs = yield Promise.resolve().then(() => __importStar(require('fs')));
79
+ return new Promise((resolve, reject) => {
80
+ fs.writeFile(path, data, (err) => {
81
+ if (err) {
82
+ reject(err);
83
+ }
84
+ else {
85
+ resolve(undefined);
86
+ }
87
+ });
88
+ });
89
+ });
90
+ exports.writeFile = writeFile;
@@ -1,13 +1,4 @@
1
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
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
@@ -16,84 +7,24 @@ const axios_1 = __importDefault(require("axios"));
16
7
  const config_1 = require("../config");
17
8
  class HttpClientImpl {
18
9
  delete(url, config) {
19
- return __awaiter(this, void 0, void 0, function* () {
20
- try {
21
- const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
22
- const res = yield axios_1.default.delete(urlWithHost, config);
23
- return {
24
- success: true,
25
- status: res.status,
26
- data: res.data,
27
- };
28
- }
29
- catch (e) {
30
- return {
31
- success: false,
32
- status: e.response.status,
33
- error: e,
34
- };
35
- }
36
- });
10
+ const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
11
+ return axios_1.default.delete(urlWithHost, config);
37
12
  }
38
13
  get(url, config) {
39
- return __awaiter(this, void 0, void 0, function* () {
40
- try {
41
- const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
42
- const res = yield axios_1.default.get(urlWithHost, config);
43
- return {
44
- success: true,
45
- status: res.status,
46
- data: res.data,
47
- };
48
- }
49
- catch (e) {
50
- return {
51
- success: false,
52
- status: e.response.status,
53
- error: e,
54
- };
55
- }
56
- });
14
+ const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
15
+ return axios_1.default.get(urlWithHost, config);
57
16
  }
58
17
  patch(url, data, config) {
59
- return __awaiter(this, void 0, void 0, function* () {
60
- try {
61
- const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
62
- const res = yield axios_1.default.patch(urlWithHost, data, config);
63
- return {
64
- success: true,
65
- status: res.status,
66
- data: res.data,
67
- };
68
- }
69
- catch (e) {
70
- return {
71
- success: false,
72
- status: e.response.status,
73
- error: e,
74
- };
75
- }
76
- });
18
+ const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
19
+ return axios_1.default.patch(urlWithHost, data, config);
77
20
  }
78
21
  post(url, data, config) {
79
- return __awaiter(this, void 0, void 0, function* () {
80
- try {
81
- const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
82
- const res = yield axios_1.default.post(urlWithHost, data, config);
83
- return {
84
- success: true,
85
- status: res.status,
86
- data: res.data,
87
- };
88
- }
89
- catch (e) {
90
- return {
91
- success: false,
92
- status: e.response.status,
93
- error: e,
94
- };
95
- }
96
- });
22
+ const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
23
+ return axios_1.default.post(urlWithHost, data, config);
24
+ }
25
+ put(url, data, config) {
26
+ const urlWithHost = url.startsWith('http') ? url : config_1.API_URL + url;
27
+ return axios_1.default.put(urlWithHost, data, config);
97
28
  }
98
29
  }
99
30
  let httpClient = new HttpClientImpl();
@@ -0,0 +1,35 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.generateManifestJson = void 0;
13
+ const config_1 = require("../config");
14
+ const buffer_1 = require("./buffer");
15
+ const file_1 = require("./file");
16
+ const hash_1 = require("./hash");
17
+ const generateManifestJson = (path) => __awaiter(void 0, void 0, void 0, function* () {
18
+ const manifestItems = [];
19
+ // Get all files
20
+ const files = yield (0, file_1.getFilesInDirectoryAndSubdirectories)(path);
21
+ // Iterate over each file
22
+ for (const [index, file] of files.entries()) {
23
+ const fileBuffer = yield (0, buffer_1.createBufferFromPath)(file.path);
24
+ const checksum = yield (0, hash_1.createHash)(fileBuffer);
25
+ const sizeInBytes = fileBuffer.byteLength;
26
+ manifestItems.push({
27
+ checksum,
28
+ href: file.path.replace(path + '/', ''),
29
+ sizeInBytes,
30
+ });
31
+ }
32
+ // Write the manifest file
33
+ (0, file_1.writeFile)(`${path}/${config_1.MANIFEST_JSON_FILE_NAME}`, JSON.stringify(manifestItems, null, 2));
34
+ });
35
+ exports.generateManifestJson = generateManifestJson;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capawesome/cli",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "The Capawesome Cloud Command Line Interface (CLI) to manage Live Updates and more.",
5
5
  "scripts": {
6
6
  "build": "rimraf ./dist && tsc",