/** * Linkup direct HTTP transport. * * Performs POSTs (and quota/diagnostics GETs) against the Linkup REST * endpoints (`https://api.linkup.so/v1`) with an * `Authorization: Bearer ` header. There is NO internal * retry — shared execution owns retry policy. Fetch and timers are * injectable for tests. * * Structurally cloned from `providers/tavily/client.ts` (Tavily/Parallel * analog, IMPLEMENTATION-CONTRACT analog-adapter table), simplified to * Linkup's smaller endpoint surface. * * Failure taxonomy (Linkup ERROR_HANDLING, locked): * 401 / 403 -> ConfigurationError (never retry) * 402 -> QuotaError (never retry) * 404 -> ApiError 404 (never retry) * 422 -> ValidationError (never retry) * 429 -> ApiError 429 (retried by shared execution) * 5xx -> ApiError status (retried by shared execution) * * Raw response bodies NEVER cross this module's error boundary — every * thrown message is a curated constant (NFR-006). * * Boundary rules (ARCHITECTURE.md §2): * - May import Adapter-local config and normalized errors. * - May import `ProviderQuotaFetch` from `providers/types.js`. * - Must NOT import command presentation, capability contracts, or * another Provider's Adapter. * - Must NOT perform response field normalization — the Adapter owns * that. This module declares Provider-native request-body types * only (Linkup API field names). * * Research lifecycle (locked Linkup SPEC): * POST /research — create async task (one POST per task) * GET /research/{taskId} — poll until terminal status * status ∈ {pending, processing, completed, failed}; 404 -> not_found * The Adapter owns the poll loop and state-file resume; the transport * performs ONE request per call. */ import type { ProviderQuotaFetch } from "../types.js"; /** Injectable transport dependencies (fetch, timers, env). */ export interface LinkupTransportDeps { readonly fetch?: ProviderQuotaFetch; readonly setTimeout?: typeof setTimeout; readonly clearTimeout?: typeof clearTimeout; readonly env?: NodeJS.ProcessEnv; } /** * Provider-native search request body fields (Linkup API field names). * The Adapter maps the Provider-neutral `SearchControls` into these * before calling {@link fetchLinkupSearch}; the transport never imports * a capability contract. */ export interface LinkupSearchWireRequest { readonly q: string; readonly depth?: "fast" | "standard" | "deep"; readonly outputType?: "searchResults" | "sourcedAnswer" | "structured"; readonly includeDomains?: readonly string[]; /** YYYY-MM-DD lower bound of the recency window. */ readonly fromDate?: string; /** YYYY-MM-DD upper bound of the recency window. */ readonly toDate?: string; } /** * Provider-native reader fetch request body fields (Linkup API field * names). `renderJs` executes client-side JavaScript in a headless * browser before extraction; the Adapter always requests it (default * `true`) so SPAs render. */ export interface LinkupFetchWireRequest { readonly url: string; readonly renderJs?: boolean; } export declare function resolveTimeoutMs(env: NodeJS.ProcessEnv): number; /** * Perform ONE POST against the Linkup /search endpoint. No retry; no * response body in public errors. Returns the parsed JSON body (raw; * the Adapter post-processes into normalized search sources). * * `request` carries Linkup-native API fields already mapped from * `SearchControls` by the Adapter. */ export declare function fetchLinkupSearch(apiKey: string, request: LinkupSearchWireRequest, deps?: LinkupTransportDeps): Promise; /** * Perform ONE POST against the Linkup /fetch endpoint (reader). No * retry; no response body in public errors. Returns the parsed JSON * body (raw; the Adapter normalizes into a `ReaderFetchResult`). */ export declare function fetchLinkupFetch(apiKey: string, request: LinkupFetchWireRequest, deps?: LinkupTransportDeps): Promise; /** * Perform ONE GET against the Linkup `/credits/balance` endpoint. No * retry; no response body in public errors. Returns the parsed JSON * body (raw; the Adapter post-processes into normalized quota * categories). * * This is the shared quota/diagnostics signal: a non-destructive read * that authenticates the key without spending credits. The Diagnostics * Capability reuses this same GET — a probe must never POST a search. */ export declare function fetchLinkupCreditBalance(apiKey: string, deps?: LinkupTransportDeps): Promise; /** * Provider-native research submit request body fields (Linkup API field * names). The Adapter maps `ResearchRequest` into these before calling * {@link createLinkupResearch}; the transport never imports a capability * contract. */ export interface LinkupResearchWireRequest { readonly q: string; readonly mode?: "answer" | "investigate" | "research"; readonly reasoningDepth?: "S" | "M" | "L" | "XL"; readonly outputType?: "sourcedAnswer" | "structured"; } /** * Structured create result for `POST /research`. `id` is the task id * subsequent poll GETs use; `status` is the server's initial status * (typically `"pending"`). */ export interface LinkupResearchCreateResult { readonly id: string; readonly status: string; } /** * Structured poll result for `GET /research/:id`. The completed shape * is intentionally permissive — the Adapter normalizes `output`, * `markdown`, and `sources` into a `ResearchResult`. `not_found` is * the load-bearing signal that the server-side task has expired and * the Adapter should recreate (Tavily/Parallel guard). */ export interface LinkupResearchPollResult { readonly status: "pending" | "processing" | "completed" | "failed" | "not_found"; /** Raw completed output — object (`{answer, sources}`) or string. */ readonly output?: unknown; /** Markdown fallback (flat completed shape). */ readonly markdown?: string; /** Raw top-level sources fallback (flat completed shape). */ readonly sources?: unknown; } /** * Perform ONE POST against the Linkup `/research` endpoint. No retry; * no response body in public errors. Returns the structured create * result `{ id, status }`. The shared Adapter lifecycle sets * `maxRetries: 0` for research so a transient POST failure is terminal * (double-charge prevention on a usage-based endpoint). */ export declare function createLinkupResearch(apiKey: string, request: LinkupResearchWireRequest, deps?: LinkupTransportDeps): Promise; /** * Perform ONE GET against the Linkup `/research/{taskId}` endpoint. No * retry. Returns a structured poll result. * * Unlike other GETs, a 404 is NOT a terminal transport error here: it * means the server-side task has expired/disappeared, so the Adapter * can delete the stale state file and create a fresh task. The poll * result carries `status: "not_found"` for that case. All other non-2xx * statuses throw the standard mapped error (auth, rate limit, 5xx). */ export declare function pollLinkupResearch(apiKey: string, taskId: string, deps?: LinkupTransportDeps, externalSignal?: AbortSignal): Promise; //# sourceMappingURL=client.d.ts.map