@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 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 RAPIDCRAWL_API_KEY=sk_live_xxx
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
- Without a key, the CLI exits with `Error: API key required. Pass --key or set RAPIDCRAWL_API_KEY.`
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
- `RAPIDCRAWL_BASE_URL` environment variable (the flag wins):
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 RAPIDCRAWL_BASE_URL=http://localhost:3001
60
+ export BYTEKIT_BASE_URL=http://localhost:3001
57
61
  ```
58
62
 
59
63
  ## Global options
60
64
 
61
- | Flag | Env var | Purpose |
62
- | ------------------ | --------------------- | -------------------------------------------------------------------- |
63
- | `--key <key>` | `RAPIDCRAWL_API_KEY` | API key used for every request. |
64
- | `--base-url <url>` | `RAPIDCRAWL_BASE_URL` | API base URL (default `https://api.bytekit.com`). |
65
- | `--json` | — | Print the raw JSON response instead of the human-readable rendering. |
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 for apiKey: --key flag → RAPIDCRAWL_API_KEY env var.
51
- * Exits with a descriptive error when no key is available.
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 for apiKey: --key flag → RAPIDCRAWL_API_KEY env var.
106
- * Exits with a descriptive error when no key is available.
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 RAPIDCRAWL_API_KEY.');
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 ?? process.env['RAPIDCRAWL_BASE_URL'] ?? DEFAULT_BASE_URL;
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 RAPIDCRAWL_API_KEY)')
29
- .option('--base-url <url>', 'Base URL override (or set RAPIDCRAWL_BASE_URL)')
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, which would
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, which would
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.write(body);
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.0",
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.0"
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,5 +0,0 @@
1
- import { Command } from 'commander';
2
- import { type GlobalOptions } from '../client.js';
3
- export declare function makeRecordingsCommand(getGlobal: () => GlobalOptions & {
4
- json: boolean;
5
- }): Command;
@@ -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
- }