Documentation
¶
Overview ¶
client.go is the ONE HTTP path from this subsystem to the Lux chain-data plane. Every handler in graph.go routes through this client, so the wire contract (base URLs, read-only auth, JSON/GraphQL decoding, error mapping) lives once here and can never drift between hand-rolled fetches.
TWO upstreams, ONE client:
- the INDEXER (luxfi/indexer) explorer REST — GET /health and GET /v1/explorer/blocks — read as plain JSON. Base from INDEXER_URL, default the in-cluster indexer Service.
- the GRAPH (luxfi/graph) GraphQL — POST /v1/explorer/graphql with a query — the O-Chain priceFeeds registry. Base from GRAPH_URL, default the in-cluster graph Service. (graphd's default route prefix is /v1/explorer.)
AUTH (one rule, read-only). Chain data is a public ledger, so the default is an UNAUTHENTICATED read. When a KMS-injected service token is configured (CHAIN_DATA_TOKEN) it is sent as a Bearer to both upstreams; otherwise the caller's own forwarded Authorization is passed through when present. The token is never logged.
ERROR MAPPING is honest and customer-appropriate: an unreachable upstream → 502, a non-2xx HTTP status → that status, and a GraphQL {errors} envelope → 502 with the upstream message. It never masks an upstream failure as success or fabricates data.
Package graph mounts the Hanzo Cloud CHAIN-DATA surface: the deployment's blockchain indexing + oracle feeds, served as clean, principal-gated REST off the unified cloud binary and fronting the Lux chain-data plane — luxfi/indexer (the per-network block/event indexer, explorer REST at /v1/explorer/*) and luxfi/graph (the GraphQL query layer that indexes O-Chain oracle price feeds). It exists so the console's Indexer and Oracles pages read REAL chain state from ONE place (api.hanzo.ai/v1/*) instead of rendering "not connected".
This subsystem OWNS no chain state — the indexer and graph do. It is a thin, principal-gated translator: it reads the indexer's health + latest block and the graph's priceFeeds, and re-shapes them into the exact JSON the console modules consume (types.go). It never fabricates: an indexer row is a real indexer's real chain + indexed height, an oracle row is a real on-chain price feed, and telemetry the upstream does not carry (the chain HEAD, hence true indexing lag) is honestly omitted (renders "—"), NEVER invented.
Surface (every route gated by the validated principal; HIP-0026):
GET /v1/indexers the deployment's chain indexer(s) + status -> {indexers:[indexerView]}
GET /v1/oracles on-chain price/data oracles (graph feeds) -> {oracles:[oracleView]}
Indexers maps to the indexer's per-network indexing status (chain, network, height, health); Oracles maps to luxfi/graph's O-Chain PriceFeed registry — the two chain- data concepts the two console pages need.
ISOLATION. Chain data is a PUBLIC ledger, but scoped per BRAND: each brand's cloud is wired to its OWN indexer/graph (INDEXER_URL / GRAPH_URL), so the surfaced networks are always the caller's brand's — exactly as the console's Networks proxy scopes networks per brand. Within a brand a ledger is public, so there is no per-org private row to leak; the ONE tenancy boundary that applies is principal-gating: every route requires a validated IAM principal (principal.Org → 403 without one), so an unauthenticated caller reads nothing.
HONEST FAILURE. Absent a reachable upstream the handler degrades to an honest-EMPTY list (200) — the same graceful fold as visor/clusters, NOT a 502 that surfaces as a console error for every org without an indexer/graph deployed. A reachable-but-empty upstream likewise returns an empty list — it NEVER fabricates an indexer or oracle row.
types.go holds the console view structs (what this subsystem emits) plus the PURE mapping from the upstream chain-data objects to them. The view JSON keys mirror the console modules EXACTLY so the Indexer and Oracles pages render with no front-end change:
- indexerView -> console IndexerModule.tsx Indexer {id,chain,network,height,lag,status,updatedAt}
- oracleView -> console OraclesModule.tsx Oracle {id,name,feed,value,source,status,updatedAt}
Every field is a REAL upstream value or an honest omission. Data the upstream does not carry — the chain HEAD (hence true indexing lag) — is left off so the UI renders "—", never a fabricated 0.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
This section is empty.