@decodo/cli
Advanced tools
| import type { DecodoSchema } from "@decodo/sdk-ts"; | ||
| export declare function resolveTargetGroup(schema: DecodoSchema, target: string): string | undefined; |
| const NO_GROUP = "None"; | ||
| export function resolveTargetGroup(schema, target) { | ||
| const group = schema.getTargetMeta(target)?.group; | ||
| if (!group || group === NO_GROUP) { | ||
| return; | ||
| } | ||
| return group; | ||
| } |
@@ -24,2 +24,5 @@ import { writeBinaryOutput } from "../../platform/services/write-binary.js"; | ||
| const full = options.full === true; | ||
| if (!full && response.results.length > 1) { | ||
| console.error(`Warning: showing 1 of ${response.results.length} results; use --format ndjson or --full`); | ||
| } | ||
| const indent = resolvePrettyIndent(options); | ||
@@ -26,0 +29,0 @@ const payload = extractPayload(response, full); |
@@ -5,2 +5,3 @@ import { Command } from "commander"; | ||
| import { createTargetAction } from "../services/run-target-scrape.js"; | ||
| import { resolveTargetGroup } from "../services/target-group.js"; | ||
| export function createCodegenTargetCommands(schema) { | ||
@@ -10,4 +11,4 @@ const commands = []; | ||
| const commandName = snakeToKebab(target); | ||
| const meta = schema.getTargetMeta(target); | ||
| const command = new Command(commandName).description(meta?.group ? `${meta.group} scrape target` : `${target} scrape target`); | ||
| const group = resolveTargetGroup(schema, target); | ||
| const command = new Command(commandName).description(group ? `${group} scrape target` : "Scrape target"); | ||
| configureTargetCommand(command, target, schema); | ||
@@ -14,0 +15,0 @@ command.action(createTargetAction(target, schema)); |
| import { Command } from "commander"; | ||
| import { snakeToKebab } from "../services/naming.js"; | ||
| import { resolveTargetGroup } from "../services/target-group.js"; | ||
| export function createListTargetsCommand(schema) { | ||
@@ -9,3 +10,3 @@ return new Command("targets") | ||
| for (const target of schema.listTargets()) { | ||
| const group = schema.getTargetMeta(target)?.group ?? "Other"; | ||
| const group = resolveTargetGroup(schema, target) ?? "Other"; | ||
| const names = grouped.get(group) ?? []; | ||
@@ -12,0 +13,0 @@ names.push(snakeToKebab(target)); |
@@ -1,9 +0,23 @@ | ||
| import { Target as ScrapeTarget } from "@decodo/sdk-ts"; | ||
| import { AuthenticationError, DecodoError, RateLimitError, Target as ScrapeTarget, TimeoutError, } from "@decodo/sdk-ts"; | ||
| import { createDecodoClient } from "./client.js"; | ||
| const AUTH_PROBE_URL = "https://does-not-exist.decodo.com"; | ||
| export async function validateAuthToken(token) { | ||
| const client = createDecodoClient(token); | ||
| await client.webScrapingApi.scrape({ | ||
| target: ScrapeTarget.Universal, | ||
| url: "https://does-not-exist.decodo.com", | ||
| }); | ||
| try { | ||
| await client.webScrapingApi.scrape({ | ||
| target: ScrapeTarget.Universal, | ||
| url: AUTH_PROBE_URL, | ||
| }); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof AuthenticationError || | ||
| err instanceof RateLimitError || | ||
| err instanceof TimeoutError) { | ||
| throw err; | ||
| } | ||
| if (err instanceof DecodoError) { | ||
| return; | ||
| } | ||
| throw err; | ||
| } | ||
| } |
| import type { DecodoSchema } from "@decodo/sdk-ts"; | ||
| import type { Command } from "commander"; | ||
| import type { OutputContextBuilder, ScrapeBodyBuilder } from "../types/run-target-scrape.js"; | ||
| export declare function createTargetAction(target: string, schema: DecodoSchema, buildBody?: ScrapeBodyBuilder, getOutputContext?: OutputContextBuilder): (input: string | undefined, options: Record<string, unknown>, command: Command) => Promise<void>; | ||
| export declare function createTargetAction(target: string, schema: DecodoSchema, buildBody?: ScrapeBodyBuilder, getOutputContext?: OutputContextBuilder): (...args: unknown[]) => Promise<void>; |
@@ -25,3 +25,13 @@ import { AuthRequiredError } from "../../auth/errors/auth-required-error.js"; | ||
| ((input, options) => buildScrapeBody(target, input, options, config, schema)); | ||
| return async (input, options, command) => { | ||
| return async (...args) => { | ||
| let input; | ||
| let options; | ||
| let command; | ||
| if (config.primaryField) { | ||
| [input, options, command] = args; | ||
| } | ||
| else { | ||
| [options, command] = args; | ||
| input = undefined; | ||
| } | ||
| const rootOpts = getRootOpts(command); | ||
@@ -28,0 +38,0 @@ const verbose = rootOpts.verbose === true; |
+1
-1
| { | ||
| "name": "@decodo/cli", | ||
| "version": "0.1.5", | ||
| "version": "0.1.6", | ||
| "description": "Official CLI for the Decodo APIs", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
+7
-5
@@ -147,3 +147,3 @@ # Decodo CLI | ||
| decodo scrape https://ip.decodo.com | ||
| decodo google-search "top articles hacker news" --limit 5 --parse | ||
| decodo google-search "top articles hacker news" --page-count 5 --parse | ||
| ``` | ||
@@ -187,3 +187,3 @@ | ||
| | `--full` | Print the full API response envelope | | ||
| | `--format ndjson` | One JSON object per result (pipe-friendly) | | ||
| | `--format ndjson` | One JSON object per result line on stdout (pipe-friendly) | | ||
| | `--pretty` | Indented JSON on stdout | | ||
@@ -195,2 +195,4 @@ | `-o, --output <path>` | Write to a file instead of stdout | | ||
| **NDJSON line contract:** With `--format ndjson`, stdout is one JSON object per API result line. Without `--full`, each line is that result's `content`. With `--full`, each line is the full result entry (e.g. `content`, `status_code`, `url`). There is no envelope-level `.results[]` on a single line — pipe each line through `jq` individually. | ||
| ```bash | ||
@@ -204,3 +206,3 @@ # Parsed JSON from Google Search | ||
| # NDJSON stream for jq / agents | ||
| decodo google-search "query" --format ndjson --full | jq -c '.results[]' | ||
| decodo google-search "query" --format ndjson --full | jq -c '.url' | ||
| ``` | ||
@@ -214,6 +216,6 @@ | ||
| # Search and extract titles | ||
| decodo google-search "rust web scraping" --limit 3 --parse | jq '.[].title' | ||
| decodo google-search "rust web scraping" --page-count 3 --parse | jq '.results.results.organic[].title' | ||
| # Scrape JSON API endpoint | ||
| decodo scrape https://ip.decodo.com/json | jq '.ip' | ||
| decodo scrape https://ip.decodo.com/json | jq '.proxy.ip' | ||
@@ -220,0 +222,0 @@ # Screenshot to file, then open |
63241
2.6%115
1.77%1297
3.02%344
0.58%