@hunt-labs/bytekit-cli 0.2.0 → 0.2.2
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 +72 -0
- package/README.md +13 -18
- package/dist/client.d.ts +5 -2
- package/dist/client.js +11 -5
- package/dist/index.js +2 -4
- package/dist/output.d.ts +9 -2
- package/dist/output.js +11 -3
- package/package.json +6 -9
- package/dist/commands/recordings.d.ts +0 -5
- package/dist/commands/recordings.js +0 -36
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@hunt-labs/bytekit-cli` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
This file records only the delta between versions. For how to use the package
|
|
9
|
+
today, see [README.md](./README.md), which remains the authoritative usage guide.
|
|
10
|
+
|
|
11
|
+
## [0.2.2] - 2026-07-16
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Re-release of 0.2.1. The 0.2.1 artifacts never reached npm — the prod publish's
|
|
16
|
+
`publish-sdk` step failed on a CI test-isolation flake (`cjs-require.test.ts`
|
|
17
|
+
rebuilding the shared `dist`), which is now fixed. No consumer-facing changes
|
|
18
|
+
beyond 0.2.1.
|
|
19
|
+
|
|
20
|
+
## [0.2.1] - 2026-07-16
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- `BYTEKIT_API_KEY` / `BYTEKIT_BASE_URL` are now the primary environment
|
|
25
|
+
variables (precedence: flag > `BYTEKIT_*` > legacy `RAPIDCRAWL_*`).
|
|
26
|
+
`RAPIDCRAWL_API_KEY` / `RAPIDCRAWL_BASE_URL` continue to work as silent
|
|
27
|
+
fallbacks. `--help` text, the missing-key error, and the README now reference
|
|
28
|
+
`BYTEKIT_*`. (#2421)
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- The `recordings` command (the endpoint is permanently `410` deactivated). (#2421)
|
|
33
|
+
|
|
34
|
+
## [0.2.0] - 2026-07-15
|
|
35
|
+
|
|
36
|
+
Additive, lower-risk release — no breaking changes to existing commands.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- `scrape create --raw` / `-o, --output <file>`: write the raw response body to
|
|
41
|
+
stdout or a file (#2425).
|
|
42
|
+
- Local `search --limit` validation via a commander `argParser`, so an invalid limit
|
|
43
|
+
is rejected before a request is sent (#2425).
|
|
44
|
+
- One automatic retry on HTTP 429, honoring a clamped `Retry-After` header, in the
|
|
45
|
+
CLI transport (#2425).
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Entrypoint guard canonicalized so the `bytekit` bin runs correctly when invoked
|
|
50
|
+
through an npm/npx symlink (#2418).
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- Package renamed to `@hunt-labs/bytekit-cli` (the `@bytekit` npm scope was
|
|
55
|
+
unobtainable); the `bin` name stays `bytekit`. The prior `rapidcrawl-cli` name
|
|
56
|
+
remains installable at its last version but is deprecated.
|
|
57
|
+
- Consumer call sites propagate the SDK's narrowed, spec-derived request types (#2426).
|
|
58
|
+
- Publish-ready packaging metadata: dropped `main`, unpinned the SDK dependency to
|
|
59
|
+
`workspace:^`, added `engines`, `keywords`, `homepage`, `bugs`, `README.md`,
|
|
60
|
+
`LICENSE`, and an MIT `license` field.
|
|
61
|
+
|
|
62
|
+
## [0.1.0] - 2026
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
|
|
66
|
+
- Initial release of the ByteKit CLI, wrapping the ByteKit SDK as shell
|
|
67
|
+
subcommands, published under the original `rapidcrawl-cli` name.
|
|
68
|
+
|
|
69
|
+
[0.2.2]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/cli
|
|
70
|
+
[0.2.1]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/cli
|
|
71
|
+
[0.2.0]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/cli
|
|
72
|
+
[0.1.0]: https://github.com/Hunt-Labs-Inc/ByteKit/tree/main/packages/cli
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Create an API key at [app.bytekit.com](https://app.bytekit.com) (keys are
|
|
|
32
32
|
prefixed `sk_live_`), then either export it:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
export
|
|
35
|
+
export BYTEKIT_API_KEY=sk_live_xxx
|
|
36
36
|
bytekit scrape create --url https://example.com
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -43,26 +43,30 @@ over the environment variable):
|
|
|
43
43
|
bytekit --key sk_live_xxx scrape create --url https://example.com
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Precedence is `--key` flag → `BYTEKIT_API_KEY` → `RAPIDCRAWL_API_KEY` (legacy
|
|
47
|
+
fallback, deprecated — kept for existing scripts, will eventually be removed).
|
|
48
|
+
|
|
49
|
+
Without a key, the CLI exits with `Error: API key required. Pass --key or set BYTEKIT_API_KEY.`
|
|
47
50
|
|
|
48
51
|
## Base-URL override
|
|
49
52
|
|
|
50
53
|
Requests go to `https://api.bytekit.com` by default. Point the CLI at staging, a
|
|
51
54
|
local gateway, or a proxy with the global `--base-url` flag or the
|
|
52
|
-
`
|
|
55
|
+
`BYTEKIT_BASE_URL` environment variable (the flag wins; `RAPIDCRAWL_BASE_URL` is
|
|
56
|
+
a deprecated legacy fallback):
|
|
53
57
|
|
|
54
58
|
```bash
|
|
55
59
|
bytekit --base-url https://api-stg.bytekit.com scrape create --url https://example.com
|
|
56
|
-
export
|
|
60
|
+
export BYTEKIT_BASE_URL=http://localhost:3001
|
|
57
61
|
```
|
|
58
62
|
|
|
59
63
|
## Global options
|
|
60
64
|
|
|
61
|
-
| Flag | Env var
|
|
62
|
-
| ------------------ |
|
|
63
|
-
| `--key <key>` | `RAPIDCRAWL_API_KEY`
|
|
64
|
-
| `--base-url <url>` | `RAPIDCRAWL_BASE_URL` | API base URL (default `https://api.bytekit.com`). |
|
|
65
|
-
| `--json` | —
|
|
65
|
+
| Flag | Env var | Purpose |
|
|
66
|
+
| ------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
67
|
+
| `--key <key>` | `BYTEKIT_API_KEY` (legacy fallback: `RAPIDCRAWL_API_KEY`) | API key used for every request. |
|
|
68
|
+
| `--base-url <url>` | `BYTEKIT_BASE_URL` (legacy fallback: `RAPIDCRAWL_BASE_URL`) | API base URL (default `https://api.bytekit.com`). |
|
|
69
|
+
| `--json` | — | Print the raw JSON response instead of the human-readable rendering. |
|
|
66
70
|
|
|
67
71
|
## Commands
|
|
68
72
|
|
|
@@ -130,15 +134,6 @@ bytekit account api-keys list
|
|
|
130
134
|
bytekit account api-keys create --name "ci-key"
|
|
131
135
|
```
|
|
132
136
|
|
|
133
|
-
### `recordings` — deactivated
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
bytekit recordings get rec_123abc
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
The `/v1/recordings` endpoints are deactivated server-side and return HTTP 410;
|
|
140
|
-
the subcommand remains only so existing scripts fail loudly rather than silently.
|
|
141
|
-
|
|
142
137
|
## Documentation
|
|
143
138
|
|
|
144
139
|
Full API reference: [bytekit.com/docs](https://bytekit.com/docs).
|
package/dist/client.d.ts
CHANGED
|
@@ -47,8 +47,11 @@ export declare function createRetryingRequest(apiKey: string, baseUrl: string):
|
|
|
47
47
|
/**
|
|
48
48
|
* Build an authenticated SDK client from global CLI options.
|
|
49
49
|
*
|
|
50
|
-
* Resolution order
|
|
51
|
-
*
|
|
50
|
+
* Resolution order (explicit input beats environment; new brand beats legacy brand):
|
|
51
|
+
* apiKey: --key flag → BYTEKIT_API_KEY → RAPIDCRAWL_API_KEY (legacy fallback).
|
|
52
|
+
* baseUrl: --base-url flag → BYTEKIT_BASE_URL → RAPIDCRAWL_BASE_URL (legacy) → DEFAULT_BASE_URL.
|
|
53
|
+
* The legacy RAPIDCRAWL_* vars stay silently honored so existing setups keep working; exits with a
|
|
54
|
+
* descriptive error when no key is available.
|
|
52
55
|
*
|
|
53
56
|
* The returned client's `request` is replaced by the retrying transport, so every command inherits
|
|
54
57
|
* the 429 retry from this one seam.
|
package/dist/client.js
CHANGED
|
@@ -102,19 +102,25 @@ export function createRetryingRequest(apiKey, baseUrl) {
|
|
|
102
102
|
/**
|
|
103
103
|
* Build an authenticated SDK client from global CLI options.
|
|
104
104
|
*
|
|
105
|
-
* Resolution order
|
|
106
|
-
*
|
|
105
|
+
* Resolution order (explicit input beats environment; new brand beats legacy brand):
|
|
106
|
+
* apiKey: --key flag → BYTEKIT_API_KEY → RAPIDCRAWL_API_KEY (legacy fallback).
|
|
107
|
+
* baseUrl: --base-url flag → BYTEKIT_BASE_URL → RAPIDCRAWL_BASE_URL (legacy) → DEFAULT_BASE_URL.
|
|
108
|
+
* The legacy RAPIDCRAWL_* vars stay silently honored so existing setups keep working; exits with a
|
|
109
|
+
* descriptive error when no key is available.
|
|
107
110
|
*
|
|
108
111
|
* The returned client's `request` is replaced by the retrying transport, so every command inherits
|
|
109
112
|
* the 429 retry from this one seam.
|
|
110
113
|
*/
|
|
111
114
|
export function buildClient(opts) {
|
|
112
|
-
const apiKey = opts.key ?? process.env['RAPIDCRAWL_API_KEY'];
|
|
115
|
+
const apiKey = opts.key ?? process.env['BYTEKIT_API_KEY'] ?? process.env['RAPIDCRAWL_API_KEY'];
|
|
113
116
|
if (!apiKey) {
|
|
114
|
-
console.error('Error: API key required. Pass --key or set
|
|
117
|
+
console.error('Error: API key required. Pass --key or set BYTEKIT_API_KEY.');
|
|
115
118
|
process.exit(1);
|
|
116
119
|
}
|
|
117
|
-
const baseUrl = opts.baseUrl ??
|
|
120
|
+
const baseUrl = opts.baseUrl ??
|
|
121
|
+
process.env['BYTEKIT_BASE_URL'] ??
|
|
122
|
+
process.env['RAPIDCRAWL_BASE_URL'] ??
|
|
123
|
+
DEFAULT_BASE_URL;
|
|
118
124
|
const client = new RapidCrawl({ apiKey, baseUrl });
|
|
119
125
|
client.request = createRetryingRequest(apiKey, baseUrl);
|
|
120
126
|
return client;
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@ import { createRequire } from 'node:module';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { makeScrapeCommand } from './commands/scrape.js';
|
|
7
7
|
import { makeScreenshotsCommand } from './commands/screenshots.js';
|
|
8
|
-
import { makeRecordingsCommand } from './commands/recordings.js';
|
|
9
8
|
import { makeBulkCommand } from './commands/bulk.js';
|
|
10
9
|
import { makeFetchCommand } from './commands/fetch.js';
|
|
11
10
|
import { makeMonitorsCommand } from './commands/monitors.js';
|
|
@@ -25,8 +24,8 @@ export function buildProgram() {
|
|
|
25
24
|
.name('bytekit')
|
|
26
25
|
.description('ByteKit CLI — capture, scrape, monitor')
|
|
27
26
|
.version(version)
|
|
28
|
-
.option('--key <key>', 'API key (or set
|
|
29
|
-
.option('--base-url <url>', 'Base URL override (or set
|
|
27
|
+
.option('--key <key>', 'API key (or set BYTEKIT_API_KEY)')
|
|
28
|
+
.option('--base-url <url>', 'Base URL override (or set BYTEKIT_BASE_URL)')
|
|
30
29
|
.option('--json', 'Output raw JSON');
|
|
31
30
|
/** Read global options from the root program instance. */
|
|
32
31
|
const getGlobal = () => {
|
|
@@ -39,7 +38,6 @@ export function buildProgram() {
|
|
|
39
38
|
};
|
|
40
39
|
program.addCommand(makeScrapeCommand(getGlobal));
|
|
41
40
|
program.addCommand(makeScreenshotsCommand(getGlobal));
|
|
42
|
-
program.addCommand(makeRecordingsCommand(getGlobal));
|
|
43
41
|
program.addCommand(makeBulkCommand(getGlobal));
|
|
44
42
|
program.addCommand(makeFetchCommand(getGlobal));
|
|
45
43
|
program.addCommand(makeMonitorsCommand(getGlobal));
|
package/dist/output.d.ts
CHANGED
|
@@ -59,8 +59,15 @@ export declare function extractRawBody(response: unknown, requestedFormat?: stri
|
|
|
59
59
|
/**
|
|
60
60
|
* Emit a raw body to the target.
|
|
61
61
|
*
|
|
62
|
-
* Uses `process.stdout.write`, never `console.log`: `console.log` appends a newline,
|
|
63
|
-
* make the stdout bytes and the `--output` file bytes differ.
|
|
62
|
+
* Uses `process.stdout.write`, never `console.log`: `console.log` unconditionally appends a newline,
|
|
63
|
+
* which would make the stdout bytes and the `--output` file bytes differ.
|
|
64
|
+
*
|
|
65
|
+
* Trailing-newline rule (#2452 item 6): a body has no guaranteed trailing newline (a scraped markdown
|
|
66
|
+
* page rarely ends in one), so a naked `--raw` glued the shell prompt onto the last line. When stdout
|
|
67
|
+
* is an interactive TTY we append a single newline (idempotent — never doubling an existing one) so the
|
|
68
|
+
* prompt starts cleanly. Off a TTY (a pipe or `>`/`>>` redirect) we write the body verbatim, preserving
|
|
69
|
+
* the byte-exact invariant that `--raw > file` matches `--output file`. A FILE destination is never
|
|
70
|
+
* touched by this rule at all.
|
|
64
71
|
*/
|
|
65
72
|
export declare function emitRaw(body: string, target: OutputTarget): void;
|
|
66
73
|
/**
|
package/dist/output.js
CHANGED
|
@@ -74,15 +74,23 @@ export function extractRawBody(response, requestedFormat) {
|
|
|
74
74
|
/**
|
|
75
75
|
* Emit a raw body to the target.
|
|
76
76
|
*
|
|
77
|
-
* Uses `process.stdout.write`, never `console.log`: `console.log` appends a newline,
|
|
78
|
-
* make the stdout bytes and the `--output` file bytes differ.
|
|
77
|
+
* Uses `process.stdout.write`, never `console.log`: `console.log` unconditionally appends a newline,
|
|
78
|
+
* which would make the stdout bytes and the `--output` file bytes differ.
|
|
79
|
+
*
|
|
80
|
+
* Trailing-newline rule (#2452 item 6): a body has no guaranteed trailing newline (a scraped markdown
|
|
81
|
+
* page rarely ends in one), so a naked `--raw` glued the shell prompt onto the last line. When stdout
|
|
82
|
+
* is an interactive TTY we append a single newline (idempotent — never doubling an existing one) so the
|
|
83
|
+
* prompt starts cleanly. Off a TTY (a pipe or `>`/`>>` redirect) we write the body verbatim, preserving
|
|
84
|
+
* the byte-exact invariant that `--raw > file` matches `--output file`. A FILE destination is never
|
|
85
|
+
* touched by this rule at all.
|
|
79
86
|
*/
|
|
80
87
|
export function emitRaw(body, target) {
|
|
81
88
|
if (target.file !== undefined) {
|
|
82
89
|
writeFileSync(target.file, body);
|
|
83
90
|
return;
|
|
84
91
|
}
|
|
85
|
-
process.stdout.
|
|
92
|
+
const appendNewline = process.stdout.isTTY === true && !body.endsWith('\n');
|
|
93
|
+
process.stdout.write(appendNewline ? `${body}\n` : body);
|
|
86
94
|
}
|
|
87
95
|
/**
|
|
88
96
|
* The single output dispatch a command calls — so no command needs `node:fs` and every rendering
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hunt-labs/bytekit-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "ByteKit CLI — wraps @hunt-labs/bytekit-sdk as shell subcommands",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -32,19 +32,16 @@
|
|
|
32
32
|
],
|
|
33
33
|
"homepage": "https://bytekit.com/docs",
|
|
34
34
|
"bugs": {
|
|
35
|
-
"email": "support@bytekit.com"
|
|
35
|
+
"email": "support@bytekit.com",
|
|
36
|
+
"url": "https://bytekit.com/contact"
|
|
36
37
|
},
|
|
37
38
|
"files": [
|
|
38
|
-
"dist"
|
|
39
|
+
"dist",
|
|
40
|
+
"CHANGELOG.md"
|
|
39
41
|
],
|
|
40
42
|
"dependencies": {
|
|
41
43
|
"commander": "^12.0.0",
|
|
42
|
-
"@hunt-labs/bytekit-sdk": "^0.2.
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@types/node": "^22.0.0",
|
|
46
|
-
"typescript": "^5.0.0",
|
|
47
|
-
"vitest": "^1.0.0"
|
|
44
|
+
"@hunt-labs/bytekit-sdk": "^0.2.2"
|
|
48
45
|
},
|
|
49
46
|
"scripts": {
|
|
50
47
|
"build": "tsc",
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { buildClient } from '../client.js';
|
|
3
|
-
import { printResult, handleError } from '../output.js';
|
|
4
|
-
export function makeRecordingsCommand(getGlobal) {
|
|
5
|
-
const cmd = new Command('recordings').description('Recording operations');
|
|
6
|
-
cmd
|
|
7
|
-
.command('create')
|
|
8
|
-
.description('Start a page recording')
|
|
9
|
-
.requiredOption('--url <url>', 'URL to record')
|
|
10
|
-
.action(async (opts) => {
|
|
11
|
-
const g = getGlobal();
|
|
12
|
-
const client = buildClient(g);
|
|
13
|
-
try {
|
|
14
|
-
const result = await client.recordings.create({ url: opts.url });
|
|
15
|
-
printResult(result, g.json);
|
|
16
|
-
}
|
|
17
|
-
catch (err) {
|
|
18
|
-
handleError(err);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
cmd
|
|
22
|
-
.command('get <id>')
|
|
23
|
-
.description('Get a recording by ID')
|
|
24
|
-
.action(async (id) => {
|
|
25
|
-
const g = getGlobal();
|
|
26
|
-
const client = buildClient(g);
|
|
27
|
-
try {
|
|
28
|
-
const result = await client.recordings.get(id);
|
|
29
|
-
printResult(result, g.json);
|
|
30
|
-
}
|
|
31
|
-
catch (err) {
|
|
32
|
-
handleError(err);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
return cmd;
|
|
36
|
-
}
|