@ensnode/ponder-metadata
Version:
A Hono middleware for making Ponder app metadata available to clients.
366 lines (358 loc) • 11.9 kB
TypeScript
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 };