@fabricorg/experiments-db-pool 0.1.1 → 0.1.2

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.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var pg = require('pg');
4
4
  var events = require('events');
5
+ var promises = require('fs/promises');
5
6
 
6
7
  // src/providers/neon.ts
7
8
  var NeonDatabaseProvider = class {
@@ -11,8 +12,16 @@ var NeonDatabaseProvider = class {
11
12
  this.pool = new pg.Pool({
12
13
  connectionString: options.connectionString,
13
14
  max: options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? "5", 10),
14
- idleTimeoutMillis: options.idleTimeoutMillis ?? 3e4,
15
- connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5e3
15
+ idleTimeoutMillis: options.idleTimeoutMillis ?? Number.parseInt(process.env.PG_POOL_IDLE_TIMEOUT_MS ?? "30000", 10),
16
+ connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5e3,
17
+ // Cloudflare request isolates cannot safely carry a TCP client owned by
18
+ // one request into the next. Set PG_POOL_MAX_USES=1 there so release()
19
+ // destroys the client synchronously; conventional Node runtimes retain
20
+ // pg-pool's effectively-unbounded default.
21
+ maxUses: Number.parseInt(process.env.PG_POOL_MAX_USES ?? "7500", 10),
22
+ // Lets an edge isolate release its final idle socket instead of keeping
23
+ // an I/O handle owned by a completed request alive indefinitely.
24
+ allowExitOnIdle: true
16
25
  });
17
26
  }
18
27
  getPool() {
@@ -27,9 +36,37 @@ function databricksIdentity(principal) {
27
36
  const { token } = principal;
28
37
  return async () => token;
29
38
  }
39
+ if (principal.kind === "federated") return federatedIdentityProvider(principal);
30
40
  return servicePrincipalProvider(principal);
31
41
  }
32
42
  function databricksPrincipalFromEnv(env = typeof process !== "undefined" ? process.env : {}) {
43
+ const authType = env.DATABRICKS_AUTH_TYPE?.trim();
44
+ if (authType === "env-oidc" || authType === "file-oidc") {
45
+ const host2 = env.DATABRICKS_HOST?.trim();
46
+ if (!host2) throw new Error("Missing DATABRICKS_HOST for Databricks OAuth federation.");
47
+ return {
48
+ kind: "federated",
49
+ host: host2,
50
+ clientId: env.DATABRICKS_CLIENT_ID?.trim() || void 0,
51
+ scope: env.DATABRICKS_SCOPE,
52
+ refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10) : void 0,
53
+ subjectToken: async () => {
54
+ if (authType === "env-oidc") {
55
+ const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV?.trim() || "DATABRICKS_OIDC_TOKEN";
56
+ const token3 = env[tokenEnv]?.trim();
57
+ if (!token3) throw new Error(`Databricks OIDC token environment ${tokenEnv} is empty.`);
58
+ return token3;
59
+ }
60
+ const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH?.trim();
61
+ if (!path) {
62
+ throw new Error("Missing DATABRICKS_OIDC_TOKEN_FILEPATH for file-oidc federation.");
63
+ }
64
+ const token2 = (await promises.readFile(path, "utf8")).trim();
65
+ if (!token2) throw new Error(`Databricks OIDC token file ${path} is empty.`);
66
+ return token2;
67
+ }
68
+ };
69
+ }
33
70
  const token = env.DATABRICKS_TOKEN?.trim();
34
71
  if (token) return { kind: "pat", token };
35
72
  const clientId = env.DATABRICKS_CLIENT_ID?.trim();
@@ -47,7 +84,7 @@ function databricksPrincipalFromEnv(env = typeof process !== "undefined" ? proce
47
84
  };
48
85
  }
49
86
  throw new Error(
50
- "Missing Databricks credentials: DATABRICKS_TOKEN or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET."
87
+ "Missing Databricks credentials: env/file OIDC federation, DATABRICKS_TOKEN, or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET."
51
88
  );
52
89
  }
53
90
  function servicePrincipalProvider(principal) {
@@ -92,6 +129,54 @@ function servicePrincipalProvider(principal) {
92
129
  };
93
130
  return getToken;
94
131
  }
132
+ function federatedIdentityProvider(principal) {
133
+ const host = principal.host.replace(/\/$/, "");
134
+ const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1e3;
135
+ let cached;
136
+ let refreshing;
137
+ const refresh = async () => {
138
+ const params = new URLSearchParams({
139
+ grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
140
+ subject_token: await principal.subjectToken(),
141
+ subject_token_type: "urn:ietf:params:oauth:token-type:jwt",
142
+ scope: principal.scope ?? "all-apis"
143
+ });
144
+ if (principal.clientId) params.set("client_id", principal.clientId);
145
+ const response = await fetch(`${host}/oidc/v1/token`, {
146
+ method: "POST",
147
+ headers: { "content-type": "application/x-www-form-urlencoded" },
148
+ body: params
149
+ });
150
+ if (!response.ok) {
151
+ const text = await response.text();
152
+ throw new Error(
153
+ `Databricks federated token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
154
+ );
155
+ }
156
+ const value = await response.json();
157
+ if (typeof value.access_token !== "string" || !value.access_token) {
158
+ throw new Error("Databricks federated token exchange returned no access_token.");
159
+ }
160
+ const expiresInSeconds = typeof value.expires_in === "number" ? value.expires_in : 3600;
161
+ cached = {
162
+ token: value.access_token,
163
+ refreshAtMs: Date.now() + expiresInSeconds * 1e3 - refreshSkewMs
164
+ };
165
+ return value.access_token;
166
+ };
167
+ const getToken = async () => {
168
+ if (cached && Date.now() < cached.refreshAtMs) return cached.token;
169
+ refreshing ??= refresh().finally(() => {
170
+ refreshing = void 0;
171
+ });
172
+ return refreshing;
173
+ };
174
+ getToken.refresh = async () => {
175
+ cached = void 0;
176
+ return getToken();
177
+ };
178
+ return getToken;
179
+ }
95
180
  async function exchangeLakebaseCredential(options) {
96
181
  const fetchImpl = options.fetchImpl ?? fetch;
97
182
  const response = await fetchImpl(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/providers/neon.ts","../src/providers/lakebase.ts","../src/index.ts"],"names":["Pool","EventEmitter"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\nexport interface NeonProviderOptions {\n connectionString: string;\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n}\n\n/** Standard Postgres provider using a static connection string. */\nexport class NeonDatabaseProvider implements DatabaseProvider {\n readonly kind = 'neon' as const;\n private readonly pool: Pool;\n\n constructor(options: NeonProviderOptions) {\n this.pool = new Pool({\n connectionString: options.connectionString,\n max: options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis: options.idleTimeoutMillis ?? 30_000,\n connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5_000,\n });\n }\n\n getPool(): Pool {\n return this.pool;\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n","import { EventEmitter } from 'node:events';\nimport { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\n/** A resolver that returns a valid Databricks workspace OAuth token. */\nexport type DatabricksTokenProvider = (() => Promise<string>) & {\n /** Bypass the cache and obtain a new token when the downstream credential is rotated. */\n refresh?: () => Promise<string>;\n};\n\n/** Supported Databricks authentication shapes. */\nexport type DatabricksPrincipal =\n | { kind: 'pat'; token: string }\n | {\n kind: 'service-principal';\n host: string;\n clientId: string;\n clientSecret: string;\n scope?: string;\n refreshSkewSeconds?: number;\n };\n\n/** Resolve a PAT or OAuth M2M principal to a cached, auto-refreshing token provider. */\nexport function databricksIdentity(principal: DatabricksPrincipal): DatabricksTokenProvider {\n if (principal.kind === 'pat') {\n const { token } = principal;\n return async () => token;\n }\n return servicePrincipalProvider(principal);\n}\n\n/** Build a principal from environment variables. */\nexport function databricksPrincipalFromEnv(\n env: Record<string, string | undefined> = typeof process !== 'undefined' ? process.env : {},\n): Extract<DatabricksPrincipal, { kind: 'pat' | 'service-principal' }> {\n const token = env.DATABRICKS_TOKEN?.trim();\n if (token) return { kind: 'pat', token };\n\n const clientId = env.DATABRICKS_CLIENT_ID?.trim();\n const clientSecret = env.DATABRICKS_CLIENT_SECRET?.trim();\n const host = env.DATABRICKS_HOST?.trim();\n if (clientId && clientSecret) {\n if (!host) throw new Error('Missing DATABRICKS_HOST for Databricks OAuth M2M.');\n return {\n kind: 'service-principal',\n host,\n clientId,\n clientSecret,\n scope: env.DATABRICKS_SCOPE,\n refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS\n ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10)\n : undefined,\n };\n }\n throw new Error(\n 'Missing Databricks credentials: DATABRICKS_TOKEN or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET.',\n );\n}\n\ninterface CachedToken {\n token: string;\n refreshAtMs: number;\n}\n\nfunction servicePrincipalProvider(\n principal: Extract<DatabricksPrincipal, { kind: 'service-principal' }>,\n): DatabricksTokenProvider {\n const host = principal.host.replace(/\\/$/, '');\n const scope = principal.scope ?? 'all-apis';\n const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1_000;\n let cached: CachedToken | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (): Promise<string> => {\n const response = await fetch(`${host}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${principal.clientId}:${principal.clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({ grant_type: 'client_credentials', scope }),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Databricks OAuth token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n const token = typeof value.access_token === 'string' ? value.access_token : undefined;\n if (!token) throw new Error('Databricks OAuth token exchange returned no access_token.');\n const expiresInSeconds = typeof value.expires_in === 'number' ? value.expires_in : 3_600;\n const expiresAtMs = Date.now() + expiresInSeconds * 1_000;\n cached = { token, refreshAtMs: expiresAtMs - refreshSkewMs };\n return token;\n };\n\n const getToken: DatabricksTokenProvider = async () => {\n if (cached && Date.now() < cached.refreshAtMs) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getToken.refresh = async () => {\n cached = undefined;\n return getToken();\n };\n\n return getToken;\n}\n\nexport interface LakebaseCredentialProviderOptions {\n workspaceHost: string;\n endpoint: string;\n token: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n refreshBeforeMs?: number;\n refreshJitterMs?: number;\n now?: () => number;\n random?: () => number;\n}\n\ninterface LakebaseCredentialResponse {\n token?: unknown;\n expire_time?: unknown;\n}\n\nexport interface LakebaseCredential {\n token: string;\n expiresAt: number;\n}\n\nexport interface ExchangeLakebaseCredentialOptions {\n workspaceHost: string;\n endpoint: string;\n workspaceToken: string;\n fetchImpl?: typeof fetch;\n}\n\n/** Perform one uncached workspace-token to Lakebase-credential exchange. */\nexport async function exchangeLakebaseCredential(\n options: ExchangeLakebaseCredentialOptions,\n): Promise<LakebaseCredential> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const response = await fetchImpl(\n `${options.workspaceHost.replace(/\\/$/, '')}/api/2.0/postgres/credentials`,\n {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.workspaceToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ endpoint: options.endpoint }),\n },\n );\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as LakebaseCredentialResponse;\n if (typeof value.token !== 'string' || !value.token) {\n throw new Error('Lakebase credential exchange returned no token.');\n }\n const expiresAt = parseExpireTime(value.expire_time);\n if (!Number.isFinite(expiresAt)) {\n throw new Error('Lakebase credential exchange returned an invalid expire_time.');\n }\n return { token: value.token, expiresAt };\n}\n\nexport type LakebaseCredentialProvider = (() => Promise<string>) & {\n /** Force both the workspace OAuth token and database credential to rotate. */\n refresh: () => Promise<string>;\n};\n\n/** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */\nexport function lakebaseCredentialProvider(\n options: LakebaseCredentialProviderOptions,\n): LakebaseCredentialProvider {\n const now = options.now ?? Date.now;\n const random = options.random ?? Math.random;\n const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 60_000;\n const refreshJitterMs = options.refreshJitterMs ?? 30_000;\n let cached: { token: string; refreshAt: number } | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (forceWorkspaceToken = false): Promise<string> => {\n const workspaceToken =\n typeof options.token === 'function'\n ? await (forceWorkspaceToken && options.token.refresh\n ? options.token.refresh()\n : options.token())\n : options.token;\n const value = await exchangeLakebaseCredential({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n workspaceToken,\n fetchImpl: options.fetchImpl,\n });\n const jitter = Math.max(0, refreshJitterMs) * random();\n cached = {\n token: value.token,\n refreshAt: Math.max(now(), value.expiresAt - Math.max(0, refreshBeforeMs) - jitter),\n };\n return value.token;\n };\n\n const getCredential: LakebaseCredentialProvider = async () => {\n if (cached && now() < cached.refreshAt) return cached.token;\n refreshing ??= refresh(false).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getCredential.refresh = async () => {\n cached = undefined;\n refreshing ??= refresh(true).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n return getCredential;\n}\n\nfunction parseExpireTime(value: unknown): number {\n if (typeof value === 'number') {\n return value < 1_000_000_000_000 ? value * 1_000 : value;\n }\n if (typeof value === 'string') return new Date(value).getTime();\n return Number.NaN;\n}\n\nexport interface LakebasePoolConfig {\n host: string;\n port: number;\n database: string;\n user: string;\n password?: string;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** Postgres `options` connection parameter, e.g. `-c search_path=fx,public`. */\n options?: string;\n}\n\nexport type LakebasePoolFactory = (config: LakebasePoolConfig) => Pool;\n\nexport interface LakebaseProviderOptions {\n /** Direct endpoint host from list-endpoints (NOT the pooled host). */\n host: string;\n port?: number;\n database: string;\n user: string;\n /** Static database password. If omitted, OAuth exchange is required. */\n password?: string;\n /** Workspace URL, e.g. https://adb-....azuredatabricks.net */\n workspaceHost?: string;\n /** Full endpoint resource name: projects/.../branches/.../endpoints/... */\n endpoint?: string;\n /** Workspace OAuth token or provider. */\n token?: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** How often to force-refresh the credential and recreate the pool. Default 45 minutes. */\n refreshIntervalMs?: number;\n /** Injected pool factory for tests. */\n poolFactory?: LakebasePoolFactory;\n /** Observe recoverable idle pooled-connection failures. */\n onPoolError?: (error: Error) => void;\n}\n\n/** A Pool-like facade that lazily initializes and always delegates to the current underlying pool. */\nclass DelegatingPool extends EventEmitter {\n private current: Pool | undefined;\n private initPromise: Promise<void> | undefined;\n private closed = false;\n\n private attachErrorHandler(pool: Pool) {\n pool.on('error', (error) => {\n this.emit('error', error);\n });\n }\n\n initialize(createPool: (password: string) => Pool, getPassword: () => Promise<string>) {\n this.initPromise = getPassword()\n .then((password) => {\n if (!this.closed) this.swap(createPool(password));\n })\n .catch((error) => {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n throw error;\n });\n }\n\n swap(pool: Pool) {\n if (this.closed) {\n pool.end().catch(() => undefined);\n return;\n }\n const previous = this.current;\n this.current = pool;\n this.attachErrorHandler(pool);\n if (previous) {\n previous.removeAllListeners();\n previous.end().catch(() => undefined);\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) await this.initPromise;\n }\n\n query(...args: Parameters<Pool['query']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.query(...args));\n }\n\n connect(...args: Parameters<Pool['connect']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.connect(...args));\n }\n\n end(): Promise<void> {\n this.closed = true;\n this.removeAllListeners();\n return this.current?.end() ?? Promise.resolve();\n }\n\n get totalCount() {\n return this.current?.totalCount ?? 0;\n }\n\n get idleCount() {\n return this.current?.idleCount ?? 0;\n }\n\n get waitingCount() {\n return this.current?.waitingCount ?? 0;\n }\n}\n\n/** Databricks Lakebase Postgres provider with credential refresh. */\nexport class LakebaseDatabaseProvider implements DatabaseProvider {\n readonly kind = 'databricks-lakebase' as const;\n private readonly options: LakebaseProviderOptions;\n private readonly poolFactory: LakebasePoolFactory;\n private readonly getPassword: () => Promise<string>;\n private readonly refreshPassword: () => Promise<string>;\n private readonly delegatingPool: DelegatingPool;\n private refreshTimer: NodeJS.Timeout | undefined;\n\n constructor(options: LakebaseProviderOptions) {\n this.options = options;\n this.poolFactory = options.poolFactory ?? defaultPoolFactory();\n this.delegatingPool = new DelegatingPool();\n if (options.password !== undefined) {\n this.getPassword = async () => options.password as string;\n this.refreshPassword = this.getPassword;\n this.delegatingPool.swap(this.createPool(options.password));\n } else {\n if (!options.token || !options.workspaceHost || !options.endpoint) {\n throw new Error(\n 'Lakebase OAuth requires token, workspaceHost, and endpoint. A workspace token cannot be used directly as the Postgres password.',\n );\n }\n const credential = lakebaseCredentialProvider({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n token: options.token,\n fetchImpl: options.fetchImpl,\n });\n this.getPassword = credential;\n this.refreshPassword = credential.refresh;\n this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);\n const intervalMs = options.refreshIntervalMs ?? 45 * 60_000;\n this.refreshTimer = setInterval(() => {\n void this.refreshCredentials().catch((error) => {\n this.delegatingPool.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n });\n }, intervalMs);\n }\n }\n\n private createPool(password?: string): Pool {\n return this.poolFactory({\n host: this.options.host,\n port: this.options.port ?? 5432,\n database: this.options.database,\n user: this.options.user,\n password,\n ssl: this.options.ssl ?? { rejectUnauthorized: true },\n max: this.options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis: this.options.idleTimeoutMillis ?? 30_000,\n connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5_000,\n options: '-c search_path=fx,public',\n });\n }\n\n /** Force a new database credential and atomically swap the active pool. */\n async refreshCredentials(): Promise<void> {\n const password = await this.refreshPassword();\n const pool = this.createPool(password);\n this.delegatingPool.swap(pool);\n }\n\n getPool(): Pool {\n return this.delegatingPool as unknown as Pool;\n }\n\n async close(): Promise<void> {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n await this.delegatingPool.end();\n }\n}\n\nfunction defaultPoolFactory(): LakebasePoolFactory {\n return (config) => new Pool(config);\n}\n","import type { Gauge, MetricsCollector } from '@fabricorg/experiments-metrics';\nimport type { Pool } from 'pg';\nimport {\n type DatabaseProvider,\n LakebaseDatabaseProvider,\n NeonDatabaseProvider,\n databricksIdentity,\n databricksPrincipalFromEnv,\n} from './providers/index.js';\n\nexport {\n LakebaseDatabaseProvider,\n exchangeLakebaseCredential,\n lakebaseCredentialProvider,\n type ExchangeLakebaseCredentialOptions,\n type LakebaseCredential,\n type LakebasePoolFactory,\n type LakebaseProviderOptions,\n} from './providers/index.js';\n\nlet provider: DatabaseProvider | null = null;\n\nfunction createProvider(): DatabaseProvider {\n const kind = process.env.DATABASE_PROVIDER ?? 'neon';\n\n if (kind === 'databricks-lakebase') {\n const host = process.env.DATABRICKS_LAKEBASE_HOST?.trim();\n const database = process.env.DATABRICKS_LAKEBASE_DATABASE?.trim() ?? 'databricks_postgres';\n const user = process.env.DATABRICKS_LAKEBASE_USER?.trim();\n const workspaceHost = process.env.DATABRICKS_HOST?.trim();\n const endpoint = process.env.DATABRICKS_LAKEBASE_ENDPOINT?.trim();\n const password = process.env.DATABRICKS_LAKEBASE_PASSWORD?.trim();\n\n if (!host) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_HOST is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n if (!user) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_USER is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n\n if (password) {\n return new LakebaseDatabaseProvider({ host, database, user, password });\n }\n\n if (!workspaceHost || !endpoint) {\n throw new Error(\n 'DATABRICKS_HOST and DATABRICKS_LAKEBASE_ENDPOINT are required for Lakebase OAuth, or provide DATABRICKS_LAKEBASE_PASSWORD for native auth.',\n );\n }\n\n const principal = databricksPrincipalFromEnv(process.env);\n return new LakebaseDatabaseProvider({\n host,\n database,\n user,\n workspaceHost,\n endpoint,\n token: databricksIdentity(principal),\n });\n }\n\n const connectionString = process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error('DATABASE_URL is required');\n }\n return new NeonDatabaseProvider({ connectionString });\n}\n\n/**\n * Return a singleton `pg.Pool` configured for the active database provider.\n *\n * Provider selection:\n * - `DATABASE_PROVIDER=neon` (default): uses `DATABASE_URL`.\n * - `DATABASE_PROVIDER=databricks-lakebase`: uses Lakebase OAuth credentials.\n *\n * On the first call, a new Pool is created with the following defaults:\n * - `max`: parseInt(process.env.PG_POOL_MAX ?? '5') — caps concurrent connections.\n * - `idleTimeoutMillis`: 30000 — recycle idle connections before Vercel's 60s timeout.\n * - `connectionTimeoutMillis`: 5000 — fail fast when the database is unreachable.\n */\nexport function getPool(): Pool {\n if (!provider) {\n provider = createProvider();\n }\n return provider.getPool();\n}\n\n/** Close the active provider and any background refresh loops. */\nexport async function closePool(): Promise<void> {\n await provider?.close();\n provider = null;\n}\n\n/** Reset the singleton provider. Intended for tests. */\nexport function resetPoolProvider(): void {\n provider = null;\n}\n\n/** Return the active provider, or create it. */\nexport function getProvider(): DatabaseProvider {\n if (!provider) {\n provider = createProvider();\n }\n return provider;\n}\n\ninterface PoolGauges {\n total: Gauge;\n idle: Gauge;\n waiting: Gauge;\n active: Gauge;\n}\n\nfunction ensurePoolGauges(collector: MetricsCollector): PoolGauges {\n const reg = collector.registry;\n const existingTotal = reg.get('db_pool_connections_total');\n if (existingTotal) {\n return {\n total: existingTotal as Gauge,\n idle: reg.get('db_pool_connections_idle') as Gauge,\n waiting: reg.get('db_pool_connections_waiting') as Gauge,\n active: reg.get('db_pool_connections_active') as Gauge,\n };\n }\n\n return {\n total: collector.gauge('db_pool_connections_total', 'Total connections in the pool'),\n idle: collector.gauge('db_pool_connections_idle', 'Idle connections in the pool'),\n waiting: collector.gauge('db_pool_connections_waiting', 'Waiting clients in the pool'),\n active: collector.gauge(\n 'db_pool_connections_active',\n 'Active (non-idle) connections in the pool',\n ),\n };\n}\n\n/** Update pool gauge values from the current pool state. */\nexport function updatePoolMetrics(collector: MetricsCollector, poolInstance?: Pool): void {\n const p = poolInstance ?? getPool();\n const total = (p as unknown as { totalCount: number }).totalCount ?? 0;\n const idle = p.idleCount ?? 0;\n const waiting = p.waitingCount ?? 0;\n\n const gauges = ensurePoolGauges(collector);\n gauges.total.set({}, total);\n gauges.idle.set({}, idle);\n gauges.waiting.set({}, waiting);\n gauges.active.set({}, Math.max(0, total - idle));\n}\n\n/**\n * Register pool metrics with the given collector.\n *\n * Returns a cleanup function that stops the update interval.\n */\nexport function registerPoolMetrics(\n collector: MetricsCollector,\n poolInstance?: Pool,\n intervalMs = 5000,\n): () => void {\n updatePoolMetrics(collector, poolInstance);\n\n const interval = setInterval(() => {\n updatePoolMetrics(collector, poolInstance);\n }, intervalMs);\n\n return () => clearInterval(interval);\n}\n"]}
1
+ {"version":3,"sources":["../src/providers/neon.ts","../src/providers/lakebase.ts","../src/index.ts"],"names":["Pool","host","token","readFile","EventEmitter"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\nexport interface NeonProviderOptions {\n connectionString: string;\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n}\n\n/** Standard Postgres provider using a static connection string. */\nexport class NeonDatabaseProvider implements DatabaseProvider {\n readonly kind = 'neon' as const;\n private readonly pool: Pool;\n\n constructor(options: NeonProviderOptions) {\n this.pool = new Pool({\n connectionString: options.connectionString,\n max: options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis:\n options.idleTimeoutMillis ??\n Number.parseInt(process.env.PG_POOL_IDLE_TIMEOUT_MS ?? '30000', 10),\n connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5_000,\n // Cloudflare request isolates cannot safely carry a TCP client owned by\n // one request into the next. Set PG_POOL_MAX_USES=1 there so release()\n // destroys the client synchronously; conventional Node runtimes retain\n // pg-pool's effectively-unbounded default.\n maxUses: Number.parseInt(process.env.PG_POOL_MAX_USES ?? '7500', 10),\n // Lets an edge isolate release its final idle socket instead of keeping\n // an I/O handle owned by a completed request alive indefinitely.\n allowExitOnIdle: true,\n });\n }\n\n getPool(): Pool {\n return this.pool;\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n","import { EventEmitter } from 'node:events';\nimport { readFile } from 'node:fs/promises';\nimport { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\n/** A resolver that returns a valid Databricks workspace OAuth token. */\nexport type DatabricksTokenProvider = (() => Promise<string>) & {\n /** Bypass the cache and obtain a new token when the downstream credential is rotated. */\n refresh?: () => Promise<string>;\n};\n\n/** Supported Databricks authentication shapes. */\nexport type DatabricksPrincipal =\n | { kind: 'pat'; token: string }\n | {\n kind: 'service-principal';\n host: string;\n clientId: string;\n clientSecret: string;\n scope?: string;\n refreshSkewSeconds?: number;\n }\n | {\n kind: 'federated';\n host: string;\n clientId?: string;\n subjectToken: () => Promise<string>;\n scope?: string;\n refreshSkewSeconds?: number;\n };\n\n/** Resolve a PAT or OAuth M2M principal to a cached, auto-refreshing token provider. */\nexport function databricksIdentity(principal: DatabricksPrincipal): DatabricksTokenProvider {\n if (principal.kind === 'pat') {\n const { token } = principal;\n return async () => token;\n }\n if (principal.kind === 'federated') return federatedIdentityProvider(principal);\n return servicePrincipalProvider(principal);\n}\n\n/** Build a principal from environment variables. */\nexport function databricksPrincipalFromEnv(\n env: Record<string, string | undefined> = typeof process !== 'undefined' ? process.env : {},\n): DatabricksPrincipal {\n const authType = env.DATABRICKS_AUTH_TYPE?.trim();\n if (authType === 'env-oidc' || authType === 'file-oidc') {\n const host = env.DATABRICKS_HOST?.trim();\n if (!host) throw new Error('Missing DATABRICKS_HOST for Databricks OAuth federation.');\n return {\n kind: 'federated',\n host,\n clientId: env.DATABRICKS_CLIENT_ID?.trim() || undefined,\n scope: env.DATABRICKS_SCOPE,\n refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS\n ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10)\n : undefined,\n subjectToken: async () => {\n if (authType === 'env-oidc') {\n const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV?.trim() || 'DATABRICKS_OIDC_TOKEN';\n const token = env[tokenEnv]?.trim();\n if (!token) throw new Error(`Databricks OIDC token environment ${tokenEnv} is empty.`);\n return token;\n }\n const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH?.trim();\n if (!path) {\n throw new Error('Missing DATABRICKS_OIDC_TOKEN_FILEPATH for file-oidc federation.');\n }\n const token = (await readFile(path, 'utf8')).trim();\n if (!token) throw new Error(`Databricks OIDC token file ${path} is empty.`);\n return token;\n },\n };\n }\n const token = env.DATABRICKS_TOKEN?.trim();\n if (token) return { kind: 'pat', token };\n\n const clientId = env.DATABRICKS_CLIENT_ID?.trim();\n const clientSecret = env.DATABRICKS_CLIENT_SECRET?.trim();\n const host = env.DATABRICKS_HOST?.trim();\n if (clientId && clientSecret) {\n if (!host) throw new Error('Missing DATABRICKS_HOST for Databricks OAuth M2M.');\n return {\n kind: 'service-principal',\n host,\n clientId,\n clientSecret,\n scope: env.DATABRICKS_SCOPE,\n refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS\n ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10)\n : undefined,\n };\n }\n throw new Error(\n 'Missing Databricks credentials: env/file OIDC federation, DATABRICKS_TOKEN, or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET.',\n );\n}\n\ninterface CachedToken {\n token: string;\n refreshAtMs: number;\n}\n\nfunction servicePrincipalProvider(\n principal: Extract<DatabricksPrincipal, { kind: 'service-principal' }>,\n): DatabricksTokenProvider {\n const host = principal.host.replace(/\\/$/, '');\n const scope = principal.scope ?? 'all-apis';\n const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1_000;\n let cached: CachedToken | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (): Promise<string> => {\n const response = await fetch(`${host}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${principal.clientId}:${principal.clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({ grant_type: 'client_credentials', scope }),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Databricks OAuth token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n const token = typeof value.access_token === 'string' ? value.access_token : undefined;\n if (!token) throw new Error('Databricks OAuth token exchange returned no access_token.');\n const expiresInSeconds = typeof value.expires_in === 'number' ? value.expires_in : 3_600;\n const expiresAtMs = Date.now() + expiresInSeconds * 1_000;\n cached = { token, refreshAtMs: expiresAtMs - refreshSkewMs };\n return token;\n };\n\n const getToken: DatabricksTokenProvider = async () => {\n if (cached && Date.now() < cached.refreshAtMs) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getToken.refresh = async () => {\n cached = undefined;\n return getToken();\n };\n\n return getToken;\n}\n\nfunction federatedIdentityProvider(\n principal: Extract<DatabricksPrincipal, { kind: 'federated' }>,\n): DatabricksTokenProvider {\n const host = principal.host.replace(/\\/$/, '');\n const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1_000;\n let cached: CachedToken | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (): Promise<string> => {\n const params = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n subject_token: await principal.subjectToken(),\n subject_token_type: 'urn:ietf:params:oauth:token-type:jwt',\n scope: principal.scope ?? 'all-apis',\n });\n if (principal.clientId) params.set('client_id', principal.clientId);\n const response = await fetch(`${host}/oidc/v1/token`, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: params,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Databricks federated token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n if (typeof value.access_token !== 'string' || !value.access_token) {\n throw new Error('Databricks federated token exchange returned no access_token.');\n }\n const expiresInSeconds = typeof value.expires_in === 'number' ? value.expires_in : 3_600;\n cached = {\n token: value.access_token,\n refreshAtMs: Date.now() + expiresInSeconds * 1_000 - refreshSkewMs,\n };\n return value.access_token;\n };\n\n const getToken: DatabricksTokenProvider = async () => {\n if (cached && Date.now() < cached.refreshAtMs) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n getToken.refresh = async () => {\n cached = undefined;\n return getToken();\n };\n return getToken;\n}\n\nexport interface LakebaseCredentialProviderOptions {\n workspaceHost: string;\n endpoint: string;\n token: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n refreshBeforeMs?: number;\n refreshJitterMs?: number;\n now?: () => number;\n random?: () => number;\n}\n\ninterface LakebaseCredentialResponse {\n token?: unknown;\n expire_time?: unknown;\n}\n\nexport interface LakebaseCredential {\n token: string;\n expiresAt: number;\n}\n\nexport interface ExchangeLakebaseCredentialOptions {\n workspaceHost: string;\n endpoint: string;\n workspaceToken: string;\n fetchImpl?: typeof fetch;\n}\n\n/** Perform one uncached workspace-token to Lakebase-credential exchange. */\nexport async function exchangeLakebaseCredential(\n options: ExchangeLakebaseCredentialOptions,\n): Promise<LakebaseCredential> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const response = await fetchImpl(\n `${options.workspaceHost.replace(/\\/$/, '')}/api/2.0/postgres/credentials`,\n {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.workspaceToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ endpoint: options.endpoint }),\n },\n );\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as LakebaseCredentialResponse;\n if (typeof value.token !== 'string' || !value.token) {\n throw new Error('Lakebase credential exchange returned no token.');\n }\n const expiresAt = parseExpireTime(value.expire_time);\n if (!Number.isFinite(expiresAt)) {\n throw new Error('Lakebase credential exchange returned an invalid expire_time.');\n }\n return { token: value.token, expiresAt };\n}\n\nexport type LakebaseCredentialProvider = (() => Promise<string>) & {\n /** Force both the workspace OAuth token and database credential to rotate. */\n refresh: () => Promise<string>;\n};\n\n/** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */\nexport function lakebaseCredentialProvider(\n options: LakebaseCredentialProviderOptions,\n): LakebaseCredentialProvider {\n const now = options.now ?? Date.now;\n const random = options.random ?? Math.random;\n const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 60_000;\n const refreshJitterMs = options.refreshJitterMs ?? 30_000;\n let cached: { token: string; refreshAt: number } | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (forceWorkspaceToken = false): Promise<string> => {\n const workspaceToken =\n typeof options.token === 'function'\n ? await (forceWorkspaceToken && options.token.refresh\n ? options.token.refresh()\n : options.token())\n : options.token;\n const value = await exchangeLakebaseCredential({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n workspaceToken,\n fetchImpl: options.fetchImpl,\n });\n const jitter = Math.max(0, refreshJitterMs) * random();\n cached = {\n token: value.token,\n refreshAt: Math.max(now(), value.expiresAt - Math.max(0, refreshBeforeMs) - jitter),\n };\n return value.token;\n };\n\n const getCredential: LakebaseCredentialProvider = async () => {\n if (cached && now() < cached.refreshAt) return cached.token;\n refreshing ??= refresh(false).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getCredential.refresh = async () => {\n cached = undefined;\n refreshing ??= refresh(true).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n return getCredential;\n}\n\nfunction parseExpireTime(value: unknown): number {\n if (typeof value === 'number') {\n return value < 1_000_000_000_000 ? value * 1_000 : value;\n }\n if (typeof value === 'string') return new Date(value).getTime();\n return Number.NaN;\n}\n\nexport interface LakebasePoolConfig {\n host: string;\n port: number;\n database: string;\n user: string;\n password?: string;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** Postgres `options` connection parameter, e.g. `-c search_path=fx,public`. */\n options?: string;\n}\n\nexport type LakebasePoolFactory = (config: LakebasePoolConfig) => Pool;\n\nexport interface LakebaseProviderOptions {\n /** Direct endpoint host from list-endpoints (NOT the pooled host). */\n host: string;\n port?: number;\n database: string;\n user: string;\n /** Static database password. If omitted, OAuth exchange is required. */\n password?: string;\n /** Workspace URL, e.g. https://adb-....azuredatabricks.net */\n workspaceHost?: string;\n /** Full endpoint resource name: projects/.../branches/.../endpoints/... */\n endpoint?: string;\n /** Workspace OAuth token or provider. */\n token?: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** How often to force-refresh the credential and recreate the pool. Default 45 minutes. */\n refreshIntervalMs?: number;\n /** Injected pool factory for tests. */\n poolFactory?: LakebasePoolFactory;\n /** Observe recoverable idle pooled-connection failures. */\n onPoolError?: (error: Error) => void;\n}\n\n/** A Pool-like facade that lazily initializes and always delegates to the current underlying pool. */\nclass DelegatingPool extends EventEmitter {\n private current: Pool | undefined;\n private initPromise: Promise<void> | undefined;\n private closed = false;\n\n private attachErrorHandler(pool: Pool) {\n pool.on('error', (error) => {\n this.emit('error', error);\n });\n }\n\n initialize(createPool: (password: string) => Pool, getPassword: () => Promise<string>) {\n this.initPromise = getPassword()\n .then((password) => {\n if (!this.closed) this.swap(createPool(password));\n })\n .catch((error) => {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n throw error;\n });\n }\n\n swap(pool: Pool) {\n if (this.closed) {\n pool.end().catch(() => undefined);\n return;\n }\n const previous = this.current;\n this.current = pool;\n this.attachErrorHandler(pool);\n if (previous) {\n previous.removeAllListeners();\n previous.end().catch(() => undefined);\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) await this.initPromise;\n }\n\n query(...args: Parameters<Pool['query']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.query(...args));\n }\n\n connect(...args: Parameters<Pool['connect']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.connect(...args));\n }\n\n end(): Promise<void> {\n this.closed = true;\n this.removeAllListeners();\n return this.current?.end() ?? Promise.resolve();\n }\n\n get totalCount() {\n return this.current?.totalCount ?? 0;\n }\n\n get idleCount() {\n return this.current?.idleCount ?? 0;\n }\n\n get waitingCount() {\n return this.current?.waitingCount ?? 0;\n }\n}\n\n/** Databricks Lakebase Postgres provider with credential refresh. */\nexport class LakebaseDatabaseProvider implements DatabaseProvider {\n readonly kind = 'databricks-lakebase' as const;\n private readonly options: LakebaseProviderOptions;\n private readonly poolFactory: LakebasePoolFactory;\n private readonly getPassword: () => Promise<string>;\n private readonly refreshPassword: () => Promise<string>;\n private readonly delegatingPool: DelegatingPool;\n private refreshTimer: NodeJS.Timeout | undefined;\n\n constructor(options: LakebaseProviderOptions) {\n this.options = options;\n this.poolFactory = options.poolFactory ?? defaultPoolFactory();\n this.delegatingPool = new DelegatingPool();\n if (options.password !== undefined) {\n this.getPassword = async () => options.password as string;\n this.refreshPassword = this.getPassword;\n this.delegatingPool.swap(this.createPool(options.password));\n } else {\n if (!options.token || !options.workspaceHost || !options.endpoint) {\n throw new Error(\n 'Lakebase OAuth requires token, workspaceHost, and endpoint. A workspace token cannot be used directly as the Postgres password.',\n );\n }\n const credential = lakebaseCredentialProvider({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n token: options.token,\n fetchImpl: options.fetchImpl,\n });\n this.getPassword = credential;\n this.refreshPassword = credential.refresh;\n this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);\n const intervalMs = options.refreshIntervalMs ?? 45 * 60_000;\n this.refreshTimer = setInterval(() => {\n void this.refreshCredentials().catch((error) => {\n this.delegatingPool.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n });\n }, intervalMs);\n }\n }\n\n private createPool(password?: string): Pool {\n return this.poolFactory({\n host: this.options.host,\n port: this.options.port ?? 5432,\n database: this.options.database,\n user: this.options.user,\n password,\n ssl: this.options.ssl ?? { rejectUnauthorized: true },\n max: this.options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis: this.options.idleTimeoutMillis ?? 30_000,\n connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5_000,\n options: '-c search_path=fx,public',\n });\n }\n\n /** Force a new database credential and atomically swap the active pool. */\n async refreshCredentials(): Promise<void> {\n const password = await this.refreshPassword();\n const pool = this.createPool(password);\n this.delegatingPool.swap(pool);\n }\n\n getPool(): Pool {\n return this.delegatingPool as unknown as Pool;\n }\n\n async close(): Promise<void> {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n await this.delegatingPool.end();\n }\n}\n\nfunction defaultPoolFactory(): LakebasePoolFactory {\n return (config) => new Pool(config);\n}\n","import type { Gauge, MetricsCollector } from '@fabricorg/experiments-metrics';\nimport type { Pool } from 'pg';\nimport {\n type DatabaseProvider,\n LakebaseDatabaseProvider,\n NeonDatabaseProvider,\n databricksIdentity,\n databricksPrincipalFromEnv,\n} from './providers/index.js';\n\nexport {\n LakebaseDatabaseProvider,\n exchangeLakebaseCredential,\n lakebaseCredentialProvider,\n type ExchangeLakebaseCredentialOptions,\n type LakebaseCredential,\n type LakebasePoolFactory,\n type LakebaseProviderOptions,\n} from './providers/index.js';\n\nlet provider: DatabaseProvider | null = null;\n\nfunction createProvider(): DatabaseProvider {\n const kind = process.env.DATABASE_PROVIDER ?? 'neon';\n\n if (kind === 'databricks-lakebase') {\n const host = process.env.DATABRICKS_LAKEBASE_HOST?.trim();\n const database = process.env.DATABRICKS_LAKEBASE_DATABASE?.trim() ?? 'databricks_postgres';\n const user = process.env.DATABRICKS_LAKEBASE_USER?.trim();\n const workspaceHost = process.env.DATABRICKS_HOST?.trim();\n const endpoint = process.env.DATABRICKS_LAKEBASE_ENDPOINT?.trim();\n const password = process.env.DATABRICKS_LAKEBASE_PASSWORD?.trim();\n\n if (!host) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_HOST is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n if (!user) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_USER is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n\n if (password) {\n return new LakebaseDatabaseProvider({ host, database, user, password });\n }\n\n if (!workspaceHost || !endpoint) {\n throw new Error(\n 'DATABRICKS_HOST and DATABRICKS_LAKEBASE_ENDPOINT are required for Lakebase OAuth, or provide DATABRICKS_LAKEBASE_PASSWORD for native auth.',\n );\n }\n\n const principal = databricksPrincipalFromEnv(process.env);\n return new LakebaseDatabaseProvider({\n host,\n database,\n user,\n workspaceHost,\n endpoint,\n token: databricksIdentity(principal),\n });\n }\n\n const connectionString = process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error('DATABASE_URL is required');\n }\n return new NeonDatabaseProvider({ connectionString });\n}\n\n/**\n * Return a singleton `pg.Pool` configured for the active database provider.\n *\n * Provider selection:\n * - `DATABASE_PROVIDER=neon` (default): uses `DATABASE_URL`.\n * - `DATABASE_PROVIDER=databricks-lakebase`: uses Lakebase OAuth credentials.\n *\n * On the first call, a new Pool is created with the following defaults:\n * - `max`: parseInt(process.env.PG_POOL_MAX ?? '5') — caps concurrent connections.\n * - `idleTimeoutMillis`: 30000 — recycle idle connections before Vercel's 60s timeout.\n * - `connectionTimeoutMillis`: 5000 — fail fast when the database is unreachable.\n */\nexport function getPool(): Pool {\n if (!provider) {\n provider = createProvider();\n }\n return provider.getPool();\n}\n\n/** Close the active provider and any background refresh loops. */\nexport async function closePool(): Promise<void> {\n await provider?.close();\n provider = null;\n}\n\n/** Reset the singleton provider. Intended for tests. */\nexport function resetPoolProvider(): void {\n provider = null;\n}\n\n/** Return the active provider, or create it. */\nexport function getProvider(): DatabaseProvider {\n if (!provider) {\n provider = createProvider();\n }\n return provider;\n}\n\ninterface PoolGauges {\n total: Gauge;\n idle: Gauge;\n waiting: Gauge;\n active: Gauge;\n}\n\nfunction ensurePoolGauges(collector: MetricsCollector): PoolGauges {\n const reg = collector.registry;\n const existingTotal = reg.get('db_pool_connections_total');\n if (existingTotal) {\n return {\n total: existingTotal as Gauge,\n idle: reg.get('db_pool_connections_idle') as Gauge,\n waiting: reg.get('db_pool_connections_waiting') as Gauge,\n active: reg.get('db_pool_connections_active') as Gauge,\n };\n }\n\n return {\n total: collector.gauge('db_pool_connections_total', 'Total connections in the pool'),\n idle: collector.gauge('db_pool_connections_idle', 'Idle connections in the pool'),\n waiting: collector.gauge('db_pool_connections_waiting', 'Waiting clients in the pool'),\n active: collector.gauge(\n 'db_pool_connections_active',\n 'Active (non-idle) connections in the pool',\n ),\n };\n}\n\n/** Update pool gauge values from the current pool state. */\nexport function updatePoolMetrics(collector: MetricsCollector, poolInstance?: Pool): void {\n const p = poolInstance ?? getPool();\n const total = (p as unknown as { totalCount: number }).totalCount ?? 0;\n const idle = p.idleCount ?? 0;\n const waiting = p.waitingCount ?? 0;\n\n const gauges = ensurePoolGauges(collector);\n gauges.total.set({}, total);\n gauges.idle.set({}, idle);\n gauges.waiting.set({}, waiting);\n gauges.active.set({}, Math.max(0, total - idle));\n}\n\n/**\n * Register pool metrics with the given collector.\n *\n * Returns a cleanup function that stops the update interval.\n */\nexport function registerPoolMetrics(\n collector: MetricsCollector,\n poolInstance?: Pool,\n intervalMs = 5000,\n): () => void {\n updatePoolMetrics(collector, poolInstance);\n\n const interval = setInterval(() => {\n updatePoolMetrics(collector, poolInstance);\n }, intervalMs);\n\n return () => clearInterval(interval);\n}\n"]}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Pool } from 'pg';
2
2
  import { EventEmitter } from 'events';
3
+ import { readFile } from 'fs/promises';
3
4
 
4
5
  // src/providers/neon.ts
5
6
  var NeonDatabaseProvider = class {
@@ -9,8 +10,16 @@ var NeonDatabaseProvider = class {
9
10
  this.pool = new Pool({
10
11
  connectionString: options.connectionString,
11
12
  max: options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? "5", 10),
12
- idleTimeoutMillis: options.idleTimeoutMillis ?? 3e4,
13
- connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5e3
13
+ idleTimeoutMillis: options.idleTimeoutMillis ?? Number.parseInt(process.env.PG_POOL_IDLE_TIMEOUT_MS ?? "30000", 10),
14
+ connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5e3,
15
+ // Cloudflare request isolates cannot safely carry a TCP client owned by
16
+ // one request into the next. Set PG_POOL_MAX_USES=1 there so release()
17
+ // destroys the client synchronously; conventional Node runtimes retain
18
+ // pg-pool's effectively-unbounded default.
19
+ maxUses: Number.parseInt(process.env.PG_POOL_MAX_USES ?? "7500", 10),
20
+ // Lets an edge isolate release its final idle socket instead of keeping
21
+ // an I/O handle owned by a completed request alive indefinitely.
22
+ allowExitOnIdle: true
14
23
  });
15
24
  }
16
25
  getPool() {
@@ -25,9 +34,37 @@ function databricksIdentity(principal) {
25
34
  const { token } = principal;
26
35
  return async () => token;
27
36
  }
37
+ if (principal.kind === "federated") return federatedIdentityProvider(principal);
28
38
  return servicePrincipalProvider(principal);
29
39
  }
30
40
  function databricksPrincipalFromEnv(env = typeof process !== "undefined" ? process.env : {}) {
41
+ const authType = env.DATABRICKS_AUTH_TYPE?.trim();
42
+ if (authType === "env-oidc" || authType === "file-oidc") {
43
+ const host2 = env.DATABRICKS_HOST?.trim();
44
+ if (!host2) throw new Error("Missing DATABRICKS_HOST for Databricks OAuth federation.");
45
+ return {
46
+ kind: "federated",
47
+ host: host2,
48
+ clientId: env.DATABRICKS_CLIENT_ID?.trim() || void 0,
49
+ scope: env.DATABRICKS_SCOPE,
50
+ refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10) : void 0,
51
+ subjectToken: async () => {
52
+ if (authType === "env-oidc") {
53
+ const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV?.trim() || "DATABRICKS_OIDC_TOKEN";
54
+ const token3 = env[tokenEnv]?.trim();
55
+ if (!token3) throw new Error(`Databricks OIDC token environment ${tokenEnv} is empty.`);
56
+ return token3;
57
+ }
58
+ const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH?.trim();
59
+ if (!path) {
60
+ throw new Error("Missing DATABRICKS_OIDC_TOKEN_FILEPATH for file-oidc federation.");
61
+ }
62
+ const token2 = (await readFile(path, "utf8")).trim();
63
+ if (!token2) throw new Error(`Databricks OIDC token file ${path} is empty.`);
64
+ return token2;
65
+ }
66
+ };
67
+ }
31
68
  const token = env.DATABRICKS_TOKEN?.trim();
32
69
  if (token) return { kind: "pat", token };
33
70
  const clientId = env.DATABRICKS_CLIENT_ID?.trim();
@@ -45,7 +82,7 @@ function databricksPrincipalFromEnv(env = typeof process !== "undefined" ? proce
45
82
  };
46
83
  }
47
84
  throw new Error(
48
- "Missing Databricks credentials: DATABRICKS_TOKEN or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET."
85
+ "Missing Databricks credentials: env/file OIDC federation, DATABRICKS_TOKEN, or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET."
49
86
  );
50
87
  }
51
88
  function servicePrincipalProvider(principal) {
@@ -90,6 +127,54 @@ function servicePrincipalProvider(principal) {
90
127
  };
91
128
  return getToken;
92
129
  }
130
+ function federatedIdentityProvider(principal) {
131
+ const host = principal.host.replace(/\/$/, "");
132
+ const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1e3;
133
+ let cached;
134
+ let refreshing;
135
+ const refresh = async () => {
136
+ const params = new URLSearchParams({
137
+ grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
138
+ subject_token: await principal.subjectToken(),
139
+ subject_token_type: "urn:ietf:params:oauth:token-type:jwt",
140
+ scope: principal.scope ?? "all-apis"
141
+ });
142
+ if (principal.clientId) params.set("client_id", principal.clientId);
143
+ const response = await fetch(`${host}/oidc/v1/token`, {
144
+ method: "POST",
145
+ headers: { "content-type": "application/x-www-form-urlencoded" },
146
+ body: params
147
+ });
148
+ if (!response.ok) {
149
+ const text = await response.text();
150
+ throw new Error(
151
+ `Databricks federated token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
152
+ );
153
+ }
154
+ const value = await response.json();
155
+ if (typeof value.access_token !== "string" || !value.access_token) {
156
+ throw new Error("Databricks federated token exchange returned no access_token.");
157
+ }
158
+ const expiresInSeconds = typeof value.expires_in === "number" ? value.expires_in : 3600;
159
+ cached = {
160
+ token: value.access_token,
161
+ refreshAtMs: Date.now() + expiresInSeconds * 1e3 - refreshSkewMs
162
+ };
163
+ return value.access_token;
164
+ };
165
+ const getToken = async () => {
166
+ if (cached && Date.now() < cached.refreshAtMs) return cached.token;
167
+ refreshing ??= refresh().finally(() => {
168
+ refreshing = void 0;
169
+ });
170
+ return refreshing;
171
+ };
172
+ getToken.refresh = async () => {
173
+ cached = void 0;
174
+ return getToken();
175
+ };
176
+ return getToken;
177
+ }
93
178
  async function exchangeLakebaseCredential(options) {
94
179
  const fetchImpl = options.fetchImpl ?? fetch;
95
180
  const response = await fetchImpl(
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/providers/neon.ts","../src/providers/lakebase.ts","../src/index.ts"],"names":["Pool"],"mappings":"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","file":"index.js","sourcesContent":["import { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\nexport interface NeonProviderOptions {\n connectionString: string;\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n}\n\n/** Standard Postgres provider using a static connection string. */\nexport class NeonDatabaseProvider implements DatabaseProvider {\n readonly kind = 'neon' as const;\n private readonly pool: Pool;\n\n constructor(options: NeonProviderOptions) {\n this.pool = new Pool({\n connectionString: options.connectionString,\n max: options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis: options.idleTimeoutMillis ?? 30_000,\n connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5_000,\n });\n }\n\n getPool(): Pool {\n return this.pool;\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n","import { EventEmitter } from 'node:events';\nimport { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\n/** A resolver that returns a valid Databricks workspace OAuth token. */\nexport type DatabricksTokenProvider = (() => Promise<string>) & {\n /** Bypass the cache and obtain a new token when the downstream credential is rotated. */\n refresh?: () => Promise<string>;\n};\n\n/** Supported Databricks authentication shapes. */\nexport type DatabricksPrincipal =\n | { kind: 'pat'; token: string }\n | {\n kind: 'service-principal';\n host: string;\n clientId: string;\n clientSecret: string;\n scope?: string;\n refreshSkewSeconds?: number;\n };\n\n/** Resolve a PAT or OAuth M2M principal to a cached, auto-refreshing token provider. */\nexport function databricksIdentity(principal: DatabricksPrincipal): DatabricksTokenProvider {\n if (principal.kind === 'pat') {\n const { token } = principal;\n return async () => token;\n }\n return servicePrincipalProvider(principal);\n}\n\n/** Build a principal from environment variables. */\nexport function databricksPrincipalFromEnv(\n env: Record<string, string | undefined> = typeof process !== 'undefined' ? process.env : {},\n): Extract<DatabricksPrincipal, { kind: 'pat' | 'service-principal' }> {\n const token = env.DATABRICKS_TOKEN?.trim();\n if (token) return { kind: 'pat', token };\n\n const clientId = env.DATABRICKS_CLIENT_ID?.trim();\n const clientSecret = env.DATABRICKS_CLIENT_SECRET?.trim();\n const host = env.DATABRICKS_HOST?.trim();\n if (clientId && clientSecret) {\n if (!host) throw new Error('Missing DATABRICKS_HOST for Databricks OAuth M2M.');\n return {\n kind: 'service-principal',\n host,\n clientId,\n clientSecret,\n scope: env.DATABRICKS_SCOPE,\n refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS\n ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10)\n : undefined,\n };\n }\n throw new Error(\n 'Missing Databricks credentials: DATABRICKS_TOKEN or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET.',\n );\n}\n\ninterface CachedToken {\n token: string;\n refreshAtMs: number;\n}\n\nfunction servicePrincipalProvider(\n principal: Extract<DatabricksPrincipal, { kind: 'service-principal' }>,\n): DatabricksTokenProvider {\n const host = principal.host.replace(/\\/$/, '');\n const scope = principal.scope ?? 'all-apis';\n const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1_000;\n let cached: CachedToken | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (): Promise<string> => {\n const response = await fetch(`${host}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${principal.clientId}:${principal.clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({ grant_type: 'client_credentials', scope }),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Databricks OAuth token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n const token = typeof value.access_token === 'string' ? value.access_token : undefined;\n if (!token) throw new Error('Databricks OAuth token exchange returned no access_token.');\n const expiresInSeconds = typeof value.expires_in === 'number' ? value.expires_in : 3_600;\n const expiresAtMs = Date.now() + expiresInSeconds * 1_000;\n cached = { token, refreshAtMs: expiresAtMs - refreshSkewMs };\n return token;\n };\n\n const getToken: DatabricksTokenProvider = async () => {\n if (cached && Date.now() < cached.refreshAtMs) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getToken.refresh = async () => {\n cached = undefined;\n return getToken();\n };\n\n return getToken;\n}\n\nexport interface LakebaseCredentialProviderOptions {\n workspaceHost: string;\n endpoint: string;\n token: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n refreshBeforeMs?: number;\n refreshJitterMs?: number;\n now?: () => number;\n random?: () => number;\n}\n\ninterface LakebaseCredentialResponse {\n token?: unknown;\n expire_time?: unknown;\n}\n\nexport interface LakebaseCredential {\n token: string;\n expiresAt: number;\n}\n\nexport interface ExchangeLakebaseCredentialOptions {\n workspaceHost: string;\n endpoint: string;\n workspaceToken: string;\n fetchImpl?: typeof fetch;\n}\n\n/** Perform one uncached workspace-token to Lakebase-credential exchange. */\nexport async function exchangeLakebaseCredential(\n options: ExchangeLakebaseCredentialOptions,\n): Promise<LakebaseCredential> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const response = await fetchImpl(\n `${options.workspaceHost.replace(/\\/$/, '')}/api/2.0/postgres/credentials`,\n {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.workspaceToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ endpoint: options.endpoint }),\n },\n );\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as LakebaseCredentialResponse;\n if (typeof value.token !== 'string' || !value.token) {\n throw new Error('Lakebase credential exchange returned no token.');\n }\n const expiresAt = parseExpireTime(value.expire_time);\n if (!Number.isFinite(expiresAt)) {\n throw new Error('Lakebase credential exchange returned an invalid expire_time.');\n }\n return { token: value.token, expiresAt };\n}\n\nexport type LakebaseCredentialProvider = (() => Promise<string>) & {\n /** Force both the workspace OAuth token and database credential to rotate. */\n refresh: () => Promise<string>;\n};\n\n/** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */\nexport function lakebaseCredentialProvider(\n options: LakebaseCredentialProviderOptions,\n): LakebaseCredentialProvider {\n const now = options.now ?? Date.now;\n const random = options.random ?? Math.random;\n const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 60_000;\n const refreshJitterMs = options.refreshJitterMs ?? 30_000;\n let cached: { token: string; refreshAt: number } | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (forceWorkspaceToken = false): Promise<string> => {\n const workspaceToken =\n typeof options.token === 'function'\n ? await (forceWorkspaceToken && options.token.refresh\n ? options.token.refresh()\n : options.token())\n : options.token;\n const value = await exchangeLakebaseCredential({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n workspaceToken,\n fetchImpl: options.fetchImpl,\n });\n const jitter = Math.max(0, refreshJitterMs) * random();\n cached = {\n token: value.token,\n refreshAt: Math.max(now(), value.expiresAt - Math.max(0, refreshBeforeMs) - jitter),\n };\n return value.token;\n };\n\n const getCredential: LakebaseCredentialProvider = async () => {\n if (cached && now() < cached.refreshAt) return cached.token;\n refreshing ??= refresh(false).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getCredential.refresh = async () => {\n cached = undefined;\n refreshing ??= refresh(true).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n return getCredential;\n}\n\nfunction parseExpireTime(value: unknown): number {\n if (typeof value === 'number') {\n return value < 1_000_000_000_000 ? value * 1_000 : value;\n }\n if (typeof value === 'string') return new Date(value).getTime();\n return Number.NaN;\n}\n\nexport interface LakebasePoolConfig {\n host: string;\n port: number;\n database: string;\n user: string;\n password?: string;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** Postgres `options` connection parameter, e.g. `-c search_path=fx,public`. */\n options?: string;\n}\n\nexport type LakebasePoolFactory = (config: LakebasePoolConfig) => Pool;\n\nexport interface LakebaseProviderOptions {\n /** Direct endpoint host from list-endpoints (NOT the pooled host). */\n host: string;\n port?: number;\n database: string;\n user: string;\n /** Static database password. If omitted, OAuth exchange is required. */\n password?: string;\n /** Workspace URL, e.g. https://adb-....azuredatabricks.net */\n workspaceHost?: string;\n /** Full endpoint resource name: projects/.../branches/.../endpoints/... */\n endpoint?: string;\n /** Workspace OAuth token or provider. */\n token?: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** How often to force-refresh the credential and recreate the pool. Default 45 minutes. */\n refreshIntervalMs?: number;\n /** Injected pool factory for tests. */\n poolFactory?: LakebasePoolFactory;\n /** Observe recoverable idle pooled-connection failures. */\n onPoolError?: (error: Error) => void;\n}\n\n/** A Pool-like facade that lazily initializes and always delegates to the current underlying pool. */\nclass DelegatingPool extends EventEmitter {\n private current: Pool | undefined;\n private initPromise: Promise<void> | undefined;\n private closed = false;\n\n private attachErrorHandler(pool: Pool) {\n pool.on('error', (error) => {\n this.emit('error', error);\n });\n }\n\n initialize(createPool: (password: string) => Pool, getPassword: () => Promise<string>) {\n this.initPromise = getPassword()\n .then((password) => {\n if (!this.closed) this.swap(createPool(password));\n })\n .catch((error) => {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n throw error;\n });\n }\n\n swap(pool: Pool) {\n if (this.closed) {\n pool.end().catch(() => undefined);\n return;\n }\n const previous = this.current;\n this.current = pool;\n this.attachErrorHandler(pool);\n if (previous) {\n previous.removeAllListeners();\n previous.end().catch(() => undefined);\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) await this.initPromise;\n }\n\n query(...args: Parameters<Pool['query']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.query(...args));\n }\n\n connect(...args: Parameters<Pool['connect']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.connect(...args));\n }\n\n end(): Promise<void> {\n this.closed = true;\n this.removeAllListeners();\n return this.current?.end() ?? Promise.resolve();\n }\n\n get totalCount() {\n return this.current?.totalCount ?? 0;\n }\n\n get idleCount() {\n return this.current?.idleCount ?? 0;\n }\n\n get waitingCount() {\n return this.current?.waitingCount ?? 0;\n }\n}\n\n/** Databricks Lakebase Postgres provider with credential refresh. */\nexport class LakebaseDatabaseProvider implements DatabaseProvider {\n readonly kind = 'databricks-lakebase' as const;\n private readonly options: LakebaseProviderOptions;\n private readonly poolFactory: LakebasePoolFactory;\n private readonly getPassword: () => Promise<string>;\n private readonly refreshPassword: () => Promise<string>;\n private readonly delegatingPool: DelegatingPool;\n private refreshTimer: NodeJS.Timeout | undefined;\n\n constructor(options: LakebaseProviderOptions) {\n this.options = options;\n this.poolFactory = options.poolFactory ?? defaultPoolFactory();\n this.delegatingPool = new DelegatingPool();\n if (options.password !== undefined) {\n this.getPassword = async () => options.password as string;\n this.refreshPassword = this.getPassword;\n this.delegatingPool.swap(this.createPool(options.password));\n } else {\n if (!options.token || !options.workspaceHost || !options.endpoint) {\n throw new Error(\n 'Lakebase OAuth requires token, workspaceHost, and endpoint. A workspace token cannot be used directly as the Postgres password.',\n );\n }\n const credential = lakebaseCredentialProvider({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n token: options.token,\n fetchImpl: options.fetchImpl,\n });\n this.getPassword = credential;\n this.refreshPassword = credential.refresh;\n this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);\n const intervalMs = options.refreshIntervalMs ?? 45 * 60_000;\n this.refreshTimer = setInterval(() => {\n void this.refreshCredentials().catch((error) => {\n this.delegatingPool.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n });\n }, intervalMs);\n }\n }\n\n private createPool(password?: string): Pool {\n return this.poolFactory({\n host: this.options.host,\n port: this.options.port ?? 5432,\n database: this.options.database,\n user: this.options.user,\n password,\n ssl: this.options.ssl ?? { rejectUnauthorized: true },\n max: this.options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis: this.options.idleTimeoutMillis ?? 30_000,\n connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5_000,\n options: '-c search_path=fx,public',\n });\n }\n\n /** Force a new database credential and atomically swap the active pool. */\n async refreshCredentials(): Promise<void> {\n const password = await this.refreshPassword();\n const pool = this.createPool(password);\n this.delegatingPool.swap(pool);\n }\n\n getPool(): Pool {\n return this.delegatingPool as unknown as Pool;\n }\n\n async close(): Promise<void> {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n await this.delegatingPool.end();\n }\n}\n\nfunction defaultPoolFactory(): LakebasePoolFactory {\n return (config) => new Pool(config);\n}\n","import type { Gauge, MetricsCollector } from '@fabricorg/experiments-metrics';\nimport type { Pool } from 'pg';\nimport {\n type DatabaseProvider,\n LakebaseDatabaseProvider,\n NeonDatabaseProvider,\n databricksIdentity,\n databricksPrincipalFromEnv,\n} from './providers/index.js';\n\nexport {\n LakebaseDatabaseProvider,\n exchangeLakebaseCredential,\n lakebaseCredentialProvider,\n type ExchangeLakebaseCredentialOptions,\n type LakebaseCredential,\n type LakebasePoolFactory,\n type LakebaseProviderOptions,\n} from './providers/index.js';\n\nlet provider: DatabaseProvider | null = null;\n\nfunction createProvider(): DatabaseProvider {\n const kind = process.env.DATABASE_PROVIDER ?? 'neon';\n\n if (kind === 'databricks-lakebase') {\n const host = process.env.DATABRICKS_LAKEBASE_HOST?.trim();\n const database = process.env.DATABRICKS_LAKEBASE_DATABASE?.trim() ?? 'databricks_postgres';\n const user = process.env.DATABRICKS_LAKEBASE_USER?.trim();\n const workspaceHost = process.env.DATABRICKS_HOST?.trim();\n const endpoint = process.env.DATABRICKS_LAKEBASE_ENDPOINT?.trim();\n const password = process.env.DATABRICKS_LAKEBASE_PASSWORD?.trim();\n\n if (!host) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_HOST is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n if (!user) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_USER is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n\n if (password) {\n return new LakebaseDatabaseProvider({ host, database, user, password });\n }\n\n if (!workspaceHost || !endpoint) {\n throw new Error(\n 'DATABRICKS_HOST and DATABRICKS_LAKEBASE_ENDPOINT are required for Lakebase OAuth, or provide DATABRICKS_LAKEBASE_PASSWORD for native auth.',\n );\n }\n\n const principal = databricksPrincipalFromEnv(process.env);\n return new LakebaseDatabaseProvider({\n host,\n database,\n user,\n workspaceHost,\n endpoint,\n token: databricksIdentity(principal),\n });\n }\n\n const connectionString = process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error('DATABASE_URL is required');\n }\n return new NeonDatabaseProvider({ connectionString });\n}\n\n/**\n * Return a singleton `pg.Pool` configured for the active database provider.\n *\n * Provider selection:\n * - `DATABASE_PROVIDER=neon` (default): uses `DATABASE_URL`.\n * - `DATABASE_PROVIDER=databricks-lakebase`: uses Lakebase OAuth credentials.\n *\n * On the first call, a new Pool is created with the following defaults:\n * - `max`: parseInt(process.env.PG_POOL_MAX ?? '5') — caps concurrent connections.\n * - `idleTimeoutMillis`: 30000 — recycle idle connections before Vercel's 60s timeout.\n * - `connectionTimeoutMillis`: 5000 — fail fast when the database is unreachable.\n */\nexport function getPool(): Pool {\n if (!provider) {\n provider = createProvider();\n }\n return provider.getPool();\n}\n\n/** Close the active provider and any background refresh loops. */\nexport async function closePool(): Promise<void> {\n await provider?.close();\n provider = null;\n}\n\n/** Reset the singleton provider. Intended for tests. */\nexport function resetPoolProvider(): void {\n provider = null;\n}\n\n/** Return the active provider, or create it. */\nexport function getProvider(): DatabaseProvider {\n if (!provider) {\n provider = createProvider();\n }\n return provider;\n}\n\ninterface PoolGauges {\n total: Gauge;\n idle: Gauge;\n waiting: Gauge;\n active: Gauge;\n}\n\nfunction ensurePoolGauges(collector: MetricsCollector): PoolGauges {\n const reg = collector.registry;\n const existingTotal = reg.get('db_pool_connections_total');\n if (existingTotal) {\n return {\n total: existingTotal as Gauge,\n idle: reg.get('db_pool_connections_idle') as Gauge,\n waiting: reg.get('db_pool_connections_waiting') as Gauge,\n active: reg.get('db_pool_connections_active') as Gauge,\n };\n }\n\n return {\n total: collector.gauge('db_pool_connections_total', 'Total connections in the pool'),\n idle: collector.gauge('db_pool_connections_idle', 'Idle connections in the pool'),\n waiting: collector.gauge('db_pool_connections_waiting', 'Waiting clients in the pool'),\n active: collector.gauge(\n 'db_pool_connections_active',\n 'Active (non-idle) connections in the pool',\n ),\n };\n}\n\n/** Update pool gauge values from the current pool state. */\nexport function updatePoolMetrics(collector: MetricsCollector, poolInstance?: Pool): void {\n const p = poolInstance ?? getPool();\n const total = (p as unknown as { totalCount: number }).totalCount ?? 0;\n const idle = p.idleCount ?? 0;\n const waiting = p.waitingCount ?? 0;\n\n const gauges = ensurePoolGauges(collector);\n gauges.total.set({}, total);\n gauges.idle.set({}, idle);\n gauges.waiting.set({}, waiting);\n gauges.active.set({}, Math.max(0, total - idle));\n}\n\n/**\n * Register pool metrics with the given collector.\n *\n * Returns a cleanup function that stops the update interval.\n */\nexport function registerPoolMetrics(\n collector: MetricsCollector,\n poolInstance?: Pool,\n intervalMs = 5000,\n): () => void {\n updatePoolMetrics(collector, poolInstance);\n\n const interval = setInterval(() => {\n updatePoolMetrics(collector, poolInstance);\n }, intervalMs);\n\n return () => clearInterval(interval);\n}\n"]}
1
+ {"version":3,"sources":["../src/providers/neon.ts","../src/providers/lakebase.ts","../src/index.ts"],"names":["host","token","Pool"],"mappings":"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","file":"index.js","sourcesContent":["import { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\nexport interface NeonProviderOptions {\n connectionString: string;\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n}\n\n/** Standard Postgres provider using a static connection string. */\nexport class NeonDatabaseProvider implements DatabaseProvider {\n readonly kind = 'neon' as const;\n private readonly pool: Pool;\n\n constructor(options: NeonProviderOptions) {\n this.pool = new Pool({\n connectionString: options.connectionString,\n max: options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis:\n options.idleTimeoutMillis ??\n Number.parseInt(process.env.PG_POOL_IDLE_TIMEOUT_MS ?? '30000', 10),\n connectionTimeoutMillis: options.connectionTimeoutMillis ?? 5_000,\n // Cloudflare request isolates cannot safely carry a TCP client owned by\n // one request into the next. Set PG_POOL_MAX_USES=1 there so release()\n // destroys the client synchronously; conventional Node runtimes retain\n // pg-pool's effectively-unbounded default.\n maxUses: Number.parseInt(process.env.PG_POOL_MAX_USES ?? '7500', 10),\n // Lets an edge isolate release its final idle socket instead of keeping\n // an I/O handle owned by a completed request alive indefinitely.\n allowExitOnIdle: true,\n });\n }\n\n getPool(): Pool {\n return this.pool;\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n","import { EventEmitter } from 'node:events';\nimport { readFile } from 'node:fs/promises';\nimport { Pool } from 'pg';\nimport type { DatabaseProvider } from './types.js';\n\n/** A resolver that returns a valid Databricks workspace OAuth token. */\nexport type DatabricksTokenProvider = (() => Promise<string>) & {\n /** Bypass the cache and obtain a new token when the downstream credential is rotated. */\n refresh?: () => Promise<string>;\n};\n\n/** Supported Databricks authentication shapes. */\nexport type DatabricksPrincipal =\n | { kind: 'pat'; token: string }\n | {\n kind: 'service-principal';\n host: string;\n clientId: string;\n clientSecret: string;\n scope?: string;\n refreshSkewSeconds?: number;\n }\n | {\n kind: 'federated';\n host: string;\n clientId?: string;\n subjectToken: () => Promise<string>;\n scope?: string;\n refreshSkewSeconds?: number;\n };\n\n/** Resolve a PAT or OAuth M2M principal to a cached, auto-refreshing token provider. */\nexport function databricksIdentity(principal: DatabricksPrincipal): DatabricksTokenProvider {\n if (principal.kind === 'pat') {\n const { token } = principal;\n return async () => token;\n }\n if (principal.kind === 'federated') return federatedIdentityProvider(principal);\n return servicePrincipalProvider(principal);\n}\n\n/** Build a principal from environment variables. */\nexport function databricksPrincipalFromEnv(\n env: Record<string, string | undefined> = typeof process !== 'undefined' ? process.env : {},\n): DatabricksPrincipal {\n const authType = env.DATABRICKS_AUTH_TYPE?.trim();\n if (authType === 'env-oidc' || authType === 'file-oidc') {\n const host = env.DATABRICKS_HOST?.trim();\n if (!host) throw new Error('Missing DATABRICKS_HOST for Databricks OAuth federation.');\n return {\n kind: 'federated',\n host,\n clientId: env.DATABRICKS_CLIENT_ID?.trim() || undefined,\n scope: env.DATABRICKS_SCOPE,\n refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS\n ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10)\n : undefined,\n subjectToken: async () => {\n if (authType === 'env-oidc') {\n const tokenEnv = env.DATABRICKS_OIDC_TOKEN_ENV?.trim() || 'DATABRICKS_OIDC_TOKEN';\n const token = env[tokenEnv]?.trim();\n if (!token) throw new Error(`Databricks OIDC token environment ${tokenEnv} is empty.`);\n return token;\n }\n const path = env.DATABRICKS_OIDC_TOKEN_FILEPATH?.trim();\n if (!path) {\n throw new Error('Missing DATABRICKS_OIDC_TOKEN_FILEPATH for file-oidc federation.');\n }\n const token = (await readFile(path, 'utf8')).trim();\n if (!token) throw new Error(`Databricks OIDC token file ${path} is empty.`);\n return token;\n },\n };\n }\n const token = env.DATABRICKS_TOKEN?.trim();\n if (token) return { kind: 'pat', token };\n\n const clientId = env.DATABRICKS_CLIENT_ID?.trim();\n const clientSecret = env.DATABRICKS_CLIENT_SECRET?.trim();\n const host = env.DATABRICKS_HOST?.trim();\n if (clientId && clientSecret) {\n if (!host) throw new Error('Missing DATABRICKS_HOST for Databricks OAuth M2M.');\n return {\n kind: 'service-principal',\n host,\n clientId,\n clientSecret,\n scope: env.DATABRICKS_SCOPE,\n refreshSkewSeconds: env.DATABRICKS_REFRESH_SKEW_SECONDS\n ? Number.parseInt(env.DATABRICKS_REFRESH_SKEW_SECONDS, 10)\n : undefined,\n };\n }\n throw new Error(\n 'Missing Databricks credentials: env/file OIDC federation, DATABRICKS_TOKEN, or DATABRICKS_CLIENT_ID+DATABRICKS_CLIENT_SECRET.',\n );\n}\n\ninterface CachedToken {\n token: string;\n refreshAtMs: number;\n}\n\nfunction servicePrincipalProvider(\n principal: Extract<DatabricksPrincipal, { kind: 'service-principal' }>,\n): DatabricksTokenProvider {\n const host = principal.host.replace(/\\/$/, '');\n const scope = principal.scope ?? 'all-apis';\n const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1_000;\n let cached: CachedToken | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (): Promise<string> => {\n const response = await fetch(`${host}/oidc/v1/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${principal.clientId}:${principal.clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({ grant_type: 'client_credentials', scope }),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Databricks OAuth token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n const token = typeof value.access_token === 'string' ? value.access_token : undefined;\n if (!token) throw new Error('Databricks OAuth token exchange returned no access_token.');\n const expiresInSeconds = typeof value.expires_in === 'number' ? value.expires_in : 3_600;\n const expiresAtMs = Date.now() + expiresInSeconds * 1_000;\n cached = { token, refreshAtMs: expiresAtMs - refreshSkewMs };\n return token;\n };\n\n const getToken: DatabricksTokenProvider = async () => {\n if (cached && Date.now() < cached.refreshAtMs) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getToken.refresh = async () => {\n cached = undefined;\n return getToken();\n };\n\n return getToken;\n}\n\nfunction federatedIdentityProvider(\n principal: Extract<DatabricksPrincipal, { kind: 'federated' }>,\n): DatabricksTokenProvider {\n const host = principal.host.replace(/\\/$/, '');\n const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1_000;\n let cached: CachedToken | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (): Promise<string> => {\n const params = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n subject_token: await principal.subjectToken(),\n subject_token_type: 'urn:ietf:params:oauth:token-type:jwt',\n scope: principal.scope ?? 'all-apis',\n });\n if (principal.clientId) params.set('client_id', principal.clientId);\n const response = await fetch(`${host}/oidc/v1/token`, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: params,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Databricks federated token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as { access_token?: unknown; expires_in?: unknown };\n if (typeof value.access_token !== 'string' || !value.access_token) {\n throw new Error('Databricks federated token exchange returned no access_token.');\n }\n const expiresInSeconds = typeof value.expires_in === 'number' ? value.expires_in : 3_600;\n cached = {\n token: value.access_token,\n refreshAtMs: Date.now() + expiresInSeconds * 1_000 - refreshSkewMs,\n };\n return value.access_token;\n };\n\n const getToken: DatabricksTokenProvider = async () => {\n if (cached && Date.now() < cached.refreshAtMs) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n getToken.refresh = async () => {\n cached = undefined;\n return getToken();\n };\n return getToken;\n}\n\nexport interface LakebaseCredentialProviderOptions {\n workspaceHost: string;\n endpoint: string;\n token: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n refreshBeforeMs?: number;\n refreshJitterMs?: number;\n now?: () => number;\n random?: () => number;\n}\n\ninterface LakebaseCredentialResponse {\n token?: unknown;\n expire_time?: unknown;\n}\n\nexport interface LakebaseCredential {\n token: string;\n expiresAt: number;\n}\n\nexport interface ExchangeLakebaseCredentialOptions {\n workspaceHost: string;\n endpoint: string;\n workspaceToken: string;\n fetchImpl?: typeof fetch;\n}\n\n/** Perform one uncached workspace-token to Lakebase-credential exchange. */\nexport async function exchangeLakebaseCredential(\n options: ExchangeLakebaseCredentialOptions,\n): Promise<LakebaseCredential> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const response = await fetchImpl(\n `${options.workspaceHost.replace(/\\/$/, '')}/api/2.0/postgres/credentials`,\n {\n method: 'POST',\n headers: {\n authorization: `Bearer ${options.workspaceToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ endpoint: options.endpoint }),\n },\n );\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,\n );\n }\n const value = (await response.json()) as LakebaseCredentialResponse;\n if (typeof value.token !== 'string' || !value.token) {\n throw new Error('Lakebase credential exchange returned no token.');\n }\n const expiresAt = parseExpireTime(value.expire_time);\n if (!Number.isFinite(expiresAt)) {\n throw new Error('Lakebase credential exchange returned an invalid expire_time.');\n }\n return { token: value.token, expiresAt };\n}\n\nexport type LakebaseCredentialProvider = (() => Promise<string>) & {\n /** Force both the workspace OAuth token and database credential to rotate. */\n refresh: () => Promise<string>;\n};\n\n/** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */\nexport function lakebaseCredentialProvider(\n options: LakebaseCredentialProviderOptions,\n): LakebaseCredentialProvider {\n const now = options.now ?? Date.now;\n const random = options.random ?? Math.random;\n const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 60_000;\n const refreshJitterMs = options.refreshJitterMs ?? 30_000;\n let cached: { token: string; refreshAt: number } | undefined;\n let refreshing: Promise<string> | undefined;\n\n const refresh = async (forceWorkspaceToken = false): Promise<string> => {\n const workspaceToken =\n typeof options.token === 'function'\n ? await (forceWorkspaceToken && options.token.refresh\n ? options.token.refresh()\n : options.token())\n : options.token;\n const value = await exchangeLakebaseCredential({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n workspaceToken,\n fetchImpl: options.fetchImpl,\n });\n const jitter = Math.max(0, refreshJitterMs) * random();\n cached = {\n token: value.token,\n refreshAt: Math.max(now(), value.expiresAt - Math.max(0, refreshBeforeMs) - jitter),\n };\n return value.token;\n };\n\n const getCredential: LakebaseCredentialProvider = async () => {\n if (cached && now() < cached.refreshAt) return cached.token;\n refreshing ??= refresh(false).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n getCredential.refresh = async () => {\n cached = undefined;\n refreshing ??= refresh(true).finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\n\n return getCredential;\n}\n\nfunction parseExpireTime(value: unknown): number {\n if (typeof value === 'number') {\n return value < 1_000_000_000_000 ? value * 1_000 : value;\n }\n if (typeof value === 'string') return new Date(value).getTime();\n return Number.NaN;\n}\n\nexport interface LakebasePoolConfig {\n host: string;\n port: number;\n database: string;\n user: string;\n password?: string;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** Postgres `options` connection parameter, e.g. `-c search_path=fx,public`. */\n options?: string;\n}\n\nexport type LakebasePoolFactory = (config: LakebasePoolConfig) => Pool;\n\nexport interface LakebaseProviderOptions {\n /** Direct endpoint host from list-endpoints (NOT the pooled host). */\n host: string;\n port?: number;\n database: string;\n user: string;\n /** Static database password. If omitted, OAuth exchange is required. */\n password?: string;\n /** Workspace URL, e.g. https://adb-....azuredatabricks.net */\n workspaceHost?: string;\n /** Full endpoint resource name: projects/.../branches/.../endpoints/... */\n endpoint?: string;\n /** Workspace OAuth token or provider. */\n token?: string | DatabricksTokenProvider;\n fetchImpl?: typeof fetch;\n ssl?: boolean | { rejectUnauthorized?: boolean };\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n /** How often to force-refresh the credential and recreate the pool. Default 45 minutes. */\n refreshIntervalMs?: number;\n /** Injected pool factory for tests. */\n poolFactory?: LakebasePoolFactory;\n /** Observe recoverable idle pooled-connection failures. */\n onPoolError?: (error: Error) => void;\n}\n\n/** A Pool-like facade that lazily initializes and always delegates to the current underlying pool. */\nclass DelegatingPool extends EventEmitter {\n private current: Pool | undefined;\n private initPromise: Promise<void> | undefined;\n private closed = false;\n\n private attachErrorHandler(pool: Pool) {\n pool.on('error', (error) => {\n this.emit('error', error);\n });\n }\n\n initialize(createPool: (password: string) => Pool, getPassword: () => Promise<string>) {\n this.initPromise = getPassword()\n .then((password) => {\n if (!this.closed) this.swap(createPool(password));\n })\n .catch((error) => {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n throw error;\n });\n }\n\n swap(pool: Pool) {\n if (this.closed) {\n pool.end().catch(() => undefined);\n return;\n }\n const previous = this.current;\n this.current = pool;\n this.attachErrorHandler(pool);\n if (previous) {\n previous.removeAllListeners();\n previous.end().catch(() => undefined);\n }\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initPromise) await this.initPromise;\n }\n\n query(...args: Parameters<Pool['query']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.query(...args));\n }\n\n connect(...args: Parameters<Pool['connect']>): Promise<unknown> {\n return this.ensureInitialized().then(() => this.current!.connect(...args));\n }\n\n end(): Promise<void> {\n this.closed = true;\n this.removeAllListeners();\n return this.current?.end() ?? Promise.resolve();\n }\n\n get totalCount() {\n return this.current?.totalCount ?? 0;\n }\n\n get idleCount() {\n return this.current?.idleCount ?? 0;\n }\n\n get waitingCount() {\n return this.current?.waitingCount ?? 0;\n }\n}\n\n/** Databricks Lakebase Postgres provider with credential refresh. */\nexport class LakebaseDatabaseProvider implements DatabaseProvider {\n readonly kind = 'databricks-lakebase' as const;\n private readonly options: LakebaseProviderOptions;\n private readonly poolFactory: LakebasePoolFactory;\n private readonly getPassword: () => Promise<string>;\n private readonly refreshPassword: () => Promise<string>;\n private readonly delegatingPool: DelegatingPool;\n private refreshTimer: NodeJS.Timeout | undefined;\n\n constructor(options: LakebaseProviderOptions) {\n this.options = options;\n this.poolFactory = options.poolFactory ?? defaultPoolFactory();\n this.delegatingPool = new DelegatingPool();\n if (options.password !== undefined) {\n this.getPassword = async () => options.password as string;\n this.refreshPassword = this.getPassword;\n this.delegatingPool.swap(this.createPool(options.password));\n } else {\n if (!options.token || !options.workspaceHost || !options.endpoint) {\n throw new Error(\n 'Lakebase OAuth requires token, workspaceHost, and endpoint. A workspace token cannot be used directly as the Postgres password.',\n );\n }\n const credential = lakebaseCredentialProvider({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n token: options.token,\n fetchImpl: options.fetchImpl,\n });\n this.getPassword = credential;\n this.refreshPassword = credential.refresh;\n this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);\n const intervalMs = options.refreshIntervalMs ?? 45 * 60_000;\n this.refreshTimer = setInterval(() => {\n void this.refreshCredentials().catch((error) => {\n this.delegatingPool.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n });\n }, intervalMs);\n }\n }\n\n private createPool(password?: string): Pool {\n return this.poolFactory({\n host: this.options.host,\n port: this.options.port ?? 5432,\n database: this.options.database,\n user: this.options.user,\n password,\n ssl: this.options.ssl ?? { rejectUnauthorized: true },\n max: this.options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? '5', 10),\n idleTimeoutMillis: this.options.idleTimeoutMillis ?? 30_000,\n connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5_000,\n options: '-c search_path=fx,public',\n });\n }\n\n /** Force a new database credential and atomically swap the active pool. */\n async refreshCredentials(): Promise<void> {\n const password = await this.refreshPassword();\n const pool = this.createPool(password);\n this.delegatingPool.swap(pool);\n }\n\n getPool(): Pool {\n return this.delegatingPool as unknown as Pool;\n }\n\n async close(): Promise<void> {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n await this.delegatingPool.end();\n }\n}\n\nfunction defaultPoolFactory(): LakebasePoolFactory {\n return (config) => new Pool(config);\n}\n","import type { Gauge, MetricsCollector } from '@fabricorg/experiments-metrics';\nimport type { Pool } from 'pg';\nimport {\n type DatabaseProvider,\n LakebaseDatabaseProvider,\n NeonDatabaseProvider,\n databricksIdentity,\n databricksPrincipalFromEnv,\n} from './providers/index.js';\n\nexport {\n LakebaseDatabaseProvider,\n exchangeLakebaseCredential,\n lakebaseCredentialProvider,\n type ExchangeLakebaseCredentialOptions,\n type LakebaseCredential,\n type LakebasePoolFactory,\n type LakebaseProviderOptions,\n} from './providers/index.js';\n\nlet provider: DatabaseProvider | null = null;\n\nfunction createProvider(): DatabaseProvider {\n const kind = process.env.DATABASE_PROVIDER ?? 'neon';\n\n if (kind === 'databricks-lakebase') {\n const host = process.env.DATABRICKS_LAKEBASE_HOST?.trim();\n const database = process.env.DATABRICKS_LAKEBASE_DATABASE?.trim() ?? 'databricks_postgres';\n const user = process.env.DATABRICKS_LAKEBASE_USER?.trim();\n const workspaceHost = process.env.DATABRICKS_HOST?.trim();\n const endpoint = process.env.DATABRICKS_LAKEBASE_ENDPOINT?.trim();\n const password = process.env.DATABRICKS_LAKEBASE_PASSWORD?.trim();\n\n if (!host) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_HOST is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n if (!user) {\n throw new Error(\n 'DATABRICKS_LAKEBASE_USER is required when DATABASE_PROVIDER=databricks-lakebase',\n );\n }\n\n if (password) {\n return new LakebaseDatabaseProvider({ host, database, user, password });\n }\n\n if (!workspaceHost || !endpoint) {\n throw new Error(\n 'DATABRICKS_HOST and DATABRICKS_LAKEBASE_ENDPOINT are required for Lakebase OAuth, or provide DATABRICKS_LAKEBASE_PASSWORD for native auth.',\n );\n }\n\n const principal = databricksPrincipalFromEnv(process.env);\n return new LakebaseDatabaseProvider({\n host,\n database,\n user,\n workspaceHost,\n endpoint,\n token: databricksIdentity(principal),\n });\n }\n\n const connectionString = process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error('DATABASE_URL is required');\n }\n return new NeonDatabaseProvider({ connectionString });\n}\n\n/**\n * Return a singleton `pg.Pool` configured for the active database provider.\n *\n * Provider selection:\n * - `DATABASE_PROVIDER=neon` (default): uses `DATABASE_URL`.\n * - `DATABASE_PROVIDER=databricks-lakebase`: uses Lakebase OAuth credentials.\n *\n * On the first call, a new Pool is created with the following defaults:\n * - `max`: parseInt(process.env.PG_POOL_MAX ?? '5') — caps concurrent connections.\n * - `idleTimeoutMillis`: 30000 — recycle idle connections before Vercel's 60s timeout.\n * - `connectionTimeoutMillis`: 5000 — fail fast when the database is unreachable.\n */\nexport function getPool(): Pool {\n if (!provider) {\n provider = createProvider();\n }\n return provider.getPool();\n}\n\n/** Close the active provider and any background refresh loops. */\nexport async function closePool(): Promise<void> {\n await provider?.close();\n provider = null;\n}\n\n/** Reset the singleton provider. Intended for tests. */\nexport function resetPoolProvider(): void {\n provider = null;\n}\n\n/** Return the active provider, or create it. */\nexport function getProvider(): DatabaseProvider {\n if (!provider) {\n provider = createProvider();\n }\n return provider;\n}\n\ninterface PoolGauges {\n total: Gauge;\n idle: Gauge;\n waiting: Gauge;\n active: Gauge;\n}\n\nfunction ensurePoolGauges(collector: MetricsCollector): PoolGauges {\n const reg = collector.registry;\n const existingTotal = reg.get('db_pool_connections_total');\n if (existingTotal) {\n return {\n total: existingTotal as Gauge,\n idle: reg.get('db_pool_connections_idle') as Gauge,\n waiting: reg.get('db_pool_connections_waiting') as Gauge,\n active: reg.get('db_pool_connections_active') as Gauge,\n };\n }\n\n return {\n total: collector.gauge('db_pool_connections_total', 'Total connections in the pool'),\n idle: collector.gauge('db_pool_connections_idle', 'Idle connections in the pool'),\n waiting: collector.gauge('db_pool_connections_waiting', 'Waiting clients in the pool'),\n active: collector.gauge(\n 'db_pool_connections_active',\n 'Active (non-idle) connections in the pool',\n ),\n };\n}\n\n/** Update pool gauge values from the current pool state. */\nexport function updatePoolMetrics(collector: MetricsCollector, poolInstance?: Pool): void {\n const p = poolInstance ?? getPool();\n const total = (p as unknown as { totalCount: number }).totalCount ?? 0;\n const idle = p.idleCount ?? 0;\n const waiting = p.waitingCount ?? 0;\n\n const gauges = ensurePoolGauges(collector);\n gauges.total.set({}, total);\n gauges.idle.set({}, idle);\n gauges.waiting.set({}, waiting);\n gauges.active.set({}, Math.max(0, total - idle));\n}\n\n/**\n * Register pool metrics with the given collector.\n *\n * Returns a cleanup function that stops the update interval.\n */\nexport function registerPoolMetrics(\n collector: MetricsCollector,\n poolInstance?: Pool,\n intervalMs = 5000,\n): () => void {\n updatePoolMetrics(collector, poolInstance);\n\n const interval = setInterval(() => {\n updatePoolMetrics(collector, poolInstance);\n }, intervalMs);\n\n return () => clearInterval(interval);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabricorg/experiments-db-pool",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Singleton pg.Pool for serverless runtimes.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,12 +20,16 @@
20
20
  }
21
21
  }
22
22
  },
23
- "files": [
24
- "dist"
25
- ],
23
+ "files": ["dist"],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "type-check": "tsc --noEmit",
27
+ "test": "vitest run",
28
+ "clean": "rm -rf dist"
29
+ },
26
30
  "dependencies": {
27
- "pg": "^8.13.0",
28
- "@fabricorg/experiments-metrics": "0.0.1"
31
+ "@fabricorg/experiments-metrics": "^0.0.1",
32
+ "pg": "^8.13.0"
29
33
  },
30
34
  "devDependencies": {
31
35
  "@types/node": "^22.15.3",
@@ -33,11 +37,5 @@
33
37
  "tsup": "^8.3.5",
34
38
  "typescript": "^5.8.3",
35
39
  "vitest": "^2.1.8"
36
- },
37
- "scripts": {
38
- "build": "tsup",
39
- "type-check": "tsc --noEmit",
40
- "test": "vitest run",
41
- "clean": "rm -rf dist"
42
40
  }
43
- }
41
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Fabric
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.