@supabase/pg-delta 1.0.0-alpha.14 → 1.0.0-alpha.16

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.
@@ -225,14 +225,20 @@ interface CreatePoolOptions extends Partial<PoolConfig> {
225
225
 
226
226
  /**
227
227
  * Create a Pool with custom type handlers and optional event listeners.
228
+ *
229
+ * `connectionString` may be `undefined` when the caller needs pg to rely on
230
+ * explicit `host`/`port`/`user`/... fields from `options` instead — notably
231
+ * the bracketed-IPv6 workaround in {@link poolConfigFromUrl}, where passing
232
+ * the connection string would cause `pg-connection-string` to re-inject the
233
+ * bracketed host that breaks `getaddrinfo`.
228
234
  */
229
235
  export function createPool(
230
- connectionString: string,
236
+ connectionString: string | undefined,
231
237
  options?: CreatePoolOptions,
232
238
  ): Pool {
233
239
  const { onConnect, onError, onAcquire, onRemove, ...config } = options ?? {};
234
240
  const pool = new Pool({
235
- connectionString,
241
+ ...(connectionString ? { connectionString } : {}),
236
242
  max: DEFAULT_POOL_MAX,
237
243
  connectionTimeoutMillis: DEFAULT_CONNECTION_TIMEOUT_MS,
238
244
  ...config,
@@ -301,6 +307,50 @@ export function createPool(
301
307
  return pool;
302
308
  }
303
309
 
310
+ /**
311
+ * Build a pg {@link PoolConfig} from a cleaned connection URL.
312
+ *
313
+ * For most URLs this just returns `{ connectionString }` and pg does its
314
+ * normal parsing. But for URLs whose hostname is a bracketed IPv6 literal
315
+ * (e.g. `postgresql://user@[::1]:5432/db`, as produced by
316
+ * {@link normalizeConnectionUrl}), we expand the URL into explicit
317
+ * `host`/`port`/`user`/`password`/`database` fields with a **bare** IPv6
318
+ * host — no brackets.
319
+ *
320
+ * This works around a `pg-connection-string` quirk: its parser sets
321
+ * `config.host` to the WHATWG `URL.hostname`, which keeps the surrounding
322
+ * `[...]` for IPv6 literals. That bracketed value is then passed verbatim to
323
+ * `getaddrinfo`, which rejects it with `ENOTFOUND`. Since
324
+ * `pg`'s connection-parameters module does
325
+ * `Object.assign({}, config, parse(connectionString))`, any `host` we pass
326
+ * alongside `connectionString` gets clobbered — so we drop `connectionString`
327
+ * entirely on this path and hand pg the parsed fields directly.
328
+ *
329
+ * Remaining query parameters (e.g. `application_name`, `options`,
330
+ * `connect_timeout`) are forwarded as top-level config keys, mirroring how
331
+ * `pg-connection-string` would normally surface them.
332
+ */
333
+ export function poolConfigFromUrl(cleanedUrl: string): PoolConfig {
334
+ const urlObj = new URL(cleanedUrl);
335
+ if (!urlObj.hostname.startsWith("[")) {
336
+ return { connectionString: cleanedUrl };
337
+ }
338
+
339
+ const config: Record<string, unknown> = {
340
+ host: urlObj.hostname.slice(1, -1),
341
+ };
342
+ if (urlObj.port) config.port = Number(urlObj.port);
343
+ if (urlObj.username) config.user = decodeURIComponent(urlObj.username);
344
+ if (urlObj.password) config.password = decodeURIComponent(urlObj.password);
345
+ if (urlObj.pathname.length > 1) {
346
+ config.database = decodeURIComponent(urlObj.pathname.slice(1));
347
+ }
348
+ for (const [key, value] of urlObj.searchParams) {
349
+ config[key] = value;
350
+ }
351
+ return config as PoolConfig;
352
+ }
353
+
304
354
  /**
305
355
  * End a pool and wait for all client sockets to fully close.
306
356
  *
@@ -334,7 +384,11 @@ export async function createManagedPool(
334
384
  normalizedUrl,
335
385
  options?.label ?? "target",
336
386
  );
337
- const pool = createPool(sslConfig.cleanedUrl, {
387
+ // Expand bracketed-IPv6 URLs into explicit pg fields so the brackets never
388
+ // reach `getaddrinfo` — see `poolConfigFromUrl` for the full rationale.
389
+ const connectionConfig = poolConfigFromUrl(sslConfig.cleanedUrl);
390
+ const pool = createPool(connectionConfig.connectionString, {
391
+ ...connectionConfig,
338
392
  ...(sslConfig.ssl !== undefined ? { ssl: sslConfig.ssl } : {}),
339
393
  onError: (err: Error & { code?: string }) => {
340
394
  if (err.code !== "57P01") {