UNPKG

@ensnode/ponder-metadata

Version:

A Hono middleware for making Ponder app metadata available to clients.

366 lines (358 loc) 11.9 kB
import { EnsRainbow } from '@ensnode/ensrainbow-sdk'; import { MiddlewareHandler } from 'hono'; import * as ponder from 'ponder'; import { ReadonlyDrizzle } from 'ponder'; import { PublicClient } from 'viem'; /** * Basic information about a block. */ interface BlockInfo { /** block number */ number: number; /** block unix timestamp */ timestamp: number; } /** * Ponder Status type * * It's a type of value returned by the `GET /status` endpoint on ponder server. * * Akin to: * https://github.com/ponder-sh/ponder/blob/8c012a3/packages/client/src/index.ts#L13-L18 */ interface PonderStatus { [chainName: string]: { /** @var id Chain ID */ id: number; /** @var block Last Indexed Block data */ block: BlockInfo; }; } /** * Indexing status for a chain. */ interface ChainIndexingStatus { /** Chain ID of the indexed chain */ chainId: number; /** * First block required to be indexed during the historical sync. */ firstBlockToIndex: BlockInfo; /** * Latest block synced into indexer's RPC cache. */ lastSyncedBlock: BlockInfo | null; /** * Last block processed & indexed by the indexer. */ lastIndexedBlock: BlockInfo | null; /** * Latest safe block available on the chain. */ latestSafeBlock: BlockInfo; } type PonderEnvVarsInfo = Record<string, unknown>; /** * Helper type which describes public clients grouped by chain name */ type PublicClientsByChainName<ChainName extends string = string> = Record<ChainName, PublicClient>; interface PonderMetadataMiddlewareOptions<AppInfo, EnvVars extends PonderEnvVarsInfo> { /** Database access object (readonly Drizzle) */ db: ReadonlyDrizzle<Record<string, unknown>>; /** Application info */ app: AppInfo; /** Environment settings info */ env: EnvVars; /** Query methods */ query: { /** Fetches Ponder Status object for Ponder application */ ponderStatus(): Promise<PonderStatus>; /** Fetches prometheus metrics for Ponder application */ prometheusMetrics(): Promise<string>; /** Fetches the first block do be indexed for a requested chain ID */ firstBlockToIndexByChainId(chainId: number, publicClient: PublicClient): Promise<BlockInfo>; /** Fetches ENSRainbow version information */ ensRainbowVersion?(): Promise<EnsRainbow.VersionInfo>; }; /** Public clients for fetching data from each chain */ publicClients: PublicClientsByChainName; } interface PonderMetadataMiddlewareResponse<AppInfo, EnvVarsInfo extends PonderEnvVarsInfo, RuntimeInfo> { /** Application info */ app: AppInfo; /** Dependencies info */ deps: { /** Ponder application version */ ponder: string; /** Node.js runtime version */ nodejs: string; }; /** Environment settings info */ env: EnvVarsInfo; /** Runtime status info */ runtime: RuntimeInfo; } /** * Ponder Metadata types definition. */ interface PonderMetadataModule { /** Application info */ AppInfo: { /** Application name */ name: string; /** Application version */ version: string; }; /** Environment Variables info */ EnvVars: { /** Database schema */ DATABASE_SCHEMA: string; } & PonderEnvVarsInfo; /** Runtime info */ RuntimeInfo: { /** * Application build id * https://github.com/ponder-sh/ponder/blob/626e524/packages/core/src/build/index.ts#L425-L431 **/ codebaseBuildId: string; /** Chain indexing statuses by chain ID */ chainIndexingStatuses: { [chainId: number]: ChainIndexingStatus; }; /** ENSRainbow version info */ ensRainbow?: EnsRainbow.VersionInfo; }; } type MetadataMiddlewareResponse = PonderMetadataMiddlewareResponse<PonderMetadataModule["AppInfo"], PonderMetadataModule["EnvVars"], PonderMetadataModule["RuntimeInfo"]>; declare function ponderMetadata<AppInfo extends PonderMetadataModule["AppInfo"], EnvVars extends PonderMetadataModule["EnvVars"]>({ app, db, env, query, publicClients, }: PonderMetadataMiddlewareOptions<AppInfo, EnvVars>): MiddlewareHandler; /** * Internal ponder metadata type. * Copied from https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L94-L102 */ type PonderAppMeta = { is_locked: 0 | 1; is_dev: 0 | 1; heartbeat_at: number; build_id: string; table_names: Array<string>; version: string; is_ready: 0 | 1; }; /** * Get DB schema for _ponder_meta table. * Akin to https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L129-L141 * * @param databaseNamespace A namespace for the database. * @returns A table schema for _ponder_meta table. * */ declare const getPonderMetaTableSchema: (databaseNamespace: string) => ponder.PgTableWithColumns<{ name: "_ponder_meta"; schema: undefined; columns: { key: ponder.PgColumn<{ name: "key"; tableName: "_ponder_meta"; dataType: "string"; columnType: "PgText"; data: "app"; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, { $type: "app"; }>; value: ponder.PgColumn<{ name: "value"; tableName: "_ponder_meta"; dataType: "json"; columnType: "PgJsonb"; data: PonderAppMeta; driverParam: unknown; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, { $type: PonderAppMeta; }>; }; dialect: "pg"; }> | ponder.PgTableWithColumns<{ name: "_ponder_meta"; schema: string; columns: { key: ponder.PgColumn<{ name: "key"; tableName: "_ponder_meta"; dataType: "string"; columnType: "PgText"; data: "app"; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, { $type: "app"; }>; value: ponder.PgColumn<{ name: "value"; tableName: "_ponder_meta"; dataType: "json"; columnType: "PgJsonb"; data: PonderAppMeta; driverParam: unknown; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, { $type: PonderAppMeta; }>; }; dialect: "pg"; }>; type PonderMetaTableSchema = ReturnType<typeof getPonderMetaTableSchema>; /** * Get ponder metadata for the app. * * @param namespace A namespace for the database (e.g. "public"). * @param db Drizzle DB Client instance. * @returns ponder metadata for the app. * @throws Error if ponder metadata not found. */ declare function queryPonderMeta(namespace: string, db: ReadonlyDrizzle<Record<string, unknown>>): Promise<PonderMetaTableSchema["$inferSelect"]["value"]>; declare module "parse-prometheus-text-format" { interface PrometheusMetric { name: string; help: string; type: string; metrics: Array<{ value: string; labels?: Record<string, string>; }>; } export default function parsePrometheusTextFormat(text: string): Array<PrometheusMetric>; } declare class PrometheusMetrics { private readonly metrics; private constructor(); static parse(maybePrometheusMetricsText: string): PrometheusMetrics; /** * Gets all metrics of a specific name * @param name Metric name * @returns Array of metrics or undefined if not found * @example * ```ts * const metrics = parser.get('ponder_historical_total_indexing_seconds'); * // Returns: [ * // { value: 251224935, labels: { network: "1" } }, * // { value: 251224935, labels: { network: "8453" } } * // ] * ``` */ get(name: string): Array<{ value: number; labels?: Record<string, string>; }> | undefined; /** * Gets a single metric value, optionally filtered by labels * @param name Metric name * @param labelFilter Optional label key-value pairs to match * @returns Metric value or undefined if not found * @example * ```ts * // Get simple value * parser.getValue('ponder_historical_start_timestamp_seconds') // Returns: 1740391265 * * // Get value with label filter * parser.getValue('ponder_historical_total_indexing_seconds', { network: '1' }) // Returns: 251224935 * ``` */ getValue(name: string, labelFilter?: Record<string, string>): number | undefined; /** * Gets a label value from a metric * @param name Metric name * @param label Label name to retrieve * @returns Label value or undefined if not found * @example * ```ts * parser.getLabel('ponder_version_info', 'version') // Returns: "0.9.18" * parser.getLabel('ponder_settings_info', 'ordering') // Returns: "omnichain" * ``` */ getLabel(name: string, label: string): string | undefined; /** * Gets all unique label values for a metric * @param name Metric name * @param label Label name to retrieve * @returns Array of unique label values * @example * ```ts * // Get all network IDs * parser.getLabels('ponder_historical_total_indexing_seconds', 'network') * // Returns: ['1', '8453'] * ``` */ getLabels(name: string, label: string): string[]; /** * Gets help text for a metric * @param name Metric name * @returns Help text or undefined if not found * @example * ```ts * parser.getHelp('ponder_historical_start_timestamp_seconds') * // Returns: "Timestamp at which historical indexing started" * ``` */ getHelp(name: string): string | undefined; /** * Gets metric type * @param name Metric name * @returns Metric type or undefined if not found * @example * ```ts * parser.getType('ponder_version_info') // Returns: "gauge" * parser.getType('ponder_postgres_query_total') // Returns: "counter" * ``` */ getType(name: string): string | undefined; /** * Gets all metric names * @returns Array of metric names * @example * ```ts * parser.getMetricNames() * // Returns: [ * // 'ponder_version_info', * // 'ponder_settings_info', * // 'ponder_historical_start_timestamp_seconds', * // 'ponder_historical_total_indexing_seconds' * // ] * ``` */ getMetricNames(): string[]; } export { type BlockInfo, type ChainIndexingStatus, type MetadataMiddlewareResponse, type PonderMetadataMiddlewareResponse, type PonderStatus, PrometheusMetrics, ponderMetadata, queryPonderMeta };