@steadybrew/postgresjs 4.0.0 → 4.2.0-rc1
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/README.md +53 -11
- package/cf/src/connection.js +307 -322
- package/cf/src/errors.js +2 -2
- package/cf/src/index.js +138 -81
- package/cf/src/query.js +18 -3
- package/cf/src/subscribe.js +1 -0
- package/cf/src/timeout.js +5 -0
- package/cf/src/transport.js +88 -0
- package/cf/src/types.js +2 -2
- package/cf/src/vercel.js +20 -0
- package/cjs/src/connection.js +307 -322
- package/cjs/src/errors.js +2 -2
- package/cjs/src/index.js +138 -81
- package/cjs/src/query.js +18 -3
- package/cjs/src/subscribe.js +1 -0
- package/cjs/src/timeout.js +5 -0
- package/cjs/src/transport.js +88 -0
- package/cjs/src/types.js +2 -2
- package/cjs/src/vercel.js +20 -0
- package/package.json +19 -7
- package/src/connection.js +307 -322
- package/src/errors.js +2 -2
- package/src/index.js +138 -81
- package/src/query.js +18 -3
- package/src/subscribe.js +1 -0
- package/src/timeout.js +5 -0
- package/src/transport.js +88 -0
- package/src/types.js +2 -2
- package/src/vercel.js +20 -0
- package/types/index.d.ts +7 -1
- package/types/vercel.d.ts +8 -0
package/README.md
CHANGED
|
@@ -11,24 +11,35 @@ This is an independently maintained fork of [Postgres.js](https://github.com/por
|
|
|
11
11
|
- 🏄♀️ Simple surface API
|
|
12
12
|
- 🖊️ Dynamic query support
|
|
13
13
|
|
|
14
|
-
<br>
|
|
14
|
+
<br clear="all">
|
|
15
15
|
|
|
16
16
|
## Compatibility policy
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
**Version 4 requires Node.js 24 or newer** and supports PostgreSQL 15–18. Version 4.0.0 raised the minimum Node.js version from 12. The minimum stays at Node 24 until an explicit policy change; newly maintained Node majors are tested before compatibility is claimed.
|
|
19
19
|
|
|
20
20
|
| Runtime | PostgreSQL target | CI jobs | Validation status |
|
|
21
21
|
| --- | --- | ---: | --- |
|
|
22
|
-
| Node 24, ESM and CJS | 15, 16, 17, 18 | 4 |
|
|
23
|
-
| Node 26, ESM and CJS | 15, 16, 17, 18 | 4 |
|
|
24
|
-
| Deno 1.46.3 | 17 | 1 |
|
|
25
|
-
| Cloudflare workerd, Wrangler 4.123.0 | 17 | 1 |
|
|
22
|
+
| Node 24, ESM and CJS | 15, 16, 17, 18 | 4 | Passed release-candidate CI |
|
|
23
|
+
| Node 26, ESM and CJS | 15, 16, 17, 18 | 4 | Passed release-candidate CI |
|
|
24
|
+
| Deno 1.46.3 | 17 | 1 | Passed release-candidate CI; no Deno 2 claim |
|
|
25
|
+
| Cloudflare workerd, Wrangler 4.123.0 | 17 | 1 | Passed release-candidate CI; known "Stream was cancelled" rejection remains |
|
|
26
26
|
| Bun export | No dedicated target | 0 | Retained as best effort; unverified, without dedicated CI |
|
|
27
27
|
|
|
28
|
-
The core Node matrix has eight jobs
|
|
28
|
+
All ten [CI jobs](https://github.com/steadybrew/postgresjs/actions/runs/37943516565) passed for 4.1.0. The core Node matrix has eight jobs; Deno and Cloudflare run independently. PostgreSQL versions below 15 are outside the supported matrix. See the [release notes](./CHANGELOG.md#v410---2026-10-09) for validation details and [known limitations](./CHANGELOG.md#known-limitations), including the Cloudflare cancellation rejection tolerated by its CI gate.
|
|
29
29
|
|
|
30
30
|
Supabase PostgreSQL and Supabase Edge are separate environments. Deno 1.46.3 coverage does not imply Deno 2 or hosted Supabase Edge certification.
|
|
31
31
|
|
|
32
|
+
## Upgrading to 4.0.0
|
|
33
|
+
|
|
34
|
+
Version 4.0.0 fixes connection startup, reservations, reconnects, shutdown, transaction ownership, and built-in array handling. When upgrading from `@steadybrew/postgresjs` 3.x:
|
|
35
|
+
|
|
36
|
+
- Upgrade to **Node.js 24 or newer** before installing.
|
|
37
|
+
- Keep queries within the reservation or transaction that owns them. Reserved handles used after `release()`, and transaction handles used after completion, reject with `CONNECTION_ENDED`. A handle whose connection has closed cannot run queries on a reconnected session.
|
|
38
|
+
- Pass a non-empty string without NUL characters to transaction `sql.prepare(name)`. Invalid names throw `INVALID_TRANSACTION_NAME`.
|
|
39
|
+
- If you use `fetch_types: false`, review code that expects built-in arrays as raw strings: supported built-in arrays are now decoded as JavaScript arrays. SQL `NULL` elements become JavaScript `null`; quoted `"NULL"` text remains a string.
|
|
40
|
+
|
|
41
|
+
See the [changelog](./CHANGELOG.md#breaking-changes-and-migration) for the full migration notes and fixes.
|
|
42
|
+
|
|
32
43
|
## Getting started
|
|
33
44
|
|
|
34
45
|
<br>
|
|
@@ -92,6 +103,7 @@ const { default: postgres } = await import('@steadybrew/postgresjs')
|
|
|
92
103
|
|
|
93
104
|
## Table of Contents
|
|
94
105
|
|
|
106
|
+
* [Upgrading to 4.0.0](#upgrading-to-400)
|
|
95
107
|
* [Connection](#connection)
|
|
96
108
|
* [Queries](#queries)
|
|
97
109
|
* [Building queries](#building-queries)
|
|
@@ -713,11 +725,13 @@ sql.begin('read write', async sql => {
|
|
|
713
725
|
```
|
|
714
726
|
|
|
715
727
|
|
|
716
|
-
#### PREPARE TRANSACTION `
|
|
728
|
+
#### PREPARE TRANSACTION `sql.prepare(name)`
|
|
717
729
|
|
|
718
730
|
Indicates that the transactions should be prepared using the [`PREPARE TRANSACTION [NAME]`](https://www.postgresql.org/docs/current/sql-prepare-transaction.html) statement
|
|
719
731
|
instead of being committed.
|
|
720
732
|
|
|
733
|
+
The name must be a non-empty string without NUL characters; invalid names throw `INVALID_TRANSACTION_NAME`. Quotes and backslashes in valid names are preserved.
|
|
734
|
+
|
|
721
735
|
```js
|
|
722
736
|
sql.begin('read write', async sql => {
|
|
723
737
|
const [user] = await sql`
|
|
@@ -1017,6 +1031,7 @@ const sql = postgres('postgres://username:password@host:port/database', {
|
|
|
1017
1031
|
types : [], // Array of custom types, see more below
|
|
1018
1032
|
onnotice : fn, // Default console.log, set false to silence NOTICE
|
|
1019
1033
|
onparameter : fn, // (key, value) when server param change
|
|
1034
|
+
onidle : fn, // (connId) when a connection returns to the pool idle
|
|
1020
1035
|
debug : fn, // Is called with (connection, query, params, types)
|
|
1021
1036
|
socket : fn, // fn returning custom socket to use
|
|
1022
1037
|
transform : {
|
|
@@ -1114,7 +1129,7 @@ By default, connections will not close until `.end()` is called. However, it may
|
|
|
1114
1129
|
- using Postgres.js in a Serverless environment (Lambda, etc.)
|
|
1115
1130
|
- using Postgres.js with a database service that automatically closes connections after some time (see [`ECONNRESET` issue](https://github.com/porsager/postgres/issues/179))
|
|
1116
1131
|
|
|
1117
|
-
This can be done using the `idle_timeout` or `max_lifetime` options. These configuration options specify the number of seconds to wait before automatically closing an idle connection and the maximum time a connection can exist, respectively.
|
|
1132
|
+
This can be done using the `idle_timeout` or `max_lifetime` options. These configuration options specify the number of seconds to wait before automatically closing an idle connection and the maximum time a connection can exist, respectively. Both are also checked when an idle connection is handed out, so an idle connection that is past either limit (for example after a serverless instance was frozen) is closed instead of being used.
|
|
1118
1133
|
|
|
1119
1134
|
For example, to close a connection that has either been idle for 20 seconds or existed for more than 30 minutes:
|
|
1120
1135
|
|
|
@@ -1125,6 +1140,21 @@ const sql = postgres({
|
|
|
1125
1140
|
})
|
|
1126
1141
|
```
|
|
1127
1142
|
|
|
1143
|
+
### Vercel Fluid Compute
|
|
1144
|
+
|
|
1145
|
+
On Vercel's Fluid Compute an instance can be suspended while a connection sits idle and before `idle_timeout` has closed it, which leaves the connection open on the server. `attachDatabasePool` from `@vercel/functions` keeps the instance alive until idle connections have closed. Pass it the pool through `vercelPool`:
|
|
1146
|
+
|
|
1147
|
+
```js
|
|
1148
|
+
import postgres from '@steadybrew/postgresjs'
|
|
1149
|
+
import { vercelPool } from '@steadybrew/postgresjs/vercel'
|
|
1150
|
+
import { attachDatabasePool } from '@vercel/functions'
|
|
1151
|
+
|
|
1152
|
+
const sql = postgres({ idle_timeout: 5 })
|
|
1153
|
+
attachDatabasePool(vercelPool(sql))
|
|
1154
|
+
```
|
|
1155
|
+
|
|
1156
|
+
`vercelPool` requires `idle_timeout` to be a number of seconds. It hooks into the `onidle` option, which is called with the connection id each time a connection returns to the pool idle and its idle timer starts, and it keeps any `onidle` you set yourself. If `onidle` throws, the error is rethrown as an uncaught exception and the connection is not affected. A connection that was frozen past `idle_timeout` anyway is closed when it is next handed out (see [Connection timeout](#connection-timeout)).
|
|
1157
|
+
|
|
1128
1158
|
### Cloudflare Workers support
|
|
1129
1159
|
|
|
1130
1160
|
Postgres.js has built-in support for the [TCP socket API](https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/) in Cloudflare Workers, which is [on-track](https://github.com/wintercg/proposal-sockets-api) to be standardized and adopted in Node.js and other JavaScript runtimes, such as Deno.
|
|
@@ -1291,6 +1321,8 @@ await reserved.release()
|
|
|
1291
1321
|
|
|
1292
1322
|
Once you have finished with the reserved connection, call `release` to add it back to the pool.
|
|
1293
1323
|
|
|
1324
|
+
After release, queries through that reserved handle reject with `CONNECTION_ENDED`. Call `sql.reserve()` again to acquire a new handle. A reserved handle whose connection has closed cannot be reused after reconnect.
|
|
1325
|
+
|
|
1294
1326
|
## Error handling
|
|
1295
1327
|
|
|
1296
1328
|
Errors are all thrown to related queries and never globally. Errors coming from database itself are always in the [native Postgres format](https://www.postgresql.org/docs/current/errcodes-appendix.html), and the same goes for any [Node.js errors](https://nodejs.org/api/errors.html#errors_common_system_errors) eg. coming from the underlying connection.
|
|
@@ -1331,6 +1363,16 @@ When using SASL authentication the server responds with a signature at the end o
|
|
|
1331
1363
|
|
|
1332
1364
|
Making queries has to be done using the sql function as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates). This is to ensure parameters are serialized and passed to Postgres as query parameters with correct types and to avoid SQL injection.
|
|
1333
1365
|
|
|
1366
|
+
##### SSL_NOT_SUPPORTED
|
|
1367
|
+
> The server does not support SSL connections
|
|
1368
|
+
|
|
1369
|
+
The server answered the SSL request with a refusal while `ssl` is set to `require` (or another mode that does not fall back to plain text). The attempt fails at once for a single host. Use `ssl: 'prefer'` to fall back to an unencrypted connection, or enable SSL on the server.
|
|
1370
|
+
|
|
1371
|
+
##### TARGET_SESSION_ATTRS
|
|
1372
|
+
> No host matched target_session_attrs=read-write: localhost:5432 is read-only
|
|
1373
|
+
|
|
1374
|
+
No host satisfied [`target_session_attrs`](#connection-details). This error is the `cause` of the `CONNECTION_CLOSED` error the query rejects with, so retry logic keyed on `CONNECTION_CLOSED` keeps working; read `err.cause.code` and `err.cause.message` for the reason. The message names the requested value and each host with the reason it was rejected. With several hosts, the connection fails at once when every host answered and none matched; if any host failed for another reason (refused, closed, timed out), the client keeps retrying until `connect_timeout` instead, since a failover may be in progress. With a single host, the client keeps retrying until `connect_timeout` before failing, because a single endpoint that is read-only is often in the middle of a failover, for example a cluster DNS name that still points at the old primary.
|
|
1375
|
+
|
|
1334
1376
|
##### AUTH_TYPE_NOT_IMPLEMENTED
|
|
1335
1377
|
> Auth type X not implemented
|
|
1336
1378
|
|
|
@@ -1339,7 +1381,7 @@ Postgres supports many different authentication types. This one is not supported
|
|
|
1339
1381
|
##### CONNECTION_CLOSED
|
|
1340
1382
|
> write CONNECTION_CLOSED host:port
|
|
1341
1383
|
|
|
1342
|
-
This error is thrown if the connection was closed without an error.
|
|
1384
|
+
This error is thrown if the connection was closed, or could not be opened, without an error of its own. When the server or the network ended the session, or no host matched `target_session_attrs`, the underlying error is available as `err.cause`.
|
|
1343
1385
|
|
|
1344
1386
|
##### CONNECTION_ENDED
|
|
1345
1387
|
> write CONNECTION_ENDED host:port
|
|
@@ -1356,7 +1398,7 @@ This error is thrown for any queries that were pending when the timeout to [`sql
|
|
|
1356
1398
|
##### CONNECT_TIMEOUT
|
|
1357
1399
|
> write CONNECT_TIMEOUT host:port
|
|
1358
1400
|
|
|
1359
|
-
The timeout applies to each connection attempt and covers socket creation, TCP and TLS negotiation, authentication, session checks and type discovery. When an attempt times out, the next host is tried. The acquisition as a whole is bounded by `connect_timeout` multiplied by the number of hosts, measured from the first attempt; time spent waiting on an inherited reconnect delay is not counted. Set it with `connect_timeout` or `PGCONNECT_TIMEOUT` (30 seconds by default); zero disables both limits.
|
|
1401
|
+
The timeout applies to each connection attempt and covers socket creation, TCP and TLS negotiation, authentication, session checks and type discovery. When an attempt times out, the next host is tried. The acquisition as a whole is bounded by `connect_timeout` multiplied by the number of hosts, measured from the first attempt; time spent waiting on an inherited reconnect delay is not counted. Set it with `connect_timeout` or `PGCONNECT_TIMEOUT` (30 seconds by default); zero disables both limits. The same value also bounds a graceful close: if the server does not close the socket within `connect_timeout` seconds after `end()` sends Terminate, the connection is closed anyway; zero leaves a graceful close unbounded.
|
|
1360
1402
|
|
|
1361
1403
|
If the only attempt times out, the error is `CONNECT_TIMEOUT`. Once earlier attempts have failed, exhausting the overall budget reports the earlier error, such as the last server error or `CONNECTION_CLOSED`. With a single host, a socket or socket factory error rejects the query once; with several hosts, errors keep cycling through the hosts with backoff until the budget is spent. Queries already sent to the server are not replayed.
|
|
1362
1404
|
|