bdy 1.22.44-dev-distro → 1.22.44-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.
Files changed (30) hide show
  1. package/distTs/package.json +1 -1
  2. package/distTs/src/command/artifact/get.js +16 -9
  3. package/distTs/src/command/artifact/list.js +23 -8
  4. package/distTs/src/command/artifact/version/get.js +20 -13
  5. package/distTs/src/command/artifact/version/list.js +19 -12
  6. package/distTs/src/command/distro/list.js +18 -11
  7. package/distTs/src/command/distro/route/list.js +22 -13
  8. package/distTs/src/command/domain/get.js +17 -11
  9. package/distTs/src/command/domain/list.js +13 -6
  10. package/distTs/src/command/project/get.js +18 -0
  11. package/distTs/src/command/project/list.js +13 -6
  12. package/distTs/src/command/project/set.js +31 -0
  13. package/distTs/src/command/sandbox/app/list.js +13 -7
  14. package/distTs/src/command/sandbox/app/status.js +10 -4
  15. package/distTs/src/command/sandbox/endpoint/get.js +61 -52
  16. package/distTs/src/command/sandbox/endpoint/list.js +18 -12
  17. package/distTs/src/command/sandbox/exec/list.js +22 -16
  18. package/distTs/src/command/sandbox/exec/status.js +18 -9
  19. package/distTs/src/command/sandbox/get/yaml.js +30 -0
  20. package/distTs/src/command/sandbox/get.js +26 -18
  21. package/distTs/src/command/sandbox/list.js +21 -15
  22. package/distTs/src/command/sandbox/snapshot/get.js +19 -13
  23. package/distTs/src/command/sandbox/snapshot/list.js +17 -11
  24. package/distTs/src/command/sandbox/status.js +11 -5
  25. package/distTs/src/command/vt/scrape.js +193 -0
  26. package/distTs/src/command/whoami.js +17 -8
  27. package/distTs/src/command/workspace/list.js +14 -8
  28. package/distTs/src/output.js +8 -6
  29. package/package.json +1 -1
  30. package/distTs/src/command/pipeline/run/apply.js +0 -62
@@ -0,0 +1,193 @@
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 commander_1 = require("commander");
8
+ const texts_1 = require("../../texts");
9
+ const validation_1 = require("../../visualTest/validation");
10
+ const output_1 = __importDefault(require("../../output"));
11
+ const requests_1 = require("../../visualTest/requests");
12
+ const zod_1 = require("zod");
13
+ const node_zlib_1 = require("node:zlib");
14
+ const tar_stream_1 = __importDefault(require("tar-stream"));
15
+ const promises_1 = require("node:stream/promises");
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = __importDefault(require("node:path"));
18
+ const promises_2 = require("node:fs/promises");
19
+ const commandScrape = (0, utils_1.newCommand)('scrape', texts_1.DESC_COMMAND_VT_SCRAPE);
20
+ commandScrape.argument('<url>', texts_1.OPTION_SCRAPE_URL);
21
+ commandScrape.option('--follow', texts_1.OPTION_SCRAPE_FOLLOW, false);
22
+ commandScrape.addOption(new commander_1.Option('--outputType <type>', texts_1.OPTION_SCRAPE_OUTPUT_TYPE)
23
+ .choices(['jpeg', 'png', 'md', 'html'])
24
+ .makeOptionMandatory());
25
+ commandScrape.option('--quality <quality>', texts_1.OPTION_SCRAPE_QUALITY);
26
+ commandScrape.option('--fullPage', texts_1.OPTION_SCRAPE_FULL_PAGE, false);
27
+ commandScrape.option('--cssSelector <selector>', texts_1.OPTION_SCRAPE_CSS_SELECTOR);
28
+ commandScrape.option('--xpathSelector <selector>', texts_1.OPTION_SCRAPE_XPATH_SELECTOR);
29
+ commandScrape.addOption(new commander_1.Option('--browser <browser>', texts_1.OPTION_SCRAPE_BROWSER)
30
+ .choices(['chrome', 'firefox', 'safari'])
31
+ .default('chrome'));
32
+ commandScrape.option('--viewport <viewport>', texts_1.OPTION_SCRAPE_VIEWPORT, '1920x1080');
33
+ commandScrape.option('--devicePixelRatio <ratio>', texts_1.OPTION_SCRAPE_DEVICE_PIXEL_RATIO, '1');
34
+ commandScrape.option('--waitForElement <selector>', texts_1.OPTION_SCRAPE_WAIT_FOR_ELEMENT);
35
+ commandScrape.option('--darkMode', texts_1.OPTION_SCRAPE_DARK_MODE, false);
36
+ commandScrape.option('--delay <delay>', texts_1.OPTION_SCRAPE_DELAY, '0');
37
+ commandScrape.option('--outputDir <dir>', texts_1.OPTION_SCRAPE_OUTPUT_DIR, '.');
38
+ commandScrape.action(async (inputUrl, options) => {
39
+ if (!(0, validation_1.checkToken)()) {
40
+ output_1.default.exitError(texts_1.ERR_MISSING_VT_TOKEN);
41
+ }
42
+ const { url, follow, outputType, quality, outputDir, fullPage, cssSelector, xpathSelector, browser, viewport, devicePixelRatio, darkMode, delay, waitForElement, } = validateInputAndOptions(inputUrl, options);
43
+ try {
44
+ const { buildId } = await (0, requests_1.sendScrap)(url, outputType, follow, quality, fullPage, cssSelector, xpathSelector, browser, viewport, devicePixelRatio, darkMode, delay, waitForElement);
45
+ output_1.default.normal('Starting scrape session');
46
+ const status = await watchSessionStatus(buildId);
47
+ if (!status.ok) {
48
+ output_1.default.exitError(`Unexpected error while watching session status: ${status.error}`);
49
+ }
50
+ output_1.default.normal('Downloading scrape package');
51
+ const scrapPackageStream = await (0, requests_1.downloadScrapPackage)(buildId);
52
+ const brotliDecompressor = (0, node_zlib_1.createBrotliDecompress)();
53
+ const unpack = tar_stream_1.default.extract();
54
+ unpack.on('entry', async (header, stream, next) => {
55
+ const currentDir = process.cwd();
56
+ const preparedOutputDir = outputDir.startsWith('.')
57
+ ? node_path_1.default.join(currentDir, outputDir)
58
+ : outputDir;
59
+ const newFilePath = node_path_1.default.join(preparedOutputDir, header.name);
60
+ try {
61
+ if (header.type === 'file') {
62
+ await (0, promises_2.mkdir)(node_path_1.default.dirname(newFilePath), { recursive: true });
63
+ const fileWriteStream = (0, node_fs_1.createWriteStream)(newFilePath);
64
+ await (0, promises_1.pipeline)(stream, fileWriteStream);
65
+ next();
66
+ }
67
+ else {
68
+ stream.resume();
69
+ next();
70
+ }
71
+ }
72
+ catch (entryError) {
73
+ output_1.default.error(`Error processing entry ${header.name}: ${entryError}`);
74
+ next(entryError);
75
+ }
76
+ });
77
+ await (0, promises_1.pipeline)(scrapPackageStream, brotliDecompressor, unpack);
78
+ output_1.default.exitSuccess('Downloading scrape package finished');
79
+ }
80
+ catch (error) {
81
+ output_1.default.exitError(`${error}`);
82
+ }
83
+ });
84
+ function validateInputAndOptions(input, options) {
85
+ const urlSchema = zod_1.z.string().url();
86
+ const optionsSchema = zod_1.z.object({
87
+ follow: zod_1.z.boolean(),
88
+ outputType: zod_1.z.enum(['jpeg', 'png', 'md', 'html']),
89
+ quality: zod_1.z.coerce.number().min(1).max(100).optional(),
90
+ outputDir: zod_1.z.string().default('.'),
91
+ fullPage: zod_1.z.boolean().optional(),
92
+ cssSelector: zod_1.z.string().optional(),
93
+ xpathSelector: zod_1.z.string().optional(),
94
+ browser: zod_1.z.enum(['chrome', 'firefox', 'safari']),
95
+ viewport: zod_1.z
96
+ .string()
97
+ .refine((value) => {
98
+ const [width, height] = value.split('x');
99
+ return (width &&
100
+ height &&
101
+ !isNaN(Number(width)) &&
102
+ !isNaN(Number(height)) &&
103
+ Number(width) > 0 &&
104
+ Number(height) > 0);
105
+ }, 'Invalid viewport format, example: 1920x1080')
106
+ .transform((value) => {
107
+ const [width, height] = value.split('x');
108
+ return {
109
+ width: Number(width),
110
+ height: Number(height),
111
+ };
112
+ }),
113
+ devicePixelRatio: zod_1.z.coerce.number().min(1).max(4),
114
+ darkMode: zod_1.z.boolean(),
115
+ delay: zod_1.z.coerce.number().min(0).max(10000),
116
+ waitForElement: zod_1.z.string().optional(),
117
+ });
118
+ try {
119
+ const url = urlSchema.parse(input);
120
+ const { follow, outputType, quality, outputDir, fullPage, cssSelector, xpathSelector, browser, viewport, devicePixelRatio, darkMode, delay, waitForElement, } = optionsSchema.parse(options);
121
+ if (typeof quality === 'number' && outputType !== 'jpeg') {
122
+ output_1.default.exitError('Quality is only supported for jpeg output type, use --outputType jpeg');
123
+ }
124
+ if (cssSelector && xpathSelector) {
125
+ output_1.default.exitError('Only one of --cssSelector or --xpathSelector can be used');
126
+ }
127
+ return {
128
+ url,
129
+ follow,
130
+ outputType,
131
+ quality,
132
+ outputDir,
133
+ fullPage,
134
+ cssSelector,
135
+ xpathSelector,
136
+ browser,
137
+ viewport,
138
+ devicePixelRatio,
139
+ darkMode,
140
+ delay,
141
+ waitForElement,
142
+ };
143
+ }
144
+ catch (error) {
145
+ if (error instanceof zod_1.ZodError) {
146
+ output_1.default.exitError(error.errors.map((e) => `${e.path}: ${e.message}`).join(', '));
147
+ }
148
+ else {
149
+ throw error;
150
+ }
151
+ }
152
+ }
153
+ async function watchSessionStatus(buildId) {
154
+ return new Promise((resolve) => {
155
+ const eventSource = (0, requests_1.connectToScrapSession)(buildId);
156
+ eventSource.addEventListener('SESSION_STATUS', (event) => {
157
+ const data = JSON.parse(event.data);
158
+ if (data.status === 'GATHER_URLS_COMPLETED') {
159
+ output_1.default.normal(`Gathering URLs completed, found ${data.text} URLs`);
160
+ }
161
+ else if (data.status === 'GATHER_URLS_FAILED') {
162
+ output_1.default.error('Gathering URLs failed');
163
+ }
164
+ else if (data.status === 'SCRAPE_URL_COMPLETED') {
165
+ output_1.default.normal(`Scraping ${data.text} completed`);
166
+ }
167
+ else if (data.status === 'SCRAPE_URL_FAILED') {
168
+ output_1.default.error(`Scraping ${data.text} failed`);
169
+ }
170
+ else if (data.status === 'CREATE_PACKAGE_COMPLETED') {
171
+ output_1.default.normal('Package created');
172
+ }
173
+ else if (data.status === 'CREATE_PACKAGE_FAILED') {
174
+ output_1.default.error('Package creation failed');
175
+ }
176
+ else if (data.status === 'FINISHED') {
177
+ eventSource.close();
178
+ output_1.default.normal('Scrape session finished');
179
+ resolve({ ok: true });
180
+ }
181
+ });
182
+ eventSource.addEventListener('error', (event) => {
183
+ if (event.code) {
184
+ eventSource.close();
185
+ if (event.code === 410) {
186
+ output_1.default.normal('Scrape session finished');
187
+ }
188
+ resolve({ ok: event.code === 410, error: event.code });
189
+ }
190
+ });
191
+ });
192
+ }
193
+ exports.default = commandScrape;
@@ -10,7 +10,8 @@ const output_1 = __importDefault(require("../output"));
10
10
  const input_1 = __importDefault(require("../input"));
11
11
  const cfg_2 = __importDefault(require("../project/cfg"));
12
12
  const commandWhoami = (0, utils_1.newCommand)('whoami', texts_1.DESC_COMMAND_WHOAMI);
13
- commandWhoami.action(async () => {
13
+ commandWhoami.option('--format <text|json>', texts_1.OPTION_FORMAT);
14
+ commandWhoami.action(async (options) => {
14
15
  const workspace = cfg_1.default.getWorkspace();
15
16
  const localWorkspace = cfg_2.default.getWorkspace();
16
17
  const localProject = cfg_2.default.getProject();
@@ -20,27 +21,35 @@ commandWhoami.action(async () => {
20
21
  output_1.default.exitError(texts_1.ERR_WHOAMI_LOGOUT);
21
22
  }
22
23
  const email = await (0, utils_1.tryGetEmail)(client);
23
- output_1.default.normal(`User: ${user.name}${email ? ` (${email})` : ''}`);
24
+ const obj = {
25
+ 'User': `${user.name}${email ? ` (${email})` : ''}`
26
+ };
24
27
  if (localWorkspace) {
25
- output_1.default.normal(`Workspace: ${localWorkspace}`);
28
+ obj.Workspace = localWorkspace;
26
29
  }
27
30
  else {
28
- output_1.default.normal(`Workspace: ${!workspace ? texts_1.TXT_WHOAMI_NO_WORKSPACE : workspace}`);
31
+ obj.Workspace = !workspace ? texts_1.TXT_WHOAMI_NO_WORKSPACE : workspace;
29
32
  }
30
33
  if (localProject) {
31
- output_1.default.normal(`Project: ${localProject}`);
34
+ obj.Project = localProject;
32
35
  }
33
36
  const vtSuite = cfg_2.default.getVtSuite();
34
37
  const utSuite = cfg_2.default.getUtSuite();
35
38
  const crawlSuite = cfg_2.default.getCrawlSuite();
36
39
  if (vtSuite) {
37
- output_1.default.normal(`Visual test suite: ${vtSuite}`);
40
+ obj['Visual test suite'] = vtSuite;
38
41
  }
39
42
  if (utSuite) {
40
- output_1.default.normal(`Unit test suite: ${utSuite}`);
43
+ obj['Unit test suite'] = utSuite;
41
44
  }
42
45
  if (crawlSuite) {
43
- output_1.default.normal(`Crawl suite: ${crawlSuite}`);
46
+ obj['Crawl suite'] = crawlSuite;
47
+ }
48
+ if (options.format === 'json') {
49
+ output_1.default.json(obj);
50
+ }
51
+ else {
52
+ output_1.default.object(obj);
44
53
  }
45
54
  output_1.default.exitNormal();
46
55
  });
@@ -9,18 +9,24 @@ const utils_1 = require("../../utils");
9
9
  const input_1 = __importDefault(require("../../input"));
10
10
  const commandWorkspaceList = (0, utils_1.newCommand)('list', texts_1.DESC_COMMAND_WORKSPACE_LIST);
11
11
  commandWorkspaceList.alias('ls');
12
- commandWorkspaceList.action(async () => {
12
+ commandWorkspaceList.option('--format <text|json>', texts_1.OPTION_FORMAT);
13
+ commandWorkspaceList.action(async (options) => {
13
14
  const client = input_1.default.restApiTokenClient();
14
15
  const response = await client.getWorkspaces();
15
- if (!response.workspaces || response.workspaces.length === 0) {
16
- output_1.default.normal('No workspaces found.');
17
- output_1.default.exitNormal();
16
+ if (options.format === 'json') {
17
+ output_1.default.json(response.workspaces || []);
18
18
  }
19
- const data = [['NAME', 'DOMAIN', 'URL']];
20
- for (const ws of response.workspaces) {
21
- data.push([ws.name, ws.domain, ws.html_url]);
19
+ else {
20
+ if (!response.workspaces || response.workspaces.length === 0) {
21
+ output_1.default.normal('No workspaces found.');
22
+ output_1.default.exitNormal();
23
+ }
24
+ const data = [['NAME', 'DOMAIN', 'URL']];
25
+ for (const ws of response.workspaces) {
26
+ data.push([ws.name, ws.domain, ws.html_url]);
27
+ }
28
+ output_1.default.table(data);
22
29
  }
23
- output_1.default.table(data);
24
30
  output_1.default.exitNormal();
25
31
  });
26
32
  exports.default = commandWorkspaceList;
@@ -251,10 +251,10 @@ class Output {
251
251
  this.tunnelNonInteractive(tunnel);
252
252
  }
253
253
  static object(data) {
254
- const table = [['Field', 'Value'], ...Object.entries(data)];
255
- this.table(table);
254
+ const table = [...Object.entries(data)];
255
+ this.table(table, false);
256
256
  }
257
- static table(data) {
257
+ static table(data, firstRowBlue = true) {
258
258
  // apply padding
259
259
  for (let i = 0; i < data.length; i += 1) {
260
260
  for (let j = 0; j < data[i].length; j += 1) {
@@ -266,11 +266,13 @@ class Output {
266
266
  data[i][j] = tmp.join('\n');
267
267
  }
268
268
  }
269
- getTerminal().table(data, {
269
+ const opts = {
270
270
  fit: false,
271
271
  hasBorder: false,
272
- firstRowTextAttr: { color: 'blue' },
273
- });
272
+ };
273
+ if (firstRowBlue)
274
+ opts.firstRowTextAttr = { color: 'blue' };
275
+ getTerminal().table(data, opts);
274
276
  }
275
277
  static configTunnels(tunnels) {
276
278
  const OutputNoninteractiveConfigTunnels = require('./tunnel/output/noninteractive/config/tunnels').default;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.22.44-dev-distro",
4
+ "version": "1.22.44-dev",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "scripts": {
@@ -1,62 +0,0 @@
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 output_1 = __importDefault(require("../../../output"));
10
- const pipeline_1 = require("../../../types/pipeline");
11
- const commandPipelineRunApply = (0, utils_1.newCommand)('apply', texts_1.DESC_COMMAND_PIPELINE_RUN_APPLY);
12
- commandPipelineRunApply.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
13
- commandPipelineRunApply.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
14
- commandPipelineRunApply.option('-n, --no-wait', texts_1.OPTION_PIPELINE_RUN_NO_WAIT);
15
- commandPipelineRunApply.argument('<identifier>', texts_1.OPTION_PIPELINE_RUN_ARGUMENT);
16
- commandPipelineRunApply.argument('<run-id>', texts_1.OPTION_PIPELINE_RUN_ID);
17
- commandPipelineRunApply.argument('<run-action-id>', texts_1.OPTION_PIPELINE_RUN_ACTION_ID);
18
- commandPipelineRunApply.option('-v,--variable <variables...>', texts_1.OPTION_PIPELINE_RUN_VAR);
19
- commandPipelineRunApply.addHelpText('after', texts_1.EXAMPLE_PIPELINE_RUN_APPLY);
20
- commandPipelineRunApply.action(async (identifier, runId, runActionId, options) => {
21
- const workspace = input_1.default.restApiWorkspace(options.workspace);
22
- const project = input_1.default.restApiProject(options.project);
23
- const rid = input_1.default.pipelineRunId(runId);
24
- const variables = input_1.default.pipelineRunVariable(options.variable || [], false);
25
- const client = input_1.default.restApiTokenClient();
26
- const data = await client.getPipelineByIdentifier(workspace, project, identifier);
27
- if (!data || !data.domain) {
28
- output_1.default.exitError(texts_1.ERR_WORKSPACE_NOT_FOUND);
29
- }
30
- if (!data.project_identifier) {
31
- output_1.default.exitError(texts_1.ERR_PROJECT_NOT_FOUND);
32
- }
33
- if (!data.pipeline_id) {
34
- output_1.default.exitError(texts_1.ERR_PIPELINE_NOT_FOUND);
35
- }
36
- const a = await client.getPipelineRunActionExecution(workspace, project, data.pipeline_id, rid, runActionId);
37
- let type;
38
- if (a.status === pipeline_1.PIPELINE_RUN_STATUS.WAITING_FOR_APPLY) {
39
- type = 'APPLY';
40
- }
41
- else if (a.status === pipeline_1.PIPELINE_RUN_STATUS.WAITING_FOR_VT_SESSION) {
42
- type = 'APPROVE_VT';
43
- }
44
- else if (a.status === pipeline_1.PIPELINE_RUN_STATUS.WAITING_FOR_VARIABLES) {
45
- type = 'APPLY_VARIABLES';
46
- }
47
- else if (a.status === pipeline_1.PIPELINE_RUN_STATUS.WAITING_FOR_SETTABLE_VARIABLES) {
48
- type = 'SET_VARIABLES';
49
- }
50
- else {
51
- output_1.default.exitError(texts_1.ERR_CANT_APPLY_ACTION_EXECUTION);
52
- }
53
- const body = {
54
- operation: type,
55
- approve_action_id: runActionId,
56
- variables,
57
- };
58
- await client.pipelineRunApply(workspace, project, data.pipeline_id, rid, body);
59
- const OutputPipeline = require('../../../output/pipeline').default;
60
- await OutputPipeline.runStatus(client, workspace, project, data.pipeline_id, rid, !options.wait);
61
- });
62
- exports.default = commandPipelineRunApply;