@capawesome/cli 1.13.2 → 1.14.0-dev.3b0fc7e.1755934102

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +7 -3
  3. package/dist/commands/apps/bundles/create.js +218 -234
  4. package/dist/commands/apps/bundles/create.test.js +276 -0
  5. package/dist/commands/apps/bundles/delete.js +47 -55
  6. package/dist/commands/apps/bundles/delete.test.js +139 -0
  7. package/dist/commands/apps/bundles/update.js +73 -84
  8. package/dist/commands/apps/bundles/update.test.js +141 -0
  9. package/dist/commands/apps/channels/create.js +57 -70
  10. package/dist/commands/apps/channels/create.test.js +119 -0
  11. package/dist/commands/apps/channels/delete.js +58 -64
  12. package/dist/commands/apps/channels/delete.test.js +141 -0
  13. package/dist/commands/apps/channels/get.js +52 -94
  14. package/dist/commands/apps/channels/get.test.js +135 -0
  15. package/dist/commands/apps/channels/list.js +37 -82
  16. package/dist/commands/apps/channels/list.test.js +121 -0
  17. package/dist/commands/apps/channels/update.js +50 -77
  18. package/dist/commands/apps/channels/update.test.js +138 -0
  19. package/dist/commands/apps/create.js +39 -42
  20. package/dist/commands/apps/create.test.js +117 -0
  21. package/dist/commands/apps/delete.js +41 -45
  22. package/dist/commands/apps/delete.test.js +120 -0
  23. package/dist/commands/apps/devices/delete.js +47 -55
  24. package/dist/commands/apps/devices/delete.test.js +139 -0
  25. package/dist/commands/doctor.js +12 -29
  26. package/dist/commands/doctor.test.js +52 -0
  27. package/dist/commands/login.js +50 -71
  28. package/dist/commands/login.test.js +116 -0
  29. package/dist/commands/logout.js +13 -31
  30. package/dist/commands/logout.test.js +47 -0
  31. package/dist/commands/manifests/generate.js +20 -38
  32. package/dist/commands/manifests/generate.test.js +60 -0
  33. package/dist/commands/organizations/create.js +25 -0
  34. package/dist/commands/organizations/create.test.js +80 -0
  35. package/dist/commands/whoami.js +20 -31
  36. package/dist/commands/whoami.test.js +30 -0
  37. package/dist/config/consts.js +4 -5
  38. package/dist/config/index.js +1 -17
  39. package/dist/index.js +54 -80
  40. package/dist/services/app-bundle-files.js +117 -136
  41. package/dist/services/app-bundles.js +22 -41
  42. package/dist/services/app-channels.js +54 -77
  43. package/dist/services/app-devices.js +10 -25
  44. package/dist/services/apps.js +25 -41
  45. package/dist/services/authorization-service.js +4 -8
  46. package/dist/services/config.js +15 -28
  47. package/dist/services/organizations.js +26 -0
  48. package/dist/services/session-code.js +7 -22
  49. package/dist/services/sessions.js +13 -30
  50. package/dist/services/update.js +17 -55
  51. package/dist/services/users.js +11 -26
  52. package/dist/types/app-bundle-file.js +1 -2
  53. package/dist/types/app-bundle.js +1 -2
  54. package/dist/types/app-channel.js +1 -2
  55. package/dist/types/app-device.js +1 -2
  56. package/dist/types/app.js +1 -2
  57. package/dist/types/index.js +8 -23
  58. package/dist/types/npm-package.js +1 -2
  59. package/dist/types/organization.js +1 -0
  60. package/dist/types/session-code.js +1 -2
  61. package/dist/types/session.js +1 -2
  62. package/dist/types/user.js +1 -2
  63. package/dist/utils/buffer.js +12 -43
  64. package/dist/utils/error.js +24 -14
  65. package/dist/utils/file.js +22 -41
  66. package/dist/utils/hash.js +3 -39
  67. package/dist/utils/http-client.js +27 -53
  68. package/dist/utils/manifest.js +11 -24
  69. package/dist/utils/private-key.js +23 -0
  70. package/dist/utils/prompt.js +9 -26
  71. package/dist/utils/signature.js +3 -39
  72. package/dist/utils/user-config.js +12 -0
  73. package/dist/utils/zip.js +11 -27
  74. package/package.json +22 -9
  75. package/dist/utils/ci.js +0 -7
  76. package/dist/utils/userConfig.js +0 -16
@@ -0,0 +1,80 @@
1
+ import { DEFAULT_API_BASE_URL } from '../../config/consts.js';
2
+ import authorizationService from '../../services/authorization-service.js';
3
+ import { prompt } from '../../utils/prompt.js';
4
+ import userConfig from '../../utils/user-config.js';
5
+ import consola from 'consola';
6
+ import nock from 'nock';
7
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
8
+ import createOrganizationCommand from './create.js';
9
+ // Mock dependencies
10
+ vi.mock('@/utils/user-config.js');
11
+ vi.mock('@/utils/prompt.js');
12
+ vi.mock('@/services/authorization-service.js');
13
+ vi.mock('consola');
14
+ describe('organizations-create', () => {
15
+ const mockUserConfig = vi.mocked(userConfig);
16
+ const mockPrompt = vi.mocked(prompt);
17
+ const mockConsola = vi.mocked(consola);
18
+ const mockAuthorizationService = vi.mocked(authorizationService);
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ mockUserConfig.read.mockReturnValue({ token: 'test-token' });
22
+ mockAuthorizationService.getCurrentAuthorizationToken.mockReturnValue('test-token');
23
+ mockAuthorizationService.hasAuthorizationToken.mockReturnValue(true);
24
+ vi.spyOn(process, 'exit').mockImplementation((code) => {
25
+ throw new Error(`Process exited with code ${code}`);
26
+ });
27
+ });
28
+ afterEach(() => {
29
+ nock.cleanAll();
30
+ vi.restoreAllMocks();
31
+ });
32
+ it('should create organization with provided name', async () => {
33
+ const organizationName = 'Test Organization';
34
+ const organizationId = 'org-456';
35
+ const testToken = 'test-token';
36
+ const options = { name: organizationName };
37
+ const scope = nock(DEFAULT_API_BASE_URL)
38
+ .post('/v1/organizations', { name: organizationName })
39
+ .matchHeader('Authorization', `Bearer ${testToken}`)
40
+ .reply(201, { id: organizationId, name: organizationName });
41
+ await createOrganizationCommand.action(options, undefined);
42
+ expect(scope.isDone()).toBe(true);
43
+ expect(mockConsola.success).toHaveBeenCalledWith('Organization created successfully.');
44
+ expect(mockConsola.info).toHaveBeenCalledWith(`Organization ID: ${organizationId}`);
45
+ });
46
+ it('should prompt for organization name when not provided', async () => {
47
+ const promptedOrganizationName = 'Prompted Organization';
48
+ const organizationId = 'org-456';
49
+ const testToken = 'test-token';
50
+ const options = {};
51
+ const scope = nock(DEFAULT_API_BASE_URL)
52
+ .post('/v1/organizations', { name: promptedOrganizationName })
53
+ .matchHeader('Authorization', `Bearer ${testToken}`)
54
+ .reply(201, { id: organizationId, name: promptedOrganizationName });
55
+ mockPrompt.mockResolvedValueOnce(promptedOrganizationName);
56
+ await createOrganizationCommand.action(options, undefined);
57
+ expect(scope.isDone()).toBe(true);
58
+ expect(mockPrompt).toHaveBeenCalledWith('Enter the name of the organization:', { type: 'text' });
59
+ expect(mockConsola.success).toHaveBeenCalledWith('Organization created successfully.');
60
+ expect(mockConsola.info).toHaveBeenCalledWith(`Organization ID: ${organizationId}`);
61
+ });
62
+ it('should exit when not logged in', async () => {
63
+ const organizationName = 'Test Organization';
64
+ const options = { name: organizationName };
65
+ mockAuthorizationService.hasAuthorizationToken.mockReturnValue(false);
66
+ await expect(createOrganizationCommand.action(options, undefined)).rejects.toThrow('Process exited with code 1');
67
+ expect(mockConsola.error).toHaveBeenCalledWith('You must be logged in to run this command.');
68
+ });
69
+ it('should handle API error during creation', async () => {
70
+ const organizationName = 'Test Organization';
71
+ const testToken = 'test-token';
72
+ const options = { name: organizationName };
73
+ const scope = nock(DEFAULT_API_BASE_URL)
74
+ .post('/v1/organizations', { name: organizationName })
75
+ .matchHeader('Authorization', `Bearer ${testToken}`)
76
+ .reply(400, { message: 'Organization name already exists' });
77
+ await expect(createOrganizationCommand.action(options, undefined)).rejects.toThrow();
78
+ expect(scope.isDone()).toBe(true);
79
+ });
80
+ });
@@ -1,41 +1,30 @@
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 users_1 = __importDefault(require("../services/users"));
18
- const userConfig_1 = __importDefault(require("../utils/userConfig"));
19
- exports.default = (0, citty_1.defineCommand)({
20
- meta: {
21
- name: 'whoami',
22
- description: 'Show current user',
23
- },
24
- run: () => __awaiter(void 0, void 0, void 0, function* () {
25
- const { token } = userConfig_1.default.read();
1
+ import usersService from '../services/users.js';
2
+ import userConfig from '../utils/user-config.js';
3
+ import { defineCommand } from '@robingenz/zli';
4
+ import { AxiosError } from 'axios';
5
+ import consola from 'consola';
6
+ export default defineCommand({
7
+ description: 'Show current user',
8
+ action: async (options, args) => {
9
+ const { token } = userConfig.read();
26
10
  if (token) {
27
11
  try {
28
- const user = yield users_1.default.me();
29
- consola_1.default.info(`Logged in as ${user.email}.`);
12
+ const user = await usersService.me();
13
+ consola.info(`Logged in as ${user.email}.`);
30
14
  }
31
15
  catch (error) {
32
- consola_1.default.error('Token is invalid. Please sign in again.');
33
- process.exit(1);
16
+ if (error instanceof AxiosError && error.response?.status === 401) {
17
+ consola.error('Token is invalid. Please sign in again.');
18
+ process.exit(1);
19
+ }
20
+ else {
21
+ throw error;
22
+ }
34
23
  }
35
24
  }
36
25
  else {
37
- consola_1.default.error('Not logged in.');
26
+ consola.error('Not logged in.');
38
27
  process.exit(1);
39
28
  }
40
- }),
29
+ },
41
30
  });
@@ -0,0 +1,30 @@
1
+ import { DEFAULT_API_BASE_URL } from '../config/consts.js';
2
+ import userConfig from '../utils/user-config.js';
3
+ import nock from 'nock';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
+ import whoamiCommand from './whoami.js';
6
+ // Mock only the dependencies we need to control
7
+ vi.mock('@/utils/user-config.js');
8
+ describe('whoami', () => {
9
+ const mockUserConfig = vi.mocked(userConfig);
10
+ beforeEach(() => {
11
+ vi.clearAllMocks();
12
+ vi.spyOn(process, 'exit').mockImplementation(() => undefined);
13
+ });
14
+ afterEach(() => {
15
+ nock.cleanAll();
16
+ vi.restoreAllMocks();
17
+ });
18
+ it('should send Bearer token in Authorization header when checking current user', async () => {
19
+ const testToken = 'user-token-456';
20
+ // Mock userConfig.read to return our test token
21
+ mockUserConfig.read.mockReturnValue({ token: testToken });
22
+ // Set up nock to intercept the /v1/users/me request
23
+ const scope = nock(DEFAULT_API_BASE_URL)
24
+ .get('/v1/users/me')
25
+ .matchHeader('Authorization', `Bearer ${testToken}`)
26
+ .reply(200, { id: 'user-456', email: 'user@example.com' });
27
+ await whoamiCommand.action({}, undefined);
28
+ expect(scope.isDone()).toBe(true);
29
+ });
30
+ });
@@ -1,5 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MAX_CONCURRENT_UPLOADS = exports.MANIFEST_JSON_FILE_NAME = void 0;
4
- exports.MANIFEST_JSON_FILE_NAME = 'capawesome-live-update-manifest.json'; // Do NOT change this!
5
- exports.MAX_CONCURRENT_UPLOADS = 20;
1
+ export const DEFAULT_API_BASE_URL = 'https://api.cloud.capawesome.io';
2
+ export const DEFAULT_CONSOLE_BASE_URL = 'https://console.cloud.capawesome.io';
3
+ export const MANIFEST_JSON_FILE_NAME = 'capawesome-live-update-manifest.json'; // Do NOT change this!
4
+ export const MAX_CONCURRENT_UPLOADS = 20;
@@ -1,17 +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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./consts"), exports);
1
+ export * from './consts.js';
package/dist/index.js CHANGED
@@ -1,81 +1,39 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || function (mod) {
20
- if (mod && mod.__esModule) return mod;
21
- var result = {};
22
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
- __setModuleDefault(result, mod);
24
- return result;
25
- };
26
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
27
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
28
- return new (P || (P = Promise))(function (resolve, reject) {
29
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
30
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
31
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
32
- step((generator = generator.apply(thisArg, _arguments || [])).next());
33
- });
34
- };
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- const Sentry = __importStar(require("@sentry/node"));
40
- const citty_1 = require("citty");
41
- const consola_1 = __importDefault(require("consola"));
42
- const package_json_1 = __importDefault(require("../package.json"));
43
- const config_1 = __importDefault(require("./services/config"));
44
- const update_1 = __importDefault(require("./services/update"));
45
- const error_1 = require("./utils/error");
46
- const main = (0, citty_1.defineCommand)({
2
+ import configService from './services/config.js';
3
+ import updateService from './services/update.js';
4
+ import { getMessageFromUnknownError } from './utils/error.js';
5
+ import { defineConfig, processConfig } from '@robingenz/zli';
6
+ import * as Sentry from '@sentry/node';
7
+ import consola from 'consola';
8
+ import pkg from '../package.json' with { type: 'json' };
9
+ const config = defineConfig({
47
10
  meta: {
48
- name: package_json_1.default.name,
49
- version: package_json_1.default.version,
50
- description: package_json_1.default.description,
11
+ name: pkg.name,
12
+ version: pkg.version,
13
+ description: pkg.description,
51
14
  },
52
- setup() {
53
- // No op
54
- },
55
- cleanup() {
56
- return update_1.default.checkForUpdate();
57
- },
58
- subCommands: {
59
- whoami: Promise.resolve().then(() => __importStar(require('./commands/whoami'))).then((mod) => mod.default),
60
- login: Promise.resolve().then(() => __importStar(require('./commands/login'))).then((mod) => mod.default),
61
- logout: Promise.resolve().then(() => __importStar(require('./commands/logout'))).then((mod) => mod.default),
62
- doctor: Promise.resolve().then(() => __importStar(require('./commands/doctor'))).then((mod) => mod.default),
63
- 'apps:create': Promise.resolve().then(() => __importStar(require('./commands/apps/create'))).then((mod) => mod.default),
64
- 'apps:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/delete'))).then((mod) => mod.default),
65
- 'apps:bundles:create': Promise.resolve().then(() => __importStar(require('./commands/apps/bundles/create'))).then((mod) => mod.default),
66
- 'apps:bundles:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/bundles/delete'))).then((mod) => mod.default),
67
- 'apps:bundles:update': Promise.resolve().then(() => __importStar(require('./commands/apps/bundles/update'))).then((mod) => mod.default),
68
- 'apps:channels:create': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/create'))).then((mod) => mod.default),
69
- 'apps:channels:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/delete'))).then((mod) => mod.default),
70
- 'apps:channels:get': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/get'))).then((mod) => mod.default),
71
- 'apps:channels:list': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/list'))).then((mod) => mod.default),
72
- 'apps:channels:update': Promise.resolve().then(() => __importStar(require('./commands/apps/channels/update'))).then((mod) => mod.default),
73
- 'apps:devices:delete': Promise.resolve().then(() => __importStar(require('./commands/apps/devices/delete'))).then((mod) => mod.default),
74
- 'manifests:generate': Promise.resolve().then(() => __importStar(require('./commands/manifests/generate'))).then((mod) => mod.default),
15
+ commands: {
16
+ whoami: await import('./commands/whoami.js').then((mod) => mod.default),
17
+ login: await import('./commands/login.js').then((mod) => mod.default),
18
+ logout: await import('./commands/logout.js').then((mod) => mod.default),
19
+ doctor: await import('./commands/doctor.js').then((mod) => mod.default),
20
+ 'apps:create': await import('./commands/apps/create.js').then((mod) => mod.default),
21
+ 'apps:delete': await import('./commands/apps/delete.js').then((mod) => mod.default),
22
+ 'apps:bundles:create': await import('./commands/apps/bundles/create.js').then((mod) => mod.default),
23
+ 'apps:bundles:delete': await import('./commands/apps/bundles/delete.js').then((mod) => mod.default),
24
+ 'apps:bundles:update': await import('./commands/apps/bundles/update.js').then((mod) => mod.default),
25
+ 'apps:channels:create': await import('./commands/apps/channels/create.js').then((mod) => mod.default),
26
+ 'apps:channels:delete': await import('./commands/apps/channels/delete.js').then((mod) => mod.default),
27
+ 'apps:channels:get': await import('./commands/apps/channels/get.js').then((mod) => mod.default),
28
+ 'apps:channels:list': await import('./commands/apps/channels/list.js').then((mod) => mod.default),
29
+ 'apps:channels:update': await import('./commands/apps/channels/update.js').then((mod) => mod.default),
30
+ 'apps:devices:delete': await import('./commands/apps/devices/delete.js').then((mod) => mod.default),
31
+ 'manifests:generate': await import('./commands/manifests/generate.js').then((mod) => mod.default),
32
+ 'organizations:create': await import('./commands/organizations/create.js').then((mod) => mod.default),
75
33
  },
76
34
  });
77
- const captureException = (error) => __awaiter(void 0, void 0, void 0, function* () {
78
- const environment = yield config_1.default.getValueForKey('ENVIRONMENT');
35
+ const captureException = async (error) => {
36
+ const environment = await configService.getValueForKey('ENVIRONMENT');
79
37
  if (environment !== 'production') {
80
38
  return;
81
39
  }
@@ -83,19 +41,35 @@ const captureException = (error) => __awaiter(void 0, void 0, void 0, function*
83
41
  dsn: 'https://19f30f2ec4b91899abc33818568ceb42@o4507446340747264.ingest.de.sentry.io/4508506426966096',
84
42
  });
85
43
  Sentry.captureException(error);
86
- yield Sentry.close();
87
- });
88
- (0, citty_1.runMain)(main).catch((error) => __awaiter(void 0, void 0, void 0, function* () {
44
+ await Sentry.close();
45
+ };
46
+ try {
47
+ if (!process.argv.includes('@capawesome/cli')) {
48
+ consola.warn('The `capawesome` command is deprecated. Please use `@capawesome/cli` instead.');
49
+ }
50
+ const result = processConfig(config, process.argv.slice(2));
51
+ await result.command.action(result.options, result.args);
52
+ }
53
+ catch (error) {
89
54
  try {
90
- yield captureException(error).catch(() => {
55
+ await captureException(error).catch(() => {
91
56
  // No op
92
57
  });
93
58
  // Print the error message
94
- const message = (0, error_1.getMessageFromUnknownError)(error);
95
- consola_1.default.error(message);
59
+ const message = getMessageFromUnknownError(error);
60
+ consola.error(message);
96
61
  }
97
62
  finally {
63
+ // Suggest opening an issue
64
+ consola.log('If you think this is a bug, please open an issue at:');
65
+ consola.log(' https://github.com/capawesome-team/cli/issues/new/choose');
66
+ // Check for updates
67
+ await updateService.checkForUpdate();
98
68
  // Exit with a non-zero code
99
69
  process.exit(1);
100
70
  }
101
- }));
71
+ }
72
+ finally {
73
+ // Check for updates
74
+ await updateService.checkForUpdate();
75
+ }
@@ -1,155 +1,136 @@
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 config_1 = require("../config");
17
- const http_client_1 = __importDefault(require("../utils/http-client"));
18
- const authorization_service_1 = __importDefault(require("./authorization-service"));
1
+ import FormData from 'form-data';
2
+ import { MAX_CONCURRENT_UPLOADS } from '../config/index.js';
3
+ import httpClient from '../utils/http-client.js';
4
+ import authorizationService from '../services/authorization-service.js';
19
5
  class AppBundleFilesServiceImpl {
6
+ httpClient;
20
7
  constructor(httpClient) {
21
8
  this.httpClient = httpClient;
22
9
  }
23
- create(dto) {
24
- return __awaiter(this, void 0, void 0, function* () {
25
- const sizeInBytes = dto.buffer.byteLength;
26
- const useMultipartUpload = sizeInBytes >= 100 * 1024 * 1024; // 100 MB
27
- const formData = new form_data_1.default();
28
- formData.append('checksum', dto.checksum);
29
- if (!useMultipartUpload) {
30
- formData.append('file', dto.buffer, { filename: dto.name });
31
- }
32
- if (dto.href) {
33
- formData.append('href', dto.href);
34
- }
35
- formData.append('mimeType', dto.mimeType);
36
- formData.append('name', dto.name);
37
- if (dto.signature) {
38
- formData.append('signature', dto.signature);
39
- }
40
- formData.append('sizeInBytes', sizeInBytes.toString());
41
- const response = yield this.httpClient.post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files`, formData, {
42
- headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, formData.getHeaders()),
43
- });
44
- if (useMultipartUpload) {
45
- yield this.upload({
46
- appBundleFileId: response.data.id,
47
- appBundleId: dto.appBundleId,
48
- appId: dto.appId,
49
- buffer: dto.buffer,
50
- name: dto.name,
51
- checksum: dto.checksum,
52
- });
53
- }
54
- return response.data;
10
+ async create(dto) {
11
+ const sizeInBytes = dto.buffer.byteLength;
12
+ const useMultipartUpload = sizeInBytes >= 100 * 1024 * 1024; // 100 MB
13
+ const formData = new FormData();
14
+ formData.append('checksum', dto.checksum);
15
+ if (!useMultipartUpload) {
16
+ formData.append('file', dto.buffer, { filename: dto.name });
17
+ }
18
+ if (dto.href) {
19
+ formData.append('href', dto.href);
20
+ }
21
+ formData.append('mimeType', dto.mimeType);
22
+ formData.append('name', dto.name);
23
+ if (dto.signature) {
24
+ formData.append('signature', dto.signature);
25
+ }
26
+ formData.append('sizeInBytes', sizeInBytes.toString());
27
+ const response = await this.httpClient.post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files`, formData, {
28
+ headers: {
29
+ Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
30
+ ...formData.getHeaders(),
31
+ },
55
32
  });
33
+ if (useMultipartUpload) {
34
+ await this.upload({
35
+ appBundleFileId: response.data.id,
36
+ appBundleId: dto.appBundleId,
37
+ appId: dto.appId,
38
+ buffer: dto.buffer,
39
+ name: dto.name,
40
+ checksum: dto.checksum,
41
+ });
42
+ }
43
+ return response.data;
56
44
  }
57
- completeUpload(dto) {
58
- return __awaiter(this, void 0, void 0, function* () {
59
- return this.httpClient
60
- .post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-complete&uploadId=${dto.uploadId}`, {
61
- parts: dto.parts,
62
- }, {
63
- headers: {
64
- Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
65
- },
66
- })
67
- .then((response) => response.data);
68
- });
45
+ async completeUpload(dto) {
46
+ return this.httpClient
47
+ .post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-complete&uploadId=${dto.uploadId}`, {
48
+ parts: dto.parts,
49
+ }, {
50
+ headers: {
51
+ Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
52
+ },
53
+ })
54
+ .then((response) => response.data);
69
55
  }
70
- createUpload(dto) {
71
- return __awaiter(this, void 0, void 0, function* () {
72
- const response = yield this.httpClient.post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-create`, {}, {
73
- headers: {
74
- Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
75
- },
76
- });
77
- return response.data;
56
+ async createUpload(dto) {
57
+ const response = await this.httpClient.post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-create`, {}, {
58
+ headers: {
59
+ Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
60
+ },
78
61
  });
62
+ return response.data;
79
63
  }
80
- createUploadPart(dto) {
81
- return __awaiter(this, void 0, void 0, function* () {
82
- const formData = new form_data_1.default();
83
- formData.append('blob', dto.buffer, { filename: dto.name });
84
- formData.append('partNumber', dto.partNumber.toString());
85
- return this.httpClient
86
- .put(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-uploadpart&uploadId=${dto.uploadId}`, formData, {
87
- headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, formData.getHeaders()),
88
- })
89
- .then((response) => response.data);
90
- });
64
+ async createUploadPart(dto) {
65
+ const formData = new FormData();
66
+ formData.append('blob', dto.buffer, { filename: dto.name });
67
+ formData.append('partNumber', dto.partNumber.toString());
68
+ return this.httpClient
69
+ .put(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-uploadpart&uploadId=${dto.uploadId}`, formData, {
70
+ headers: {
71
+ Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`,
72
+ ...formData.getHeaders(),
73
+ },
74
+ })
75
+ .then((response) => response.data);
91
76
  }
92
- createUploadParts(dto) {
93
- return __awaiter(this, void 0, void 0, function* () {
94
- const uploadedParts = [];
95
- const partSize = 10 * 1024 * 1024; // 10 MB. 5 MB is the minimum part size except for the last part.
96
- const totalParts = Math.ceil(dto.buffer.byteLength / partSize);
97
- let partNumber = 0;
98
- const uploadNextPart = () => __awaiter(this, void 0, void 0, function* () {
99
- if (partNumber >= totalParts) {
100
- return;
101
- }
102
- partNumber++;
103
- const start = (partNumber - 1) * partSize;
104
- const end = Math.min(start + partSize, dto.buffer.byteLength);
105
- const partBuffer = dto.buffer.subarray(start, end);
106
- const uploadedPart = yield this.createUploadPart({
107
- appBundleFileId: dto.appBundleFileId,
108
- appBundleId: dto.appBundleId,
109
- appId: dto.appId,
110
- buffer: partBuffer,
111
- name: dto.name,
112
- partNumber,
113
- uploadId: dto.uploadId,
114
- });
115
- uploadedParts.push(uploadedPart);
116
- yield uploadNextPart();
117
- });
118
- const uploadPartPromises = Array.from({ length: config_1.MAX_CONCURRENT_UPLOADS });
119
- for (let i = 0; i < config_1.MAX_CONCURRENT_UPLOADS; i++) {
120
- uploadPartPromises[i] = uploadNextPart();
77
+ async createUploadParts(dto) {
78
+ const uploadedParts = [];
79
+ const partSize = 10 * 1024 * 1024; // 10 MB. 5 MB is the minimum part size except for the last part.
80
+ const totalParts = Math.ceil(dto.buffer.byteLength / partSize);
81
+ let partNumber = 0;
82
+ const uploadNextPart = async () => {
83
+ if (partNumber >= totalParts) {
84
+ return;
121
85
  }
122
- yield Promise.all(uploadPartPromises);
123
- return uploadedParts;
124
- });
125
- }
126
- upload(dto) {
127
- return __awaiter(this, void 0, void 0, function* () {
128
- // 1. Create a multipart upload
129
- const { uploadId } = yield this.createUpload({
86
+ partNumber++;
87
+ const start = (partNumber - 1) * partSize;
88
+ const end = Math.min(start + partSize, dto.buffer.byteLength);
89
+ const partBuffer = dto.buffer.subarray(start, end);
90
+ const uploadedPart = await this.createUploadPart({
130
91
  appBundleFileId: dto.appBundleFileId,
131
92
  appBundleId: dto.appBundleId,
132
93
  appId: dto.appId,
133
- });
134
- // 2. Upload the file in parts
135
- const parts = yield this.createUploadParts({
136
- appBundleFileId: dto.appBundleFileId,
137
- appBundleId: dto.appBundleId,
138
- appId: dto.appId,
139
- buffer: dto.buffer,
94
+ buffer: partBuffer,
140
95
  name: dto.name,
141
- uploadId,
142
- });
143
- // 3. Complete the upload
144
- yield this.completeUpload({
145
- appBundleFileId: dto.appBundleFileId,
146
- appBundleId: dto.appBundleId,
147
- appId: dto.appId,
148
- parts,
149
- uploadId,
96
+ partNumber,
97
+ uploadId: dto.uploadId,
150
98
  });
99
+ uploadedParts.push(uploadedPart);
100
+ await uploadNextPart();
101
+ };
102
+ const uploadPartPromises = Array.from({ length: MAX_CONCURRENT_UPLOADS });
103
+ for (let i = 0; i < MAX_CONCURRENT_UPLOADS; i++) {
104
+ uploadPartPromises[i] = uploadNextPart();
105
+ }
106
+ await Promise.all(uploadPartPromises);
107
+ return uploadedParts;
108
+ }
109
+ async upload(dto) {
110
+ // 1. Create a multipart upload
111
+ const { uploadId } = await this.createUpload({
112
+ appBundleFileId: dto.appBundleFileId,
113
+ appBundleId: dto.appBundleId,
114
+ appId: dto.appId,
115
+ });
116
+ // 2. Upload the file in parts
117
+ const parts = await this.createUploadParts({
118
+ appBundleFileId: dto.appBundleFileId,
119
+ appBundleId: dto.appBundleId,
120
+ appId: dto.appId,
121
+ buffer: dto.buffer,
122
+ name: dto.name,
123
+ uploadId,
124
+ });
125
+ // 3. Complete the upload
126
+ await this.completeUpload({
127
+ appBundleFileId: dto.appBundleFileId,
128
+ appBundleId: dto.appBundleId,
129
+ appId: dto.appId,
130
+ parts,
131
+ uploadId,
151
132
  });
152
133
  }
153
134
  }
154
- const appBundleFilesService = new AppBundleFilesServiceImpl(http_client_1.default);
155
- exports.default = appBundleFilesService;
135
+ const appBundleFilesService = new AppBundleFilesServiceImpl(httpClient);
136
+ export default appBundleFilesService;