bdy 1.17.29-dev → 1.18.0-dev-scrape-869b6rbvf

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.
@@ -3,49 +3,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const utils_1 = require("../../utils");
6
+ const utils_1 = require("../utils");
7
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");
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");
13
12
  const node_zlib_1 = require("node:zlib");
14
13
  const tar_stream_1 = __importDefault(require("tar-stream"));
15
14
  const promises_1 = require("node:stream/promises");
16
15
  const node_fs_1 = require("node:fs");
17
16
  const node_path_1 = __importDefault(require("node:path"));
18
17
  const promises_2 = require("node:fs/promises");
18
+ const context_1 = require("../visualTest/context");
19
+ const ci_info_1 = require("@buddy-works/ci-info");
20
+ const validation_2 = require("./scrape/validation");
19
21
  const commandScrape = (0, utils_1.newCommand)('scrape', texts_1.DESC_COMMAND_VT_SCRAPE);
20
- commandScrape.argument('<url>', texts_1.OPTION_SCRAPE_URL);
22
+ commandScrape.argument('[url]', texts_1.OPTION_SCRAPE_URL);
21
23
  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());
24
+ commandScrape.option('--respectRobots', texts_1.OPTION_COMPARE_RESPECT_ROBOTS, false);
25
+ commandScrape.addOption(new commander_1.Option('--outputType <type>', texts_1.OPTION_SCRAPE_OUTPUT_TYPE).choices([
26
+ 'jpeg',
27
+ 'png',
28
+ 'md',
29
+ 'html',
30
+ ]));
31
+ commandScrape.option('--outputTypes <json>', texts_1.OPTION_SCRAPE_OUTPUT_TYPES);
25
32
  commandScrape.option('--quality <quality>', texts_1.OPTION_SCRAPE_QUALITY);
26
33
  commandScrape.option('--fullPage', texts_1.OPTION_SCRAPE_FULL_PAGE, false);
27
34
  commandScrape.option('--cssSelector <selector>', texts_1.OPTION_SCRAPE_CSS_SELECTOR);
28
35
  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.addOption(new commander_1.Option('--colorScheme <scheme>', texts_1.OPTION_SCRAPE_COLOR_SCHEME).choices([
37
+ 'LIGHT',
38
+ 'DARK',
39
+ 'LIGHT_AND_DARK',
40
+ ]));
41
+ commandScrape.option('--browsers <browsers>', texts_1.OPTION_SCRAPE_BROWSERS);
42
+ commandScrape.option('--devices <devices>', texts_1.OPTION_SCRAPE_DEVICES);
43
+ commandScrape.option('--waitFor <waitFors...>', texts_1.OPTION_COMPARE_WAIT_FOR);
44
+ commandScrape.option('--cookie <cookies...>', texts_1.OPTION_COMPARE_COOKIE);
45
+ commandScrape.option('--header <headers...>', texts_1.OPTION_COMPARE_HEADER);
46
+ commandScrape.option('--localStorage <items...>', texts_1.OPTION_SCRAPE_LOCAL_STORAGE);
36
47
  commandScrape.option('--delay <delay>', texts_1.OPTION_SCRAPE_DELAY, '0');
37
48
  commandScrape.option('--outputDir <dir>', texts_1.OPTION_SCRAPE_OUTPUT_DIR, '.');
38
49
  commandScrape.action(async (inputUrl, options) => {
39
- if (!(0, validation_1.checkToken)()) {
40
- output_1.default.exitError(texts_1.ERR_MISSING_VT_TOKEN);
50
+ if (!(0, validation_1.checkToken)('scrape')) {
51
+ output_1.default.exitError(texts_1.ERR_MISSING_SCRAPE_TOKEN);
41
52
  }
42
- const { url, follow, outputType, quality, outputDir, fullPage, cssSelector, xpathSelector, browser, viewport, devicePixelRatio, darkMode, delay, waitForElement, } = validateInputAndOptions(inputUrl, options);
53
+ const { url, follow, respectRobots, outputTypes, outputDir, fullPage, colorScheme, browsers, devices, cookies, requestHeaders, delay, waitForSelectors, localStorage, } = (0, validation_2.validateInputAndOptions)(inputUrl, options);
43
54
  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');
55
+ const ciAndGitInfo = await (0, ci_info_1.getCiAndGitInfo)({});
56
+ (0, context_1.setCiAndCommitInfo)(ciAndGitInfo);
57
+ const { buildId } = await (0, requests_1.sendScrap)(url, follow, respectRobots, outputTypes, fullPage, colorScheme, browsers, devices, cookies, requestHeaders, delay, waitForSelectors, localStorage);
46
58
  const status = await watchSessionStatus(buildId);
47
59
  if (!status.ok) {
48
- output_1.default.exitError(`Unexpected error while watching session status: ${status.error}`);
60
+ output_1.default.exitError(`Scrape session failed: ${status.error}`);
49
61
  }
50
62
  output_1.default.normal('Downloading scrape package');
51
63
  const scrapPackageStream = await (0, requests_1.downloadScrapPackage)(buildId);
@@ -81,81 +93,15 @@ commandScrape.action(async (inputUrl, options) => {
81
93
  output_1.default.exitError(`${error}`);
82
94
  }
83
95
  });
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
96
  async function watchSessionStatus(buildId) {
154
97
  return new Promise((resolve) => {
155
98
  const eventSource = (0, requests_1.connectToScrapSession)(buildId);
156
99
  eventSource.addEventListener('SESSION_STATUS', (event) => {
157
100
  const data = JSON.parse(event.data);
158
- if (data.status === 'GATHER_URLS_COMPLETED') {
101
+ if (data.status === 'STARTED') {
102
+ output_1.default.normal('Scrape session started');
103
+ }
104
+ else if (data.status === 'GATHER_URLS_COMPLETED') {
159
105
  output_1.default.normal(`Gathering URLs completed, found ${data.text} URLs`);
160
106
  }
161
107
  else if (data.status === 'GATHER_URLS_FAILED') {
@@ -173,6 +119,10 @@ async function watchSessionStatus(buildId) {
173
119
  else if (data.status === 'CREATE_PACKAGE_FAILED') {
174
120
  output_1.default.error('Package creation failed');
175
121
  }
122
+ else if (data.status === 'ERROR') {
123
+ eventSource.close();
124
+ resolve({ ok: false, error: data.text });
125
+ }
176
126
  else if (data.status === 'FINISHED') {
177
127
  eventSource.close();
178
128
  output_1.default.normal('Scrape session finished');
@@ -10,7 +10,7 @@ const requests_1 = require("../../visualTest/requests");
10
10
  const output_1 = __importDefault(require("../../output"));
11
11
  const commandVtClose = (0, utils_1.newCommand)('close', texts_1.DESC_COMMAND_VT_CLOSE);
12
12
  commandVtClose.action(async () => {
13
- if (!(0, validation_1.checkToken)()) {
13
+ if (!(0, validation_1.checkToken)('vt')) {
14
14
  output_1.default.exitError(texts_1.ERR_MISSING_VT_TOKEN);
15
15
  }
16
16
  if (!(0, validation_1.checkBuildId)()) {
@@ -7,7 +7,7 @@ exports.validateOptions = validateOptions;
7
7
  exports.checkIfMinimalOptionsAreProvided = checkIfMinimalOptionsAreProvided;
8
8
  const zod_1 = require("zod");
9
9
  const output_1 = __importDefault(require("../../../output"));
10
- const DEFAULT_SCOPE = '**';
10
+ const validation_1 = require("../shared/validation");
11
11
  const optionsSchema = zod_1.z.object({
12
12
  urls: zod_1.z.string().optional(),
13
13
  sitemap: zod_1.z.string().optional(),
@@ -19,102 +19,9 @@ const optionsSchema = zod_1.z.object({
19
19
  message: "Ignore option must follow pattern '[scope::]type=value' where type must be CSS or XPATH (scope is optional)",
20
20
  }))
21
21
  .optional()
22
- .transform((value) => value?.map((v) => {
23
- let scope, type, value;
24
- if (v.includes('::CSS=') || v.includes('::XPATH=')) {
25
- const [scopePart, ...rest] = v.split('::');
26
- const [typePart, ...valuePart] = rest.join('::').split('=');
27
- type = typePart;
28
- value = valuePart.join('=');
29
- scope = scopePart;
30
- }
31
- else {
32
- const [typePart, ...valuePart] = v.split('=');
33
- type = typePart;
34
- value = valuePart.join('=');
35
- scope = DEFAULT_SCOPE;
36
- }
37
- return { scope, type, value };
38
- })),
39
- cookie: zod_1.z
40
- .array(zod_1.z
41
- .string()
42
- .max(4096, {
43
- message: 'Cookie must be less than 4096 characters',
44
- })
45
- .regex(/^(?:([^:]+)::)?(.+)$/, {
46
- message: "Cookie option must follow pattern '[scope::]cookie_value' (scope is optional)",
47
- }))
48
- .optional()
49
- .transform((value) => value?.map((v) => {
50
- let scope = DEFAULT_SCOPE;
51
- let cookieValue = v;
52
- if (v.includes('::')) {
53
- const [scopePart, valuePart] = v.split('::');
54
- scope = scopePart.trim();
55
- cookieValue = valuePart.trim();
56
- }
57
- // Parse cookie string into components
58
- const cookieParts = cookieValue.split(';').map((part) => part.trim());
59
- const mainPart = cookieParts[0].split('=');
60
- const key = mainPart[0].trim();
61
- const value = mainPart[1].trim();
62
- const cookie = {
63
- scope,
64
- key,
65
- value,
66
- httpOnly: false,
67
- secure: false,
68
- };
69
- // Process additional cookie attributes
70
- for (let i = 1; i < cookieParts.length; i++) {
71
- const part = cookieParts[i].toLowerCase();
72
- if (part === 'httponly') {
73
- cookie.httpOnly = true;
74
- }
75
- else if (part === 'secure') {
76
- cookie.secure = true;
77
- }
78
- else if (part.startsWith('domain=')) {
79
- cookie.domain = part.substring(7);
80
- }
81
- else if (part.startsWith('path=')) {
82
- cookie.path = part.substring(5);
83
- }
84
- else if (part.startsWith('samesite=')) {
85
- const sameSiteValue = part.substring(9);
86
- if (['strict', 'lax', 'none'].includes(sameSiteValue.toLowerCase())) {
87
- cookie.sameSite = (sameSiteValue.charAt(0).toUpperCase() +
88
- sameSiteValue.slice(1).toLowerCase());
89
- }
90
- }
91
- }
92
- return cookie;
93
- })),
94
- header: zod_1.z
95
- .array(zod_1.z.string().regex(/^(?:([^:]+)::)?(.+)$/, {
96
- message: "Header option must follow pattern '[scope::]header_value' (scope is optional)",
97
- }))
98
- .optional()
99
- .transform((value) => value?.map((v) => {
100
- if (v.includes('::')) {
101
- const [scope, headerValue] = v.split('::');
102
- const [name, value] = headerValue.split('=');
103
- return {
104
- scope: scope.trim(),
105
- key: name.trim(),
106
- value: value.trim(),
107
- };
108
- }
109
- else {
110
- const [name, value] = v.split('=');
111
- return {
112
- scope: DEFAULT_SCOPE,
113
- key: name.trim(),
114
- value: value.trim(),
115
- };
116
- }
117
- })),
22
+ .transform(validation_1.parseScopedSelector),
23
+ cookie: validation_1.cookieSchema,
24
+ header: validation_1.headerSchema,
118
25
  delay: zod_1.z
119
26
  .array(zod_1.z.string().regex(/^(?:([^:]+)::)?(\d+)$/, {
120
27
  message: "Delay option must follow pattern '[scope::]milliseconds' (scope is optional)",
@@ -126,31 +33,10 @@ const optionsSchema = zod_1.z.object({
126
33
  return { scope: scope.trim(), value: Number(milliseconds) };
127
34
  }
128
35
  else {
129
- return { scope: DEFAULT_SCOPE, value: Number(v) };
130
- }
131
- })),
132
- waitFor: zod_1.z
133
- .array(zod_1.z.string().regex(/^(?:([^:]+)::)?(?:(CSS|XPATH))=(.+)$/, {
134
- message: "WaitFor option must follow pattern '[scope::]type=value' where type must be CSS or XPATH (scope is optional)",
135
- }))
136
- .optional()
137
- .transform((value) => value?.map((v) => {
138
- let scope, type, value;
139
- if (v.includes('::CSS=') || v.includes('::XPATH=')) {
140
- const [scopePart, ...rest] = v.split('::');
141
- const [typePart, ...valuePart] = rest.join('::').split('=');
142
- type = typePart;
143
- value = valuePart.join('=');
144
- scope = scopePart;
145
- }
146
- else {
147
- const [typePart, ...valuePart] = v.split('=');
148
- type = typePart;
149
- value = valuePart.join('=');
150
- scope = DEFAULT_SCOPE;
36
+ return { scope: validation_1.DEFAULT_SCOPE, value: Number(v) };
151
37
  }
152
- return { scope, type, value };
153
38
  })),
39
+ waitFor: validation_1.waitForSchema,
154
40
  ignoreUrls: zod_1.z.array(zod_1.z.string()).optional(),
155
41
  dryRun: zod_1.z.boolean().optional(),
156
42
  });
@@ -28,7 +28,7 @@ commandVtCompare.option('--delay <delays...>', texts_1.OPTION_COMPARE_DELAY);
28
28
  commandVtCompare.option('--waitFor <waitFors...>', texts_1.OPTION_COMPARE_WAIT_FOR);
29
29
  commandVtCompare.action(async (options) => {
30
30
  const validatedOptions = (0, validation_2.validateOptions)(options);
31
- if (!(0, validation_1.checkToken)()) {
31
+ if (!(0, validation_1.checkToken)('vt')) {
32
32
  output_1.default.exitError(texts_1.ERR_MISSING_VT_TOKEN);
33
33
  }
34
34
  if (!(0, validation_2.checkIfMinimalOptionsAreProvided)(validatedOptions)) {
@@ -29,7 +29,7 @@ commandVtExec.action(async (command, options) => {
29
29
  catch (error) {
30
30
  output_1.default.exitError(`${error}`);
31
31
  }
32
- if (!(0, validation_1.checkToken)()) {
32
+ if (!(0, validation_1.checkToken)('vt')) {
33
33
  output_1.default.exitError(texts_1.ERR_MISSING_VT_TOKEN);
34
34
  }
35
35
  if (!(0, validation_1.checkParallel)()) {
@@ -0,0 +1,118 @@
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
+ exports.waitForSchema = exports.headerSchema = exports.cookieSchema = exports.DEFAULT_SCOPE = void 0;
7
+ exports.parseScopedSelector = parseScopedSelector;
8
+ exports.parseScopedKeyValue = parseScopedKeyValue;
9
+ const zod_1 = require("zod");
10
+ const output_1 = __importDefault(require("../../../output"));
11
+ exports.DEFAULT_SCOPE = '**';
12
+ function parseScopedSelector(value) {
13
+ return value?.map((v) => {
14
+ let scope, type, selectorValue;
15
+ if (v.includes('::CSS=') || v.includes('::XPATH=')) {
16
+ const [scopePart, ...rest] = v.split('::');
17
+ const [typePart, ...valuePart] = rest.join('::').split('=');
18
+ type = typePart;
19
+ selectorValue = valuePart.join('=');
20
+ scope = scopePart;
21
+ }
22
+ else {
23
+ const [typePart, ...valuePart] = v.split('=');
24
+ type = typePart;
25
+ selectorValue = valuePart.join('=');
26
+ scope = exports.DEFAULT_SCOPE;
27
+ }
28
+ return { scope, type, value: selectorValue };
29
+ });
30
+ }
31
+ function parseScopedKeyValue(rawValue) {
32
+ let scope = exports.DEFAULT_SCOPE;
33
+ let keyValue = rawValue;
34
+ const scopeSeparatorIndex = rawValue.indexOf('::');
35
+ if (scopeSeparatorIndex >= 0) {
36
+ scope = rawValue.slice(0, scopeSeparatorIndex).trim();
37
+ keyValue = rawValue.slice(scopeSeparatorIndex + 2).trim();
38
+ }
39
+ const equalSignIndex = keyValue.indexOf('=');
40
+ if (equalSignIndex <= 0) {
41
+ output_1.default.exitError("Option value must follow pattern '[scope::]key=value' (scope is optional)");
42
+ }
43
+ const key = keyValue.slice(0, equalSignIndex).trim();
44
+ const value = keyValue.slice(equalSignIndex + 1).trim();
45
+ if (!key) {
46
+ output_1.default.exitError('Option key cannot be empty');
47
+ }
48
+ return { scope, key, value };
49
+ }
50
+ exports.cookieSchema = zod_1.z
51
+ .array(zod_1.z
52
+ .string()
53
+ .max(4096, {
54
+ message: 'Cookie must be less than 4096 characters',
55
+ })
56
+ .regex(/^(?:([^:]+)::)?([^=]+)=(.*)$/, {
57
+ message: "Cookie option must follow pattern '[scope::]key=value[;attribute]' (scope is optional)",
58
+ }))
59
+ .optional()
60
+ .transform((value) => value?.map((v) => {
61
+ let scope = exports.DEFAULT_SCOPE;
62
+ let cookieValue = v;
63
+ if (v.includes('::')) {
64
+ const [scopePart, valuePart] = v.split('::');
65
+ scope = scopePart.trim();
66
+ cookieValue = valuePart.trim();
67
+ }
68
+ const cookieParts = cookieValue.split(';').map((part) => part.trim());
69
+ const mainPart = cookieParts[0];
70
+ const firstEqualSignIndex = mainPart.indexOf('=');
71
+ const key = mainPart.slice(0, firstEqualSignIndex).trim();
72
+ const value = mainPart.slice(firstEqualSignIndex + 1).trim();
73
+ const cookie = {
74
+ scope,
75
+ key,
76
+ value,
77
+ httpOnly: false,
78
+ secure: false,
79
+ };
80
+ for (let i = 1; i < cookieParts.length; i++) {
81
+ const part = cookieParts[i].toLowerCase();
82
+ if (part === 'httponly') {
83
+ cookie.httpOnly = true;
84
+ }
85
+ else if (part === 'secure') {
86
+ cookie.secure = true;
87
+ }
88
+ else if (part.startsWith('domain=')) {
89
+ cookie.domain = part.substring(7);
90
+ }
91
+ else if (part.startsWith('path=')) {
92
+ cookie.path = part.substring(5);
93
+ }
94
+ else if (part.startsWith('samesite=')) {
95
+ const sameSiteValue = part.substring(9);
96
+ if (['strict', 'lax', 'none'].includes(sameSiteValue)) {
97
+ cookie.sameSite = (sameSiteValue.charAt(0).toUpperCase() +
98
+ sameSiteValue.slice(1));
99
+ }
100
+ }
101
+ }
102
+ return cookie;
103
+ }));
104
+ exports.headerSchema = zod_1.z
105
+ .array(zod_1.z.string().regex(/^(?:([^:]+)::)?([^=]+)=(.*)$/, {
106
+ message: "Header option must follow pattern '[scope::]key=value' (scope is optional)",
107
+ }))
108
+ .optional()
109
+ .transform((value) => value?.map((v) => {
110
+ const { scope, key, value } = parseScopedKeyValue(v);
111
+ return { scope, key, value };
112
+ }));
113
+ exports.waitForSchema = zod_1.z
114
+ .array(zod_1.z.string().regex(/^(?:([^:]+)::)?(?:(CSS|XPATH))=(.+)$/, {
115
+ message: "WaitFor option must follow pattern '[scope::]type=value' where type must be CSS or XPATH (scope is optional)",
116
+ }))
117
+ .optional()
118
+ .transform(parseScopedSelector);
@@ -17,7 +17,7 @@ const tar_stream_1 = __importDefault(require("tar-stream"));
17
17
  const node_zlib_1 = require("node:zlib");
18
18
  const commandVtStorybook = (0, utils_1.newCommand)('storybook', texts_1.DESC_COMMAND_VT_STORYBOOK);
19
19
  commandVtStorybook.action(async () => {
20
- if (!(0, validation_1.checkToken)()) {
20
+ if (!(0, validation_1.checkToken)('vt')) {
21
21
  output_1.default.exitError(texts_1.ERR_MISSING_VT_TOKEN);
22
22
  }
23
23
  const currentDirectoryFiles = getCurrentDirectoryFiles();
@@ -10,7 +10,6 @@ const storybook_1 = __importDefault(require("./vt/storybook"));
10
10
  const exec_1 = __importDefault(require("./vt/exec"));
11
11
  const installBrowser_1 = __importDefault(require("./vt/installBrowser"));
12
12
  const compare_1 = __importDefault(require("./vt/compare"));
13
- const scrape_1 = __importDefault(require("./vt/scrape"));
14
13
  const commandVt = (0, utils_1.newCommand)('visual', texts_1.DESC_COMMAND_VT);
15
14
  commandVt.alias('vt');
16
15
  commandVt.addCommand(close_1.default);
@@ -18,5 +17,4 @@ commandVt.addCommand(storybook_1.default);
18
17
  commandVt.addCommand(exec_1.default);
19
18
  commandVt.addCommand(installBrowser_1.default);
20
19
  commandVt.addCommand(compare_1.default);
21
- commandVt.addCommand(scrape_1.default);
22
20
  exports.default = commandVt;
@@ -12,6 +12,7 @@ const stream_1 = __importDefault(require("stream"));
12
12
  const utils_1 = require("./utils");
13
13
  const texts_1 = require("./texts");
14
14
  const vt_1 = __importDefault(require("./command/vt"));
15
+ const scrape_1 = __importDefault(require("./command/scrape"));
15
16
  const ut_1 = __importDefault(require("./command/ut"));
16
17
  const tunnel_1 = __importDefault(require("./command/tunnel"));
17
18
  const pipeline_1 = __importDefault(require("./command/pipeline"));
@@ -25,6 +26,7 @@ const package_1 = __importDefault(require("./command/package"));
25
26
  const api_1 = __importDefault(require("./command/api"));
26
27
  const autocomplete_1 = __importDefault(require("./autocomplete"));
27
28
  const autocomplete_2 = __importDefault(require("./command/autocomplete"));
29
+ const domain_1 = __importDefault(require("./command/domain"));
28
30
  stream_1.default.setDefaultHighWaterMark(false, 67108864);
29
31
  process.title = 'bdy';
30
32
  process.on('uncaughtException', (err) => {
@@ -41,10 +43,12 @@ if (!(0, utils_1.isDocker)())
41
43
  program.addCommand(agent_1.default);
42
44
  program.addCommand(version_1.default);
43
45
  program.addCommand(vt_1.default);
46
+ program.addCommand(scrape_1.default);
44
47
  program.addCommand(ut_1.default);
45
48
  program.addCommand(pipeline_1.default);
46
49
  program.addCommand(package_1.default);
47
50
  program.addCommand(sandbox_1.default);
51
+ program.addCommand(domain_1.default);
48
52
  program.addCommand(login_1.default);
49
53
  program.addCommand(whoami_1.default);
50
54
  program.addCommand(logout_1.default);
@@ -66,9 +66,15 @@ class Output {
66
66
  static getOkSign() {
67
67
  return '✔ ';
68
68
  }
69
+ static getArrowSign() {
70
+ return '→ ';
71
+ }
69
72
  static okSign(newLine = false) {
70
73
  return this.cyan(this.getOkSign(), newLine);
71
74
  }
75
+ static arrowSign(newLine = false) {
76
+ return this.cyan(this.getArrowSign(), newLine);
77
+ }
72
78
  static exitSuccess(msg) {
73
79
  this.exitNormal(this.getGreenColor(msg));
74
80
  }
@@ -280,14 +286,27 @@ class Output {
280
286
  else {
281
287
  this.cyan('? ', false);
282
288
  this.normal(message, false);
283
- if (items.length > 0) {
284
- this.cyan(` ${items[0].name}`);
285
- return items[0].value;
289
+ const item = items.find((item) => !prompts_1.default.Separator.isSeparator(item) && !item.disabled);
290
+ if (item && item.name && item.value) {
291
+ this.cyan(` ${item.name}`);
292
+ return item.value;
286
293
  }
287
294
  this.normal('');
288
295
  return '';
289
296
  }
290
297
  }
298
+ static createMenuSeparator(text) {
299
+ return new prompts_1.default.Separator(text);
300
+ }
301
+ static createMenuItem(name, value, description) {
302
+ const item = {
303
+ name,
304
+ value,
305
+ };
306
+ if (description)
307
+ item.description = description;
308
+ return item;
309
+ }
291
310
  static async inputMenu(message, items) {
292
311
  if (this.isStdInTTY()) {
293
312
  return await prompts_1.default.select({