@steadybrew/postgresjs 3.4.9 → 4.0.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 CHANGED
@@ -13,6 +13,22 @@ This is an independently maintained fork of [Postgres.js](https://github.com/por
13
13
 
14
14
  <br>
15
15
 
16
+ ## Compatibility policy
17
+
18
+ The next release raises the npm package's minimum Node.js version to **24**. This is a breaking compatibility change for applications using older Node versions. The minimum stays at Node 24 until an explicit policy change; newly maintained Node majors are tested before compatibility is claimed.
19
+
20
+ | Runtime | PostgreSQL target | CI jobs | Validation status |
21
+ | --- | --- | ---: | --- |
22
+ | Node 24, ESM and CJS | 15, 16, 17, 18 | 4 | Locally validated |
23
+ | Node 26, ESM and CJS | 15, 16, 17, 18 | 4 | Configured; local execution pending |
24
+ | Deno 1.46.3 | 17 | 1 | Validated legacy runtime; no Deno 2 claim |
25
+ | Cloudflare workerd, Wrangler 4.123.0 | 17 | 1 | Configured; startup/array, timer, `sql.end()` and TLS gates; #1202 "Stream was cancelled" still open |
26
+ | Bun export | No dedicated target | 0 | Retained as best effort; unverified, without dedicated CI |
27
+
28
+ The core Node matrix has eight jobs. Deno and Cloudflare run independently, so they do not multiply that matrix. PostgreSQL versions below 15 are outside the next release's supported matrix.
29
+
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
+
16
32
  ## Getting started
17
33
 
18
34
  <br>
@@ -1139,11 +1155,15 @@ compatibility_flags = ["nodejs_compat"]
1139
1155
 
1140
1156
  ### Auto fetching of array types
1141
1157
 
1142
- Postgres.js will automatically fetch table/array-type information when it first connects to a database.
1158
+ Postgres.js automatically fetches array-type information when each connection initializes.
1143
1159
 
1144
1160
  If you have revoked access to `pg_catalog` this feature will no longer work and will need to be disabled.
1145
1161
 
1146
- You can disable this feature by setting `fetch_types` to `false`.
1162
+ You can disable catalog discovery by setting `fetch_types` to `false`. A fixed set of 22 common built-in array types still supports parsing and serialization, including text, numeric, boolean, JSON, date, UUID, and byte arrays. This changes earlier `fetch_types: false` behavior, which returned built-in arrays as raw strings. Other built-in, user-defined, and extension arrays still require discovery or explicit type handlers.
1163
+
1164
+ SQL `NULL` elements are returned as JavaScript `null`; a quoted text element `"NULL"` remains a string. Explicit array parsers and serializers are preserved independently. Catalog discovery with `fetch_types: true` remains per connection; this change does not cache catalog metadata.
1165
+
1166
+ Column, value, and row transforms apply to application query results; initialization metadata retains its original shape.
1147
1167
 
1148
1168
  ### Environmental variables
1149
1169
 
@@ -1326,6 +1346,8 @@ This error is thrown if the connection was closed without an error. This should
1326
1346
 
1327
1347
  This error is thrown if the user has called [`sql.end()`](#teardown--cleanup) and performed a query afterward.
1328
1348
 
1349
+ A reserved `sql` used after `release()`, or a transaction `sql` used after `begin()` has committed, rolled back or prepared, also rejects with `CONNECTION_ENDED`.
1350
+
1329
1351
  ##### CONNECTION_DESTROYED
1330
1352
  > write CONNECTION_DESTROYED host:port
1331
1353
 
@@ -1334,7 +1356,9 @@ This error is thrown for any queries that were pending when the timeout to [`sql
1334
1356
  ##### CONNECT_TIMEOUT
1335
1357
  > write CONNECT_TIMEOUT host:port
1336
1358
 
1337
- This error is thrown if the startup phase of the connection (tcp, protocol negotiation, and auth) took more than the default 30 seconds or what was specified using `connect_timeout` or `PGCONNECT_TIMEOUT`.
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.
1360
+
1361
+ 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.
1338
1362
 
1339
1363
  ##### COPY_IN_PROGRESS
1340
1364
  > You cannot execute queries during copy
package/cf/polyfills.js CHANGED
@@ -3,6 +3,7 @@ import { Buffer } from 'node:buffer'
3
3
 
4
4
  const Crypto = globalThis.crypto
5
5
 
6
+ const noop = () => undefined
6
7
  let ids = 1
7
8
  const tasks = new Set()
8
9
 
@@ -115,8 +116,8 @@ export const tls = {
115
116
  tcp.readyState = 'upgrading'
116
117
  tcp.raw = tcp.raw.startTls({ servername })
117
118
  tcp.raw.closed.then(
118
- () => tcp.emit('close'),
119
- (e) => tcp.emit('error', e)
119
+ () => tcp.close(),
120
+ (e) => (tcp.closing || tcp.emit('error', e), tcp.close())
120
121
  )
121
122
  tcp.writer = tcp.raw.writable.getWriter()
122
123
  tcp.reader = tcp.raw.readable.getReader()
@@ -139,7 +140,8 @@ function Socket() {
139
140
  write,
140
141
  end,
141
142
  destroy,
142
- read
143
+ read,
144
+ close
143
145
  })
144
146
 
145
147
  return tcp
@@ -148,14 +150,19 @@ function Socket() {
148
150
  try {
149
151
  tcp.readyState = 'opening'
150
152
  const { connect } = await import('cloudflare:sockets')
151
- tcp.raw = connect(host + ':' + port, tcp.ssl ? { secureTransport: 'starttls' } : {})
153
+ const raw = connect(host + ':' + port, tcp.ssl ? { secureTransport: 'starttls' } : {})
154
+ if (tcp.destroyed || tcp.closing) {
155
+ raw.closed.catch(noop)
156
+ return Promise.resolve(raw.close()).catch(noop)
157
+ }
158
+ tcp.raw = raw
152
159
  tcp.raw.closed.then(
153
160
  () => {
154
161
  tcp.readyState !== 'upgrade'
155
162
  ? close()
156
163
  : ((tcp.readyState = 'open'), tcp.emit('secureConnect'))
157
164
  },
158
- (e) => tcp.emit('error', e)
165
+ (e) => (tcp.closing || tcp.emit('error', e), close())
159
166
  )
160
167
  tcp.writer = tcp.raw.writable.getWriter()
161
168
  tcp.reader = tcp.raw.readable.getReader()
@@ -184,6 +191,10 @@ function Socket() {
184
191
  }
185
192
 
186
193
  function end(data) {
194
+ tcp.closing = true
195
+ if (!tcp.raw)
196
+ return close()
197
+
187
198
  return data
188
199
  ? tcp.write(data, () => tcp.raw.close())
189
200
  : tcp.raw.close()
@@ -206,13 +217,20 @@ function Socket() {
206
217
  }
207
218
 
208
219
  async function readFirst() {
209
- const { value } = await tcp.reader.read()
210
- tcp.emit('data', Buffer.from(value))
220
+ try {
221
+ const { done, value } = await tcp.reader.read()
222
+ if (done)
223
+ return close()
224
+
225
+ tcp.emit('data', Buffer.from(value))
226
+ } catch (err) {
227
+ error(err)
228
+ }
211
229
  }
212
230
 
213
231
  function error(err) {
214
- tcp.emit('error', err)
215
- tcp.emit('close')
232
+ tcp.closing || tcp.emit('error', err)
233
+ close()
216
234
  }
217
235
  }
218
236