@fabricorg/experiments-db-pool 0.1.0 → 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) {
@@ -79,61 +116,133 @@ function servicePrincipalProvider(principal) {
79
116
  cached = { token, refreshAtMs: expiresAtMs - refreshSkewMs };
80
117
  return token;
81
118
  };
82
- return async () => {
119
+ const getToken = async () => {
83
120
  if (cached && Date.now() < cached.refreshAtMs) return cached.token;
84
121
  refreshing ??= refresh().finally(() => {
85
122
  refreshing = void 0;
86
123
  });
87
124
  return refreshing;
88
125
  };
126
+ getToken.refresh = async () => {
127
+ cached = void 0;
128
+ return getToken();
129
+ };
130
+ return getToken;
89
131
  }
90
- function lakebaseCredentialProvider(options) {
91
- const workspaceHost = options.workspaceHost.replace(/\/$/, "");
92
- const fetchImpl = options.fetchImpl ?? fetch;
93
- const now = options.now ?? Date.now;
94
- const random = options.random ?? Math.random;
95
- const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 6e4;
96
- const refreshJitterMs = options.refreshJitterMs ?? 3e4;
132
+ function federatedIdentityProvider(principal) {
133
+ const host = principal.host.replace(/\/$/, "");
134
+ const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1e3;
97
135
  let cached;
98
136
  let refreshing;
99
137
  const refresh = async () => {
100
- const workspaceToken = typeof options.token === "function" ? await options.token() : options.token;
101
- const response = await fetchImpl(`${workspaceHost}/api/2.0/postgres/credentials`, {
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`, {
102
146
  method: "POST",
103
- headers: {
104
- authorization: `Bearer ${workspaceToken}`,
105
- "content-type": "application/json"
106
- },
107
- body: JSON.stringify({ endpoint: options.endpoint })
147
+ headers: { "content-type": "application/x-www-form-urlencoded" },
148
+ body: params
108
149
  });
109
150
  if (!response.ok) {
110
151
  const text = await response.text();
111
152
  throw new Error(
112
- `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
153
+ `Databricks federated token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
113
154
  );
114
155
  }
115
156
  const value = await response.json();
116
- if (typeof value.token !== "string" || !value.token) {
117
- throw new Error("Lakebase credential exchange returned no token.");
157
+ if (typeof value.access_token !== "string" || !value.access_token) {
158
+ throw new Error("Databricks federated token exchange returned no access_token.");
118
159
  }
119
- const expiresAt = parseExpireTime(value.expire_time);
120
- if (!Number.isFinite(expiresAt)) {
121
- throw new Error("Lakebase credential exchange returned an invalid expire_time.");
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
+ }
180
+ async function exchangeLakebaseCredential(options) {
181
+ const fetchImpl = options.fetchImpl ?? fetch;
182
+ const response = await fetchImpl(
183
+ `${options.workspaceHost.replace(/\/$/, "")}/api/2.0/postgres/credentials`,
184
+ {
185
+ method: "POST",
186
+ headers: {
187
+ authorization: `Bearer ${options.workspaceToken}`,
188
+ "content-type": "application/json"
189
+ },
190
+ body: JSON.stringify({ endpoint: options.endpoint })
122
191
  }
192
+ );
193
+ if (!response.ok) {
194
+ const text = await response.text();
195
+ throw new Error(
196
+ `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
197
+ );
198
+ }
199
+ const value = await response.json();
200
+ if (typeof value.token !== "string" || !value.token) {
201
+ throw new Error("Lakebase credential exchange returned no token.");
202
+ }
203
+ const expiresAt = parseExpireTime(value.expire_time);
204
+ if (!Number.isFinite(expiresAt)) {
205
+ throw new Error("Lakebase credential exchange returned an invalid expire_time.");
206
+ }
207
+ return { token: value.token, expiresAt };
208
+ }
209
+ function lakebaseCredentialProvider(options) {
210
+ const now = options.now ?? Date.now;
211
+ const random = options.random ?? Math.random;
212
+ const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 6e4;
213
+ const refreshJitterMs = options.refreshJitterMs ?? 3e4;
214
+ let cached;
215
+ let refreshing;
216
+ const refresh = async (forceWorkspaceToken = false) => {
217
+ const workspaceToken = typeof options.token === "function" ? await (forceWorkspaceToken && options.token.refresh ? options.token.refresh() : options.token()) : options.token;
218
+ const value = await exchangeLakebaseCredential({
219
+ workspaceHost: options.workspaceHost,
220
+ endpoint: options.endpoint,
221
+ workspaceToken,
222
+ fetchImpl: options.fetchImpl
223
+ });
123
224
  const jitter = Math.max(0, refreshJitterMs) * random();
124
225
  cached = {
125
226
  token: value.token,
126
- refreshAt: Math.max(now(), expiresAt - Math.max(0, refreshBeforeMs) - jitter)
227
+ refreshAt: Math.max(now(), value.expiresAt - Math.max(0, refreshBeforeMs) - jitter)
127
228
  };
128
229
  return value.token;
129
230
  };
130
- return async () => {
231
+ const getCredential = async () => {
131
232
  if (cached && now() < cached.refreshAt) return cached.token;
132
- refreshing ??= refresh().finally(() => {
233
+ refreshing ??= refresh(false).finally(() => {
133
234
  refreshing = void 0;
134
235
  });
135
236
  return refreshing;
136
237
  };
238
+ getCredential.refresh = async () => {
239
+ cached = void 0;
240
+ refreshing ??= refresh(true).finally(() => {
241
+ refreshing = void 0;
242
+ });
243
+ return refreshing;
244
+ };
245
+ return getCredential;
137
246
  }
138
247
  function parseExpireTime(value) {
139
248
  if (typeof value === "number") {
@@ -201,6 +310,7 @@ var LakebaseDatabaseProvider = class {
201
310
  options;
202
311
  poolFactory;
203
312
  getPassword;
313
+ refreshPassword;
204
314
  delegatingPool;
205
315
  refreshTimer;
206
316
  constructor(options) {
@@ -209,6 +319,7 @@ var LakebaseDatabaseProvider = class {
209
319
  this.delegatingPool = new DelegatingPool();
210
320
  if (options.password !== void 0) {
211
321
  this.getPassword = async () => options.password;
322
+ this.refreshPassword = this.getPassword;
212
323
  this.delegatingPool.swap(this.createPool(options.password));
213
324
  } else {
214
325
  if (!options.token || !options.workspaceHost || !options.endpoint) {
@@ -216,16 +327,23 @@ var LakebaseDatabaseProvider = class {
216
327
  "Lakebase OAuth requires token, workspaceHost, and endpoint. A workspace token cannot be used directly as the Postgres password."
217
328
  );
218
329
  }
219
- this.getPassword = lakebaseCredentialProvider({
330
+ const credential = lakebaseCredentialProvider({
220
331
  workspaceHost: options.workspaceHost,
221
332
  endpoint: options.endpoint,
222
333
  token: options.token,
223
334
  fetchImpl: options.fetchImpl
224
335
  });
336
+ this.getPassword = credential;
337
+ this.refreshPassword = credential.refresh;
225
338
  this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);
226
- const intervalMs = options.refreshIntervalMs ?? 50 * 6e4;
339
+ const intervalMs = options.refreshIntervalMs ?? 45 * 6e4;
227
340
  this.refreshTimer = setInterval(() => {
228
- void this.refreshPool();
341
+ void this.refreshCredentials().catch((error) => {
342
+ this.delegatingPool.emit(
343
+ "error",
344
+ error instanceof Error ? error : new Error(String(error))
345
+ );
346
+ });
229
347
  }, intervalMs);
230
348
  }
231
349
  }
@@ -239,17 +357,15 @@ var LakebaseDatabaseProvider = class {
239
357
  ssl: this.options.ssl ?? { rejectUnauthorized: true },
240
358
  max: this.options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? "5", 10),
241
359
  idleTimeoutMillis: this.options.idleTimeoutMillis ?? 3e4,
242
- connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5e3
360
+ connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5e3,
361
+ options: "-c search_path=fx,public"
243
362
  });
244
363
  }
245
- async refreshPool() {
246
- try {
247
- const password = await this.getPassword();
248
- const pool = this.createPool(password);
249
- this.delegatingPool.swap(pool);
250
- } catch (error) {
251
- this.delegatingPool.emit("error", error instanceof Error ? error : new Error(String(error)));
252
- }
364
+ /** Force a new database credential and atomically swap the active pool. */
365
+ async refreshCredentials() {
366
+ const password = await this.refreshPassword();
367
+ const pool = this.createPool(password);
368
+ this.delegatingPool.swap(pool);
253
369
  }
254
370
  getPool() {
255
371
  return this.delegatingPool;
@@ -370,9 +486,12 @@ function registerPoolMetrics(collector, poolInstance, intervalMs = 5e3) {
370
486
  return () => clearInterval(interval);
371
487
  }
372
488
 
489
+ exports.LakebaseDatabaseProvider = LakebaseDatabaseProvider;
373
490
  exports.closePool = closePool;
491
+ exports.exchangeLakebaseCredential = exchangeLakebaseCredential;
374
492
  exports.getPool = getPool;
375
493
  exports.getProvider = getProvider;
494
+ exports.lakebaseCredentialProvider = lakebaseCredentialProvider;
376
495
  exports.registerPoolMetrics = registerPoolMetrics;
377
496
  exports.resetPoolProvider = resetPoolProvider;
378
497
  exports.updatePoolMetrics = updatePoolMetrics;
@@ -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\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 return 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\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\n/** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */\nexport function lakebaseCredentialProvider(\n options: LakebaseCredentialProviderOptions,\n): () => Promise<string> {\n const workspaceHost = options.workspaceHost.replace(/\\/$/, '');\n const fetchImpl = options.fetchImpl ?? fetch;\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 (): Promise<string> => {\n const workspaceToken =\n typeof options.token === 'function' ? await options.token() : options.token;\n const response = await fetchImpl(`${workspaceHost}/api/2.0/postgres/credentials`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${workspaceToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ endpoint: options.endpoint }),\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 const jitter = Math.max(0, refreshJitterMs) * random();\n cached = {\n token: value.token,\n refreshAt: Math.max(now(), expiresAt - Math.max(0, refreshBeforeMs) - jitter),\n };\n return value.token;\n };\n\n return async () => {\n if (cached && now() < cached.refreshAt) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\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}\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 refresh the credential and recreate the pool. Default 50 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 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.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 this.getPassword = lakebaseCredentialProvider({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n token: options.token,\n fetchImpl: options.fetchImpl,\n });\n this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);\n const intervalMs = options.refreshIntervalMs ?? 50 * 60_000;\n this.refreshTimer = setInterval(() => {\n void this.refreshPool();\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 });\n }\n\n private async refreshPool(): Promise<void> {\n try {\n const password = await this.getPassword();\n const pool = this.createPool(password);\n this.delegatingPool.swap(pool);\n } catch (error) {\n this.delegatingPool.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\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\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.d.cts CHANGED
@@ -10,6 +10,100 @@ interface DatabaseProvider {
10
10
  close(): Promise<void>;
11
11
  }
12
12
 
13
+ /** A resolver that returns a valid Databricks workspace OAuth token. */
14
+ type DatabricksTokenProvider = (() => Promise<string>) & {
15
+ /** Bypass the cache and obtain a new token when the downstream credential is rotated. */
16
+ refresh?: () => Promise<string>;
17
+ };
18
+ interface LakebaseCredentialProviderOptions {
19
+ workspaceHost: string;
20
+ endpoint: string;
21
+ token: string | DatabricksTokenProvider;
22
+ fetchImpl?: typeof fetch;
23
+ refreshBeforeMs?: number;
24
+ refreshJitterMs?: number;
25
+ now?: () => number;
26
+ random?: () => number;
27
+ }
28
+ interface LakebaseCredential {
29
+ token: string;
30
+ expiresAt: number;
31
+ }
32
+ interface ExchangeLakebaseCredentialOptions {
33
+ workspaceHost: string;
34
+ endpoint: string;
35
+ workspaceToken: string;
36
+ fetchImpl?: typeof fetch;
37
+ }
38
+ /** Perform one uncached workspace-token to Lakebase-credential exchange. */
39
+ declare function exchangeLakebaseCredential(options: ExchangeLakebaseCredentialOptions): Promise<LakebaseCredential>;
40
+ type LakebaseCredentialProvider = (() => Promise<string>) & {
41
+ /** Force both the workspace OAuth token and database credential to rotate. */
42
+ refresh: () => Promise<string>;
43
+ };
44
+ /** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */
45
+ declare function lakebaseCredentialProvider(options: LakebaseCredentialProviderOptions): LakebaseCredentialProvider;
46
+ interface LakebasePoolConfig {
47
+ host: string;
48
+ port: number;
49
+ database: string;
50
+ user: string;
51
+ password?: string;
52
+ ssl?: boolean | {
53
+ rejectUnauthorized?: boolean;
54
+ };
55
+ max?: number;
56
+ idleTimeoutMillis?: number;
57
+ connectionTimeoutMillis?: number;
58
+ /** Postgres `options` connection parameter, e.g. `-c search_path=fx,public`. */
59
+ options?: string;
60
+ }
61
+ type LakebasePoolFactory = (config: LakebasePoolConfig) => Pool;
62
+ interface LakebaseProviderOptions {
63
+ /** Direct endpoint host from list-endpoints (NOT the pooled host). */
64
+ host: string;
65
+ port?: number;
66
+ database: string;
67
+ user: string;
68
+ /** Static database password. If omitted, OAuth exchange is required. */
69
+ password?: string;
70
+ /** Workspace URL, e.g. https://adb-....azuredatabricks.net */
71
+ workspaceHost?: string;
72
+ /** Full endpoint resource name: projects/.../branches/.../endpoints/... */
73
+ endpoint?: string;
74
+ /** Workspace OAuth token or provider. */
75
+ token?: string | DatabricksTokenProvider;
76
+ fetchImpl?: typeof fetch;
77
+ ssl?: boolean | {
78
+ rejectUnauthorized?: boolean;
79
+ };
80
+ max?: number;
81
+ idleTimeoutMillis?: number;
82
+ connectionTimeoutMillis?: number;
83
+ /** How often to force-refresh the credential and recreate the pool. Default 45 minutes. */
84
+ refreshIntervalMs?: number;
85
+ /** Injected pool factory for tests. */
86
+ poolFactory?: LakebasePoolFactory;
87
+ /** Observe recoverable idle pooled-connection failures. */
88
+ onPoolError?: (error: Error) => void;
89
+ }
90
+ /** Databricks Lakebase Postgres provider with credential refresh. */
91
+ declare class LakebaseDatabaseProvider implements DatabaseProvider {
92
+ readonly kind: "databricks-lakebase";
93
+ private readonly options;
94
+ private readonly poolFactory;
95
+ private readonly getPassword;
96
+ private readonly refreshPassword;
97
+ private readonly delegatingPool;
98
+ private refreshTimer;
99
+ constructor(options: LakebaseProviderOptions);
100
+ private createPool;
101
+ /** Force a new database credential and atomically swap the active pool. */
102
+ refreshCredentials(): Promise<void>;
103
+ getPool(): Pool;
104
+ close(): Promise<void>;
105
+ }
106
+
13
107
  /**
14
108
  * Return a singleton `pg.Pool` configured for the active database provider.
15
109
  *
@@ -38,4 +132,4 @@ declare function updatePoolMetrics(collector: MetricsCollector, poolInstance?: P
38
132
  */
39
133
  declare function registerPoolMetrics(collector: MetricsCollector, poolInstance?: Pool, intervalMs?: number): () => void;
40
134
 
41
- export { closePool, getPool, getProvider, registerPoolMetrics, resetPoolProvider, updatePoolMetrics };
135
+ export { type ExchangeLakebaseCredentialOptions, type LakebaseCredential, LakebaseDatabaseProvider, type LakebasePoolFactory, type LakebaseProviderOptions, closePool, exchangeLakebaseCredential, getPool, getProvider, lakebaseCredentialProvider, registerPoolMetrics, resetPoolProvider, updatePoolMetrics };
package/dist/index.d.ts CHANGED
@@ -10,6 +10,100 @@ interface DatabaseProvider {
10
10
  close(): Promise<void>;
11
11
  }
12
12
 
13
+ /** A resolver that returns a valid Databricks workspace OAuth token. */
14
+ type DatabricksTokenProvider = (() => Promise<string>) & {
15
+ /** Bypass the cache and obtain a new token when the downstream credential is rotated. */
16
+ refresh?: () => Promise<string>;
17
+ };
18
+ interface LakebaseCredentialProviderOptions {
19
+ workspaceHost: string;
20
+ endpoint: string;
21
+ token: string | DatabricksTokenProvider;
22
+ fetchImpl?: typeof fetch;
23
+ refreshBeforeMs?: number;
24
+ refreshJitterMs?: number;
25
+ now?: () => number;
26
+ random?: () => number;
27
+ }
28
+ interface LakebaseCredential {
29
+ token: string;
30
+ expiresAt: number;
31
+ }
32
+ interface ExchangeLakebaseCredentialOptions {
33
+ workspaceHost: string;
34
+ endpoint: string;
35
+ workspaceToken: string;
36
+ fetchImpl?: typeof fetch;
37
+ }
38
+ /** Perform one uncached workspace-token to Lakebase-credential exchange. */
39
+ declare function exchangeLakebaseCredential(options: ExchangeLakebaseCredentialOptions): Promise<LakebaseCredential>;
40
+ type LakebaseCredentialProvider = (() => Promise<string>) & {
41
+ /** Force both the workspace OAuth token and database credential to rotate. */
42
+ refresh: () => Promise<string>;
43
+ };
44
+ /** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */
45
+ declare function lakebaseCredentialProvider(options: LakebaseCredentialProviderOptions): LakebaseCredentialProvider;
46
+ interface LakebasePoolConfig {
47
+ host: string;
48
+ port: number;
49
+ database: string;
50
+ user: string;
51
+ password?: string;
52
+ ssl?: boolean | {
53
+ rejectUnauthorized?: boolean;
54
+ };
55
+ max?: number;
56
+ idleTimeoutMillis?: number;
57
+ connectionTimeoutMillis?: number;
58
+ /** Postgres `options` connection parameter, e.g. `-c search_path=fx,public`. */
59
+ options?: string;
60
+ }
61
+ type LakebasePoolFactory = (config: LakebasePoolConfig) => Pool;
62
+ interface LakebaseProviderOptions {
63
+ /** Direct endpoint host from list-endpoints (NOT the pooled host). */
64
+ host: string;
65
+ port?: number;
66
+ database: string;
67
+ user: string;
68
+ /** Static database password. If omitted, OAuth exchange is required. */
69
+ password?: string;
70
+ /** Workspace URL, e.g. https://adb-....azuredatabricks.net */
71
+ workspaceHost?: string;
72
+ /** Full endpoint resource name: projects/.../branches/.../endpoints/... */
73
+ endpoint?: string;
74
+ /** Workspace OAuth token or provider. */
75
+ token?: string | DatabricksTokenProvider;
76
+ fetchImpl?: typeof fetch;
77
+ ssl?: boolean | {
78
+ rejectUnauthorized?: boolean;
79
+ };
80
+ max?: number;
81
+ idleTimeoutMillis?: number;
82
+ connectionTimeoutMillis?: number;
83
+ /** How often to force-refresh the credential and recreate the pool. Default 45 minutes. */
84
+ refreshIntervalMs?: number;
85
+ /** Injected pool factory for tests. */
86
+ poolFactory?: LakebasePoolFactory;
87
+ /** Observe recoverable idle pooled-connection failures. */
88
+ onPoolError?: (error: Error) => void;
89
+ }
90
+ /** Databricks Lakebase Postgres provider with credential refresh. */
91
+ declare class LakebaseDatabaseProvider implements DatabaseProvider {
92
+ readonly kind: "databricks-lakebase";
93
+ private readonly options;
94
+ private readonly poolFactory;
95
+ private readonly getPassword;
96
+ private readonly refreshPassword;
97
+ private readonly delegatingPool;
98
+ private refreshTimer;
99
+ constructor(options: LakebaseProviderOptions);
100
+ private createPool;
101
+ /** Force a new database credential and atomically swap the active pool. */
102
+ refreshCredentials(): Promise<void>;
103
+ getPool(): Pool;
104
+ close(): Promise<void>;
105
+ }
106
+
13
107
  /**
14
108
  * Return a singleton `pg.Pool` configured for the active database provider.
15
109
  *
@@ -38,4 +132,4 @@ declare function updatePoolMetrics(collector: MetricsCollector, poolInstance?: P
38
132
  */
39
133
  declare function registerPoolMetrics(collector: MetricsCollector, poolInstance?: Pool, intervalMs?: number): () => void;
40
134
 
41
- export { closePool, getPool, getProvider, registerPoolMetrics, resetPoolProvider, updatePoolMetrics };
135
+ export { type ExchangeLakebaseCredentialOptions, type LakebaseCredential, LakebaseDatabaseProvider, type LakebasePoolFactory, type LakebaseProviderOptions, closePool, exchangeLakebaseCredential, getPool, getProvider, lakebaseCredentialProvider, registerPoolMetrics, resetPoolProvider, updatePoolMetrics };
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) {
@@ -77,61 +114,133 @@ function servicePrincipalProvider(principal) {
77
114
  cached = { token, refreshAtMs: expiresAtMs - refreshSkewMs };
78
115
  return token;
79
116
  };
80
- return async () => {
117
+ const getToken = async () => {
81
118
  if (cached && Date.now() < cached.refreshAtMs) return cached.token;
82
119
  refreshing ??= refresh().finally(() => {
83
120
  refreshing = void 0;
84
121
  });
85
122
  return refreshing;
86
123
  };
124
+ getToken.refresh = async () => {
125
+ cached = void 0;
126
+ return getToken();
127
+ };
128
+ return getToken;
87
129
  }
88
- function lakebaseCredentialProvider(options) {
89
- const workspaceHost = options.workspaceHost.replace(/\/$/, "");
90
- const fetchImpl = options.fetchImpl ?? fetch;
91
- const now = options.now ?? Date.now;
92
- const random = options.random ?? Math.random;
93
- const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 6e4;
94
- const refreshJitterMs = options.refreshJitterMs ?? 3e4;
130
+ function federatedIdentityProvider(principal) {
131
+ const host = principal.host.replace(/\/$/, "");
132
+ const refreshSkewMs = (principal.refreshSkewSeconds ?? 60) * 1e3;
95
133
  let cached;
96
134
  let refreshing;
97
135
  const refresh = async () => {
98
- const workspaceToken = typeof options.token === "function" ? await options.token() : options.token;
99
- const response = await fetchImpl(`${workspaceHost}/api/2.0/postgres/credentials`, {
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`, {
100
144
  method: "POST",
101
- headers: {
102
- authorization: `Bearer ${workspaceToken}`,
103
- "content-type": "application/json"
104
- },
105
- body: JSON.stringify({ endpoint: options.endpoint })
145
+ headers: { "content-type": "application/x-www-form-urlencoded" },
146
+ body: params
106
147
  });
107
148
  if (!response.ok) {
108
149
  const text = await response.text();
109
150
  throw new Error(
110
- `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
151
+ `Databricks federated token exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
111
152
  );
112
153
  }
113
154
  const value = await response.json();
114
- if (typeof value.token !== "string" || !value.token) {
115
- throw new Error("Lakebase credential exchange returned no token.");
155
+ if (typeof value.access_token !== "string" || !value.access_token) {
156
+ throw new Error("Databricks federated token exchange returned no access_token.");
116
157
  }
117
- const expiresAt = parseExpireTime(value.expire_time);
118
- if (!Number.isFinite(expiresAt)) {
119
- throw new Error("Lakebase credential exchange returned an invalid expire_time.");
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
+ }
178
+ async function exchangeLakebaseCredential(options) {
179
+ const fetchImpl = options.fetchImpl ?? fetch;
180
+ const response = await fetchImpl(
181
+ `${options.workspaceHost.replace(/\/$/, "")}/api/2.0/postgres/credentials`,
182
+ {
183
+ method: "POST",
184
+ headers: {
185
+ authorization: `Bearer ${options.workspaceToken}`,
186
+ "content-type": "application/json"
187
+ },
188
+ body: JSON.stringify({ endpoint: options.endpoint })
120
189
  }
190
+ );
191
+ if (!response.ok) {
192
+ const text = await response.text();
193
+ throw new Error(
194
+ `Lakebase credential exchange failed: ${response.status} ${response.statusText}: ${text.slice(0, 500)}`
195
+ );
196
+ }
197
+ const value = await response.json();
198
+ if (typeof value.token !== "string" || !value.token) {
199
+ throw new Error("Lakebase credential exchange returned no token.");
200
+ }
201
+ const expiresAt = parseExpireTime(value.expire_time);
202
+ if (!Number.isFinite(expiresAt)) {
203
+ throw new Error("Lakebase credential exchange returned an invalid expire_time.");
204
+ }
205
+ return { token: value.token, expiresAt };
206
+ }
207
+ function lakebaseCredentialProvider(options) {
208
+ const now = options.now ?? Date.now;
209
+ const random = options.random ?? Math.random;
210
+ const refreshBeforeMs = options.refreshBeforeMs ?? 5 * 6e4;
211
+ const refreshJitterMs = options.refreshJitterMs ?? 3e4;
212
+ let cached;
213
+ let refreshing;
214
+ const refresh = async (forceWorkspaceToken = false) => {
215
+ const workspaceToken = typeof options.token === "function" ? await (forceWorkspaceToken && options.token.refresh ? options.token.refresh() : options.token()) : options.token;
216
+ const value = await exchangeLakebaseCredential({
217
+ workspaceHost: options.workspaceHost,
218
+ endpoint: options.endpoint,
219
+ workspaceToken,
220
+ fetchImpl: options.fetchImpl
221
+ });
121
222
  const jitter = Math.max(0, refreshJitterMs) * random();
122
223
  cached = {
123
224
  token: value.token,
124
- refreshAt: Math.max(now(), expiresAt - Math.max(0, refreshBeforeMs) - jitter)
225
+ refreshAt: Math.max(now(), value.expiresAt - Math.max(0, refreshBeforeMs) - jitter)
125
226
  };
126
227
  return value.token;
127
228
  };
128
- return async () => {
229
+ const getCredential = async () => {
129
230
  if (cached && now() < cached.refreshAt) return cached.token;
130
- refreshing ??= refresh().finally(() => {
231
+ refreshing ??= refresh(false).finally(() => {
131
232
  refreshing = void 0;
132
233
  });
133
234
  return refreshing;
134
235
  };
236
+ getCredential.refresh = async () => {
237
+ cached = void 0;
238
+ refreshing ??= refresh(true).finally(() => {
239
+ refreshing = void 0;
240
+ });
241
+ return refreshing;
242
+ };
243
+ return getCredential;
135
244
  }
136
245
  function parseExpireTime(value) {
137
246
  if (typeof value === "number") {
@@ -199,6 +308,7 @@ var LakebaseDatabaseProvider = class {
199
308
  options;
200
309
  poolFactory;
201
310
  getPassword;
311
+ refreshPassword;
202
312
  delegatingPool;
203
313
  refreshTimer;
204
314
  constructor(options) {
@@ -207,6 +317,7 @@ var LakebaseDatabaseProvider = class {
207
317
  this.delegatingPool = new DelegatingPool();
208
318
  if (options.password !== void 0) {
209
319
  this.getPassword = async () => options.password;
320
+ this.refreshPassword = this.getPassword;
210
321
  this.delegatingPool.swap(this.createPool(options.password));
211
322
  } else {
212
323
  if (!options.token || !options.workspaceHost || !options.endpoint) {
@@ -214,16 +325,23 @@ var LakebaseDatabaseProvider = class {
214
325
  "Lakebase OAuth requires token, workspaceHost, and endpoint. A workspace token cannot be used directly as the Postgres password."
215
326
  );
216
327
  }
217
- this.getPassword = lakebaseCredentialProvider({
328
+ const credential = lakebaseCredentialProvider({
218
329
  workspaceHost: options.workspaceHost,
219
330
  endpoint: options.endpoint,
220
331
  token: options.token,
221
332
  fetchImpl: options.fetchImpl
222
333
  });
334
+ this.getPassword = credential;
335
+ this.refreshPassword = credential.refresh;
223
336
  this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);
224
- const intervalMs = options.refreshIntervalMs ?? 50 * 6e4;
337
+ const intervalMs = options.refreshIntervalMs ?? 45 * 6e4;
225
338
  this.refreshTimer = setInterval(() => {
226
- void this.refreshPool();
339
+ void this.refreshCredentials().catch((error) => {
340
+ this.delegatingPool.emit(
341
+ "error",
342
+ error instanceof Error ? error : new Error(String(error))
343
+ );
344
+ });
227
345
  }, intervalMs);
228
346
  }
229
347
  }
@@ -237,17 +355,15 @@ var LakebaseDatabaseProvider = class {
237
355
  ssl: this.options.ssl ?? { rejectUnauthorized: true },
238
356
  max: this.options.max ?? Number.parseInt(process.env.PG_POOL_MAX ?? "5", 10),
239
357
  idleTimeoutMillis: this.options.idleTimeoutMillis ?? 3e4,
240
- connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5e3
358
+ connectionTimeoutMillis: this.options.connectionTimeoutMillis ?? 5e3,
359
+ options: "-c search_path=fx,public"
241
360
  });
242
361
  }
243
- async refreshPool() {
244
- try {
245
- const password = await this.getPassword();
246
- const pool = this.createPool(password);
247
- this.delegatingPool.swap(pool);
248
- } catch (error) {
249
- this.delegatingPool.emit("error", error instanceof Error ? error : new Error(String(error)));
250
- }
362
+ /** Force a new database credential and atomically swap the active pool. */
363
+ async refreshCredentials() {
364
+ const password = await this.refreshPassword();
365
+ const pool = this.createPool(password);
366
+ this.delegatingPool.swap(pool);
251
367
  }
252
368
  getPool() {
253
369
  return this.delegatingPool;
@@ -368,6 +484,6 @@ function registerPoolMetrics(collector, poolInstance, intervalMs = 5e3) {
368
484
  return () => clearInterval(interval);
369
485
  }
370
486
 
371
- export { closePool, getPool, getProvider, registerPoolMetrics, resetPoolProvider, updatePoolMetrics };
487
+ export { LakebaseDatabaseProvider, closePool, exchangeLakebaseCredential, getPool, getProvider, lakebaseCredentialProvider, registerPoolMetrics, resetPoolProvider, updatePoolMetrics };
372
488
  //# sourceMappingURL=index.js.map
373
489
  //# sourceMappingURL=index.js.map
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\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 return 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\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\n/** Exchange a workspace OAuth token for a Lakebase database credential. Caches, refreshes early, single-flight. */\nexport function lakebaseCredentialProvider(\n options: LakebaseCredentialProviderOptions,\n): () => Promise<string> {\n const workspaceHost = options.workspaceHost.replace(/\\/$/, '');\n const fetchImpl = options.fetchImpl ?? fetch;\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 (): Promise<string> => {\n const workspaceToken =\n typeof options.token === 'function' ? await options.token() : options.token;\n const response = await fetchImpl(`${workspaceHost}/api/2.0/postgres/credentials`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${workspaceToken}`,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ endpoint: options.endpoint }),\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 const jitter = Math.max(0, refreshJitterMs) * random();\n cached = {\n token: value.token,\n refreshAt: Math.max(now(), expiresAt - Math.max(0, refreshBeforeMs) - jitter),\n };\n return value.token;\n };\n\n return async () => {\n if (cached && now() < cached.refreshAt) return cached.token;\n refreshing ??= refresh().finally(() => {\n refreshing = undefined;\n });\n return refreshing;\n };\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}\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 refresh the credential and recreate the pool. Default 50 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 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.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 this.getPassword = lakebaseCredentialProvider({\n workspaceHost: options.workspaceHost,\n endpoint: options.endpoint,\n token: options.token,\n fetchImpl: options.fetchImpl,\n });\n this.delegatingPool.initialize((password) => this.createPool(password), this.getPassword);\n const intervalMs = options.refreshIntervalMs ?? 50 * 60_000;\n this.refreshTimer = setInterval(() => {\n void this.refreshPool();\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 });\n }\n\n private async refreshPool(): Promise<void> {\n try {\n const password = await this.getPassword();\n const pool = this.createPool(password);\n this.delegatingPool.swap(pool);\n } catch (error) {\n this.delegatingPool.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\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\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.0",
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.