From c6028a875f953eff9e8e403622b0aac127d1b4a6 Mon Sep 17 00:00:00 2001 From: Brian C Date: Wed, 4 Mar 2026 18:49:05 -0600 Subject: [PATCH 01/16] Docs updates (#3622) * Add docs for * Add docs for max uses * Clean up casing and grammar in comments * Add more docs on pool sizing * Grammar * Add better footer * Final updates --- docs/pages/apis/pool.mdx | 59 +++++++++++++++++++++++--------- docs/pages/features/queries.mdx | 6 ++-- docs/pages/guides/pool-sizing.md | 12 +++++++ docs/theme.config.js | 30 +++++++++++++++- 4 files changed, 86 insertions(+), 21 deletions(-) diff --git a/docs/pages/apis/pool.mdx b/docs/pages/apis/pool.mdx index fbe0279e1..d9323979e 100644 --- a/docs/pages/apis/pool.mdx +++ b/docs/pages/apis/pool.mdx @@ -16,28 +16,28 @@ The pool is initially created empty and will create new clients lazily as they a ```ts type Config = { - // all valid client config options are also valid here - // in addition here are the pool specific configuration parameters: + // All valid client config options are also valid here. + // In addition here are the pool specific configuration parameters: - // number of milliseconds to wait before timing out when connecting a new client - // by default this is 0 which means no timeout + // Number of milliseconds to wait before timing out when connecting a new client. + // By default this is 0 which means no timeout. connectionTimeoutMillis?: number - // number of milliseconds a client must sit idle in the pool and not be checked out - // before it is disconnected from the backend and discarded - // default is 10000 (10 seconds) - set to 0 to disable auto-disconnection of idle clients + // Number of milliseconds a client must sit idle in the pool and not be checked out + // before it is disconnected from the backend and discarded. + // Default is 10000 (10 seconds) - set to 0 to disable auto-disconnection of idle clients. idleTimeoutMillis?: number - // maximum number of clients the pool should contain - // by default this is set to 10. There is some nuance to setting the maximum size of your pool. - // see https://node-postgres.com/guides/pool-sizing for more information + // Maximum number of clients the pool should contain. + // By default this is set to 10. There is some nuance to setting the maximum size of your pool. + // See https://node-postgres.com/guides/pool-sizing for more information. max?: number - // minimum number of clients the pool should hold on to and _not_ destroy with the idleTimeoutMillis - // this can be useful if you get very bursty traffic and want to keep a few clients around. - // note: current the pool will not automatically create and connect new clients up to the min, it will + // Minimum number of clients the pool should hold on to and _not_ destroy with the idleTimeoutMillis. + // This can be useful if you get very bursty traffic and want to keep a few clients around. + // Note: currently the pool will not automatically create and connect new clients up to the min, it will // only not evict and close clients except those which exceed the min count. - // the default is 0 which disables this behavior. + // The default is 0 which disables this behavior. min?: number // Default behavior is the pool will keep clients open & connected to the backend @@ -47,15 +47,28 @@ type Config = { // // Setting `allowExitOnIdle: true` in the config will allow the node event loop to exit // as soon as all clients in the pool are idle, even if their socket is still open - // to the postgres server. This can be handy in scripts & tests + // to the postgres server. This can be handy in scripts & tests // where you don't want to wait for your clients to go idle before your process exits. allowExitOnIdle?: boolean + // Number of times a client can be checked out from the pool before it is + // disconnected and a new client is created in its place. + // The default is Infinity which means a client will never be automatically destroyed + // outside of other lifecycle events like manually removing it, it timing out due to idleness, etc. + maxUses?: number + // Sets a max overall life for the connection. // A value of 60 would evict connections that have been around for over 60 seconds, // regardless of whether they are idle. It's useful to force rotation of connection pools through - // middleware so that you can rotate the underlying servers. The default is disabled (value of zero) + // middleware so that you can rotate the underlying servers. The default is disabled (value of zero). maxLifetimeSeconds?: number + + // Called once when a new client is created, before it is made available to the pool. + // The client is fully connected and queryable at this point. + // Can be a regular function or an async function. + // If the function throws or returns a promise that rejects, the client is destroyed + // and the error is returned to the caller requesting the connection. + onConnect?: (client: Client) => void | Promise } ``` @@ -70,7 +83,19 @@ const pool = new Pool({ max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, - maxLifetimeSeconds: 60 + maxLifetimeSeconds: 60, +}) +``` + +example using `onConnect` to run setup commands on each new client: + +```js +import { Pool } from 'pg' + +const pool = new Pool({ + onConnect: async (client) => { + await client.query('SET search_path TO my_schema') + }, }) ``` diff --git a/docs/pages/features/queries.mdx b/docs/pages/features/queries.mdx index 39bcfbe1d..63ecdde1e 100644 --- a/docs/pages/features/queries.mdx +++ b/docs/pages/features/queries.mdx @@ -26,7 +26,7 @@ console.log(res.rows[0]) // { name: 'brianc', email: 'brian.m.carlson@gmail.com' } ``` -
+
PostgreSQL does not support parameters for identifiers. If you need to have dynamic database, schema, table, or column names (e.g. in DDL statements) use [pg-format](https://www.npmjs.com/package/pg-format) package for handling escaping these values to ensure you do not have SQL injection!
@@ -99,8 +99,8 @@ console.log(res.rows[0]) In the above example the first time the client sees a query with the name `'fetch-user'` it will send a 'parse' request to the PostgreSQL server & execute the query as normal. The second time, it will skip the 'parse' request and send the _name_ of the query to the PostgreSQL server. -
-
+
+
Be careful not to fall into the trap of premature optimization. Most of your queries will likely not benefit much, if at all, from using prepared statements. This is a somewhat "power user" feature of PostgreSQL that is best used when you know how to use it - namely with very complex queries with lots of joins and advanced operations like union and switch statements. I rarely use this feature in my own apps unless writing complex aggregate queries for reports and I know the reports are going to be executed very frequently.
diff --git a/docs/pages/guides/pool-sizing.md b/docs/pages/guides/pool-sizing.md index 5c7ddaad8..430e69190 100644 --- a/docs/pages/guides/pool-sizing.md +++ b/docs/pages/guides/pool-sizing.md @@ -16,6 +16,14 @@ In this situation, I'd probably set the `max` to 20 or 25. This lets you have pl If the number of instances of your services which connect to your database is more dynamic and based on things like load, auto-scaling containers, or running in cloud-functions, you need to be a bit more thoughtful about what your max might be. Often in these environments, there will be another database pooling proxy in front of the database like pg-bouncer or the RDS-proxy, etc. I'm not sure how all these function exactly, and they all have some trade-offs, but let's assume you're not using a proxy. Then I'd be pretty cautious about how large you set any individual pool. If you're running an application under pretty serious load where you need dynamic scaling or lots of lambdas spinning up and sending queries, your queries are likely fast and you should be fine setting the `max` to a low value like 10 -- or just leave it alone, since `10` is the default. +### Vercel + +If you're running on Vercel with [fluid compute](https://vercel.com/kb/guide/efficiently-manage-database-connection-pools-with-fluid-compute), your serverless functions can handle multiple requests concurrently and stick around between invocations. In this case, you can treat it similarly to a traditional long-lived process and use a default-ish pool size of `10`. The pool will stay warm across requests and you'll get the benefits of connection reuse. You'll probably need to put pgBouncer (or some kind of pooler like what is offered with Supabase, RDS, GCP, etc.) in front of your database, as Vercel worker count can grow quite a bit larger than the number of reasonable max connections Postgres can handle. + +### Cloudflare workers + +In a fully stateless serverless environment like Cloudflare Workers where your worker is killed, suspended, moved to a new compute node, or shut down at the end of every request, you'll still probably be okay with a pool size `max` of `10`, though you can lower it if you start hitting connection exhaustion limits on your pooler. In Cloudflare the pooler is Hyperdrive, and in my experience it works fantastically with their workers setup. Make sure at the end of your serverless handler, after everything is done, you close and dispose of the pool by calling `pool.end()`. Setting the pool to a size larger than 1 is still recommended, as things like tRPC and other server-side routing & request batching code could result in multiple independent queries executing at the same time. With a pool size of `1` you are turning what is "a few things at once" into all things waiting in line one after another on the one available client in the pool. + ## pg-bouncer, RDS-proxy, etc. I'm not sure of all the pooling services for Postgres. I haven't used any myself. Throughout the years of working on `pg`, I've addressed issues caused by various proxies behaving differently than an actual Postgres backend. There are also gotchas with things like transactions. On the other hand, plenty of people run these with much success. In this situation, I would just recommend using some small but reasonable `max` value like the default value of `10` as it can still be helpful to keep a few TCP sockets from your services to the Postgres proxy open. @@ -23,3 +31,7 @@ I'm not sure of all the pooling services for Postgres. I haven't used any myself ## Conclusion, tl;dr It's a bit of a complicated topic and doesn't have much impact on things until you need to start scaling. At that point, your number of connections _still_ probably won't be your scaling bottleneck. It's worth thinking about a bit, but mostly I'd just leave the pool size to the default of `10` until you run into troubles: hopefully you never do! + +## Need help? + +In my career, this has been the most error-prone thing related to running Postgres & Node, particularly with the differences in various serverless providers (Cloudflare, Vercel, Lambda, etc.) versus more traditional hosting. If you have any questions or need help, please don't hesitate to email me at [brian.m.carlson@gmail.com](mailto:brian.m.carlson@gmail.com) or reach out on GitHub. diff --git a/docs/theme.config.js b/docs/theme.config.js index 29f115cb0..03ba3665c 100644 --- a/docs/theme.config.js +++ b/docs/theme.config.js @@ -15,7 +15,20 @@ export default { next: true, }, footer: { - text: `MIT ${new Date().getFullYear()} © Brian Carlson.`, + content: ( + + As of 2026-03-01 I am taking a break from the workforce to focus entirely on this project! Please consider{' '} + + sponsoring this work on GitHub + + ! + + ), }, editLink: { text: 'Edit this page on GitHub', @@ -55,6 +68,21 @@ l-161 -22 -94 41 c-201 87 -327 113 -533 112 -77 -1 -166 -7 -196 -13z m-89 chat: { link: 'https://discord.gg/2afXp5vUWm', }, + navbar: { + extraContent: ( + + + + + + ), + }, head: ( <> From 412dc88bc962e8792c292943e2f722333415b031 Mon Sep 17 00:00:00 2001 From: Daniel Diekmeier Date: Fri, 6 Mar 2026 00:00:57 +0100 Subject: [PATCH 02/16] Don't encourage people to use on('connect') for setup anymore (#3623) --- docs/pages/apis/pool.mdx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/pages/apis/pool.mdx b/docs/pages/apis/pool.mdx index d9323979e..123bc8ba4 100644 --- a/docs/pages/apis/pool.mdx +++ b/docs/pages/apis/pool.mdx @@ -232,14 +232,11 @@ The number of queued requests waiting on a client when all clients are checked o `pool.on('connect', (client: Client) => void) => void` -Whenever the pool establishes a new client connection to the PostgreSQL backend it will emit the `connect` event with the newly connected client. This presents an opportunity for you to run setup commands on a client. +Whenever the pool establishes a new client connection to the PostgreSQL backend it will emit the `connect` event with the newly connected client. -```js -const pool = new Pool() -pool.on('connect', (client) => { - client.query('SET DATESTYLE = iso, mdy') -}) -``` + + The event listener does not wait for promises or async functions. If you want to run setup commands on each new client, use the `onConnect` option. (See documentation above.) + ### acquire From 32ec730b51a1fd73bf97d65105c949729fa9ec80 Mon Sep 17 00:00:00 2001 From: Brian C Date: Thu, 5 Mar 2026 18:26:08 -0600 Subject: [PATCH 03/16] Update readme text slightly (#3637) * Update readme text slightly * Better words --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a680ff7b3..fc052cccf 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ When you open an issue please provide: - version of Postgres - smallest possible snippet of code to reproduce the problem -You can also follow me [@briancarlson](https://twitter.com/briancarlson) if that's your thing. I try to always announce noteworthy changes & developments with node-postgres on Twitter. +You can also follow me [@brianc](https://bsky.app/profile/brianc.bsky.social) on bluesky if that's your thing for updates on node-postgres with nearly zero non node-postgres content. My old twitter/x account is no longer used. ## Sponsorship :two_hearts: @@ -87,11 +87,11 @@ If your change involves breaking backwards compatibility please please point tha ### Setting up for local development 1. Clone the repo -2. Ensure you have installed libpq-dev in your system. +2. Ensure you have installed libpq-dev in your system (the native bindings are built in the test process) 3. From your workspace root run `yarn` and then `yarn lerna bootstrap` -4. Ensure you have a PostgreSQL instance running with SSL enabled and an empty database for tests -5. Ensure you have the proper environment variables configured for connecting to the instance -6. Run `yarn test` to run all the tests +4. Ensure you have a PostgreSQL instance running with SSL enabled and an empty database for tests. _note: you can skip the tests requring SSL by setting the environment variable `PGTESTNOSSL=1` if you're not changing any SSL related code_. +5. Ensure you have the proper environment variables configured for connecting to your postgres instance. Using the standard `PG*` environment variables like `PGUSER` and `PGPASSWORD` etc... +6. Run `yarn test` to run all the tests. ## Troubleshooting and FAQ From e7fa94a0f7820bc40949625aea5b8d2b788fe55a Mon Sep 17 00:00:00 2001 From: Brian C Date: Fri, 6 Mar 2026 01:14:21 -0600 Subject: [PATCH 04/16] Update the sub-readme (#3638) --- packages/pg/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pg/README.md b/packages/pg/README.md index bf4effefb..75242374c 100644 --- a/packages/pg/README.md +++ b/packages/pg/README.md @@ -42,7 +42,7 @@ When you open an issue please provide: - version of Postgres - smallest possible snippet of code to reproduce the problem -You can also follow me [@briancarlson](https://twitter.com/briancarlson) if that's your thing. I try to always announce noteworthy changes & developments with node-postgres on Twitter. +You can also follow me [@brianc](https://bsky.app/profile/brianc.bsky.social) on bluesky if that's your thing for updates on node-postgres with nearly zero non node-postgres content. My old twitter/x account is no longer used. ## Sponsorship :two_hearts: From c78b302666d593007359eb2bd223c5b325a07058 Mon Sep 17 00:00:00 2001 From: Brian C Date: Fri, 6 Mar 2026 19:07:16 -0600 Subject: [PATCH 05/16] Cleanup tests (#3640) --- packages/pg-cloudflare/src/index.ts | 2 +- packages/pg/Makefile | 12 +- packages/pg/script/create-test-tables.js | 56 ----- packages/pg/test/cli.js | 25 -- packages/pg/test/cloudflare/vitest-cf.test.ts | 3 +- .../client/big-simple-query-tests.js | 126 ++++++----- .../client/prepared-statement-tests.js | 214 +++++++++++------- .../integration/client/simple-query-tests.js | 77 ++++--- .../integration/client/transaction-tests.js | 79 +++---- .../connection-pool/native-instance-tests.js | 1 + .../test/integration/gh-issues/3174-tests.js | 2 +- packages/pg/test/integration/test-helper.js | 2 +- packages/pg/test/native/callback-api-tests.js | 39 ++-- packages/pg/test/native/stress-tests.js | 24 +- packages/pg/test/test-helper.js | 62 ++++- 15 files changed, 363 insertions(+), 361 deletions(-) delete mode 100644 packages/pg/script/create-test-tables.js delete mode 100644 packages/pg/test/cli.js diff --git a/packages/pg-cloudflare/src/index.ts b/packages/pg-cloudflare/src/index.ts index d83882efe..1e55c4165 100644 --- a/packages/pg-cloudflare/src/index.ts +++ b/packages/pg-cloudflare/src/index.ts @@ -1,4 +1,4 @@ -import { SocketOptions, Socket, TlsOptions } from 'cloudflare:sockets' +import { SocketOptions, Socket, TlsOptions } from 'cloudflare:sockets' // eslint-disable-line import { EventEmitter } from 'events' /** diff --git a/packages/pg/Makefile b/packages/pg/Makefile index a66c107ae..2979dd750 100644 --- a/packages/pg/Makefile +++ b/packages/pg/Makefile @@ -6,7 +6,7 @@ params := $(connectionString) node-command := xargs -n 1 -I file node file $(params) -.PHONY : test test-connection test-integration bench test-native \ +.PHONY : test test-integration bench test-native \ publish update-npm all: @@ -30,11 +30,7 @@ test-unit: @chmod 600 test/unit/client/pgpass.file @find test/unit -name "*-tests.js" | $(node-command) -test-connection: - @echo "***Testing connection***" - @node script/create-test-tables.js $(params) - -test-native: test-connection +test-native: @echo "***Testing native bindings***" ifeq ($(TEST_SKIP_NATIVE), true) @echo "***Skipping tests***" @@ -43,11 +39,11 @@ else @find test/integration -name "*-tests.js" | $(node-command) native endif -test-integration: test-connection +test-integration: @echo "***Testing Pure Javascript***" @find test/integration -name "*-tests.js" | $(node-command) -test-binary: test-connection +test-binary: @echo "***Testing Pure Javascript (binary)***" @find test/integration -name "*-tests.js" | $(node-command) binary diff --git a/packages/pg/script/create-test-tables.js b/packages/pg/script/create-test-tables.js deleted file mode 100644 index 76ba2dbe4..000000000 --- a/packages/pg/script/create-test-tables.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict' -const args = require('../test/cli') -const pg = require('../lib') - -const people = [ - { name: 'Aaron', age: 10 }, - { name: 'Brian', age: 20 }, - { name: 'Chris', age: 30 }, - { name: 'David', age: 40 }, - { name: 'Elvis', age: 50 }, - { name: 'Frank', age: 60 }, - { name: 'Grace', age: 70 }, - { name: 'Haley', age: 80 }, - { name: 'Irma', age: 90 }, - { name: 'Jenny', age: 100 }, - { name: 'Kevin', age: 110 }, - { name: 'Larry', age: 120 }, - { name: 'Michelle', age: 130 }, - { name: 'Nancy', age: 140 }, - { name: 'Olivia', age: 150 }, - { name: 'Peter', age: 160 }, - { name: 'Quinn', age: 170 }, - { name: 'Ronda', age: 180 }, - { name: 'Shelley', age: 190 }, - { name: 'Tobias', age: 200 }, - { name: 'Uma', age: 210 }, - { name: 'Veena', age: 220 }, - { name: 'Wanda', age: 230 }, - { name: 'Xavier', age: 240 }, - { name: 'Yoyo', age: 250 }, - { name: 'Zanzabar', age: 260 }, -] - -async function run() { - const con = new pg.Client({ - user: args.user, - password: args.password, - host: args.host, - port: args.port, - database: args.database, - }) - console.log('creating test dataset') - await con.connect() - await con.query('DROP TABLE IF EXISTS person') - await con.query('CREATE TABLE person (id serial, name varchar(10), age integer)') - await con.query( - 'INSERT INTO person (name, age) VALUES' + people.map((person) => ` ('${person.name}', ${person.age})`).join(',') - ) - await con.end() - console.log('created test dataset') -} - -run().catch((e) => { - console.log('setup failed', e) - process.exit(255) -}) diff --git a/packages/pg/test/cli.js b/packages/pg/test/cli.js deleted file mode 100644 index 5bea4912c..000000000 --- a/packages/pg/test/cli.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict' -const ConnectionParameters = require('../lib/connection-parameters') -const config = new ConnectionParameters(process.argv[2]) - -for (let i = 0; i < process.argv.length; i++) { - switch (process.argv[i].toLowerCase()) { - case 'native': - config.native = true - break - case 'binary': - config.binary = true - break - case 'down': - config.down = true - break - default: - break - } -} - -if (process.env['PG_TEST_NATIVE']) { - config.native = true -} - -module.exports = config diff --git a/packages/pg/test/cloudflare/vitest-cf.test.ts b/packages/pg/test/cloudflare/vitest-cf.test.ts index 2fe0188b2..c71e01961 100644 --- a/packages/pg/test/cloudflare/vitest-cf.test.ts +++ b/packages/pg/test/cloudflare/vitest-cf.test.ts @@ -1,10 +1,9 @@ import { Pool } from 'pg' import { test } from 'vitest' import assert from 'assert' -import args from '../cli' test('default', async () => { - const pool = new Pool(args) + const pool = new Pool() const result = await pool.query('SELECT $1::text as name', ['cloudflare']) assert(result.rows[0].name === 'cloudflare') pool.end() diff --git a/packages/pg/test/integration/client/big-simple-query-tests.js b/packages/pg/test/integration/client/big-simple-query-tests.js index 2e66a1af8..0948d1178 100644 --- a/packages/pg/test/integration/client/big-simple-query-tests.js +++ b/packages/pg/test/integration/client/big-simple-query-tests.js @@ -18,71 +18,80 @@ const big_query_rows_2 = [] const big_query_rows_3 = [] // Works -suite.test('big simple query 1', function (done) { +suite.test('big simple query 1', async function () { const client = helper.client() - client - .query( - new Query( - "select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = '' or 1 = 1" + await helper.createPersonTable(client) + return new Promise((resolve) => { + client + .query( + new Query( + "select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = '' or 1 = 1" + ) ) - ) - .on('row', function (row) { - big_query_rows_1.push(row) + .on('row', function (row) { + big_query_rows_1.push(row) + }) + .on('error', function (error) { + console.log('big simple query 1 error') + console.log(error) + }) + client.on('drain', () => { + client.end() + resolve() }) - .on('error', function (error) { - console.log('big simple query 1 error') - console.log(error) - }) - client.on('drain', () => { - client.end() - done() }) }) // Works -suite.test('big simple query 2', function (done) { +suite.test('big simple query 2', async function () { const client = helper.client() - client - .query( - new Query( - "select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", - [''] + await helper.createPersonTable(client) + return new Promise((resolve) => { + client + .query( + new Query( + "select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", + [''] + ) ) - ) - .on('row', function (row) { - big_query_rows_2.push(row) - }) - .on('error', function (error) { - console.log('big simple query 2 error') - console.log(error) + .on('row', function (row) { + big_query_rows_2.push(row) + }) + .on('error', function (error) { + console.log('big simple query 2 error') + console.log(error) + }) + client.on('drain', () => { + client.end() + resolve() }) - client.on('drain', () => { - client.end() - done() }) }) // Fails most of the time with 'invalid byte sequence for encoding "UTF8": 0xb9' or 'insufficient data left in message' // If test 1 and 2 are commented out it works -suite.test('big simple query 3', function (done) { +suite.test('big simple query 3', async function () { const client = helper.client() - client - .query( - new Query( - "select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", - [''] + await helper.createPersonTable(client) + return new Promise((resolve) => { + client + .query( + new Query( + "select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as bla from person where name = $1 or 1 = 1", + [''] + ) ) - ) - .on('row', function (row) { - big_query_rows_3.push(row) - }) - .on('error', function (error) { - console.log('big simple query 3 error') - console.log(error) + .on('row', function (row) { + big_query_rows_3.push(row) + }) + .on('error', function (error) { + console.log('big simple query 3 error') + console.log(error) + }) + client.on('drain', () => { + client.end() + resolve() }) - client.on('drain', () => { - client.end() - done() }) }) @@ -106,16 +115,19 @@ const runBigQuery = function (client) { ) } -suite.test('many times', function (done) { +suite.test('many times', async function () { const client = helper.client() - for (let i = 0; i < 20; i++) { - runBigQuery(client) - } - client.on('drain', function () { - client.end() - setTimeout(function () { - done() - // let client disconnect fully - }, 100) + await helper.createPersonTable(client) + return new Promise((resolve) => { + for (let i = 0; i < 20; i++) { + runBigQuery(client) + } + client.on('drain', function () { + client.end() + setTimeout(function () { + resolve() + // let client disconnect fully + }, 100) + }) }) }) diff --git a/packages/pg/test/integration/client/prepared-statement-tests.js b/packages/pg/test/integration/client/prepared-statement-tests.js index 5ff72a89e..5c102eb13 100644 --- a/packages/pg/test/integration/client/prepared-statement-tests.js +++ b/packages/pg/test/integration/client/prepared-statement-tests.js @@ -6,78 +6,119 @@ const assert = require('assert') const suite = new helper.Suite() ;(function () { - const client = helper.client() - client.on('drain', client.end.bind(client)) - const queryName = 'user by age and like name' - suite.test('first named prepared statement', function (done) { - const query = client.query( - new Query({ - text: 'select name from person where age <= $1 and name LIKE $2', - values: [20, 'Bri%'], - name: queryName, + suite.test('first named prepared statement', async function () { + const client = helper.client() + await helper.createPersonTable(client) + return new Promise((resolve) => { + const query = client.query( + new Query({ + text: 'select name from person where age <= $1 and name LIKE $2', + values: [20, 'Bri%'], + name: queryName, + }) + ) + + assert.emits(query, 'row', function (row) { + assert.equal(row.name, 'Brian') }) - ) - assert.emits(query, 'row', function (row) { - assert.equal(row.name, 'Brian') + query.on('end', () => { + client.end(resolve) + }) }) - - query.on('end', () => done()) }) - suite.test('second named prepared statement with same name & text', function (done) { - const cachedQuery = client.query( - new Query({ - text: 'select name from person where age <= $1 and name LIKE $2', - name: queryName, - values: [10, 'A%'], + suite.test('second named prepared statement with same name & text', async function () { + const client = helper.client() + await helper.createPersonTable(client) + return new Promise((resolve) => { + const cachedQuery = client.query( + new Query({ + text: 'select name from person where age <= $1 and name LIKE $2', + name: queryName, + values: [10, 'A%'], + }) + ) + + assert.emits(cachedQuery, 'row', function (row) { + assert.equal(row.name, 'Aaron') }) - ) - assert.emits(cachedQuery, 'row', function (row) { - assert.equal(row.name, 'Aaron') + cachedQuery.on('end', () => { + client.end(resolve) + }) }) - - cachedQuery.on('end', () => done()) }) - suite.test('with same name, but without query text', function (done) { - const q = client.query( - new Query({ - name: queryName, - values: [30, '%n%'], - }) - ) - - assert.emits(q, 'row', function (row) { - assert.equal(row.name, 'Aaron') + suite.test('with same name, but without query text', async function () { + const client = helper.client() + await helper.createPersonTable(client) + // First, register the named statement + await new Promise((resolve) => { + const reg = client.query( + new Query({ + text: 'select name from person where age <= $1 and name LIKE $2', + name: queryName, + values: [20, 'Bri%'], + }) + ) + reg.on('end', resolve) + }) + return new Promise((resolve) => { + const q = client.query( + new Query({ + name: queryName, + values: [30, '%n%'], + }) + ) - // test second row is emitted as well assert.emits(q, 'row', function (row) { - assert.equal(row.name, 'Brian') + assert.equal(row.name, 'Aaron') + + // test second row is emitted as well + assert.emits(q, 'row', function (row) { + assert.equal(row.name, 'Brian') + }) }) - }) - q.on('end', () => done()) + q.on('end', () => { + client.end(resolve) + }) + }) }) - suite.test('with same name, but with different text', function (done) { - client.query( - new Query({ - text: 'select name from person where age >= $1 and name LIKE $2', - name: queryName, - values: [30, '%n%'], - }), - assert.calls((err) => { - assert.equal( - err.message, - `Prepared statements must be unique - '${queryName}' was used for a different statement` - ) - done() - }) - ) + suite.test('with same name, but with different text', async function () { + const client = helper.client() + await helper.createPersonTable(client) + // First, register the named statement + await new Promise((resolve) => { + const reg = client.query( + new Query({ + text: 'select name from person where age <= $1 and name LIKE $2', + name: queryName, + values: [20, 'Bri%'], + }) + ) + reg.on('end', resolve) + }) + return new Promise((resolve) => { + client.query( + new Query({ + text: 'select name from person where age >= $1 and name LIKE $2', + name: queryName, + values: [30, '%n%'], + }), + assert.calls((err) => { + assert.equal( + err.message, + `Prepared statements must be unique - '${queryName}' was used for a different statement` + ) + client.end(resolve) + }) + ) + }) }) })() ;(function () { @@ -85,44 +126,45 @@ const suite = new helper.Suite() const statement1 = 'select count(*)::int4 as count from person' const statement2 = 'select count(*)::int4 as count from person where age < $1' - const client1 = helper.client() - const client2 = helper.client() - - suite.test('client 1 execution', function (done) { - client1.query( - { - name: statementName, - text: statement1, - }, - (err, res) => { - assert(!err) - assert.equal(res.rows[0].count, 26) - done() - } - ) + suite.test('client 1 execution', async function () { + const client1 = helper.client() + await helper.createPersonTable(client1) + return new Promise((resolve) => { + client1.query( + { + name: statementName, + text: statement1, + }, + (err, res) => { + assert(!err) + assert.equal(res.rows[0].count, 26) + client1.end(resolve) + } + ) + }) }) - suite.test('client 2 execution', function (done) { - const query = client2.query( - new Query({ - name: statementName, - text: statement2, - values: [11], - }) - ) + suite.test('client 2 execution', async function () { + const client2 = helper.client() + await helper.createPersonTable(client2) + return new Promise((resolve) => { + const query = client2.query( + new Query({ + name: statementName, + text: statement2, + values: [11], + }) + ) - assert.emits(query, 'row', function (row) { - assert.equal(row.count, 1) - }) + assert.emits(query, 'row', function (row) { + assert.equal(row.count, 1) + }) - assert.emits(query, 'end', function () { - done() + assert.emits(query, 'end', function () { + client2.end(resolve) + }) }) }) - - suite.test('clean up clients', () => { - return client1.end().then(() => client2.end()) - }) })() ;(function () { const client = helper.client() diff --git a/packages/pg/test/integration/client/simple-query-tests.js b/packages/pg/test/integration/client/simple-query-tests.js index 60a8f76f7..d295abfa1 100644 --- a/packages/pg/test/integration/client/simple-query-tests.js +++ b/packages/pg/test/integration/client/simple-query-tests.js @@ -5,58 +5,61 @@ const assert = require('assert') const suite = new helper.Suite() const test = suite.test.bind(suite) -// before running this test make sure you run the script create-test-tables -test('simple query interface', function () { +test('simple query interface', async function () { const client = helper.client() + await helper.createPersonTable(client) - const query = client.query(new Query('select name from person order by name collate "C"')) + return new Promise((resolve) => { + const query = client.query(new Query('select name from person order by name collate "C"')) - client.on('drain', client.end.bind(client)) - - const rows = [] - query.on('row', function (row, result) { - assert.ok(result) - rows.push(row['name']) - }) - query.once('row', function (row) { - test('returned right columns', function () { - assert.deepStrictEqual(row, { name: row.name }) + const rows = [] + query.on('row', function (row, result) { + assert.ok(result) + rows.push(row['name']) }) - }) - - assert.emits(query, 'end', function () { - test('returned right number of rows', function () { - assert.lengthIs(rows, 26) + query.once('row', function (row) { + test('returned right columns', function () { + assert.deepStrictEqual(row, { name: row.name }) + }) }) - test('row ordering', function () { - assert.equal(rows[0], 'Aaron') - assert.equal(rows[25], 'Zanzabar') + + assert.emits(query, 'end', function () { + test('returned right number of rows', function () { + assert.lengthIs(rows, 26) + }) + test('row ordering', function () { + assert.equal(rows[0], 'Aaron') + assert.equal(rows[25], 'Zanzabar') + }) + client.end(resolve) }) }) }) -test('prepared statements do not mutate params', function () { +test('prepared statements do not mutate params', async function () { const client = helper.client() + await helper.createPersonTable(client) - const params = [1] + return new Promise((resolve) => { + const params = [1] - const query = client.query(new Query('select name from person where $1 = 1 order by name collate "C"', params)) + const query = client.query(new Query('select name from person where $1 = 1 order by name collate "C"', params)) - assert.deepEqual(params, [1]) + assert.deepEqual(params, [1]) - client.on('drain', client.end.bind(client)) - - const rows = [] - query.on('row', function (row, result) { - assert.ok(result) - rows.push(row) - }) + const rows = [] + query.on('row', function (row, result) { + assert.ok(result) + rows.push(row) + }) - query.on('end', function (result) { - assert.lengthIs(rows, 26, 'result returned wrong number of rows') - assert.lengthIs(rows, result.rowCount) - assert.equal(rows[0].name, 'Aaron') - assert.equal(rows[25].name, 'Zanzabar') + query.on('end', function (result) { + assert.lengthIs(rows, 26, 'result returned wrong number of rows') + assert.lengthIs(rows, result.rowCount) + assert.equal(rows[0].name, 'Aaron') + assert.equal(rows[25].name, 'Zanzabar') + client.end(resolve) + }) }) }) diff --git a/packages/pg/test/integration/client/transaction-tests.js b/packages/pg/test/integration/client/transaction-tests.js index feb178fef..7e0b36964 100644 --- a/packages/pg/test/integration/client/transaction-tests.js +++ b/packages/pg/test/integration/client/transaction-tests.js @@ -4,65 +4,38 @@ const suite = new helper.Suite() const pg = helper.pg const assert = require('assert') -const client = new pg.Client() -client.connect( - assert.success(function () { - client.query('begin') +suite.test('transactions', async function () { + const client = new pg.Client() + await client.connect() + await helper.createPersonTable(client) - const getZed = { - text: 'SELECT * FROM person WHERE name = $1', - values: ['Zed'], - } + await client.query('begin') - suite.test('name should not exist in the database', function (done) { - client.query( - getZed, - assert.calls(function (err, result) { - assert(!err) - assert.empty(result.rows) - done() - }) - ) - }) + const getZed = { + text: 'SELECT * FROM person WHERE name = $1', + values: ['Zed'], + } - suite.test('can insert name', (done) => { - client.query( - 'INSERT INTO person(name, age) VALUES($1, $2)', - ['Zed', 270], - assert.calls(function (err, result) { - assert(!err) - done() - }) - ) - }) + // name should not exist + const r1 = await client.query(getZed) + assert.empty(r1.rows) - suite.test('name should exist in the database', function (done) { - client.query( - getZed, - assert.calls(function (err, result) { - assert(!err) - assert.equal(result.rows[0].name, 'Zed') - done() - }) - ) - }) + // insert name + await client.query('INSERT INTO person(name, age) VALUES($1, $2)', ['Zed', 270]) - suite.test('rollback', (done) => { - client.query('rollback', done) - }) + // name should exist + const r2 = await client.query(getZed) + assert.equal(r2.rows[0].name, 'Zed') - suite.test('name should not exist in the database', function (done) { - client.query( - getZed, - assert.calls(function (err, result) { - assert(!err) - assert.empty(result.rows) - client.end(done) - }) - ) - }) - }) -) + // rollback + await client.query('rollback') + + // name should not exist after rollback + const r3 = await client.query(getZed) + assert.empty(r3.rows) + + await client.end() +}) suite.test('gh#36', function (cb) { const pool = new pg.Pool() diff --git a/packages/pg/test/integration/connection-pool/native-instance-tests.js b/packages/pg/test/integration/connection-pool/native-instance-tests.js index 6f713411d..ae49813d0 100644 --- a/packages/pg/test/integration/connection-pool/native-instance-tests.js +++ b/packages/pg/test/integration/connection-pool/native-instance-tests.js @@ -8,6 +8,7 @@ const pool = new pg.Pool() pool.connect( assert.calls(function (err, client, done) { + console.log('native?', native) if (native) { assert(client.native) } else { diff --git a/packages/pg/test/integration/gh-issues/3174-tests.js b/packages/pg/test/integration/gh-issues/3174-tests.js index 24347a23e..99044df0e 100644 --- a/packages/pg/test/integration/gh-issues/3174-tests.js +++ b/packages/pg/test/integration/gh-issues/3174-tests.js @@ -2,7 +2,7 @@ const net = require('net') const buffers = require('../../test-buffers') const helper = require('../test-helper') const assert = require('assert') -const cli = require('../../cli') +const cli = helper.args const suite = new helper.Suite() diff --git a/packages/pg/test/integration/test-helper.js b/packages/pg/test/integration/test-helper.js index 631acbae3..9dab8843a 100644 --- a/packages/pg/test/integration/test-helper.js +++ b/packages/pg/test/integration/test-helper.js @@ -6,7 +6,7 @@ const assert = require('assert') if (helper.args.native) { Client = require('./../../lib/native') helper.Client = Client - helper.pg = helper.pg.native + helper.pg = require('../../lib').native } // creates a client from cli parameters diff --git a/packages/pg/test/native/callback-api-tests.js b/packages/pg/test/native/callback-api-tests.js index d129e4a24..8ff2063e5 100644 --- a/packages/pg/test/native/callback-api-tests.js +++ b/packages/pg/test/native/callback-api-tests.js @@ -5,26 +5,29 @@ const Client = require('./../../lib/native') const suite = new helper.Suite() const assert = require('assert') -suite.test('fires callback with results', function (done) { +suite.test('fires callback with results', async function () { const client = new Client(helper.config) client.connect() - client.query( - 'SELECT 1 as num', - assert.calls(function (err, result) { - assert(!err) - assert.equal(result.rows[0].num, 1) - assert.strictEqual(result.rowCount, 1) - client.query( - 'SELECT * FROM person WHERE name = $1', - ['Brian'], - assert.calls(function (err, result) { - assert(!err) - assert.equal(result.rows[0].name, 'Brian') - client.end(done) - }) - ) - }) - ) + await helper.createPersonTable(client) + return new Promise((resolve) => { + client.query( + 'SELECT 1 as num', + assert.calls(function (err, result) { + assert(!err) + assert.equal(result.rows[0].num, 1) + assert.strictEqual(result.rowCount, 1) + client.query( + 'SELECT * FROM person WHERE name = $1', + ['Brian'], + assert.calls(function (err, result) { + assert(!err) + assert.equal(result.rows[0].name, 'Brian') + client.end(resolve) + }) + ) + }) + ) + }) }) suite.test('preserves domain', function (done) { diff --git a/packages/pg/test/native/stress-tests.js b/packages/pg/test/native/stress-tests.js index 2cccb44bf..8496abe80 100644 --- a/packages/pg/test/native/stress-tests.js +++ b/packages/pg/test/native/stress-tests.js @@ -5,9 +5,10 @@ const Query = Client.Query const assert = require('assert') const suite = new helper.Suite() -suite.test('many rows', function () { +suite.test('many rows', async function () { const client = new Client(helper.config) client.connect() + await helper.createPersonTable(client) const q = client.query(new Query('SELECT * FROM person')) const rows = [] q.on('row', function (row) { @@ -19,9 +20,10 @@ suite.test('many rows', function () { }) }) -suite.test('many queries', function () { +suite.test('many queries', async function () { const client = new Client(helper.config) client.connect() + await helper.createPersonTable(client) let count = 0 const expected = 100 for (let i = 0; i < expected; i++) { @@ -36,18 +38,20 @@ suite.test('many queries', function () { }) }) -suite.test('many clients', function () { +suite.test('many clients', async function () { const clients = [] for (let i = 0; i < 10; i++) { clients.push(new Client(helper.config)) } - clients.forEach(function (client) { - client.connect() - for (let i = 0; i < 20; i++) { - client.query('SELECT * FROM person') - } - assert.emits(client, 'drain', function () { + await Promise.all( + clients.map(async function (client) { + client.connect() + await helper.createPersonTable(client) + for (let i = 0; i < 20; i++) { + await client.query('SELECT * FROM person') + } + client.end() }) - }) + ) }) diff --git a/packages/pg/test/test-helper.js b/packages/pg/test/test-helper.js index da70973f6..8cd9dda36 100644 --- a/packages/pg/test/test-helper.js +++ b/packages/pg/test/test-helper.js @@ -3,10 +3,17 @@ const assert = require('assert') const sys = require('util') const Suite = require('./suite') -const args = require('./cli') - const Client = require('./../lib').Client +let isNativeMode = false +for (let i = 0; i < process.argv.length; i++) { + switch (process.argv[i].toLowerCase()) { + case 'native': + isNativeMode = true + break + } +} + process.on('uncaughtException', function (d) { if ('stack' in d && 'message' in d) { console.log('Message: ' + d.message) @@ -53,8 +60,7 @@ const expect = function (callback, timeout) { } // print out the filename process.stdout.write(require('path').basename(process.argv[1])) -if (args.binary) process.stdout.write(' (binary)') -if (args.native) process.stdout.write(' (native)') +if (isNativeMode) process.stdout.write(' (native)') process.on('exit', function () { console.log('') @@ -199,14 +205,58 @@ if (Object.isExtensible(assert)) { } } +const names = [ + 'Aaron', + 'Brian', + 'Chris', + 'David', + 'Elvis', + 'Frank', + 'Grace', + 'Haley', + 'Irma', + 'Jenny', + 'Kevin', + 'Larry', + 'Michelle', + 'Nancy', + 'Olivia', + 'Peter', + 'Quinn', + 'Ronda', + 'Shelley', + 'Tobias', + 'Uma', + 'Veena', + 'Wanda', + 'Xavier', + 'Yoyo', + 'Zanzabar', +] + +const createPersonTable = async (client) => { + await client.query('CREATE TEMP TABLE person (id serial, name varchar(10), age integer)') + await client.query( + 'INSERT INTO person (name, age) VALUES' + names.map((name, i) => ` ('${name}', ${(i + 1) * 10})`).join(',') + ) +} + module.exports = { Suite: Suite, pg: require('./../lib/'), - args: args, - config: args, + args: { native: isNativeMode }, + config: { + native: isNativeMode, + host: process.env.PGHOST || 'localhost', + port: process.env.PGPORT || 5432, + user: process.env.PGUSER || 'postgres', + password: process.env.PGPASSWORD || '', + database: process.env.PGDATABASE || 'postgres', + }, sys: sys, Client: Client, setTimezoneOffset: setTimezoneOffset, resetTimezoneOffset: resetTimezoneOffset, rejection: rejection, + createPersonTable: createPersonTable, } From 4e6bdf07eff793ba1753aea28e81c818f6adb362 Mon Sep 17 00:00:00 2001 From: Karl Pietrzak Date: Wed, 22 Apr 2026 16:31:53 -0400 Subject: [PATCH 06/16] Update Medplum logo in README (#3659) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc052cccf..4ca28ce5d 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ If you or your company are benefiting from node-postgres and would like to help Special thanks to [medplum](https://medplum.com) for their generous and thoughtful support of node-postgres! -![medplum](https://raw.githubusercontent.com/medplum/medplum-logo/refs/heads/main/medplum-logo.png) +Medplum logo ## Contributing From 77cb77150d6c0f07b0aa2134c6b3ef0cb80335c1 Mon Sep 17 00:00:00 2001 From: Karl Pietrzak Date: Wed, 22 Apr 2026 17:11:39 -0400 Subject: [PATCH 07/16] remove deprecated 'version' attribute from docker-compose.ymla (#3660) Removes the warning: ``` WARN[0000] .../node-postgres/.devcontainer/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion ``` The `version` attribute has been removed as of v2 of the docker compose plugin (https://github.com/compose-spec/compose-spec/blob/main/spec.md#version-top-level-element-obsolete). --- .devcontainer/docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index d0ab0e8dd..83e302207 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -3,7 +3,6 @@ # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. #------------------------------------------------------------------------------------------------------------- -version: '3.9' services: web: # Uncomment the next line to use a non-root user for all processes. You can also From 341cb60b0f4579382c7f65be97815c3fe4621064 Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Thu, 30 Apr 2026 10:31:26 +0000 Subject: [PATCH 08/16] =?UTF-8?q?docs:=20Fix=20changelog=20entry=E2=80=99s?= =?UTF-8?q?=20spelling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36a7136c0..8d167ceef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ We do not include break-fix version release in this file. ## pg@8.14.0 -- Add support from SCRAM-SAH-256-PLUS i.e. [channel binding](https://github.com/brianc/node-postgres/pull/3356). +- Add support for SCRAM-SHA-256-PLUS, i.e. [channel binding](https://github.com/brianc/node-postgres/pull/3356). ## pg@8.13.0 From 02367b8325d6f378419242b07ec3b206309e049f Mon Sep 17 00:00:00 2001 From: Chow Loong Jin Date: Sat, 9 May 2026 22:29:50 +0800 Subject: [PATCH 09/16] Upgrade eslint and typescript (#3662) * Upgrade eslint and typescript * eslint: Port config to new flat config format * Fix preserve-caught-error eslint warning * Drop unused eslint-disable-line * pg-cloudflare: Fix typescript errors - rootDir defaults have changed, so we need to specify it manually now - baseUrl is no longer supported - types no longer loads everything in @types by default, so we have to specify that we want node types - Pin @types/node to 16.* because we support node16 and above * pg-cloudflare: Workaround typescript bug regarding Buffer.from Fixes the following error: % yarn build yarn run v1.22.19 $ tsc --build packages/pg-cloudflare/src/index.ts:156:29 - error TS2769: No overload matches this call. The last overload gave the following error. Argument of type 'ArrayBuffer | Uint8Array' is not assignable to parameter of type 'WithImplicitCoercion | { [Symbol.toPrimitive](hint: "string"): string; }'. Type 'ArrayBuffer' is not assignable to type 'WithImplicitCoercion | { [Symbol.toPrimitive](hint: "string"): string; }'. 156 const hex = Buffer.from(data).toString('hex') ~~~~ node_modules/@types/node/buffer.buffer.d.ts:83:13 83 from( ~~~~~ 84 str: ~~~~~~~~~~~~~~~~~~~~ ... 89 encoding?: BufferEncoding, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 ): Buffer; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The last overload is declared here. Found 1 error. See https://github.com/microsoft/TypeScript/issues/63447 for more info * Fix tsconfig for pg-protocol and pg-query-stream * Standardize @types/node on ^16 Fixes the following typescript error: node_modules/typescript/lib/lib.esnext.intl.d.ts:26:135 - error TS2552: Cannot find name 'DateTimeRangeFormatPart'. Did you mean 'DateTimeFormatPart'? 26 formatRangeToParts(startDate: FormattableTemporalObject | Date | number, endDate: FormattableTemporalObject | Date | number): DateTimeRangeFormatPart[]; * pg-protocol: Narrow type of BufferReader.encoding `BufferReader.encoding` to `BufferEncoding` from `string` to match the new signature of `Buffer.toString`. * pg-query-stream: Bump eslint-plugin-promise to fix unmet peer dependency * Run eslint on its own config --- .eslintignore | 1 - .eslintrc | 35 - eslint.config.mjs | 76 ++ package.json | 11 +- packages/pg-cloudflare/package.json | 2 +- packages/pg-cloudflare/src/index.ts | 7 +- packages/pg-cloudflare/tsconfig.json | 9 +- packages/pg-connection-string/package.json | 2 +- packages/pg-protocol/package.json | 4 +- packages/pg-protocol/src/buffer-reader.ts | 2 +- packages/pg-protocol/tsconfig.json | 12 +- packages/pg-query-stream/package.json | 6 +- packages/pg-query-stream/tsconfig.json | 2 +- packages/pg/package.json | 2 +- .../client/async-stack-trace-tests.js | 4 +- yarn.lock | 787 ++++++++---------- 16 files changed, 446 insertions(+), 516 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc create mode 100644 eslint.config.mjs diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 050c39538..000000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -/packages/*/dist/ diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index b1999b544..000000000 --- a/.eslintrc +++ /dev/null @@ -1,35 +0,0 @@ -{ - "plugins": ["@typescript-eslint", "prettier"], - "parser": "@typescript-eslint/parser", - "extends": ["eslint:recommended", "plugin:prettier/recommended", "prettier"], - "ignorePatterns": ["node_modules", "coverage", "packages/pg-protocol/dist/**/*", "packages/pg-query-stream/dist/**/*"], - "parserOptions": { - "ecmaVersion": 2017, - "sourceType": "module" - }, - "env": { - "node": true, - "es6": true, - "mocha": true - }, - "rules": { - "@typescript-eslint/no-unused-vars": ["error", { - "args": "none", - "varsIgnorePattern": "^_$" - }], - "no-unused-vars": ["error", { - "args": "none", - "varsIgnorePattern": "^_$" - }], - "no-var": "error", - "prefer-const": "error" - }, - "overrides": [ - { - "files": ["*.ts", "*.mts", "*.cts", "*.tsx"], - "rules": { - "no-undef": "off" - } - } - ] -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..3f95083a0 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,76 @@ +import { defineConfig, globalIgnores } from 'eslint/config' +import typescriptEslint from '@typescript-eslint/eslint-plugin' +import prettier from 'eslint-plugin-prettier' +import globals from 'globals' +import tsParser from '@typescript-eslint/parser' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import js from '@eslint/js' +import { FlatCompat } from '@eslint/eslintrc' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}) + +export default defineConfig([ + globalIgnores([ + '**/node_modules', + '**/coverage', + 'packages/*/dist', + 'packages/pg-protocol/dist/**/*', + 'packages/pg-query-stream/dist/**/*', + ]), + { + extends: compat.extends('eslint:recommended', 'plugin:prettier/recommended', 'prettier'), + + plugins: { + '@typescript-eslint': typescriptEslint, + prettier, + }, + + languageOptions: { + globals: { + ...globals.node, + ...globals.mocha, + }, + + parser: tsParser, + ecmaVersion: 2017, + sourceType: 'module', + }, + + rules: { + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'none', + caughtErrors: 'none', + varsIgnorePattern: '^_$', + }, + ], + + // handled by @typescript-eslint/no-unused-vars + 'no-unused-vars': 'off', + + 'no-var': 'error', + 'prefer-const': 'error', + 'no-constant-condition': [ + 'error', + { + checkLoops: 'all', + }, + ], + }, + }, + { + files: ['**/*.ts', '**/*.mts', '**/*.cts', '**/*.tsx'], + + rules: { + 'no-undef': 'off', + }, + }, +]) diff --git a/package.json b/package.json index 1f40662b9..9285ad142 100644 --- a/package.json +++ b/package.json @@ -20,15 +20,18 @@ "lint": "eslint --cache 'packages/**/*.{js,ts,tsx}'" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^6.17.0", - "eslint": "^8.56.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "^10.0.1", + "@typescript-eslint/eslint-plugin": "^8.58.0", + "@typescript-eslint/parser": "^8.58.0", + "eslint": "^10.2.1", "eslint-config-prettier": "^10.1.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^5.1.2", "lerna": "^3.19.0", "prettier": "3.0.3", - "typescript": "^4.0.3" + "typescript": "^6.0.3", + "@types/node": "^16" }, "prettier": { "semi": false, diff --git a/packages/pg-cloudflare/package.json b/packages/pg-cloudflare/package.json index c1584fc09..ac68bb22e 100644 --- a/packages/pg-cloudflare/package.json +++ b/packages/pg-cloudflare/package.json @@ -7,7 +7,7 @@ "license": "MIT", "devDependencies": { "ts-node": "^8.5.4", - "typescript": "^4.0.3" + "typescript": "^6.0.3" }, "exports": { ".": { diff --git a/packages/pg-cloudflare/src/index.ts b/packages/pg-cloudflare/src/index.ts index 1e55c4165..9b1e517ba 100644 --- a/packages/pg-cloudflare/src/index.ts +++ b/packages/pg-cloudflare/src/index.ts @@ -1,4 +1,4 @@ -import { SocketOptions, Socket, TlsOptions } from 'cloudflare:sockets' // eslint-disable-line +import { SocketOptions, Socket, TlsOptions } from 'cloudflare:sockets' import { EventEmitter } from 'events' /** @@ -153,7 +153,10 @@ const debug = false function dump(data: unknown) { if (data instanceof Uint8Array || data instanceof ArrayBuffer) { - const hex = Buffer.from(data).toString('hex') + // workaround https://github.com/microsoft/TypeScript/issues/63447 + const buf = data instanceof Uint8Array ? Buffer.from(data) : Buffer.from(data) + + const hex = buf.toString('hex') const str = new TextDecoder().decode(data) return `\n>>> STR: "${str.replace(/\n/g, '\\n')}"\n>>> HEX: ${hex}\n` } else { diff --git a/packages/pg-cloudflare/tsconfig.json b/packages/pg-cloudflare/tsconfig.json index 31d494681..840b52aff 100644 --- a/packages/pg-cloudflare/tsconfig.json +++ b/packages/pg-cloudflare/tsconfig.json @@ -9,15 +9,16 @@ "moduleResolution": "node16", "sourceMap": true, "outDir": "dist", + "rootDir": "./src", "incremental": true, - "baseUrl": ".", "declaration": true, "paths": { "*": [ - "node_modules/*", - "src/types/*" + "./node_modules/*", + "./src/types/*" ] - } + }, + "types": ["node"] }, "include": [ "src/**/*" diff --git a/packages/pg-connection-string/package.json b/packages/pg-connection-string/package.json index a60131456..d02588a6c 100644 --- a/packages/pg-connection-string/package.json +++ b/packages/pg-connection-string/package.json @@ -41,7 +41,7 @@ "mocha": "^11.7.5", "nyc": "^15", "tsx": "^4.19.4", - "typescript": "^4.0.3" + "typescript": "^6.0.3" }, "files": [ "index.js", diff --git a/packages/pg-protocol/package.json b/packages/pg-protocol/package.json index 896c21e69..d3326bdbc 100644 --- a/packages/pg-protocol/package.json +++ b/packages/pg-protocol/package.json @@ -17,12 +17,12 @@ "devDependencies": { "@types/chai": "^4.2.7", "@types/mocha": "^10.0.10", - "@types/node": "^12.12.21", + "@types/node": "^16", "chai": "^4.2.0", "chunky": "^0.0.0", "mocha": "^11.7.5", "ts-node": "^8.5.4", - "typescript": "^4.0.3" + "typescript": "^6.0.3" }, "scripts": { "test": "mocha dist/**/*.test.js", diff --git a/packages/pg-protocol/src/buffer-reader.ts b/packages/pg-protocol/src/buffer-reader.ts index b89aceb89..c9d9c2b66 100644 --- a/packages/pg-protocol/src/buffer-reader.ts +++ b/packages/pg-protocol/src/buffer-reader.ts @@ -2,7 +2,7 @@ export class BufferReader { private buffer: Buffer = Buffer.allocUnsafe(0) // TODO(bmc): support non-utf8 encoding? - private encoding: string = 'utf-8' + private encoding: BufferEncoding = 'utf-8' constructor(private offset: number = 0) {} diff --git a/packages/pg-protocol/tsconfig.json b/packages/pg-protocol/tsconfig.json index 0ae32c8dc..e09c03cd7 100644 --- a/packages/pg-protocol/tsconfig.json +++ b/packages/pg-protocol/tsconfig.json @@ -9,15 +9,19 @@ "moduleResolution": "node16", "sourceMap": true, "outDir": "dist", + "rootDir": "./src", "incremental": true, - "baseUrl": ".", "declaration": true, "paths": { "*": [ - "node_modules/*", - "src/types/*" + "./node_modules/*", + "./src/types/*" ] - } + }, + "types": [ + "node", + "mocha" + ] }, "include": [ "src/**/*" diff --git a/packages/pg-query-stream/package.json b/packages/pg-query-stream/package.json index 5369a3c4c..42ef8f268 100644 --- a/packages/pg-query-stream/package.json +++ b/packages/pg-query-stream/package.json @@ -39,16 +39,16 @@ "devDependencies": { "@types/chai": "^4.2.13", "@types/mocha": "^10.0.10", - "@types/node": "^14.0.0", + "@types/node": "^16.0.0", "@types/pg": "^7.14.5", "JSONStream": "~1.3.5", "concat-stream": "~1.0.1", - "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-promise": "^7.3.0", "mocha": "^11.7.5", "pg": "^8.20.0", "stream-spec": "~0.3.5", "ts-node": "^8.5.4", - "typescript": "^4.0.3" + "typescript": "^6.0.3" }, "peerDependencies": { "pg": "^8" diff --git a/packages/pg-query-stream/tsconfig.json b/packages/pg-query-stream/tsconfig.json index 56eec5083..e9c97b335 100644 --- a/packages/pg-query-stream/tsconfig.json +++ b/packages/pg-query-stream/tsconfig.json @@ -10,8 +10,8 @@ "sourceMap": true, "pretty": true, "outDir": "dist", + "rootDir": "./src", "incremental": true, - "baseUrl": ".", "declaration": true, "types": [ "node", diff --git a/packages/pg/package.json b/packages/pg/package.json index 6be526ee8..d14e448d6 100644 --- a/packages/pg/package.json +++ b/packages/pg/package.json @@ -45,7 +45,7 @@ "bluebird": "3.7.2", "co": "4.6.0", "pg-copy-streams": "0.3.0", - "typescript": "^4.0.3", + "typescript": "^6.0.3", "vitest": "~3.0.9", "wrangler": "^3.x" }, diff --git a/packages/pg/test/integration/client/async-stack-trace-tests.js b/packages/pg/test/integration/client/async-stack-trace-tests.js index 92ca3e4d2..8f289f5ad 100644 --- a/packages/pg/test/integration/client/async-stack-trace-tests.js +++ b/packages/pg/test/integration/client/async-stack-trace-tests.js @@ -23,7 +23,7 @@ if (NODE_MAJOR_VERSION >= 16) { } catch (e) { const stack = e.stack if (!e.stack.includes('innerFunction') || !e.stack.includes('outerFunction')) { - throw Error('async stack trace does not contain wanted values: ' + stack) + throw Error('async stack trace does not contain wanted values: ' + stack, { cause: e }) } } }) @@ -44,7 +44,7 @@ if (NODE_MAJOR_VERSION >= 16) { } catch (e) { const stack = e.stack if (!e.stack.includes('innerFunction') || !e.stack.includes('outerFunction')) { - throw Error('async stack trace does not contain wanted values: ' + stack) + throw Error('async stack trace does not contain wanted values: ' + stack, { cause: e }) } } }) diff --git a/yarn.lock b/yarn.lock index dd6662852..b221bd37a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -654,37 +654,80 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz#7fc114af5f6563f19f73324b5d5ff36ece0803d1" integrity sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g== -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": +"@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + dependencies: + eslint-visitor-keys "^3.4.3" -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint-community/regexpp@^4.12.2": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.23.5": + version "0.23.5" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.23.5.tgz#56e86d243049195d8acc0c06a1b3dfdc3fa3de95" + integrity sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA== + dependencies: + "@eslint/object-schema" "^3.0.5" + debug "^4.3.1" + minimatch "^10.2.4" + +"@eslint/config-helpers@^0.5.5": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.5.5.tgz#ae16134e4792ac5fbdc533548a24ac1ea9f7f3ae" + integrity sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w== + dependencies: + "@eslint/core" "^1.2.1" + +"@eslint/core@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-1.2.1.tgz#c1da7cd1b82fa8787f98b5629fb811848a1b63ce" + integrity sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ== dependencies: - ajv "^6.12.4" + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.5": + version "3.3.5" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.5.tgz#c131793cfc1a7b96f24a83e0a8bbd4b881558c60" + integrity sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg== + dependencies: + ajv "^6.14.0" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" + js-yaml "^4.1.1" + minimatch "^3.1.5" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-10.0.1.tgz#1e8a876f50117af8ab67e47d5ad94d38d6622583" + integrity sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA== + +"@eslint/object-schema@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-3.0.5.tgz#88e9bf4d11d2b19c082e78ebe7ce88724a5eb091" + integrity sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw== + +"@eslint/plugin-kit@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz#c4125fd015eceeb09b793109fdbcd4dd0a02d346" + integrity sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ== + dependencies: + "@eslint/core" "^1.2.1" + levn "^0.4.1" "@evocateur/libnpmaccess@^3.1.2": version "3.1.2" @@ -765,24 +808,36 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@humanfs/core@^0.19.2": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.2.tgz#a8272ca03b2acf492670222b2320b6c421bfde60" + integrity sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" + "@humanfs/types" "^0.15.0" + +"@humanfs/node@^0.16.6": + version "0.16.8" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.8.tgz#8f800cccc13f4f8cd3116e2d9c0a94939da3e3ed" + integrity sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ== + dependencies: + "@humanfs/core" "^0.19.2" + "@humanfs/types" "^0.15.0" + "@humanwhocodes/retry" "^0.4.0" + +"@humanfs/types@^0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@humanfs/types/-/types-0.15.0.tgz#f2a09f62012390b2bff3fc6fb248ddec8c09a090" + integrity sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q== "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== "@img/sharp-darwin-arm64@0.33.5": version "0.33.5" @@ -1678,37 +1733,11 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - "@nodelib/fs.stat@^1.1.2": version "1.1.3" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - "@npmcli/agent@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-3.0.0.tgz#1685b1fbd4a1b7bb4f930cbb68ce801edfe7aa44" @@ -2010,12 +2039,17 @@ "@types/estree" "*" "@types/json-schema" "*" +"@types/esrecurse@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/esrecurse/-/esrecurse-4.3.1.tgz#6f636af962fbe6191b830bd676ba5986926bccec" + integrity sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw== + "@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.7" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== -"@types/estree@1.0.8": +"@types/estree@1.0.8", "@types/estree@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== @@ -2028,7 +2062,7 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2053,15 +2087,10 @@ resolved "https://registry.npmjs.org/@types/node/-/node-12.12.21.tgz" integrity sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA== -"@types/node@^12.12.21": - version "12.12.67" - resolved "https://registry.npmjs.org/@types/node/-/node-12.12.67.tgz" - integrity sha512-R48tgL2izApf+9rYNH+3RBMbRpPeW3N8f0I9HMhggeq4UXwBDqumJ14SDs4ctTMhG11pIOduZ4z3QWGOiMc9Vg== - -"@types/node@^14.0.0": - version "14.11.8" - resolved "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz" - integrity sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw== +"@types/node@^16", "@types/node@^16.0.0": + version "16.18.126" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.126.tgz#27875faa2926c0f475b39a8bb1e546c0176f8d4b" + integrity sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -2095,136 +2124,101 @@ resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== -"@types/semver@^7.5.0": - version "7.5.6" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" - integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== - -"@typescript-eslint/eslint-plugin@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.0.tgz#62cda0d35bbf601683c6e58cf5d04f0275caca4e" - integrity sha512-M72SJ0DkcQVmmsbqlzc6EJgb/3Oz2Wdm6AyESB4YkGgCxP8u5jt5jn4/OBMPK3HLOxcttZq5xbBBU7e2By4SZQ== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "7.0.0" - "@typescript-eslint/type-utils" "7.0.0" - "@typescript-eslint/utils" "7.0.0" - "@typescript-eslint/visitor-keys" "7.0.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.4" +"@typescript-eslint/eslint-plugin@^8.58.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.0.tgz#fcbe76b693ce2412410cf4d48aefd617d345f2d9" + integrity sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.59.0" + "@typescript-eslint/type-utils" "8.59.0" + "@typescript-eslint/utils" "8.59.0" + "@typescript-eslint/visitor-keys" "8.59.0" + ignore "^7.0.5" natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/parser@^6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.17.0.tgz#8cd7a0599888ca6056082225b2fdf9a635bf32a1" - integrity sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A== - dependencies: - "@typescript-eslint/scope-manager" "6.17.0" - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/typescript-estree" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz#70e6c1334d0d76562dfa61aed9009c140a7601b4" - integrity sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA== - dependencies: - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" - -"@typescript-eslint/scope-manager@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.0.0.tgz#15ea9abad2b56fc8f5c0b516775f41c86c5c8685" - integrity sha512-IxTStwhNDPO07CCrYuAqjuJ3Xf5MrMaNgbAZPxFXAUpAtwqFxiuItxUaVtP/SJQeCdJjwDGh9/lMOluAndkKeg== - dependencies: - "@typescript-eslint/types" "7.0.0" - "@typescript-eslint/visitor-keys" "7.0.0" - -"@typescript-eslint/type-utils@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.0.0.tgz#a4c7ae114414e09dbbd3c823b5924793f7483252" - integrity sha512-FIM8HPxj1P2G7qfrpiXvbHeHypgo2mFpFGoh5I73ZlqmJOsloSa1x0ZyXCer43++P1doxCgNqIOLqmZR6SOT8g== - dependencies: - "@typescript-eslint/typescript-estree" "7.0.0" - "@typescript-eslint/utils" "7.0.0" - debug "^4.3.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/types@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.17.0.tgz#844a92eb7c527110bf9a7d177e3f22bd5a2f40cb" - integrity sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A== - -"@typescript-eslint/types@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.0.0.tgz#2e5889c7fe3c873fc6dc6420aa77775f17cd5dc6" - integrity sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg== + ts-api-utils "^2.5.0" + +"@typescript-eslint/parser@^8.58.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.59.0.tgz#57a138280b3ceaf07904fbd62c433d5cc1ee1573" + integrity sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg== + dependencies: + "@typescript-eslint/scope-manager" "8.59.0" + "@typescript-eslint/types" "8.59.0" + "@typescript-eslint/typescript-estree" "8.59.0" + "@typescript-eslint/visitor-keys" "8.59.0" + debug "^4.4.3" + +"@typescript-eslint/project-service@8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.59.0.tgz#914bf62069d870faa0389ffd725774a200f511bf" + integrity sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.59.0" + "@typescript-eslint/types" "^8.59.0" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.59.0.tgz#f71be268bd31da1c160815c689e4dde7c9bc9e8e" + integrity sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg== + dependencies: + "@typescript-eslint/types" "8.59.0" + "@typescript-eslint/visitor-keys" "8.59.0" + +"@typescript-eslint/tsconfig-utils@8.59.0", "@typescript-eslint/tsconfig-utils@^8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.0.tgz#1276077f5ad77e384446ea28a2474e8f8be1af41" + integrity sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg== + +"@typescript-eslint/type-utils@8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.59.0.tgz#2834ea3b179cedfc9244dcd4f74105a27751a439" + integrity sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg== + dependencies: + "@typescript-eslint/types" "8.59.0" + "@typescript-eslint/typescript-estree" "8.59.0" + "@typescript-eslint/utils" "8.59.0" + debug "^4.4.3" + ts-api-utils "^2.5.0" + +"@typescript-eslint/types@8.59.0", "@typescript-eslint/types@^8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.59.0.tgz#cfcc643c6e879016479775850d86d84c14492738" + integrity sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A== + +"@typescript-eslint/typescript-estree@8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.0.tgz#feba58a70ab6ea7ac53a2f3ae900db28ce3454c2" + integrity sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw== + dependencies: + "@typescript-eslint/project-service" "8.59.0" + "@typescript-eslint/tsconfig-utils" "8.59.0" + "@typescript-eslint/types" "8.59.0" + "@typescript-eslint/visitor-keys" "8.59.0" + debug "^4.4.3" + minimatch "^10.2.2" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.5.0" -"@typescript-eslint/typescript-estree@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz#b913d19886c52d8dc3db856903a36c6c64fd62aa" - integrity sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg== +"@typescript-eslint/utils@8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.59.0.tgz#f50df9bd6967881ef64fba62230111153179ead5" + integrity sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g== dependencies: - "@typescript-eslint/types" "6.17.0" - "@typescript-eslint/visitor-keys" "6.17.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.59.0" + "@typescript-eslint/types" "8.59.0" + "@typescript-eslint/typescript-estree" "8.59.0" -"@typescript-eslint/typescript-estree@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.0.tgz#7ce66f2ce068517f034f73fba9029300302fdae9" - integrity sha512-JzsOzhJJm74aQ3c9um/aDryHgSHfaX8SHFIu9x4Gpik/+qxLvxUylhTsO9abcNu39JIdhY2LgYrFxTii3IajLA== +"@typescript-eslint/visitor-keys@8.59.0": + version "8.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.0.tgz#2e80de30e7e944ed4bd47d751e37dcb04db03795" + integrity sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q== dependencies: - "@typescript-eslint/types" "7.0.0" - "@typescript-eslint/visitor-keys" "7.0.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/utils@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.0.0.tgz#e43710af746c6ae08484f7afc68abc0212782c7e" - integrity sha512-kuPZcPAdGcDBAyqDn/JVeJVhySvpkxzfXjJq1X1BFSTYo1TTuo4iyb937u457q4K0In84p6u2VHQGaFnv7VYqg== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "7.0.0" - "@typescript-eslint/types" "7.0.0" - "@typescript-eslint/typescript-estree" "7.0.0" - semver "^7.5.4" - -"@typescript-eslint/visitor-keys@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz#3ed043709c39b43ec1e58694f329e0b0430c26b6" - integrity sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg== - dependencies: - "@typescript-eslint/types" "6.17.0" - eslint-visitor-keys "^3.4.1" - -"@typescript-eslint/visitor-keys@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz#83cdadd193ee735fe9ea541f6a2b4d76dfe62081" - integrity sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w== - dependencies: - "@typescript-eslint/types" "7.0.0" - eslint-visitor-keys "^3.4.1" - -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + "@typescript-eslint/types" "8.59.0" + eslint-visitor-keys "^5.0.0" "@vitest/expect@3.0.9": version "3.0.9" @@ -2490,10 +2484,10 @@ acorn@^8.14.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== -acorn@^8.9.0: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.15.0, acorn@^8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" + integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== agent-base@4, agent-base@^4.3.0: version "4.3.0" @@ -2545,7 +2539,7 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.12.3: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2555,6 +2549,16 @@ ajv@^6.12.3, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.14.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.15.0.tgz#07e982c74626167aa7a2495c53817892d7139492" + integrity sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^8.0.0, ajv@^8.9.0: version "8.17.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" @@ -2708,11 +2712,6 @@ array-union@^1.0.2: dependencies: array-uniq "^1.0.1" -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" @@ -2901,6 +2900,13 @@ brace-expansion@^5.0.2: dependencies: balanced-match "^4.0.2" +brace-expansion@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" + integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== + dependencies: + balanced-match "^4.0.2" + braces@^2.3.1: version "2.3.2" resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" @@ -2917,13 +2923,6 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" @@ -3059,7 +3058,7 @@ callsites@^2.0.0: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase-keys@^2.0.0: @@ -3151,14 +3150,6 @@ chalk@^2.0.0, chalk@^2.3.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -3590,7 +3581,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.2: +cross-spawn@^7.0.0: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3599,7 +3590,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" -cross-spawn@^7.0.3: +cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -3679,7 +3670,7 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.4.0: dependencies: ms "^2.1.3" -debug@^4.3.5: +debug@^4.3.5, debug@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -3844,20 +3835,6 @@ dir-glob@^2.2.2: dependencies: path-type "^3.0.0" -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - dot-prop@^4.2.0: version "4.2.1" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz" @@ -4200,10 +4177,10 @@ eslint-plugin-prettier@^5.1.2: prettier-linter-helpers "^1.0.0" synckit "^0.11.7" -eslint-plugin-promise@^7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz#a0652195700aea40b926dc3c74b38e373377bfb0" - integrity sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA== +eslint-plugin-promise@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-7.3.0.tgz#7c61e117f5db8d7a300bd5143c15d1d828e4c124" + integrity sha512-6uGiOR0INuujr6PEQmeSSP7GbIMJ/ebEXXiEzb/nOj68LknH5Pxzb/AbZivmr6VE6TkTE8rTjRK9zhKpK6HsRA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" @@ -4215,11 +4192,13 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-9.1.2.tgz#b9de6ace2fab1cff24d2e58d85b74c8fcea39802" + integrity sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ== dependencies: + "@types/esrecurse" "^4.3.1" + "@types/estree" "^1.0.8" esrecurse "^4.3.0" estraverse "^5.2.0" @@ -4235,63 +4214,74 @@ eslint-visitor-keys@^1.1.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.56.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be" + integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA== + +eslint@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.2.1.tgz#224b2a6caeb34473eddcf918762363e2e063222a" + integrity sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.2" + "@eslint/config-array" "^0.23.5" + "@eslint/config-helpers" "^0.5.5" + "@eslint/core" "^1.2.1" + "@eslint/plugin-kit" "^0.7.1" + "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.14.0" + cross-spawn "^7.0.6" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^9.1.2" + eslint-visitor-keys "^5.0.1" + espree "^11.2.0" + esquery "^1.7.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" + minimatch "^10.2.4" natural-compare "^1.4.0" optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^10.0.1: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== dependencies: - acorn "^8.9.0" + acorn "^8.15.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^4.2.1" + +espree@^11.2.0: + version "11.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-11.2.0.tgz#01d5e47dc332aaba3059008362454a8cc34ccaa5" + integrity sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw== + dependencies: + acorn "^8.16.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^5.0.1" esprima@2.7.x, esprima@^2.7.1: version "2.7.3" @@ -4303,10 +4293,10 @@ esprima@^4.0.0: resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== dependencies: estraverse "^5.1.0" @@ -4490,17 +4480,6 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" -fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" @@ -4521,13 +4500,6 @@ fastest-levenshtein@^1.0.12: resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== -fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz" - integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== - dependencies: - reusify "^1.0.4" - fdir@^6.2.0, fdir@^6.4.3, fdir@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" @@ -4545,12 +4517,12 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" file-uri-to-path@1.0.0: version "1.0.0" @@ -4567,13 +4539,6 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - find-cache-dir@^3.2.0: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -4621,14 +4586,13 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" + keyv "^4.5.4" flat@^5.0.2: version "5.0.2" @@ -4917,7 +4881,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.2: +glob-parent@^5.0.0: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4992,24 +4956,10 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.19.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== globby@^9.2.0: version "9.2.0" @@ -5030,11 +4980,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - handlebars@^4.0.1, handlebars@^4.7.6: version "4.7.7" resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz" @@ -5247,11 +5192,16 @@ ignore@^4.0.3: resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: +ignore@^5.1.1, ignore@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== +ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz" @@ -5261,9 +5211,9 @@ import-fresh@^2.0.0: resolve-from "^3.0.0" import-fresh@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -5540,11 +5490,6 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - is-obj@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz" @@ -5797,6 +5742,13 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + dependencies: + argparse "^2.0.1" + jsbn@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" @@ -5879,7 +5831,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -keyv@^4.5.3: +keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== @@ -6060,11 +6012,6 @@ lodash.ismatch@^4.4.0: resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz" @@ -6317,7 +6264,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.2.3: version "1.4.1" resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -6341,14 +6288,6 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - mime-db@1.44.0: version "1.44.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz" @@ -6422,19 +6361,26 @@ miniflare@4.20250428.0: youch "3.3.4" zod "3.22.3" -"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== +minimatch@^10.2.2, minimatch@^10.2.4: + version "10.2.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" + integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== dependencies: - brace-expansion "^2.0.1" + brace-expansion "^5.0.5" + +minimatch@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== + dependencies: + brace-expansion "^1.1.7" minimatch@^9.0.4: version "9.0.4" @@ -7220,7 +7166,7 @@ parallel-transform@^1.1.0: parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" @@ -7349,11 +7295,6 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - pathe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" @@ -7425,11 +7366,6 @@ picocolors@^1.1.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - picomatch@^4.0.2, picomatch@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" @@ -8005,11 +7941,6 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" @@ -8017,7 +7948,7 @@ rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -8083,11 +8014,6 @@ run-async@^2.2.0: resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== - run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz" @@ -8144,7 +8070,7 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3, semver@^7.7.1, semver@^7.7.2: +semver@^7.3.5, semver@^7.5.3, semver@^7.6.3, semver@^7.7.1, semver@^7.7.2, semver@^7.7.3: version "7.7.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== @@ -8258,11 +8184,6 @@ slash@^2.0.0: resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - sliced@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/sliced/-/sliced-0.0.5.tgz#5edc044ca4eb6f7816d50ba2fc63e25d8fe4707f" @@ -8566,7 +8487,7 @@ stream-spec@~0.3.5: dependencies: macgyver "~1.10" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -8601,15 +8522,6 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -8649,7 +8561,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8677,13 +8589,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -8868,11 +8773,6 @@ text-extensions@^1.0.0: resolved "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" @@ -8963,13 +8863,6 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz" @@ -9025,10 +8918,10 @@ trim-off-newlines@^1.0.0: resolved "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz" integrity sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg== -ts-api-utils@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" - integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== +ts-api-utils@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz#4acd4a155e22734990a5ed1fe9e97f113bcb37c1" + integrity sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA== ts-node@^8.5.4: version "8.10.2" @@ -9097,11 +8990,6 @@ type-fest@^0.13.1: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz" integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz" @@ -9129,10 +9017,10 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.0.3: - version "4.8.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== +typescript@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" + integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw== ufo@^1.5.4: version "1.6.1" @@ -9618,7 +9506,7 @@ wrangler@^3.x: fsevents "~2.3.2" sharp "^0.33.5" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -9645,15 +9533,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 1025d12b24f277f9b7cdba2d5488103745939d6b Mon Sep 17 00:00:00 2001 From: francesco Date: Mon, 11 May 2026 18:39:54 +0200 Subject: [PATCH 10/16] Node JS 26 (#3667) * chore: update libpq to 1.11.0 * chore: add node 26 --- .github/workflows/ci.yml | 2 +- packages/pg-native/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d90e474c..1aae36233 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: - '20' - '22' - '24' - - '25' + - '26' os: - ubuntu-latest name: Node.js ${{ matrix.node }} diff --git a/packages/pg-native/package.json b/packages/pg-native/package.json index 4c8148ac1..b75b2ffdb 100644 --- a/packages/pg-native/package.json +++ b/packages/pg-native/package.json @@ -34,7 +34,7 @@ }, "homepage": "https://github.com/brianc/node-postgres/tree/master/packages/pg-native", "dependencies": { - "libpq": "^1.8.15", + "libpq": "^1.11.0", "pg-types": "2.2.0" }, "devDependencies": { From 7674d8c27fe8c10f981f4db22c89d1ae566c9380 Mon Sep 17 00:00:00 2001 From: "Herman J. Radtke III" Date: Mon, 11 May 2026 15:20:28 -0400 Subject: [PATCH 11/16] Fix pg prototype pollution via server supplied column names (#3656) * fix(pg-connection-string): prototype pollution via query strings * fix(pg): prototype pollution via server-supplied column names Fixes #3654 --- packages/pg-connection-string/index.js | 6 +- .../pg-connection-string/test/clientConfig.ts | 14 +-- packages/pg-connection-string/test/parse.ts | 34 ++++++ packages/pg/lib/result.js | 2 +- packages/pg/test/unit/result-tests.js | 111 ++++++++++++++++++ 5 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 packages/pg/test/unit/result-tests.js diff --git a/packages/pg-connection-string/index.js b/packages/pg-connection-string/index.js index 29ffeafd7..4b8d7afb9 100644 --- a/packages/pg-connection-string/index.js +++ b/packages/pg-connection-string/index.js @@ -14,7 +14,7 @@ function parse(str, options = {}) { // Check for empty host in URL - const config = {} + const config = Object.create(null) let result let dummyHost = false if (/ |%[^a-f0-9]|%[a-f0-9][^a-f0-9]/i.test(str)) { @@ -164,7 +164,7 @@ function toConnectionOptions(sslConfig) { } return c - }, {}) + }, Object.create(null)) return connectionOptions } @@ -200,7 +200,7 @@ function toClientConfig(config) { } return c - }, {}) + }, Object.create(null)) return poolConfig } diff --git a/packages/pg-connection-string/test/clientConfig.ts b/packages/pg-connection-string/test/clientConfig.ts index 14759570f..c4aeec6a7 100644 --- a/packages/pg-connection-string/test/clientConfig.ts +++ b/packages/pg-connection-string/test/clientConfig.ts @@ -46,7 +46,7 @@ describe('toClientConfig', function () { const config = parse('pg:///?sslmode=no-verify') const clientConfig = toClientConfig(config) - clientConfig.ssl?.should.deep.equal({ + expect(clientConfig.ssl).to.deep.equal({ rejectUnauthorized: false, }) }) @@ -55,14 +55,14 @@ describe('toClientConfig', function () { const config = parse('pg:///?sslmode=verify-ca') const clientConfig = toClientConfig(config) - clientConfig.ssl?.should.deep.equal({}) + expect(clientConfig.ssl).to.deep.equal({}) }) it('converts other sslmode options', function () { const config = parse('pg:///?sslmode=verify-ca') const clientConfig = toClientConfig(config) - clientConfig.ssl?.should.deep.equal({}) + expect(clientConfig.ssl).to.deep.equal({}) }) it('converts ssl cert options', function () { @@ -77,7 +77,7 @@ describe('toClientConfig', function () { const config = parse(connectionString) const clientConfig = toClientConfig(config) - clientConfig.ssl?.should.deep.equal({ + expect(clientConfig.ssl).to.deep.equal({ ca: 'example ca\n', cert: 'example cert\n', key: 'example key\n', @@ -106,9 +106,9 @@ describe('toClientConfig', function () { const clientConfig = toClientConfig(config) - clientConfig.host?.should.equal('boom') - clientConfig.database?.should.equal('lala') - clientConfig.ssl?.should.deep.equal({}) + expect(clientConfig.host).to.equal('boom') + expect(clientConfig.database).to.equal('lala') + expect(clientConfig.ssl).to.deep.equal({}) }) }) diff --git a/packages/pg-connection-string/test/parse.ts b/packages/pg-connection-string/test/parse.ts index a58edbe9c..814e49c58 100644 --- a/packages/pg-connection-string/test/parse.ts +++ b/packages/pg-connection-string/test/parse.ts @@ -467,4 +467,38 @@ describe('parse', function () { const subject = parse(connectionString) subject.port?.should.equal('1234') }) + + describe('prototype pollution protection', function () { + it('returns object with null prototype', function () { + const subject = parse('postgres://localhost/db') + expect(Object.getPrototypeOf(subject)).to.equal(null) + }) + + it('__proto__ query parameter is stored as regular property', function () { + const subject = parse('postgres://localhost/db?__proto__=malicious') + expect(Object.getPrototypeOf(subject)).to.equal(null) + expect(subject['__proto__']).to.equal('malicious') + // global Object.prototype should not be affected + expect(({} as any).malicious).to.equal(undefined) + }) + + it('constructor query parameter is stored as regular property', function () { + const subject = parse('postgres://localhost/db?constructor=evil') + expect(subject.constructor).to.equal('evil') + }) + + it('prototype query parameter is stored as regular property', function () { + const subject = parse('postgres://localhost/db?prototype=evil') + expect(subject['prototype']).to.equal('evil') + }) + + it('multiple dangerous query parameters are handled safely', function () { + const subject = parse('postgres://localhost/db?__proto__=a&constructor=b&prototype=c&toString=d') + expect(Object.getPrototypeOf(subject)).to.equal(null) + expect(subject['__proto__']).to.equal('a') + expect(subject.constructor).to.equal('b') + expect(subject['prototype']).to.equal('c') + expect(subject['toString']).to.equal('d') + }) + }) }) diff --git a/packages/pg/lib/result.js b/packages/pg/lib/result.js index 0ab7bb80c..329fbf9fc 100644 --- a/packages/pg/lib/result.js +++ b/packages/pg/lib/result.js @@ -89,7 +89,7 @@ class Result { this._parsers = new Array(fieldDescriptions.length) } - const row = {} + const row = Object.create(null) for (let i = 0; i < fieldDescriptions.length; i++) { const desc = fieldDescriptions[i] diff --git a/packages/pg/test/unit/result-tests.js b/packages/pg/test/unit/result-tests.js new file mode 100644 index 000000000..5135723ed --- /dev/null +++ b/packages/pg/test/unit/result-tests.js @@ -0,0 +1,111 @@ +'use strict' +const helper = require('./test-helper') +const assert = require('assert') +const suite = new helper.Suite() +const test = suite.test.bind(suite) + +const Result = require('../../lib/result') + +test('__proto__ column name does not pollute prototype', function () { + const result = new Result() + result.addFields([ + { name: '__proto__', dataTypeID: 25, format: 'text' }, + { name: 'id', dataTypeID: 23, format: 'text' }, + ]) + const row = result.parseRow(['malicious', '1']) + + // __proto__ should be a regular property, not affect prototype chain + assert.strictEqual(row['__proto__'], 'malicious') + assert.strictEqual(row.id, 1) + + // global Object.prototype should not be affected + assert.strictEqual({}.malicious, undefined) + assert.strictEqual(Object.prototype.malicious, undefined) +}) + +test('__proto__ column with object value does not inject prototype', function () { + // custom type parser that returns objects (like JSON) + const customTypes = { + getTypeParser: () => (val) => JSON.parse(val), + } + const result = new Result('object', customTypes) + result.addFields([ + { name: '__proto__', dataTypeID: 114, format: 'text' }, + { name: 'id', dataTypeID: 23, format: 'text' }, + ]) + + const maliciousPayload = JSON.stringify({ isAdmin: true, role: 'admin' }) + const row = result.parseRow([maliciousPayload, '1']) + + // __proto__ should be stored as a regular property + assert.deepStrictEqual(row['__proto__'], { isAdmin: true, role: 'admin' }) + + // the row should NOT inherit from the malicious payload + assert.strictEqual('isAdmin' in row, false) + assert.strictEqual('role' in row, false) +}) + +test('constructor column name is safely stored as property', function () { + const result = new Result() + result.addFields([ + { name: 'constructor', dataTypeID: 25, format: 'text' }, + { name: 'id', dataTypeID: 23, format: 'text' }, + ]) + const row = result.parseRow(['malicious', '1']) + + assert.strictEqual(row.constructor, 'malicious') + assert.strictEqual(row.id, 1) +}) + +test('hasOwnProperty column name is safely stored as property', function () { + const result = new Result() + result.addFields([ + { name: 'hasOwnProperty', dataTypeID: 25, format: 'text' }, + { name: 'data', dataTypeID: 25, format: 'text' }, + ]) + const row = result.parseRow(['not_a_function', 'value']) + + assert.strictEqual(row.hasOwnProperty, 'not_a_function') + assert.strictEqual(row.data, 'value') + + // can still check properties using Object.prototype.hasOwnProperty.call + assert.strictEqual(Object.prototype.hasOwnProperty.call(row, 'data'), true) +}) + +test('toString column name is safely stored as property', function () { + const result = new Result() + result.addFields([{ name: 'toString', dataTypeID: 25, format: 'text' }]) + const row = result.parseRow(['not_a_function']) + + assert.strictEqual(row.toString, 'not_a_function') +}) + +test('prototype column name is safely stored as property', function () { + const result = new Result() + result.addFields([ + { name: 'prototype', dataTypeID: 25, format: 'text' }, + { name: 'id', dataTypeID: 23, format: 'text' }, + ]) + const row = result.parseRow(['value', '1']) + + assert.strictEqual(row.prototype, 'value') + assert.strictEqual(row.id, 1) +}) + +test('multiple dangerous column names handled safely', function () { + const result = new Result() + result.addFields([ + { name: '__proto__', dataTypeID: 25, format: 'text' }, + { name: 'constructor', dataTypeID: 25, format: 'text' }, + { name: 'prototype', dataTypeID: 25, format: 'text' }, + { name: '__defineGetter__', dataTypeID: 25, format: 'text' }, + { name: 'id', dataTypeID: 23, format: 'text' }, + ]) + const row = result.parseRow(['a', 'b', 'c', 'd', '1']) + + assert.strictEqual(row['__proto__'], 'a') + assert.strictEqual(row.constructor, 'b') + assert.strictEqual(row.prototype, 'c') + assert.strictEqual(row['__defineGetter__'], 'd') + assert.strictEqual(row.id, 1) +}) From effc3f6c2e785f8295a14c53a0c6848c8a66910c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 14:40:03 -0500 Subject: [PATCH 12/16] build(deps-dev): bump eslint-plugin-prettier from 5.5.1 to 5.5.5 (#3648) Bumps [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) from 5.5.1 to 5.5.5. - [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases) - [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v5.5.1...v5.5.5) --- updated-dependencies: - dependency-name: eslint-plugin-prettier dependency-version: 5.5.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/yarn.lock b/yarn.lock index b221bd37a..3379c62b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1870,10 +1870,10 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@pkgr/core@^0.2.4": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.7.tgz#eb5014dfd0b03e7f3ba2eeeff506eed89b028058" - integrity sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg== +"@pkgr/core@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b" + integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== "@rollup/plugin-commonjs@^28.0.3": version "28.0.3" @@ -4170,12 +4170,12 @@ eslint-plugin-node@^11.1.0: semver "^6.1.0" eslint-plugin-prettier@^5.1.2: - version "5.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz#470820964de9aedb37e9ce62c3266d2d26d08d15" - integrity sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw== + version "5.5.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz#9eae11593faa108859c26f9a9c367d619a0769c0" + integrity sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw== dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.11.7" + prettier-linter-helpers "^1.0.1" + synckit "^0.11.12" eslint-plugin-promise@^7.3.0: version "7.3.0" @@ -7485,10 +7485,10 @@ prelude-ls@~1.1.2: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== +prettier-linter-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz#6a31f88a4bad6c7adda253de12ba4edaea80ebcd" + integrity sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg== dependencies: fast-diff "^1.1.2" @@ -8684,12 +8684,12 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: - version "0.11.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" - integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== +synckit@^0.11.12: + version "0.11.12" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.12.tgz#abe74124264fbc00a48011b0d98bdc1cffb64a7b" + integrity sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ== dependencies: - "@pkgr/core" "^0.2.4" + "@pkgr/core" "^0.2.9" tapable@^2.1.1, tapable@^2.2.0: version "2.2.2" From 939725e02c392a6f863cd57970aa3202fb500912 Mon Sep 17 00:00:00 2001 From: Leonardo Zanivan Date: Mon, 11 May 2026 16:55:10 -0300 Subject: [PATCH 13/16] feat: add new client.getTransactionStatus() method (#3645) * feat: add new client.getTransactionStatus() method Adds a new public method to retrieve the current transaction status of the client connection. Returns 'I' (idle), 'T' (in transaction), 'E' (error/aborted), or null (initial state/native client). The transaction status is tracked from PostgreSQL's ReadyForQuery message after each query completes. Native client returns null as it does not support this feature yet. * feat: add native client support for getTransactionStatus() - Add getTransactionStatus() to pg-native using libpq's PQtransactionStatus() with status mapping (0->I, 2->T, 3->E) - Update pg native client wrapper to delegate to pg-native - Remove native guard from txstatus tests (now runs in both modes) - Bump libpq to ^1.10.0 for transactionStatus() binding support * docs * Tests * fix: docs * clear docs --------- Co-authored-by: Brian C --- docs/pages/apis/client.mdx | 55 +++++++++++++ packages/pg-native/index.js | 8 ++ packages/pg/lib/client.js | 6 ++ packages/pg/lib/native/client.js | 4 + .../test/integration/client/txstatus-tests.js | 82 +++++++++++++++++++ yarn.lock | 15 ++-- 6 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 packages/pg/test/integration/client/txstatus-tests.js diff --git a/docs/pages/apis/client.mdx b/docs/pages/apis/client.mdx index 5867ad5a6..ecfd67fca 100644 --- a/docs/pages/apis/client.mdx +++ b/docs/pages/apis/client.mdx @@ -175,6 +175,61 @@ await client.end() console.log('client has disconnected') ``` +## client.getTransactionStatus + +`client.getTransactionStatus() => string | null` + +Returns the current transaction status of the client connection. This can be useful for debugging transaction state issues or implementing custom transaction management logic. + +**Return values:** + +- `'I'` - Idle (not in a transaction) +- `'T'` - Transaction active (BEGIN has been issued) +- `'E'` - Error (transaction aborted, requires ROLLBACK) +- `null` - Initial state (before first query) + +The transaction status is updated after each query completes based on the PostgreSQL backend's `ReadyForQuery` message. + +**Example: Checking transaction state** + +```js +import { Client } from 'pg' +const client = new Client() +await client.connect() + +await client.query('BEGIN') +console.log(client.getTransactionStatus()) // 'T' - in transaction + +await client.query('SELECT * FROM users') +console.log(client.getTransactionStatus()) // 'T' - still in transaction + +await client.query('COMMIT') +console.log(client.getTransactionStatus()) // 'I' - idle + +await client.end() +``` + +**Example: Handling transaction errors** + +```js +import { Client } from 'pg' +const client = new Client() +await client.connect() + +await client.query('BEGIN') +try { + await client.query('INVALID SQL') +} catch (err) { + console.log(client.getTransactionStatus()) // 'E' - error state + + // Must rollback to recover + await client.query('ROLLBACK') + console.log(client.getTransactionStatus()) // 'I' - idle again +} + +await client.end() +``` + ## events ### error diff --git a/packages/pg-native/index.js b/packages/pg-native/index.js index 8c83406bb..1c18241db 100644 --- a/packages/pg-native/index.js +++ b/packages/pg-native/index.js @@ -6,6 +6,10 @@ const types = require('pg-types') const buildResult = require('./lib/build-result') const CopyStream = require('./lib/copy-stream') +// https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQTRANSACTIONSTATUS +// 0=IDLE, 1=ACTIVE, 2=INTRANS, 3=INERROR +const statusMap = { 0: 'I', 2: 'T', 3: 'E' } + const Client = (module.exports = function (config) { if (!(this instanceof Client)) { return new Client(config) @@ -145,6 +149,10 @@ Client.prototype.escapeIdentifier = function (value) { return this.pq.escapeIdentifier(value) } +Client.prototype.getTransactionStatus = function () { + return statusMap[this.pq.transactionStatus()] ?? null +} + // export the version number so we can check it in node-postgres module.exports.version = require('./package.json').version diff --git a/packages/pg/lib/client.js b/packages/pg/lib/client.js index 9200dded6..48d3a595b 100644 --- a/packages/pg/lib/client.js +++ b/packages/pg/lib/client.js @@ -71,6 +71,7 @@ class Client extends EventEmitter { this._connectionError = false this._queryable = true this._activeQuery = null + this._txStatus = null this.enableChannelBinding = Boolean(c.enableChannelBinding) // set true to use SCRAM-SHA-256-PLUS when offered this.connection = @@ -359,6 +360,7 @@ class Client extends EventEmitter { } const activeQuery = this._getActiveQuery() this._activeQuery = null + this._txStatus = msg?.status ?? null this.readyForQuery = true if (activeQuery) { activeQuery.handleReadyForQuery(this.connection) @@ -703,6 +705,10 @@ class Client extends EventEmitter { this.connection.unref() } + getTransactionStatus() { + return this._txStatus + } + end(cb) { this._ending = true diff --git a/packages/pg/lib/native/client.js b/packages/pg/lib/native/client.js index d8bb4dce5..6df471b83 100644 --- a/packages/pg/lib/native/client.js +++ b/packages/pg/lib/native/client.js @@ -321,3 +321,7 @@ Client.prototype.getTypeParser = function (oid, format) { Client.prototype.isConnected = function () { return this._connected } + +Client.prototype.getTransactionStatus = function () { + return this.native.getTransactionStatus() +} diff --git a/packages/pg/test/integration/client/txstatus-tests.js b/packages/pg/test/integration/client/txstatus-tests.js new file mode 100644 index 000000000..cb8b740f8 --- /dev/null +++ b/packages/pg/test/integration/client/txstatus-tests.js @@ -0,0 +1,82 @@ +'use strict' +const helper = require('./test-helper') +const suite = new helper.Suite() +const pg = helper.pg +const assert = require('assert') + +suite.test('txStatus tracking', function (done) { + const client = new pg.Client() + client.connect( + assert.success(function () { + // Run a simple query to initialize txStatus + client.query( + 'SELECT 1', + assert.success(function () { + // Test 1: Initial state after query (should be idle) + assert.equal(client.getTransactionStatus(), 'I', 'should start in idle state') + + // Test 2: BEGIN transaction + client.query( + 'BEGIN', + assert.success(function () { + assert.equal(client.getTransactionStatus(), 'T', 'should be in transaction state') + + // Test 3: COMMIT + client.query( + 'COMMIT', + assert.success(function () { + assert.equal(client.getTransactionStatus(), 'I', 'should return to idle after commit') + + client.end(done) + }) + ) + }) + ) + }) + ) + }) + ) +}) + +suite.test('txStatus error state', function (done) { + const client = new pg.Client() + client.connect( + assert.success(function () { + // Run a simple query to initialize txStatus + client.query( + 'SELECT 1', + assert.success(function () { + client.query( + 'BEGIN', + assert.success(function () { + // Execute invalid SQL to trigger error state + client.query('INVALID SQL SYNTAX', function (err) { + assert(err, 'should receive error from invalid query') + + // Issue a sync query to ensure ReadyForQuery has been processed + // This guarantees transaction status has been updated + client.query('SELECT 1', function () { + // This callback fires after ReadyForQuery is processed + assert.equal(client.getTransactionStatus(), 'E', 'should be in error state') + + // Rollback to recover + client.query( + 'ROLLBACK', + assert.success(function () { + assert.equal( + client.getTransactionStatus(), + 'I', + 'should return to idle after rollback from error' + ) + client.end(done) + }) + ) + }) + }) + }) + ) + }) + ) + }) + ) +}) diff --git a/yarn.lock b/yarn.lock index 3379c62b4..6e45ace78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5907,13 +5907,13 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libpq@^1.8.15: - version "1.8.15" - resolved "https://registry.yarnpkg.com/libpq/-/libpq-1.8.15.tgz#bf9cea8e59e1a4a911d06df01d408213a09925ad" - integrity sha512-4lSWmly2Nsj3LaTxxtFmJWuP3Kx+0hYHEd+aNrcXEWT0nKWaPd9/QZPiMkkC680zeALFGHQdQWjBvnilL+vgWA== +libpq@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/libpq/-/libpq-1.10.0.tgz#238d01d416abca8768aab09bc82d81af9c7ffa23" + integrity sha512-PHY+JGD3+9X5b2emXLh+WJEnz1jhczO1xs25ZH0xbMWvQi+Hd9X/mTZOrGA99Rcw/DvNjsBRlegroqigpNfaJA== dependencies: bindings "1.5.0" - nan "~2.22.2" + nan "~2.23.1" lines-and-columns@^1.1.6: version "1.1.6" @@ -6632,6 +6632,11 @@ nan@~2.22.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.2.tgz#6b504fd029fb8f38c0990e52ad5c26772fdacfbb" integrity sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ== +nan@~2.23.1: + version "2.23.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.23.1.tgz#6f86a31dd87e3d1eb77512bf4b9e14c8aded3975" + integrity sha512-r7bBUGKzlqk8oPBDYxt6Z0aEdF1G1rwlMcLk8LCOMbOzf0mG+JUfUzG4fIMWwHWP0iyaLWEQZJmtB7nOHEm/qw== + nanoid@^3.3.11: version "3.3.11" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" From 7ba4efe25d40359c0fb2dec0cd674a3abc5d1026 Mon Sep 17 00:00:00 2001 From: felipe stival <14948182+v0idpwn@users.noreply.github.com> Date: Mon, 11 May 2026 17:42:35 -0300 Subject: [PATCH 14/16] Handle SASL SCRAM server error responses (#3521) Add proper error handling for SCRAM-SERVER-FINAL-MESSAGE error attribute. The SCRAM specification allows servers to return error messages via the 'e' attribute in the server final message. Currently, these errors are ignored and authentication fails later during signature verification. Postgres typically doesn't return this error (see [here](https://github.com/postgres/postgres/blob/2047ad068139f0b8c6da73d0b845ca9ba30fb33d/src/backend/libpq/auth-scram.c#L423) on why), but poolers, or other applications using the postgres protocol might, and it's part of the SCRAM spec, so it probably makes sense for node-postgres to handle it. Aligns behaviour with psql, postgrex, and somewhat with pgJDBC (pgJDBC in particular is stricter with scram errors). For reference: - libpq handling it: https://github.com/postgres/postgres/blob/2047ad068139f0b8c6da73d0b845ca9ba30fb33d/src/interfaces/libpq/fe-auth-scram.c#L708 --- packages/pg/lib/crypto/sasl.js | 6 ++++++ .../pg/test/unit/client/sasl-scram-tests.js | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/packages/pg/lib/crypto/sasl.js b/packages/pg/lib/crypto/sasl.js index 47b77610c..a782ae48a 100644 --- a/packages/pg/lib/crypto/sasl.js +++ b/packages/pg/lib/crypto/sasl.js @@ -178,7 +178,13 @@ function parseServerFirstMessage(data) { function parseServerFinalMessage(serverData) { const attrPairs = parseAttributePairs(serverData) + const error = attrPairs.get('e') const serverSignature = attrPairs.get('v') + + if (error) { + throw new Error(`SASL: SCRAM-SERVER-FINAL-MESSAGE: server returned error: "${error}"`) + } + if (!serverSignature) { throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing') } else if (!isBase64(serverSignature)) { diff --git a/packages/pg/test/unit/client/sasl-scram-tests.js b/packages/pg/test/unit/client/sasl-scram-tests.js index 2df0f1860..7554a9814 100644 --- a/packages/pg/test/unit/client/sasl-scram-tests.js +++ b/packages/pg/test/unit/client/sasl-scram-tests.js @@ -284,6 +284,23 @@ suite.test('sasl/scram', function () { ) }) + suite.test('fails when server returns an error', function () { + assert.throws( + function () { + sasl.finalizeSession( + { + message: 'SASLResponse', + serverSignature: 'abcd', + }, + 'e=no-resources' + ) + }, + { + message: 'SASL: SCRAM-SERVER-FINAL-MESSAGE: server returned error: "no-resources"', + } + ) + }) + suite.test('fails when server signature does not match', function () { assert.throws( function () { From 3bb9fbaa5f1b25078cd4ba12d501d4bb05677d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?sebastian=20kr=C3=A4mer?= Date: Mon, 11 May 2026 22:43:46 +0200 Subject: [PATCH 15/16] Add error handling for non-function callback (#3561) * Add error handling for non-function callback catch callback not a function earlier to get a proper callstack. later when executing the callback the stack may be wrong/insufficient. * fix: lint * fix: lint * fix: test * feat: add test for new error --- packages/pg-pool/index.js | 2 +- packages/pg/lib/client.js | 4 ++++ packages/pg/test/unit/client/simple-query-tests.js | 12 ++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/pg-pool/index.js b/packages/pg-pool/index.js index 2fbdb78d5..ab514fa88 100644 --- a/packages/pg-pool/index.js +++ b/packages/pg-pool/index.js @@ -438,7 +438,7 @@ class Pool extends EventEmitter { return response.result } - // allow plain text query without values + // allow plain text query without values, but callback if (typeof values === 'function') { cb = values values = undefined diff --git a/packages/pg/lib/client.js b/packages/pg/lib/client.js index 48d3a595b..33a8e24f0 100644 --- a/packages/pg/lib/client.js +++ b/packages/pg/lib/client.js @@ -633,6 +633,10 @@ class Client extends EventEmitter { Error.captureStackTrace(err) throw err }) + } else { + if (!(typeof query.callback === 'function')) { + throw new Error('callback is not a function') + } } } diff --git a/packages/pg/test/unit/client/simple-query-tests.js b/packages/pg/test/unit/client/simple-query-tests.js index d7d938992..6c20c576b 100644 --- a/packages/pg/test/unit/client/simple-query-tests.js +++ b/packages/pg/test/unit/client/simple-query-tests.js @@ -140,5 +140,17 @@ test('executing query', function () { ) } }) + + test('throws an error when callback is not a function', function () { + try { + client.query('SELECT $1', [1], 'notafunction') + } catch (error) { + assert.equal( + error.message, + 'callback is not a function', + 'Should have thrown an Error for non function callback' + ) + } + }) }) }) From 0f56b76d09c9596940a78bec4a438712d1823fb5 Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Mon, 11 May 2026 15:14:33 -0700 Subject: [PATCH 16/16] Throw `TypeError` instead of base `Error` when query callback is not a function & style fix. Follow-up to #3561. --- packages/pg/lib/client.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/pg/lib/client.js b/packages/pg/lib/client.js index 33a8e24f0..bb5e6d5f0 100644 --- a/packages/pg/lib/client.js +++ b/packages/pg/lib/client.js @@ -633,10 +633,8 @@ class Client extends EventEmitter { Error.captureStackTrace(err) throw err }) - } else { - if (!(typeof query.callback === 'function')) { - throw new Error('callback is not a function') - } + } else if (typeof query.callback !== 'function') { + throw new TypeError('callback is not a function') } }