subto 9.0.4 → 9.0.5

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 (3) hide show
  1. package/README.md +20 -8
  2. package/index.js +42 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -23,8 +23,8 @@ npm install -g subto
23
23
  ```bash
24
24
  subto login
25
25
  subto account
26
- subto scan https://example.com
27
- subto scan https://example.com --wait
26
+ subto scan https://example.com basic
27
+ subto scan https://example.com full yes --wait
28
28
  subto chat
29
29
  ```
30
30
 
@@ -74,18 +74,24 @@ Output includes:
74
74
  - scan count
75
75
  - member-since date
76
76
 
77
- ### `subto scan <url>`
77
+ ### `subto scan <url> <basic|full> [yes|no]`
78
78
 
79
79
  Requests a remote scan for a URL via the Subto API.
80
80
 
81
81
  ```bash
82
- subto scan https://example.com
83
- subto scan https://example.com --wait
84
- subto scan https://example.com --no-wait
85
- subto scan https://example.com --json
86
- subto scan https://example.com --chat
82
+ subto scan https://example.com basic
83
+ subto scan https://example.com basic --wait
84
+ subto scan https://example.com full yes
85
+ subto scan https://example.com full no --json
86
+ subto scan https://example.com full yes --chat
87
87
  ```
88
88
 
89
+ Arguments:
90
+
91
+ - `<basic|full>` is required.
92
+ - `[yes|no]` is required when mode is `full`.
93
+ - Do not provide a video argument when mode is `basic`.
94
+
89
95
  Options:
90
96
 
91
97
  - `--json` prints the raw JSON response.
@@ -93,6 +99,12 @@ Options:
93
99
  - `--no-wait` returns immediately instead of polling.
94
100
  - `--chat` opens the local interactive assistant after the scan completes.
95
101
 
102
+ Examples:
103
+
104
+ - `subto scan https://example.com basic`
105
+ - `subto scan https://example.com full yes`
106
+ - `subto scan https://example.com full no --wait`
107
+
96
108
  If the server returns HTML instead of JSON, the CLI attempts to recover the `scanId` automatically. If it cannot, it saves the HTML response to a temporary file for inspection.
97
109
 
98
110
  ### `subto scan upload [dir]`
package/index.js CHANGED
@@ -215,13 +215,19 @@ async function _maskHeaders(obj){
215
215
  return out;
216
216
  }
217
217
 
218
- async function postScan(url, apiKey, debug=false) {
218
+ async function postScan(url, apiKey, scanProfile, recordVideo, debug=false) {
219
219
  // Use normalized API base
220
220
  const endpointObj = new URL('scan', SUBTO_API_BASE_SLASH);
221
221
  // API key is sent via headers only — never in query strings to prevent
222
222
  // leakage via server logs, proxy logs, and Referer headers.
223
223
  const endpoint = endpointObj.toString();
224
- const body = { url, source: 'cli', client: CLIENT_META };
224
+ const body = {
225
+ url,
226
+ source: 'cli',
227
+ client: CLIENT_META,
228
+ scanProfile,
229
+ recordVideo
230
+ };
225
231
  const fetchFn = global.fetch;
226
232
  if (typeof fetchFn !== 'function') throw new Error('Global fetch() is not available in this Node runtime. Use Node 18+');
227
233
  // Validate header-safety to avoid undici/node fetch ByteString conversion errors
@@ -623,12 +629,12 @@ Common commands:
623
629
  subto account --json
624
630
  Show your account name, email, API call count, scan count, and member-since date.
625
631
 
626
- subto scan <url>
627
- subto scan <url> --wait
628
- subto scan <url> --no-wait
629
- subto scan <url> --json
630
- subto scan <url> --chat
631
- Request a remote scan for a URL. Polling happens automatically when the server queues the scan unless you pass --no-wait.
632
+ subto scan <url> basic
633
+ subto scan <url> basic --wait
634
+ subto scan <url> full yes
635
+ subto scan <url> full no --json
636
+ subto scan <url> full yes --chat
637
+ Request a remote scan for a URL. You must choose basic or full. Full scans also require an explicit video choice: yes or no.
632
638
 
633
639
  subto scan upload [dir]
634
640
  subto scan upload [dir] --wait
@@ -730,19 +736,40 @@ Notes:
730
736
  }
731
737
  });
732
738
 
733
- program
734
- .command('scan <url>')
735
- .description('Request a scan for <url> via the Subto API')
739
+ const scanCommand = program
740
+ .command('scan')
741
+ .description('Request a remote scan for a URL, or use a scan subcommand')
742
+ .argument('<url>')
743
+ .argument('<mode>')
744
+ .argument('[videoChoice]')
736
745
  .option('--json', 'Output raw JSON')
737
746
  .option('--wait', 'Poll for completion and show progress')
738
747
  .option('--no-wait', 'Do not poll; return immediately')
739
748
  .option('--chat', 'Open interactive AI assistant after scan completes')
740
- .action(async (url, opts) => {
749
+ .action(async (url, mode, videoChoice, opts) => {
741
750
  if (!validateUrl(url)) { console.error(chalk.red('Invalid URL. Provide a full URL including http:// or https://')); process.exit(1); }
751
+ const normalizedMode = String(mode || '').trim().toLowerCase();
752
+ if (!['basic', 'full'].includes(normalizedMode)) {
753
+ console.error(chalk.red('Invalid scan mode. Use `basic` or `full`.'));
754
+ process.exit(1);
755
+ }
756
+
757
+ let effectiveVideoChoice = null;
758
+ if (normalizedMode === 'full') {
759
+ effectiveVideoChoice = String(videoChoice || '').trim().toLowerCase();
760
+ if (!['yes', 'no'].includes(effectiveVideoChoice)) {
761
+ console.error(chalk.red('Full scan mode requires an explicit video choice: `yes` or `no`.'));
762
+ process.exit(1);
763
+ }
764
+ } else if (videoChoice !== undefined) {
765
+ console.error(chalk.red('Basic scan mode does not accept a video argument. Use `subto scan <url> basic`.'));
766
+ process.exit(1);
767
+ }
768
+
742
769
  const cfg = await readConfig(); if (!cfg || !cfg.apiKey) { console.error(chalk.red('Missing API key. Run:'), chalk.cyan('subto login')); process.exit(1); }
743
770
  try {
744
771
  const DEBUG = (program && typeof program.opts === 'function') ? Boolean(program.opts().debug) : false;
745
- const resp = await postScan(url, cfg.apiKey, DEBUG);
772
+ const resp = await postScan(url, cfg.apiKey, normalizedMode, effectiveVideoChoice === 'yes', DEBUG);
746
773
  if (resp.status === 429) {
747
774
  let retrySeconds = null;
748
775
  if (resp.body && typeof resp.body === 'object' && resp.body.retry_after) retrySeconds = resp.body.retry_after;
@@ -1264,8 +1291,8 @@ Notes:
1264
1291
  });
1265
1292
 
1266
1293
  // Upload and scan locally via server: `subto scan upload [dir]`
1267
- program
1268
- .command('scan upload [dir]')
1294
+ scanCommand
1295
+ .command('upload [dir]')
1269
1296
  .description('Upload a directory to the server and request a scan (respects .subtoignore)')
1270
1297
  .option('--wait', 'Poll until analysis completes')
1271
1298
  .action(async (dir, opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subto",
3
- "version": "9.0.4",
3
+ "version": "9.0.5",
4
4
  "description": "Subto CLI — thin wrapper around the Subto.One API",
5
5
  "bin": {
6
6
  "subto": "bin/subto.js"