lambda-pool 0.1.0
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/LICENSE +21 -0
- package/README.md +291 -0
- package/dist/adapters/health.d.ts +30 -0
- package/dist/adapters/health.d.ts.map +1 -0
- package/dist/adapters/health.js +36 -0
- package/dist/adapters/health.js.map +1 -0
- package/dist/adapters/mysql.d.ts +40 -0
- package/dist/adapters/mysql.d.ts.map +1 -0
- package/dist/adapters/mysql.js +34 -0
- package/dist/adapters/mysql.js.map +1 -0
- package/dist/adapters/pg.d.ts +46 -0
- package/dist/adapters/pg.d.ts.map +1 -0
- package/dist/adapters/pg.js +34 -0
- package/dist/adapters/pg.js.map +1 -0
- package/dist/application/diagnostics.d.ts +33 -0
- package/dist/application/diagnostics.d.ts.map +1 -0
- package/dist/application/diagnostics.js +94 -0
- package/dist/application/diagnostics.js.map +1 -0
- package/dist/application/inspect.d.ts +20 -0
- package/dist/application/inspect.d.ts.map +1 -0
- package/dist/application/inspect.js +31 -0
- package/dist/application/inspect.js.map +1 -0
- package/dist/application/preflight.d.ts +28 -0
- package/dist/application/preflight.d.ts.map +1 -0
- package/dist/application/preflight.js +49 -0
- package/dist/application/preflight.js.map +1 -0
- package/dist/application/recommend.d.ts +22 -0
- package/dist/application/recommend.d.ts.map +1 -0
- package/dist/application/recommend.js +30 -0
- package/dist/application/recommend.js.map +1 -0
- package/dist/core/budget.d.ts +35 -0
- package/dist/core/budget.d.ts.map +1 -0
- package/dist/core/budget.js +48 -0
- package/dist/core/budget.js.map +1 -0
- package/dist/core/config.d.ts +24 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +32 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/dsn.d.ts +20 -0
- package/dist/core/dsn.d.ts.map +1 -0
- package/dist/core/dsn.js +38 -0
- package/dist/core/dsn.js.map +1 -0
- package/dist/core/env.d.ts +27 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/env.js +52 -0
- package/dist/core/env.js.map +1 -0
- package/dist/core/providers.d.ts +29 -0
- package/dist/core/providers.d.ts.map +1 -0
- package/dist/core/providers.js +121 -0
- package/dist/core/providers.js.map +1 -0
- package/dist/core/redact.d.ts +20 -0
- package/dist/core/redact.d.ts.map +1 -0
- package/dist/core/redact.js +63 -0
- package/dist/core/redact.js.map +1 -0
- package/dist/core/result.d.ts +16 -0
- package/dist/core/result.d.ts.map +1 -0
- package/dist/core/result.js +32 -0
- package/dist/core/result.js.map +1 -0
- package/dist/core/retry.d.ts +31 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +67 -0
- package/dist/core/retry.js.map +1 -0
- package/dist/core/url.d.ts +38 -0
- package/dist/core/url.d.ts.map +1 -0
- package/dist/core/url.js +88 -0
- package/dist/core/url.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/presentation/bin.d.ts +3 -0
- package/dist/presentation/bin.d.ts.map +1 -0
- package/dist/presentation/bin.js +11 -0
- package/dist/presentation/bin.js.map +1 -0
- package/dist/presentation/cli.d.ts +10 -0
- package/dist/presentation/cli.d.ts.map +1 -0
- package/dist/presentation/cli.js +124 -0
- package/dist/presentation/cli.js.map +1 -0
- package/package.json +133 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 owlCoder
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# lambda-pool
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/lambda-pool)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/lambda-pool)
|
|
6
|
+
[](#zero-runtime-dependencies)
|
|
7
|
+
|
|
8
|
+
Serverless-safe **connection-pool options** for **MySQL** (`mysql2`) and **Postgres** (`pg`)
|
|
9
|
+
on Vercel / AWS Lambda / Cloudflare-to-DB, where the database has a **small
|
|
10
|
+
`max_connections`** budget (Aiven free tier, Neon, Supabase, RDS micro, PlanetScale).
|
|
11
|
+
|
|
12
|
+
It returns a plain options object you pass to your own driver. **Zero runtime
|
|
13
|
+
dependencies.** It does not open connections, wrap your driver, or pin a version.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install lambda-pool
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## The bug this prevents
|
|
20
|
+
|
|
21
|
+
On Vercel/Lambda every **warm** function instance keeps **its own** pool. If each
|
|
22
|
+
pool opens `N` connections and the platform keeps `M` instances warm, your
|
|
23
|
+
database sees up to **`N × M`** connections.
|
|
24
|
+
|
|
25
|
+
Managed databases on small plans cap `max_connections` very low (often **10–25**).
|
|
26
|
+
So a perfectly reasonable-looking `connectionLimit: 10` blows the budget under
|
|
27
|
+
mild traffic and you get:
|
|
28
|
+
|
|
29
|
+
- MySQL: `ER_CON_COUNT_ERROR: Too many connections`
|
|
30
|
+
- Postgres: `sorry, too many clients already`
|
|
31
|
+
|
|
32
|
+
…intermittently, only in production, only under load. The classic "works on my
|
|
33
|
+
machine, dies on Black Friday" footgun.
|
|
34
|
+
|
|
35
|
+
## The fix (and why it's counter-intuitive)
|
|
36
|
+
|
|
37
|
+
Make each pool **tiny** — default **1 connection per instance**. The platform's
|
|
38
|
+
horizontal scaling *is* your concurrency; the database stops melting. Idle
|
|
39
|
+
instances release their slot so they don't sit on the budget.
|
|
40
|
+
|
|
41
|
+
That's the whole idea. This package just encodes the right defaults so you don't
|
|
42
|
+
have to rediscover them in an incident.
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
### MySQL (`mysql2`)
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import mysql from "mysql2/promise";
|
|
50
|
+
import { buildMysqlPoolOptions } from "lambda-pool/mysql";
|
|
51
|
+
|
|
52
|
+
const pool = mysql.createPool(buildMysqlPoolOptions(process.env));
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Postgres (`pg`)
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { Pool } from "pg";
|
|
59
|
+
import { buildPgPoolOptions } from "lambda-pool/pg";
|
|
60
|
+
|
|
61
|
+
const pool = new Pool(buildPgPoolOptions(process.env));
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Both also re-exported from the root: `import { buildPgPoolOptions } from "lambda-pool"`.
|
|
65
|
+
|
|
66
|
+
## Diagnostics — lint your connection for serverless
|
|
67
|
+
|
|
68
|
+
Beyond building options, `lambda-pool` can **analyze** a connection config and
|
|
69
|
+
tell you whether it will survive serverless fan-out. Pure function, no I/O:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { inspectEnv, formatReport } from "lambda-pool";
|
|
73
|
+
|
|
74
|
+
const report = inspectEnv(process.env);
|
|
75
|
+
console.log(formatReport(report));
|
|
76
|
+
// lambda-pool diagnostics for mysql://u:***@pg.aivencloud.com/db [aiven]
|
|
77
|
+
// ⚠ SMALL_MAX_CONNECTIONS: Aiven typically caps max_connections around 20; keep the per-instance pool at 1.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
It recognizes the provider from the host (Aiven, Neon, Supabase, PlanetScale,
|
|
81
|
+
RDS/Aurora, Railway, Render, Vercel Postgres) and warns about: pool sizes too
|
|
82
|
+
large for the provider's budget, SSL requested in the URL with no CA supplied,
|
|
83
|
+
and using a direct host when a pooled endpoint is available.
|
|
84
|
+
|
|
85
|
+
## CLI
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Lint the connection in your env (exit 1 on any warning — good as a CI gate)
|
|
89
|
+
DATABASE_URL=postgres://… npx lambda-pool inspect
|
|
90
|
+
|
|
91
|
+
# Full preflight check (config + diagnostics) — strict gate, exit 1 on any issue
|
|
92
|
+
DATABASE_URL=postgres://… npx lambda-pool doctor
|
|
93
|
+
|
|
94
|
+
# Recommend a pool size straight from a connection URL (detects the provider)
|
|
95
|
+
npx lambda-pool recommend "postgres://…@db.aivencloud.com/app" 10
|
|
96
|
+
|
|
97
|
+
# Recommend from raw numbers: max_connections, instances, [reserved], [other]
|
|
98
|
+
npx lambda-pool budget 100 20
|
|
99
|
+
# recommended pool limit: 4
|
|
100
|
+
# 97 usable connections (100 max − 3 reserved − 0 other) ÷ 20 instances → pool of 4 per instance (peak 80).
|
|
101
|
+
|
|
102
|
+
# List recognized providers
|
|
103
|
+
npx lambda-pool providers
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Budget calculator (programmatic)
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { recommendPoolLimit } from "lambda-pool";
|
|
110
|
+
|
|
111
|
+
const { recommendedPoolLimit, exceedsBudget, rationale } = recommendPoolLimit({
|
|
112
|
+
maxConnections: 20, // your DB's max_connections
|
|
113
|
+
expectedInstances: 30, // peak warm serverless instances
|
|
114
|
+
});
|
|
115
|
+
// recommendedPoolLimit: 1, exceedsBudget: true → use a pooler
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Connection-string utilities
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { parseConnectionString, redactUrl } from "lambda-pool";
|
|
122
|
+
|
|
123
|
+
redactUrl("postgres://u:secret@host/db"); // → "postgres://u:***@host/db"
|
|
124
|
+
parseConnectionString("mysql://root@127.0.0.1/test").port; // → 3306
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Health checks
|
|
128
|
+
|
|
129
|
+
Driver-agnostic readiness probe. Works with any pool that has a `query()`
|
|
130
|
+
method (both `mysql2` and `pg` do), so `lambda-pool` stays dependency-free:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { checkHealth } from "lambda-pool";
|
|
134
|
+
|
|
135
|
+
const { healthy, latencyMs, error } = await checkHealth(pool, { timeoutMs: 2000 });
|
|
136
|
+
// use in a /healthz endpoint — never throws
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Retry transient connect errors
|
|
140
|
+
|
|
141
|
+
Cold starts and brief failovers cause transient connect errors. `withRetry`
|
|
142
|
+
wraps an operation with jittered exponential backoff:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { withRetry, isTransientDbError } from "lambda-pool";
|
|
146
|
+
|
|
147
|
+
const client = await withRetry(() => pool.connect(), {
|
|
148
|
+
attempts: 4,
|
|
149
|
+
retryable: isTransientDbError, // don't retry auth failures
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Preflight (startup gate)
|
|
154
|
+
|
|
155
|
+
Run a single check at boot that combines config validation, diagnostics, and an
|
|
156
|
+
optional live reachability probe. The probe is **injected**, so the check stays
|
|
157
|
+
pure unless you opt into a real connection:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { preflight } from "lambda-pool";
|
|
161
|
+
import { isReachable } from "lambda-pool/health";
|
|
162
|
+
|
|
163
|
+
const result = await preflight(process.env, {
|
|
164
|
+
probe: () => isReachable(pool), // optional live check
|
|
165
|
+
});
|
|
166
|
+
if (!result.ok) {
|
|
167
|
+
console.error(result.diagnostics);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Redact objects for logging
|
|
173
|
+
|
|
174
|
+
`redactUrl` masks a connection string; `redact` masks whole objects (config
|
|
175
|
+
dumps, error context) by key name, so secrets never reach your log aggregator:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { redact } from "lambda-pool";
|
|
179
|
+
|
|
180
|
+
redact({ host: "db", password: "p", nested: { token: "t" } });
|
|
181
|
+
// → { host: "db", password: "***", nested: { token: "***" } }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Build a connection string from parts
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { buildDsn } from "lambda-pool";
|
|
188
|
+
|
|
189
|
+
buildDsn({ engine: "postgres", host: "db", user: "u", password: "p/w", database: "app" });
|
|
190
|
+
// → "postgres://u:p%2Fw@db:5432/app" (credentials safely encoded)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Result type
|
|
194
|
+
|
|
195
|
+
Non-throwing variants return a small `Result` you can branch on:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { safeParseConnectionString } from "lambda-pool";
|
|
199
|
+
|
|
200
|
+
const r = safeParseConnectionString(process.env.DATABASE_URL ?? "");
|
|
201
|
+
if (!r.ok) { /* handle r.error */ } else { /* use r.value */ }
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## API surface
|
|
205
|
+
|
|
206
|
+
| Import | Exports |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `lambda-pool/mysql` | `buildMysqlPoolOptions` |
|
|
209
|
+
| `lambda-pool/pg` | `buildPgPoolOptions` |
|
|
210
|
+
| `lambda-pool/url` | `parseConnectionString`, `safeParseConnectionString`, `redactUrl`, `urlRequestsSsl` |
|
|
211
|
+
| `lambda-pool/providers` | `detectProvider`, `listProviders`, `isPooledEndpoint` |
|
|
212
|
+
| `lambda-pool/budget` | `recommendPoolLimit` |
|
|
213
|
+
| `lambda-pool/diagnostics` | `diagnose`, `formatReport` |
|
|
214
|
+
| `lambda-pool/recommend` | `recommendForUrl` |
|
|
215
|
+
| `lambda-pool/preflight` | `preflight` |
|
|
216
|
+
| `lambda-pool/config` | `loadPoolConfig` |
|
|
217
|
+
| `lambda-pool/dsn` | `buildDsn` |
|
|
218
|
+
| `lambda-pool/redact` | `redact` |
|
|
219
|
+
| `lambda-pool/health` | `checkHealth`, `isReachable` |
|
|
220
|
+
| `lambda-pool/retry` | `withRetry`, `backoffDelay`, `isTransientDbError` |
|
|
221
|
+
| `lambda-pool/result` | `Result`, `ok`, `err`, `attempt`, `unwrap` |
|
|
222
|
+
|
|
223
|
+
All of the above are also re-exported from the package root.
|
|
224
|
+
|
|
225
|
+
## Environment variables
|
|
226
|
+
|
|
227
|
+
| Variable | Purpose | Default |
|
|
228
|
+
|---|---|---|
|
|
229
|
+
| `DATABASE_URL` | Connection URI. Aliases: `MYSQL_URL` / `POSTGRES_URL` / `PG_URL`. | **required** |
|
|
230
|
+
| `DATABASE_POOL_LIMIT` | Per-instance pool size. Raise **only** behind a pooler (PgBouncer, Neon pooled endpoint) or on a bigger plan. | `1` |
|
|
231
|
+
| `DATABASE_SSL_CA_BASE64` | Base64 of your provider's CA cert → enables strict TLS. | off |
|
|
232
|
+
|
|
233
|
+
A non-positive or non-numeric `DATABASE_POOL_LIMIT` is ignored and falls back to
|
|
234
|
+
the default, so a bad env var can never silently widen the pool.
|
|
235
|
+
|
|
236
|
+
## What the defaults are
|
|
237
|
+
|
|
238
|
+
**MySQL** (`mysql2` `PoolOptions`): `connectionLimit: 1`, `maxIdle: 1`,
|
|
239
|
+
`idleTimeout: 30000`, `enableKeepAlive: true`, `waitForConnections: true`,
|
|
240
|
+
`queueLimit: 0`.
|
|
241
|
+
|
|
242
|
+
**Postgres** (`pg` `PoolConfig`): `max: 1`, `idleTimeoutMillis: 30000`,
|
|
243
|
+
`connectionTimeoutMillis: 10000`, `maxUses: 7500`, `allowExitOnIdle: true`.
|
|
244
|
+
|
|
245
|
+
Override the default size in code without an env var:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
buildPgPoolOptions(process.env, { defaultPoolLimit: 2 }); // behind a pooler
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### A note on TLS
|
|
252
|
+
|
|
253
|
+
Managed providers hand you a CA bundle, but the URI's `?ssl-mode=REQUIRED` /
|
|
254
|
+
`?sslmode=require` param is **not** interpreted by `mysql2` / `pg` the way people
|
|
255
|
+
expect. Pass the CA explicitly via `DATABASE_SSL_CA_BASE64` and the server is
|
|
256
|
+
verified (`rejectUnauthorized: true`).
|
|
257
|
+
|
|
258
|
+
## Architecture
|
|
259
|
+
|
|
260
|
+
The source is organized into strict clean-architecture layers
|
|
261
|
+
(`core → application → adapters → presentation`) with the dependency rule
|
|
262
|
+
enforced in CI. See [ARCHITECTURE.md](./ARCHITECTURE.md).
|
|
263
|
+
|
|
264
|
+
## Zero runtime dependencies
|
|
265
|
+
|
|
266
|
+
`lambda-pool` imports nothing at runtime. `mysql2` / `pg` are **your** dependency
|
|
267
|
+
and only `devDependencies` here (for tests/types). You stay in control of the
|
|
268
|
+
driver version.
|
|
269
|
+
|
|
270
|
+
## Development
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
npm install
|
|
274
|
+
npm run typecheck
|
|
275
|
+
npm test # hermetic unit tests, no DB needed
|
|
276
|
+
npm run build
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Integration tests run the option objects against real `mysql2` / `pg` pools,
|
|
280
|
+
using throwaway containers whose `max_connections` is pinned to 10 to mirror a
|
|
281
|
+
free tier:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
docker compose -f docker-compose.test.yml up -d
|
|
285
|
+
RUN_DB_TESTS=1 npm run test:integration
|
|
286
|
+
docker compose -f docker-compose.test.yml down -v
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
MIT
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The minimal surface needed to run a trivial probe query. Both
|
|
3
|
+
* `mysql2`'s pool and `pg`'s pool structurally satisfy this.
|
|
4
|
+
*/
|
|
5
|
+
export interface Queryable {
|
|
6
|
+
query(sql: string): Promise<unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface HealthResult {
|
|
9
|
+
healthy: boolean;
|
|
10
|
+
/** Round-trip latency of the probe query, in milliseconds. */
|
|
11
|
+
latencyMs: number;
|
|
12
|
+
/** Present when the probe failed. */
|
|
13
|
+
error?: Error;
|
|
14
|
+
}
|
|
15
|
+
export interface HealthOptions {
|
|
16
|
+
/** SQL used to probe. Defaults to `SELECT 1`. */
|
|
17
|
+
probeSql?: string;
|
|
18
|
+
/** Fail the probe if it takes longer than this many ms. */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run a probe query against any `Queryable` and report health + latency.
|
|
23
|
+
*
|
|
24
|
+
* Never throws — failures are returned in the result so callers can use it
|
|
25
|
+
* directly in a readiness endpoint.
|
|
26
|
+
*/
|
|
27
|
+
export declare function checkHealth(db: Queryable, options?: HealthOptions): Promise<HealthResult>;
|
|
28
|
+
/** Convenience: true/false readiness, swallowing the detail. */
|
|
29
|
+
export declare function isReachable(db: Queryable, options?: HealthOptions): Promise<boolean>;
|
|
30
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/adapters/health.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAWD;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,SAAS,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAwBvB;AAED,gEAAgE;AAChE,wBAAsB,WAAW,CAC/B,EAAE,EAAE,SAAS,EACb,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,OAAO,CAAC,CAGlB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Driver-agnostic health checks (Dependency Inversion + Interface Segregation).
|
|
2
|
+
//
|
|
3
|
+
// The package depends on a tiny `Queryable` port — the narrowest surface that
|
|
4
|
+
// both `mysql2` pools and `pg` pools already satisfy — not on a concrete driver.
|
|
5
|
+
// Adapters live next to the builders. This keeps `lambda-pool` dependency-free
|
|
6
|
+
// while still offering a "is the DB reachable?" helper.
|
|
7
|
+
function timeout(ms) {
|
|
8
|
+
return new Promise((_, reject) => setTimeout(() => reject(new Error(`lambda-pool: health probe timed out after ${ms}ms`)), ms));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Run a probe query against any `Queryable` and report health + latency.
|
|
12
|
+
*
|
|
13
|
+
* Never throws — failures are returned in the result so callers can use it
|
|
14
|
+
* directly in a readiness endpoint.
|
|
15
|
+
*/
|
|
16
|
+
export async function checkHealth(db, options = {}) {
|
|
17
|
+
const sql = options.probeSql ?? "SELECT 1";
|
|
18
|
+
const started = performance.now();
|
|
19
|
+
const probe = (async () => {
|
|
20
|
+
await db.query(sql);
|
|
21
|
+
})();
|
|
22
|
+
const race = options.timeoutMs
|
|
23
|
+
? Promise.race([probe, timeout(options.timeoutMs)]).then(() => ({ ok: true, value: undefined }), (e) => ({ ok: false, error: e }))
|
|
24
|
+
: probe.then(() => ({ ok: true, value: undefined }), (e) => ({ ok: false, error: e }));
|
|
25
|
+
const outcome = await race;
|
|
26
|
+
const latencyMs = Math.round(performance.now() - started);
|
|
27
|
+
return outcome.ok
|
|
28
|
+
? { healthy: true, latencyMs }
|
|
29
|
+
: { healthy: false, latencyMs, error: outcome.error };
|
|
30
|
+
}
|
|
31
|
+
/** Convenience: true/false readiness, swallowing the detail. */
|
|
32
|
+
export async function isReachable(db, options) {
|
|
33
|
+
const r = await checkHealth(db, options);
|
|
34
|
+
return r.healthy;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/adapters/health.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,8EAA8E;AAC9E,iFAAiF;AACjF,+EAA+E;AAC/E,wDAAwD;AA2BxD,SAAS,OAAO,CAAC,EAAU;IACzB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CACR,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6CAA6C,EAAE,IAAI,CAAC,CAAC,EAC5E,EAAE,CACH,CACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAa,EACb,UAAyB,EAAE;IAE3B,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC;IAC3C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAElC,MAAM,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE;QACxB,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,IAAI,GAAiC,OAAO,CAAC,SAAS;QAC1D,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CACpD,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAC/C,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAc,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CACjD;QACH,CAAC,CAAC,KAAK,CAAC,IAAI,CACR,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAC/C,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAc,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CACjD,CAAC;IAEN,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC;IAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;IAE1D,OAAO,OAAO,CAAC,EAAE;QACf,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;QAC9B,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAa,EACb,OAAuB;IAEvB,MAAM,CAAC,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,CAAC,CAAC,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Env } from "../core/env.ts";
|
|
2
|
+
export interface MysqlPoolEnv extends Env {
|
|
3
|
+
/** Connection URI (mysql://...). Alias: MYSQL_URL. */
|
|
4
|
+
DATABASE_URL?: string;
|
|
5
|
+
MYSQL_URL?: string;
|
|
6
|
+
/** Base64-encoded CA cert — when present, enables strict TLS. */
|
|
7
|
+
DATABASE_SSL_CA_BASE64?: string;
|
|
8
|
+
/** Per-instance pool size override; defaults to 1. */
|
|
9
|
+
DATABASE_POOL_LIMIT?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Shape compatible with mysql2 `PoolOptions` (structural — no import needed). */
|
|
12
|
+
export interface MysqlPoolOptions {
|
|
13
|
+
uri: string;
|
|
14
|
+
connectionLimit: number;
|
|
15
|
+
maxIdle: number;
|
|
16
|
+
idleTimeout: number;
|
|
17
|
+
enableKeepAlive: boolean;
|
|
18
|
+
waitForConnections: boolean;
|
|
19
|
+
queueLimit: number;
|
|
20
|
+
ssl?: {
|
|
21
|
+
ca: string;
|
|
22
|
+
rejectUnauthorized: boolean;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface BuildMysqlOptions {
|
|
26
|
+
/** Override the default pool size of 1. */
|
|
27
|
+
defaultPoolLimit?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build serverless-safe mysql2 pool options.
|
|
31
|
+
*
|
|
32
|
+
* - `connectionLimit` defaults to 1 (one connection per warm lambda). Raise it
|
|
33
|
+
* only behind a connection pooler or on a plan with headroom, via
|
|
34
|
+
* `DATABASE_POOL_LIMIT`.
|
|
35
|
+
* - `maxIdle: 1` + `idleTimeout` lets idle lambdas release their connection so
|
|
36
|
+
* they don't sit on a slot of a tiny `max_connections` budget.
|
|
37
|
+
* - TLS is enabled with strict verification when `DATABASE_SSL_CA_BASE64` is set.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildMysqlPoolOptions(env: MysqlPoolEnv, opts?: BuildMysqlOptions): MysqlPoolOptions;
|
|
40
|
+
//# sourceMappingURL=mysql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../src/adapters/mysql.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,GAAG,EAIT,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,YAAa,SAAQ,GAAG;IACvC,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sDAAsD;IACtD,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,OAAO,CAAA;KAAE,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,YAAY,EACjB,IAAI,GAAE,iBAAsB,GAC3B,gBAAgB,CAuBlB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Serverless-safe pool options for mysql2.
|
|
2
|
+
//
|
|
3
|
+
// Returns a PLAIN options object — you pass it to your own
|
|
4
|
+
// `mysql.createPool(...)`, so this module has zero runtime dependencies and is
|
|
5
|
+
// not pinned to any mysql2 version.
|
|
6
|
+
import { decodeCaBase64, firstEnv, resolvePoolLimit, } from "../core/env.js";
|
|
7
|
+
/**
|
|
8
|
+
* Build serverless-safe mysql2 pool options.
|
|
9
|
+
*
|
|
10
|
+
* - `connectionLimit` defaults to 1 (one connection per warm lambda). Raise it
|
|
11
|
+
* only behind a connection pooler or on a plan with headroom, via
|
|
12
|
+
* `DATABASE_POOL_LIMIT`.
|
|
13
|
+
* - `maxIdle: 1` + `idleTimeout` lets idle lambdas release their connection so
|
|
14
|
+
* they don't sit on a slot of a tiny `max_connections` budget.
|
|
15
|
+
* - TLS is enabled with strict verification when `DATABASE_SSL_CA_BASE64` is set.
|
|
16
|
+
*/
|
|
17
|
+
export function buildMysqlPoolOptions(env, opts = {}) {
|
|
18
|
+
const uri = firstEnv(env, "DATABASE_URL", "MYSQL_URL");
|
|
19
|
+
if (!uri) {
|
|
20
|
+
throw new Error("lambda-pool: DATABASE_URL (or MYSQL_URL) is not set — cannot build a MySQL pool.");
|
|
21
|
+
}
|
|
22
|
+
const ssl = decodeCaBase64(env.DATABASE_SSL_CA_BASE64);
|
|
23
|
+
return {
|
|
24
|
+
uri,
|
|
25
|
+
connectionLimit: resolvePoolLimit(env.DATABASE_POOL_LIMIT, opts.defaultPoolLimit ?? 1),
|
|
26
|
+
maxIdle: 1,
|
|
27
|
+
idleTimeout: 30_000,
|
|
28
|
+
enableKeepAlive: true,
|
|
29
|
+
waitForConnections: true,
|
|
30
|
+
queueLimit: 0,
|
|
31
|
+
...(ssl ? { ssl } : {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=mysql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../src/adapters/mysql.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,2DAA2D;AAC3D,+EAA+E;AAC/E,oCAAoC;AAEpC,OAAO,EAEL,cAAc,EACd,QAAQ,EACR,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AA6BxB;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAiB,EACjB,OAA0B,EAAE;IAE5B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IACvD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAEvD,OAAO;QACL,GAAG;QACH,eAAe,EAAE,gBAAgB,CAC/B,GAAG,CAAC,mBAAmB,EACvB,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAC3B;QACD,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,MAAM;QACnB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,IAAI;QACxB,UAAU,EAAE,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Env } from "../core/env.ts";
|
|
2
|
+
export interface PgPoolEnv extends Env {
|
|
3
|
+
/** Connection URI (postgres://...). Aliases: POSTGRES_URL, PG_URL. */
|
|
4
|
+
DATABASE_URL?: string;
|
|
5
|
+
POSTGRES_URL?: string;
|
|
6
|
+
PG_URL?: string;
|
|
7
|
+
/** Base64-encoded CA cert — when present, enables strict TLS. */
|
|
8
|
+
DATABASE_SSL_CA_BASE64?: string;
|
|
9
|
+
/** Per-instance pool size override; defaults to 1. */
|
|
10
|
+
DATABASE_POOL_LIMIT?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Shape compatible with pg `PoolConfig` (structural — no import needed). */
|
|
13
|
+
export interface PgPoolOptions {
|
|
14
|
+
connectionString: string;
|
|
15
|
+
/** pg calls this `max` (mysql2 calls it `connectionLimit`). */
|
|
16
|
+
max: number;
|
|
17
|
+
/** Close a connection after it sits idle this long (ms). 0 disables. */
|
|
18
|
+
idleTimeoutMillis: number;
|
|
19
|
+
/** Fail fast instead of hanging when the DB has no free slots (ms). */
|
|
20
|
+
connectionTimeoutMillis: number;
|
|
21
|
+
/** Recycle a connection after this many uses (0 = never). */
|
|
22
|
+
maxUses: number;
|
|
23
|
+
/** Don't keep the event loop alive for idle clients. */
|
|
24
|
+
allowExitOnIdle: boolean;
|
|
25
|
+
ssl?: {
|
|
26
|
+
ca: string;
|
|
27
|
+
rejectUnauthorized: boolean;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface BuildPgOptions {
|
|
31
|
+
/** Override the default pool size of 1. */
|
|
32
|
+
defaultPoolLimit?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build serverless-safe `pg` pool options.
|
|
36
|
+
*
|
|
37
|
+
* - `max` defaults to 1 (one connection per warm lambda). Raise it only behind
|
|
38
|
+
* a pooler (PgBouncer / Neon pooled endpoint) via `DATABASE_POOL_LIMIT`.
|
|
39
|
+
* - `idleTimeoutMillis` + `allowExitOnIdle` let an idle lambda release its slot
|
|
40
|
+
* of a tiny `max_connections` budget and not pin the process open.
|
|
41
|
+
* - `connectionTimeoutMillis` makes "too many clients" surface as a fast error
|
|
42
|
+
* rather than a hung request.
|
|
43
|
+
* - TLS is enabled with strict verification when `DATABASE_SSL_CA_BASE64` is set.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildPgPoolOptions(env: PgPoolEnv, opts?: BuildPgOptions): PgPoolOptions;
|
|
46
|
+
//# sourceMappingURL=pg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,GAAG,EAIT,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,SAAU,SAAQ,GAAG;IACpC,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sDAAsD;IACtD,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,uBAAuB,EAAE,MAAM,CAAC;IAChC,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,eAAe,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,OAAO,CAAA;KAAE,CAAC;CACnD;AAED,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,SAAS,EACd,IAAI,GAAE,cAAmB,GACxB,aAAa,CAwBf"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Serverless-safe pool options for node-postgres (`pg`).
|
|
2
|
+
//
|
|
3
|
+
// Returns a PLAIN options object — you pass it to your own `new pg.Pool(...)`,
|
|
4
|
+
// so this module has zero runtime dependencies and is not pinned to any pg
|
|
5
|
+
// version.
|
|
6
|
+
import { decodeCaBase64, firstEnv, resolvePoolLimit, } from "../core/env.js";
|
|
7
|
+
/**
|
|
8
|
+
* Build serverless-safe `pg` pool options.
|
|
9
|
+
*
|
|
10
|
+
* - `max` defaults to 1 (one connection per warm lambda). Raise it only behind
|
|
11
|
+
* a pooler (PgBouncer / Neon pooled endpoint) via `DATABASE_POOL_LIMIT`.
|
|
12
|
+
* - `idleTimeoutMillis` + `allowExitOnIdle` let an idle lambda release its slot
|
|
13
|
+
* of a tiny `max_connections` budget and not pin the process open.
|
|
14
|
+
* - `connectionTimeoutMillis` makes "too many clients" surface as a fast error
|
|
15
|
+
* rather than a hung request.
|
|
16
|
+
* - TLS is enabled with strict verification when `DATABASE_SSL_CA_BASE64` is set.
|
|
17
|
+
*/
|
|
18
|
+
export function buildPgPoolOptions(env, opts = {}) {
|
|
19
|
+
const connectionString = firstEnv(env, "DATABASE_URL", "POSTGRES_URL", "PG_URL");
|
|
20
|
+
if (!connectionString) {
|
|
21
|
+
throw new Error("lambda-pool: DATABASE_URL (or POSTGRES_URL / PG_URL) is not set — cannot build a Postgres pool.");
|
|
22
|
+
}
|
|
23
|
+
const ssl = decodeCaBase64(env.DATABASE_SSL_CA_BASE64);
|
|
24
|
+
return {
|
|
25
|
+
connectionString,
|
|
26
|
+
max: resolvePoolLimit(env.DATABASE_POOL_LIMIT, opts.defaultPoolLimit ?? 1),
|
|
27
|
+
idleTimeoutMillis: 30_000,
|
|
28
|
+
connectionTimeoutMillis: 10_000,
|
|
29
|
+
maxUses: 7_500,
|
|
30
|
+
allowExitOnIdle: true,
|
|
31
|
+
...(ssl ? { ssl } : {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,+EAA+E;AAC/E,2EAA2E;AAC3E,WAAW;AAEX,OAAO,EAEL,cAAc,EACd,QAAQ,EACR,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAkCxB;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAc,EACd,OAAuB,EAAE;IAEzB,MAAM,gBAAgB,GAAG,QAAQ,CAC/B,GAAG,EACH,cAAc,EACd,cAAc,EACd,QAAQ,CACT,CAAC;IACF,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,iGAAiG,CAClG,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAEvD,OAAO;QACL,gBAAgB;QAChB,GAAG,EAAE,gBAAgB,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC1E,iBAAiB,EAAE,MAAM;QACzB,uBAAuB,EAAE,MAAM;QAC/B,OAAO,EAAE,KAAK;QACd,eAAe,EAAE,IAAI;QACrB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ProviderId } from "../core/providers.ts";
|
|
2
|
+
export type Severity = "error" | "warning" | "info";
|
|
3
|
+
export interface Diagnostic {
|
|
4
|
+
severity: Severity;
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DiagnoseInput {
|
|
9
|
+
/** The connection URI to analyze. */
|
|
10
|
+
url: string;
|
|
11
|
+
/** The pool size you intend to use (per warm instance). */
|
|
12
|
+
poolLimit: number;
|
|
13
|
+
/** Whether a CA cert was supplied out-of-band (DATABASE_SSL_CA_BASE64). */
|
|
14
|
+
hasCaCert?: boolean;
|
|
15
|
+
/** Peak warm instances, for budget checks. Defaults to a typical serverless fan-out. */
|
|
16
|
+
expectedInstances?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface DiagnoseReport {
|
|
19
|
+
/** Password-redacted URL, safe to log alongside the report. */
|
|
20
|
+
safeUrl: string;
|
|
21
|
+
provider: ProviderId;
|
|
22
|
+
diagnostics: Diagnostic[];
|
|
23
|
+
/** True when no `error`-severity diagnostics are present. */
|
|
24
|
+
ok: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Analyze a connection config for serverless safety. Pure: returns a report,
|
|
28
|
+
* performs no I/O.
|
|
29
|
+
*/
|
|
30
|
+
export declare function diagnose(input: DiagnoseInput): DiagnoseReport;
|
|
31
|
+
/** Format a report as plain text lines (for CLI / startup logs). */
|
|
32
|
+
export declare function formatReport(report: DiagnoseReport): string;
|
|
33
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/application/diagnostics.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGzF,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wFAAwF;IACxF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,UAAU,CAAC;IACrB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,6DAA6D;IAC7D,EAAE,EAAE,OAAO,CAAC;CACb;AAID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAiF7D;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAM3D"}
|