import type { TypedDocumentString } from "./gql/graphql.js"; /** * Bind `signal` to every indexer read that goes to `indexerUrl`. Returns the * unregister function; call it when the owning client is discarded. * * Used by `createClient` for `ClientConfig.signal` — not part of the public API. */ export declare function registerIndexerSignal(indexerUrl: string, signal: AbortSignal): () => void; /** * A generated, typed operation: carries its own result and variables types, so * neither is self-declared at the call site. `documentMode: "string"` means the * document IS its text (a `String` subclass), so the bytes on the wire are * identical to the template strings these replace. * * The generated class itself, NOT a structural stand-in. A structural shape here * would be satisfied by a plain `string` — it has `toString()`, and optional * markers like `__apiType` / `__meta__` are vacuously met — which would let raw * query text slip onto the typed path. `TypedDocumentString` carries a `private` * member, so it is nominal: only `graphql()` output can produce one. */ export type TypedDocument = TypedDocumentString; /** * Issue a GraphQL read against the indexer. * * Takes a GENERATED typed document only: its result and variable types derive from * the committed schema snapshot, so a selection, alias, filter or sort the indexer * does not have fails `pnpm gql:codegen` / `pnpm typecheck` instead of throwing on * every call at runtime. This is the shape every indexer read in this file uses. * * Runtime-assembled queries cannot be documents (`graphql()` resolves its overloads * from the literal source string) — they call {@link gqlRequestDynamic}, whose only * caller is {@link aggregateCount}. Both share the request path below: same * bad-variable walk, same timeout, same throw-on-failure contract. */ export declare function gqlRequest>(document: TypedDocument, variables: TVariables, indexerUrl: string, headers?: Record, context?: { signal?: AbortSignal; }): Promise; /** * Escape hatch for the ONE read whose query text is assembled per call (the entity * name is a parameter) — see {@link aggregateCount} for why it cannot be a typed * document and what that costs. `T` is self-declared here, so nothing checks it * against the schema. * * Deliberately NOT the same name as {@link gqlRequest}: a new read that reaches for * this has to type the name out, which is the point. New reads are typed documents. */ export declare function gqlRequestDynamic(query: string, variables: Record, indexerUrl: string, headers?: Record): Promise; /** Row ceiling on the public-role fallback scan. Past this a count is a lower bound. */ export declare const COUNT_FALLBACK_CAP = 10000; /** * A row count plus whether the read was cut short — same `truncated` vocabulary * as {@link FundingRateSeries} and the `hasMore` pagers, so a caller reads one * convention across the SDK rather than two. * * `truncated: false` — a real total, from Hasura `_aggregate` or from a fallback * scan that finished inside the cap. `truncated: true` — `count` is a LOWER * BOUND (10,000 rows, the fallback cap); the true total is at least that. Render it * as "10,000+", and do not treat it as the last page when paginating: a * `rows.length < count` gate goes false while rows remain. * * @category indexing */ export type CountResult = { /** Rows matched, or the fallback cap (10,000) when `truncated`. */ count: number; /** True when the bounded fallback hit its cap, so `count` is a lower bound. */ truncated: boolean; }; /** * Count rows via Hasura `_aggregate` (O(1)). envio exposes `_aggregate` only to * a privileged role, reached by sending a Hasura admin-secret header * (`ClientConfig.indexerHeaders`, server-only). When that header is present this * is a single fast count. When it is NOT — the request lands on the public role, * where the aggregate field does not exist and Hasura returns * `field 'X_aggregate' not found in type: 'query_root'` — we fall back to a * BOUNDED row count so the caller still gets a total (accurate up to * {@link COUNT_FALLBACK_CAP}) instead of throwing and blanking the page. Any * other error (bad filter, indexer down) still surfaces. * * THE ONE TYPED-DOCUMENT EXEMPTION. Every other indexer read in this file is a * generated `graphql()` document whose result and variables derive from the * committed schema snapshot. These two cannot be: the ENTITY NAME is a parameter, * so the query text is assembled per call — and `graphql()` resolves its overloads * from the literal source string, which a template with a `${table}` hole does not * have. Generating one document per (table × aggregate/fallback) pair would be 10 * near-identical documents to keep in step, for two queries whose result shape is * a single integer. * * What that costs: a wrong `whereType` or a renamed `id` column here surfaces as a * Hasura runtime error, not a compile error. Contained only PARTLY — `table` is a * closed union of five entity names and the selections are * `{ aggregate { count } }` and `{ id }`, but the emitted `table`/`whereType`/ * `where` triple is pinned by unit tests for `countMarkets` and * `countBinaryMarkets` ONLY. `countOrders`, `countUserFills`, `countOperators` * and `countVenues` are unpinned: a wrong pair there passes the suite. Pin a * helper's triple when you touch it. Do NOT widen `table` to `string`, and do * not add new callers of the untyped {@link gqlRequest} overload: new reads are * typed documents. * * THE FALLBACK IS BOUNDED, AND SAYS SO. A scan capped at N rows returns N both * for "exactly N" and for "millions", so it asks for * {@link COUNT_FALLBACK_CAP} + 1 and reads the extra row as the truncation * signal — see {@link CountResult}. The probe row is never counted. */ export declare function aggregateCountBounded(table: "Market" | "Operator" | "Venue" | "Order" | "Fill", whereType: string, where: Record, indexerUrl: string, headers?: Record): Promise; /** * {@link aggregateCountBounded} with the exactness signal dropped — the total * as a plain number, which past the cap is a LOWER BOUND reported as if it were * exact. Prefer `aggregateCountBounded` in new code; this exists so the six * count helpers keep returning `number`. */ export declare function aggregateCount(table: "Market" | "Operator" | "Venue" | "Order" | "Fill", whereType: string, where: Record, indexerUrl: string, headers?: Record): Promise; /** * Narrow an indexer row to a public type that is stricter than the schema. * * Hasura must declare every market-type-specific column nullable — a column has * to be null for the OTHER market types — and it types object relationships * (`market`) nullable even when the owning row's `market_id` is `String!`. A * query filtered to BINARY rows (or reading a binary-only entity such as * `OutcomeBalance`) therefore receives non-null values the SCHEMA still calls * nullable. * * Two shapes of that gap, both unprovable by GraphQL: * * - NULLABILITY a query's own filter guarantees (a BINARY-scoped query's binary * columns; an object relationship whose owning `*_id` is non-null); * - a VALUE SET the indexer controls but the column does not declare (e.g. * `PoolBinding.closedBy`, a `String` the handlers only ever set to "Rotated" / * "Released"). * * Same treatment as {@link toMarket}: one named seam instead of scattered casts, * so every place trusting the indexer's handlers is greppable. Field NAMES and * WIRE TYPES stay compiler-checked either side of it. * * Verified against the live indexer: `OutcomeBalance` rows are BINARY-only, with * non-null `market`/`asset`/`question`. The spot equivalents are scoped the same * way (`market: {marketType: {_eq: "SPOT"}}`, or a registry-scoped StopOrder). */ export declare function narrowIndexerInvariant(rows: readonly unknown[]): T[];