/** * The CLI's Clustly-API client (V11; refactor R5) — ONE authenticated request helper for every * hosting domain module (upload, secrets, publish, lifecycle), each of which carried a * near-identical copy: same bearer header, same unreachable-network message, same * parse-or-empty-body handling. One copy means one place to change a header, a retry, or a * timeout policy — which is where the deadline and the transport attribution now live. * * Zero-dependency by contract (GUIDELINES §1): `fetch` and nothing else. The `fetchFn` seam is * how every consumer's tests script the wire (DIP). */ /** What a CLI domain module needs to talk to the API. `home` is the config/credentials root. */ export interface CliApiDeps { /** API base ending in /v1 (auth/login.ts `resolveBases`). */ apiBase: string; /** The builder's `clb_` key. */ apiKey: string; /** The CLI home (`~`) — where per-workspace memory and credentials live. */ home: string; /** Injectable for tests. */ fetchFn?: typeof fetch; /** Per-request deadline; the default suits control-plane calls, uploads pass their own signal. */ timeoutMs?: number; } /** Control-plane calls answer in seconds; a socket that stays open for longer is wedged. */ export declare const API_TIMEOUT_MS = 30000; /** The bundle upload is the seller's bytes at the seller's bandwidth — minutes, still bounded. */ export declare const API_UPLOAD_TIMEOUT_MS: number; export interface ApiAnswer { status: number; body: Record; } export declare function apiFetch(deps: CliApiDeps, path: string, init?: RequestInit): Promise; /** * A failure BEFORE any HTTP answer, with its cause kept in the message. `.catch(() => null)` * used to turn DNS, TLS, refused and proxy faults alike into "check your connection" — * permanently, for a builder behind a corporate proxy, because Node's fetch ignores * HTTPS_PROXY unless told to honour it. The cause names the fault; the hint names the switch. * `deadlineMs` is OUR deadline when we set one; undefined when the caller brought its own. */ export declare function transportError(e: unknown, url: string, deadlineMs: number | undefined, env?: Record): Error; /** The body as JSON, or `{}` when there is none or it is not JSON (a proxy's HTML 502). */ export declare function readJsonOrEmpty(res: Response): Promise>; export declare function apiRequest(deps: CliApiDeps, path: string, init?: RequestInit): Promise; export declare function apiJson(deps: CliApiDeps, path: string, method: string, body: unknown): Promise; /** The marketplace's own `error` slugs for faults on ITS side of the seam — never the builder's. */ export declare const SERVER_FAULT_CODES: Set; export declare function apiMessage(body: Record, fallback: string, status?: number): string; export declare class ApiError extends Error { readonly status: number; /** The marketplace's `error` slug — what decides WHOSE fault a 4xx is (hosting_busy is ours). */ readonly code: string | undefined; /** `Retry-After` in seconds when the server sent one. */ readonly retryAfterSec: number | null; constructor(message: string, status: number, /** The marketplace's `error` slug — what decides WHOSE fault a 4xx is (hosting_busy is ours). */ code?: string | undefined, /** `Retry-After` in seconds when the server sent one. */ retryAfterSec?: number | null); } export declare function apiErrorFrom(res: Response, fallback: string): Promise;