@jami-studio/core 0.92.19 → 0.92.21

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.
@@ -1,5 +1,17 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.92.21
4
+
5
+ ### Patch Changes
6
+
7
+ - 30edbbe: Keep Neon's poolQueryViaFetch HTTP path alive on Cloudflare Workers: attachNeonPoolErrorLogger's per-client 'connect' listener flips @neondatabase/serverless's hasFetchUnsupportedListeners flag, silently reverting every plain query to a WebSocket checkout — which, combined with the single-use clients workerd requires, churned a new WebSocket per query until the isolate hit its connection cap and pool.connect() hung forever (observed: authed action requests hanging after ~10 queries under wrangler pages dev). The logger now attaches only the pool-level 'error' listener on workerd; the per-client listener's purpose (preventing Node's uncaught-'error' process crash) doesn't apply there.
8
+
9
+ ## 0.92.20
10
+
11
+ ### Patch Changes
12
+
13
+ - 7a019a3: Complete the Neon-on-workerd fix: the better-auth Neon pool (third pool site) now also routes over stateless HTTP with single-use WebSocket clients on Cloudflare Workers, and buildResilientNeonPool gains an httpPerQuery mode so the Drizzle path actually goes through pool.query() (its manual connect()/client.query() checkout was bypassing poolQueryViaFetch and pinning queries to per-request WebSocket clients). Fixes worker hangs on the request following an authenticated write under wrangler pages dev.
14
+
3
15
  ## 0.92.19
4
16
 
5
17
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.92.19",
3
+ "version": "0.92.21",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/studio-jami/jami-studio#readme",
6
6
  "bugs": {
@@ -938,6 +938,17 @@ export function attachNeonPoolErrorLogger(
938
938
  );
939
939
  });
940
940
 
941
+ // On Cloudflare Workers, DO NOT attach the per-client 'connect' listener
942
+ // below. @neondatabase/serverless disables its poolQueryViaFetch HTTP path
943
+ // the moment ANY non-'error' listener is registered on the pool
944
+ // (hasFetchUnsupportedListeners) — silently reverting every plain query to
945
+ // a WebSocket checkout. Combined with the single-use clients workerd
946
+ // requires, that churns a new WebSocket per query until the isolate hits
947
+ // its connection cap and pool.connect() hangs forever. The listener's
948
+ // purpose (preventing Node's uncaught-'error' process crash) doesn't apply
949
+ // on workerd, where an unhandled emit can't kill a process.
950
+ if (isCloudflareRuntime()) return;
951
+
941
952
  // Attach a persistent 'error' listener to EVERY client for its whole lifetime.
942
953
  //
943
954
  // @neondatabase/serverless mirrors pg-pool, which only keeps its own idle
@@ -88,15 +88,28 @@ export function isSqlRead(sql: string): boolean {
88
88
  * connection the transaction needs. The pool-level error logger still fires
89
89
  * on idle-client drops inside transactions.
90
90
  */
91
- export function buildResilientNeonPool(pool: {
92
- connect(): Promise<any>;
93
- query(
94
- sql: string,
95
- args?: any[],
96
- ): Promise<{ rows: unknown[]; rowCount?: number }>;
97
- end(): Promise<void>;
98
- on(event: string, listener: (...args: any[]) => void): unknown;
99
- }): typeof pool {
91
+ export function buildResilientNeonPool(
92
+ pool: {
93
+ connect(): Promise<any>;
94
+ query(
95
+ sql: string,
96
+ args?: any[],
97
+ ): Promise<{ rows: unknown[]; rowCount?: number }>;
98
+ end(): Promise<void>;
99
+ on(event: string, listener: (...args: any[]) => void): unknown;
100
+ },
101
+ options?: {
102
+ /**
103
+ * Route plain queries through pool.query() instead of a manual
104
+ * connect()/client.query()/release() checkout. Required on Cloudflare
105
+ * Workers where neonConfig.poolQueryViaFetch routes pool.query() over
106
+ * Neon's stateless HTTP transport — the manual checkout would bypass
107
+ * that and pin queries to per-request WebSocket clients.
108
+ */
109
+ httpPerQuery?: boolean;
110
+ },
111
+ ): typeof pool {
112
+ const httpPerQuery = options?.httpPerQuery === true;
100
113
  // Preserve all original pool methods and properties; only override `connect`
101
114
  // and `query` at the Pool level (used by drizzle's neon-serverless adapter
102
115
  // when it calls pool.query() directly, e.g. outside a transaction).
@@ -110,6 +123,19 @@ export function buildResilientNeonPool(pool: {
110
123
  rows: unknown[];
111
124
  rowCount?: number;
112
125
  }> => {
126
+ if (httpPerQuery) {
127
+ // Stateless HTTP transport (poolQueryViaFetch): no connection
128
+ // checkout, no persistent socket — just bound the query itself.
129
+ return withDbTimeout(
130
+ "query",
131
+ () =>
132
+ pool.query(sql, args ?? []) as Promise<{
133
+ rows: unknown[];
134
+ rowCount?: number;
135
+ }>,
136
+ dbOpTimeoutMs(),
137
+ );
138
+ }
113
139
  // Bound the pool.connect() acquire — a frozen Neon WebSocket stalls here
114
140
  // before the query ever starts, so a query-level timeout alone won't help.
115
141
  let acquireTimedOut = false;
@@ -490,7 +516,9 @@ export function createGetDb<T extends Record<string, unknown>>(schema: T) {
490
516
  // same withDbTimeout + retryOnConnectionError protection as the raw
491
517
  // DbExec path in client.ts. Reads retry freely; writes only retry on
492
518
  // acquire-timeout (pre-send) errors to avoid double-execution.
493
- const pool = buildResilientNeonPool(rawPool);
519
+ const pool = buildResilientNeonPool(rawPool, {
520
+ httpPerQuery: cfWorker,
521
+ });
494
522
  _db = drizzle(pool, { schema });
495
523
  },
496
524
  );
@@ -48,6 +48,7 @@ import { getAppProductionUrl } from "./app-url.js";
48
48
  import { signupAttributionFromCookieHeader } from "./attribution.js";
49
49
  import { resolveAuthCookieNamespace } from "./cookie-namespace.js";
50
50
  import { getWorkspaceA2ADerivedSecret } from "./derived-secret.js";
51
+ import { isCloudflareRuntime } from "../shared/runtime.js";
51
52
  import {
52
53
  renderResetPasswordEmail,
53
54
  renderVerifySignupEmail,
@@ -1122,14 +1123,27 @@ async function buildDatabaseConfig(
1122
1123
  // opens a raw TCP connection on port 5432 which frequently times out on
1123
1124
  // Netlify Functions / Vercel / CF Workers when Neon's pooler is cold.
1124
1125
  if (isNeonUrl(url)) {
1125
- const { Pool } = await import("@neondatabase/serverless");
1126
+ const { Pool, neonConfig } = await import("@neondatabase/serverless");
1126
1127
  // Cap the auth pool the same way as the app pool. Better Auth runs a
1127
1128
  // session lookup on essentially every authenticated request, so an
1128
1129
  // un-capped pool here is a primary contributor to "Max client
1129
1130
  // connections reached" across concurrent serverless instances.
1131
+ //
1132
+ // Cloudflare Workers (workerd) forbids reusing I/O objects across
1133
+ // requests — a pooled WebSocket client created by one request and
1134
+ // handed to a later one hangs the worker ("Cannot perform I/O on
1135
+ // behalf of a different request"). Route plain queries over Neon's
1136
+ // stateless HTTP transport and cap WebSocket clients to a single use,
1137
+ // mirroring the app pools in db/client.ts and db/create-get-db.ts.
1138
+ const cfWorker = isCloudflareRuntime();
1139
+ if (cfWorker) {
1140
+ (neonConfig as { poolQueryViaFetch?: boolean }).poolQueryViaFetch =
1141
+ true;
1142
+ }
1130
1143
  _neonAuthPool = new Pool({
1131
1144
  connectionString: url,
1132
1145
  max: neonPoolMax(),
1146
+ ...(cfWorker ? { maxUses: 1 } : {}),
1133
1147
  });
1134
1148
  attachNeonPoolErrorLogger(_neonAuthPool, "db/neon-auth");
1135
1149
  const { drizzle } = await import("drizzle-orm/neon-serverless");
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- ok?: undefined;
30
29
  error: string;
30
+ ok?: undefined;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"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"}
package/dist/db/client.js CHANGED
@@ -797,6 +797,17 @@ export function attachNeonPoolErrorLogger(pool, label = "db/neon") {
797
797
  withEvents.on("error", (err) => {
798
798
  console.warn(`[${label}] pool error (will reconnect on next query):`, describeDbError(err));
799
799
  });
800
+ // On Cloudflare Workers, DO NOT attach the per-client 'connect' listener
801
+ // below. @neondatabase/serverless disables its poolQueryViaFetch HTTP path
802
+ // the moment ANY non-'error' listener is registered on the pool
803
+ // (hasFetchUnsupportedListeners) — silently reverting every plain query to
804
+ // a WebSocket checkout. Combined with the single-use clients workerd
805
+ // requires, that churns a new WebSocket per query until the isolate hits
806
+ // its connection cap and pool.connect() hangs forever. The listener's
807
+ // purpose (preventing Node's uncaught-'error' process crash) doesn't apply
808
+ // on workerd, where an unhandled emit can't kill a process.
809
+ if (isCloudflareRuntime())
810
+ return;
800
811
  // Attach a persistent 'error' listener to EVERY client for its whole lifetime.
801
812
  //
802
813
  // @neondatabase/serverless mirrors pg-pool, which only keeps its own idle