@huntapi/cli 0.0.0-stage → 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HuntAPI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,102 @@
1
- # Temporary Holding Version
1
+ # HuntAPI CLI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Official command-line interface for the [HuntAPI](https://www.huntapi.com) media download API.
4
+
5
+ Download video and audio from public media URLs, or extract their metadata, with one async REST API.
6
+
7
+ Every documented endpoint is a command — **6 commands** — and `request` reaches any other path. JSON responses are pretty-printed; files (images, PDFs…) are saved with `-o`.
8
+
9
+ ## Requirements
10
+
11
+ - Node.js 20 or newer
12
+ - a HuntAPI [API key](https://app.huntapi.com)
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ npm install --global @huntapi/cli
18
+ huntapi --help
19
+ ```
20
+
21
+ Or run it without installing:
22
+
23
+ ```sh
24
+ npx @huntapi/cli --help
25
+ ```
26
+
27
+ ## Configure your API key
28
+
29
+ The CLI reads the key from the environment; it does not load `.env` files.
30
+
31
+ ```sh
32
+ export HUNTAPI_API_KEY="YOUR_API_KEY"
33
+ ```
34
+
35
+ PowerShell:
36
+
37
+ ```powershell
38
+ $env:HUNTAPI_API_KEY = "YOUR_API_KEY"
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ```sh
44
+ huntapi media-metadata --query 'https://www.youtube.com/watch?v=Z5YP8kznWZs'
45
+ ```
46
+
47
+ Parameters use the names of the [API reference](https://docs.huntapi.com) as flags: `--full-page` and `--full_page` are equivalent. Boolean flags can be bare (`--flag`) or explicit (`--flag=false`); array parameters accept commas or repeated flags.
48
+
49
+ ```sh
50
+ huntapi media-metadata --help # parameters of one command
51
+ huntapi endpoints # every command and its HTTP path
52
+ huntapi endpoints search # filter the list
53
+ ```
54
+
55
+ ### JSON parameters
56
+
57
+ ```sh
58
+ echo '{"query": "https://www.youtube.com/watch?v=Z5YP8kznWZs"}' | huntapi media-metadata --params -
59
+ huntapi media-metadata --params params.json --compact
60
+ ```
61
+
62
+ Flags override values read with `--params`.
63
+
64
+ ### Any endpoint
65
+
66
+ ```sh
67
+ huntapi request get /v1/usage
68
+ huntapi request post /v1/some/new/endpoint --params body.json
69
+ ```
70
+
71
+ ### Pipe into jq
72
+
73
+ ```sh
74
+ huntapi media-metadata --query 'https://www.youtube.com/watch?v=Z5YP8kznWZs' | jq .
75
+ ```
76
+
77
+ ## Exit codes
78
+
79
+ | Code | Meaning |
80
+ | ---- | ----------------------------------------------------------------------------------- |
81
+ | `0` | Success. |
82
+ | `1` | The API returned an error (details on standard error) or the network failed. |
83
+ | `2` | Invalid usage: unknown command or parameter, missing API key or required parameter. |
84
+
85
+ ## Commands
86
+
87
+ | Command | HTTP | Description |
88
+ | ---------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
89
+ | `audio-download` | GET / POST `/v1/audio/download` | Download audio from a URL via HuntAPI and receive a job id. |
90
+ | `jobs` | GET `/v1/jobs/{id}` | Poll status, progress (0–100), and result of an async HuntAPI job. |
91
+ | `media-metadata` | GET `/v1/media/metadata` | Extract metadata from a media URL without downloading the file. |
92
+ | `stats` | GET `/v1/stats` | Infrastructure health for an engine or endpoint over the last hour. Not scoped to your account or tenant. Enabled per a… |
93
+ | `usage` | GET `/v1/usage` | Retrieve real-time usage statistics and credit balance for your Huntapi account. |
94
+ | `video-download` | GET / POST `/v1/video/download` | Video Download |
95
+
96
+ ## Built on the SDK
97
+
98
+ The CLI uses the official [Node.js SDK](https://github.com/huntapi/huntapi-node) (`@huntapi/sdk`). Use the SDK directly for programmatic access.
99
+
100
+ ## License
101
+
102
+ MIT — see [LICENSE](LICENSE).
package/SECURITY.md ADDED
@@ -0,0 +1,16 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes are released for the latest published version of the HuntAPI CLI.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please do not report security vulnerabilities through public GitHub issues.
10
+
11
+ Email **contact@huntapi.com** with a description of the issue, the affected version, and steps to reproduce. We acknowledge reports within three business days and keep you informed until the issue is resolved.
12
+
13
+ ## Handling API keys
14
+
15
+ - Keep your HuntAPI API key out of source control. Load it from the `HUNTAPI_API_KEY` environment variable or a secret manager.
16
+ - Rotate the key from the [HuntAPI dashboard](https://app.huntapi.com) if you believe it was exposed.
package/dist/args.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { ParamDefinition } from "./types.js";
2
+ export interface ParsedArgs {
3
+ readonly positionals: string[];
4
+ readonly flags: Map<string, string[]>;
5
+ }
6
+ /**
7
+ * Splits argv into positionals and `--name value` / `--name=value` flags. A flag directly followed by
8
+ * another flag (or nothing) is recorded as the string "true", so boolean parameters can be bare.
9
+ */
10
+ export declare function parseArgs(argv: readonly string[], booleanFlags?: ReadonlySet<string>): ParsedArgs;
11
+ /** `--full-page` and `--full_page` both address the `full_page` parameter. */
12
+ export declare function normalize(name: string): string;
13
+ /** Converts raw flag strings into typed parameter values. */
14
+ export declare function coerce(definition: ParamDefinition, raw: readonly string[]): unknown;
15
+ export declare function flag(name: string): string;
16
+ /** Interprets a free-form value for `request` and `--params` overrides: numbers and booleans stay strings. */
17
+ export declare function looseValue(raw: readonly string[]): unknown;
package/dist/args.js ADDED
@@ -0,0 +1,111 @@
1
+ import { CliUsageError } from "./errors.js";
2
+ const BOOLEAN_CONTROLS = new Set(["help", "h", "version", "raw", "compact"]);
3
+ /**
4
+ * Splits argv into positionals and `--name value` / `--name=value` flags. A flag directly followed by
5
+ * another flag (or nothing) is recorded as the string "true", so boolean parameters can be bare.
6
+ */
7
+ export function parseArgs(argv, booleanFlags = new Set()) {
8
+ const positionals = [];
9
+ const flags = new Map();
10
+ for (let i = 0; i < argv.length; i++) {
11
+ const arg = argv[i];
12
+ if (arg === "--") {
13
+ positionals.push(...argv.slice(i + 1));
14
+ break;
15
+ }
16
+ if (arg === "-o") {
17
+ const value = argv[i + 1];
18
+ if (value === undefined)
19
+ throw new CliUsageError("-o needs a path (or - for standard output).");
20
+ push(flags, "output", value);
21
+ i++;
22
+ continue;
23
+ }
24
+ if (arg === "-h") {
25
+ push(flags, "help", "true");
26
+ continue;
27
+ }
28
+ if (!arg.startsWith("--") || arg === "--") {
29
+ positionals.push(arg);
30
+ continue;
31
+ }
32
+ const body = arg.slice(2);
33
+ const eq = body.indexOf("=");
34
+ if (eq >= 0) {
35
+ push(flags, normalize(body.slice(0, eq)), body.slice(eq + 1));
36
+ continue;
37
+ }
38
+ const name = normalize(body);
39
+ const next = argv[i + 1];
40
+ if (BOOLEAN_CONTROLS.has(name) ||
41
+ booleanFlags.has(name) ||
42
+ next === undefined ||
43
+ next.startsWith("--")) {
44
+ push(flags, name, "true");
45
+ }
46
+ else {
47
+ push(flags, name, next);
48
+ i++;
49
+ }
50
+ }
51
+ return { positionals, flags };
52
+ }
53
+ /** `--full-page` and `--full_page` both address the `full_page` parameter. */
54
+ export function normalize(name) {
55
+ return name.replace(/-/g, "_");
56
+ }
57
+ function push(flags, name, value) {
58
+ const list = flags.get(name) ?? [];
59
+ list.push(value);
60
+ flags.set(name, list);
61
+ }
62
+ /** Converts raw flag strings into typed parameter values. */
63
+ export function coerce(definition, raw) {
64
+ const last = raw[raw.length - 1];
65
+ switch (definition.type) {
66
+ case "boolean":
67
+ if (last === "true" || last === "1")
68
+ return true;
69
+ if (last === "false" || last === "0")
70
+ return false;
71
+ throw new CliUsageError(`--${flag(definition.name)} expects true or false.`);
72
+ case "number":
73
+ case "integer": {
74
+ const value = Number(last);
75
+ if (last.trim() === "" || !Number.isFinite(value)) {
76
+ throw new CliUsageError(`--${flag(definition.name)} expects a number.`);
77
+ }
78
+ if (definition.type === "integer" && !Number.isInteger(value)) {
79
+ throw new CliUsageError(`--${flag(definition.name)} expects an integer.`);
80
+ }
81
+ return value;
82
+ }
83
+ case "array":
84
+ if (definition.items === "object")
85
+ return raw.map((item) => parseJson(definition.name, item));
86
+ return raw.flatMap((item) => item
87
+ .split(",")
88
+ .map((part) => part.trim())
89
+ .filter((part) => part !== ""));
90
+ case "object":
91
+ return parseJson(definition.name, last);
92
+ default:
93
+ return last;
94
+ }
95
+ }
96
+ export function flag(name) {
97
+ return name.replace(/_/g, "-");
98
+ }
99
+ function parseJson(name, text) {
100
+ try {
101
+ return JSON.parse(text);
102
+ }
103
+ catch {
104
+ throw new CliUsageError(`--${flag(name)} expects JSON.`);
105
+ }
106
+ }
107
+ /** Interprets a free-form value for `request` and `--params` overrides: numbers and booleans stay strings. */
108
+ export function looseValue(raw) {
109
+ return raw.length === 1 ? raw[0] : [...raw];
110
+ }
111
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { HuntApiClient, type HuntApiClientOptions } from "@huntapi/sdk";
2
+ import type { CliIo } from "./types.js";
3
+ export type ClientFactory = (options: HuntApiClientOptions) => Pick<HuntApiClient, "request">;
4
+ /** Runs the CLI and returns the process exit code: 0 success, 1 API or network failure, 2 usage error. */
5
+ export declare function runCli(argv: readonly string[], io: CliIo, clientFactory?: ClientFactory): Promise<number>;
package/dist/cli.js ADDED
@@ -0,0 +1,178 @@
1
+ import { HuntApiApiError, HuntApiClient, HuntApiError, } from "@huntapi/sdk";
2
+ import { coerce, looseValue, normalize, parseArgs } from "./args.js";
3
+ import { COMMANDS } from "./commands.js";
4
+ import { CliUsageError } from "./errors.js";
5
+ import { commandHelp, endpointsList, rootHelp } from "./help.js";
6
+ import { VERSION } from "./version.js";
7
+ const DEFAULT_FACTORY = (options) => new HuntApiClient(options);
8
+ const CONTROL_FLAGS = new Set([
9
+ "output",
10
+ "method",
11
+ "params",
12
+ "help",
13
+ "compact",
14
+ "raw",
15
+ ]);
16
+ /** Runs the CLI and returns the process exit code: 0 success, 1 API or network failure, 2 usage error. */
17
+ export async function runCli(argv, io, clientFactory = DEFAULT_FACTORY) {
18
+ try {
19
+ return await dispatch(argv, io, clientFactory);
20
+ }
21
+ catch (error) {
22
+ if (error instanceof CliUsageError) {
23
+ io.stderr.write(`Error: ${error.message}\n`);
24
+ return 2;
25
+ }
26
+ if (error instanceof HuntApiApiError) {
27
+ io.stderr.write(`HuntAPI API error ${error.status}: ${error.message}\n`);
28
+ if (error.responseBody !== undefined)
29
+ io.stderr.write(`${JSON.stringify(error.responseBody, null, 2)}\n`);
30
+ return 1;
31
+ }
32
+ if (error instanceof HuntApiError) {
33
+ io.stderr.write(`Error: ${error.message}\n`);
34
+ return error.name.endsWith("ConfigurationError") ? 2 : 1;
35
+ }
36
+ throw error;
37
+ }
38
+ }
39
+ async function dispatch(argv, io, clientFactory) {
40
+ const [first, ...rest] = argv;
41
+ if (first === undefined ||
42
+ first === "--help" ||
43
+ first === "-h" ||
44
+ first === "help") {
45
+ io.stdout.write(rootHelp());
46
+ return first === undefined ? 2 : 0;
47
+ }
48
+ if (first === "--version" || first === "-v") {
49
+ io.stdout.write(`${VERSION}\n`);
50
+ return 0;
51
+ }
52
+ if (first === "endpoints") {
53
+ io.stdout.write(endpointsList(rest[0]));
54
+ return 0;
55
+ }
56
+ if (first === "request") {
57
+ return runRequest(rest, io, clientFactory);
58
+ }
59
+ const command = COMMANDS.find((c) => c.command === first || c.operation === first);
60
+ if (!command) {
61
+ throw new CliUsageError(`Unknown command "${first}". Run "huntapi endpoints" to list commands.`);
62
+ }
63
+ const booleans = new Set(command.params.filter((p) => p.type === "boolean").map((p) => p.name));
64
+ const parsed = parseArgs(rest, booleans);
65
+ if (parsed.flags.has("help")) {
66
+ io.stdout.write(commandHelp(command));
67
+ return 0;
68
+ }
69
+ if (parsed.positionals.length > 0) {
70
+ throw new CliUsageError(`Unexpected argument "${parsed.positionals[0]}". Pass parameters as --name value.`);
71
+ }
72
+ const params = await readParamsFile(parsed.flags, io);
73
+ for (const [name, raw] of parsed.flags) {
74
+ if (CONTROL_FLAGS.has(name))
75
+ continue;
76
+ const definition = command.params.find((p) => p.name === name);
77
+ if (!definition) {
78
+ throw new CliUsageError(`Unknown parameter --${name.replace(/_/g, "-")} for ${command.command}. Run "huntapi ${command.command} --help".`);
79
+ }
80
+ params[name] = coerce(definition, raw);
81
+ }
82
+ const missing = command.params.filter((p) => p.required && params[p.name] === undefined);
83
+ if (missing.length > 0) {
84
+ throw new CliUsageError(`Missing required parameter${missing.length > 1 ? "s" : ""}: ${missing.map((p) => `--${p.name.replace(/_/g, "-")}`).join(", ")}.`);
85
+ }
86
+ const method = readMethod(parsed.flags, command);
87
+ const client = createClient(io, clientFactory);
88
+ const response = await client.request(method, command.path, params);
89
+ return writeResponse(response, parsed.flags, io);
90
+ }
91
+ async function runRequest(argv, io, clientFactory) {
92
+ const parsed = parseArgs(argv);
93
+ if (parsed.flags.has("help")) {
94
+ io.stdout.write("Usage:\n huntapi request <get|post> <path> [--name value ...] [-o <path|->] [--params <file|->]\n");
95
+ return 0;
96
+ }
97
+ const [method, path, extra] = parsed.positionals;
98
+ if (!method || !path || extra !== undefined) {
99
+ throw new CliUsageError("request needs exactly <get|post> and <path>, e.g. huntapi request get /v1/usage");
100
+ }
101
+ const verb = method.toUpperCase();
102
+ if (verb !== "GET" && verb !== "POST")
103
+ throw new CliUsageError(`Unsupported method "${method}".`);
104
+ if (!path.startsWith("/"))
105
+ throw new CliUsageError('The path must start with "/".');
106
+ const params = await readParamsFile(parsed.flags, io);
107
+ for (const [name, raw] of parsed.flags) {
108
+ if (!CONTROL_FLAGS.has(name))
109
+ params[name] = looseValue(raw);
110
+ }
111
+ const client = createClient(io, clientFactory);
112
+ const response = await client.request(verb, path, params);
113
+ return writeResponse(response, parsed.flags, io);
114
+ }
115
+ function readMethod(flags, command) {
116
+ const raw = flags.get("method")?.at(-1);
117
+ if (raw === undefined)
118
+ return command.methods[0];
119
+ const method = raw.toUpperCase();
120
+ if (method !== "GET" && method !== "POST")
121
+ throw new CliUsageError(`--method must be get or post.`);
122
+ if (!command.methods.includes(method)) {
123
+ throw new CliUsageError(`${command.command} supports ${command.methods.join(", ").toLowerCase()} only.`);
124
+ }
125
+ return method;
126
+ }
127
+ async function readParamsFile(flags, io) {
128
+ const source = flags.get("params")?.at(-1);
129
+ if (source === undefined)
130
+ return {};
131
+ const text = source === "-" ? await io.readStdin() : await io.readFile(source);
132
+ let value;
133
+ try {
134
+ value = JSON.parse(text);
135
+ }
136
+ catch {
137
+ throw new CliUsageError("--params must contain a JSON object.");
138
+ }
139
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
140
+ throw new CliUsageError("--params must contain a JSON object.");
141
+ }
142
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [normalize(k), v]));
143
+ }
144
+ function createClient(io, clientFactory) {
145
+ const apiKey = io.env.HUNTAPI_API_KEY;
146
+ if (!apiKey || apiKey.trim() === "") {
147
+ throw new CliUsageError("Set the HUNTAPI_API_KEY environment variable to your HuntAPI API key.");
148
+ }
149
+ const baseUrl = io.env.HUNTAPI_BASE_URL;
150
+ return clientFactory({ apiKey, ...(baseUrl ? { baseUrl } : {}) });
151
+ }
152
+ async function writeResponse(response, flags, io) {
153
+ const output = flags.get("output")?.at(-1);
154
+ const compact = flags.has("compact");
155
+ if (response.kind === "json") {
156
+ const text = `${JSON.stringify(response.data, null, compact ? 0 : 2)}\n`;
157
+ if (output === undefined || output === "-")
158
+ io.stdout.write(text);
159
+ else
160
+ await io.writeFile(output, text);
161
+ return 0;
162
+ }
163
+ if (output === undefined) {
164
+ if (io.stdout.isTTY) {
165
+ throw new CliUsageError(`The response is binary (${response.contentType ?? "unknown type"}). Use -o <file> to save it, or -o - to pipe it.`);
166
+ }
167
+ io.stdout.write(response.bytes);
168
+ return 0;
169
+ }
170
+ if (output === "-")
171
+ io.stdout.write(response.bytes);
172
+ else {
173
+ await io.writeFile(output, response.bytes);
174
+ io.stderr.write(`Saved ${output} (${response.contentType ?? "binary"}, ${response.bytes.length} bytes)\n`);
175
+ }
176
+ return 0;
177
+ }
178
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { CommandDefinition } from "./types.js";
2
+ export declare const COMMANDS: readonly CommandDefinition[];
@@ -0,0 +1,237 @@
1
+ // Generated from the HuntAPI OpenAPI document. Do not edit by hand.
2
+ export const COMMANDS = [
3
+ {
4
+ command: "audio-download",
5
+ operation: "audio_download",
6
+ path: "/v1/audio/download",
7
+ methods: ["GET", "POST"],
8
+ summary: "Audio Download",
9
+ description: "Download audio from a URL via HuntAPI and receive a job id.",
10
+ params: [
11
+ {
12
+ name: "query",
13
+ type: "string",
14
+ required: true,
15
+ description: "URL to download audio from.",
16
+ },
17
+ {
18
+ name: "download_type",
19
+ type: "string",
20
+ required: false,
21
+ description: "Desired download type. Supported values: audio (default).",
22
+ default: "audio",
23
+ },
24
+ {
25
+ name: "max_duration",
26
+ type: "number",
27
+ required: false,
28
+ description: "Maximum duration of the downloaded content in seconds. If the audio is longer than this value, only the content up to this duration will be downloaded.",
29
+ },
30
+ {
31
+ name: "audio_quality",
32
+ type: "string",
33
+ required: false,
34
+ description: "Desired audio quality.",
35
+ default: "best",
36
+ },
37
+ {
38
+ name: "audio_format",
39
+ type: "string",
40
+ required: false,
41
+ description: "Desired output format for the audio.",
42
+ default: "mp3",
43
+ },
44
+ {
45
+ name: "webhook_url",
46
+ type: "string",
47
+ required: false,
48
+ description: "URL of the webhook where results will be sent. When specified, the system will attempt to send the response to this URL up to 3 times with a 5-second delay between each attempt. The results will be s…",
49
+ },
50
+ {
51
+ name: "webhook_authorization",
52
+ type: "string",
53
+ required: false,
54
+ description: "Authorization header for the webhook. This parameter allows you to add authentication to your webhook endpoint.",
55
+ },
56
+ {
57
+ name: "fields",
58
+ type: "string",
59
+ required: false,
60
+ description: "Comma-separated list of fields to keep in the response, with dot notation for nested fields (e.g. name,location.city). Does not change the credit cost.",
61
+ },
62
+ {
63
+ name: "is_async",
64
+ type: "boolean",
65
+ required: false,
66
+ description: "Process the request asynchronously: the response is a job_id to poll on /v1/jobs/{id} (see waitForJob).",
67
+ default: false,
68
+ },
69
+ {
70
+ name: "soft_fail",
71
+ type: "boolean",
72
+ required: false,
73
+ description: "Return HTTP 200 even when an error occurs; the error is then in the response body.",
74
+ default: false,
75
+ },
76
+ ],
77
+ },
78
+ {
79
+ command: "jobs",
80
+ operation: "jobs",
81
+ path: "/v1/jobs/{id}",
82
+ methods: ["GET"],
83
+ summary: "Jobs",
84
+ description: "Poll status, progress (0–100), and result of an async HuntAPI job.",
85
+ params: [
86
+ {
87
+ name: "id",
88
+ type: "string",
89
+ required: true,
90
+ description: "Job UUID returned as job_id by async endpoints such as /v1/video/download and /v1/audio/download.",
91
+ },
92
+ ],
93
+ },
94
+ {
95
+ command: "media-metadata",
96
+ operation: "media_metadata",
97
+ path: "/v1/media/metadata",
98
+ methods: ["GET"],
99
+ summary: "Media Metadata",
100
+ description: "Extract metadata from a media URL without downloading the file.",
101
+ params: [
102
+ {
103
+ name: "query",
104
+ type: "string",
105
+ required: true,
106
+ description: "Media URL to inspect (YouTube, Instagram, TikTok, Vimeo, X, Facebook, Twitch, Reddit, etc.).",
107
+ },
108
+ {
109
+ name: "fields",
110
+ type: "string",
111
+ required: false,
112
+ description: "Comma-separated list of fields to keep in the response, with dot notation for nested fields (e.g. name,location.city). Does not change the credit cost.",
113
+ },
114
+ {
115
+ name: "is_async",
116
+ type: "boolean",
117
+ required: false,
118
+ description: "Process the request asynchronously: the response is a job_id to poll on /v1/jobs/{id} (see waitForJob).",
119
+ default: false,
120
+ },
121
+ {
122
+ name: "soft_fail",
123
+ type: "boolean",
124
+ required: false,
125
+ description: "Return HTTP 200 even when an error occurs; the error is then in the response body.",
126
+ default: false,
127
+ },
128
+ ],
129
+ },
130
+ {
131
+ command: "stats",
132
+ operation: "stats",
133
+ path: "/v1/stats",
134
+ methods: ["GET"],
135
+ summary: "Stats",
136
+ description: "Infrastructure health for an engine or endpoint over the last hour. Not scoped to your account or tenant. Enabled per account: HTTP 403 means contact support to activate it.",
137
+ params: [
138
+ {
139
+ name: "engine",
140
+ type: "string",
141
+ required: false,
142
+ description: "API family to check, for example video. Provide at least engine or path.",
143
+ },
144
+ {
145
+ name: "path",
146
+ type: "string",
147
+ required: false,
148
+ description: "Specific endpoint to check, for example /v1/video/download. If you also pass engine, use an endpoint from that API.",
149
+ },
150
+ ],
151
+ },
152
+ {
153
+ command: "usage",
154
+ operation: "usage",
155
+ path: "/v1/usage",
156
+ methods: ["GET"],
157
+ summary: "Usage",
158
+ description: "Retrieve real-time usage statistics and credit balance for your Huntapi account.",
159
+ params: [],
160
+ },
161
+ {
162
+ command: "video-download",
163
+ operation: "video_download",
164
+ path: "/v1/video/download",
165
+ methods: ["GET", "POST"],
166
+ summary: "Video Download",
167
+ description: "",
168
+ params: [
169
+ {
170
+ name: "query",
171
+ type: "string",
172
+ required: true,
173
+ description: "Video URL to download.",
174
+ },
175
+ {
176
+ name: "download_type",
177
+ type: "string",
178
+ required: false,
179
+ description: "Desired download type. You have three options:",
180
+ default: "audio_video",
181
+ },
182
+ {
183
+ name: "max_duration",
184
+ type: "number",
185
+ required: false,
186
+ description: "Maximum duration of the downloaded content in seconds. If the video/audio is longer than this value, only the content up to this duration will be downloaded.",
187
+ },
188
+ {
189
+ name: "video_quality",
190
+ type: "string",
191
+ required: false,
192
+ description: "Desired video quality. Available options:",
193
+ default: "best",
194
+ },
195
+ {
196
+ name: "video_format",
197
+ type: "string",
198
+ required: false,
199
+ description: "Desired output format for the video. Available options:",
200
+ default: "mp4",
201
+ },
202
+ {
203
+ name: "webhook_url",
204
+ type: "string",
205
+ required: false,
206
+ description: "URL of the webhook where results will be sent. When specified, the system will attempt to send the response to this URL up to 3 times with a 5-second delay between each attempt. The results will be s…",
207
+ },
208
+ {
209
+ name: "webhook_authorization",
210
+ type: "string",
211
+ required: false,
212
+ description: "Authorization header for the webhook. This parameter allows you to add authentication to your webhook endpoint. This value will be included in the Authorization header when making the webhook request…",
213
+ },
214
+ {
215
+ name: "fields",
216
+ type: "string",
217
+ required: false,
218
+ description: "Comma-separated list of fields to keep in the response, with dot notation for nested fields (e.g. name,location.city). Does not change the credit cost.",
219
+ },
220
+ {
221
+ name: "is_async",
222
+ type: "boolean",
223
+ required: false,
224
+ description: "Process the request asynchronously: the response is a job_id to poll on /v1/jobs/{id} (see waitForJob).",
225
+ default: false,
226
+ },
227
+ {
228
+ name: "soft_fail",
229
+ type: "boolean",
230
+ required: false,
231
+ description: "Return HTTP 200 even when an error occurs; the error is then in the response body.",
232
+ default: false,
233
+ },
234
+ ],
235
+ },
236
+ ];
237
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** Invalid command-line usage; exits with status 2. */
2
+ export declare class CliUsageError extends Error {
3
+ constructor(message: string);
4
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,8 @@
1
+ /** Invalid command-line usage; exits with status 2. */
2
+ export class CliUsageError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "CliUsageError";
6
+ }
7
+ }
8
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
package/dist/help.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { CommandDefinition } from "./types.js";
2
+ export declare function rootHelp(): string;
3
+ export declare function commandHelp(command: CommandDefinition): string;
4
+ export declare function endpointsList(filter: string | undefined): string;
package/dist/help.js ADDED
@@ -0,0 +1,78 @@
1
+ import { flag } from "./args.js";
2
+ import { COMMANDS } from "./commands.js";
3
+ export function rootHelp() {
4
+ const width = Math.max(...COMMANDS.map((c) => c.command.length), "endpoints".length) + 2;
5
+ const lines = COMMANDS.map((c) => ` ${c.command.padEnd(width)}${c.summary}`);
6
+ return `HuntAPI CLI — media download API
7
+
8
+ Usage:
9
+ huntapi <command> [--param value ...] [-o <path|->] [--method get|post] [--params <file|->]
10
+ huntapi request <get|post> <path> [--param value ...]
11
+ huntapi endpoints [filter]
12
+ huntapi --help | --version
13
+
14
+ Commands:
15
+ ${lines.join("\n")}
16
+
17
+ ${"request".padEnd(width)}Call any API path.
18
+ ${"endpoints".padEnd(width)}List commands with their HTTP paths.
19
+
20
+ Environment:
21
+ HUNTAPI_API_KEY API key (required).
22
+
23
+ Run "huntapi <command> --help" for the parameters of a command.
24
+ `;
25
+ }
26
+ export function commandHelp(command) {
27
+ const params = command.params.map(formatParam).join("\n");
28
+ return `${command.summary} — ${command.methods.join(" / ")} ${command.path}
29
+ ${command.description ? `\n${command.description}\n` : ""}
30
+ Usage:
31
+ huntapi ${command.command}${command.params
32
+ .filter((p) => p.required)
33
+ .map((p) => ` --${flag(p.name)} <${p.type}>`)
34
+ .join("")} [options]
35
+
36
+ Parameters:
37
+ ${params || " (none)"}
38
+
39
+ CLI controls:
40
+ -o, --output <path|-> Write the response to a file, or - for standard output.
41
+ --method <get|post> HTTP method (default ${command.methods[0].toLowerCase()}).
42
+ --params <path|-> Read a JSON object of parameters from a file or standard input; flags override it.
43
+ --compact Print JSON on one line.
44
+ --help Show this help.
45
+ `;
46
+ }
47
+ function formatParam(param) {
48
+ const shape = param.type === "boolean"
49
+ ? "[=true|false]"
50
+ : ` <${param.type === "array" ? `${param.items ?? "string"},...` : param.type}>`;
51
+ const notes = [];
52
+ if (param.required)
53
+ notes.push("required");
54
+ if (param.enum)
55
+ notes.push(`one of: ${param.enum.slice(0, 12).join(", ")}${param.enum.length > 12 ? ", …" : ""}`);
56
+ if (param.default !== undefined)
57
+ notes.push(`default: ${JSON.stringify(param.default)}`);
58
+ const head = ` --${flag(param.name)}${shape}`;
59
+ const description = [
60
+ param.description,
61
+ notes.length ? `(${notes.join("; ")})` : "",
62
+ ]
63
+ .filter(Boolean)
64
+ .join(" ");
65
+ return description ? `${head}\n ${description}` : head;
66
+ }
67
+ export function endpointsList(filter) {
68
+ const needle = filter?.toLowerCase();
69
+ const rows = COMMANDS.filter((c) => !needle ||
70
+ c.command.includes(needle) ||
71
+ c.path.toLowerCase().includes(needle) ||
72
+ c.summary.toLowerCase().includes(needle));
73
+ const width = Math.max(0, ...rows.map((c) => c.command.length)) + 2;
74
+ return (rows
75
+ .map((c) => `${c.command.padEnd(width)}${c.methods.join("/").padEnd(10)}${c.path}`)
76
+ .join("\n") + "\n");
77
+ }
78
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import process from "node:process";
4
+ import { runCli } from "./cli.js";
5
+ async function readStdin() {
6
+ const chunks = [];
7
+ for await (const chunk of process.stdin)
8
+ chunks.push(Buffer.from(chunk));
9
+ return Buffer.concat(chunks).toString("utf8");
10
+ }
11
+ process.exitCode = await runCli(process.argv.slice(2), {
12
+ env: process.env,
13
+ stdout: process.stdout,
14
+ stderr: process.stderr,
15
+ readStdin,
16
+ writeFile: (path, data) => writeFile(path, data),
17
+ readFile: (path) => readFile(path, "utf8"),
18
+ });
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAmB,CAAC,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,OAAO,CAAC,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACrD,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,SAAS;IACT,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;IAChD,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CAC3C,CAAC,CAAC"}
@@ -0,0 +1,33 @@
1
+ export type ParamType = "string" | "integer" | "number" | "boolean" | "array" | "object";
2
+ export interface ParamDefinition {
3
+ readonly name: string;
4
+ readonly type: ParamType;
5
+ readonly items?: ParamType;
6
+ readonly required: boolean;
7
+ readonly description: string;
8
+ readonly enum?: readonly string[];
9
+ readonly default?: unknown;
10
+ }
11
+ export interface CommandDefinition {
12
+ readonly command: string;
13
+ readonly operation: string;
14
+ readonly path: string;
15
+ readonly methods: readonly ("GET" | "POST")[];
16
+ readonly summary: string;
17
+ readonly description: string;
18
+ readonly params: readonly ParamDefinition[];
19
+ }
20
+ /** Process streams and environment, injectable for tests. */
21
+ export interface CliIo {
22
+ readonly env: Readonly<Record<string, string | undefined>>;
23
+ readonly stdout: {
24
+ write(chunk: string | Uint8Array): unknown;
25
+ isTTY?: boolean;
26
+ };
27
+ readonly stderr: {
28
+ write(chunk: string): unknown;
29
+ };
30
+ readonly readStdin: () => Promise<string>;
31
+ readonly writeFile: (path: string, data: string | Uint8Array) => Promise<void>;
32
+ readonly readFile: (path: string) => Promise<string>;
33
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export declare const VERSION = "0.1.0";
@@ -0,0 +1,2 @@
1
+ export const VERSION = "0.1.0";
2
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,57 @@
1
1
  {
2
2
  "name": "@huntapi/cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Official command-line interface for the HuntAPI media download API.",
5
+ "type": "module",
6
+ "bin": {
7
+ "huntapi": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE",
13
+ "SECURITY.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "npm run clean && tsc -p tsconfig.build.json",
17
+ "clean": "node -e \"require('node:fs').rmSync('dist', { force: true, recursive: true })\"",
18
+ "format:check": "prettier --check .",
19
+ "prepack": "npm run build",
20
+ "test": "tsx --test test/*.test.ts",
21
+ "typecheck": "tsc -p tsconfig.json"
22
+ },
23
+ "author": "HuntAPI",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/huntapi/huntapi-cli.git"
28
+ },
29
+ "homepage": "https://github.com/huntapi/huntapi-cli#readme",
30
+ "bugs": {
31
+ "url": "https://github.com/huntapi/huntapi-cli/issues"
32
+ },
33
+ "keywords": [
34
+ "cli",
35
+ "command-line",
36
+ "huntapi",
37
+ "video-download-api",
38
+ "audio-download-api",
39
+ "media-metadata",
40
+ "async-api"
41
+ ],
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "engines": {
46
+ "node": ">=20"
47
+ },
48
+ "dependencies": {
49
+ "@huntapi/sdk": "^0.1.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^22.10.0",
53
+ "prettier": "^3.4.2",
54
+ "tsx": "^4.19.2",
55
+ "typescript": "^5.7.2"
56
+ }
57
+ }