@ponder/client 0.9.0-next.9 → 0.9.1

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,11 @@
1
1
  import { SQLWrapper, QueryWithTypings } from 'drizzle-orm';
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';
2
+ export { and, asc, avg, avgDistinct, between, count, countDistinct, desc, eq, exists, gt, gte, ilike, inArray, isNotNull, isNull, like, lt, lte, max, min, ne, not, notBetween, notExists, notIlike, notInArray, notLike, or, relations, sql, sum, sumDistinct } from 'drizzle-orm';
3
3
  import { PgRemoteDatabase } from 'drizzle-orm/pg-proxy';
4
4
  export { alias, except, exceptAll, intersect, intersectAll, union, unionAll } from 'drizzle-orm/pg-core';
5
5
 
6
+ type Schema = {
7
+ [name: string]: unknown;
8
+ };
6
9
  type Prettify<T> = {
7
10
  [K in keyof T]: T[K];
8
11
  } & {};
@@ -19,14 +22,34 @@ type ClientDb<schema extends Schema = Schema> = Prettify<Omit<PgRemoteDatabase<s
19
22
  type Client<schema extends Schema = Schema> = {
20
23
  /** Query the database. */
21
24
  db: ClientDb<schema>;
22
- /** Subscribe to live updates. */
25
+ /**
26
+ * Subscribe to live updates.
27
+ *
28
+ * @param queryFn - The query to subscribe to.
29
+ * @param onData - The callback to call with each new query result
30
+ * @param onError - The callback to call when an error occurs.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { createClient } from "@ponder/client";
35
+ * import * as schema from "../ponder.schema";
36
+ *
37
+ * const client = createClient("https://.../sql", { schema });
38
+ *
39
+ * client.live(
40
+ * (db) => db.select().from(schema.account),
41
+ * (result) => console.log(result),
42
+ * (error) => console.error(error),
43
+ * );
44
+ * ```
45
+ */
23
46
  live: <result>(queryFn: (db: ClientDb<schema>) => Promise<result>, onData: (result: result) => void, onError?: (error: Error) => void) => {
24
47
  unsubscribe: () => void;
25
48
  };
26
49
  /** Get the status of all chains. */
27
50
  getStatus: () => Promise<Status>;
28
51
  };
29
- declare const compileQuery: (query: SQLWrapper | string) => QueryWithTypings;
52
+ declare const compileQuery: (query: SQLWrapper) => QueryWithTypings;
30
53
  /**
31
54
  * Create a client for querying Ponder apps.
32
55
  *
@@ -38,19 +61,11 @@ declare const compileQuery: (query: SQLWrapper | string) => QueryWithTypings;
38
61
  * import { createClient } from "@ponder/client";
39
62
  * import * as schema from "../ponder.schema";
40
63
  *
41
- * const client = createClient("https://...", { schema });
64
+ * const client = createClient("https://.../sql", { schema });
42
65
  * ```
43
66
  */
44
67
  declare const createClient: <schema extends Schema>(baseUrl: string, { schema }: {
45
68
  schema: schema;
46
69
  }) => Client<schema>;
47
70
 
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 };
71
+ export { type Client, type Status, compileQuery, createClient };
package/dist/index.js CHANGED
@@ -1,12 +1,9 @@
1
1
  // src/index.ts
2
- import {
3
- Table,
4
- is,
5
- sql
6
- } from "drizzle-orm";
7
2
  import { drizzle } from "drizzle-orm/pg-proxy";
3
+ import { EventSource } from "eventsource";
4
+ import superjson from "superjson";
8
5
  import {
9
- sql as sql2,
6
+ sql,
10
7
  eq,
11
8
  gt,
12
9
  gte,
@@ -22,6 +19,8 @@ import {
22
19
  between,
23
20
  notBetween,
24
21
  like,
22
+ notLike,
23
+ ilike,
25
24
  notIlike,
26
25
  not,
27
26
  asc,
@@ -47,23 +46,11 @@ import {
47
46
  except,
48
47
  exceptAll
49
48
  } from "drizzle-orm/pg-core";
50
- var getEventSource = async () => {
51
- let SSE;
52
- if (typeof window === "undefined") {
53
- const undici = await import(
54
- /* webpackIgnore: true */
55
- "undici"
56
- );
57
- SSE = undici.EventSource;
58
- } else {
59
- SSE = EventSource;
60
- }
61
- return SSE;
62
- };
63
49
  var getUrl = (baseUrl, method, query) => {
64
- const url = new URL(`${baseUrl}/client/${method}`);
50
+ const url = new URL(baseUrl);
51
+ url.pathname = `${url.pathname}/${method}`;
65
52
  if (query) {
66
- url.searchParams.set("sql", JSON.stringify(query));
53
+ url.searchParams.set("sql", superjson.stringify(query));
67
54
  }
68
55
  return url;
69
56
  };
@@ -72,16 +59,15 @@ var noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {
72
59
  });
73
60
  var dialect = noopDatabase.dialect;
74
61
  var compileQuery = (query) => {
75
- const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL();
76
- return dialect.sqlToQuery(sequel);
62
+ return dialect.sqlToQuery(query.getSQL());
77
63
  };
78
64
  var createClient = (baseUrl, { schema }) => {
79
65
  let sse;
80
66
  let liveCount = 0;
81
67
  const client = {
82
68
  db: drizzle(
83
- async (sql3, params, _, typings) => {
84
- const builtQuery = { sql: sql3, params, typings };
69
+ async (sql2, params, _, typings) => {
70
+ const builtQuery = { sql: sql2, params, typings };
85
71
  const response = await fetch(getUrl(baseUrl, "db", builtQuery), {
86
72
  method: "POST"
87
73
  });
@@ -99,34 +85,27 @@ var createClient = (baseUrl, { schema }) => {
99
85
  { schema, casing: "snake_case" }
100
86
  ),
101
87
  live: (queryFn, onData, onError) => {
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);
111
- }
112
- });
113
- sse.addEventListener("error", () => {
114
- onError?.(new Error("server disconnected"));
115
- });
116
- };
117
- liveCount++;
118
88
  if (sse === void 0) {
119
- getEventSource().then((SSE) => {
120
- sse = new SSE(getUrl(baseUrl, "live"));
121
- addEventListeners();
122
- });
123
- } else {
124
- addEventListeners();
89
+ sse = new EventSource(getUrl(baseUrl, "live"));
125
90
  }
91
+ const onDataListener = (_event) => {
92
+ queryFn(client.db).then(onData).catch(onError);
93
+ };
94
+ const onErrorListener = (_event) => {
95
+ onError?.(new Error("server disconnected"));
96
+ };
97
+ sse?.addEventListener("message", onDataListener);
98
+ sse?.addEventListener("error", onErrorListener);
99
+ liveCount = liveCount + 1;
126
100
  return {
127
101
  unsubscribe: () => {
128
- if (--liveCount === 0)
102
+ sse?.removeEventListener("message", onDataListener);
103
+ sse?.removeEventListener("error", onErrorListener);
104
+ liveCount = liveCount - 1;
105
+ if (liveCount === 0) {
129
106
  sse?.close();
107
+ sse = void 0;
108
+ }
130
109
  }
131
110
  };
132
111
  },
@@ -139,15 +118,6 @@ var createClient = (baseUrl, { schema }) => {
139
118
  };
140
119
  return client;
141
120
  };
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
- };
151
121
  export {
152
122
  alias,
153
123
  and,
@@ -166,6 +136,7 @@ export {
166
136
  exists,
167
137
  gt,
168
138
  gte,
139
+ ilike,
169
140
  inArray,
170
141
  intersect,
171
142
  intersectAll,
@@ -182,10 +153,10 @@ export {
182
153
  notExists,
183
154
  notIlike,
184
155
  notInArray,
156
+ notLike,
185
157
  or,
186
158
  relations,
187
- setDatabaseSchema,
188
- sql2 as sql,
159
+ sql,
189
160
  sum,
190
161
  sumDistinct,
191
162
  union,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { QueryWithTypings, SQLWrapper } from \"drizzle-orm\";\nimport type { PgDialect } from \"drizzle-orm/pg-core\";\nimport { type PgRemoteDatabase, drizzle } from \"drizzle-orm/pg-proxy\";\nimport { EventSource } from \"eventsource\";\nimport superjson from \"superjson\";\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 /**\n * Subscribe to live updates.\n *\n * @param queryFn - The query to subscribe to.\n * @param onData - The callback to call with each new query result\n * @param onError - The callback to call when an error occurs.\n *\n * @example\n * ```ts\n * import { createClient } from \"@ponder/client\";\n * import * as schema from \"../ponder.schema\";\n *\n * const client = createClient(\"https://.../sql\", { schema });\n *\n * client.live(\n * (db) => db.select().from(schema.account),\n * (result) => console.log(result),\n * (error) => console.error(error),\n * );\n * ```\n */\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);\n url.pathname = `${url.pathname}/${method}`;\n if (query) {\n url.searchParams.set(\"sql\", superjson.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) => {\n return dialect.sqlToQuery(query.getSQL());\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://.../sql\", { 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 if (sse === undefined) {\n sse = new EventSource(getUrl(baseUrl, \"live\"));\n }\n\n const onDataListener = (_event: MessageEvent) => {\n queryFn(client.db).then(onData).catch(onError);\n };\n\n const onErrorListener = (_event: MessageEvent) => {\n onError?.(new Error(\"server disconnected\"));\n };\n\n sse?.addEventListener(\"message\", onDataListener);\n sse?.addEventListener(\"error\", onErrorListener);\n liveCount = liveCount + 1;\n\n return {\n unsubscribe: () => {\n sse?.removeEventListener(\"message\", onDataListener);\n sse?.removeEventListener(\"error\", onErrorListener);\n liveCount = liveCount - 1;\n if (liveCount === 0) {\n sse?.close();\n sse = undefined;\n }\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 notLike,\n ilike,\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"],"mappings":";AAEA,SAAgC,eAAe;AAC/C,SAAS,mBAAmB;AAC5B,OAAO,eAAe;AA2KtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAzJP,IAAM,SAAS,CACb,SACA,QACA,UACG;AACH,QAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,MAAI,WAAW,GAAG,IAAI,QAAQ,IAAI,MAAM;AACxC,MAAI,OAAO;AACT,QAAI,aAAa,IAAI,OAAO,UAAU,UAAU,KAAK,CAAC;AAAA,EACxD;AACA,SAAO;AACT;AAEA,IAAM,eAAe,QAAQ,MAAM,QAAQ,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG;AAAA,EAChE,QAAQ;AACV,CAAC;AAGD,IAAM,UAAqB,aAAa;AAEjC,IAAM,eAAe,CAAC,UAAsB;AACjD,SAAO,QAAQ,WAAW,MAAM,OAAO,CAAC;AAC1C;AAgBO,IAAM,eAAe,CAC1B,SACA,EAAE,OAAO,MACU;AACnB,MAAI;AACJ,MAAI,YAAY;AAEhB,QAAM,SAAyB;AAAA,IAC7B,IAAI;AAAA,MACF,OAAOA,MAAK,QAAQ,GAAG,YAAY;AACjC,cAAM,aAAa,EAAE,KAAAA,MAAK,QAAQ,QAAQ;AAC1C,cAAM,WAAW,MAAM,MAAM,OAAO,SAAS,MAAM,UAAU,GAAG;AAAA,UAC9D,QAAQ;AAAA,QACV,CAAC;AAED,YAAI,SAAS,OAAO,OAAO;AACzB,gBAAM,QAAQ,IAAI,MAAM,MAAM,SAAS,KAAK,CAAC;AAC7C,gBAAM,QAAQ;AACd,gBAAM;AAAA,QACR;AAEA,cAAM,SAAS,MAAM,SAAS,KAAK;AAEnC,eAAO;AAAA,UACL,GAAG;AAAA,UACH,MAAM,OAAO,KAAK,IAAI,CAAC,QAAgB,OAAO,OAAO,GAAG,CAAC;AAAA,QAC3D;AAAA,MACF;AAAA,MACA,EAAE,QAAQ,QAAQ,aAAa;AAAA,IACjC;AAAA,IACA,MAAM,CAAC,SAAS,QAAQ,YAAY;AAClC,UAAI,QAAQ,QAAW;AACrB,cAAM,IAAI,YAAY,OAAO,SAAS,MAAM,CAAC;AAAA,MAC/C;AAEA,YAAM,iBAAiB,CAAC,WAAyB;AAC/C,gBAAQ,OAAO,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,OAAO;AAAA,MAC/C;AAEA,YAAM,kBAAkB,CAAC,WAAyB;AAChD,kBAAU,IAAI,MAAM,qBAAqB,CAAC;AAAA,MAC5C;AAEA,WAAK,iBAAiB,WAAW,cAAc;AAC/C,WAAK,iBAAiB,SAAS,eAAe;AAC9C,kBAAY,YAAY;AAExB,aAAO;AAAA,QACL,aAAa,MAAM;AACjB,eAAK,oBAAoB,WAAW,cAAc;AAClD,eAAK,oBAAoB,SAAS,eAAe;AACjD,sBAAY,YAAY;AACxB,cAAI,cAAc,GAAG;AACnB,iBAAK,MAAM;AACX,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW,YAAY;AACrB,YAAM,WAAW,MAAM,MAAM,OAAO,SAAS,QAAQ,GAAG;AAAA,QACtD,QAAQ;AAAA,MACV,CAAC;AAED,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AACT;","names":["sql"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponder/client",
3
- "version": "0.9.0-next.9",
3
+ "version": "0.9.1",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -26,9 +26,6 @@
26
26
  "import": "./dist/index.js"
27
27
  }
28
28
  },
29
- "browser": {
30
- "undici": false
31
- },
32
29
  "peerDependencies": {
33
30
  "typescript": ">=5.0.4"
34
31
  },
@@ -39,7 +36,8 @@
39
36
  },
40
37
  "dependencies": {
41
38
  "drizzle-orm": "0.36.4",
42
- "undici": "^7.2.0"
39
+ "eventsource": "^3.0.5",
40
+ "superjson": "^2.2.2"
43
41
  },
44
42
  "devDependencies": {
45
43
  "tsup": "^8.0.1"
package/src/index.ts CHANGED
@@ -1,25 +1,8 @@
1
- import {
2
- type QueryWithTypings,
3
- type SQLWrapper,
4
- Table,
5
- is,
6
- sql,
7
- } from "drizzle-orm";
1
+ import type { QueryWithTypings, SQLWrapper } from "drizzle-orm";
8
2
  import type { PgDialect } from "drizzle-orm/pg-core";
9
3
  import { type PgRemoteDatabase, drizzle } from "drizzle-orm/pg-proxy";
10
-
11
- const getEventSource = async () => {
12
- let SSE: typeof EventSource;
13
- if (typeof window === "undefined") {
14
- const undici = await import(/* webpackIgnore: true */ "undici");
15
- // @ts-ignore
16
- SSE = undici.EventSource;
17
- } else {
18
- SSE = EventSource;
19
- }
20
-
21
- return SSE;
22
- };
4
+ import { EventSource } from "eventsource";
5
+ import superjson from "superjson";
23
6
 
24
7
  type Schema = { [name: string]: unknown };
25
8
 
@@ -49,7 +32,27 @@ type ClientDb<schema extends Schema = Schema> = Prettify<
49
32
  export type Client<schema extends Schema = Schema> = {
50
33
  /** Query the database. */
51
34
  db: ClientDb<schema>;
52
- /** Subscribe to live updates. */
35
+ /**
36
+ * Subscribe to live updates.
37
+ *
38
+ * @param queryFn - The query to subscribe to.
39
+ * @param onData - The callback to call with each new query result
40
+ * @param onError - The callback to call when an error occurs.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { createClient } from "@ponder/client";
45
+ * import * as schema from "../ponder.schema";
46
+ *
47
+ * const client = createClient("https://.../sql", { schema });
48
+ *
49
+ * client.live(
50
+ * (db) => db.select().from(schema.account),
51
+ * (result) => console.log(result),
52
+ * (error) => console.error(error),
53
+ * );
54
+ * ```
55
+ */
53
56
  live: <result>(
54
57
  queryFn: (db: ClientDb<schema>) => Promise<result>,
55
58
  onData: (result: result) => void,
@@ -66,9 +69,10 @@ const getUrl = (
66
69
  method: "live" | "db" | "status",
67
70
  query?: QueryWithTypings,
68
71
  ) => {
69
- const url = new URL(`${baseUrl}/client/${method}`);
72
+ const url = new URL(baseUrl);
73
+ url.pathname = `${url.pathname}/${method}`;
70
74
  if (query) {
71
- url.searchParams.set("sql", JSON.stringify(query));
75
+ url.searchParams.set("sql", superjson.stringify(query));
72
76
  }
73
77
  return url;
74
78
  };
@@ -80,9 +84,8 @@ const noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {
80
84
  // @ts-ignore
81
85
  const dialect: PgDialect = noopDatabase.dialect;
82
86
 
83
- export const compileQuery = (query: SQLWrapper | string) => {
84
- const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL();
85
- return dialect.sqlToQuery(sequel);
87
+ export const compileQuery = (query: SQLWrapper) => {
88
+ return dialect.sqlToQuery(query.getSQL());
86
89
  };
87
90
 
88
91
  /**
@@ -96,7 +99,7 @@ export const compileQuery = (query: SQLWrapper | string) => {
96
99
  * import { createClient } from "@ponder/client";
97
100
  * import * as schema from "../ponder.schema";
98
101
  *
99
- * const client = createClient("https://...", { schema });
102
+ * const client = createClient("https://.../sql", { schema });
100
103
  * ```
101
104
  */
102
105
  export const createClient = <schema extends Schema>(
@@ -130,41 +133,31 @@ export const createClient = <schema extends Schema>(
130
133
  { schema, casing: "snake_case" },
131
134
  ),
132
135
  live: (queryFn, onData, onError) => {
133
- // https://github.com/drizzle-team/drizzle-orm/blob/04c91434c7ac10aeb2923efd1d19a7ebf10ea9d4/drizzle-orm/src/pg-core/db.ts#L602-L621
134
-
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
- });
136
+ if (sse === undefined) {
137
+ sse = new EventSource(getUrl(baseUrl, "live"));
138
+ }
149
139
 
150
- sse!.addEventListener("error", () => {
151
- onError?.(new Error("server disconnected"));
152
- });
140
+ const onDataListener = (_event: MessageEvent) => {
141
+ queryFn(client.db).then(onData).catch(onError);
153
142
  };
154
143
 
155
- liveCount++;
156
- if (sse === undefined) {
157
- getEventSource().then((SSE) => {
158
- sse = new SSE(getUrl(baseUrl, "live"));
159
- addEventListeners();
160
- });
161
- } else {
162
- addEventListeners();
163
- }
144
+ const onErrorListener = (_event: MessageEvent) => {
145
+ onError?.(new Error("server disconnected"));
146
+ };
147
+
148
+ sse?.addEventListener("message", onDataListener);
149
+ sse?.addEventListener("error", onErrorListener);
150
+ liveCount = liveCount + 1;
164
151
 
165
152
  return {
166
153
  unsubscribe: () => {
167
- if (--liveCount === 0) sse?.close();
154
+ sse?.removeEventListener("message", onDataListener);
155
+ sse?.removeEventListener("error", onErrorListener);
156
+ liveCount = liveCount - 1;
157
+ if (liveCount === 0) {
158
+ sse?.close();
159
+ sse = undefined;
160
+ }
168
161
  },
169
162
  };
170
163
  },
@@ -197,6 +190,8 @@ export {
197
190
  between,
198
191
  notBetween,
199
192
  like,
193
+ notLike,
194
+ ilike,
200
195
  notIlike,
201
196
  not,
202
197
  asc,
@@ -223,18 +218,3 @@ export {
223
218
  except,
224
219
  exceptAll,
225
220
  } from "drizzle-orm/pg-core";
226
-
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
- };