diff --git a/README.md b/README.md index 1c14c2e..ed52d65 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ The CLI is the right tool when you need direct shell access, scripting, or autom - **Pipe-friendly by design**. Compact JSON when piped, human-readable output in a TTY, and explicit exit codes for authentication, validation, rate limits, and API errors. -- **Fast time to value**. From API token to your first scrape in minutes. Install with one command or use `npx` with zero setup. +- **Fast time to value**. From API key to your first scrape in minutes. Install with one command or use `npx` with zero setup. ## Use cases @@ -69,7 +69,7 @@ Common scenarios: ## Quick start 1. **Create a free account** at [dashboard.decodo.com](https://dashboard.decodo.com/) — get up to 2K free requests with no credit card required. -2. **Get your Web Scraping API token** from the Decodo [Playground](https://dashboard.decodo.com/playground). +2. **Get your Web Data API key** from your Web Data API subscription on the Decodo [dashboard](https://dashboard.decodo.com/web-data/playground). Older plans only have a basic authentication token, which also works. 3. **Install Node.js 18+** from [nodejs.org](https://nodejs.org/) (required for npm or `npx`). 4. **Install the CLI** using one of the methods below. 5. **Authenticate and run** your first scrape: @@ -111,23 +111,25 @@ npx @decodo/cli scrape https://ip.decodo.com --token "$DECODO_AUTH_TOKEN" ## Authentication -Get an auth token from the Decodo [Playground](https://dashboard.decodo.com/playground). +Use the Web Data API key from your subscription on the Decodo [dashboard](https://dashboard.decodo.com/web-data/playground). +Older plans only have a basic authentication token, which works the same way. The CLI detects which +one you provide, so the commands below take either. ```bash -# Interactive — saves token to config +# Interactive — saves the credential to config decodo setup # Environment variable — no saved config required -export DECODO_AUTH_TOKEN='your-token' +export DECODO_AUTH_TOKEN='your-api-key' # Per-command override -decodo whoami --token 'your-token' +decodo whoami --token 'your-api-key' ``` **Precedence:** `--token` flag → `DECODO_AUTH_TOKEN` env var → saved config (`decodo setup`). ```bash -decodo whoami # shows token source (flag / env / config) +decodo whoami # shows credential source (flag / env / config) decodo reset # clear saved config ``` @@ -140,7 +142,7 @@ decodo scrape https://ip.decodo.com decodo google-search "top articles hacker news" --page-count 5 --parse ``` -You should see Markdown or parsed JSON within seconds. If you see an auth error, double-check your token from the dashboard. +You should see Markdown or parsed JSON within seconds. If you see an auth error, double-check your API key on the dashboard. ## Commands @@ -152,7 +154,7 @@ You should see Markdown or parsed JSON within seconds. If you see an auth error, | `decodo search ` | Web search (`--engine google\|bing`, `--geo`, `--limit`) | | `decodo screenshot ` | Capture a PNG screenshot (`-o` file or directory) | | `decodo targets` | List all scrape targets by group | -| `decodo setup` | Save auth token interactively | +| `decodo setup` | Save your API key or auth token interactively | | `decodo whoami` | Show configured auth source | | `decodo reset` | Remove saved auth config | @@ -252,7 +254,7 @@ Use the CLI when your agent needs to scrape from a shell, terminal, CI/CD pipeli | Variable | Description | | --- | --- | -| `DECODO_AUTH_TOKEN` | Auth token (overrides saved config, below `--token`) | +| `DECODO_AUTH_TOKEN` | API key or basic auth token (overrides saved config, below `--token`) | | `DECODO_CONFIG_HOME` | Override config directory (default: `$XDG_CONFIG_HOME/decodo`, else `~/.config/decodo`) | ## Exit codes @@ -262,7 +264,7 @@ Use the CLI when your agent needs to scrape from a shell, terminal, CI/CD pipeli | `0` | Success | | `1` | General error | | `2` | Usage error (invalid flags, missing args) | -| `3` | Authentication error (missing or invalid token) | +| `3` | Authentication error (missing or invalid credential) | | `4` | Validation error (invalid request parameters) | | `5` | Rate limit | | `6` | Timeout | @@ -270,7 +272,7 @@ Use the CLI when your agent needs to scrape from a shell, terminal, CI/CD pipeli ## Troubleshooting -**`No auth token found`** +**`No API key or auth token found`** Run `decodo setup` or export `DECODO_AUTH_TOKEN`. diff --git a/docs/install.ps1 b/docs/install.ps1 index 95aaf72..14aa4f1 100644 --- a/docs/install.ps1 +++ b/docs/install.ps1 @@ -136,7 +136,7 @@ function Offer-Setup([string]$BinDir) { if (-not [Console]::IsInputRedirected -and -not [Console]::IsOutputRedirected) { Write-Host '' - Write-Host 'Next: configure your auth token.' + Write-Host 'Next: configure your API key or auth token.' Write-Host '' $answer = Read-Host 'Continue with setup? [Y/n]' if ($answer -match '^[nN]') { @@ -153,7 +153,7 @@ function Offer-Setup([string]$BinDir) { $cmd = Get-CommandPrefix $BinDir Write-Host '' - Write-Host "Next step: configure your auth token with $cmd setup" + Write-Host "Next step: configure your API key or auth token with $cmd setup" Write-Host '' } diff --git a/docs/install.sh b/docs/install.sh index b404f2b..2383d38 100755 --- a/docs/install.sh +++ b/docs/install.sh @@ -173,11 +173,11 @@ offer_setup() { if ! [ -t 0 ] || ! [ -t 1 ]; then cmd=$(command_prefix "$bin_dir") - printf "\nNext step: configure your auth token with ${BOLD}%s setup${RESET}\n\n" "$cmd" + printf "\nNext step: configure your API key or auth token with ${BOLD}%s setup${RESET}\n\n" "$cmd" return 0 fi - printf '\nNext: configure your auth token.\n\n' + printf '\nNext: configure your API key or auth token.\n\n' printf 'Continue with setup? [Y/n] ' if ! read -r answer /dev/null; then cmd=$(command_prefix "$bin_dir") diff --git a/package.json b/package.json index 490a826..fa6c5b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@decodo/cli", - "version": "1.0.3", + "version": "1.0.4", "description": "Official CLI for the Decodo APIs", "license": "MIT", "type": "module", diff --git a/src/auth/commands/setup.ts b/src/auth/commands/setup.ts index b9ff471..db6721e 100644 --- a/src/auth/commands/setup.ts +++ b/src/auth/commands/setup.ts @@ -11,7 +11,7 @@ import { detectCredentialType } from "../services/detect-credential-type.js"; import type { DecodoConfig } from "../types/config.js"; import type { AuthCredential, AuthType } from "../types/credential.js"; -const TOKEN_PROMPT = `Paste your Web Scraping API auth token (${PLAYGROUND_URL}): `; +const TOKEN_PROMPT = `Paste your Web Data API key or auth token (${PLAYGROUND_URL}): `; interface SetupOptions { token?: string; @@ -59,8 +59,8 @@ async function verifyCredential(value: string): Promise { } export const setupCommand = new Command("setup") - .description("Configure the Decodo CLI with your auth token") - .option("--token ", "Web Scraping API auth token (non-interactive)") + .description("Configure the Decodo CLI with your API key or auth token") + .option("--token ", "Web Data API key or auth token (non-interactive)") .action(async (options: SetupOptions, command) => { const rootOpts = getRootOpts(command); const token = ( @@ -70,7 +70,7 @@ export const setupCommand = new Command("setup") ).trim(); if (!token) { - handleCliError(new CliUsageError("auth token is required.")); + handleCliError(new CliUsageError("API key or auth token is required.")); } try { diff --git a/src/auth/commands/whoami.ts b/src/auth/commands/whoami.ts index bf041eb..a982418 100644 --- a/src/auth/commands/whoami.ts +++ b/src/auth/commands/whoami.ts @@ -13,7 +13,7 @@ const CREDENTIAL_LABEL: Record = { }; export const whoamiCommand = new Command("whoami") - .description("Show the active auth source and masked token") + .description("Show the active auth source and masked credential") .action(async (_options, command) => { const rootOpts = getRootOpts(command); const { credential, source } = await resolveAuthToken({ diff --git a/src/auth/constants.ts b/src/auth/constants.ts index 7460922..b451d80 100644 --- a/src/auth/constants.ts +++ b/src/auth/constants.ts @@ -1,6 +1,7 @@ -export const PLAYGROUND_URL = "https://dashboard.decodo.com/playground"; +export const PLAYGROUND_URL = + "https://dashboard.decodo.com/web-data/playground"; -export const AUTH_MISSING_MESSAGE = "No auth token found."; +export const AUTH_MISSING_MESSAGE = "No API key or auth token found."; export const AUTH_TYPE = { TOKEN: "token", diff --git a/src/index.ts b/src/index.ts index ed81eb7..1f21d84 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,7 +26,7 @@ const program = new Command() .option("-v, --verbose", "Print debug logs to stderr") .option( "--token ", - "Auth token (overrides DECODO_AUTH_TOKEN and saved config)" + "API key or auth token (overrides DECODO_AUTH_TOKEN and saved config)" ); async function main(): Promise { diff --git a/src/platform/services/handle-cli-error.ts b/src/platform/services/handle-cli-error.ts index f5c45bd..3c44737 100644 --- a/src/platform/services/handle-cli-error.ts +++ b/src/platform/services/handle-cli-error.ts @@ -157,13 +157,15 @@ export function handleCliError( if (err instanceof AuthRequiredError) { console.error( - "\nThe Decodo CLI is installed and working - it just needs an auth token:\n" + - ` 1. Get your Web Scraping API token at ${PLAYGROUND_URL}\n` + + "\nThe Decodo CLI is installed and working - it just needs an API key or auth token:\n" + + ` 1. Get your Web Data API key at ${PLAYGROUND_URL}\n` + " 2. Run `decodo setup` to save it (or set DECODO_AUTH_TOKEN)\n" + " 3. Re-run your command" ); } else if (err instanceof AuthenticationError) { - console.error("Hint: Run `decodo setup` to configure your auth token."); + console.error( + "Hint: Run `decodo setup` to configure your API key or auth token." + ); } if (err instanceof RateLimitError) { diff --git a/src/platform/services/prompt-hidden.ts b/src/platform/services/prompt-hidden.ts index 8df4481..38be5b9 100644 --- a/src/platform/services/prompt-hidden.ts +++ b/src/platform/services/prompt-hidden.ts @@ -27,7 +27,9 @@ function handleHiddenPromptChar(char: string, state: HiddenPromptState): void { if (code === CHAR_EOT) { state.cleanup(); stdout.write("\n"); - state.reject(new CliUsageError("No auth token provided on stdin.")); + state.reject( + new CliUsageError("No API key or auth token provided on stdin.") + ); return; } @@ -55,7 +57,9 @@ async function promptViaReadline(message: string): Promise { return await new Promise((resolve, reject) => { rl.question(message).then((answer) => resolve(answer.trim()), reject); rl.once("close", () => { - reject(new CliUsageError("No auth token provided on stdin.")); + reject( + new CliUsageError("No API key or auth token provided on stdin.") + ); }); }); } finally { @@ -91,7 +95,7 @@ export async function promptHidden(message: string): Promise { const onEnd = (): void => { state.cleanup(); stdout.write("\n"); - reject(new CliUsageError("No auth token provided on stdin.")); + reject(new CliUsageError("No API key or auth token provided on stdin.")); }; state.cleanup = (): void => { diff --git a/tests/auth/commands/setup.test.ts b/tests/auth/commands/setup.test.ts index be99191..0e9cd46 100644 --- a/tests/auth/commands/setup.test.ts +++ b/tests/auth/commands/setup.test.ts @@ -168,7 +168,7 @@ describe("setupCommand", () => { await expect(runSetup([])).rejects.toThrow("process.exit:2"); expect(exitCode).toBe(2); - expect(stderr.join("\n")).toContain("auth token is required"); + expect(stderr.join("\n")).toContain("API key or auth token is required"); }); it("exits with usage when interactive prompt returns whitespace", async () => { @@ -177,7 +177,7 @@ describe("setupCommand", () => { await expect(runSetup([])).rejects.toThrow("process.exit:2"); expect(exitCode).toBe(2); - expect(stderr.join("\n")).toContain("auth token is required"); + expect(stderr.join("\n")).toContain("API key or auth token is required"); }); it("falls back to prompt when global --token is whitespace-only", async () => { diff --git a/tests/platform/services/prompt-hidden.test.ts b/tests/platform/services/prompt-hidden.test.ts index 4c6ebc1..f0f02b6 100644 --- a/tests/platform/services/prompt-hidden.test.ts +++ b/tests/platform/services/prompt-hidden.test.ts @@ -44,6 +44,8 @@ describe("promptHidden", () => { listener(); } - await expect(pending).rejects.toThrow("No auth token provided on stdin."); + await expect(pending).rejects.toThrow( + "No API key or auth token provided on stdin." + ); }); });