@hunt-labs/bytekit-cli 0.9.2 → 0.9.4
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.
- package/CHANGELOG.md +30 -0
- package/README.md +35 -33
- package/dist/client.js +8 -1
- package/dist/commands/bulk.js +19 -4
- package/dist/commands/fetch.js +18 -3
- package/dist/commands/scrape.js +20 -5
- package/dist/lib/parse-flags.d.ts +11 -3
- package/dist/lib/parse-flags.js +13 -4
- package/dist/output.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,36 @@ today, see [README.md](./README.md), which remains the authoritative usage guide
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [0.9.4] - 2026-09-10
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `--cursor`, `--limit` and `--status` on the three bulk recovery commands (#3717):
|
|
18
|
+
`bulk screenshots list <id>`, `scrape bulk get <id>` and `fetch bulk get <id>`.
|
|
19
|
+
They forward the cursor pagination the API already exposed, so a job whose webhook
|
|
20
|
+
manifest came back incomplete can be enumerated page by page from the CLI.
|
|
21
|
+
`--limit` is bounded 1-500 and `--status` accepts only the documented result
|
|
22
|
+
statuses; both are rejected locally before a request is made. No new command and no
|
|
23
|
+
`--all` flag — the existing commands gained options, nothing else moved.
|
|
24
|
+
|
|
25
|
+
## [0.9.3] - 2026-09-03
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- **Breaking (API):** `--format` now takes `raw | markdown | links | images` (#3775). `raw` is
|
|
30
|
+
the renamed unprocessed-source format, and the cleaned-article-HTML format is gone; the
|
|
31
|
+
server rejects both retired values rather than translating them, so
|
|
32
|
+
`--format raw --format markdown` replaces the old spelling. `--raw`/`-o` accept the two
|
|
33
|
+
textual formats, `markdown` and `raw`.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- A failed request's response headers now survive on the thrown `ByteKitError` (#3784). The CLI's
|
|
38
|
+
own copy of the SDK error parser dropped the response after reading its body, so `Retry-After`
|
|
39
|
+
and the `X-Quota-*` trio were unreadable on an error even though the gateway sent them. The SDK
|
|
40
|
+
has passed them into the fifth constructor argument since #2957; this copy now matches, and the
|
|
41
|
+
parity suite pins the two parsers against each other on a shared header corpus.
|
|
42
|
+
|
|
13
43
|
## [0.9.2] - 2026-08-31
|
|
14
44
|
|
|
15
45
|
### Changed
|
package/README.md
CHANGED
|
@@ -100,37 +100,37 @@ bytekit scrape bulk create --file urls.txt --webhook-url https://your.app/hooks/
|
|
|
100
100
|
absent (a boolean flag never sends `false`, so a server default is never
|
|
101
101
|
materialized):
|
|
102
102
|
|
|
103
|
-
| Flag | Effect
|
|
104
|
-
| ------------------------------------------------------ |
|
|
105
|
-
| `--format <fmt>` | Output format. **Repeatable and comma-separated** — `--format
|
|
106
|
-
| `--country <cc>` | Route through a country (e.g. `us`, `de`).
|
|
107
|
-
| `--timeout-ms <n>` | Per-request timeout in milliseconds.
|
|
108
|
-
| `--cache-ttl <ttl>` | Cache freshness: `0`, `Nh` (hours), or `Nd` (days) — e.g. `48h`, `2d`, `0`. Omitted → server default.
|
|
109
|
-
| `--markdown-mode <mode>` | Markdown extraction mode: `article`, `raw`, `llm`.
|
|
110
|
-
| `--markdown-query <q>` | BM25 query for relevance-ranked markdown filtering.
|
|
111
|
-
| `--cookies <json>` | Cookies as a JSON array, e.g. `'[{"name":"a","value":"b"}]'`.
|
|
112
|
-
| `--headers <json>` | Extra request headers as a JSON object, e.g. `'{"X-A":"b"}'`.
|
|
113
|
-
| `--delay-ms <n>` | Post-load delay before capture, in milliseconds.
|
|
114
|
-
| `--events <csv>` | Webhook events (comma-separated): `queued`, `completed`, `failed`.
|
|
115
|
-
| `--token-budget <n>` | Cap the markdown returned to `n` tokens.
|
|
116
|
-
| `--token-encoding <enc>` | Tokenizer for `--token-budget`: `cl100k_base`, `o200k_base`.
|
|
117
|
-
| `--custom <json>` | User payload echoed on the envelope, as a JSON object.
|
|
118
|
-
| `--remove-base64-images` / `--no-remove-base64-images` | Tri-state: strip / preserve base64 `data:` images. Omitted → server default (strip).
|
|
119
|
-
| `--markdown-links <mode>` | Link rendering: `inline`, `references`, `none`, `text`.
|
|
120
|
-
| `--markdown-images <mode>` | Image retention: `inline`, `references`, `none`, `text`.
|
|
121
|
-
| `--with-links-summary` | Append a Links footer to the markdown.
|
|
122
|
-
| `--with-images-summary` | Append an Images footer to the markdown.
|
|
123
|
-
| `--markdown-compact` | Collapse excessive whitespace.
|
|
124
|
-
| `--markdown-filter-images` | Filter low-signal images.
|
|
125
|
-
| `--markdown-include-media` | Return rich link/image objects and a tables array.
|
|
126
|
-
| `--markdown-include-warnings` | Include markdown-pipeline and tag-filter warnings.
|
|
127
|
-
| `--markdown-include-stats` | Include a top-level stats object (chars, tokens, blocks).
|
|
128
|
-
| `--clean-markdown` | LLM-clean the markdown (billed 3x).
|
|
129
|
-
| `--include-tags <csv>` | Comma-separated HTML tags to keep.
|
|
130
|
-
| `--exclude-tags <csv>` | Comma-separated HTML tags to drop.
|
|
131
|
-
| `--mobile` | Render with a mobile viewport/user-agent.
|
|
132
|
-
| `--async` | Queue the scrape and return a job envelope immediately.
|
|
133
|
-
| `--webhook-url <url>` | Webhook notified when an async scrape completes.
|
|
103
|
+
| Flag | Effect |
|
|
104
|
+
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
105
|
+
| `--format <fmt>` | Output format. **Repeatable and comma-separated** — `--format raw --format markdown` and `--format raw,markdown` both send `formats: ["raw","markdown"]`. Omitted → server default. |
|
|
106
|
+
| `--country <cc>` | Route through a country (e.g. `us`, `de`). |
|
|
107
|
+
| `--timeout-ms <n>` | Per-request timeout in milliseconds. |
|
|
108
|
+
| `--cache-ttl <ttl>` | Cache freshness: `0`, `Nh` (hours), or `Nd` (days) — e.g. `48h`, `2d`, `0`. Omitted → server default. |
|
|
109
|
+
| `--markdown-mode <mode>` | Markdown extraction mode: `article`, `raw`, `llm`. |
|
|
110
|
+
| `--markdown-query <q>` | BM25 query for relevance-ranked markdown filtering. |
|
|
111
|
+
| `--cookies <json>` | Cookies as a JSON array, e.g. `'[{"name":"a","value":"b"}]'`. |
|
|
112
|
+
| `--headers <json>` | Extra request headers as a JSON object, e.g. `'{"X-A":"b"}'`. |
|
|
113
|
+
| `--delay-ms <n>` | Post-load delay before capture, in milliseconds. |
|
|
114
|
+
| `--events <csv>` | Webhook events (comma-separated): `queued`, `completed`, `failed`. |
|
|
115
|
+
| `--token-budget <n>` | Cap the markdown returned to `n` tokens. |
|
|
116
|
+
| `--token-encoding <enc>` | Tokenizer for `--token-budget`: `cl100k_base`, `o200k_base`. |
|
|
117
|
+
| `--custom <json>` | User payload echoed on the envelope, as a JSON object. |
|
|
118
|
+
| `--remove-base64-images` / `--no-remove-base64-images` | Tri-state: strip / preserve base64 `data:` images. Omitted → server default (strip). |
|
|
119
|
+
| `--markdown-links <mode>` | Link rendering: `inline`, `references`, `none`, `text`. |
|
|
120
|
+
| `--markdown-images <mode>` | Image retention: `inline`, `references`, `none`, `text`. |
|
|
121
|
+
| `--with-links-summary` | Append a Links footer to the markdown. |
|
|
122
|
+
| `--with-images-summary` | Append an Images footer to the markdown. |
|
|
123
|
+
| `--markdown-compact` | Collapse excessive whitespace. |
|
|
124
|
+
| `--markdown-filter-images` | Filter low-signal images. |
|
|
125
|
+
| `--markdown-include-media` | Return rich link/image objects and a tables array. |
|
|
126
|
+
| `--markdown-include-warnings` | Include markdown-pipeline and tag-filter warnings. |
|
|
127
|
+
| `--markdown-include-stats` | Include a top-level stats object (chars, tokens, blocks). |
|
|
128
|
+
| `--clean-markdown` | LLM-clean the markdown (billed 3x). |
|
|
129
|
+
| `--include-tags <csv>` | Comma-separated HTML tags to keep. |
|
|
130
|
+
| `--exclude-tags <csv>` | Comma-separated HTML tags to drop. |
|
|
131
|
+
| `--mobile` | Render with a mobile viewport/user-agent. |
|
|
132
|
+
| `--async` | Queue the scrape and return a job envelope immediately. |
|
|
133
|
+
| `--webhook-url <url>` | Webhook notified when an async scrape completes. |
|
|
134
134
|
|
|
135
135
|
`scrape get` accepts the same output flags as `scrape create` —
|
|
136
136
|
`--raw`, `-o <file>`, and `--format <fmt>` — so a job queued with `--async --raw`
|
|
@@ -276,8 +276,10 @@ bytekit bulk screenshots list "$bulk_id"
|
|
|
276
276
|
`urls.txt` is newline-delimited: one plain URL (or `{"url":"https://..."}`) per
|
|
277
277
|
line. A line whose only key is `url` is sent as a bare URL string; any line with
|
|
278
278
|
additional keys switches that entry to the per-item shape. `bulk cancel <id>`
|
|
279
|
-
stops an in-flight job
|
|
280
|
-
|
|
279
|
+
stops an in-flight job. Recover another result page with `--cursor <cursor>`,
|
|
280
|
+
bound it with `--limit <n>`, or filter it with `--status <status>` on
|
|
281
|
+
`bulk screenshots list <id>`. The same recovery options are available on
|
|
282
|
+
`scrape bulk get <id>` and `fetch bulk get <id>`.
|
|
281
283
|
|
|
282
284
|
The three bulk-job creators — `bulk create`, `scrape bulk create` and
|
|
283
285
|
`fetch bulk create` — share one flag set:
|
package/dist/client.js
CHANGED
|
@@ -240,6 +240,10 @@ function drainBestEffort(body, abort) {
|
|
|
240
240
|
* phantom `details`, and `ByteKitErrorDetails` promises something indexable, so an array or a
|
|
241
241
|
* scalar is dropped rather than surfaced. `error-parser-parity.test.ts` compares this field against
|
|
242
242
|
* the real SDK's parser on a shared corpus.
|
|
243
|
+
*
|
|
244
|
+
* The response's headers are mirrored for the same reason (#3784 E4): the SDK grew that fifth
|
|
245
|
+
* constructor argument in #2957 and this copy did not follow, so `Retry-After` and the `X-Quota-*`
|
|
246
|
+
* trio were parsed away before any caller could read them off the rejection.
|
|
243
247
|
*/
|
|
244
248
|
async function toApiError(response) {
|
|
245
249
|
let code = 'internal_error';
|
|
@@ -265,7 +269,10 @@ async function toApiError(response) {
|
|
|
265
269
|
catch {
|
|
266
270
|
// leave defaults
|
|
267
271
|
}
|
|
268
|
-
|
|
272
|
+
// The failing response's OWN headers ride along as the SDK's fifth argument (#2957, mirrored
|
|
273
|
+
// here for #3784 E4). Without them a caught CLI error could not tell the caller how long to wait
|
|
274
|
+
// (`Retry-After`) or how much budget is left (`X-Quota-*`), even though the gateway sent both.
|
|
275
|
+
return new ByteKitError(response.status, code, message, details, response.headers);
|
|
269
276
|
}
|
|
270
277
|
/**
|
|
271
278
|
* Perform the authenticated round-trip with a single bounded retry on 429, returning whatever the
|
package/dist/commands/bulk.js
CHANGED
|
@@ -2,19 +2,34 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { buildClient } from '../client.js';
|
|
3
3
|
import { printResult, handleError } from '../output.js';
|
|
4
4
|
import { parseBulkLines, toBulkItems } from '../lib/url-lines.js';
|
|
5
|
-
import { parseJsonFlag } from '../lib/parse-flags.js';
|
|
5
|
+
import { parseEnum, parseIntFlag, parseJsonFlag } from '../lib/parse-flags.js';
|
|
6
|
+
const BULK_RESULT_STATUSES = ['pending', 'processing', 'completed', 'failed', 'cancelled'];
|
|
7
|
+
// Mirrors the `limit` query schema (`minimum: 1, maximum: 500`) on this job's recovery route in
|
|
8
|
+
// docs/api/openapi.yaml, so the range the `--limit` help text advertises is enforced locally.
|
|
9
|
+
const PAGE_LIMIT_BOUNDS = { min: 1, max: 500 };
|
|
6
10
|
export function makeBulkCommand(getGlobal) {
|
|
7
11
|
const cmd = new Command('bulk').description('Bulk screenshot operations');
|
|
8
12
|
const screenshotsCmd = new Command('screenshots').description('Bulk screenshot sub-resources');
|
|
9
13
|
screenshotsCmd
|
|
10
14
|
.command('list <id>')
|
|
11
|
-
.description('List
|
|
12
|
-
.
|
|
15
|
+
.description('List items in a mixed bulk job')
|
|
16
|
+
.option('--cursor <cursor>', 'Continue from a cursor returned by the preceding page')
|
|
17
|
+
.option('--limit <n>', 'Maximum items per type to return (1-500)', (v) => parseIntFlag('--limit', v, PAGE_LIMIT_BOUNDS))
|
|
18
|
+
.option('--status <status>', `Filter items by status: ${BULK_RESULT_STATUSES.join(', ')}`, (v) => parseEnum('--status', BULK_RESULT_STATUSES, v))
|
|
19
|
+
.action(async (id, opts) => {
|
|
13
20
|
const g = getGlobal();
|
|
14
21
|
try {
|
|
15
22
|
// Inside the try: buildClient() throws on a missing key (#2686 item 4) and the throw must reach handleError(). See its doc comment in client.ts.
|
|
16
23
|
const client = buildClient(g);
|
|
17
|
-
const
|
|
24
|
+
const bulkId = id;
|
|
25
|
+
const pageParams = {
|
|
26
|
+
...(opts.cursor !== undefined ? { cursor: opts.cursor } : {}),
|
|
27
|
+
...(opts.limit !== undefined ? { limit: opts.limit } : {}),
|
|
28
|
+
...(opts.status !== undefined ? { status: opts.status } : {}),
|
|
29
|
+
};
|
|
30
|
+
const result = Object.keys(pageParams).length === 0
|
|
31
|
+
? await client.bulk.screenshots.list(bulkId)
|
|
32
|
+
: await client.bulk.screenshots.list(bulkId, pageParams);
|
|
18
33
|
printResult(result, g.json);
|
|
19
34
|
}
|
|
20
35
|
catch (err) {
|
package/dist/commands/fetch.js
CHANGED
|
@@ -2,7 +2,11 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { buildClient } from '../client.js';
|
|
3
3
|
import { printResult, emitFetchResult, handleError } from '../output.js';
|
|
4
4
|
import { parseBulkLines } from '../lib/url-lines.js';
|
|
5
|
-
import { parseIntFlag, parseCacheTtl, parseJsonFlag } from '../lib/parse-flags.js';
|
|
5
|
+
import { parseIntFlag, parseCacheTtl, parseJsonFlag, parseEnum } from '../lib/parse-flags.js';
|
|
6
|
+
const BULK_RESULT_STATUSES = ['pending', 'processing', 'completed', 'failed', 'cancelled'];
|
|
7
|
+
// Mirrors the `limit` query schema (`minimum: 1, maximum: 500`) on this job's recovery route in
|
|
8
|
+
// docs/api/openapi.yaml, so the range the `--limit` help text advertises is enforced locally.
|
|
9
|
+
const PAGE_LIMIT_BOUNDS = { min: 1, max: 500 };
|
|
6
10
|
export function makeFetchCommand(getGlobal) {
|
|
7
11
|
const cmd = new Command('fetch').description('Fetch URL content operations');
|
|
8
12
|
const bulkCmd = new Command('bulk').description('Bulk fetch operations');
|
|
@@ -44,12 +48,23 @@ export function makeFetchCommand(getGlobal) {
|
|
|
44
48
|
bulkCmd
|
|
45
49
|
.command('get <id>')
|
|
46
50
|
.description('Get a bulk fetch job')
|
|
47
|
-
.
|
|
51
|
+
.option('--cursor <cursor>', 'Continue from a cursor returned by the preceding page')
|
|
52
|
+
.option('--limit <n>', 'Maximum items to return (1-500)', (v) => parseIntFlag('--limit', v, PAGE_LIMIT_BOUNDS))
|
|
53
|
+
.option('--status <status>', `Filter items by status: ${BULK_RESULT_STATUSES.join(', ')}`, (v) => parseEnum('--status', BULK_RESULT_STATUSES, v))
|
|
54
|
+
.action(async (id, opts) => {
|
|
48
55
|
const g = getGlobal();
|
|
49
56
|
try {
|
|
50
57
|
// Inside the try: buildClient() throws on a missing key (#2686 item 4) and the throw must reach handleError(). See its doc comment in client.ts.
|
|
51
58
|
const client = buildClient(g);
|
|
52
|
-
const
|
|
59
|
+
const bulkId = id;
|
|
60
|
+
const pageParams = {
|
|
61
|
+
...(opts.cursor !== undefined ? { cursor: opts.cursor } : {}),
|
|
62
|
+
...(opts.limit !== undefined ? { limit: opts.limit } : {}),
|
|
63
|
+
...(opts.status !== undefined ? { status: opts.status } : {}),
|
|
64
|
+
};
|
|
65
|
+
const result = Object.keys(pageParams).length === 0
|
|
66
|
+
? await client.fetch.bulk.get(bulkId)
|
|
67
|
+
: await client.fetch.bulk.get(bulkId, pageParams);
|
|
53
68
|
printResult(result, g.json);
|
|
54
69
|
}
|
|
55
70
|
catch (err) {
|
package/dist/commands/scrape.js
CHANGED
|
@@ -11,6 +11,10 @@ const SCRAPE_EVENTS = ['queued', 'completed', 'failed'];
|
|
|
11
11
|
const TOKEN_ENCODINGS = ['cl100k_base', 'o200k_base'];
|
|
12
12
|
/** The `markdown_links` / `markdown_images` render-mode enum. */
|
|
13
13
|
const MARKDOWN_RENDER_MODES = ['inline', 'references', 'none', 'text'];
|
|
14
|
+
const BULK_RESULT_STATUSES = ['pending', 'processing', 'completed', 'failed', 'cancelled'];
|
|
15
|
+
// Mirrors the `limit` query schema (`minimum: 1, maximum: 500`) on this job's recovery route in
|
|
16
|
+
// docs/api/openapi.yaml, so the range the `--limit` help text advertises is enforced locally.
|
|
17
|
+
const PAGE_LIMIT_BOUNDS = { min: 1, max: 500 };
|
|
14
18
|
/**
|
|
15
19
|
* Exit code when a queued (202 async) envelope reaches a non-JSON output mode.
|
|
16
20
|
*
|
|
@@ -83,12 +87,23 @@ export function makeScrapeCommand(getGlobal) {
|
|
|
83
87
|
bulkCmd
|
|
84
88
|
.command('get <id>')
|
|
85
89
|
.description('Get a bulk scrape job')
|
|
86
|
-
.
|
|
90
|
+
.option('--cursor <cursor>', 'Continue from a cursor returned by the preceding page')
|
|
91
|
+
.option('--limit <n>', 'Maximum items to return (1-500)', (v) => parseIntFlag('--limit', v, PAGE_LIMIT_BOUNDS))
|
|
92
|
+
.option('--status <status>', `Filter items by status: ${BULK_RESULT_STATUSES.join(', ')}`, (v) => parseEnum('--status', BULK_RESULT_STATUSES, v))
|
|
93
|
+
.action(async (id, opts) => {
|
|
87
94
|
const g = getGlobal();
|
|
88
95
|
try {
|
|
89
96
|
// Inside the try: buildClient() throws on a missing key (#2686 item 4) and the throw must reach handleError(). See its doc comment in client.ts.
|
|
90
97
|
const client = buildClient(g);
|
|
91
|
-
const
|
|
98
|
+
const bulkId = id;
|
|
99
|
+
const pageParams = {
|
|
100
|
+
...(opts.cursor !== undefined ? { cursor: opts.cursor } : {}),
|
|
101
|
+
...(opts.limit !== undefined ? { limit: opts.limit } : {}),
|
|
102
|
+
...(opts.status !== undefined ? { status: opts.status } : {}),
|
|
103
|
+
};
|
|
104
|
+
const result = Object.keys(pageParams).length === 0
|
|
105
|
+
? await client.scrape.bulk.get(bulkId)
|
|
106
|
+
: await client.scrape.bulk.get(bulkId, pageParams);
|
|
92
107
|
printResult(result, g.json);
|
|
93
108
|
}
|
|
94
109
|
catch (err) {
|
|
@@ -100,8 +115,8 @@ export function makeScrapeCommand(getGlobal) {
|
|
|
100
115
|
.command('create')
|
|
101
116
|
.description('Create a scrape job')
|
|
102
117
|
.requiredOption('--url <url>', 'URL to scrape')
|
|
103
|
-
// Repeatable AND CSV-aware: `--format
|
|
104
|
-
// both send formats: ['
|
|
118
|
+
// Repeatable AND CSV-aware: `--format raw --format markdown` and `--format raw,markdown`
|
|
119
|
+
// both send formats: ['raw','markdown']. Sent as the `formats` array; omitted → server
|
|
105
120
|
// default. `--raw`/`-o` require EXACTLY ONE format (validated pre-request; see the action).
|
|
106
121
|
//
|
|
107
122
|
// The format VALUES travel to the server unvalidated — deliberate, and recorded here for
|
|
@@ -109,7 +124,7 @@ export function makeScrapeCommand(getGlobal) {
|
|
|
109
124
|
// `--type`/`--date-range`). The persisted-format vocabulary grows with the spec, and a local
|
|
110
125
|
// enum list is a second source of truth that drifts silently: the CLI would reject a format
|
|
111
126
|
// the API has begun serving, and the error would come from a stale copy rather than the API.
|
|
112
|
-
.option('--format <format>', 'Output format; repeat or comma-separate for multiple (e.g. --format
|
|
127
|
+
.option('--format <format>', 'Output format; repeat or comma-separate for multiple (e.g. --format raw --format markdown, or --format raw,markdown). Sent as the formats array; omitted → server default.', collectFormats)
|
|
113
128
|
.option('--country <cc>', 'Two-letter country code to route the request through (e.g. us, de)')
|
|
114
129
|
.option('--timeout-ms <n>', 'Per-request timeout in milliseconds', (v) => parseIntFlag('--timeout-ms', v))
|
|
115
130
|
.option('--markdown-mode <mode>', `Markdown extraction mode: ${MARKDOWN_MODES.join(', ')}`, (v) => parseEnum('--markdown-mode', MARKDOWN_MODES, v))
|
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
* Parse a whole-number flag value. The strict `/^\d+$/` test deterministically rejects `abc`, ``,
|
|
9
9
|
* `1.5`, `-5`, `1e2`, so an off-spec value fails at parse time with an actionable message instead
|
|
10
10
|
* of a server 422 or a NaN on the wire.
|
|
11
|
+
*
|
|
12
|
+
* `bounds` extends that guarantee to flags whose spec schema declares a range (#3717): a
|
|
13
|
+
* well-formed integer outside `[min, max]` is just as certain to 422 as `abc` is, so it is
|
|
14
|
+
* rejected here rather than spending a round trip to be told so. Pass it wherever the flag's help
|
|
15
|
+
* text states a range; omit it where the spec declares none.
|
|
11
16
|
*/
|
|
12
|
-
export declare function parseIntFlag(flag: string, value: string
|
|
17
|
+
export declare function parseIntFlag(flag: string, value: string, bounds?: {
|
|
18
|
+
min: number;
|
|
19
|
+
max: number;
|
|
20
|
+
}): number;
|
|
13
21
|
/** Reject an off-spec enum value at parse time with the allowed set in the message. */
|
|
14
22
|
export declare function parseEnum<T extends string>(flag: string, allowed: readonly T[], value: string): T;
|
|
15
23
|
/** Split a comma-separated flag value into a trimmed, non-empty string array. */
|
|
@@ -39,8 +47,8 @@ export declare function parseCacheTtl(flag: string, value: string): string;
|
|
|
39
47
|
export declare function parseJsonFlag(flag: string, value: string, expect: 'object' | 'array'): unknown;
|
|
40
48
|
/**
|
|
41
49
|
* Commander collector for a repeatable, CSV-aware `--format` flag (#2545). Each occurrence is
|
|
42
|
-
* CSV-split and appended to the accumulator, so `--format
|
|
43
|
-
* `--format
|
|
50
|
+
* CSV-split and appended to the accumulator, so `--format raw --format markdown` and
|
|
51
|
+
* `--format raw,markdown` both yield `['raw','markdown']`. Commander seeds `prev` with
|
|
44
52
|
* the option default (or the previous return) on each occurrence.
|
|
45
53
|
*/
|
|
46
54
|
export declare function collectFormats(value: string, prev: string[] | undefined): string[];
|
package/dist/lib/parse-flags.js
CHANGED
|
@@ -9,12 +9,21 @@ import { InvalidArgumentError } from 'commander';
|
|
|
9
9
|
* Parse a whole-number flag value. The strict `/^\d+$/` test deterministically rejects `abc`, ``,
|
|
10
10
|
* `1.5`, `-5`, `1e2`, so an off-spec value fails at parse time with an actionable message instead
|
|
11
11
|
* of a server 422 or a NaN on the wire.
|
|
12
|
+
*
|
|
13
|
+
* `bounds` extends that guarantee to flags whose spec schema declares a range (#3717): a
|
|
14
|
+
* well-formed integer outside `[min, max]` is just as certain to 422 as `abc` is, so it is
|
|
15
|
+
* rejected here rather than spending a round trip to be told so. Pass it wherever the flag's help
|
|
16
|
+
* text states a range; omit it where the spec declares none.
|
|
12
17
|
*/
|
|
13
|
-
export function parseIntFlag(flag, value) {
|
|
18
|
+
export function parseIntFlag(flag, value, bounds) {
|
|
14
19
|
if (!/^\d+$/.test(value)) {
|
|
15
20
|
throw new InvalidArgumentError(`${flag} must be a whole number.`);
|
|
16
21
|
}
|
|
17
|
-
|
|
22
|
+
const parsed = Number(value);
|
|
23
|
+
if (bounds && (parsed < bounds.min || parsed > bounds.max)) {
|
|
24
|
+
throw new InvalidArgumentError(`${flag} must be between ${bounds.min} and ${bounds.max}.`);
|
|
25
|
+
}
|
|
26
|
+
return parsed;
|
|
18
27
|
}
|
|
19
28
|
/** Reject an off-spec enum value at parse time with the allowed set in the message. */
|
|
20
29
|
export function parseEnum(flag, allowed, value) {
|
|
@@ -83,8 +92,8 @@ export function parseJsonFlag(flag, value, expect) {
|
|
|
83
92
|
}
|
|
84
93
|
/**
|
|
85
94
|
* Commander collector for a repeatable, CSV-aware `--format` flag (#2545). Each occurrence is
|
|
86
|
-
* CSV-split and appended to the accumulator, so `--format
|
|
87
|
-
* `--format
|
|
95
|
+
* CSV-split and appended to the accumulator, so `--format raw --format markdown` and
|
|
96
|
+
* `--format raw,markdown` both yield `['raw','markdown']`. Commander seeds `prev` with
|
|
88
97
|
* the option default (or the previous return) on each occurrence.
|
|
89
98
|
*/
|
|
90
99
|
export function collectFormats(value, prev) {
|
package/dist/output.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { writeFileSync } from 'node:fs';
|
|
2
2
|
/** Text formats whose bodies are strings and can therefore be emitted raw. */
|
|
3
|
-
const TEXT_FORMATS = 'markdown,
|
|
3
|
+
const TEXT_FORMATS = 'markdown, raw';
|
|
4
4
|
/**
|
|
5
5
|
* Serialize a value as the CLI's `--json` payload text. The single serializer EVERY `--json`
|
|
6
6
|
* branch in this module goes through, so no branch can regress to a raw `JSON.stringify`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hunt-labs/bytekit-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "ByteKit CLI — wraps @hunt-labs/bytekit-sdk as shell subcommands",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"commander": "^12.0.0",
|
|
44
|
-
"@hunt-labs/bytekit-sdk": "^0.
|
|
44
|
+
"@hunt-labs/bytekit-sdk": "^0.10.0"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc",
|