/** * Query handling for `GET /api/agents` (GH#310). * * The endpoint returns the full network agent registry — ~750 agents / * ~150 KB on a typical node — with no way to ask for less. Integrations whose * only need is "what's my own agent address" pay for the whole registry on * every call. This module adds `connectionStatus=`, `local=true` and * `limit`/`cursor` pagination, while keeping the no-parameter response * byte-shape identical for existing consumers (node-ui's `fetchAgents()` * takes no arguments; the MCP `dkg_find_agents` tool passes none either). * * DUPLICATE ROWS. `DiscoveryClient.findAgents()` owns the invariant that * registry rows are duplicate-free. Keeping that guarantee at the discovery * boundary means pagination and every other discovery consumer see the same * typed rows instead of each repairing query-engine artifacts independently. * * CURSOR STABILITY. Pages are ordered first by a digest of the canonical agent * URI, then by a digest of the exhaustive row projection. The cursor names the * last row returned. Mutable profile fields cannot move an identity across the * walk; their row digest only disambiguates conflicting bindings within that * identity. Keyset (strictly-after) semantics mean deleting a row cannot wedge * the walk. * * The cursor is a DIGEST, not the row itself, for two reasons. Size: row * fields are other agents' self-published profile literals, so a row-embedding * cursor hands any network agent that publishes a multi-KB name the power to * push every client's next-page URL past proxy header limits and wedge the * walk at its row. And filter binding: the cursor also carries a fingerprint * of the filters it was issued under, so continuing a walk with different * filters is a 400 instead of a plausible-looking wrong continuation. */ import { type DiscoveredAgent } from '@origintrail-official/dkg-agent'; import type { RequestContext } from './context.js'; import { type AgentConnectionStatus, type AgentListFilters } from '@origintrail-official/dkg-core'; export type { AgentConnectionStatus }; /** The route's filter vocabulary IS the shared wire contract's. */ export type AgentsListFilters = AgentListFilters; interface AgentsListCursor { readonly identityDigest: string; readonly rowDigest?: string; } export interface AgentsListQuery extends AgentsListFilters { limit?: number; /** Decoded only by request parsing and already proven to belong to these filters. */ cursor?: AgentsListCursor; } export type AgentsListQueryResult = { ok: true; query: AgentsListQuery; } | { ok: false; error: string; }; /** * Parse and validate the GH#310 query parameters. Unknown values are a 400, * not a silent no-op — `?local=ture` returning 750 agents would be worse than * an error. */ export declare function parseAgentsListQuery(searchParams: URLSearchParams): AgentsListQueryResult; export interface AgentsPage { rows: DiscoveredAgent[]; /** Present only when a `limit` was given and rows remain past this page. */ nextCursor?: string; } /** * Keyset pagination over stable discovered-agent identity. * * No `limit` and no `cursor` returns the rows untouched, in their original * order — the compatibility contract for parameterless callers. Paginated * requests retain every exact-distinct binding and order rows by canonical * identity digest, then exact-row digest. `limit` is a hard bound on the flat * response, so a large conflict group continues across pages instead of * producing an oversized response. */ export declare function paginateAgentRows(rows: DiscoveredAgent[], query: AgentsListQuery): AgentsPage; /** * Complete `GET /api/agents` workflow. The parent route module only dispatches * here; parsing, discovery, filtering, enrichment, pagination and response * ownership stay together at this endpoint boundary. */ export declare function handleAgentsListRoute(ctx: RequestContext): Promise; //# sourceMappingURL=agents-list.d.ts.map