@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 +41 -180
- package/dist/index.js +32 -57
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
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
|
-
*
|
|
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
|
|
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
|
|
56
|
-
publicClients:
|
|
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
|
-
/**
|
|
98
|
-
|
|
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) =>
|
|
152
|
+
declare const getPonderMetaTableSchema: (databaseNamespace: string) => ponder.PgTableWithColumns<{
|
|
127
153
|
name: "_ponder_meta";
|
|
128
154
|
schema: undefined;
|
|
129
155
|
columns: {
|
|
130
|
-
key:
|
|
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:
|
|
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
|
-
}> |
|
|
196
|
+
}> | ponder.PgTableWithColumns<{
|
|
171
197
|
name: "_ponder_meta";
|
|
172
198
|
schema: string;
|
|
173
199
|
columns: {
|
|
174
|
-
key:
|
|
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:
|
|
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
|
|
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
|
|
209
|
-
const ponderStatus = await
|
|
188
|
+
const indexedChainNames = Object.keys(publicClients);
|
|
189
|
+
const ponderStatus = await query.ponderStatus();
|
|
210
190
|
const metrics = PrometheusMetrics.parse(await query.prometheusMetrics());
|
|
211
|
-
const
|
|
212
|
-
for (const
|
|
213
|
-
const publicClient = publicClients[
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
224
|
+
const chain = indexedChainName;
|
|
244
225
|
const lastSyncedBlockHeight = metrics.getValue("ponder_sync_block", {
|
|
245
|
-
|
|
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
|
|
256
|
-
|
|
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 (
|
|
260
|
-
|
|
244
|
+
if (ponderStatusForChain) {
|
|
245
|
+
if (firstBlockToIndex.number < ponderStatusForChain.block.number) {
|
|
246
|
+
lastIndexedBlock = ponderStatusForChain.block;
|
|
247
|
+
}
|
|
261
248
|
}
|
|
262
|
-
|
|
249
|
+
chainIndexingStatuses[publicClientChainId] = {
|
|
250
|
+
chainId: publicClientChainId,
|
|
263
251
|
lastSyncedBlock,
|
|
264
252
|
lastIndexedBlock,
|
|
265
253
|
latestSafeBlock,
|
|
266
|
-
firstBlockToIndex
|
|
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
|
-
|
|
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 {
|
|
302
|
-
if (Object.keys(
|
|
289
|
+
const { chainIndexingStatuses } = response.runtime;
|
|
290
|
+
if (Object.keys(chainIndexingStatuses).length === 0) {
|
|
303
291
|
throw new HTTPException(500, {
|
|
304
|
-
message: "No
|
|
292
|
+
message: "No chain indexing status found"
|
|
305
293
|
});
|
|
306
294
|
}
|
|
307
|
-
if (Object.values(
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
42
|
+
"@ensnode/shared-configs": "0.30.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"hono": "^4.7.6",
|
|
46
|
-
"ponder": "0.
|
|
46
|
+
"ponder": "0.11.25"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"prepublish": "tsup",
|