postgresai 0.14.0-dev.82 → 0.14.0-dev.84

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.
@@ -96,21 +96,21 @@ describe("MCP Server", () => {
96
96
  });
97
97
 
98
98
  // Mock fetch to verify API key is used
99
- let capturedHeaders: HeadersInit | undefined;
99
+ let capturedHeaders: Record<string, string> | undefined;
100
100
  globalThis.fetch = mock((url: string, options?: RequestInit) => {
101
- capturedHeaders = options?.headers;
101
+ capturedHeaders = options?.headers as Record<string, string> | undefined;
102
102
  return Promise.resolve(
103
103
  new Response(JSON.stringify([]), {
104
104
  status: 200,
105
105
  headers: { "Content-Type": "application/json" },
106
106
  })
107
107
  );
108
- });
108
+ }) as unknown as typeof fetch;
109
109
 
110
110
  await handleToolCall(createRequest("list_issues"), { apiKey: "test-api-key" });
111
111
 
112
112
  expect(capturedHeaders).toBeDefined();
113
- expect((capturedHeaders as Record<string, string>)["access-token"]).toBe("test-api-key");
113
+ expect(capturedHeaders!["access-token"]).toBe("test-api-key");
114
114
 
115
115
  readConfigSpy.mockRestore();
116
116
  });
@@ -123,21 +123,21 @@ describe("MCP Server", () => {
123
123
  defaultProject: null,
124
124
  });
125
125
 
126
- let capturedHeaders: HeadersInit | undefined;
126
+ let capturedHeaders: Record<string, string> | undefined;
127
127
  globalThis.fetch = mock((url: string, options?: RequestInit) => {
128
- capturedHeaders = options?.headers;
128
+ capturedHeaders = options?.headers as Record<string, string> | undefined;
129
129
  return Promise.resolve(
130
130
  new Response(JSON.stringify([]), {
131
131
  status: 200,
132
132
  headers: { "Content-Type": "application/json" },
133
133
  })
134
134
  );
135
- });
135
+ }) as unknown as typeof fetch;
136
136
 
137
137
  await handleToolCall(createRequest("list_issues"));
138
138
 
139
139
  expect(capturedHeaders).toBeDefined();
140
- expect((capturedHeaders as Record<string, string>)["access-token"]).toBe("config-api-key");
140
+ expect(capturedHeaders!["access-token"]).toBe("config-api-key");
141
141
 
142
142
  readConfigSpy.mockRestore();
143
143
  });
@@ -152,21 +152,21 @@ describe("MCP Server", () => {
152
152
  defaultProject: null,
153
153
  });
154
154
 
155
- let capturedHeaders: HeadersInit | undefined;
155
+ let capturedHeaders: Record<string, string> | undefined;
156
156
  globalThis.fetch = mock((url: string, options?: RequestInit) => {
157
- capturedHeaders = options?.headers;
157
+ capturedHeaders = options?.headers as Record<string, string> | undefined;
158
158
  return Promise.resolve(
159
159
  new Response(JSON.stringify([]), {
160
160
  status: 200,
161
161
  headers: { "Content-Type": "application/json" },
162
162
  })
163
163
  );
164
- });
164
+ }) as unknown as typeof fetch;
165
165
 
166
166
  await handleToolCall(createRequest("list_issues"));
167
167
 
168
168
  expect(capturedHeaders).toBeDefined();
169
- expect((capturedHeaders as Record<string, string>)["access-token"]).toBe("env-api-key");
169
+ expect(capturedHeaders!["access-token"]).toBe("env-api-key");
170
170
 
171
171
  readConfigSpy.mockRestore();
172
172
  });
@@ -193,7 +193,7 @@ describe("MCP Server", () => {
193
193
  headers: { "Content-Type": "application/json" },
194
194
  })
195
195
  )
196
- );
196
+ ) as unknown as typeof fetch;
197
197
 
198
198
  const response = await handleToolCall(createRequest("list_issues"));
199
199
 
@@ -220,7 +220,7 @@ describe("MCP Server", () => {
220
220
  headers: { "Content-Type": "application/json" },
221
221
  })
222
222
  )
223
- );
223
+ ) as unknown as typeof fetch;
224
224
 
225
225
  const response = await handleToolCall(createRequest("list_issues"));
226
226
 
@@ -280,7 +280,7 @@ describe("MCP Server", () => {
280
280
  headers: { "Content-Type": "application/json" },
281
281
  })
282
282
  )
283
- );
283
+ ) as unknown as typeof fetch;
284
284
 
285
285
  const response = await handleToolCall(createRequest("view_issue", { issue_id: "nonexistent-id" }));
286
286
 
@@ -319,7 +319,7 @@ describe("MCP Server", () => {
319
319
  headers: { "Content-Type": "application/json" },
320
320
  })
321
321
  );
322
- });
322
+ }) as unknown as typeof fetch;
323
323
 
324
324
  const response = await handleToolCall(createRequest("view_issue", { issue_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" }));
325
325
 
@@ -386,7 +386,7 @@ describe("MCP Server", () => {
386
386
  headers: { "Content-Type": "application/json" },
387
387
  })
388
388
  );
389
- });
389
+ }) as unknown as typeof fetch;
390
390
 
391
391
  await handleToolCall(
392
392
  createRequest("post_issue_comment", {
@@ -419,7 +419,7 @@ describe("MCP Server", () => {
419
419
  headers: { "Content-Type": "application/json" },
420
420
  })
421
421
  );
422
- });
422
+ }) as unknown as typeof fetch;
423
423
 
424
424
  const response = await handleToolCall(
425
425
  createRequest("post_issue_comment", {
@@ -504,7 +504,7 @@ describe("MCP Server", () => {
504
504
  headers: { "Content-Type": "application/json" },
505
505
  })
506
506
  );
507
- });
507
+ }) as unknown as typeof fetch;
508
508
 
509
509
  await handleToolCall(createRequest("create_issue", { title: "Test Issue" }));
510
510
 
@@ -532,7 +532,7 @@ describe("MCP Server", () => {
532
532
  headers: { "Content-Type": "application/json" },
533
533
  })
534
534
  );
535
- });
535
+ }) as unknown as typeof fetch;
536
536
 
537
537
  await handleToolCall(
538
538
  createRequest("create_issue", {
@@ -566,7 +566,7 @@ describe("MCP Server", () => {
566
566
  headers: { "Content-Type": "application/json" },
567
567
  })
568
568
  );
569
- });
569
+ }) as unknown as typeof fetch;
570
570
 
571
571
  const response = await handleToolCall(
572
572
  createRequest("create_issue", {
@@ -679,7 +679,7 @@ describe("MCP Server", () => {
679
679
  headers: { "Content-Type": "application/json" },
680
680
  })
681
681
  );
682
- });
682
+ }) as unknown as typeof fetch;
683
683
 
684
684
  await handleToolCall(
685
685
  createRequest("update_issue", {
@@ -712,7 +712,7 @@ describe("MCP Server", () => {
712
712
  headers: { "Content-Type": "application/json" },
713
713
  })
714
714
  )
715
- );
715
+ ) as unknown as typeof fetch;
716
716
 
717
717
  const response = await handleToolCall(
718
718
  createRequest("update_issue", { issue_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", title: "New Title" })
@@ -740,7 +740,7 @@ describe("MCP Server", () => {
740
740
  headers: { "Content-Type": "application/json" },
741
741
  })
742
742
  );
743
- });
743
+ }) as unknown as typeof fetch;
744
744
 
745
745
  const response = await handleToolCall(
746
746
  createRequest("update_issue", { issue_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", status: 1 })
@@ -771,7 +771,7 @@ describe("MCP Server", () => {
771
771
  headers: { "Content-Type": "application/json" },
772
772
  })
773
773
  );
774
- });
774
+ }) as unknown as typeof fetch;
775
775
 
776
776
  const response = await handleToolCall(
777
777
  createRequest("update_issue", { issue_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", labels: ["new-label"] })
@@ -802,7 +802,7 @@ describe("MCP Server", () => {
802
802
  headers: { "Content-Type": "application/json" },
803
803
  })
804
804
  );
805
- });
805
+ }) as unknown as typeof fetch;
806
806
 
807
807
  const response = await handleToolCall(
808
808
  createRequest("update_issue", { issue_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", status: 0 })
@@ -871,7 +871,7 @@ describe("MCP Server", () => {
871
871
  headers: { "Content-Type": "application/json" },
872
872
  })
873
873
  );
874
- });
874
+ }) as unknown as typeof fetch;
875
875
 
876
876
  await handleToolCall(
877
877
  createRequest("update_issue_comment", {
@@ -902,7 +902,7 @@ describe("MCP Server", () => {
902
902
  headers: { "Content-Type": "application/json" },
903
903
  })
904
904
  )
905
- );
905
+ ) as unknown as typeof fetch;
906
906
 
907
907
  const response = await handleToolCall(
908
908
  createRequest("update_issue_comment", {
@@ -999,7 +999,7 @@ describe("MCP Server", () => {
999
999
  headers: { "Content-Type": "application/json" },
1000
1000
  })
1001
1001
  )
1002
- );
1002
+ ) as unknown as typeof fetch;
1003
1003
 
1004
1004
  const response = await handleToolCall(createRequest("view_action_item", { action_item_id: "00000000-0000-0000-0000-000000000000" }));
1005
1005
 
@@ -1036,7 +1036,7 @@ describe("MCP Server", () => {
1036
1036
  headers: { "Content-Type": "application/json" },
1037
1037
  })
1038
1038
  )
1039
- );
1039
+ ) as unknown as typeof fetch;
1040
1040
 
1041
1041
  const response = await handleToolCall(createRequest("view_action_item", { action_item_id: "11111111-1111-1111-1111-111111111111" }));
1042
1042
 
@@ -1072,7 +1072,7 @@ describe("MCP Server", () => {
1072
1072
  headers: { "Content-Type": "application/json" },
1073
1073
  })
1074
1074
  );
1075
- });
1075
+ }) as unknown as typeof fetch;
1076
1076
 
1077
1077
  const response = await handleToolCall(createRequest("view_action_item", { action_item_ids: ["11111111-1111-1111-1111-111111111111", "22222222-2222-2222-2222-222222222222"] }));
1078
1078
 
@@ -1141,7 +1141,7 @@ describe("MCP Server", () => {
1141
1141
  headers: { "Content-Type": "application/json" },
1142
1142
  })
1143
1143
  )
1144
- );
1144
+ ) as unknown as typeof fetch;
1145
1145
 
1146
1146
  const response = await handleToolCall(createRequest("list_action_items", { issue_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" }));
1147
1147
 
@@ -1208,7 +1208,7 @@ describe("MCP Server", () => {
1208
1208
  headers: { "Content-Type": "application/json" },
1209
1209
  })
1210
1210
  );
1211
- });
1211
+ }) as unknown as typeof fetch;
1212
1212
 
1213
1213
  const response = await handleToolCall(
1214
1214
  createRequest("create_action_item", {
@@ -1243,7 +1243,7 @@ describe("MCP Server", () => {
1243
1243
  headers: { "Content-Type": "application/json" },
1244
1244
  })
1245
1245
  );
1246
- });
1246
+ }) as unknown as typeof fetch;
1247
1247
 
1248
1248
  const response = await handleToolCall(
1249
1249
  createRequest("create_action_item", {
@@ -1284,7 +1284,7 @@ describe("MCP Server", () => {
1284
1284
  headers: { "Content-Type": "application/json" },
1285
1285
  })
1286
1286
  );
1287
- });
1287
+ }) as unknown as typeof fetch;
1288
1288
 
1289
1289
  await handleToolCall(
1290
1290
  createRequest("create_action_item", {
@@ -1375,7 +1375,7 @@ describe("MCP Server", () => {
1375
1375
  headers: { "Content-Type": "application/json" },
1376
1376
  })
1377
1377
  );
1378
- });
1378
+ }) as unknown as typeof fetch;
1379
1379
 
1380
1380
  const response = await handleToolCall(
1381
1381
  createRequest("update_action_item", { action_item_id: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", title: "New Title" })
@@ -1407,7 +1407,7 @@ describe("MCP Server", () => {
1407
1407
  headers: { "Content-Type": "application/json" },
1408
1408
  })
1409
1409
  );
1410
- });
1410
+ }) as unknown as typeof fetch;
1411
1411
 
1412
1412
  const response = await handleToolCall(
1413
1413
  createRequest("update_action_item", { action_item_id: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", is_done: true })
@@ -1438,7 +1438,7 @@ describe("MCP Server", () => {
1438
1438
  headers: { "Content-Type": "application/json" },
1439
1439
  })
1440
1440
  );
1441
- });
1441
+ }) as unknown as typeof fetch;
1442
1442
 
1443
1443
  const response = await handleToolCall(
1444
1444
  createRequest("update_action_item", {
@@ -1492,7 +1492,7 @@ describe("MCP Server", () => {
1492
1492
  headers: { "Content-Type": "application/json" },
1493
1493
  })
1494
1494
  )
1495
- );
1495
+ ) as unknown as typeof fetch;
1496
1496
 
1497
1497
  const response = await handleToolCall(
1498
1498
  createRequest("create_issue", { title: "Test Issue" })
@@ -1512,7 +1512,7 @@ describe("MCP Server", () => {
1512
1512
  defaultProject: null,
1513
1513
  });
1514
1514
 
1515
- globalThis.fetch = mock(() => Promise.reject(new Error("Network error")));
1515
+ globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch;
1516
1516
 
1517
1517
  const response = await handleToolCall(
1518
1518
  createRequest("create_issue", { title: "Test Issue" })
@@ -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,146 @@ 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
+ test("returns pooler db url via connection_string fallback path", async () => {
199
+ globalThis.fetch = mock(() =>
200
+ Promise.resolve(
201
+ new Response(
202
+ JSON.stringify([
203
+ {
204
+ // No db_host/db_port/db_name - uses connection_string fallback
205
+ connection_string:
206
+ "postgresql://ignored@aws-1-eu-west-1.pooler.supabase.com:6543/postgres",
207
+ },
208
+ ]),
209
+ { status: 200 }
210
+ )
211
+ )
212
+ ) as unknown as typeof fetch;
213
+
214
+ const url = await fetchPoolerDatabaseUrl(
215
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
216
+ "postgres_ai_mon"
217
+ );
218
+ expect(url).toBe(
219
+ "postgresql://postgres_ai_mon.xhaqmsvczjkkvkgdyast@aws-1-eu-west-1.pooler.supabase.com:6543/postgres"
220
+ );
221
+ });
222
+
223
+ test("returns null for invalid connection_string URL", async () => {
224
+ globalThis.fetch = mock(() =>
225
+ Promise.resolve(
226
+ new Response(
227
+ JSON.stringify([
228
+ {
229
+ connection_string: "not-a-valid-url",
230
+ },
231
+ ]),
232
+ { status: 200 }
233
+ )
234
+ )
235
+ ) as unknown as typeof fetch;
236
+
237
+ const url = await fetchPoolerDatabaseUrl(
238
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
239
+ "postgres_ai_mon"
240
+ );
241
+ expect(url).toBeNull();
242
+ });
243
+
244
+ test("returns null for empty API response", async () => {
245
+ globalThis.fetch = mock(() =>
246
+ Promise.resolve(new Response(JSON.stringify([]), { status: 200 }))
247
+ ) as unknown as typeof fetch;
248
+
249
+ const url = await fetchPoolerDatabaseUrl(
250
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
251
+ "postgres_ai_mon"
252
+ );
253
+ expect(url).toBeNull();
254
+ });
255
+
256
+ test("returns null for API error response", async () => {
257
+ globalThis.fetch = mock(() =>
258
+ Promise.resolve(new Response("Unauthorized", { status: 401 }))
259
+ ) as unknown as typeof fetch;
260
+
261
+ const url = await fetchPoolerDatabaseUrl(
262
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
263
+ "postgres_ai_mon"
264
+ );
265
+ expect(url).toBeNull();
266
+ });
267
+
268
+ test("returns null when fetch throws network error", async () => {
269
+ globalThis.fetch = mock(() =>
270
+ Promise.reject(new Error("Network error"))
271
+ ) as unknown as typeof fetch;
272
+
273
+ const url = await fetchPoolerDatabaseUrl(
274
+ { projectRef: "xhaqmsvczjkkvkgdyast", accessToken: "token" },
275
+ "postgres_ai_mon"
276
+ );
277
+ expect(url).toBeNull();
278
+ });
279
+ });
280
+
140
281
  describe("SupabaseClient", () => {
141
282
  test("throws error when project ref is empty", () => {
142
283
  expect(() => new SupabaseClient({ projectRef: "", accessToken: "token" })).toThrow(