bdy 1.16.15-dev → 1.16.17-dev

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.16.15-dev",
4
+ "version": "1.16.17-dev",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "scripts": {
@@ -31,6 +31,7 @@
31
31
  "eventsource": "4.0.0",
32
32
  "fastify": "4.28.1",
33
33
  "fdir": "6.5.0",
34
+ "open": "11.0.0",
34
35
  "fflate": "0.8.2",
35
36
  "human-id": "^4.1.3",
36
37
  "isbinaryfile": "5.0.2",
@@ -21,18 +21,24 @@ class ApiClient {
21
21
  },
22
22
  });
23
23
  }
24
- async request(method, path, body, parseResponseBody = false, rawResponseBody = false) {
25
- const headers = {
26
- authorization: `Bearer ${this.token}`,
27
- };
24
+ async request(method, path, body, parseResponseBody = false, rawResponseBody = false, httpUrlEncoded = false) {
25
+ const headers = {};
26
+ if (this.token)
27
+ headers.authorization = `Bearer ${this.token}`;
28
28
  let bodyParsed = undefined;
29
29
  if (body) {
30
30
  if (body instanceof undici_1.FormData) {
31
31
  bodyParsed = body;
32
32
  }
33
33
  else {
34
- headers['content-type'] = 'application/json; charset=utf-8';
35
- bodyParsed = JSON.stringify(body);
34
+ if (httpUrlEncoded) {
35
+ headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8';
36
+ bodyParsed = new URLSearchParams(body).toString();
37
+ }
38
+ else {
39
+ headers['content-type'] = 'application/json; charset=utf-8';
40
+ bodyParsed = JSON.stringify(body);
41
+ }
36
42
  }
37
43
  }
38
44
  const opts = {
@@ -45,7 +51,7 @@ class ApiClient {
45
51
  let responseBody;
46
52
  logger_1.default.debug(`API CLIENT: ${method} ${this.baseUrl.protocol}//${this.baseUrl.host}${path}`);
47
53
  logger_1.default.debug(headers);
48
- logger_1.default.debug(body);
54
+ logger_1.default.debug(bodyParsed);
49
55
  try {
50
56
  const r = await this.client.request(opts);
51
57
  status = r.statusCode;
@@ -101,7 +107,7 @@ class ApiClient {
101
107
  else
102
108
  throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
103
109
  }
104
- if (status === 200 || status === 201) {
110
+ if ([200, 201].includes(status)) {
105
111
  if (parseResponseBody) {
106
112
  try {
107
113
  const b = await responseBody.json();
@@ -132,9 +138,6 @@ class ApiClient {
132
138
  throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
133
139
  }
134
140
  }
135
- async getPipelineByIdentifier(workspace, project, identifier) {
136
- return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/identifiers?project=${encodeURIComponent(project)}&pipeline=${encodeURIComponent(identifier)}`, null, true);
137
- }
138
141
  async getPipelineRun(workspace, project, pipelineId, executionId) {
139
142
  return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/projects/${encodeURIComponent(project)}/pipelines/${encodeURIComponent(pipelineId)}/executions/${encodeURIComponent(executionId)}`, null, true);
140
143
  }
@@ -172,6 +175,28 @@ class ApiClient {
172
175
  async stopSandbox(workspace, sandboxId) {
173
176
  return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/stop`, {}, true);
174
177
  }
178
+ async registerApp(name, redirectUrl) {
179
+ return await this.request('POST', '/auth/register', {
180
+ redirect_uris: [redirectUrl],
181
+ client_name: name,
182
+ grant_types: ['authorization_code', 'refresh_token'],
183
+ response_types: ['code'],
184
+ token_endpoint_auth_method: "client_secret_basic",
185
+ token_expires_in: 3600
186
+ }, true);
187
+ }
188
+ async getApp(clientId) {
189
+ return await this.request('GET', `/auth/register/${encodeURIComponent(clientId)}`, null, true);
190
+ }
191
+ async exchangeAppToken(code, clientId, clientSecret, redirectUrl) {
192
+ return await this.request('POST', '/oauth2/token', {
193
+ grant_type: 'authorization_code',
194
+ code,
195
+ client_id: clientId,
196
+ client_secret: clientSecret,
197
+ redirect_uri: redirectUrl
198
+ }, true, false, true);
199
+ }
175
200
  async restartSandbox(workspace, sandboxId) {
176
201
  return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/restart`, {}, true);
177
202
  }
@@ -184,9 +209,6 @@ class ApiClient {
184
209
  async listSandboxCommands(workspace, sandboxId) {
185
210
  return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands`, null, true);
186
211
  }
187
- async getSandboxCommandLogsUrl(workspace, sandboxId, commandId) {
188
- return `${this.baseUrl.origin}/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands/${encodeURIComponent(commandId)}/logs`;
189
- }
190
212
  async streamSandboxCommandLogs(workspace, sandboxId, commandId, follow = true) {
191
213
  let q = '';
192
214
  if (follow)
@@ -280,8 +302,79 @@ class ApiClient {
280
302
  async getWorkspaces() {
281
303
  return await this.request('GET', '/workspaces', null, true);
282
304
  }
305
+ async getPackages(workspace, project) {
306
+ let query = '';
307
+ if (project)
308
+ query += `?project_name=${encodeURIComponent(project)}`;
309
+ return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages${query}`, null, true);
310
+ }
283
311
  async getProjects(workspace) {
284
312
  return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/projects`, null, true);
285
313
  }
314
+ async getResourceByIdentifier(workspace, params) {
315
+ let query = '';
316
+ Object.keys(params).forEach((key) => {
317
+ if (!query)
318
+ query += '?';
319
+ else
320
+ query += '&';
321
+ query += encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
322
+ });
323
+ return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/identifiers${query}`, null, true);
324
+ }
325
+ async getPipelineByIdentifier(workspace, project, identifier) {
326
+ return await this.getResourceByIdentifier(workspace, { project, pipeline: identifier });
327
+ }
328
+ async getPackageVersionByIdentifier(workspace, project, pkg, version) {
329
+ const opts = {
330
+ package: pkg,
331
+ };
332
+ if (project)
333
+ opts.project = project;
334
+ if (version)
335
+ opts.package_version = version;
336
+ return await this.getResourceByIdentifier(workspace, opts);
337
+ }
338
+ async getPackageVersion(workspace, pkgId, versionId) {
339
+ return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions/${encodeURIComponent(versionId)}`, null, true);
340
+ }
341
+ async getPackageLatest(workspace, pkgId) {
342
+ const res = await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions?page=1&per_page=1`, null, true);
343
+ if (res && res.versions && res.versions.length > 0) {
344
+ return res.versions[0];
345
+ }
346
+ return null;
347
+ }
348
+ async downloadPackageVersion(workspace, pkgId, versionId) {
349
+ return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions/${encodeURIComponent(versionId)}/download`, null, false, true);
350
+ }
351
+ async postPackageVersion(workspace, pkgId, version) {
352
+ return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions`, {
353
+ version
354
+ }, true);
355
+ }
356
+ async postPackageVersionZip(workspace, pkgId, versionId, file) {
357
+ const form = new undici_1.FormData();
358
+ form.append('file', file);
359
+ return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions/${versionId}/upload`, form, true);
360
+ }
361
+ async postPackage(workspace, project, identifier) {
362
+ const body = {
363
+ name: identifier,
364
+ identifier,
365
+ type: 'FILE',
366
+ scope: 'WORKSPACE',
367
+ authorization: {
368
+ type: 'BUDDY'
369
+ }
370
+ };
371
+ if (project) {
372
+ body.project = {
373
+ name: project
374
+ };
375
+ body.scope = 'PROJECT';
376
+ }
377
+ return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/packages`, body, true);
378
+ }
286
379
  }
287
380
  exports.default = ApiClient;
@@ -6,21 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const cfg_1 = __importDefault(require("../tunnel/cfg"));
7
7
  const output_1 = __importDefault(require("../output"));
8
8
  const client_1 = __importDefault(require("../api/client"));
9
+ const node_http_1 = __importDefault(require("node:http"));
10
+ const open_1 = __importDefault(require("open"));
9
11
  const texts_1 = require("../texts");
10
12
  const utils_1 = require("../utils");
11
13
  const input_1 = __importDefault(require("../input"));
12
- function getSecurityUrl(region, baseUrl) {
13
- switch (region) {
14
- case utils_1.REST_API_REGION.US:
15
- return 'https://app.buddy.works/security';
16
- case utils_1.REST_API_REGION.EU:
17
- return 'https://eu.buddy.works/security';
18
- case utils_1.REST_API_REGION.AS:
19
- return 'https://asia.buddy.works/security';
20
- default:
21
- return `https://${baseUrl}/security`;
22
- }
23
- }
14
+ const OAUTH_CLIENT_APP_PORT = 7596;
15
+ const OAUTH_CLIENT_APP_HOST = 'localhost';
16
+ const OAUTH_CLIENT_APP_REDIRECT_URL = `http://localhost:${OAUTH_CLIENT_APP_PORT}`;
17
+ const OAUTH_CLIENT_APP_SCOPES = 'WORKSPACE USER_INFO EXECUTION_MANAGE SANDBOX_MANAGE PACKAGE_MANAGE';
24
18
  function normalizeBaseUrl(url) {
25
19
  let normalized = url.trim();
26
20
  normalized = normalized.replace(/^https?:\/\//i, '');
@@ -52,10 +46,104 @@ async function restApiBaseUrl() {
52
46
  }
53
47
  return `${normalized}/api`;
54
48
  }
55
- async function inputToken(region, baseUrl) {
56
- const securityUrl = getSecurityUrl(region, baseUrl);
57
- output_1.default.normal((0, texts_1.TXT_LOGIN_ENTER_TOKEN)(securityUrl));
58
- return await output_1.default.inputString();
49
+ async function oauthServer(api, clientId, clientSecret) {
50
+ return new Promise((resolve, reject) => {
51
+ const s = node_http_1.default.createServer(async (req, res) => {
52
+ const url = new URL(req.url || '', `http://${OAUTH_CLIENT_APP_HOST}`);
53
+ const urlCode = url.searchParams.get('code');
54
+ if (!urlCode) {
55
+ res.end(texts_1.ERR_LOGIN_HTTP_FAILED);
56
+ s.close();
57
+ reject(new Error(texts_1.ERR_LOGIN_HTTP_FAILED));
58
+ return;
59
+ }
60
+ const client = new client_1.default(new URL(`https://${api}`));
61
+ try {
62
+ const response = await client.exchangeAppToken(urlCode, clientId, clientSecret, OAUTH_CLIENT_APP_REDIRECT_URL);
63
+ res.end(texts_1.ERR_LOGIN_HTTP_SUCCESS);
64
+ s.close();
65
+ resolve(response.access_token);
66
+ }
67
+ catch {
68
+ res.end(texts_1.ERR_LOGIN_HTTP_FAILED);
69
+ s.close();
70
+ reject(new Error(texts_1.ERR_LOGIN_HTTP_FAILED));
71
+ return;
72
+ }
73
+ });
74
+ s.on('error', () => {
75
+ s.close();
76
+ reject(texts_1.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN);
77
+ });
78
+ s.listen(OAUTH_CLIENT_APP_PORT, OAUTH_CLIENT_APP_HOST);
79
+ const url = `https://${api}/oauth2/authorize?type=web_server&client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(OAUTH_CLIENT_APP_REDIRECT_URL)}&response_type=code&scope=${encodeURIComponent(OAUTH_CLIENT_APP_SCOPES)}`;
80
+ (0, open_1.default)(url);
81
+ });
82
+ }
83
+ async function getOrCreateApp(api) {
84
+ const client = new client_1.default(new URL(`https://${api}`));
85
+ let clientId = cfg_1.default.getApiClientId();
86
+ let clientSecret = cfg_1.default.getApiClientSecret();
87
+ if (clientId && clientSecret) {
88
+ let clear = false;
89
+ try {
90
+ const app = await client.getApp(clientId);
91
+ if (!app || !app.redirect_uris || !app.redirect_uris.includes(OAUTH_CLIENT_APP_REDIRECT_URL)) {
92
+ clear = true;
93
+ }
94
+ }
95
+ catch {
96
+ clear = true;
97
+ }
98
+ if (clear) {
99
+ clientId = null;
100
+ clientSecret = null;
101
+ }
102
+ }
103
+ if (!clientId || !clientSecret) {
104
+ const app = await client.registerApp('bdy cli app', OAUTH_CLIENT_APP_REDIRECT_URL);
105
+ clientId = app.client_id;
106
+ clientSecret = app.client_secret;
107
+ cfg_1.default.setApiClient(clientId, clientSecret);
108
+ }
109
+ return {
110
+ clientId,
111
+ clientSecret,
112
+ };
113
+ }
114
+ async function authorizeOAuth(api) {
115
+ const { clientId, clientSecret } = await getOrCreateApp(api);
116
+ return await oauthServer(api, clientId, clientSecret);
117
+ }
118
+ async function authorizeToken(api, token, workspace, project) {
119
+ const client = new client_1.default(new URL(`https://${api}`), token);
120
+ const w = await client.getWorkspaces();
121
+ if (!w.workspaces?.length) {
122
+ output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
123
+ }
124
+ if (workspace) {
125
+ const found = w.workspaces.find((w) => w.domain === workspace);
126
+ if (!found) {
127
+ output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACE_FOUND);
128
+ }
129
+ }
130
+ else {
131
+ workspace = await output_1.default.selectWorkspace(w.workspaces);
132
+ }
133
+ cfg_1.default.setApiToken(token);
134
+ cfg_1.default.setWorkspace(workspace);
135
+ const p = await client.getProjects(workspace);
136
+ if (project) {
137
+ const found = p.projects.find((p) => p.name === project);
138
+ if (!found) {
139
+ output_1.default.exitError(texts_1.ERR_LOGIN_NO_PROJECT_FOUND);
140
+ }
141
+ }
142
+ else {
143
+ project = await output_1.default.selectProject(p.projects);
144
+ }
145
+ cfg_1.default.setProject(project);
146
+ output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
59
147
  }
60
148
  const commandLogin = (0, utils_1.newCommand)('login', texts_1.DESC_COMMAND_LOGIN);
61
149
  commandLogin.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
@@ -68,9 +156,9 @@ commandLogin.action(async (options) => {
68
156
  cfg_1.default.clearLogin();
69
157
  let api = options.api || process.env.BUDDY_API_ENDPOINT;
70
158
  let region = options.region || process.env.BUDDY_REGION;
71
- let token = options.token || process.env.BUDDY_TOKEN;
72
- let workspace = options.workspace || process.env.BUDDY_WORKSPACE;
73
- let project = options.project || process.env.BUDDY_PROJECT;
159
+ const token = options.token || process.env.BUDDY_TOKEN;
160
+ const workspace = options.workspace || process.env.BUDDY_WORKSPACE;
161
+ const project = options.project || process.env.BUDDY_PROJECT;
74
162
  if (api) {
75
163
  region = utils_1.REST_API_REGION.ONPREM;
76
164
  }
@@ -96,35 +184,12 @@ commandLogin.action(async (options) => {
96
184
  }
97
185
  cfg_1.default.setBaseUrl(api);
98
186
  if (!token) {
99
- token = await inputToken(region, api);
100
- }
101
- const client = new client_1.default(new URL(`https://${api}`), token);
102
- const w = await client.getWorkspaces();
103
- if (!w.workspaces?.length) {
104
- output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
105
- }
106
- if (workspace) {
107
- const found = w.workspaces.find((w) => w.domain === workspace);
108
- if (!found) {
109
- output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACE_FOUND);
110
- }
111
- }
112
- else {
113
- workspace = await output_1.default.selectWorkspace(w.workspaces);
114
- }
115
- cfg_1.default.setApiToken(token);
116
- cfg_1.default.setWorkspace(workspace);
117
- const p = await client.getProjects(workspace);
118
- if (project) {
119
- const found = p.projects.find((p) => p.name === project);
120
- if (!found) {
121
- output_1.default.exitError(texts_1.ERR_LOGIN_NO_PROJECT_FOUND);
122
- }
187
+ output_1.default.normal(texts_1.TXT_LOGIN_OAUTH);
188
+ const token = await authorizeOAuth(api);
189
+ await authorizeToken(api, token, workspace, project);
123
190
  }
124
191
  else {
125
- project = await output_1.default.selectProject(p.projects);
192
+ await authorizeToken(api, token, workspace, project);
126
193
  }
127
- cfg_1.default.setProject(project);
128
- output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
129
194
  });
130
195
  exports.default = commandLogin;
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../utils");
7
+ const texts_1 = require("../../texts");
8
+ const input_1 = __importDefault(require("../../input"));
9
+ const client_1 = __importDefault(require("../../api/client"));
10
+ const output_1 = __importDefault(require("../../output"));
11
+ const logger_1 = __importDefault(require("../../logger"));
12
+ const path_1 = require("path");
13
+ const uuid_1 = require("uuid");
14
+ const fs_1 = __importDefault(require("fs"));
15
+ const promises_1 = __importDefault(require("stream/promises"));
16
+ const fflate_1 = require("fflate");
17
+ const commandPackageDownload = (0, utils_1.newCommand)('download', texts_1.DESC_COMMAND_PACKAGE_DOWNLOAD);
18
+ commandPackageDownload.alias('dd');
19
+ commandPackageDownload.option('-t, --token <token>', texts_1.OPTION_REST_API_TOKEN);
20
+ commandPackageDownload.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
21
+ commandPackageDownload.option('--region <region>', texts_1.OPTION_REST_API_REGION);
22
+ commandPackageDownload.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
23
+ commandPackageDownload.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
24
+ commandPackageDownload.option('-m, --merge', texts_1.OPTION_PACKAGE_DOWNLOAD_MERGE);
25
+ commandPackageDownload.option('-r, --replace', texts_1.OPTION_PACKAGE_DOWNLOAD_REPLACE);
26
+ commandPackageDownload.argument('<identifier>', texts_1.OPTION_PACKAGE_ID);
27
+ commandPackageDownload.argument('<directory>', texts_1.OPTION_PACKAGE_DOWNLOAD_PATH);
28
+ commandPackageDownload.action(async (id, path, options) => {
29
+ const token = input_1.default.restApiToken(options.token);
30
+ const baseUrl = input_1.default.restApiBaseUrl(options.api, options.region);
31
+ const workspace = input_1.default.restApiWorkspace(options.workspace);
32
+ const project = input_1.default.restApiProject(options.project, true);
33
+ const client = new client_1.default(baseUrl, token);
34
+ // eslint-disable-next-line prefer-const
35
+ let { identifier, version } = input_1.default.packageSplitIdentifier(id);
36
+ const data = await client.getPackageVersionByIdentifier(workspace, project, identifier, version);
37
+ if (!data || !data.domain) {
38
+ output_1.default.exitError(texts_1.ERR_WORKSPACE_NOT_FOUND);
39
+ }
40
+ if (project && !data.project_identifier) {
41
+ output_1.default.exitError(texts_1.ERR_PROJECT_NOT_FOUND);
42
+ }
43
+ const packageId = data.pkg_id;
44
+ if (!packageId) {
45
+ output_1.default.exitError(texts_1.ERR_PACKAGE_DOWNLOAD_NOT_FOUND);
46
+ }
47
+ let versionId = data.pkg_version_id;
48
+ if (version && !versionId) {
49
+ output_1.default.exitError(texts_1.ERR_PACKAGE_VERSION_NOT_FOUND);
50
+ }
51
+ if (!version || !versionId) {
52
+ const v = await client.getPackageLatest(workspace, packageId);
53
+ if (!v) {
54
+ output_1.default.exitError(texts_1.ERR_PACKAGE_VERSION_NOT_FOUND);
55
+ }
56
+ version = v.version;
57
+ versionId = v.id;
58
+ }
59
+ const dirPath = (0, path_1.resolve)(path);
60
+ const exists = fs_1.default.existsSync(dirPath);
61
+ if (!exists) {
62
+ try {
63
+ fs_1.default.mkdirSync(dirPath, {
64
+ recursive: true,
65
+ });
66
+ }
67
+ catch (err) {
68
+ logger_1.default.error(err);
69
+ output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_MKDIR)(dirPath));
70
+ }
71
+ }
72
+ else if (options.replace) {
73
+ try {
74
+ fs_1.default.rmSync(dirPath, {
75
+ recursive: true,
76
+ force: true,
77
+ });
78
+ fs_1.default.mkdirSync(dirPath, {
79
+ recursive: true,
80
+ });
81
+ }
82
+ catch (err) {
83
+ logger_1.default.error(err);
84
+ output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_REPLACE)(dirPath));
85
+ }
86
+ }
87
+ try {
88
+ const stat = fs_1.default.statSync(dirPath);
89
+ if (!stat.isDirectory()) {
90
+ output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_IS_FILE)(dirPath));
91
+ }
92
+ }
93
+ catch (err) {
94
+ logger_1.default.error(err);
95
+ output_1.default.exitError(texts_1.ERR_SWW);
96
+ }
97
+ let empty = true;
98
+ try {
99
+ const entries = fs_1.default.readdirSync(dirPath);
100
+ empty = !entries.length;
101
+ }
102
+ catch (err) {
103
+ logger_1.default.error(err);
104
+ output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_READDIR)(dirPath));
105
+ }
106
+ if (!empty && !options.merge) {
107
+ output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_NOT_EMPTY_DIR)(dirPath));
108
+ }
109
+ const zipPath = (0, path_1.join)((0, utils_1.getHomeDirectory)(), `${(0, uuid_1.v4)()}.zip`);
110
+ const clearZip = () => {
111
+ try {
112
+ fs_1.default.rmSync(zipPath);
113
+ }
114
+ catch {
115
+ // do nothing
116
+ }
117
+ };
118
+ output_1.default.normal(texts_1.TXT_PACKAGE_DOWNLOADING_ZIP);
119
+ const body = await client.downloadPackageVersion(workspace, packageId, versionId);
120
+ try {
121
+ await promises_1.default.pipeline(body, fs_1.default.createWriteStream(zipPath));
122
+ output_1.default.clearPreviousLine();
123
+ output_1.default.normal(texts_1.TXT_PACKAGE_DOWNLOADED_ZIP);
124
+ output_1.default.normal(texts_1.TXT_PACKAGE_UNZIPPING);
125
+ let count = 0;
126
+ await unzip(dirPath, zipPath, () => {
127
+ count += 1;
128
+ output_1.default.clearPreviousLine();
129
+ output_1.default.normal((0, texts_1.TXT_PACKAGE_UNZIPPING_COUNT)(count));
130
+ });
131
+ clearZip();
132
+ output_1.default.clearPreviousLine();
133
+ output_1.default.normal(texts_1.TXT_PACKAGE_UNZIPPED);
134
+ }
135
+ catch (err) {
136
+ logger_1.default.error(err);
137
+ clearZip();
138
+ output_1.default.exitError(texts_1.ERR_SWW);
139
+ }
140
+ output_1.default.exitSuccess((0, texts_1.TXT_PACKAGE_DOWNLOADED)(version, dirPath));
141
+ });
142
+ const unzip = (dirPath, zipPath, onFile) => {
143
+ return new Promise((resolve, reject) => {
144
+ let _startedFiles = 0;
145
+ let _finishedFiles = 0;
146
+ let _finishedStream = false;
147
+ let _finishedError = null;
148
+ let _calledResolve = false;
149
+ const rs = fs_1.default.createReadStream(zipPath);
150
+ const _finish = () => {
151
+ if (_finishedError || _finishedStream) {
152
+ try {
153
+ rs.removeAllListeners();
154
+ rs.close();
155
+ }
156
+ catch {
157
+ // do nothing
158
+ }
159
+ }
160
+ if (_calledResolve)
161
+ return;
162
+ if (_finishedError) {
163
+ _calledResolve = true;
164
+ reject(_finishedError);
165
+ return;
166
+ }
167
+ if (_finishedStream && _startedFiles === _finishedFiles) {
168
+ _calledResolve = true;
169
+ resolve();
170
+ }
171
+ };
172
+ const finishFile = (err, fws) => {
173
+ if (!_finishedError && err)
174
+ _finishedError = err;
175
+ _finishedFiles += 1;
176
+ if (fws) {
177
+ try {
178
+ fws.removeAllListeners();
179
+ fws.close();
180
+ }
181
+ catch {
182
+ // do nothing
183
+ }
184
+ }
185
+ onFile();
186
+ _finish();
187
+ };
188
+ const finishStream = (err) => {
189
+ if (!_finishedError && err)
190
+ _finishedError = err;
191
+ _finishedStream = true;
192
+ _finish();
193
+ };
194
+ const unzip = new fflate_1.Unzip(async (file) => {
195
+ if (_finishedError)
196
+ return;
197
+ _startedFiles += 1;
198
+ const fullPath = (0, path_1.join)(dirPath, file.name);
199
+ const parentPath = (0, path_1.dirname)(fullPath);
200
+ let fws;
201
+ try {
202
+ await fs_1.default.promises.rm(fullPath, {
203
+ recursive: true,
204
+ force: true,
205
+ });
206
+ }
207
+ catch {
208
+ // do nothing
209
+ }
210
+ try {
211
+ if (fullPath.endsWith('/')) {
212
+ await fs_1.default.promises.mkdir(fullPath, {
213
+ recursive: true,
214
+ });
215
+ finishFile();
216
+ return;
217
+ }
218
+ await fs_1.default.promises.mkdir(parentPath, {
219
+ recursive: true,
220
+ });
221
+ fws = fs_1.default.createWriteStream(fullPath, {
222
+ flags: 'w',
223
+ });
224
+ fws.on('error', (err) => {
225
+ finishFile(err, fws);
226
+ });
227
+ }
228
+ catch (err) {
229
+ finishFile(err, fws);
230
+ return;
231
+ }
232
+ file.ondata = (err, data, final) => {
233
+ if (_finishedError)
234
+ return;
235
+ if (err)
236
+ finishFile(err, fws);
237
+ else {
238
+ if (fws)
239
+ fws.write(data);
240
+ if (final)
241
+ finishFile(null, fws);
242
+ }
243
+ };
244
+ file.start();
245
+ });
246
+ unzip.register(fflate_1.AsyncUnzipInflate);
247
+ rs.on('data', (chunk) => {
248
+ unzip.push(chunk, false);
249
+ });
250
+ rs.on('error', (err) => {
251
+ finishStream(err);
252
+ });
253
+ rs.on('end', () => {
254
+ unzip.push(new Uint8Array(0), true);
255
+ finishStream();
256
+ });
257
+ });
258
+ };
259
+ exports.default = commandPackageDownload;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const output_1 = __importDefault(require("../../output"));
7
+ const client_1 = __importDefault(require("../../api/client"));
8
+ const texts_1 = require("../../texts");
9
+ const utils_1 = require("../../utils");
10
+ const input_1 = __importDefault(require("../../input"));
11
+ const commandPackageList = (0, utils_1.newCommand)('list', texts_1.DESC_COMMAND_PACKAGE_LIST);
12
+ commandPackageList.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
13
+ commandPackageList.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
14
+ commandPackageList.option('--region <region>', texts_1.OPTION_REST_API_REGION);
15
+ commandPackageList.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
16
+ commandPackageList.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
17
+ commandPackageList.alias('ls');
18
+ commandPackageList.action(async (options) => {
19
+ const token = input_1.default.restApiToken(options.token);
20
+ const baseUrl = input_1.default.restApiBaseUrl(options.api, options.region);
21
+ const workspace = input_1.default.restApiWorkspace(options.workspace);
22
+ const project = input_1.default.restApiProject(options.project, true);
23
+ const client = new client_1.default(baseUrl, token);
24
+ const response = await client.getPackages(workspace, project);
25
+ if (!response.packages || response.packages.length === 0) {
26
+ output_1.default.exitError(texts_1.ERR_COMMAND_PACKAGE_NO_PROJECTS);
27
+ }
28
+ const data = [['NAME', 'IDENTIFIER']];
29
+ for (const pkg of response.packages) {
30
+ data.push([pkg.name, pkg.identifier]);
31
+ }
32
+ output_1.default.table(data);
33
+ output_1.default.exitNormal();
34
+ });
35
+ exports.default = commandPackageList;