@ponder/client 0.9.0-next.4 → 0.9.0-next.6

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,19 +1,20 @@
1
- import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
2
- export { alias, except, exceptAll, intersect, intersectAll, union, unionAll } from 'drizzle-orm/pg-core';
3
1
  import { SQLWrapper, QueryWithTypings } from 'drizzle-orm';
4
2
  export { and, asc, avg, avgDistinct, between, count, countDistinct, desc, eq, exists, gt, gte, inArray, isNotNull, isNull, like, lt, lte, max, min, ne, not, notBetween, notExists, notIlike, notInArray, or, relations, sql, sum, sumDistinct } from 'drizzle-orm';
5
3
  import { PgRemoteDatabase } from 'drizzle-orm/pg-proxy';
4
+ export { alias, except, exceptAll, intersect, intersectAll, union, unionAll } from 'drizzle-orm/pg-core';
6
5
 
7
- declare const setDatabaseSchema: <T extends {
8
- [name: string]: unknown;
9
- }>(schema: T, schemaName: string) => T;
10
-
11
- type Schema = {
12
- [name: string]: unknown;
13
- };
14
6
  type Prettify<T> = {
15
7
  [K in keyof T]: T[K];
16
8
  } & {};
9
+ type Status = {
10
+ [network: string]: {
11
+ block: {
12
+ number: number;
13
+ timestamp: number;
14
+ } | null;
15
+ ready: boolean;
16
+ };
17
+ };
17
18
  type ClientDb<schema extends Schema = Schema> = Prettify<Omit<PgRemoteDatabase<schema>, "insert" | "update" | "delete" | "transaction" | "refreshMaterializedView" | "_">>;
18
19
  type Client<schema extends Schema = Schema> = {
19
20
  /** Query the database. */
@@ -22,90 +23,9 @@ type Client<schema extends Schema = Schema> = {
22
23
  live: <result>(queryFn: (db: ClientDb<schema>) => Promise<result>, onData: (result: result) => void, onError?: (error: Error) => void) => {
23
24
  unsubscribe: () => void;
24
25
  };
26
+ /** Get the status of all chains. */
27
+ getStatus: () => Promise<Status>;
25
28
  };
26
- /**
27
- * A table that tracks the status of each chain.
28
- *
29
- * @property {number} chainId - The chain ID.
30
- * @property {number} blockNumber - The closest-to-tip indexed block number.
31
- * @property {number} blockTimestamp - The closest-to-tip indexed block timestamp.
32
- * @property {boolean} ready - `true` if the chain has completed the historical backfill.
33
- */
34
- declare const status: drizzle_orm_pg_core.PgTableWithColumns<{
35
- name: "_ponder_status";
36
- schema: undefined;
37
- columns: {
38
- chainId: drizzle_orm_pg_core.PgColumn<{
39
- name: "chainId";
40
- tableName: "_ponder_status";
41
- dataType: "number";
42
- columnType: "PgBigInt53";
43
- data: number;
44
- driverParam: string | number;
45
- notNull: true;
46
- hasDefault: false;
47
- isPrimaryKey: true;
48
- isAutoincrement: false;
49
- hasRuntimeDefault: false;
50
- enumValues: undefined;
51
- baseColumn: never;
52
- identity: undefined;
53
- generated: undefined;
54
- }, {}, {}>;
55
- blockNumber: drizzle_orm_pg_core.PgColumn<{
56
- name: "blockNumber";
57
- tableName: "_ponder_status";
58
- dataType: "number";
59
- columnType: "PgBigInt53";
60
- data: number;
61
- driverParam: string | number;
62
- notNull: false;
63
- hasDefault: false;
64
- isPrimaryKey: false;
65
- isAutoincrement: false;
66
- hasRuntimeDefault: false;
67
- enumValues: undefined;
68
- baseColumn: never;
69
- identity: undefined;
70
- generated: undefined;
71
- }, {}, {}>;
72
- blockTimestamp: drizzle_orm_pg_core.PgColumn<{
73
- name: "blockTimestamp";
74
- tableName: "_ponder_status";
75
- dataType: "number";
76
- columnType: "PgBigInt53";
77
- data: number;
78
- driverParam: string | number;
79
- notNull: false;
80
- hasDefault: false;
81
- isPrimaryKey: false;
82
- isAutoincrement: false;
83
- hasRuntimeDefault: false;
84
- enumValues: undefined;
85
- baseColumn: never;
86
- identity: undefined;
87
- generated: undefined;
88
- }, {}, {}>;
89
- ready: drizzle_orm_pg_core.PgColumn<{
90
- name: "ready";
91
- tableName: "_ponder_status";
92
- dataType: "boolean";
93
- columnType: "PgBoolean";
94
- data: boolean;
95
- driverParam: boolean;
96
- notNull: true;
97
- hasDefault: false;
98
- isPrimaryKey: false;
99
- isAutoincrement: false;
100
- hasRuntimeDefault: false;
101
- enumValues: undefined;
102
- baseColumn: never;
103
- identity: undefined;
104
- generated: undefined;
105
- }, {}, {}>;
106
- };
107
- dialect: "pg";
108
- }>;
109
29
  declare const compileQuery: (query: SQLWrapper | string) => QueryWithTypings;
110
30
  /**
111
31
  * Create a client for querying Ponder apps.
@@ -125,4 +45,12 @@ declare const createClient: <schema extends Schema>(baseUrl: string, { schema }:
125
45
  schema: schema;
126
46
  }) => Client<schema>;
127
47
 
128
- export { type Client, compileQuery, createClient, setDatabaseSchema, status };
48
+ type Schema = {
49
+ [name: string]: unknown;
50
+ };
51
+ declare const Schema: unique symbol;
52
+ declare const setDatabaseSchema: <T extends {
53
+ [name: string]: unknown;
54
+ }>(schema: T, schemaName: string) => T;
55
+
56
+ export { type Client, type Status, compileQuery, createClient, setDatabaseSchema };
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // src/index.ts
2
- import { sql } from "drizzle-orm";
3
- import { pgTable } from "drizzle-orm/pg-core";
2
+ import {
3
+ Table,
4
+ is,
5
+ sql
6
+ } from "drizzle-orm";
4
7
  import { drizzle } from "drizzle-orm/pg-proxy";
5
8
  import {
6
9
  sql as sql2,
@@ -44,20 +47,6 @@ import {
44
47
  except,
45
48
  exceptAll
46
49
  } from "drizzle-orm/pg-core";
47
-
48
- // src/setDatabaseSchema.ts
49
- import { Table, is } from "drizzle-orm";
50
- var Schema = Symbol.for("drizzle:Schema");
51
- var setDatabaseSchema = (schema, schemaName) => {
52
- for (const table of Object.values(schema)) {
53
- if (is(table, Table)) {
54
- table[Schema] = schemaName;
55
- }
56
- }
57
- return schema;
58
- };
59
-
60
- // src/index.ts
61
50
  var getEventSource = async () => {
62
51
  let SSE;
63
52
  if (typeof window === "undefined") {
@@ -78,18 +67,10 @@ var getUrl = (baseUrl, method, query) => {
78
67
  }
79
68
  return url;
80
69
  };
81
- var status = pgTable("_ponder_status", (t) => ({
82
- chainId: t.bigint({ mode: "number" }).primaryKey(),
83
- blockNumber: t.bigint({ mode: "number" }),
84
- blockTimestamp: t.bigint({ mode: "number" }),
85
- ready: t.boolean().notNull()
86
- }));
87
- status[Symbol.for("ponder:onchain")] = true;
88
70
  var noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {
89
71
  casing: "snake_case"
90
72
  });
91
73
  var dialect = noopDatabase.dialect;
92
- var session = noopDatabase.session;
93
74
  var compileQuery = (query) => {
94
75
  const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL();
95
76
  return dialect.sqlToQuery(sequel);
@@ -118,51 +99,55 @@ var createClient = (baseUrl, { schema }) => {
118
99
  { schema, casing: "snake_case" }
119
100
  ),
120
101
  live: (queryFn, onData, onError) => {
121
- const builtQuery = compileQuery(queryFn(noopDatabase));
122
- if (builtQuery.sql === 'select "chain_id", "block_number", "block_timestamp", "ready" from "_ponder_status"' && builtQuery.params.length === 0) {
123
- const addEventListeners = () => {
124
- sse.addEventListener("message", (event) => {
125
- const data = JSON.parse(event.data);
126
- if (data.status === "error") {
127
- const error = new Error(data.error);
128
- error.stack = void 0;
129
- onError?.(error);
130
- } else {
131
- onData(data.result);
132
- }
133
- });
134
- sse.addEventListener("error", () => {
135
- onError?.(new Error("server disconnected"));
136
- });
137
- };
138
- liveCount++;
139
- if (sse === void 0) {
140
- getEventSource().then((SSE) => {
141
- sse = new SSE(getUrl(baseUrl, "live"));
142
- addEventListeners();
143
- });
144
- } else {
145
- addEventListeners();
146
- }
147
- return {
148
- unsubscribe: () => {
149
- if (--liveCount === 0)
150
- sse?.close();
102
+ const addEventListeners = () => {
103
+ sse.addEventListener("message", (event) => {
104
+ const data = JSON.parse(event.data);
105
+ if (data.status === "error") {
106
+ const error = new Error(data.error);
107
+ error.stack = void 0;
108
+ onError?.(error);
109
+ } else {
110
+ queryFn(client.db).then(onData).catch(onError);
151
111
  }
152
- };
112
+ });
113
+ sse.addEventListener("error", () => {
114
+ onError?.(new Error("server disconnected"));
115
+ });
116
+ };
117
+ liveCount++;
118
+ if (sse === void 0) {
119
+ getEventSource().then((SSE) => {
120
+ sse = new SSE(getUrl(baseUrl, "live"));
121
+ addEventListeners();
122
+ });
153
123
  } else {
154
- return client.live(
155
- (db) => db.select().from(status),
156
- () => {
157
- queryFn(client.db).then(onData).catch(onError);
158
- },
159
- onError
160
- );
124
+ addEventListeners();
161
125
  }
126
+ return {
127
+ unsubscribe: () => {
128
+ if (--liveCount === 0)
129
+ sse?.close();
130
+ }
131
+ };
132
+ },
133
+ getStatus: async () => {
134
+ const response = await fetch(getUrl(baseUrl, "status"), {
135
+ method: "POST"
136
+ });
137
+ return response.json();
162
138
  }
163
139
  };
164
140
  return client;
165
141
  };
142
+ var Schema = Symbol.for("drizzle:Schema");
143
+ var setDatabaseSchema = (schema, schemaName) => {
144
+ for (const table of Object.values(schema)) {
145
+ if (is(table, Table)) {
146
+ table[Schema] = schemaName;
147
+ }
148
+ }
149
+ return schema;
150
+ };
166
151
  export {
167
152
  alias,
168
153
  and,
@@ -201,7 +186,6 @@ export {
201
186
  relations,
202
187
  setDatabaseSchema,
203
188
  sql2 as sql,
204
- status,
205
189
  sum,
206
190
  sumDistinct,
207
191
  union,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/setDatabaseSchema.ts"],"sourcesContent":["import { type QueryWithTypings, type SQLWrapper, sql } from \"drizzle-orm\";\nimport { type PgDialect, type PgSession, pgTable } from \"drizzle-orm/pg-core\";\nimport { type PgRemoteDatabase, drizzle } from \"drizzle-orm/pg-proxy\";\n\nconst getEventSource = async () => {\n let SSE: typeof EventSource;\n if (typeof window === \"undefined\") {\n const undici = await import(/* webpackIgnore: true */ \"undici\");\n // @ts-ignore\n SSE = undici.EventSource;\n } else {\n SSE = EventSource;\n }\n\n return SSE;\n};\n\ntype Schema = { [name: string]: unknown };\n\ntype Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\n\ntype ClientDb<schema extends Schema = Schema> = Prettify<\n Omit<\n PgRemoteDatabase<schema>,\n | \"insert\"\n | \"update\"\n | \"delete\"\n | \"transaction\"\n | \"refreshMaterializedView\"\n | \"_\"\n >\n>;\n\nexport type Client<schema extends Schema = Schema> = {\n /** Query the database. */\n db: ClientDb<schema>;\n /** Subscribe to live updates. */\n live: <result>(\n queryFn: (db: ClientDb<schema>) => Promise<result>,\n onData: (result: result) => void,\n onError?: (error: Error) => void,\n ) => {\n unsubscribe: () => void;\n };\n};\n\nconst getUrl = (\n baseUrl: string,\n method: \"live\" | \"db\" | \"status\",\n query?: QueryWithTypings,\n) => {\n const url = new URL(`${baseUrl}/client/${method}`);\n if (query) {\n url.searchParams.set(\"sql\", JSON.stringify(query));\n }\n return url;\n};\n\n/**\n * A table that tracks the status of each chain.\n *\n * @property {number} chainId - The chain ID.\n * @property {number} blockNumber - The closest-to-tip indexed block number.\n * @property {number} blockTimestamp - The closest-to-tip indexed block timestamp.\n * @property {boolean} ready - `true` if the chain has completed the historical backfill.\n */\nexport const status = pgTable(\"_ponder_status\", (t) => ({\n chainId: t.bigint({ mode: \"number\" }).primaryKey(),\n blockNumber: t.bigint({ mode: \"number\" }),\n blockTimestamp: t.bigint({ mode: \"number\" }),\n ready: t.boolean().notNull(),\n}));\n\n// @ts-ignore\nstatus[Symbol.for(\"ponder:onchain\")] = true;\n\nconst noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {\n casing: \"snake_case\",\n});\n\n// @ts-ignore\nconst dialect: PgDialect = noopDatabase.dialect;\n// @ts-ignore\nconst session: PgSession = noopDatabase.session;\n\nexport const compileQuery = (query: SQLWrapper | string) => {\n const sequel = typeof query === \"string\" ? sql.raw(query) : query.getSQL();\n return dialect.sqlToQuery(sequel);\n};\n\n/**\n * Create a client for querying Ponder apps.\n *\n * @param baseUrl - The URL of the Ponder app.\n * @param schema - The schema of the Ponder app.\n *\n * @example\n * ```ts\n * import { createClient } from \"@ponder/client\";\n * import * as schema from \"../ponder.schema\";\n *\n * const client = createClient(\"https://...\", { schema });\n * ```\n */\nexport const createClient = <schema extends Schema>(\n baseUrl: string,\n { schema }: { schema: schema },\n): Client<schema> => {\n let sse: EventSource | undefined;\n let liveCount = 0;\n\n const client: Client<schema> = {\n db: drizzle(\n async (sql, params, _, typings) => {\n const builtQuery = { sql, params, typings };\n const response = await fetch(getUrl(baseUrl, \"db\", builtQuery), {\n method: \"POST\",\n });\n\n if (response.ok === false) {\n const error = new Error(await response.text());\n error.stack = undefined;\n throw error;\n }\n\n const result = await response.json();\n\n return {\n ...result,\n rows: result.rows.map((row: object) => Object.values(row)),\n };\n },\n { schema, casing: \"snake_case\" },\n ),\n live: (queryFn, onData, onError) => {\n // https://github.com/drizzle-team/drizzle-orm/blob/04c91434c7ac10aeb2923efd1d19a7ebf10ea9d4/drizzle-orm/src/pg-core/db.ts#L602-L621\n\n // @ts-ignore\n const builtQuery = compileQuery(queryFn(noopDatabase));\n\n if (\n builtQuery.sql ===\n 'select \"chain_id\", \"block_number\", \"block_timestamp\", \"ready\" from \"_ponder_status\"' &&\n builtQuery.params.length === 0\n ) {\n const addEventListeners = () => {\n sse!.addEventListener(\"message\", (event) => {\n const data = JSON.parse(event.data) as\n | { status: \"success\"; result: unknown }\n | { status: \"error\"; error: string };\n\n if (data.status === \"error\") {\n const error = new Error(data.error);\n error.stack = undefined;\n onError?.(error);\n } else {\n // @ts-ignore\n onData(data.result);\n }\n });\n\n sse!.addEventListener(\"error\", () => {\n onError?.(new Error(\"server disconnected\"));\n });\n };\n\n liveCount++;\n if (sse === undefined) {\n getEventSource().then((SSE) => {\n sse = new SSE(getUrl(baseUrl, \"live\"));\n addEventListeners();\n });\n } else {\n addEventListeners();\n }\n\n return {\n unsubscribe: () => {\n if (--liveCount === 0) sse?.close();\n },\n };\n } else {\n return client.live(\n (db) => db.select().from(status),\n () => {\n queryFn(client.db).then(onData).catch(onError);\n },\n onError,\n );\n }\n },\n };\n\n return client;\n};\n\nexport {\n sql,\n eq,\n gt,\n gte,\n lt,\n lte,\n ne,\n isNull,\n isNotNull,\n inArray,\n notInArray,\n exists,\n notExists,\n between,\n notBetween,\n like,\n notIlike,\n not,\n asc,\n desc,\n and,\n or,\n count,\n countDistinct,\n avg,\n avgDistinct,\n sum,\n sumDistinct,\n max,\n min,\n relations,\n} from \"drizzle-orm\";\n\nexport {\n alias,\n union,\n unionAll,\n intersect,\n intersectAll,\n except,\n exceptAll,\n} from \"drizzle-orm/pg-core\";\n\nexport { setDatabaseSchema } from \"./setDatabaseSchema.js\";\n","import { Table, is } from \"drizzle-orm\";\n\nconst Schema = Symbol.for(\"drizzle:Schema\");\n\nexport const setDatabaseSchema = <T extends { [name: string]: unknown }>(\n schema: T,\n schemaName: string,\n): T => {\n for (const table of Object.values(schema)) {\n if (is(table, Table)) {\n // @ts-ignore\n table[Schema] = schemaName;\n }\n }\n return schema;\n};\n"],"mappings":"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","names":["sql","sql"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n type QueryWithTypings,\n type SQLWrapper,\n Table,\n is,\n sql,\n} from \"drizzle-orm\";\nimport type { PgDialect } from \"drizzle-orm/pg-core\";\nimport { type PgRemoteDatabase, drizzle } from \"drizzle-orm/pg-proxy\";\n\nconst getEventSource = async () => {\n let SSE: typeof EventSource;\n if (typeof window === \"undefined\") {\n const undici = await import(/* webpackIgnore: true */ \"undici\");\n // @ts-ignore\n SSE = undici.EventSource;\n } else {\n SSE = EventSource;\n }\n\n return SSE;\n};\n\ntype Schema = { [name: string]: unknown };\n\ntype Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\n\nexport type Status = {\n [network: string]: {\n block: { number: number; timestamp: number } | null;\n ready: boolean;\n };\n};\n\ntype ClientDb<schema extends Schema = Schema> = Prettify<\n Omit<\n PgRemoteDatabase<schema>,\n | \"insert\"\n | \"update\"\n | \"delete\"\n | \"transaction\"\n | \"refreshMaterializedView\"\n | \"_\"\n >\n>;\n\nexport type Client<schema extends Schema = Schema> = {\n /** Query the database. */\n db: ClientDb<schema>;\n /** Subscribe to live updates. */\n live: <result>(\n queryFn: (db: ClientDb<schema>) => Promise<result>,\n onData: (result: result) => void,\n onError?: (error: Error) => void,\n ) => {\n unsubscribe: () => void;\n };\n /** Get the status of all chains. */\n getStatus: () => Promise<Status>;\n};\n\nconst getUrl = (\n baseUrl: string,\n method: \"live\" | \"db\" | \"status\",\n query?: QueryWithTypings,\n) => {\n const url = new URL(`${baseUrl}/client/${method}`);\n if (query) {\n url.searchParams.set(\"sql\", JSON.stringify(query));\n }\n return url;\n};\n\nconst noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {\n casing: \"snake_case\",\n});\n\n// @ts-ignore\nconst dialect: PgDialect = noopDatabase.dialect;\n\nexport const compileQuery = (query: SQLWrapper | string) => {\n const sequel = typeof query === \"string\" ? sql.raw(query) : query.getSQL();\n return dialect.sqlToQuery(sequel);\n};\n\n/**\n * Create a client for querying Ponder apps.\n *\n * @param baseUrl - The URL of the Ponder app.\n * @param schema - The schema of the Ponder app.\n *\n * @example\n * ```ts\n * import { createClient } from \"@ponder/client\";\n * import * as schema from \"../ponder.schema\";\n *\n * const client = createClient(\"https://...\", { schema });\n * ```\n */\nexport const createClient = <schema extends Schema>(\n baseUrl: string,\n { schema }: { schema: schema },\n): Client<schema> => {\n let sse: EventSource | undefined;\n let liveCount = 0;\n\n const client: Client<schema> = {\n db: drizzle(\n async (sql, params, _, typings) => {\n const builtQuery = { sql, params, typings };\n const response = await fetch(getUrl(baseUrl, \"db\", builtQuery), {\n method: \"POST\",\n });\n\n if (response.ok === false) {\n const error = new Error(await response.text());\n error.stack = undefined;\n throw error;\n }\n\n const result = await response.json();\n\n return {\n ...result,\n rows: result.rows.map((row: object) => Object.values(row)),\n };\n },\n { schema, casing: \"snake_case\" },\n ),\n live: (queryFn, onData, onError) => {\n // https://github.com/drizzle-team/drizzle-orm/blob/04c91434c7ac10aeb2923efd1d19a7ebf10ea9d4/drizzle-orm/src/pg-core/db.ts#L602-L621\n\n const addEventListeners = () => {\n sse!.addEventListener(\"message\", (event) => {\n const data = JSON.parse(event.data) as\n | { status: \"success\"; result: unknown }\n | { status: \"error\"; error: string };\n\n if (data.status === \"error\") {\n const error = new Error(data.error);\n error.stack = undefined;\n onError?.(error);\n } else {\n queryFn(client.db).then(onData).catch(onError);\n }\n });\n\n sse!.addEventListener(\"error\", () => {\n onError?.(new Error(\"server disconnected\"));\n });\n };\n\n liveCount++;\n if (sse === undefined) {\n getEventSource().then((SSE) => {\n sse = new SSE(getUrl(baseUrl, \"live\"));\n addEventListeners();\n });\n } else {\n addEventListeners();\n }\n\n return {\n unsubscribe: () => {\n if (--liveCount === 0) sse?.close();\n },\n };\n },\n getStatus: async () => {\n const response = await fetch(getUrl(baseUrl, \"status\"), {\n method: \"POST\",\n });\n\n return response.json();\n },\n };\n\n return client;\n};\n\nexport {\n sql,\n eq,\n gt,\n gte,\n lt,\n lte,\n ne,\n isNull,\n isNotNull,\n inArray,\n notInArray,\n exists,\n notExists,\n between,\n notBetween,\n like,\n notIlike,\n not,\n asc,\n desc,\n and,\n or,\n count,\n countDistinct,\n avg,\n avgDistinct,\n sum,\n sumDistinct,\n max,\n min,\n relations,\n} from \"drizzle-orm\";\n\nexport {\n alias,\n union,\n unionAll,\n intersect,\n intersectAll,\n except,\n exceptAll,\n} from \"drizzle-orm/pg-core\";\n\nconst Schema = Symbol.for(\"drizzle:Schema\");\n\nexport const setDatabaseSchema = <T extends { [name: string]: unknown }>(\n schema: T,\n schemaName: string,\n): T => {\n for (const table of Object.values(schema)) {\n if (is(table, Table)) {\n // @ts-ignore\n table[Schema] = schemaName;\n }\n }\n return schema;\n};\n"],"mappings":"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","names":["sql"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponder/client",
3
- "version": "0.9.0-next.4",
3
+ "version": "0.9.0-next.6",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -1,5 +1,11 @@
1
- import { type QueryWithTypings, type SQLWrapper, sql } from "drizzle-orm";
2
- import { type PgDialect, type PgSession, pgTable } from "drizzle-orm/pg-core";
1
+ import {
2
+ type QueryWithTypings,
3
+ type SQLWrapper,
4
+ Table,
5
+ is,
6
+ sql,
7
+ } from "drizzle-orm";
8
+ import type { PgDialect } from "drizzle-orm/pg-core";
3
9
  import { type PgRemoteDatabase, drizzle } from "drizzle-orm/pg-proxy";
4
10
 
5
11
  const getEventSource = async () => {
@@ -21,6 +27,13 @@ type Prettify<T> = {
21
27
  [K in keyof T]: T[K];
22
28
  } & {};
23
29
 
30
+ export type Status = {
31
+ [network: string]: {
32
+ block: { number: number; timestamp: number } | null;
33
+ ready: boolean;
34
+ };
35
+ };
36
+
24
37
  type ClientDb<schema extends Schema = Schema> = Prettify<
25
38
  Omit<
26
39
  PgRemoteDatabase<schema>,
@@ -44,6 +57,8 @@ export type Client<schema extends Schema = Schema> = {
44
57
  ) => {
45
58
  unsubscribe: () => void;
46
59
  };
60
+ /** Get the status of all chains. */
61
+ getStatus: () => Promise<Status>;
47
62
  };
48
63
 
49
64
  const getUrl = (
@@ -58,32 +73,12 @@ const getUrl = (
58
73
  return url;
59
74
  };
60
75
 
61
- /**
62
- * A table that tracks the status of each chain.
63
- *
64
- * @property {number} chainId - The chain ID.
65
- * @property {number} blockNumber - The closest-to-tip indexed block number.
66
- * @property {number} blockTimestamp - The closest-to-tip indexed block timestamp.
67
- * @property {boolean} ready - `true` if the chain has completed the historical backfill.
68
- */
69
- export const status = pgTable("_ponder_status", (t) => ({
70
- chainId: t.bigint({ mode: "number" }).primaryKey(),
71
- blockNumber: t.bigint({ mode: "number" }),
72
- blockTimestamp: t.bigint({ mode: "number" }),
73
- ready: t.boolean().notNull(),
74
- }));
75
-
76
- // @ts-ignore
77
- status[Symbol.for("ponder:onchain")] = true;
78
-
79
76
  const noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {
80
77
  casing: "snake_case",
81
78
  });
82
79
 
83
80
  // @ts-ignore
84
81
  const dialect: PgDialect = noopDatabase.dialect;
85
- // @ts-ignore
86
- const session: PgSession = noopDatabase.session;
87
82
 
88
83
  export const compileQuery = (query: SQLWrapper | string) => {
89
84
  const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL();
@@ -137,59 +132,48 @@ export const createClient = <schema extends Schema>(
137
132
  live: (queryFn, onData, onError) => {
138
133
  // https://github.com/drizzle-team/drizzle-orm/blob/04c91434c7ac10aeb2923efd1d19a7ebf10ea9d4/drizzle-orm/src/pg-core/db.ts#L602-L621
139
134
 
140
- // @ts-ignore
141
- const builtQuery = compileQuery(queryFn(noopDatabase));
142
-
143
- if (
144
- builtQuery.sql ===
145
- 'select "chain_id", "block_number", "block_timestamp", "ready" from "_ponder_status"' &&
146
- builtQuery.params.length === 0
147
- ) {
148
- const addEventListeners = () => {
149
- sse!.addEventListener("message", (event) => {
150
- const data = JSON.parse(event.data) as
151
- | { status: "success"; result: unknown }
152
- | { status: "error"; error: string };
153
-
154
- if (data.status === "error") {
155
- const error = new Error(data.error);
156
- error.stack = undefined;
157
- onError?.(error);
158
- } else {
159
- // @ts-ignore
160
- onData(data.result);
161
- }
162
- });
163
-
164
- sse!.addEventListener("error", () => {
165
- onError?.(new Error("server disconnected"));
166
- });
167
- };
135
+ const addEventListeners = () => {
136
+ sse!.addEventListener("message", (event) => {
137
+ const data = JSON.parse(event.data) as
138
+ | { status: "success"; result: unknown }
139
+ | { status: "error"; error: string };
140
+
141
+ if (data.status === "error") {
142
+ const error = new Error(data.error);
143
+ error.stack = undefined;
144
+ onError?.(error);
145
+ } else {
146
+ queryFn(client.db).then(onData).catch(onError);
147
+ }
148
+ });
168
149
 
169
- liveCount++;
170
- if (sse === undefined) {
171
- getEventSource().then((SSE) => {
172
- sse = new SSE(getUrl(baseUrl, "live"));
173
- addEventListeners();
174
- });
175
- } else {
176
- addEventListeners();
177
- }
150
+ sse!.addEventListener("error", () => {
151
+ onError?.(new Error("server disconnected"));
152
+ });
153
+ };
178
154
 
179
- return {
180
- unsubscribe: () => {
181
- if (--liveCount === 0) sse?.close();
182
- },
183
- };
155
+ liveCount++;
156
+ if (sse === undefined) {
157
+ getEventSource().then((SSE) => {
158
+ sse = new SSE(getUrl(baseUrl, "live"));
159
+ addEventListeners();
160
+ });
184
161
  } else {
185
- return client.live(
186
- (db) => db.select().from(status),
187
- () => {
188
- queryFn(client.db).then(onData).catch(onError);
189
- },
190
- onError,
191
- );
162
+ addEventListeners();
192
163
  }
164
+
165
+ return {
166
+ unsubscribe: () => {
167
+ if (--liveCount === 0) sse?.close();
168
+ },
169
+ };
170
+ },
171
+ getStatus: async () => {
172
+ const response = await fetch(getUrl(baseUrl, "status"), {
173
+ method: "POST",
174
+ });
175
+
176
+ return response.json();
193
177
  },
194
178
  };
195
179
 
@@ -240,4 +224,17 @@ export {
240
224
  exceptAll,
241
225
  } from "drizzle-orm/pg-core";
242
226
 
243
- export { setDatabaseSchema } from "./setDatabaseSchema.js";
227
+ const Schema = Symbol.for("drizzle:Schema");
228
+
229
+ export const setDatabaseSchema = <T extends { [name: string]: unknown }>(
230
+ schema: T,
231
+ schemaName: string,
232
+ ): T => {
233
+ for (const table of Object.values(schema)) {
234
+ if (is(table, Table)) {
235
+ // @ts-ignore
236
+ table[Schema] = schemaName;
237
+ }
238
+ }
239
+ return schema;
240
+ };
@@ -1,16 +0,0 @@
1
- import { Table, is } from "drizzle-orm";
2
-
3
- const Schema = Symbol.for("drizzle:Schema");
4
-
5
- export const setDatabaseSchema = <T extends { [name: string]: unknown }>(
6
- schema: T,
7
- schemaName: string,
8
- ): T => {
9
- for (const table of Object.values(schema)) {
10
- if (is(table, Table)) {
11
- // @ts-ignore
12
- table[Schema] = schemaName;
13
- }
14
- }
15
- return schema;
16
- };