postgresai 0.14.0-dev.73 → 0.14.0-dev.74

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.
@@ -13064,7 +13064,7 @@ var {
13064
13064
  // package.json
13065
13065
  var package_default = {
13066
13066
  name: "postgresai",
13067
- version: "0.14.0-dev.73",
13067
+ version: "0.14.0-dev.74",
13068
13068
  description: "postgres_ai CLI",
13069
13069
  license: "Apache-2.0",
13070
13070
  private: false,
@@ -15887,7 +15887,7 @@ var Result = import_lib.default.Result;
15887
15887
  var TypeOverrides = import_lib.default.TypeOverrides;
15888
15888
  var defaults = import_lib.default.defaults;
15889
15889
  // package.json
15890
- var version = "0.14.0-dev.73";
15890
+ var version = "0.14.0-dev.74";
15891
15891
  var package_default2 = {
15892
15892
  name: "postgresai",
15893
15893
  version,
@@ -25314,6 +25314,10 @@ class SupabaseClient {
25314
25314
  }
25315
25315
  async function fetchPoolerDatabaseUrl(config2, username) {
25316
25316
  const url = `${SUPABASE_API_BASE}/v1/projects/${encodeURIComponent(config2.projectRef)}/config/database/pooler`;
25317
+ const effectiveUsername = (() => {
25318
+ const suffix = `.${config2.projectRef}`;
25319
+ return username.endsWith(suffix) ? username : `${username}${suffix}`;
25320
+ })();
25317
25321
  try {
25318
25322
  const response = await fetch(url, {
25319
25323
  method: "GET",
@@ -25328,13 +25332,13 @@ async function fetchPoolerDatabaseUrl(config2, username) {
25328
25332
  if (Array.isArray(data) && data.length > 0) {
25329
25333
  const pooler = data[0];
25330
25334
  if (pooler.db_host && pooler.db_port && pooler.db_name) {
25331
- return `postgresql://${username}@${pooler.db_host}:${pooler.db_port}/${pooler.db_name}`;
25335
+ return `postgresql://${effectiveUsername}@${pooler.db_host}:${pooler.db_port}/${pooler.db_name}`;
25332
25336
  }
25333
25337
  if (typeof pooler.connection_string === "string") {
25334
25338
  try {
25335
25339
  const connUrl = new URL(pooler.connection_string);
25336
25340
  const portPart = connUrl.port ? `:${connUrl.port}` : "";
25337
- return `postgresql://${username}@${connUrl.hostname}${portPart}${connUrl.pathname}`;
25341
+ return `postgresql://${effectiveUsername}@${connUrl.hostname}${portPart}${connUrl.pathname}`;
25338
25342
  } catch {
25339
25343
  return null;
25340
25344
  }
@@ -1,6 +1,6 @@
1
1
  // AUTO-GENERATED FILE - DO NOT EDIT
2
2
  // Generated from config/pgwatch-prometheus/metrics.yml by scripts/embed-metrics.ts
3
- // Generated at: 2026-01-09T16:03:14.462Z
3
+ // Generated at: 2026-01-09T18:10:39.847Z
4
4
 
5
5
  /**
6
6
  * Metric definition from metrics.yml
package/lib/supabase.ts CHANGED
@@ -347,6 +347,14 @@ export async function fetchPoolerDatabaseUrl(
347
347
  ): Promise<string | null> {
348
348
  const url = `${SUPABASE_API_BASE}/v1/projects/${encodeURIComponent(config.projectRef)}/config/database/pooler`;
349
349
 
350
+ // For Supabase pooler connections, the username must include the project ref:
351
+ // <user>.<project_ref>
352
+ // Example:
353
+ // postgresql://postgres_ai_mon.xhaqmsvczjkkvkgdyast@aws-1-eu-west-1.pooler.supabase.com:6543/postgres
354
+ const effectiveUsername = (() => {
355
+ const suffix = `.${config.projectRef}`;
356
+ return username.endsWith(suffix) ? username : `${username}${suffix}`;
357
+ })();
350
358
  try {
351
359
  const response = await fetch(url, {
352
360
  method: "GET",
@@ -367,7 +375,7 @@ export async function fetchPoolerDatabaseUrl(
367
375
  const pooler = data[0];
368
376
  // Build URL from components if available
369
377
  if (pooler.db_host && pooler.db_port && pooler.db_name) {
370
- return `postgresql://${username}@${pooler.db_host}:${pooler.db_port}/${pooler.db_name}`;
378
+ return `postgresql://${effectiveUsername}@${pooler.db_host}:${pooler.db_port}/${pooler.db_name}`;
371
379
  }
372
380
  // Fallback: try to extract from connection_string if present
373
381
  if (typeof pooler.connection_string === "string") {
@@ -375,7 +383,7 @@ export async function fetchPoolerDatabaseUrl(
375
383
  const connUrl = new URL(pooler.connection_string);
376
384
  // Use provided username; handle empty port for default ports (e.g., 5432)
377
385
  const portPart = connUrl.port ? `:${connUrl.port}` : "";
378
- return `postgresql://${username}@${connUrl.hostname}${portPart}${connUrl.pathname}`;
386
+ return `postgresql://${effectiveUsername}@${connUrl.hostname}${portPart}${connUrl.pathname}`;
379
387
  } catch {
380
388
  return null;
381
389
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postgresai",
3
- "version": "0.14.0-dev.73",
3
+ "version": "0.14.0-dev.74",
4
4
  "description": "postgres_ai CLI",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,
@@ -2,6 +2,7 @@ import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test";
2
2
  import {
3
3
  resolveSupabaseConfig,
4
4
  extractProjectRefFromUrl,
5
+ fetchPoolerDatabaseUrl,
5
6
  SupabaseClient,
6
7
  applyInitPlanViaSupabase,
7
8
  verifyInitSetupViaSupabase,
@@ -137,6 +138,64 @@ describe("Supabase module", () => {
137
138
  });
138
139
  });
139
140
 
141
+ describe("fetchPoolerDatabaseUrl", () => {
142
+ const originalFetch = globalThis.fetch;
143
+
144
+ afterEach(() => {
145
+ globalThis.fetch = originalFetch;
146
+ });
147
+
148
+ test("returns pooler db url with username including project ref (db_host/db_port/db_name response)", async () => {
149
+ globalThis.fetch = mock(() =>
150
+ Promise.resolve(
151
+ new Response(
152
+ JSON.stringify([
153
+ {
154
+ db_host: "aws-1-eu-west-1.pooler.supabase.com",
155
+ db_port: 6543,
156
+ db_name: "postgres",
157
+ },
158
+ ]),
159
+ { status: 200 }
160
+ )
161
+ )
162
+ ) as unknown as typeof fetch;
163
+
164
+ const url = await fetchPoolerDatabaseUrl(
165
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
166
+ "postgres_ai_mon"
167
+ );
168
+ expect(url).toBe(
169
+ "postgresql://postgres_ai_mon.xhaqmsvczjkkvkgdyast@aws-1-eu-west-1.pooler.supabase.com:6543/postgres"
170
+ );
171
+ });
172
+
173
+ test("does not double-append project ref if username already has it", async () => {
174
+ globalThis.fetch = mock(() =>
175
+ Promise.resolve(
176
+ new Response(
177
+ JSON.stringify([
178
+ {
179
+ db_host: "aws-1-eu-west-1.pooler.supabase.com",
180
+ db_port: 6543,
181
+ db_name: "postgres",
182
+ },
183
+ ]),
184
+ { status: 200 }
185
+ )
186
+ )
187
+ ) as unknown as typeof fetch;
188
+
189
+ const url = await fetchPoolerDatabaseUrl(
190
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
191
+ "postgres_ai_mon.xhaqmsvczjkkvkgdyast"
192
+ );
193
+ expect(url).toBe(
194
+ "postgresql://postgres_ai_mon.xhaqmsvczjkkvkgdyast@aws-1-eu-west-1.pooler.supabase.com:6543/postgres"
195
+ );
196
+ });
197
+ });
198
+
140
199
  describe("SupabaseClient", () => {
141
200
  test("throws error when project ref is empty", () => {
142
201
  expect(() => new SupabaseClient({ projectRef: "", accessToken: "token" })).toThrow(