@ensnode/ponder-metadata 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { EnsRainbow } from '@ensnode/ensrainbow-sdk';
2
2
  import { MiddlewareHandler } from 'hono';
3
+ import * as ponder from 'ponder';
3
4
  import { ReadonlyDrizzle } from 'ponder';
4
5
  import { PublicClient } from 'viem';
5
- import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
6
6
 
7
7
  /**
8
8
  * Basic information about a block.
@@ -14,9 +14,27 @@ interface BlockInfo {
14
14
  timestamp: number;
15
15
  }
16
16
  /**
17
- * Network indexing status for a chain.
17
+ * Ponder Status type
18
+ *
19
+ * It's a type of value returned by the `GET /status` endpoint on ponder server.
20
+ *
21
+ * Akin to:
22
+ * https://github.com/ponder-sh/ponder/blob/8c012a3/packages/client/src/index.ts#L13-L18
18
23
  */
19
- interface NetworkIndexingStatus {
24
+ interface PonderStatus {
25
+ [chainName: string]: {
26
+ /** @var id Chain ID */
27
+ id: number;
28
+ /** @var block Last Indexed Block data */
29
+ block: BlockInfo;
30
+ };
31
+ }
32
+ /**
33
+ * Indexing status for a chain.
34
+ */
35
+ interface ChainIndexingStatus {
36
+ /** Chain ID of the indexed chain */
37
+ chainId: number;
20
38
  /**
21
39
  * First block required to be indexed during the historical sync.
22
40
  */
@@ -36,6 +54,10 @@ interface NetworkIndexingStatus {
36
54
  }
37
55
 
38
56
  type PonderEnvVarsInfo = Record<string, unknown>;
57
+ /**
58
+ * Helper type which describes public clients grouped by chain name
59
+ */
60
+ type PublicClientsByChainName<ChainName extends string = string> = Record<ChainName, PublicClient>;
39
61
  interface PonderMetadataMiddlewareOptions<AppInfo, EnvVars extends PonderEnvVarsInfo> {
40
62
  /** Database access object (readonly Drizzle) */
41
63
  db: ReadonlyDrizzle<Record<string, unknown>>;
@@ -45,6 +67,8 @@ interface PonderMetadataMiddlewareOptions<AppInfo, EnvVars extends PonderEnvVars
45
67
  env: EnvVars;
46
68
  /** Query methods */
47
69
  query: {
70
+ /** Fetches Ponder Status object for Ponder application */
71
+ ponderStatus(): Promise<PonderStatus>;
48
72
  /** Fetches prometheus metrics for Ponder application */
49
73
  prometheusMetrics(): Promise<string>;
50
74
  /** Fetches the first block do be indexed for a requested chain ID */
@@ -52,8 +76,8 @@ interface PonderMetadataMiddlewareOptions<AppInfo, EnvVars extends PonderEnvVars
52
76
  /** Fetches ENSRainbow version information */
53
77
  ensRainbowVersion?(): Promise<EnsRainbow.VersionInfo>;
54
78
  };
55
- /** Public clients for each blockchain network fetching data */
56
- publicClients: Record<number, PublicClient>;
79
+ /** Public clients for fetching data from each chain */
80
+ publicClients: PublicClientsByChainName;
57
81
  }
58
82
  interface PonderMetadataMiddlewareResponse<AppInfo, EnvVarsInfo extends PonderEnvVarsInfo, RuntimeInfo> {
59
83
  /** Application info */
@@ -94,8 +118,10 @@ interface PonderMetadataModule {
94
118
  * https://github.com/ponder-sh/ponder/blob/626e524/packages/core/src/build/index.ts#L425-L431
95
119
  **/
96
120
  codebaseBuildId: string;
97
- /** Network indexing status by chain ID */
98
- networkIndexingStatusByChainId: Record<number, NetworkIndexingStatus>;
121
+ /** Chain indexing statuses by chain ID */
122
+ chainIndexingStatuses: {
123
+ [chainId: number]: ChainIndexingStatus;
124
+ };
99
125
  /** ENSRainbow version info */
100
126
  ensRainbow?: EnsRainbow.VersionInfo;
101
127
  };
@@ -112,9 +138,9 @@ type PonderAppMeta = {
112
138
  is_dev: 0 | 1;
113
139
  heartbeat_at: number;
114
140
  build_id: string;
115
- checkpoint: string;
116
141
  table_names: Array<string>;
117
142
  version: string;
143
+ is_ready: 0 | 1;
118
144
  };
119
145
  /**
120
146
  * Get DB schema for _ponder_meta table.
@@ -123,11 +149,11 @@ type PonderAppMeta = {
123
149
  * @param databaseNamespace A namespace for the database.
124
150
  * @returns A table schema for _ponder_meta table.
125
151
  * */
126
- declare const getPonderMetaTableSchema: (databaseNamespace: string) => drizzle_orm_pg_core.PgTableWithColumns<{
152
+ declare const getPonderMetaTableSchema: (databaseNamespace: string) => ponder.PgTableWithColumns<{
127
153
  name: "_ponder_meta";
128
154
  schema: undefined;
129
155
  columns: {
130
- key: drizzle_orm_pg_core.PgColumn<{
156
+ key: ponder.PgColumn<{
131
157
  name: "key";
132
158
  tableName: "_ponder_meta";
133
159
  dataType: "string";
@@ -146,7 +172,7 @@ declare const getPonderMetaTableSchema: (databaseNamespace: string) => drizzle_o
146
172
  }, {}, {
147
173
  $type: "app";
148
174
  }>;
149
- value: drizzle_orm_pg_core.PgColumn<{
175
+ value: ponder.PgColumn<{
150
176
  name: "value";
151
177
  tableName: "_ponder_meta";
152
178
  dataType: "json";
@@ -167,11 +193,11 @@ declare const getPonderMetaTableSchema: (databaseNamespace: string) => drizzle_o
167
193
  }>;
168
194
  };
169
195
  dialect: "pg";
170
- }> | drizzle_orm_pg_core.PgTableWithColumns<{
196
+ }> | ponder.PgTableWithColumns<{
171
197
  name: "_ponder_meta";
172
198
  schema: string;
173
199
  columns: {
174
- key: drizzle_orm_pg_core.PgColumn<{
200
+ key: ponder.PgColumn<{
175
201
  name: "key";
176
202
  tableName: "_ponder_meta";
177
203
  dataType: "string";
@@ -190,7 +216,7 @@ declare const getPonderMetaTableSchema: (databaseNamespace: string) => drizzle_o
190
216
  }, {}, {
191
217
  $type: "app";
192
218
  }>;
193
- value: drizzle_orm_pg_core.PgColumn<{
219
+ value: ponder.PgColumn<{
194
220
  name: "value";
195
221
  tableName: "_ponder_meta";
196
222
  dataType: "json";
@@ -212,171 +238,6 @@ declare const getPonderMetaTableSchema: (databaseNamespace: string) => drizzle_o
212
238
  };
213
239
  dialect: "pg";
214
240
  }>;
215
- /**
216
- * Get DB schema for _ponder_status table.
217
- * Akin to https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L143-L159
218
- *
219
- * @param databaseNamespace A namespace for the database.
220
- * @returns A table schema for _ponder_status table.
221
- */
222
- declare const getPonderStatusTableSchema: (databaseNamespace: string) => drizzle_orm_pg_core.PgTableWithColumns<{
223
- name: "_ponder_status";
224
- schema: undefined;
225
- columns: {
226
- network_name: drizzle_orm_pg_core.PgColumn<{
227
- name: "network_name";
228
- tableName: "_ponder_status";
229
- dataType: "string";
230
- columnType: "PgText";
231
- data: string;
232
- driverParam: string;
233
- notNull: true;
234
- hasDefault: false;
235
- isPrimaryKey: true;
236
- isAutoincrement: false;
237
- hasRuntimeDefault: false;
238
- enumValues: [string, ...string[]];
239
- baseColumn: never;
240
- identity: undefined;
241
- generated: undefined;
242
- }, {}, {}>;
243
- block_number: drizzle_orm_pg_core.PgColumn<{
244
- name: "block_number";
245
- tableName: "_ponder_status";
246
- dataType: "number";
247
- columnType: "PgBigInt53";
248
- data: number;
249
- driverParam: string | number;
250
- notNull: false;
251
- hasDefault: false;
252
- isPrimaryKey: false;
253
- isAutoincrement: false;
254
- hasRuntimeDefault: false;
255
- enumValues: undefined;
256
- baseColumn: never;
257
- identity: undefined;
258
- generated: undefined;
259
- }, {}, {}>;
260
- block_timestamp: drizzle_orm_pg_core.PgColumn<{
261
- name: "block_timestamp";
262
- tableName: "_ponder_status";
263
- dataType: "number";
264
- columnType: "PgBigInt53";
265
- data: number;
266
- driverParam: string | number;
267
- notNull: false;
268
- hasDefault: false;
269
- isPrimaryKey: false;
270
- isAutoincrement: false;
271
- hasRuntimeDefault: false;
272
- enumValues: undefined;
273
- baseColumn: never;
274
- identity: undefined;
275
- generated: undefined;
276
- }, {}, {}>;
277
- ready: drizzle_orm_pg_core.PgColumn<{
278
- name: "ready";
279
- tableName: "_ponder_status";
280
- dataType: "boolean";
281
- columnType: "PgBoolean";
282
- data: boolean;
283
- driverParam: boolean;
284
- notNull: true;
285
- hasDefault: false;
286
- isPrimaryKey: false;
287
- isAutoincrement: false;
288
- hasRuntimeDefault: false;
289
- enumValues: undefined;
290
- baseColumn: never;
291
- identity: undefined;
292
- generated: undefined;
293
- }, {}, {}>;
294
- };
295
- dialect: "pg";
296
- }> | drizzle_orm_pg_core.PgTableWithColumns<{
297
- name: "_ponder_status";
298
- schema: string;
299
- columns: {
300
- network_name: drizzle_orm_pg_core.PgColumn<{
301
- name: "network_name";
302
- tableName: "_ponder_status";
303
- dataType: "string";
304
- columnType: "PgText";
305
- data: string;
306
- driverParam: string;
307
- notNull: true;
308
- hasDefault: false;
309
- isPrimaryKey: true;
310
- isAutoincrement: false;
311
- hasRuntimeDefault: false;
312
- enumValues: [string, ...string[]];
313
- baseColumn: never;
314
- identity: undefined;
315
- generated: undefined;
316
- }, {}, {}>;
317
- block_number: drizzle_orm_pg_core.PgColumn<{
318
- name: "block_number";
319
- tableName: "_ponder_status";
320
- dataType: "number";
321
- columnType: "PgBigInt53";
322
- data: number;
323
- driverParam: string | number;
324
- notNull: false;
325
- hasDefault: false;
326
- isPrimaryKey: false;
327
- isAutoincrement: false;
328
- hasRuntimeDefault: false;
329
- enumValues: undefined;
330
- baseColumn: never;
331
- identity: undefined;
332
- generated: undefined;
333
- }, {}, {}>;
334
- block_timestamp: drizzle_orm_pg_core.PgColumn<{
335
- name: "block_timestamp";
336
- tableName: "_ponder_status";
337
- dataType: "number";
338
- columnType: "PgBigInt53";
339
- data: number;
340
- driverParam: string | number;
341
- notNull: false;
342
- hasDefault: false;
343
- isPrimaryKey: false;
344
- isAutoincrement: false;
345
- hasRuntimeDefault: false;
346
- enumValues: undefined;
347
- baseColumn: never;
348
- identity: undefined;
349
- generated: undefined;
350
- }, {}, {}>;
351
- ready: drizzle_orm_pg_core.PgColumn<{
352
- name: "ready";
353
- tableName: "_ponder_status";
354
- dataType: "boolean";
355
- columnType: "PgBoolean";
356
- data: boolean;
357
- driverParam: boolean;
358
- notNull: true;
359
- hasDefault: false;
360
- isPrimaryKey: false;
361
- isAutoincrement: false;
362
- hasRuntimeDefault: false;
363
- enumValues: undefined;
364
- baseColumn: never;
365
- identity: undefined;
366
- generated: undefined;
367
- }, {}, {}>;
368
- };
369
- dialect: "pg";
370
- }>;
371
- type PonderStatusTableSchema = ReturnType<typeof getPonderStatusTableSchema>;
372
- /**
373
- * Get a list of ponder status entries for each network.
374
- *
375
- * @param namespace A namespace for the database (e.g. "public").
376
- * @param db Drizzle DB Client instance.
377
- * @returns a list of ponder status entries for each network.
378
- */
379
- declare function queryPonderStatus(namespace: string, db: ReadonlyDrizzle<Record<string, unknown>>): Promise<Array<PonderStatusTableSchema["$inferSelect"]>>;
380
241
  type PonderMetaTableSchema = ReturnType<typeof getPonderMetaTableSchema>;
381
242
  /**
382
243
  * Get ponder metadata for the app.
@@ -501,4 +362,4 @@ declare class PrometheusMetrics {
501
362
  getMetricNames(): string[];
502
363
  }
503
364
 
504
- export { type BlockInfo, type MetadataMiddlewareResponse, type NetworkIndexingStatus, type PonderMetadataMiddlewareResponse, PrometheusMetrics, ponderMetadata, queryPonderMeta, queryPonderStatus };
365
+ export { type BlockInfo, type ChainIndexingStatus, type MetadataMiddlewareResponse, type PonderMetadataMiddlewareResponse, type PonderStatus, PrometheusMetrics, ponderMetadata, queryPonderMeta };
package/dist/index.js CHANGED
@@ -16,26 +16,6 @@ var getPonderMetaTableSchema = (databaseNamespace) => {
16
16
  value: t.jsonb().$type().notNull()
17
17
  }));
18
18
  };
19
- var getPonderStatusTableSchema = (databaseNamespace) => {
20
- if (databaseNamespace === "public") {
21
- return pgTable("_ponder_status", (t) => ({
22
- network_name: t.text().primaryKey(),
23
- block_number: t.bigint({ mode: "number" }),
24
- block_timestamp: t.bigint({ mode: "number" }),
25
- ready: t.boolean().notNull()
26
- }));
27
- }
28
- return pgSchema(databaseNamespace).table("_ponder_status", (t) => ({
29
- network_name: t.text().primaryKey(),
30
- block_number: t.bigint({ mode: "number" }),
31
- block_timestamp: t.bigint({ mode: "number" }),
32
- ready: t.boolean().notNull()
33
- }));
34
- };
35
- async function queryPonderStatus(namespace, db) {
36
- const PONDER_STATUS = getPonderStatusTableSchema(namespace);
37
- return db.select().from(PONDER_STATUS);
38
- }
39
19
  async function queryPonderMeta(namespace, db) {
40
20
  const PONDER_META = getPonderMetaTableSchema(namespace);
41
21
  const [ponderAppMeta] = await db.select({ value: PONDER_META.value }).from(PONDER_META).where(eq(PONDER_META.key, "app")).limit(1);
@@ -205,24 +185,25 @@ function ponderMetadata({
205
185
  publicClients
206
186
  }) {
207
187
  return async function ponderMetadataMiddleware(ctx) {
208
- const indexedChainIds = Object.keys(publicClients).map(Number);
209
- const ponderStatus = await queryPonderStatus(env.DATABASE_SCHEMA, db);
188
+ const indexedChainNames = Object.keys(publicClients);
189
+ const ponderStatus = await query.ponderStatus();
210
190
  const metrics = PrometheusMetrics.parse(await query.prometheusMetrics());
211
- const networkIndexingStatusByChainId = {};
212
- for (const indexedChainId of indexedChainIds) {
213
- const publicClient = publicClients[indexedChainId];
214
- if (!publicClient) {
191
+ const chainIndexingStatuses = {};
192
+ for (const indexedChainName of indexedChainNames) {
193
+ const publicClient = publicClients[indexedChainName];
194
+ if (!publicClient || typeof publicClient.chain === "undefined") {
215
195
  throw new HTTPException(500, {
216
- message: `No public client found for chainId ${indexedChainId}`
196
+ message: `No public client found for "${indexedChainName}" chain name`
217
197
  });
218
198
  }
199
+ const publicClientChainId = publicClient.chain.id;
219
200
  const fetchBlockMetadata = async (blockNumber) => {
220
201
  const block = await publicClient.getBlock({
221
202
  blockNumber: BigInt(blockNumber)
222
203
  });
223
204
  if (!block) {
224
205
  throw new Error(
225
- `Failed to fetch block metadata for block number ${blockNumber} with chain ID ${indexedChainId}`
206
+ `Failed to fetch block metadata for block number ${blockNumber} on chain ID "${publicClientChainId}"`
226
207
  );
227
208
  }
228
209
  return {
@@ -233,16 +214,16 @@ function ponderMetadata({
233
214
  const latestSafeBlockData = await publicClient.getBlock();
234
215
  if (!latestSafeBlockData) {
235
216
  throw new HTTPException(500, {
236
- message: `Failed to fetch latest safe block for chainId ${indexedChainId}`
217
+ message: `Failed to fetch latest safe block for chain ID "${publicClientChainId}"`
237
218
  });
238
219
  }
239
220
  const latestSafeBlock = {
240
221
  number: Number(latestSafeBlockData.number),
241
222
  timestamp: Number(latestSafeBlockData.timestamp)
242
223
  };
243
- const network = indexedChainId.toString();
224
+ const chain = indexedChainName;
244
225
  const lastSyncedBlockHeight = metrics.getValue("ponder_sync_block", {
245
- network
226
+ chain
246
227
  });
247
228
  let lastSyncedBlock = null;
248
229
  if (lastSyncedBlockHeight) {
@@ -252,18 +233,25 @@ function ponderMetadata({
252
233
  console.error("Failed to fetch block metadata for last synced block", error);
253
234
  }
254
235
  }
255
- const ponderStatusForNetwork = ponderStatus.find(
256
- (ponderStatusEntry) => ponderStatusEntry.network_name === network
236
+ const firstBlockToIndex = await query.firstBlockToIndexByChainId(
237
+ publicClientChainId,
238
+ publicClient
239
+ );
240
+ const ponderStatusForChain = Object.values(ponderStatus).find(
241
+ (ponderStatusEntry) => ponderStatusEntry.id === publicClientChainId
257
242
  );
258
243
  let lastIndexedBlock = null;
259
- if (ponderStatusForNetwork) {
260
- lastIndexedBlock = ponderBlockInfoToBlockMetadata(ponderStatusForNetwork);
244
+ if (ponderStatusForChain) {
245
+ if (firstBlockToIndex.number < ponderStatusForChain.block.number) {
246
+ lastIndexedBlock = ponderStatusForChain.block;
247
+ }
261
248
  }
262
- networkIndexingStatusByChainId[indexedChainId] = {
249
+ chainIndexingStatuses[publicClientChainId] = {
250
+ chainId: publicClientChainId,
263
251
  lastSyncedBlock,
264
252
  lastIndexedBlock,
265
253
  latestSafeBlock,
266
- firstBlockToIndex: await query.firstBlockToIndexByChainId(indexedChainId, publicClient)
254
+ firstBlockToIndex
267
255
  };
268
256
  }
269
257
  let ponderAppBuildId;
@@ -289,7 +277,7 @@ function ponderMetadata({
289
277
  env,
290
278
  runtime: {
291
279
  codebaseBuildId: formatTextMetricValue(ponderAppBuildId),
292
- networkIndexingStatusByChainId,
280
+ chainIndexingStatuses,
293
281
  ensRainbow: ensRainbowVersionInfo
294
282
  }
295
283
  };
@@ -298,37 +286,24 @@ function ponderMetadata({
298
286
  };
299
287
  }
300
288
  function validateResponse(response) {
301
- const { networkIndexingStatusByChainId } = response.runtime;
302
- if (Object.keys(networkIndexingStatusByChainId).length === 0) {
289
+ const { chainIndexingStatuses } = response.runtime;
290
+ if (Object.keys(chainIndexingStatuses).length === 0) {
303
291
  throw new HTTPException(500, {
304
- message: "No network indexing status found"
292
+ message: "No chain indexing status found"
305
293
  });
306
294
  }
307
- if (Object.values(networkIndexingStatusByChainId).some((n) => n.firstBlockToIndex === null)) {
295
+ if (Object.values(chainIndexingStatuses).some((n) => n.firstBlockToIndex === null)) {
308
296
  throw new HTTPException(500, {
309
- message: "Failed to fetch first block to index for some networks"
297
+ message: "Failed to fetch first block to index for some chains"
310
298
  });
311
299
  }
312
300
  }
313
301
  function formatTextMetricValue(value) {
314
302
  return value ?? "unknown";
315
303
  }
316
- function ponderBlockInfoToBlockMetadata(block) {
317
- if (!block) {
318
- return null;
319
- }
320
- if (!block.block_number || !block.block_timestamp) {
321
- return null;
322
- }
323
- return {
324
- number: block.block_number,
325
- timestamp: block.block_timestamp
326
- };
327
- }
328
304
  export {
329
305
  PrometheusMetrics,
330
306
  ponderMetadata,
331
- queryPonderMeta,
332
- queryPonderStatus
307
+ queryPonderMeta
333
308
  };
334
309
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts","../src/db-helpers.ts","../src/prometheus-metrics.ts"],"sourcesContent":["import type { EnsRainbow } from \"@ensnode/ensrainbow-sdk\";\nimport { MiddlewareHandler } from \"hono\";\nimport { HTTPException } from \"hono/http-exception\";\n\nimport { queryPonderMeta, queryPonderStatus } from \"./db-helpers\";\nimport { PrometheusMetrics } from \"./prometheus-metrics\";\nimport type {\n PonderEnvVarsInfo,\n PonderMetadataMiddlewareOptions,\n PonderMetadataMiddlewareResponse,\n} from \"./types/api\";\nimport type { BlockInfo, NetworkIndexingStatus, PonderBlockStatus } from \"./types/common\";\n\n/**\n * Ponder Metadata types definition.\n */\ninterface PonderMetadataModule {\n /** Application info */\n AppInfo: {\n /** Application name */\n name: string;\n /** Application version */\n version: string;\n };\n\n /** Environment Variables info */\n EnvVars: {\n /** Database schema */\n DATABASE_SCHEMA: string;\n } & PonderEnvVarsInfo;\n\n /** Runtime info */\n RuntimeInfo: {\n /**\n * Application build id\n * https://github.com/ponder-sh/ponder/blob/626e524/packages/core/src/build/index.ts#L425-L431\n **/\n codebaseBuildId: string;\n\n /** Network indexing status by chain ID */\n networkIndexingStatusByChainId: Record<number, NetworkIndexingStatus>;\n\n /** ENSRainbow version info */\n ensRainbow?: EnsRainbow.VersionInfo;\n };\n}\n\nexport type MetadataMiddlewareResponse = PonderMetadataMiddlewareResponse<\n PonderMetadataModule[\"AppInfo\"],\n PonderMetadataModule[\"EnvVars\"],\n PonderMetadataModule[\"RuntimeInfo\"]\n>;\n\nexport function ponderMetadata<\n AppInfo extends PonderMetadataModule[\"AppInfo\"],\n EnvVars extends PonderMetadataModule[\"EnvVars\"],\n>({\n app,\n db,\n env,\n query,\n publicClients,\n}: PonderMetadataMiddlewareOptions<AppInfo, EnvVars>): MiddlewareHandler {\n return async function ponderMetadataMiddleware(ctx) {\n const indexedChainIds = Object.keys(publicClients).map(Number);\n\n const ponderStatus = await queryPonderStatus(env.DATABASE_SCHEMA, db);\n const metrics = PrometheusMetrics.parse(await query.prometheusMetrics());\n\n const networkIndexingStatusByChainId: Record<number, NetworkIndexingStatus> = {};\n\n for (const indexedChainId of indexedChainIds) {\n const publicClient = publicClients[indexedChainId];\n\n if (!publicClient) {\n throw new HTTPException(500, {\n message: `No public client found for chainId ${indexedChainId}`,\n });\n }\n\n /**\n * Fetches block metadata from blockchain network for a given block number.\n * @param blockNumber\n * @returns block metadata\n * @throws {Error} if failed to fetch block metadata from blockchain network\n */\n const fetchBlockMetadata = async (blockNumber: number): Promise<BlockInfo> => {\n const block = await publicClient.getBlock({\n blockNumber: BigInt(blockNumber),\n });\n\n if (!block) {\n throw new Error(\n `Failed to fetch block metadata for block number ${blockNumber} with chain ID ${indexedChainId}`,\n );\n }\n\n return {\n number: Number(block.number),\n timestamp: Number(block.timestamp),\n } satisfies BlockInfo;\n };\n\n const latestSafeBlockData = await publicClient.getBlock();\n\n if (!latestSafeBlockData) {\n throw new HTTPException(500, {\n message: `Failed to fetch latest safe block for chainId ${indexedChainId}`,\n });\n }\n\n // mapping latest safe block\n const latestSafeBlock = {\n number: Number(latestSafeBlockData.number),\n timestamp: Number(latestSafeBlockData.timestamp),\n } satisfies BlockInfo;\n\n // mapping chain id to its string representation for metric queries\n const network = indexedChainId.toString();\n\n // mapping last synced block if available\n const lastSyncedBlockHeight = metrics.getValue(\"ponder_sync_block\", {\n network,\n });\n let lastSyncedBlock: BlockInfo | null = null;\n if (lastSyncedBlockHeight) {\n try {\n lastSyncedBlock = await fetchBlockMetadata(lastSyncedBlockHeight);\n } catch (error) {\n console.error(\"Failed to fetch block metadata for last synced block\", error);\n }\n }\n\n // mapping ponder status for current network\n const ponderStatusForNetwork = ponderStatus.find(\n (ponderStatusEntry) => ponderStatusEntry.network_name === network,\n );\n\n // mapping last indexed block if available\n let lastIndexedBlock: BlockInfo | null = null;\n if (ponderStatusForNetwork) {\n lastIndexedBlock = ponderBlockInfoToBlockMetadata(ponderStatusForNetwork);\n }\n\n networkIndexingStatusByChainId[indexedChainId] = {\n lastSyncedBlock,\n lastIndexedBlock,\n latestSafeBlock,\n firstBlockToIndex: await query.firstBlockToIndexByChainId(indexedChainId, publicClient),\n } satisfies NetworkIndexingStatus;\n }\n\n // mapping ponder app build id if available\n let ponderAppBuildId: string | undefined;\n try {\n ponderAppBuildId = (await queryPonderMeta(env.DATABASE_SCHEMA, db)).build_id;\n } catch (error) {\n console.error(\"Failed to fetch ponder metadata\", error);\n }\n\n // fetch ENSRainbow version if available\n let ensRainbowVersionInfo = undefined;\n if (query.ensRainbowVersion) {\n try {\n ensRainbowVersionInfo = await query.ensRainbowVersion();\n } catch (error) {\n console.error(\"Failed to fetch ENSRainbow version\", error);\n }\n }\n\n const response = {\n app,\n deps: {\n ponder: formatTextMetricValue(metrics.getLabel(\"ponder_version_info\", \"version\")),\n nodejs: formatTextMetricValue(metrics.getLabel(\"nodejs_version_info\", \"version\")),\n },\n env,\n runtime: {\n codebaseBuildId: formatTextMetricValue(ponderAppBuildId),\n networkIndexingStatusByChainId,\n ensRainbow: ensRainbowVersionInfo,\n },\n } satisfies MetadataMiddlewareResponse;\n\n // validate if response is in correct state\n validateResponse(response);\n\n return ctx.json(response);\n };\n}\n\n/**\n * Validates the metadata middleware response to ensure correct state.\n *\n * @param response The response to validate\n * @throws {HTTPException} if the response is in an invalid state\n */\nfunction validateResponse(response: MetadataMiddlewareResponse): void {\n const { networkIndexingStatusByChainId } = response.runtime;\n\n if (Object.keys(networkIndexingStatusByChainId).length === 0) {\n throw new HTTPException(500, {\n message: \"No network indexing status found\",\n });\n }\n\n if (Object.values(networkIndexingStatusByChainId).some((n) => n.firstBlockToIndex === null)) {\n throw new HTTPException(500, {\n message: \"Failed to fetch first block to index for some networks\",\n });\n }\n}\n\n/**\n * Formats a text metric value.\n * @param value\n * @returns\n */\nfunction formatTextMetricValue(value?: string): string {\n return value ?? \"unknown\";\n}\n\n/**\n * Converts a Ponder block status to a block info object.\n **/\nfunction ponderBlockInfoToBlockMetadata(block: PonderBlockStatus | undefined): BlockInfo | null {\n if (!block) {\n return null;\n }\n\n if (!block.block_number || !block.block_timestamp) {\n return null;\n }\n\n return {\n number: block.block_number,\n timestamp: block.block_timestamp,\n };\n}\n","import { pgSchema, pgTable } from \"drizzle-orm/pg-core\";\nimport { type ReadonlyDrizzle, eq } from \"ponder\";\n\n/**\n * Internal ponder metadata type.\n * Copied from https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L94-L102\n */\ntype PonderAppMeta = {\n is_locked: 0 | 1;\n is_dev: 0 | 1;\n heartbeat_at: number;\n build_id: string;\n checkpoint: string;\n table_names: Array<string>;\n version: string;\n};\n\n/**\n * Get DB schema for _ponder_meta table.\n * Akin to https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L129-L141\n *\n * @param databaseNamespace A namespace for the database.\n * @returns A table schema for _ponder_meta table.\n * */\nconst getPonderMetaTableSchema = (databaseNamespace: string) => {\n if (databaseNamespace === \"public\") {\n return pgTable(\"_ponder_meta\", (t) => ({\n key: t.text().primaryKey().$type<\"app\">(),\n value: t.jsonb().$type<PonderAppMeta>().notNull(),\n }));\n }\n\n return pgSchema(databaseNamespace).table(\"_ponder_meta\", (t) => ({\n key: t.text().primaryKey().$type<\"app\">(),\n value: t.jsonb().$type<PonderAppMeta>().notNull(),\n }));\n};\n\n/**\n * Get DB schema for _ponder_status table.\n * Akin to https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L143-L159\n *\n * @param databaseNamespace A namespace for the database.\n * @returns A table schema for _ponder_status table.\n */\nconst getPonderStatusTableSchema = (databaseNamespace: string) => {\n if (databaseNamespace === \"public\") {\n return pgTable(\"_ponder_status\", (t) => ({\n network_name: t.text().primaryKey(),\n block_number: t.bigint({ mode: \"number\" }),\n block_timestamp: t.bigint({ mode: \"number\" }),\n ready: t.boolean().notNull(),\n }));\n }\n\n return pgSchema(databaseNamespace).table(\"_ponder_status\", (t) => ({\n network_name: t.text().primaryKey(),\n block_number: t.bigint({ mode: \"number\" }),\n block_timestamp: t.bigint({ mode: \"number\" }),\n ready: t.boolean().notNull(),\n }));\n};\n\ntype PonderStatusTableSchema = ReturnType<typeof getPonderStatusTableSchema>;\n\n/**\n * Get a list of ponder status entries for each network.\n *\n * @param namespace A namespace for the database (e.g. \"public\").\n * @param db Drizzle DB Client instance.\n * @returns a list of ponder status entries for each network.\n */\nexport async function queryPonderStatus(\n namespace: string,\n db: ReadonlyDrizzle<Record<string, unknown>>,\n): Promise<Array<PonderStatusTableSchema[\"$inferSelect\"]>> {\n const PONDER_STATUS = getPonderStatusTableSchema(namespace);\n\n return db.select().from(PONDER_STATUS);\n}\n\ntype PonderMetaTableSchema = ReturnType<typeof getPonderMetaTableSchema>;\n\n/**\n * Get ponder metadata for the app.\n *\n * @param namespace A namespace for the database (e.g. \"public\").\n * @param db Drizzle DB Client instance.\n * @returns ponder metadata for the app.\n * @throws Error if ponder metadata not found.\n */\nexport async function queryPonderMeta(\n namespace: string,\n db: ReadonlyDrizzle<Record<string, unknown>>,\n): Promise<PonderMetaTableSchema[\"$inferSelect\"][\"value\"]> {\n const PONDER_META = getPonderMetaTableSchema(namespace);\n\n const [ponderAppMeta] = await db\n .select({ value: PONDER_META.value })\n .from(PONDER_META)\n .where(eq(PONDER_META.key, \"app\"))\n .limit(1);\n\n if (!ponderAppMeta) {\n throw new Error(\"Ponder metadata not found\");\n }\n\n return ponderAppMeta.value;\n}\n","import parsePrometheusTextFormat, { type PrometheusMetric } from \"parse-prometheus-text-format\";\n// Ensures local declaration file is available to downstream consumers\nimport \"./types/parse-prometheus-text-format\";\n\ninterface ParsedPrometheusMetric extends Omit<PrometheusMetric, \"metrics\"> {\n metrics: Array<{\n value: number;\n labels?: Record<string, string>;\n }>;\n}\n\n/**\n * Converts Prometheus text format to JSON format compatible with prom2json\n * @param text Raw Prometheus metric text\n * @returns Array of metrics in prom2json compatible format\n * @example\n * ```ts\n * const metrics = parsePrometheusText(`\n * # HELP ponder_version_info Ponder version information\n * # TYPE ponder_version_info gauge\n * ponder_version_info{version=\"0.9.18\",major=\"0\",minor=\"9\",patch=\"18\"} 1\n * `);\n * // Returns:\n * // [{\n * // name: \"ponder_version_info\",\n * // help: \"Ponder version information\",\n * // type: \"gauge\",\n * // metrics: [{\n * // value: 1,\n * // labels: { version: \"0.9.18\", major: \"0\", minor: \"9\", patch: \"18\" }\n * // }]\n * // }]\n * ```\n */\nexport function parsePrometheusText(text: string): Array<ParsedPrometheusMetric> {\n return parsePrometheusTextFormat(text).map((metric) => ({\n name: metric.name,\n help: metric.help || \"\",\n type: metric.type.toLowerCase(),\n metrics: metric.metrics.map((m) => ({\n value: Number(m.value),\n ...(m.labels && Object.keys(m.labels).length > 0 ? { labels: m.labels } : {}),\n })),\n }));\n}\n\nexport class PrometheusMetrics {\n private constructor(private readonly metrics: Array<ParsedPrometheusMetric>) {}\n\n static parse(maybePrometheusMetricsText: string): PrometheusMetrics {\n return new PrometheusMetrics(parsePrometheusText(maybePrometheusMetricsText));\n }\n\n /**\n * Gets all metrics of a specific name\n * @param name Metric name\n * @returns Array of metrics or undefined if not found\n * @example\n * ```ts\n * const metrics = parser.get('ponder_historical_total_indexing_seconds');\n * // Returns: [\n * // { value: 251224935, labels: { network: \"1\" } },\n * // { value: 251224935, labels: { network: \"8453\" } }\n * // ]\n * ```\n */\n get(name: string): Array<{ value: number; labels?: Record<string, string> }> | undefined {\n const metric = this.metrics.find((m) => m.name === name);\n return metric?.metrics;\n }\n\n /**\n * Gets a single metric value, optionally filtered by labels\n * @param name Metric name\n * @param labelFilter Optional label key-value pairs to match\n * @returns Metric value or undefined if not found\n * @example\n * ```ts\n * // Get simple value\n * parser.getValue('ponder_historical_start_timestamp_seconds') // Returns: 1740391265\n *\n * // Get value with label filter\n * parser.getValue('ponder_historical_total_indexing_seconds', { network: '1' }) // Returns: 251224935\n * ```\n */\n getValue(name: string, labelFilter?: Record<string, string>): number | undefined {\n const metrics = this.get(name);\n\n if (!metrics || metrics.length === 0) {\n return undefined;\n }\n\n if (!labelFilter) {\n return metrics[0]?.value;\n }\n\n const metric = metrics.find(\n (m) => m.labels && Object.entries(labelFilter).every(([k, v]) => m.labels?.[k] === v),\n );\n\n return metric?.value;\n }\n\n /**\n * Gets a label value from a metric\n * @param name Metric name\n * @param label Label name to retrieve\n * @returns Label value or undefined if not found\n * @example\n * ```ts\n * parser.getLabel('ponder_version_info', 'version') // Returns: \"0.9.18\"\n * parser.getLabel('ponder_settings_info', 'ordering') // Returns: \"omnichain\"\n * ```\n */\n getLabel(name: string, label: string): string | undefined {\n return this.getLabels(name, label)[0];\n }\n\n /**\n * Gets all unique label values for a metric\n * @param name Metric name\n * @param label Label name to retrieve\n * @returns Array of unique label values\n * @example\n * ```ts\n * // Get all network IDs\n * parser.getLabels('ponder_historical_total_indexing_seconds', 'network')\n * // Returns: ['1', '8453']\n * ```\n */\n getLabels(name: string, label: string): string[] {\n const metrics = this.get(name);\n\n if (!metrics) return [];\n\n return [\n ...new Set(metrics.map((m) => m.labels?.[label]).filter((v): v is string => v !== undefined)),\n ];\n }\n\n /**\n * Gets help text for a metric\n * @param name Metric name\n * @returns Help text or undefined if not found\n * @example\n * ```ts\n * parser.getHelp('ponder_historical_start_timestamp_seconds')\n * // Returns: \"Timestamp at which historical indexing started\"\n * ```\n */\n getHelp(name: string): string | undefined {\n return this.metrics.find((m) => m.name === name)?.help;\n }\n\n /**\n * Gets metric type\n * @param name Metric name\n * @returns Metric type or undefined if not found\n * @example\n * ```ts\n * parser.getType('ponder_version_info') // Returns: \"gauge\"\n * parser.getType('ponder_postgres_query_total') // Returns: \"counter\"\n * ```\n */\n getType(name: string): string | undefined {\n return this.metrics.find((m) => m.name === name)?.type;\n }\n\n /**\n * Gets all metric names\n * @returns Array of metric names\n * @example\n * ```ts\n * parser.getMetricNames()\n * // Returns: [\n * // 'ponder_version_info',\n * // 'ponder_settings_info',\n * // 'ponder_historical_start_timestamp_seconds',\n * // 'ponder_historical_total_indexing_seconds'\n * // ]\n * ```\n */\n getMetricNames(): string[] {\n return this.metrics.map((m) => m.name);\n }\n}\n"],"mappings":"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","names":["_a"]}
1
+ {"version":3,"sources":["../src/middleware.ts","../src/db-helpers.ts","../src/prometheus-metrics.ts"],"sourcesContent":["import type { EnsRainbow } from \"@ensnode/ensrainbow-sdk\";\nimport { MiddlewareHandler } from \"hono\";\nimport { HTTPException } from \"hono/http-exception\";\n\nimport { queryPonderMeta } from \"./db-helpers\";\nimport { PrometheusMetrics } from \"./prometheus-metrics\";\nimport type {\n PonderEnvVarsInfo,\n PonderMetadataMiddlewareOptions,\n PonderMetadataMiddlewareResponse,\n} from \"./types/api\";\nimport type { BlockInfo, ChainIndexingStatus } from \"./types/common\";\n\n/**\n * Ponder Metadata types definition.\n */\ninterface PonderMetadataModule {\n /** Application info */\n AppInfo: {\n /** Application name */\n name: string;\n /** Application version */\n version: string;\n };\n\n /** Environment Variables info */\n EnvVars: {\n /** Database schema */\n DATABASE_SCHEMA: string;\n } & PonderEnvVarsInfo;\n\n /** Runtime info */\n RuntimeInfo: {\n /**\n * Application build id\n * https://github.com/ponder-sh/ponder/blob/626e524/packages/core/src/build/index.ts#L425-L431\n **/\n codebaseBuildId: string;\n\n /** Chain indexing statuses by chain ID */\n chainIndexingStatuses: { [chainId: number]: ChainIndexingStatus };\n\n /** ENSRainbow version info */\n ensRainbow?: EnsRainbow.VersionInfo;\n };\n}\n\nexport type MetadataMiddlewareResponse = PonderMetadataMiddlewareResponse<\n PonderMetadataModule[\"AppInfo\"],\n PonderMetadataModule[\"EnvVars\"],\n PonderMetadataModule[\"RuntimeInfo\"]\n>;\n\nexport function ponderMetadata<\n AppInfo extends PonderMetadataModule[\"AppInfo\"],\n EnvVars extends PonderMetadataModule[\"EnvVars\"],\n>({\n app,\n db,\n env,\n query,\n publicClients,\n}: PonderMetadataMiddlewareOptions<AppInfo, EnvVars>): MiddlewareHandler {\n return async function ponderMetadataMiddleware(ctx) {\n const indexedChainNames = Object.keys(publicClients);\n\n const ponderStatus = await query.ponderStatus();\n\n const metrics = PrometheusMetrics.parse(await query.prometheusMetrics());\n\n const chainIndexingStatuses: Record<number, ChainIndexingStatus> = {};\n\n for (const indexedChainName of indexedChainNames) {\n const publicClient = publicClients[indexedChainName];\n\n if (!publicClient || typeof publicClient.chain === \"undefined\") {\n throw new HTTPException(500, {\n message: `No public client found for \"${indexedChainName}\" chain name`,\n });\n }\n\n const publicClientChainId = publicClient.chain.id;\n\n /**\n * Fetches block metadata from blockchain network for a given block number.\n * @param blockNumber\n * @returns block metadata\n * @throws {Error} if failed to fetch block metadata from blockchain network\n */\n const fetchBlockMetadata = async (blockNumber: number): Promise<BlockInfo> => {\n const block = await publicClient.getBlock({\n blockNumber: BigInt(blockNumber),\n });\n\n if (!block) {\n throw new Error(\n `Failed to fetch block metadata for block number ${blockNumber} on chain ID \"${publicClientChainId}\"`,\n );\n }\n\n return {\n number: Number(block.number),\n timestamp: Number(block.timestamp),\n } satisfies BlockInfo;\n };\n\n const latestSafeBlockData = await publicClient.getBlock();\n\n if (!latestSafeBlockData) {\n throw new HTTPException(500, {\n message: `Failed to fetch latest safe block for chain ID \"${publicClientChainId}\"`,\n });\n }\n\n // mapping latest safe block\n const latestSafeBlock = {\n number: Number(latestSafeBlockData.number),\n timestamp: Number(latestSafeBlockData.timestamp),\n } satisfies BlockInfo;\n\n // mapping indexed chain name to its metric representation for metric queries\n const chain = indexedChainName;\n\n // mapping last synced block if available\n const lastSyncedBlockHeight = metrics.getValue(\"ponder_sync_block\", {\n chain,\n });\n let lastSyncedBlock: BlockInfo | null = null;\n if (lastSyncedBlockHeight) {\n try {\n lastSyncedBlock = await fetchBlockMetadata(lastSyncedBlockHeight);\n } catch (error) {\n console.error(\"Failed to fetch block metadata for last synced block\", error);\n }\n }\n\n const firstBlockToIndex = await query.firstBlockToIndexByChainId(\n publicClientChainId,\n publicClient,\n );\n\n // mapping ponder status for current chain\n const ponderStatusForChain = Object.values(ponderStatus).find(\n (ponderStatusEntry) => ponderStatusEntry.id === publicClientChainId,\n );\n\n // mapping last indexed block if available\n let lastIndexedBlock: BlockInfo | null = null;\n if (ponderStatusForChain) {\n // Since Ponder 0.11, the `block` value in the PonderStatus object\n // is always provided. It represents either the very first block to be indexed\n // or the last block that has been indexed.\n //\n // We compare the first block to be indexed (from ponder.config.ts)\n // with the block value from the PonderStatus object (from `GET /status` response).\n // We only set the `lastIndexedBlock` value if the `block` from the PonderStatus object\n // is not the same as the `firstBlockToIndex`.\n if (firstBlockToIndex.number < ponderStatusForChain.block.number) {\n lastIndexedBlock = ponderStatusForChain.block;\n }\n }\n\n chainIndexingStatuses[publicClientChainId] = {\n chainId: publicClientChainId,\n lastSyncedBlock,\n lastIndexedBlock,\n latestSafeBlock,\n firstBlockToIndex,\n } satisfies ChainIndexingStatus;\n }\n\n // mapping ponder app build id if available\n let ponderAppBuildId: string | undefined;\n try {\n ponderAppBuildId = (await queryPonderMeta(env.DATABASE_SCHEMA, db)).build_id;\n } catch (error) {\n console.error(\"Failed to fetch ponder metadata\", error);\n }\n\n // fetch ENSRainbow version if available\n let ensRainbowVersionInfo = undefined;\n if (query.ensRainbowVersion) {\n try {\n ensRainbowVersionInfo = await query.ensRainbowVersion();\n } catch (error) {\n console.error(\"Failed to fetch ENSRainbow version\", error);\n }\n }\n\n const response = {\n app,\n deps: {\n ponder: formatTextMetricValue(metrics.getLabel(\"ponder_version_info\", \"version\")),\n nodejs: formatTextMetricValue(metrics.getLabel(\"nodejs_version_info\", \"version\")),\n },\n env,\n runtime: {\n codebaseBuildId: formatTextMetricValue(ponderAppBuildId),\n chainIndexingStatuses,\n ensRainbow: ensRainbowVersionInfo,\n },\n } satisfies MetadataMiddlewareResponse;\n\n // validate if response is in correct state\n validateResponse(response);\n\n return ctx.json(response);\n };\n}\n\n/**\n * Validates the metadata middleware response to ensure correct state.\n *\n * @param response The response to validate\n * @throws {HTTPException} if the response is in an invalid state\n */\nfunction validateResponse(response: MetadataMiddlewareResponse): void {\n const { chainIndexingStatuses } = response.runtime;\n\n if (Object.keys(chainIndexingStatuses).length === 0) {\n throw new HTTPException(500, {\n message: \"No chain indexing status found\",\n });\n }\n\n if (Object.values(chainIndexingStatuses).some((n) => n.firstBlockToIndex === null)) {\n throw new HTTPException(500, {\n message: \"Failed to fetch first block to index for some chains\",\n });\n }\n}\n\n/**\n * Formats a text metric value.\n * @param value\n * @returns\n */\nfunction formatTextMetricValue(value?: string): string {\n return value ?? \"unknown\";\n}\n","import { pgSchema, pgTable } from \"drizzle-orm/pg-core\";\nimport { type ReadonlyDrizzle, eq } from \"ponder\";\n\n/**\n * Internal ponder metadata type.\n * Copied from https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L94-L102\n */\ntype PonderAppMeta = {\n is_locked: 0 | 1;\n is_dev: 0 | 1;\n heartbeat_at: number;\n build_id: string;\n table_names: Array<string>;\n version: string;\n is_ready: 0 | 1;\n};\n\n/**\n * Get DB schema for _ponder_meta table.\n * Akin to https://github.com/ponder-sh/ponder/blob/32634897bf65e92a85dc4cccdaba70c9425d90f3/packages/core/src/database/index.ts#L129-L141\n *\n * @param databaseNamespace A namespace for the database.\n * @returns A table schema for _ponder_meta table.\n * */\nconst getPonderMetaTableSchema = (databaseNamespace: string) => {\n if (databaseNamespace === \"public\") {\n return pgTable(\"_ponder_meta\", (t) => ({\n key: t.text().primaryKey().$type<\"app\">(),\n value: t.jsonb().$type<PonderAppMeta>().notNull(),\n }));\n }\n\n return pgSchema(databaseNamespace).table(\"_ponder_meta\", (t) => ({\n key: t.text().primaryKey().$type<\"app\">(),\n value: t.jsonb().$type<PonderAppMeta>().notNull(),\n }));\n};\n\ntype PonderMetaTableSchema = ReturnType<typeof getPonderMetaTableSchema>;\n\n/**\n * Get ponder metadata for the app.\n *\n * @param namespace A namespace for the database (e.g. \"public\").\n * @param db Drizzle DB Client instance.\n * @returns ponder metadata for the app.\n * @throws Error if ponder metadata not found.\n */\nexport async function queryPonderMeta(\n namespace: string,\n db: ReadonlyDrizzle<Record<string, unknown>>,\n): Promise<PonderMetaTableSchema[\"$inferSelect\"][\"value\"]> {\n const PONDER_META = getPonderMetaTableSchema(namespace);\n\n const [ponderAppMeta] = await db\n .select({ value: PONDER_META.value })\n .from(PONDER_META)\n .where(eq(PONDER_META.key, \"app\"))\n .limit(1);\n\n if (!ponderAppMeta) {\n throw new Error(\"Ponder metadata not found\");\n }\n\n return ponderAppMeta.value;\n}\n","import parsePrometheusTextFormat, { type PrometheusMetric } from \"parse-prometheus-text-format\";\n// Ensures local declaration file is available to downstream consumers\nimport \"./types/parse-prometheus-text-format\";\n\ninterface ParsedPrometheusMetric extends Omit<PrometheusMetric, \"metrics\"> {\n metrics: Array<{\n value: number;\n labels?: Record<string, string>;\n }>;\n}\n\n/**\n * Converts Prometheus text format to JSON format compatible with prom2json\n * @param text Raw Prometheus metric text\n * @returns Array of metrics in prom2json compatible format\n * @example\n * ```ts\n * const metrics = parsePrometheusText(`\n * # HELP ponder_version_info Ponder version information\n * # TYPE ponder_version_info gauge\n * ponder_version_info{version=\"0.9.18\",major=\"0\",minor=\"9\",patch=\"18\"} 1\n * `);\n * // Returns:\n * // [{\n * // name: \"ponder_version_info\",\n * // help: \"Ponder version information\",\n * // type: \"gauge\",\n * // metrics: [{\n * // value: 1,\n * // labels: { version: \"0.9.18\", major: \"0\", minor: \"9\", patch: \"18\" }\n * // }]\n * // }]\n * ```\n */\nexport function parsePrometheusText(text: string): Array<ParsedPrometheusMetric> {\n return parsePrometheusTextFormat(text).map((metric) => ({\n name: metric.name,\n help: metric.help || \"\",\n type: metric.type.toLowerCase(),\n metrics: metric.metrics.map((m) => ({\n value: Number(m.value),\n ...(m.labels && Object.keys(m.labels).length > 0 ? { labels: m.labels } : {}),\n })),\n }));\n}\n\nexport class PrometheusMetrics {\n private constructor(private readonly metrics: Array<ParsedPrometheusMetric>) {}\n\n static parse(maybePrometheusMetricsText: string): PrometheusMetrics {\n return new PrometheusMetrics(parsePrometheusText(maybePrometheusMetricsText));\n }\n\n /**\n * Gets all metrics of a specific name\n * @param name Metric name\n * @returns Array of metrics or undefined if not found\n * @example\n * ```ts\n * const metrics = parser.get('ponder_historical_total_indexing_seconds');\n * // Returns: [\n * // { value: 251224935, labels: { network: \"1\" } },\n * // { value: 251224935, labels: { network: \"8453\" } }\n * // ]\n * ```\n */\n get(name: string): Array<{ value: number; labels?: Record<string, string> }> | undefined {\n const metric = this.metrics.find((m) => m.name === name);\n return metric?.metrics;\n }\n\n /**\n * Gets a single metric value, optionally filtered by labels\n * @param name Metric name\n * @param labelFilter Optional label key-value pairs to match\n * @returns Metric value or undefined if not found\n * @example\n * ```ts\n * // Get simple value\n * parser.getValue('ponder_historical_start_timestamp_seconds') // Returns: 1740391265\n *\n * // Get value with label filter\n * parser.getValue('ponder_historical_total_indexing_seconds', { network: '1' }) // Returns: 251224935\n * ```\n */\n getValue(name: string, labelFilter?: Record<string, string>): number | undefined {\n const metrics = this.get(name);\n\n if (!metrics || metrics.length === 0) {\n return undefined;\n }\n\n if (!labelFilter) {\n return metrics[0]?.value;\n }\n\n const metric = metrics.find(\n (m) => m.labels && Object.entries(labelFilter).every(([k, v]) => m.labels?.[k] === v),\n );\n\n return metric?.value;\n }\n\n /**\n * Gets a label value from a metric\n * @param name Metric name\n * @param label Label name to retrieve\n * @returns Label value or undefined if not found\n * @example\n * ```ts\n * parser.getLabel('ponder_version_info', 'version') // Returns: \"0.9.18\"\n * parser.getLabel('ponder_settings_info', 'ordering') // Returns: \"omnichain\"\n * ```\n */\n getLabel(name: string, label: string): string | undefined {\n return this.getLabels(name, label)[0];\n }\n\n /**\n * Gets all unique label values for a metric\n * @param name Metric name\n * @param label Label name to retrieve\n * @returns Array of unique label values\n * @example\n * ```ts\n * // Get all network IDs\n * parser.getLabels('ponder_historical_total_indexing_seconds', 'network')\n * // Returns: ['1', '8453']\n * ```\n */\n getLabels(name: string, label: string): string[] {\n const metrics = this.get(name);\n\n if (!metrics) return [];\n\n return [\n ...new Set(metrics.map((m) => m.labels?.[label]).filter((v): v is string => v !== undefined)),\n ];\n }\n\n /**\n * Gets help text for a metric\n * @param name Metric name\n * @returns Help text or undefined if not found\n * @example\n * ```ts\n * parser.getHelp('ponder_historical_start_timestamp_seconds')\n * // Returns: \"Timestamp at which historical indexing started\"\n * ```\n */\n getHelp(name: string): string | undefined {\n return this.metrics.find((m) => m.name === name)?.help;\n }\n\n /**\n * Gets metric type\n * @param name Metric name\n * @returns Metric type or undefined if not found\n * @example\n * ```ts\n * parser.getType('ponder_version_info') // Returns: \"gauge\"\n * parser.getType('ponder_postgres_query_total') // Returns: \"counter\"\n * ```\n */\n getType(name: string): string | undefined {\n return this.metrics.find((m) => m.name === name)?.type;\n }\n\n /**\n * Gets all metric names\n * @returns Array of metric names\n * @example\n * ```ts\n * parser.getMetricNames()\n * // Returns: [\n * // 'ponder_version_info',\n * // 'ponder_settings_info',\n * // 'ponder_historical_start_timestamp_seconds',\n * // 'ponder_historical_total_indexing_seconds'\n * // ]\n * ```\n */\n getMetricNames(): string[] {\n return this.metrics.map((m) => m.name);\n }\n}\n"],"mappings":"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","names":["_a"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensnode/ponder-metadata",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "type": "module",
5
5
  "description": "A Hono middleware for making Ponder app metadata available to clients.",
6
6
  "license": "MIT",
@@ -29,21 +29,21 @@
29
29
  "drizzle-orm": "=0.41.0",
30
30
  "parse-prometheus-text-format": "^1.1.1",
31
31
  "viem": "^2.22.13",
32
- "@ensnode/ensrainbow-sdk": "0.28.0"
32
+ "@ensnode/ensrainbow-sdk": "0.30.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@biomejs/biome": "^1.9.4",
36
36
  "@types/node": "^22.14.0",
37
37
  "hono": "^4.7.6",
38
- "ponder": "0.10.28",
38
+ "ponder": "0.11.25",
39
39
  "tsup": "^8.3.6",
40
40
  "typescript": "^5.7.3",
41
41
  "vitest": "^3.1.1",
42
- "@ensnode/shared-configs": "0.28.0"
42
+ "@ensnode/shared-configs": "0.30.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "hono": "^4.7.6",
46
- "ponder": "0.10.28"
46
+ "ponder": "0.11.25"
47
47
  },
48
48
  "scripts": {
49
49
  "prepublish": "tsup",